diff --git a/e2e/digitalocean/main.tf b/e2e/digitalocean/main.tf index 37f5b4837..d1018d72c 100644 --- a/e2e/digitalocean/main.tf +++ b/e2e/digitalocean/main.tf @@ -41,7 +41,7 @@ resource "tls_private_key" "ssh_key" { resource "local_file" "ssh_key" { sensitive_content = "${tls_private_key.ssh_key.private_key_pem}" - filename = "ssh_key.pem" + filename = "${path.module}/ssh_key.pem" provisioner "local-exec" { command = "chmod 0600 ${local_file.ssh_key.filename}" } @@ -111,7 +111,7 @@ output "pharos_hosts" { private_address = "${digitalocean_droplet.pharos_master.*.ipv4_address_private}" role = "master" user = "root" - ssh_key_path = "./ssh_key.pem" + ssh_key_path = "${local_file.ssh_key.filename}" label = { "beta.kubernetes.io/instance-type" = "${var.worker_size}" @@ -133,10 +133,10 @@ output "pharos_hosts" { private_address = "${digitalocean_droplet.pharos_worker.*.ipv4_address_private}" role = "worker" user = "root" - ssh_key_path = "./ssh_key.pem" + ssh_key_path = "${local_file.ssh_key.filename}" bastion = { address = "${digitalocean_droplet.pharos_master.*.ipv4_address[0]}" - ssh_key_path = "./ssh_key.pem" + ssh_key_path = "${local_file.ssh_key.filename}" user = "root" } diff --git a/e2e/digitalocean/terraform-0.12/main.tf b/e2e/digitalocean/terraform-0.12/main.tf index ad88d7d10..86a7198e2 100644 --- a/e2e/digitalocean/terraform-0.12/main.tf +++ b/e2e/digitalocean/terraform-0.12/main.tf @@ -44,7 +44,7 @@ resource "tls_private_key" "ssh_key" { resource "local_file" "ssh_key" { sensitive_content = tls_private_key.ssh_key.private_key_pem - filename = "ssh_key.pem" + filename = "${path.module}/ssh_key.pem" provisioner "local-exec" { command = "chmod 0600 ${local_file.ssh_key.filename}" } @@ -126,7 +126,7 @@ output "pharos_cluster" { private_address = host.droplet.ipv4_address_private role = host.role user = "root" - ssh_key_path = "./ssh_key.pem" + ssh_key_path = "${local_file.ssh_key.filename}" label = { "beta.kubernetes.io/instance-type" = "${host.droplet.size}" diff --git a/lib/pharos/command_options/load_config.rb b/lib/pharos/command_options/load_config.rb index a67e87ace..33dd15686 100644 --- a/lib/pharos/command_options/load_config.rb +++ b/lib/pharos/command_options/load_config.rb @@ -4,6 +4,7 @@ module Pharos module CommandOptions module LoadConfig using Pharos::CoreExt::Colorize + using Pharos::CoreExt::DeepTransformKeys def self.included(base) base.prepend(InstanceMethods) @@ -56,7 +57,7 @@ def load_config(master_only: false) puts("==> Reading instructions ...".green) if $stdout.tty? - config_hash = config_yaml.load(ENV.to_h) + config_hash = config_yaml.load(ENV.to_h).deep_stringify_keys load_external_config(config_hash) diff --git a/lib/pharos/command_options/tf_json.rb b/lib/pharos/command_options/tf_json.rb index 4df519443..f98e5ed83 100644 --- a/lib/pharos/command_options/tf_json.rb +++ b/lib/pharos/command_options/tf_json.rb @@ -4,6 +4,7 @@ module Pharos module CommandOptions module TfJson using Pharos::CoreExt::Colorize + using Pharos::CoreExt::DeepTransformKeys using K8s::Util::HashDeepMerge def self.included(base) @@ -12,7 +13,7 @@ def self.included(base) base.option '--tf-json', 'PATH', 'path to terraform output json' do |config_path| @config_options ||= [] @config_options.concat(['--tf-json', config_path]) - File.realpath(config_path) + File.expand_path(config_path) rescue Errno::ENOENT signal_usage_error 'File does not exist: %s' % { path: config_path } end @@ -32,30 +33,42 @@ def load_external_config(config_hash) def load_terraform(file, config) puts("==> Importing configuration from Terraform ...".green) if $stdout.tty? - json = File.read(file) - tf_parser = Pharos::Terraform::JsonParser.new(json) - if tf_parser.valid? - config.deep_merge!( - tf_parser.cluster, - overwrite_arrays: false, - union_arrays: true - ) - else - tf_parser = Pharos::Terraform::LegacyJsonParser.new(json) - config['hosts'] ||= [] - config['api'] ||= {} - config['addons'] ||= {} - config['hosts'].concat(tf_parser.hosts) - config['api'].merge!(tf_parser.api) if tf_parser.api - config['name'] ||= tf_parser.cluster_name if tf_parser.cluster_name - config['addons'].each do |name, conf| - if addon_config = tf_parser.addons[name] - conf.merge!(addon_config) + Dir.chdir(File.dirname(file)) do + json = File.read(file) + tf_parser = Pharos::Terraform::JsonParser.new(json) + if tf_parser.valid? + config.deep_merge!( + tf_parser.cluster, + overwrite_arrays: false, + union_arrays: true + ) + else + tf_parser = Pharos::Terraform::LegacyJsonParser.new(json) + config['hosts'] ||= [] + config['api'] ||= {} + config['addons'] ||= {} + config['hosts'].concat(tf_parser.hosts) + config['api'].merge!(tf_parser.api) if tf_parser.api + config['name'] ||= tf_parser.cluster_name if tf_parser.cluster_name + tf_parser.addons.each do |name, conf| + if config['addons'][name] + config['addons'][name].merge!(conf) + else + config['addons'][name] = conf + end end end - end - config + config.deep_stringify_keys! + + config['hosts'].each do |host| + host['ssh_key_path'] = File.expand_path(host['ssh_key_path']) if host['ssh_key_path'] + + next unless host.dig('bastion', 'ssh_key_path') + + host['bastion']['ssh_key_path'] = File.expand_path(host['bastion']['ssh_key_path']) + end + end end end end diff --git a/lib/pharos/config_schema.rb b/lib/pharos/config_schema.rb index d879f57e9..c56a95339 100644 --- a/lib/pharos/config_schema.rb +++ b/lib/pharos/config_schema.rb @@ -43,6 +43,10 @@ module HostPredicates predicate(:hostname_or_ip?) do |value| value.match?(/\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\z/) || value.match?(/\A[a-z0-9\-\.]+\z/) end + + predicate(:file_exist?) do |value| + File.exist?(File.expand_path(value)) + end end # @return [Dry::Validation::Schema] @@ -56,6 +60,7 @@ def self.messages errors: { network_dns_replicas: "network.dns_replicas cannot be larger than the number of hosts", hostname_or_ip?: "is invalid", + file_exist?: "file %{value} does not exist", unique_addresses?: "duplicate address:ssh_port" } } @@ -84,7 +89,7 @@ def unique_addresses?(hosts) end end optional(:user).filled - optional(:ssh_key_path).filled + optional(:ssh_key_path).filled(:str?, :file_exist?) optional(:ssh_port).filled(:int?, gt?: 0, lt?: 65_536) optional(:ssh_proxy_command).filled(:str?) optional(:container_runtime).filled(included_in?: ['docker', 'custom_docker', 'cri-o']) @@ -93,7 +98,7 @@ def unique_addresses?(hosts) predicates(HostPredicates) required(:address).filled(:str?, :hostname_or_ip?) optional(:user).filled(:str?) - optional(:ssh_key_path).filled(:str?) + optional(:ssh_key_path).filled(:str?, :file_exist?) optional(:ssh_port).filled(:int?, gt?: 0, lt?: 65_536) optional(:ssh_proxy_command).filled(:str?) end diff --git a/lib/pharos/exec_command.rb b/lib/pharos/exec_command.rb index 1a6e1f129..ad5c8fd61 100644 --- a/lib/pharos/exec_command.rb +++ b/lib/pharos/exec_command.rb @@ -11,13 +11,13 @@ class ExecCommand < Pharos::Command banner "Opens SSH sessions to hosts in the Kontena Pharos cluster." def execute - if command_list.empty? - signal_usage_error 'interactive mode can not be used with a non-interactive terminal' unless $stdin.tty? && $stdout.tty? - run_interactive - exit 0 - end - Dir.chdir(config_yaml.dirname) do + if command_list.empty? + signal_usage_error 'interactive mode can not be used with a non-interactive terminal' unless $stdin.tty? && $stdout.tty? + run_interactive + exit 0 + end + filtered_hosts.each { |host| host.transport.connect } exit run_single(filtered_hosts.first) if filtered_hosts.size == 1