From ae86c2868f52d8b2919f868e03bb2692e04125f9 Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Tue, 13 Aug 2019 13:45:55 +0300 Subject: [PATCH 01/26] Create a service account and token during "pharos kubeconfig" --- lib/pharos/kube/config.rb | 8 +++--- lib/pharos/kubeconfig_command.rb | 49 +++++++++++++++++++++++++------- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/lib/pharos/kube/config.rb b/lib/pharos/kube/config.rb index f3df344dd..66a51399b 100644 --- a/lib/pharos/kube/config.rb +++ b/lib/pharos/kube/config.rb @@ -18,12 +18,12 @@ def initialize(content = nil) def config @config ||= yaml_content || { 'apiVersion' => 'v1', + 'kind' => 'Config', 'clusters' => [], 'contexts' => [], - 'current-context' => nil, - 'kind' => 'Config', + 'users' => [], 'preferences' => {}, - 'users' => [] + 'current-context' => nil } end alias to_h config @@ -31,7 +31,7 @@ def config # Convert to YAML # @return [String] def dump - YAML.dump(config) + YAML.dump(JSON.parse(JSON.dump(config))) # dereference to get rid of *1 &1 etc in output end alias to_s dump diff --git a/lib/pharos/kubeconfig_command.rb b/lib/pharos/kubeconfig_command.rb index ad1196c5b..4314d9096 100644 --- a/lib/pharos/kubeconfig_command.rb +++ b/lib/pharos/kubeconfig_command.rb @@ -4,8 +4,9 @@ module Pharos class KubeconfigCommand < Pharos::Command options :load_config, :tf_json - option ['-n', '--name'], 'NAME', 'overwrite cluster name', attribute_name: :new_name - option ['-C', '--context'], 'CONTEXT', 'overwrite context name', attribute_name: :new_context + option ['-n', '--name'], 'NAME', 'cluster name', attribute_name: :cluster_name, default: 'pharos-cluster' + option ['-C', '--context'], 'CONTEXT', 'context name', attribute_name: :context_name + option ['-u', '--user'], 'USER', 'user name', attribute_name: :user_name, default: 'pharos-admin' option ['-m', '--merge'], '[FILE]', 'merge with existing configuration file', multivalued: true REMOTE_FILE = "/etc/kubernetes/admin.conf" @@ -14,10 +15,32 @@ def execute Dir.chdir(config_yaml.dirname) do transport.connect - config = Pharos::Kube::Config.new(config_file_content) - config.rename_cluster(new_name) if new_name - config.rename_context(new_context) if new_context - config.update_server_address(master_host.api_address) + config = Pharos::Kube::Config.new + config.config['clusters'] << { + 'cluster' => { + 'certificate-authority-data' => certificate_authority_data, + 'server' => "https://#{master_host.api_address}:6443" + }, + 'name' => cluster_name + } + + config.config['users'] << { + 'user' => { + 'token' => create_or_update_sa_token + }, + 'name' => user_name + } + + config.config['contexts'] << { + 'context' => { + 'cluster' => cluster_name, + 'user' => 'pharos-admin' + }, + 'name' => context_name || "#{user_name}@#{cluster_name}" + } + + config.config['current-context'] = context_name || "#{user_name}@#{cluster_name}" + merge_list.each do |merge| merge_config = Pharos::Kube::Config.new(File.read(merge)) config << merge_config @@ -28,10 +51,16 @@ def execute private - def config_file_content - file = transport.file(REMOTE_FILE) - signal_usage_error "Remote file #{REMOTE_FILE} not found" unless file.exist? - file.read + # @return token [String] + def create_or_update_sa_token + transport.exec!("kubectl get -n kube-system serviceaccount/#{user_name} || kubectl -n kube-system create serviceaccount #{user_name}") + transport.exec!("kubectl get clusterrolebinding pharos-cluster-admin || kubectl create clusterrolebinding pharos-cluster-admin --clusterrole=cluster-admin --serviceaccount=kube-system:#{user_name}") + token_name = transport.exec!("kubectl -n kube-system get serviceaccount/#{user_name} -o jsonpath='{.secrets[0].name}'") + transport.exec!("kubectl -n kube-system get secret #{token_name} -o jsonpath='{.data.token}' | base64 -d") + end + + def certificate_authority_data + transport.exec!("kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.certificate-authority-data}'") end def master_host From ab3a1081778318dbdf444fbd98b8e26e42777521 Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 10:56:20 +0300 Subject: [PATCH 02/26] Revert kubeconfig and move to phase --- lib/pharos/cluster_manager.rb | 1 + lib/pharos/kubeconfig_command.rb | 49 ++------- .../phases/configure_service_account.rb | 103 ++++++++++++++++++ 3 files changed, 114 insertions(+), 39 deletions(-) create mode 100644 lib/pharos/phases/configure_service_account.rb diff --git a/lib/pharos/cluster_manager.rb b/lib/pharos/cluster_manager.rb index 0f36f8d6d..5884b8594 100644 --- a/lib/pharos/cluster_manager.rb +++ b/lib/pharos/cluster_manager.rb @@ -97,6 +97,7 @@ def apply_phases apply_phase(Phases::PullMasterImages, master_hosts, parallel: true) apply_phase(Phases::ConfigureMaster, master_hosts, parallel: false) + apply_phase(Phases::ConfigureServiceAccount, master_hosts, parallel: false) apply_phase(Phases::ConfigureClient, master_only, parallel: false) apply_phase(Phases::ReconfigureKubelet, config.hosts, parallel: true) diff --git a/lib/pharos/kubeconfig_command.rb b/lib/pharos/kubeconfig_command.rb index 4314d9096..ad1196c5b 100644 --- a/lib/pharos/kubeconfig_command.rb +++ b/lib/pharos/kubeconfig_command.rb @@ -4,9 +4,8 @@ module Pharos class KubeconfigCommand < Pharos::Command options :load_config, :tf_json - option ['-n', '--name'], 'NAME', 'cluster name', attribute_name: :cluster_name, default: 'pharos-cluster' - option ['-C', '--context'], 'CONTEXT', 'context name', attribute_name: :context_name - option ['-u', '--user'], 'USER', 'user name', attribute_name: :user_name, default: 'pharos-admin' + option ['-n', '--name'], 'NAME', 'overwrite cluster name', attribute_name: :new_name + option ['-C', '--context'], 'CONTEXT', 'overwrite context name', attribute_name: :new_context option ['-m', '--merge'], '[FILE]', 'merge with existing configuration file', multivalued: true REMOTE_FILE = "/etc/kubernetes/admin.conf" @@ -15,32 +14,10 @@ def execute Dir.chdir(config_yaml.dirname) do transport.connect - config = Pharos::Kube::Config.new - config.config['clusters'] << { - 'cluster' => { - 'certificate-authority-data' => certificate_authority_data, - 'server' => "https://#{master_host.api_address}:6443" - }, - 'name' => cluster_name - } - - config.config['users'] << { - 'user' => { - 'token' => create_or_update_sa_token - }, - 'name' => user_name - } - - config.config['contexts'] << { - 'context' => { - 'cluster' => cluster_name, - 'user' => 'pharos-admin' - }, - 'name' => context_name || "#{user_name}@#{cluster_name}" - } - - config.config['current-context'] = context_name || "#{user_name}@#{cluster_name}" - + config = Pharos::Kube::Config.new(config_file_content) + config.rename_cluster(new_name) if new_name + config.rename_context(new_context) if new_context + config.update_server_address(master_host.api_address) merge_list.each do |merge| merge_config = Pharos::Kube::Config.new(File.read(merge)) config << merge_config @@ -51,16 +28,10 @@ def execute private - # @return token [String] - def create_or_update_sa_token - transport.exec!("kubectl get -n kube-system serviceaccount/#{user_name} || kubectl -n kube-system create serviceaccount #{user_name}") - transport.exec!("kubectl get clusterrolebinding pharos-cluster-admin || kubectl create clusterrolebinding pharos-cluster-admin --clusterrole=cluster-admin --serviceaccount=kube-system:#{user_name}") - token_name = transport.exec!("kubectl -n kube-system get serviceaccount/#{user_name} -o jsonpath='{.secrets[0].name}'") - transport.exec!("kubectl -n kube-system get secret #{token_name} -o jsonpath='{.data.token}' | base64 -d") - end - - def certificate_authority_data - transport.exec!("kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.certificate-authority-data}'") + def config_file_content + file = transport.file(REMOTE_FILE) + signal_usage_error "Remote file #{REMOTE_FILE} not found" unless file.exist? + file.read end def master_host diff --git a/lib/pharos/phases/configure_service_account.rb b/lib/pharos/phases/configure_service_account.rb new file mode 100644 index 000000000..16ecf2c15 --- /dev/null +++ b/lib/pharos/phases/configure_service_account.rb @@ -0,0 +1,103 @@ +# frozen_string_literal: true + +module Pharos + module Phases + class ConfigureServiceAccount < Pharos::Phase + title "Configure 'pharos-admin' service account" + + ADMIN_USER = 'pharos-admin' + KUBECONFIG_PARAM = '--kubeconfig=/etc/kubernetes/admin.conf' + + def call + create_service_account + create_cluster_role_binding + + config = build_config + + if config_file.exist? + existing_config = Pharos::Kube::Config.new(config_file.read) + config << existing_config + end + + config_file.write(config.dump, overwrite: true) + config_file.chmod('0600') + + validate + end + + def validate + transport.exec!('kubectl get -n kube-system serviceaccount/pharos-admin') + end + + def config_file + @config_file ||= transport.file(File.join(home_kube_dir.path, 'config')) + end + + def home_kube_dir + transport.file(transport.file('~/.kube').readlink(escape: false, canonicalize: true)).tap do |dir| + transport.exec!("mkdir '#{dir}' && chmod 0700 '#{dir}") unless dir.exist? + end + end + + def create_service_account + transport.exec!("sudo kubectl get #{KUBECONFIG_PARAM} -n kube-system serviceaccount/#{ADMIN_USER} || sudo kubectl #{KUBECONFIG_PARAM} -n kube-system create serviceaccount #{ADMIN_USER}") + end + + def create_cluster_role_binding + transport.exec!("sudo kubectl get #{KUBECONFIG_PARAM} clusterrolebinding pharos-cluster-admin || sudo kubectl create #{KUBECONFIG_PARAM} clusterrolebinding pharos-cluster-admin --clusterrole=cluster-admin --serviceaccount=kube-system:#{ADMIN_USER}") + end + + # @return token_name [String] + def token_name + transport.exec!("sudo kubectl -n kube-system #{KUBECONFIG_PARAM} get serviceaccount/#{ADMIN_USER} -o jsonpath='{.secrets[0].name}'") + end + + # @return token [String] + def token + @token ||= transport.exec!("sudo kubectl -n kube-system #{KUBECONFIG_PARAM} get secret #{token_name} -o jsonpath='{.data.token}' | base64 -d") + end + + # @return [Pharos::Kube::Config] + def build_config + config = Pharos::Kube::Config.new + config.config['clusters'] << { + 'cluster' => { + 'certificate-authority-data' => certificate_authority_data, + 'server' => "https://#{master_host.api_address}:6443" + }, + 'name' => @config.name + } + + config.config['users'] << { + 'user' => { + 'token' => token + }, + 'name' => ADMIN_USER + } + + config.config['contexts'] << { + 'context' => { + 'cluster' => @config.name, + 'user' => ADMIN_USER + }, + 'name' => context_name + } + + config.config['current-context'] = context_name + + config + end + + # @return [String] + def context_name + @context_name ||= "#{ADMIN_USER}@#{@config.name}" + end + + # @return [String] + def certificate_authority_data + transport.exec!("sudo kubectl config view #{KUBECONFIG_PARAM} --raw --minify --flatten -o jsonpath='{.clusters[].cluster.certificate-authority-data}'") + end + end + end +end + From e9fc1654bb8e376b615a4d7bb27a01a8fca00fb2 Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 10:56:59 +0300 Subject: [PATCH 03/26] Transport file fixes to support overwriting and path expansion --- lib/pharos/transport/transport_file.rb | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/pharos/transport/transport_file.rb b/lib/pharos/transport/transport_file.rb index 2f31aef9a..9c6296d14 100644 --- a/lib/pharos/transport/transport_file.rb +++ b/lib/pharos/transport/transport_file.rb @@ -37,12 +37,13 @@ def dirname end # @param content [String] + # @param overwrite [Boolean] use force to overwrite target # @return [Pharos::Transport::Command::Result] # @raise [Pharos::ExecError] - def write(content) + def write(content, overwrite: false) tmp = temp_file_path.shellescape @client.exec!( - "cat > #{tmp} && (sudo mv #{tmp} #{escaped_path} || (rm #{tmp}; exit 1))", + "cat > #{tmp} && (sudo mv #{'-f ' if overwrite}#{tmp} #{escaped_path} || (rm -f #{tmp}; exit 1))", stdin: content ) end @@ -76,10 +77,11 @@ def with_existing # Moves the current file to target path # @param target [String] + # @param overwrite [Boolean] use force to overwrite target # @return [Pharos::Transport::Command::Result] # @raise [Pharos::ExecError] - def move(target) - @client.exec!("sudo mv #{@path} #{target.shellescape}") + def move(target, overwrite: false) + @client.exec!("sudo mv #{'-f ' if overwrite}#{@path} #{target.shellescape}") end alias mv move @@ -100,10 +102,12 @@ def link(target) @client.exec!("sudo ln -s #{escaped_path} #{target.shellescape}") end + # @param escape [Boolean] escape file path + # @param canonicalize [Boolean] canonicalize by following every symlink in every component of the file name recursively; all but the last component must exist # @return [String, nil] # @raise [Pharos::ExecError] - def readlink - target = @client.exec!("readlink #{escaped_path} || echo").strip + def readlink(escape: true, canonicalize: false) + target = @client.exec!("readlink #{'-f ' if canonicalize}#{escape ? escaped_path : @path} || echo").strip return nil if target.empty? From 32d69bc41d99f078772edcab8af58999b4efe8bd Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 10:57:14 +0300 Subject: [PATCH 04/26] Trailing blank --- lib/pharos/phases/configure_service_account.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/pharos/phases/configure_service_account.rb b/lib/pharos/phases/configure_service_account.rb index 16ecf2c15..f905fda17 100644 --- a/lib/pharos/phases/configure_service_account.rb +++ b/lib/pharos/phases/configure_service_account.rb @@ -100,4 +100,3 @@ def certificate_authority_data end end end - From 074adb4bcf3999acffbcf37f06768b0587d7a843 Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 11:03:57 +0300 Subject: [PATCH 05/26] Skip installing a copy of /etc/kubernetes/admin.conf to home --- lib/pharos/phases/configure_master.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/pharos/phases/configure_master.rb b/lib/pharos/phases/configure_master.rb index 6347d8852..34db64e56 100644 --- a/lib/pharos/phases/configure_master.rb +++ b/lib/pharos/phases/configure_master.rb @@ -54,7 +54,6 @@ def install def install_kubeconfig transport.exec!('install -m 0700 -d ~/.kube') - transport.exec!('sudo install -o $USER -m 0600 /etc/kubernetes/admin.conf ~/.kube/config') end def reconfigure From 3b37658b5c3bd687435b75f33e6da69761076878 Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 11:31:21 +0300 Subject: [PATCH 06/26] Add expand option to transport.file --- lib/pharos/phases/configure_service_account.rb | 2 +- lib/pharos/transport/base.rb | 5 +++-- lib/pharos/transport/transport_file.rb | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/pharos/phases/configure_service_account.rb b/lib/pharos/phases/configure_service_account.rb index f905fda17..fee755448 100644 --- a/lib/pharos/phases/configure_service_account.rb +++ b/lib/pharos/phases/configure_service_account.rb @@ -34,7 +34,7 @@ def config_file end def home_kube_dir - transport.file(transport.file('~/.kube').readlink(escape: false, canonicalize: true)).tap do |dir| + transport.file('~/.kube', expand: true).tap do |dir| transport.exec!("mkdir '#{dir}' && chmod 0700 '#{dir}") unless dir.exist? end end diff --git a/lib/pharos/transport/base.rb b/lib/pharos/transport/base.rb index c86c9a020..fc97926e3 100644 --- a/lib/pharos/transport/base.rb +++ b/lib/pharos/transport/base.rb @@ -90,9 +90,10 @@ def exec?(cmd, **options) end # @param path [String] + # @param (see Pharos::Transport::TransportFile#initialize) # @return [Pathname] - def file(path) - Pharos::Transport::TransportFile.new(self, path) + def file(path, **options) + Pharos::Transport::TransportFile.new(self, path, **options) end def closed? diff --git a/lib/pharos/transport/transport_file.rb b/lib/pharos/transport/transport_file.rb index 9c6296d14..b07fe9aa6 100644 --- a/lib/pharos/transport/transport_file.rb +++ b/lib/pharos/transport/transport_file.rb @@ -10,9 +10,9 @@ class TransportFile # Initializes an instance of a remote file # @param [Pharos::Transport::Base] # @param path [String] - def initialize(client, path) + def initialize(client, path, expand: false) @client = client - @path = path + @path = expand ? self.class.new(client, path).readlink(escape: false, canonicalize: true) : path freeze end From c59ae397e7258510841892b190d3b1e6e60d7d80 Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 11:31:55 +0300 Subject: [PATCH 07/26] Prefer ~/.kube/config in ConfigureClient --- lib/pharos/phases/configure_client.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/pharos/phases/configure_client.rb b/lib/pharos/phases/configure_client.rb index ca720817a..d96be4fc7 100644 --- a/lib/pharos/phases/configure_client.rb +++ b/lib/pharos/phases/configure_client.rb @@ -21,7 +21,11 @@ def call end def kubeconfig - @kubeconfig ||= transport.file(REMOTE_FILE) + @kubeconfig ||= user_config.exist? ? user_config : transport.file(REMOTE_FILE) + end + + def user_config + @user_config ||= transport.file('~/.kube/config', expand: true) end # @return [String] From 39b7d446620dce4b522aa2e6f66ea4cddff223fe Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 11:37:59 +0300 Subject: [PATCH 08/26] Simpler expand --- lib/pharos/transport/transport_file.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pharos/transport/transport_file.rb b/lib/pharos/transport/transport_file.rb index b07fe9aa6..4527b4f11 100644 --- a/lib/pharos/transport/transport_file.rb +++ b/lib/pharos/transport/transport_file.rb @@ -12,7 +12,9 @@ class TransportFile # @param path [String] def initialize(client, path, expand: false) @client = client - @path = expand ? self.class.new(client, path).readlink(escape: false, canonicalize: true) : path + @path = path + @path = readlink(escape: false, canonicalize: true) if expand + freeze end From 5be5ced1e38fde9e99640f6627bd196ae6bdd473 Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 11:44:27 +0300 Subject: [PATCH 09/26] Why it no work [cluster-e2e] --- lib/pharos/transport/transport_file.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pharos/transport/transport_file.rb b/lib/pharos/transport/transport_file.rb index 4527b4f11..1934dadec 100644 --- a/lib/pharos/transport/transport_file.rb +++ b/lib/pharos/transport/transport_file.rb @@ -13,7 +13,7 @@ class TransportFile def initialize(client, path, expand: false) @client = client @path = path - @path = readlink(escape: false, canonicalize: true) if expand + @path.replace(readlink(escape: false, canonicalize: true)) if expand freeze end From f70d81f01cdb447a7fe42e81f579b56814d74193 Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 11:46:48 +0300 Subject: [PATCH 10/26] Cant modify frozen string [cluster-e2e] --- lib/pharos/transport/transport_file.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pharos/transport/transport_file.rb b/lib/pharos/transport/transport_file.rb index 1934dadec..514e6d288 100644 --- a/lib/pharos/transport/transport_file.rb +++ b/lib/pharos/transport/transport_file.rb @@ -12,8 +12,9 @@ class TransportFile # @param path [String] def initialize(client, path, expand: false) @client = client - @path = path + @path = path.dup @path.replace(readlink(escape: false, canonicalize: true)) if expand + @path.freeze freeze end From dc6e523fa4374ffec006d580051b60ec601f3d3a Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 11:52:05 +0300 Subject: [PATCH 11/26] Recomplexify [cluster-e2e] --- lib/pharos/transport/transport_file.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/pharos/transport/transport_file.rb b/lib/pharos/transport/transport_file.rb index 514e6d288..3acada9ee 100644 --- a/lib/pharos/transport/transport_file.rb +++ b/lib/pharos/transport/transport_file.rb @@ -12,8 +12,7 @@ class TransportFile # @param path [String] def initialize(client, path, expand: false) @client = client - @path = path.dup - @path.replace(readlink(escape: false, canonicalize: true)) if expand + @path = expand ? (self.class.new(path).readlink(escape: false, canonicalize: true) || path) : path @path.freeze freeze From c0b727895fc0d09ca35ca7e3b568cbadca56b0db Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 11:54:47 +0300 Subject: [PATCH 12/26] Spec dont like expand [cluster-e2e] --- spec/pharos/phases/configure_client_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/pharos/phases/configure_client_spec.rb b/spec/pharos/phases/configure_client_spec.rb index 82017963c..98f0d7ed1 100644 --- a/spec/pharos/phases/configure_client_spec.rb +++ b/spec/pharos/phases/configure_client_spec.rb @@ -23,7 +23,7 @@ before(:each) do allow(host).to receive(:master_sort_score).and_return(0) allow(host).to receive(:transport).and_return(transport) - allow(transport).to receive(:file).with('/etc/kubernetes/admin.conf').and_return(remote_file) + allow(transport).to receive(:file).with('/etc/kubernetes/admin.conf', expand: true).and_return(remote_file) allow(remote_file).to receive(:exist?).and_return(true) allow(kubeclient).to receive(:apis) allow(K8s::Config).to receive(:new).and_return(k8s_config) From e18ead5fcaf938ab2692c101cc9908cde6d753fa Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 11:58:15 +0300 Subject: [PATCH 13/26] More spec fix [cluster-e2e] --- spec/pharos/phases/configure_client_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/pharos/phases/configure_client_spec.rb b/spec/pharos/phases/configure_client_spec.rb index 98f0d7ed1..495980a58 100644 --- a/spec/pharos/phases/configure_client_spec.rb +++ b/spec/pharos/phases/configure_client_spec.rb @@ -23,7 +23,8 @@ before(:each) do allow(host).to receive(:master_sort_score).and_return(0) allow(host).to receive(:transport).and_return(transport) - allow(transport).to receive(:file).with('/etc/kubernetes/admin.conf', expand: true).and_return(remote_file) + allow(transport).to receive(:file).with('~/.kube/config', expand: true).and_return(double(exist?: false)) + allow(transport).to receive(:file).with('/etc/kubernetes/admin.conf').and_return(remote_file) allow(remote_file).to receive(:exist?).and_return(true) allow(kubeclient).to receive(:apis) allow(K8s::Config).to receive(:new).and_return(k8s_config) From ddd82af9f3e8a761de5126a01efdfd3377100403 Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 12:02:14 +0300 Subject: [PATCH 14/26] More fix [cluster-e2e] --- lib/pharos/transport/transport_file.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pharos/transport/transport_file.rb b/lib/pharos/transport/transport_file.rb index 3acada9ee..76699a7bd 100644 --- a/lib/pharos/transport/transport_file.rb +++ b/lib/pharos/transport/transport_file.rb @@ -12,7 +12,7 @@ class TransportFile # @param path [String] def initialize(client, path, expand: false) @client = client - @path = expand ? (self.class.new(path).readlink(escape: false, canonicalize: true) || path) : path + @path = expand ? (self.class.new(client, path).readlink(escape: false, canonicalize: true) || path) : path @path.freeze freeze From 890788fd176b75945677c874394bf7ea38af69b7 Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 12:10:33 +0300 Subject: [PATCH 15/26] Add clarifying comments [cluster-e2e] --- lib/pharos/phases/configure_service_account.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/pharos/phases/configure_service_account.rb b/lib/pharos/phases/configure_service_account.rb index fee755448..83db96acd 100644 --- a/lib/pharos/phases/configure_service_account.rb +++ b/lib/pharos/phases/configure_service_account.rb @@ -26,6 +26,7 @@ def call end def validate + # Validates that "kubectl" without sudo or setting KUBECONFIG / --kubeconfig works on the host transport.exec!('kubectl get -n kube-system serviceaccount/pharos-admin') end @@ -33,12 +34,14 @@ def config_file @config_file ||= transport.file(File.join(home_kube_dir.path, 'config')) end + # Get a real path to ~/.kube and mkdir + chmod it unless exists def home_kube_dir transport.file('~/.kube', expand: true).tap do |dir| transport.exec!("mkdir '#{dir}' && chmod 0700 '#{dir}") unless dir.exist? end end + # Sudo used because /etc/kubernetes/admin.conf is not user-readable def create_service_account transport.exec!("sudo kubectl get #{KUBECONFIG_PARAM} -n kube-system serviceaccount/#{ADMIN_USER} || sudo kubectl #{KUBECONFIG_PARAM} -n kube-system create serviceaccount #{ADMIN_USER}") end @@ -95,6 +98,7 @@ def context_name # @return [String] def certificate_authority_data + # --flatten expands relative paths, --minify cleans out everything but the stuff needed by current_context transport.exec!("sudo kubectl config view #{KUBECONFIG_PARAM} --raw --minify --flatten -o jsonpath='{.clusters[].cluster.certificate-authority-data}'") end end From b08de30140a34adeb6cbfcd845dfbcb2a1593c4a Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 13:35:43 +0300 Subject: [PATCH 16/26] Update yardoc and retrigger e2e [cluster-e2e] --- lib/pharos/transport/transport_file.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pharos/transport/transport_file.rb b/lib/pharos/transport/transport_file.rb index 76699a7bd..4f7c908b3 100644 --- a/lib/pharos/transport/transport_file.rb +++ b/lib/pharos/transport/transport_file.rb @@ -9,6 +9,7 @@ class TransportFile attr_reader :path # Initializes an instance of a remote file # @param [Pharos::Transport::Base] + # @param expand [Boolean] when true, relative and special paths like ~/.kube or $HOME/xyz will be converted to real paths # @param path [String] def initialize(client, path, expand: false) @client = client From 324c8edb8393ddfe5b6fae33219670cfa748249b Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 13:59:37 +0300 Subject: [PATCH 17/26] Use const [cluster-e2e] --- lib/pharos/phases/configure_service_account.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pharos/phases/configure_service_account.rb b/lib/pharos/phases/configure_service_account.rb index 83db96acd..fce2b8a81 100644 --- a/lib/pharos/phases/configure_service_account.rb +++ b/lib/pharos/phases/configure_service_account.rb @@ -27,7 +27,7 @@ def call def validate # Validates that "kubectl" without sudo or setting KUBECONFIG / --kubeconfig works on the host - transport.exec!('kubectl get -n kube-system serviceaccount/pharos-admin') + transport.exec!("kubectl get -n kube-system serviceaccount/#{ADMIN_USER}") end def config_file From 888c5b994e96ede0f80c32083024d07e0617e52a Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 14:17:20 +0300 Subject: [PATCH 18/26] Adding log messages to make sense of e2e failure [cluster-e2e] --- lib/pharos/phases/configure_service_account.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/pharos/phases/configure_service_account.rb b/lib/pharos/phases/configure_service_account.rb index fce2b8a81..741926a76 100644 --- a/lib/pharos/phases/configure_service_account.rb +++ b/lib/pharos/phases/configure_service_account.rb @@ -9,19 +9,25 @@ class ConfigureServiceAccount < Pharos::Phase KUBECONFIG_PARAM = '--kubeconfig=/etc/kubernetes/admin.conf' def call + logger.info "Creating service account" create_service_account + logger.info "Creating cluster role binding" create_cluster_role_binding + logger.info "Building configuration" config = build_config if config_file.exist? + logger.info "Merging existing configuration" existing_config = Pharos::Kube::Config.new(config_file.read) config << existing_config end + logger.info "Writing configuration file" config_file.write(config.dump, overwrite: true) config_file.chmod('0600') + logger.info "Validating that new configuration works" validate end From 6a7e4e5c44f6cac1b5b4297834c6cb33e9789063 Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 14:30:54 +0300 Subject: [PATCH 19/26] And what does the config look like? [cluster-e2e] --- lib/pharos/phases/configure_service_account.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pharos/phases/configure_service_account.rb b/lib/pharos/phases/configure_service_account.rb index 741926a76..7f5c49548 100644 --- a/lib/pharos/phases/configure_service_account.rb +++ b/lib/pharos/phases/configure_service_account.rb @@ -27,6 +27,7 @@ def call config_file.write(config.dump, overwrite: true) config_file.chmod('0600') + logger.info transport.exec('cat ~/.kube/config') logger.info "Validating that new configuration works" validate end From 5e4f46695dac9faa8806b4fa3fce8a13b20a95b9 Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 15:14:37 +0300 Subject: [PATCH 20/26] bang [cluster-e2e] --- lib/pharos/phases/configure_service_account.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pharos/phases/configure_service_account.rb b/lib/pharos/phases/configure_service_account.rb index 7f5c49548..79ca497d2 100644 --- a/lib/pharos/phases/configure_service_account.rb +++ b/lib/pharos/phases/configure_service_account.rb @@ -27,7 +27,7 @@ def call config_file.write(config.dump, overwrite: true) config_file.chmod('0600') - logger.info transport.exec('cat ~/.kube/config') + logger.info transport.exec!('cat ~/.kube/config') logger.info "Validating that new configuration works" validate end From 986c2a4c064035d5de0b53578a8003e14ef41e74 Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 15:39:26 +0300 Subject: [PATCH 21/26] Less noise, retrigger e2e [cluster-e2e] --- lib/pharos/phases/configure_service_account.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/pharos/phases/configure_service_account.rb b/lib/pharos/phases/configure_service_account.rb index 79ca497d2..c36d45bae 100644 --- a/lib/pharos/phases/configure_service_account.rb +++ b/lib/pharos/phases/configure_service_account.rb @@ -14,7 +14,6 @@ def call logger.info "Creating cluster role binding" create_cluster_role_binding - logger.info "Building configuration" config = build_config if config_file.exist? From c23f89c74ba0254cfb23b58b19dc9b450b4df64c Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 14 Aug 2019 15:58:34 +0300 Subject: [PATCH 22/26] Slight tweak. I dont know why this fails on drone. [cluster-e2e] --- lib/pharos/phases/configure_service_account.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pharos/phases/configure_service_account.rb b/lib/pharos/phases/configure_service_account.rb index c36d45bae..db1b9c115 100644 --- a/lib/pharos/phases/configure_service_account.rb +++ b/lib/pharos/phases/configure_service_account.rb @@ -53,7 +53,7 @@ def create_service_account end def create_cluster_role_binding - transport.exec!("sudo kubectl get #{KUBECONFIG_PARAM} clusterrolebinding pharos-cluster-admin || sudo kubectl create #{KUBECONFIG_PARAM} clusterrolebinding pharos-cluster-admin --clusterrole=cluster-admin --serviceaccount=kube-system:#{ADMIN_USER}") + transport.exec!("sudo kubectl get #{KUBECONFIG_PARAM} -n kube-system clusterrolebinding/pharos-cluster-admin || sudo kubectl create #{KUBECONFIG_PARAM} -n kube-system clusterrolebinding pharos-cluster-admin --clusterrole=cluster-admin --serviceaccount=kube-system:#{ADMIN_USER}") end # @return token_name [String] From 053ffabc08547522e31ff615b3115e4d36191be6 Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Thu, 15 Aug 2019 07:57:01 +0300 Subject: [PATCH 23/26] Display host env [cluster-e2e] --- e2e/drone.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/e2e/drone.sh b/e2e/drone.sh index 14147b56f..e858306b3 100755 --- a/e2e/drone.sh +++ b/e2e/drone.sh @@ -25,6 +25,10 @@ pharos version || exit $? pharos license assign --help || exit $? pharos license inspect --help || exit $? +# Display host env +echo "Host env:" +(pharos exec --role master -c e2e/digitalocean/cluster.yml --tf-json e2e/digitalocean/tf.json -- "env") || exit $? + # Test cluster bootstrapping timeout 700 pharos up -y -c e2e/digitalocean/cluster.yml --tf-json e2e/digitalocean/tf.json || exit $? (pharos kubeconfig -c e2e/digitalocean/cluster.yml --tf-json e2e/digitalocean/tf.json > kubeconfig.e2e) || exit $? From 2701644b77cfb75d9af676043680896275d8acb1 Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Thu, 15 Aug 2019 08:30:44 +0300 Subject: [PATCH 24/26] Try with --kubeconfig [cluster-e2e] --- e2e/drone.sh | 4 ---- lib/pharos/phases/configure_service_account.rb | 5 ++--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/e2e/drone.sh b/e2e/drone.sh index e858306b3..14147b56f 100755 --- a/e2e/drone.sh +++ b/e2e/drone.sh @@ -25,10 +25,6 @@ pharos version || exit $? pharos license assign --help || exit $? pharos license inspect --help || exit $? -# Display host env -echo "Host env:" -(pharos exec --role master -c e2e/digitalocean/cluster.yml --tf-json e2e/digitalocean/tf.json -- "env") || exit $? - # Test cluster bootstrapping timeout 700 pharos up -y -c e2e/digitalocean/cluster.yml --tf-json e2e/digitalocean/tf.json || exit $? (pharos kubeconfig -c e2e/digitalocean/cluster.yml --tf-json e2e/digitalocean/tf.json > kubeconfig.e2e) || exit $? diff --git a/lib/pharos/phases/configure_service_account.rb b/lib/pharos/phases/configure_service_account.rb index db1b9c115..65415046d 100644 --- a/lib/pharos/phases/configure_service_account.rb +++ b/lib/pharos/phases/configure_service_account.rb @@ -22,18 +22,17 @@ def call config << existing_config end - logger.info "Writing configuration file" + logger.info "Writing configuration file to #{config_file.path}" config_file.write(config.dump, overwrite: true) config_file.chmod('0600') - logger.info transport.exec!('cat ~/.kube/config') logger.info "Validating that new configuration works" validate end def validate # Validates that "kubectl" without sudo or setting KUBECONFIG / --kubeconfig works on the host - transport.exec!("kubectl get -n kube-system serviceaccount/#{ADMIN_USER}") + transport.exec!("kubectl get --kubeconfig=~/.kube/config -n kube-system serviceaccount/#{ADMIN_USER}") end def config_file From 1792003c0c732806471996c55656ef5cd156b04e Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Thu, 15 Aug 2019 08:43:06 +0300 Subject: [PATCH 25/26] Debug [cluster-e2e] --- lib/pharos/phases/configure_service_account.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pharos/phases/configure_service_account.rb b/lib/pharos/phases/configure_service_account.rb index 65415046d..534c56552 100644 --- a/lib/pharos/phases/configure_service_account.rb +++ b/lib/pharos/phases/configure_service_account.rb @@ -32,7 +32,7 @@ def call def validate # Validates that "kubectl" without sudo or setting KUBECONFIG / --kubeconfig works on the host - transport.exec!("kubectl get --kubeconfig=~/.kube/config -n kube-system serviceaccount/#{ADMIN_USER}") + transport.exec!("kubectl get --kubeconfig=/root/.kube/config -n kube-system serviceaccount/#{ADMIN_USER}") end def config_file From a91e213f6a3e336341bb970dc20557a6d5c91a0d Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Wed, 21 Aug 2019 12:02:22 +0300 Subject: [PATCH 26/26] Retrigger e2e [cluster-e2e] --- lib/pharos/phases/configure_service_account.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/pharos/phases/configure_service_account.rb b/lib/pharos/phases/configure_service_account.rb index 534c56552..e67e69b3e 100644 --- a/lib/pharos/phases/configure_service_account.rb +++ b/lib/pharos/phases/configure_service_account.rb @@ -22,11 +22,10 @@ def call config << existing_config end - logger.info "Writing configuration file to #{config_file.path}" config_file.write(config.dump, overwrite: true) config_file.chmod('0600') - logger.info "Validating that new configuration works" + logger.info "Testing new configuration" validate end