diff options
-rw-r--r-- | lib/chef/knife/ssh.rb | 35 | ||||
-rw-r--r-- | spec/functional/knife/ssh_spec.rb | 47 | ||||
-rw-r--r-- | spec/unit/knife/ssh_spec.rb | 69 |
3 files changed, 131 insertions, 20 deletions
diff --git a/lib/chef/knife/ssh.rb b/lib/chef/knife/ssh.rb index af5b15db0d..b6abd67719 100644 --- a/lib/chef/knife/ssh.rb +++ b/lib/chef/knife/ssh.rb @@ -58,6 +58,10 @@ class Chef :description => "QUERY is a space separated list of servers", :default => false + option :prefix_attribute, + :long => "--prefix-attribute ATTR", + :description => "The attribute to use for prefixing the ouput - default depends on the context" + option :ssh_user, :short => "-x USERNAME", :long => "--ssh-user USERNAME", @@ -180,6 +184,19 @@ class Chef session_from_list(list) end + def get_prefix_attribute(item) + # Order of precedence for prefix + # 1) config value (cli or knife config) + # 2) nil + msg = "Using node attribute '%s' as the prefix: %s" + if item["prefix"] + Chef::Log.debug(sprintf(msg, config[:prefix_attribute], item["prefix"])) + item["prefix"] + else + nil + end + end + def get_ssh_attribute(item) # Order of precedence for ssh target # 1) config value (cli or knife config) @@ -205,6 +222,10 @@ class Chef separator = ui.presenter.attribute_field_separator + if config[:prefix_attribute] + required_attributes[:prefix] = config[:prefix_attribute].split(separator) + end + if config[:ssh_attribute] required_attributes[:target] = config[:ssh_attribute].split(separator) end @@ -219,8 +240,9 @@ class Chef # returned node object host = get_ssh_attribute(item) next if host.nil? + prefix = get_prefix_attribute(item) ssh_port = item.dig("cloud", "public_ssh_port") - srv = [host, ssh_port] + srv = [host, ssh_port, prefix] list.push(srv) end @@ -269,7 +291,8 @@ class Chef def session_from_list(list) list.each do |item| - host, ssh_port = item + host, ssh_port, prefix = item + prefix = host unless prefix Chef::Log.debug("Adding #{host}") session_opts = session_options(host, ssh_port) # Handle port overrides for the main connection. @@ -278,12 +301,14 @@ class Chef # Handle connection timeout session_opts[:timeout] = Chef::Config[:knife][:ssh_timeout] if Chef::Config[:knife][:ssh_timeout] session_opts[:timeout] = config[:ssh_timeout] if config[:ssh_timeout] + # Handle session prefix + session_opts[:properties] = { prefix: prefix } # Create the hostspec. hostspec = session_opts[:user] ? "#{session_opts.delete(:user)}@#{host}" : host # Connect a new session on the multi. session.use(hostspec, session_opts) - @longest = host.length if host.length > @longest + @longest = prefix.length if prefix.length > @longest end session @@ -329,9 +354,9 @@ class Chef chan.exec command do |ch, success| raise ArgumentError, "Cannot execute #{command}" unless success ch.on_data do |ichannel, data| - print_data(ichannel[:host], data) + print_data(ichannel.connection[:prefix], data) if data =~ /^knife sudo password: / - print_data(ichannel[:host], "\n") + print_data(ichannel.connection[:prefix], "\n") ichannel.send_data("#{get_password}\n") end end diff --git a/spec/functional/knife/ssh_spec.rb b/spec/functional/knife/ssh_spec.rb index 3872d34322..3defbe781f 100644 --- a/spec/functional/knife/ssh_spec.rb +++ b/spec/functional/knife/ssh_spec.rb @@ -219,6 +219,53 @@ describe Chef::Knife::Ssh do end end + describe "prefix" do + context "when knife[:prefix_attribute] is set" do + before do + setup_knife(["*:*", "uptime"]) + Chef::Config[:knife][:prefix_attribute] = "name" + end + + it "uses the prefix_attribute" do + @knife.run + expect(@knife.get_prefix_attribute({ "prefix" => "name" })).to eq("name") + end + end + + context "when knife[:prefix_attribute] is not provided" do + before do + setup_knife(["*:*", "uptime"]) + Chef::Config[:knife][:prefix_attribute] = nil + end + + it "falls back to nil" do + @knife.run + expect(@knife.get_prefix_attribute({})).to eq(nil) + end + end + + context "when --prefix-attribute ec2.public_public_hostname is provided" do + before do + setup_knife(["--prefix-attribute", "ec2.public_hostname", "*:*", "uptime"]) + Chef::Config[:knife][:prefix_attribute] = nil + end + + it "should use the value on the command line" do + @knife.run + expect(@knife.config[:prefix_attribute]).to eq("ec2.public_hostname") + end + + it "should override what is set in knife.rb" do + # This is the setting imported from knife.rb + Chef::Config[:knife][:prefix_attribute] = "fqdn" + # Then we run knife with the -b flag, which sets the above variable + setup_knife(["--prefix-attribute", "ec2.public_hostname", "*:*", "uptime"]) + @knife.run + expect(@knife.config[:prefix_attribute]).to eq("ec2.public_hostname") + end + end + end + describe "gateway" do context "when knife[:ssh_gateway] is set" do before do diff --git a/spec/unit/knife/ssh_spec.rb b/spec/unit/knife/ssh_spec.rb index e3cdf2c2f7..af54115ac7 100644 --- a/spec/unit/knife/ssh_spec.rb +++ b/spec/unit/knife/ssh_spec.rb @@ -51,26 +51,34 @@ describe Chef::Knife::Ssh do it "returns an array of the attributes specified on the command line OR config file, if only one is set" do @node_bar["target"] = "10.0.0.2" @node_foo["target"] = "10.0.0.1" + @node_bar["prefix"] = "bar" + @node_foo["prefix"] = "foo" @knife.config[:ssh_attribute] = "ipaddress" + @knife.config[:prefix_attribute] = "name" Chef::Config[:knife][:ssh_attribute] = "ipaddress" # this value will be in the config file - expect(@knife).to receive(:session_from_list).with([["10.0.0.1", nil], ["10.0.0.2", nil]]) + Chef::Config[:knife][:prefix_attribute] = "name" # this value will be in the config file + expect(@knife).to receive(:session_from_list).with([["10.0.0.1", nil, "foo"], ["10.0.0.2", nil, "bar"]]) @knife.configure_session end it "returns an array of the attributes specified on the command line even when a config value is set" do @node_bar["target"] = "10.0.0.2" @node_foo["target"] = "10.0.0.1" + @node_bar["prefix"] = "bar" + @node_foo["prefix"] = "foo" Chef::Config[:knife][:ssh_attribute] = "config_file" # this value will be in the config file + Chef::Config[:knife][:prefix_attribute] = "config_file" # this value will be in the config file @knife.config[:ssh_attribute] = "ipaddress" # this is the value of the command line via #configure_attribute - expect(@knife).to receive(:session_from_list).with([["10.0.0.1", nil], ["10.0.0.2", nil]]) + @knife.config[:prefix_attribute] = "name" # this is the value of the command line via #configure_attribute + expect(@knife).to receive(:session_from_list).with([["10.0.0.1", nil, "foo"], ["10.0.0.2", nil, "bar"]]) @knife.configure_session end end it "searches for and returns an array of fqdns" do expect(@knife).to receive(:session_from_list).with([ - ["foo.example.org", nil], - ["bar.example.org", nil], + ["foo.example.org", nil, nil], + ["bar.example.org", nil, nil], ]) @knife.configure_session end @@ -84,8 +92,8 @@ describe Chef::Knife::Ssh do end it "returns an array of cloud public hostnames" do expect(@knife).to receive(:session_from_list).with([ - ["ec2-10-0-0-1.compute-1.amazonaws.com", nil], - ["ec2-10-0-0-2.compute-1.amazonaws.com", nil], + ["ec2-10-0-0-1.compute-1.amazonaws.com", nil, nil], + ["ec2-10-0-0-2.compute-1.amazonaws.com", nil, nil], ]) @knife.configure_session end @@ -101,8 +109,8 @@ describe Chef::Knife::Ssh do it "returns an array of fqdns" do expect(@knife).to receive(:session_from_list).with([ - ["foo.example.org", nil], - ["bar.example.org", nil], + ["foo.example.org", nil, nil], + ["bar.example.org", nil, nil], ]) @knife.configure_session end @@ -144,6 +152,27 @@ describe Chef::Knife::Ssh do end end + describe "#get_prefix_attribute" do + # Order of precedence for prefix + # 1) config value (cli or knife config) + # 2) nil + before do + Chef::Config[:knife][:prefix_attribute] = nil + @knife.config[:prefix_attribute] = nil + @node_foo["cloud"]["public_hostname"] = "ec2-10-0-0-1.compute-1.amazonaws.com" + @node_bar["cloud"]["public_hostname"] = "" + end + + it "should return nil by default" do + expect(@knife.get_prefix_attribute({})).to eq(nil) + end + + it "should favor config over nil" do + @node_foo["prefix"] = "config" + expect( @knife.get_prefix_attribute(@node_foo)).to eq("config") + end + end + describe "#get_ssh_attribute" do # Order of precedence for ssh target # 1) config value (cli or knife config) @@ -182,40 +211,50 @@ describe Chef::Knife::Ssh do end it "uses the port from an ssh config file" do - @knife.session_from_list([["the.b.org", nil]]) + @knife.session_from_list([["the.b.org", nil, nil]]) expect(@knife.session.servers[0].port).to eq(23) end it "uses the port from a cloud attr" do - @knife.session_from_list([["the.b.org", 123]]) + @knife.session_from_list([["the.b.org", 123, nil]]) expect(@knife.session.servers[0].port).to eq(123) end + it "uses the prefix from list" do + @knife.session_from_list([["the.b.org", nil, "b-team"]]) + expect(@knife.session.servers[0][:prefix]).to eq("b-team") + end + + it "defaults to a prefix of host" do + @knife.session_from_list([["the.b.org", nil, nil]]) + expect(@knife.session.servers[0][:prefix]).to eq("the.b.org") + end + it "defaults to a timeout of 120 seconds" do - @knife.session_from_list([["the.b.org", nil]]) + @knife.session_from_list([["the.b.org", nil, nil]]) expect(@knife.session.servers[0].options[:timeout]).to eq(120) end it "uses the timeout from Chef Config" do Chef::Config[:knife][:ssh_timeout] = 5 @knife.config[:ssh_timeout] = nil - @knife.session_from_list([["the.b.org", nil]]) + @knife.session_from_list([["the.b.org", nil, nil]]) expect(@knife.session.servers[0].options[:timeout]).to eq(5) end it "uses the timeout from knife config" do @knife.config[:ssh_timeout] = 6 - @knife.session_from_list([["the.b.org", nil]]) + @knife.session_from_list([["the.b.org", nil, nil]]) expect(@knife.session.servers[0].options[:timeout]).to eq(6) end it "uses the user from an ssh config file" do - @knife.session_from_list([["the.b.org", 123]]) + @knife.session_from_list([["the.b.org", 123, nil]]) expect(@knife.session.servers[0].user).to eq("locutus") end it "uses keepalive settings from an ssh config file" do - @knife.session_from_list([["the.b.org", 123]]) + @knife.session_from_list([["the.b.org", 123, nil]]) expect(@knife.session.servers[0].options[:keepalive]).to be true expect(@knife.session.servers[0].options[:keepalive_interval]).to eq 60 end |