From d9dc8361297ecdcce73cf7cf7b308f2cb9edac1e Mon Sep 17 00:00:00 2001 From: Beni Cherniavsky-Paskin Date: Fri, 25 Feb 2022 16:50:42 +0200 Subject: [PATCH] [v4.y] Test VERIFY_PEER / VERIFY_NONE work against real cluster Followup to https://github.com/ManageIQ/kubeclient/pull/540, tests that it really fixes https://github.com/abonas/kubeclient/issues/525. --- test/config/update_certs_k0s.rb | 4 +- test/test_config.rb | 81 +++++++++++++++++++++++++++++++++ test/test_guestbook_go.rb | 2 + test/test_helper.rb | 2 + 4 files changed, 88 insertions(+), 1 deletion(-) diff --git a/test/config/update_certs_k0s.rb b/test/config/update_certs_k0s.rb index 26140322..dce478f7 100755 --- a/test/config/update_certs_k0s.rb +++ b/test/config/update_certs_k0s.rb @@ -36,6 +36,8 @@ def sh!(*cmd) sh! "#{DOCKER} exec #{CONTAINER} cat /var/lib/k0s/pki/admin.crt > test/config/external-cert.pem" sh! "#{DOCKER} exec #{CONTAINER} cat /var/lib/k0s/pki/admin.key > test/config/external-key.rsa" -sh! 'bundle exec rake test' +sh! 'env KUBECLIENT_TEST_REAL_CLUSTER=true bundle exec rake test' sh! "#{DOCKER} rm -f #{CONTAINER}" + +puts 'If you run this only for tests, cleanup by running: git restore test/config/' diff --git a/test/test_config.rb b/test/test_config.rb index 6097e35e..b8f09878 100644 --- a/test/test_config.rb +++ b/test/test_config.rb @@ -4,6 +4,22 @@ # Testing Kubernetes client configuration class KubeclientConfigTest < MiniTest::Test + # Some tests here actually connect to a cluster! + # (and test some aspects of `Client`, not just `Config`.) + # For simplicity, these tests use same config/*.kubeconfig files, + # so are intended to run from config/update_certs_k0s.rb script. + def require_real_cluster! + if ENV['KUBECLIENT_TEST_REAL_CLUSTER'] == 'true' + WebMock.enable_net_connect! + else + skip('Requires real cluster, see test/config/update_certs_k0s.rb.') + end + end + + def teardown + WebMock.disable_net_connect! # Don't allow any connections in other tests. + end + def test_allinone config = Kubeclient::Config.read(config_file('allinone.kubeconfig')) assert_equal(['Default'], config.contexts) @@ -16,6 +32,60 @@ def test_external check_context(config.context, ssl: true) end + def test_real_cluster_verify_peer + require_real_cluster! + + config = Kubeclient::Config.read(config_file('external.kubeconfig')) + context = config.context + # localhost and 127.0.0.1 are among names on the certificate + client1 = Kubeclient::Client.new( + 'https://127.0.0.1:6443', 'v1', + ssl_options: context.ssl_options.merge(verify_ssl: OpenSSL::SSL::VERIFY_PEER), + auth_options: context.auth_options + ) + client1.discover + client1.get_nodes + exercise_watcher_with_timeout(client1.watch_nodes) + # 127.0.0.2 also means localhost but is not included in the certificate. + client2 = Kubeclient::Client.new( + 'https://127.0.0.2:6443', 'v1', + ssl_options: context.ssl_options.merge(verify_ssl: OpenSSL::SSL::VERIFY_PEER), + auth_options: context.auth_options + ) + assert_raises(Kubeclient::HttpError) do + client2.discover + end + # Since discovery fails, methods like .get_nodes, .watch_nodes would all fail + # on method_missing -> discover. Call lower-level methods to test actual connection. + assert_raises(Kubeclient::HttpError) do + client2.get_entities('Node', 'nodes', {}) + end + assert_raises(OpenSSL::SSL::SSLError) do + exercise_watcher_with_timeout(client2.watch_entities('nodes')) + end + end + + def test_real_cluster_verify_none + require_real_cluster! + + config = Kubeclient::Config.read(config_file('external.kubeconfig')) + context = config.context + # localhost and 127.0.0.1 are among names on the certificate + client1 = Kubeclient::Client.new( + 'https://127.0.0.1:6443', 'v1', + ssl_options: context.ssl_options.merge(verify_ssl: OpenSSL::SSL::VERIFY_NONE), + auth_options: context.auth_options + ) + client1.get_nodes + # 127.0.0.2 also means localhost but is not included in the certificate. + client2 = Kubeclient::Client.new( + 'https://127.0.0.2:6443', 'v1', + ssl_options: context.ssl_options.merge(verify_ssl: OpenSSL::SSL::VERIFY_NONE), + auth_options: context.auth_options + ) + client2.get_nodes + end + def test_allinone_nopath yaml = File.read(config_file('allinone.kubeconfig')) # A self-contained config shouldn't depend on kcfg_path. @@ -218,4 +288,15 @@ def load_yaml(file_name) YAML.safe_load(File.read(file_name), [Date, Time]) end end + + def exercise_watcher_with_timeout(watcher) + thread = Thread.new do + sleep(1) + watcher.finish + end + watcher.each do |_notice| + break + end + thread.join + end end diff --git a/test/test_guestbook_go.rb b/test/test_guestbook_go.rb index 8630533d..a50e192a 100644 --- a/test/test_guestbook_go.rb +++ b/test/test_guestbook_go.rb @@ -41,6 +41,8 @@ def test_create_guestbook_entities client.delete_namespace(testing_ns.metadata.name) end + ensure + VCR.turn_off! end def delete_namespace(client, namespace_name) diff --git a/test/test_helper.rb b/test/test_helper.rb index 56965813..2b5c43bb 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -12,6 +12,8 @@ def open_test_file(name) File.new(File.join(File.dirname(__FILE__), name.split('.').last, name)) end +WebMock.disable_net_connect! + def stub_core_api_list stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)