diff --git a/lib/k8s/client.rb b/lib/k8s/client.rb index c766f62..1f810ce 100644 --- a/lib/k8s/client.rb +++ b/lib/k8s/client.rb @@ -4,6 +4,7 @@ require 'base64' require 'yajl' require 'monitor' +require 'uri' require 'k8s/util' diff --git a/lib/k8s/transport.rb b/lib/k8s/transport.rb index 6e1ca48..35f050a 100644 --- a/lib/k8s/transport.rb +++ b/lib/k8s/transport.rb @@ -142,15 +142,17 @@ def self.in_cluster_config(**options) ) end - attr_reader :server, :options + attr_reader :server, :options, :path_prefix - # @param server [String] URL with protocol://host:port - any /path is ignored + # @param server [String] URL with protocol://host:port (paths are preserved as well) # @param auth_token [String] optional Authorization: Bearer token # @param auth_username [String] optional Basic authentication username # @param auth_password [String] optional Basic authentication password # @param options [Hash] @see Excon.new def initialize(server, auth_token: nil, auth_username: nil, auth_password: nil, **options) - @server = server + uri = URI.parse(server) + @server = "#{uri.scheme}://#{uri.host}:#{uri.port}" + @path_prefix = File.join('/', uri.path, '/') # add leading and/or trailing slashes @auth_token = auth_token @auth_username = auth_username @auth_password = auth_password @@ -175,10 +177,10 @@ def build_excon ) end - # @param path [Array] join path parts together to build the full URL + # @param parts [Array] join path parts together to build the full URL # @return [String] - def path(*path) - File.join('/', *path) + def path(*parts) + File.join(path_prefix, *parts) end # @param request_object [Object] include request body using to_json diff --git a/spec/fixtures/config/kubeadm-admin-with-path-prefix.conf b/spec/fixtures/config/kubeadm-admin-with-path-prefix.conf new file mode 100644 index 0000000..43a94e5 --- /dev/null +++ b/spec/fixtures/config/kubeadm-admin-with-path-prefix.conf @@ -0,0 +1,19 @@ +apiVersion: v1 +clusters: +- cluster: + certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNE1EY3dOVEEyTWpjeE5Gb1hEVEk0TURjd01qQTJNamN4TkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBS0V4CjR0ZXN2V1hUV1Z4dlVQdzFwS29NNmE3NFhPRlRTdGF4d0YrcDFMVENUN3JmdlE3Nncwems4c3F1ZEh0MUlMRkgKMnpia1d2b3UrcFlhNUE1YUkxUjlMZk1vSGRPQ2ZUeXBqZmdDVVRzdDl1amxuZ0dmK3M0VFRqRndZMzBvSVNRWQpHaHUvajZBL3gzbWhhQ0psODM2SkhGeTZDTnE1OTk5MU5uMDlDT0RXc0NPbUZ6RHY3K2VaSGZiVzNIMjU1YUpFCm5zS2RHRTJ2ejNSdnVpbmRUUk1FZnhpc1RkRmx1YTZCMWp3MDF2MWRhWlcvek5sSXF6NDRieFJOTmlONFhLVngKeTJqb0dYSDI1aW5udmc4dDQwL1JCSStvamppcU1nQUlRUHVkdVJacW1pYnJMcytDdmtGcUVVWml3cWdWS0ZGQgpwVHQ0dHB5NjVIckZGZVdwcGFjQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFKbGE3ejFWb0dPMmNiL00vK0RJcW1vQit4T2UKY0FJTUJxYTNXZUZQUXZ1N2dFbGh3cTBFRndTQmRtOUp6R0xqVHRxbGZ5ai8veEgwc08wdWt3WS9NTkRhODdsZQpXT1lsZFN3RW5WQXhmVjRvU0U1N2J4ci9NeE1YVnlYRXVDc1VOTFhXbG9SM251Y3hINHQzUFRSV0ZrejRyZ1ZSCk95WUtsL2w4VW9ZQWQ5VytsRHBaa1ZXa2oxbDZXQTJZck5YQVdtZTNnb2xMS3FLSUpZTUhKUlhVbnBHSWN2SHUKWVZDaGxqbjVQMnpubkVrRms5aTVtZjZ0ZDlXNEErc0cwTUJkV3c2bUl0RWRSZmM0MVNQWUgrcUQwZDZaZDNzUwo2ZzRhaXA4Z2dmRG9SbjBDL0FKb3lFVkxRL0ZPdy9ua0NJNnRDSDQ2amZXak0rb2plbFVDSHRMcHFjRT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= + server: "https://192.168.56.11:6443/k8s/clusters/c-dnmgm" + name: kubernetes +contexts: +- context: + cluster: kubernetes + user: kubernetes-admin + name: kubernetes-admin@kubernetes +current-context: kubernetes-admin@kubernetes +kind: Config +preferences: {} +users: +- name: kubernetes-admin + user: + client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM4akNDQWRxZ0F3SUJBZ0lJWlFXeXFFQW8yaEF3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB4T0RBM01EVXdOakkzTVRSYUZ3MHhPVEEzTURVd05qSTNNVFphTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQTBYVWZYNlJnRnVVTGxJcWYKbm4xSkpNM0UvVTZNRUMzVVNNaVRTZUp1dERRL25wVEpVcUxLVXNVTWxCYWtrQ1dueERVTE93RDZvTW5UYmVmVgpkWVp3djIyU3hRRDRiNjd5Yk1ZSVlVdmFYOVVCQ3VvNDdvb2c3RDYraDJ1TWZRNnR4MVZ6Uk85TGIvbCtTeDNsClF4RkJhcC9lUDZ3KzZrc3NWejFReDE2a3pEaE80bkRPZ2g3b2FLUTVpOElIUUhYKzBTUVhITlZyTVRWTjk2aHQKRU5PK0tVZThHRXJvR0JTNktnNlo4MkE4TzBEejVrU2xrMWVVZ054WGQwQldlazkwRFNJcGVkZUxocE1pVnBwTApnUmVmbGloWmxuYWRoNHY0amxrUk9LMTRjS1k1SXdZSzRUdVM3bkpBSWd0blJOa2dXUENNTkRWdXl1R0R2V2U4CnZzMVhCd0lEQVFBQm95Y3dKVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFIdkE5bVVxVGZEQ1VuRDBXQUs5Ni9na2VidnVlK0dUMTFMdApYV05RQTZoekN6MHhHck9pSDhGWTNLb3piZ215TTR5VzFwOEkvR29HVzNmSGl2OHVRTVdqZFFIbVBnZVc1cW9VCm54QlBrOXRuZm1RS2E1UGxEQllIdWFVR3owYzBCdW8zdklQbCs3cU91bkh2YUxUbTR5MnBmQ1ZXaFAraHFmSVUKY24weTdsTzlsbEczWU5ZTW01SEpjSFM1SkdZaEh5cm9JclZnN0NORE5Rak9kNVF3ZnRXVnlMMWVJbktzUEVUMApjV0tRMnNPcmZ2R0pIQ0l6R2tjdWhPM09kems5M0QwbnNrNG05OVlZZ3FpdFJqdWtsdldzOXpjd3pxc3hrQWNlCnZEM011Zzk4TFFSQ1Vxcm9CVldXK0JVb2FvTTZJVER3aDV3cDhuMmE3RVNJR052S096dz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= + client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBMFhVZlg2UmdGdVVMbElxZm5uMUpKTTNFL1U2TUVDM1VTTWlUU2VKdXREUS9ucFRKClVxTEtVc1VNbEJha2tDV254RFVMT3dENm9NblRiZWZWZFlad3YyMlN4UUQ0YjY3eWJNWUlZVXZhWDlVQkN1bzQKN29vZzdENitoMnVNZlE2dHgxVnpSTzlMYi9sK1N4M2xReEZCYXAvZVA2dys2a3NzVnoxUXgxNmt6RGhPNG5ETwpnaDdvYUtRNWk4SUhRSFgrMFNRWEhOVnJNVFZOOTZodEVOTytLVWU4R0Vyb0dCUzZLZzZaODJBOE8wRHo1a1NsCmsxZVVnTnhYZDBCV2VrOTBEU0lwZWRlTGhwTWlWcHBMZ1JlZmxpaFpsbmFkaDR2NGpsa1JPSzE0Y0tZNUl3WUsKNFR1UzduSkFJZ3RuUk5rZ1dQQ01ORFZ1eXVHRHZXZTh2czFYQndJREFRQUJBb0lCQVFDKzl5QzJpMkFNSDZHUwpPVnpVRy9mZTlUZ2Zsa2greTduYTdmdlRoZjFXa0xoY05kempXWVpMTmxxRWZheGx1OThjTlJ4YkhFWms1LzI3CkczNXpXekphWldWRjlkK0x1NTVNNjdSaU9NME5TRjlkK3pRU3o1NjZwVzRDZTF5bi9BVVdVdUw0TzQrMHRHeWYKd2M3dmVjRUJuR1g5K1dXWEtSaHhKWGNMZmsrVDNEQlE0c3hmOHlGVklPQnMrcW9tVUxHWnREK3Y2YUsyaGk5Zwp5VXE2aTN4R2k1ejZVMU04VmZGN0pJZWV6Y2EyVXVHeVdaeGZtK2JyQkZnaXZPZmYxVlZFdjRTWnVKc3RDSnAvClJNUEMwb2pEN2ptSjVEci9QbXM1MjdMYm9qK3o4TmV6TmJhZW8xVmlDYmtKVkM5ZmNKcm05SGlVWVM2dHZmRzEKRVl3ZUpXVWhBb0dCQU9wMlByeGFzTWYxSlR1Zk9NcjdMeE04NTh4bVN4RndGcnlzVUhOcVYxeW9mT0N3TjF5cQplVXNIbE92RnRLd2ZmaFJBSVJTWEhiMGI5aG84STZLQWY4ZmxOUmR3eENpbVhWeUs0NUQ2WklRMXg3V3hSUDdaCllQcVZKdFp6cWp2S1pWWENNaWZWdWUyd25tWS90NXlidzd1MUR6VGpqWjZ0QklMNXBKeUhJU1RSQW9HQkFPU3kKMjhYQUpKSDJVaDA5VnlIdkovR3NrbUxaMXE4VkxrSHpaTmtHWkcxalZVRmNDU2NISXFGeE9URWdkcnZGVkJwNwpaVjQ1K2Z2VmJlTnV6Y1cyN1FNT214dUVFcC9CVEhnb2FCdmY5djdxektsMjdpY3p4S0JGZVBpbWk2VEpVS2IzCm9UL3ZQZnhDNWw1QWVpSnFoOTRvVS9wTTQvaDdFclBMWjVJWmNaUlhBb0dBRGRId2VydkJ4ZGVPWFVoU1dheWEKcHNDbFRTZ09icld6c1dWYXpLTE5DWG9vK2ptSTJkNTJqZFNoazVBd3lTQ0dGdjE4dGJEK29NSUFMS1cwMkFSSgpBK2hmeThUcTJ4YUxWRVFmaTlFbWthQjE2Q0ROMTFQSzRwcGVFcS80cmRPTlM1UEp6dzFMQzFhb3o1QWI2NUJHCjVrNlMyZVE3MmNtTEJZbGZpWlp4ZnJFQ2dZQkFBTUk2dklRL2lTVC80OXZQdG1PQ1loNXhwYTlNUG13OHJzWXAKYW4yT2szOFhsSTlIS2RzS1BXcVpFaEhJaVBmNWxWRVFKcitNTi9YUjhYK0s5cCtyL0ZseVFPc0paSXBuRWovWQpsVHhGcVNadndzWHhtSzVOZ0VQVHFxQm9GS01LcDBDc2FPTDdCeW43ZEtYNW5jQzZicVRaNXN6aURHZDJnOVZQCmNPbDFid0tCZ0VSUG5xei9Jc3VhdnFhK1FxWG0wWWRycmd2VXBrU2J1a1hsZFVjSVhWR1ZvSDlaNGVmWXE5TnQKa21LQkduNHB2VVppR3hhNkhtd0hGOVRhUVMwbUI1R2dyQ0haQkZkbVVIS1Z1TTVSMVJwejkvR1owV3Fhd0x5YgpGWnVPV0RUa01YTzFNMG45VVV0K1pITDJ5a1gxc2tGdm1lNDNzZEZTTUNZVGhwV1dKd0tMCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg== diff --git a/spec/k8s/api_client_spec.rb b/spec/k8s/api_client_spec.rb index e8066f3..9397bd5 100644 --- a/spec/k8s/api_client_spec.rb +++ b/spec/k8s/api_client_spec.rb @@ -2,6 +2,7 @@ include FixtureHelpers let(:transport) { K8s::Transport.new('http://localhost:8080') } + let(:transport_with_prefix) { K8s::Transport.new('http://localhost:8080/k8s/clusters/c-dnmgm') } context "for the v1 API" do subject { described_class.new(transport, 'v1') } @@ -22,6 +23,20 @@ end end + context "for URIs with a path prefix" do + subject { described_class.new(transport_with_prefix, 'v1') } + + describe '#path' do + it "returns the correct root path" do + expect(subject.path).to eq '/k8s/clusters/c-dnmgm/api/v1' + end + + it "returns the correct resource path" do + expect(subject.path('tests')).to eq '/k8s/clusters/c-dnmgm/api/v1/tests' + end + end + end + before do stub_request(:get, 'localhost:8080/api/v1') .to_return( diff --git a/spec/k8s/transport_spec.rb b/spec/k8s/transport_spec.rb index f6f07ad..cd10394 100644 --- a/spec/k8s/transport_spec.rb +++ b/spec/k8s/transport_spec.rb @@ -11,6 +11,10 @@ expect(subject.server).to eq 'https://192.168.56.11:6443' end + it 'uses the correct path' do + expect(subject.path).to eq '/' + end + it 'uses the correct options' do expect(subject.options).to match( ssl_cert_store: OpenSSL::X509::Store, @@ -23,6 +27,30 @@ expect(subject.options[:ssl_cert_store].verify(server_cert)).to eq true end + context "for URIs with a path prefix" do + subject { described_class.config(K8s::Config.load_file(fixture_path('config/kubeadm-admin-with-path-prefix.conf')))} + + it 'uses the correct server' do + expect(subject.server).to eq 'https://192.168.56.11:6443' + end + + it 'uses the correct path' do + expect(subject.path).to eq '/k8s/clusters/c-dnmgm/' + end + + it 'uses the correct options' do + expect(subject.options).to match( + ssl_cert_store: OpenSSL::X509::Store, + client_cert_data: /^-----BEGIN CERTIFICATE-----\n/, + client_key_data: /^-----BEGIN RSA PRIVATE KEY-----\n/, + ) + end + + it 'uses an ssl_cert_store that verifies the server cert' do + expect(subject.options[:ssl_cert_store].verify(server_cert)).to eq true + end + end + context "overriding the server option" do subject { described_class.config(K8s::Config.load_file(fixture_path('config/kubeadm-admin.conf')), @@ -33,6 +61,21 @@ it "uses the overriden server" do expect(subject.server).to eq 'http://localhost:8001' end + + context "for URIs with a path prefix" do + subject { described_class.config(K8s::Config.load_file(fixture_path('config/kubeadm-admin-with-path-prefix.conf')), + server: 'http://localhost:8001', + ) + } + + it 'uses the correct server' do + expect(subject.server).to eq 'http://localhost:8001' + end + + it 'uses the correct path' do + expect(subject.path).to eq '/' + end + end end context "overriding other options" do