diff options
author | Serdar Sutay <serdar@opscode.com> | 2014-08-22 11:34:34 -0700 |
---|---|---|
committer | Serdar Sutay <serdar@opscode.com> | 2014-08-26 15:42:27 -0700 |
commit | c79ceca006bb18b59489ac077879710711bdfd99 (patch) | |
tree | ec6e99faa9acea4993af70dee4813aa74a9230f2 /spec | |
parent | b03b2aa547e6c9766d9ed39e29351540209c7b06 (diff) | |
download | chef-c79ceca006bb18b59489ac077879710711bdfd99.tar.gz |
Specs for bootstrap cleanup.
Diffstat (limited to 'spec')
-rw-r--r-- | spec/unit/knife/bootstrap_spec.rb | 445 |
1 files changed, 277 insertions, 168 deletions
diff --git a/spec/unit/knife/bootstrap_spec.rb b/spec/unit/knife/bootstrap_spec.rb index 434878ed93..5aae5bdddf 100644 --- a/spec/unit/knife/bootstrap_spec.rb +++ b/spec/unit/knife/bootstrap_spec.rb @@ -22,110 +22,194 @@ Chef::Knife::Bootstrap.load_deps require 'net/ssh' describe Chef::Knife::Bootstrap do - before(:each) do + let(:knife) do Chef::Log.logger = Logger.new(StringIO.new) - @knife = Chef::Knife::Bootstrap.new - # Merge default settings in. - @knife.merge_configs - @knife.config[:template_file] = File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "test.erb")) - @stdout = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - @stderr = StringIO.new - @knife.ui.stub(:stderr).and_return(@stderr) - end + Chef::Config[:knife][:bootstrap_template] = bootstrap_template unless bootstrap_template.nil? - it "should return a name of default bootstrap template" do - @knife.find_template.should be_a_kind_of(String) - end + k = Chef::Knife::Bootstrap.new + k.merge_configs - it "should error if template can not be found" do - Chef::Config[:knife][:bootstrap_template] = 'penultimate' - lambda { @knife.find_template }.should raise_error + k.ui.stub(:stderr).and_return(stderr) + k end - it "should look for templates early in the run" do - File.stub(:exists?).and_return(true) - @knife.name_args = ['shatner'] - @knife.stub(:read_template).and_return("") - @knife.stub(:knife_ssh).and_return(true) - @knife_ssh = @knife.knife_ssh - @knife.should_receive(:find_template).ordered - @knife.should_receive(:knife_ssh).ordered - @knife_ssh.should_receive(:run) # rspec appears to keep order per object - @knife.run - end + let(:stderr) { StringIO.new } - it "should load the specified template" do - @knife.config[:template] = 'fedora13-gems' - lambda { @knife.find_template }.should_not raise_error - end + let(:bootstrap_template) { nil } - it "should load the specified template from a Ruby gem" do - @knife.config[:template_file] = false - Gem.stub(:find_files).and_return(["/Users/schisamo/.rvm/gems/ruby-1.9.2-p180@chef-0.10/gems/knife-windows-0.5.4/lib/chef/knife/bootstrap/fake-bootstrap-template.erb"]) - File.stub(:exists?).and_return(true) - IO.stub(:read).and_return('random content') - @knife.config[:template] = 'fake-bootstrap-template' - lambda { @knife.find_template }.should_not raise_error + it "should use chef-full as default template" do + knife.find_template.should be_a_kind_of(String) + File.basename(knife.find_template).should eq("chef-full.erb") end - it "should return an empty run_list" do - @knife.instance_variable_set("@template_file", @knife.config[:template_file]) - template_string = @knife.read_template - @knife.render_template(template_string).should == '{"run_list":[]}' - end + context "when finding templates" do + context "when :bootstrap_template config is set to a file" do + context "that doesn't exist" do + let(:bootstrap_template) { "/opt/blah/not/exists/template.erb" } - it "should have role[base] in the run_list" do - @knife.instance_variable_set("@template_file", @knife.config[:template_file]) - template_string = @knife.read_template - @knife.parse_options(["-r","role[base]"]) - @knife.render_template(template_string).should == '{"run_list":["role[base]"]}' - end + it "raises an error" do + lambda { knife.find_template }.should raise_error + end + end - it "should have role[base] and recipe[cupcakes] in the run_list" do - @knife.instance_variable_set("@template_file", @knife.config[:template_file]) - template_string = @knife.read_template - @knife.parse_options(["-r", "role[base],recipe[cupcakes]"]) - @knife.render_template(template_string).should == '{"run_list":["role[base]","recipe[cupcakes]"]}' - end + context "that exists" do + let(:bootstrap_template) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "test.erb")) } + + it "loads the given file as the template" do + Chef::Log.should_receive(:debug) + knife.find_template.should eq(File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "test.erb"))) + end + end + end + + context "when :bootstrap_template config is set to a template name" do + let(:bootstrap_template) { "example" } - it "should have foo => {bar => baz} in the first_boot" do - @knife.instance_variable_set("@template_file", @knife.config[:template_file]) - template_string = @knife.read_template - @knife.parse_options(["-j", '{"foo":{"bar":"baz"}}']) - expected_hash = FFI_Yajl::Parser.new.parse('{"foo":{"bar":"baz"},"run_list":[]}') - actual_hash = FFI_Yajl::Parser.new.parse(@knife.render_template(template_string)) - actual_hash.should == expected_hash + let(:builtin_template_path) { File.expand_path(File.join(File.dirname(__FILE__), '../../../lib/chef/knife/bootstrap', "example.erb"))} + + let(:chef_config_dir_template_path) { "/knife/chef/config/bootstrap/example.erb" } + + let(:env_home_template_path) { "/env/home/.chef/bootstrap/example.erb" } + + let(:gem_files_template_path) { "/Users/schisamo/.rvm/gems/ruby-1.9.2-p180@chef-0.10/gems/knife-windows-0.5.4/lib/chef/knife/bootstrap/fake-bootstrap-template.erb" } + + def configure_chef_config_dir + Chef::Knife.stub(:chef_config_dir).and_return("/knife/chef/config") + end + + def configure_env_home + ENV['HOME'] = "/env/home" + end + + def configure_gem_files + Gem.stub(:find_files).and_return([ gem_files_template_path ]) + end + + before(:each) do + @original_home = ENV['HOME'] + ENV['HOME'] = nil + File.should_receive(:exists?).with(bootstrap_template).and_return(false) + end + + after(:each) do + ENV['HOME'] = @original_home + end + + context "when file is available everywhere" do + before do + configure_chef_config_dir + configure_env_home + configure_gem_files + + File.should_receive(:exists?).with(builtin_template_path).and_return(true) + end + + it "should load the template from built-in templates" do + knife.find_template.should eq(builtin_template_path) + end + end + + context "when file is available in chef_config_dir" do + before do + configure_chef_config_dir + configure_env_home + configure_gem_files + + File.should_receive(:exists?).with(builtin_template_path).and_return(false) + File.should_receive(:exists?).with(chef_config_dir_template_path).and_return(true) + + it "should load the template from chef_config_dir" do + knife.find_template.should eq(chef_config_dir_template_path) + end + end + end + + context "when file is available in ENV['HOME']" do + before do + configure_chef_config_dir + configure_env_home + configure_gem_files + + File.should_receive(:exists?).with(builtin_template_path).and_return(false) + File.should_receive(:exists?).with(chef_config_dir_template_path).and_return(false) + File.should_receive(:exists?).with(env_home_template_path).and_return(true) + end + + it "should load the template from chef_config_dir" do + knife.find_template.should eq(env_home_template_path) + end + end + + context "when file is available in Gem files" do + before do + configure_chef_config_dir + configure_gem_files + + File.should_receive(:exists?).with(builtin_template_path).and_return(false) + File.should_receive(:exists?).with(chef_config_dir_template_path).and_return(false) + File.should_receive(:exists?).with(gem_files_template_path).and_return(true) + end + + it "should load the template from Gem files" do + knife.find_template.should eq(gem_files_template_path) + end + end + end end - it "should create a hint file when told to" do - @knife.config[:template_file] = File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "test-hints.erb")) - @knife.instance_variable_set("@template_file", @knife.config[:template_file]) - template_string = @knife.read_template - @knife.parse_options(["--hint", "openstack"]) - @knife.render_template(template_string).should match /\/etc\/chef\/ohai\/hints\/openstack.json/ + ["-d", "--distro", "-t", "--template", "--template-file"].each do |t| + context "when #{t} option is given in the command line" do + it "sets the knife :bootstrap_template config" do + knife.parse_options([t,"blahblah"]) + Chef::Config[:knife][:bootstrap_template].should eq("blahblah") + end + end end - it "should populate a hint file with JSON when given a file to read" do - @knife.stub(:find_template).and_return(true) - @knife.config[:template_file] = File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "test-hints.erb")) - ::File.stub(:read).and_return('{ "foo" : "bar" }') - @knife.instance_variable_set("@template_file", @knife.config[:template_file]) - template_string = @knife.read_template - @knife.stub(:read_template).and_return('{ "foo" : "bar" }') - @knife.parse_options(["--hint", "openstack=hints/openstack.json"]) - @knife.render_template(template_string).should match /\{\"foo\":\"bar\"\}/ + context "with run_list template" do + let(:bootstrap_template) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "test.erb")) } + + it "should return an empty run_list" do + knife.render_template.should == '{"run_list":[]}' + end + + it "should have role[base] in the run_list" do + knife.parse_options(["-r","role[base]"]) + knife.render_template.should == '{"run_list":["role[base]"]}' + end + + it "should have role[base] and recipe[cupcakes] in the run_list" do + knife.parse_options(["-r", "role[base],recipe[cupcakes]"]) + knife.render_template.should == '{"run_list":["role[base]","recipe[cupcakes]"]}' + end + + it "should have foo => {bar => baz} in the first_boot" do + knife.parse_options(["-j", '{"foo":{"bar":"baz"}}']) + expected_hash = FFI_Yajl::Parser.new.parse('{"foo":{"bar":"baz"},"run_list":[]}') + actual_hash = FFI_Yajl::Parser.new.parse(knife.render_template) + actual_hash.should == expected_hash + end end - it "should take the node name from ARGV" do - @knife.name_args = ['barf'] - @knife.name_args.first.should == "barf" + context "with hints template" do + let(:bootstrap_template) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "test-hints.erb")) } + + it "should create a hint file when told to" do + knife.parse_options(["--hint", "openstack"]) + knife.render_template.should match /\/etc\/chef\/ohai\/hints\/openstack.json/ + end + + it "should populate a hint file with JSON when given a file to read" do + ::File.stub(:read).and_return('{ "foo" : "bar" }') + knife.parse_options(["--hint", "openstack=hints/openstack.json"]) + knife.render_template.should match /\{\"foo\":\"bar\"\}/ + end end describe "specifying no_proxy with various entries" do subject(:knife) do k = described_class.new - k.instance_variable_set("@template_file", template_file) + Chef::Config[:knife][:bootstrap_template] = template_file k.parse_options(options) k.merge_configs k @@ -138,8 +222,7 @@ describe Chef::Knife::Bootstrap do let(:options){ ["--bootstrap-no-proxy", setting, "-s", "foo"] } let(:template_file) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "no_proxy.erb")) } let(:rendered_template) do - template_string = knife.read_template - knife.render_template(template_string) + knife.render_template end context "via --bootstrap-no-proxy" do @@ -160,16 +243,13 @@ describe Chef::Knife::Bootstrap do end describe "specifying the encrypted data bag secret key" do - subject(:knife) { described_class.new } let(:secret) { "supersekret" } let(:secret_file) { File.join(CHEF_SPEC_DATA, 'bootstrap', 'encrypted_data_bag_secret') } let(:options) { [] } - let(:template_file) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "secret.erb")) } + let(:bootstrap_template) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "secret.erb")) } let(:rendered_template) do - knife.instance_variable_set("@template_file", template_file) knife.parse_options(options) - template_string = knife.read_template - knife.render_template(template_string) + knife.render_template end context "via --secret" do @@ -197,175 +277,204 @@ describe Chef::Knife::Bootstrap do end end + context "secret via config" do + before do + Chef::Config[:knife][:secret] = secret + end + + it "creates a secret file" do + rendered_template.should match(%r{#{secret}}) + end + + it "renders the client.rb with an encrypted_data_bag_secret entry" do + rendered_template.should match(%r{encrypted_data_bag_secret\s*"/etc/chef/encrypted_data_bag_secret"}) + end + end + + context "secret-file via config" do + let(:secret) { IO.read(secret_file) } + + before do + Chef::Config[:knife][:secret_file] = secret_file + end + + it "creates a secret file" do + rendered_template.should match(%r{#{secret}}) + end + + it "renders the client.rb with an encrypted_data_bag_secret entry" do + rendered_template.should match(%r{encrypted_data_bag_secret\s*"/etc/chef/encrypted_data_bag_secret"}) + end + end end describe "when configuring the underlying knife ssh command" do context "from the command line" do - before do - @knife.name_args = ["foo.example.com"] - @knife.config[:ssh_user] = "rooty" - @knife.config[:ssh_port] = "4001" - @knife.config[:ssh_password] = "open_sesame" + let(:knife_ssh) do + knife.name_args = ["foo.example.com"] + knife.config[:ssh_user] = "rooty" + knife.config[:ssh_port] = "4001" + knife.config[:ssh_password] = "open_sesame" Chef::Config[:knife][:ssh_user] = nil Chef::Config[:knife][:ssh_port] = nil - @knife.config[:forward_agent] = true - @knife.config[:identity_file] = "~/.ssh/me.rsa" - @knife.stub(:read_template).and_return("") - @knife_ssh = @knife.knife_ssh + knife.config[:forward_agent] = true + knife.config[:identity_file] = "~/.ssh/me.rsa" + knife.stub(:render_template).and_return("") + knife.knife_ssh end it "configures the hostname" do - @knife_ssh.name_args.first.should == "foo.example.com" + knife_ssh.name_args.first.should == "foo.example.com" end it "configures the ssh user" do - @knife_ssh.config[:ssh_user].should == 'rooty' + knife_ssh.config[:ssh_user].should == 'rooty' end it "configures the ssh password" do - @knife_ssh.config[:ssh_password].should == 'open_sesame' + knife_ssh.config[:ssh_password].should == 'open_sesame' end it "configures the ssh port" do - @knife_ssh.config[:ssh_port].should == '4001' + knife_ssh.config[:ssh_port].should == '4001' end it "configures the ssh agent forwarding" do - @knife_ssh.config[:forward_agent].should == true + knife_ssh.config[:forward_agent].should == true end it "configures the ssh identity file" do - @knife_ssh.config[:identity_file].should == '~/.ssh/me.rsa' + knife_ssh.config[:identity_file].should == '~/.ssh/me.rsa' end end + context "validating use_sudo_password" do before do - @knife.config[:ssh_password] = "password" - @knife.stub(:read_template).and_return("This is the template contents.") + knife.config[:ssh_password] = "password" + knife.stub(:render_template).and_return("") end it "use_sudo_password contains description and long params for help" do - @knife.options.should have_key(:use_sudo_password) \ - and @knife.options[:use_sudo_password][:description].to_s.should_not == ''\ - and @knife.options[:use_sudo_password][:long].to_s.should_not == '' + knife.options.should have_key(:use_sudo_password) \ + and knife.options[:use_sudo_password][:description].to_s.should_not == ''\ + and knife.options[:use_sudo_password][:long].to_s.should_not == '' end it "uses the password from --ssh-password for sudo when --use-sudo-password is set" do - @knife.config[:use_sudo] = true - @knife.config[:use_sudo_password] = true - @knife.ssh_command.should include("echo \'#{@knife.config[:ssh_password]}\' | sudo -S") + knife.config[:use_sudo] = true + knife.config[:use_sudo_password] = true + knife.ssh_command.should include("echo \'#{knife.config[:ssh_password]}\' | sudo -S") end it "should not honor --use-sudo-password when --use-sudo is not set" do - @knife.config[:use_sudo] = false - @knife.config[:use_sudo_password] = true - @knife.ssh_command.should_not include("echo #{@knife.config[:ssh_password]} | sudo -S") + knife.config[:use_sudo] = false + knife.config[:use_sudo_password] = true + knife.ssh_command.should_not include("echo #{knife.config[:ssh_password]} | sudo -S") end end + context "from the knife config file" do - before do - @knife.name_args = ["config.example.com"] - @knife.config[:ssh_user] = nil - @knife.config[:ssh_port] = nil - @knife.config[:ssh_gateway] = nil - @knife.config[:forward_agent] = nil - @knife.config[:identity_file] = nil - @knife.config[:host_key_verify] = nil + let(:knife_ssh) do + knife.name_args = ["config.example.com"] + knife.config[:ssh_user] = nil + knife.config[:ssh_port] = nil + knife.config[:ssh_gateway] = nil + knife.config[:forward_agent] = nil + knife.config[:identity_file] = nil + knife.config[:host_key_verify] = nil Chef::Config[:knife][:ssh_user] = "curiosity" Chef::Config[:knife][:ssh_port] = "2430" Chef::Config[:knife][:forward_agent] = true Chef::Config[:knife][:identity_file] = "~/.ssh/you.rsa" Chef::Config[:knife][:ssh_gateway] = "towel.blinkenlights.nl" Chef::Config[:knife][:host_key_verify] = true - @knife.stub(:read_template).and_return("") - @knife_ssh = @knife.knife_ssh + knife.stub(:render_template).and_return("") + knife.knife_ssh end it "configures the ssh user" do - @knife_ssh.config[:ssh_user].should == 'curiosity' + knife_ssh.config[:ssh_user].should == 'curiosity' end it "configures the ssh port" do - @knife_ssh.config[:ssh_port].should == '2430' + knife_ssh.config[:ssh_port].should == '2430' end it "configures the ssh agent forwarding" do - @knife_ssh.config[:forward_agent].should == true + knife_ssh.config[:forward_agent].should == true end it "configures the ssh identity file" do - @knife_ssh.config[:identity_file].should == '~/.ssh/you.rsa' + knife_ssh.config[:identity_file].should == '~/.ssh/you.rsa' end it "configures the ssh gateway" do - @knife_ssh.config[:ssh_gateway].should == 'towel.blinkenlights.nl' + knife_ssh.config[:ssh_gateway].should == 'towel.blinkenlights.nl' end it "configures the host key verify mode" do - @knife_ssh.config[:host_key_verify].should == true + knife_ssh.config[:host_key_verify].should == true end end describe "when falling back to password auth when host key auth fails" do - before do - @knife.name_args = ["foo.example.com"] - @knife.config[:ssh_user] = "rooty" - @knife.config[:identity_file] = "~/.ssh/me.rsa" - @knife.stub(:read_template).and_return("") - @knife_ssh = @knife.knife_ssh + let(:knife_ssh_with_password_auth) do + knife.name_args = ["foo.example.com"] + knife.config[:ssh_user] = "rooty" + knife.config[:identity_file] = "~/.ssh/me.rsa" + knife.stub(:render_template).and_return("") + k = knife.knife_ssh + k.stub(:get_password).and_return('typed_in_password') + knife.stub(:knife_ssh).and_return(k) + knife.knife_ssh_with_password_auth end it "prompts the user for a password " do - @knife.stub(:knife_ssh).and_return(@knife_ssh) - @knife_ssh.stub(:get_password).and_return('typed_in_password') - alternate_knife_ssh = @knife.knife_ssh_with_password_auth - alternate_knife_ssh.config[:ssh_password].should == 'typed_in_password' + knife_ssh_with_password_auth.config[:ssh_password].should == 'typed_in_password' end it "configures knife not to use the identity file that didn't work previously" do - @knife.stub(:knife_ssh).and_return(@knife_ssh) - @knife_ssh.stub(:get_password).and_return('typed_in_password') - alternate_knife_ssh = @knife.knife_ssh_with_password_auth - alternate_knife_ssh.config[:identity_file].should be_nil + knife_ssh_with_password_auth.config[:identity_file].should be_nil end end end - describe "when running the bootstrap" do - before do - @knife.name_args = ["foo.example.com"] - @knife.config[:ssh_user] = "rooty" - @knife.config[:identity_file] = "~/.ssh/me.rsa" - @knife.stub(:read_template).and_return("") - @knife_ssh = @knife.knife_ssh - @knife.stub(:knife_ssh).and_return(@knife_ssh) - end + it "verifies that a server to bootstrap was given as a command line arg" do + knife.name_args = nil + lambda { knife.run }.should raise_error(SystemExit) + stderr.string.should match /ERROR:.+FQDN or ip/ + end - it "verifies that a server to bootstrap was given as a command line arg" do - @knife.name_args = nil - lambda { @knife.run }.should raise_error(SystemExit) - @stderr.string.should match /ERROR:.+FQDN or ip/ + describe "when running the bootstrap" do + let(:knife_ssh) do + knife.name_args = ["foo.example.com"] + knife.config[:ssh_user] = "rooty" + knife.config[:identity_file] = "~/.ssh/me.rsa" + knife.stub(:render_template).and_return("") + knife_ssh = knife.knife_ssh + knife.stub(:knife_ssh).and_return(knife_ssh) + knife_ssh end it "configures the underlying ssh command and then runs it" do - @knife_ssh.should_receive(:run) - @knife.run + knife_ssh.should_receive(:run) + knife.run end it "falls back to password based auth when auth fails the first time" do - @knife.stub(:puts) + knife.stub(:puts) - @fallback_knife_ssh = @knife_ssh.dup - @knife_ssh.should_receive(:run).and_raise(Net::SSH::AuthenticationFailed.new("no ssh for you")) - @knife.stub(:knife_ssh_with_password_auth).and_return(@fallback_knife_ssh) - @fallback_knife_ssh.should_receive(:run) - @knife.run + fallback_knife_ssh = knife_ssh.dup + knife_ssh.should_receive(:run).and_raise(Net::SSH::AuthenticationFailed.new("no ssh for you")) + knife.stub(:knife_ssh_with_password_auth).and_return(fallback_knife_ssh) + fallback_knife_ssh.should_receive(:run) + knife.run end it "raises the exception if config[:ssh_password] is set and an authentication exception is raised" do - @knife.config[:ssh_password] = "password" - @knife_ssh.should_receive(:run).and_raise(Net::SSH::AuthenticationFailed) - lambda { @knife.run }.should raise_error(Net::SSH::AuthenticationFailed) + knife.config[:ssh_password] = "password" + knife_ssh.should_receive(:run).and_raise(Net::SSH::AuthenticationFailed) + lambda { knife.run }.should raise_error(Net::SSH::AuthenticationFailed) end end |