From 0bd4bf692741b7152489a5c8ed5c3b413f44994d Mon Sep 17 00:00:00 2001 From: Mukta A Date: Mon, 19 Aug 2013 13:05:26 +0530 Subject: [PATCH 1/6] Auto generation of chef_node_name is handled in knife-cloud now --- lib/chef/knife/openstack_server_create.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/chef/knife/openstack_server_create.rb b/lib/chef/knife/openstack_server_create.rb index 938481c8..3fa72e40 100644 --- a/lib/chef/knife/openstack_server_create.rb +++ b/lib/chef/knife/openstack_server_create.rb @@ -44,8 +44,8 @@ def before_exec_command # setup the create options @create_options = { :server_def => { - #servers require a name, generate one if not passed - :name => get_node_name(locate_config_value(:chef_node_name)), + #servers require a name, knife-cloud generates the chef_node_name + :name => config[:chef_node_name], :image_ref => locate_config_value(:image), :flavor_ref => locate_config_value(:flavor), :security_groups => locate_config_value(:openstack_security_groups), From 1d92882f61dde9028f56a566f9d2e4e040b8bf1d Mon Sep 17 00:00:00 2001 From: siddheshwar-more Date: Wed, 21 Aug 2013 20:00:30 +0530 Subject: [PATCH 2/6] Removed openstack service stale rspec tests --- spec/unit/openstack_service_spec.rb | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 spec/unit/openstack_service_spec.rb diff --git a/spec/unit/openstack_service_spec.rb b/spec/unit/openstack_service_spec.rb deleted file mode 100644 index d7d42185..00000000 --- a/spec/unit/openstack_service_spec.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'spec_helper' -require 'chef/knife/cloud/openstack_service' -require 'chef/knife/cloud/fog/service' -require 'support/shared_examples_for_fog_service' - -describe Chef::Knife::Cloud::OpenstackService do - it_behaves_like Chef::Knife::Cloud::FogService, Chef::Knife::Cloud::OpenstackService.new -end \ No newline at end of file From 45c174cd3b3319f5c354aea24312034999dc679f Mon Sep 17 00:00:00 2001 From: siddheshwar-more Date: Wed, 21 Aug 2013 20:01:47 +0530 Subject: [PATCH 3/6] Removed set_image_os_type method --- lib/chef/knife/openstack_server_create.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/chef/knife/openstack_server_create.rb b/lib/chef/knife/openstack_server_create.rb index 3fa72e40..f382180d 100644 --- a/lib/chef/knife/openstack_server_create.rb +++ b/lib/chef/knife/openstack_server_create.rb @@ -36,10 +36,6 @@ class OpenstackServerCreate < ServerCreateCommand banner "knife openstack server create (options)" - def set_image_os_type - # Openstack does not provide a way to identify image os type, So image_os_type is taken from user. - end - def before_exec_command # setup the create options @create_options = { From 3e1190f1870a8223f8a4d92ff382592151734235 Mon Sep 17 00:00:00 2001 From: siddheshwar-more Date: Wed, 28 Aug 2013 10:53:51 +0530 Subject: [PATCH 4/6] Implemented changes to add chef data in server list --- lib/chef/knife/openstack_server_list.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/chef/knife/openstack_server_list.rb b/lib/chef/knife/openstack_server_list.rb index 831a2df2..10e28be2 100644 --- a/lib/chef/knife/openstack_server_list.rb +++ b/lib/chef/knife/openstack_server_list.rb @@ -21,6 +21,7 @@ require 'chef/knife/cloud/server/list_command' require 'chef/knife/openstack_helpers' require 'chef/knife/cloud/openstack_service_options' +require 'chef/knife/cloud/server/list_options' class Chef class Knife @@ -28,6 +29,7 @@ class Cloud class OpenstackServerList < ServerListCommand include OpenstackHelpers include OpenstackServiceOptions + include ServerListOptions banner "knife openstack server list (options)" @@ -43,6 +45,7 @@ def before_exec_command {:label => 'Keypair', :key => 'key_name'}, {:label => 'State', :key => 'state'} ] + super end def get_public_ip_address (addresses) From d8451e4b2d744d8b8c543712c95a12dddc117299 Mon Sep 17 00:00:00 2001 From: siddheshwar-more Date: Fri, 30 Aug 2013 19:29:24 +0530 Subject: [PATCH 5/6] Added rspec functional tests for chef-data and chef-node-attribute option --- spec/functional/server_list_func_spec.rb | 52 +++++++++++++++++++++--- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/spec/functional/server_list_func_spec.rb b/spec/functional/server_list_func_spec.rb index c4eb047b..2d26f462 100644 --- a/spec/functional/server_list_func_spec.rb +++ b/spec/functional/server_list_func_spec.rb @@ -7,20 +7,62 @@ context "functionality" do before do - resources = [ TestResource.new({:id => "resource-1", :name => "ubuntu01", :addresses => {"public"=>[{"version"=>4, "addr"=>"172.31.6.132"}], "private"=>[{"version"=>4, "addr"=>"172.31.6.133"}]}, :flavor => {"id" => "1"}, :image => {"id" => "image1"}, :key_name => "keypair", :state => "ACTIVE"}), + @resources = [ TestResource.new({:id => "resource-1", :name => "ubuntu01", :addresses => {"public"=>[{"version"=>4, "addr"=>"172.31.6.132"}], "private"=>[{"version"=>4, "addr"=>"172.31.6.133"}]}, :flavor => {"id" => "1"}, :image => {"id" => "image1"}, :key_name => "keypair", :state => "ACTIVE"}), TestResource.new({:id => "resource-2", :name => "windows2008", :addresses => {"public"=>[{"version"=>4, "addr"=>"172.31.6.132"}]}, :flavor => {"id" => "id2"}, :image => {"id" => "image2"}, :key_name => "keypair", :state => "ACTIVE"}) ] - instance.stub(:query_resource).and_return(resources) + instance.stub(:query_resource).and_return(@resources) instance.stub(:puts) instance.stub(:create_service_instance).and_return(Chef::Knife::Cloud::Service.new) instance.stub(:validate!) end it "lists formatted list of resources" do - instance.ui.should_receive(:list).with(["Instance ID", "Name", "Public IP", "Private IP", "Flavor", "Image", "Keypair", "State", - "resource-1", "ubuntu01", "172.31.6.132", "172.31.6.133", "1", "image1","keypair", "ACTIVE", - "resource-2", "windows2008", "172.31.6.132", nil, "id2", "image2", "keypair", "ACTIVE"], :uneven_columns_across, 8) + instance.ui.should_receive(:list).with(["Instance ID", "Name", "Public IP", "Private IP", "Flavor", "Image", "Keypair", "State", "resource-1", "ubuntu01", "172.31.6.132", "172.31.6.133", "1", "image1","keypair", "ACTIVE", "resource-2", "windows2008", "172.31.6.132", nil, "id2", "image2", "keypair", "ACTIVE"], :uneven_columns_across, 8) instance.run end + + context "when chef-data and chef-node-attribute set" do + before(:each) do + @resources.push(TestResource.new({:id => "server-4", :name => "server-4", :addresses => {"public"=>[{"version"=>4, "addr"=>"172.31.6.132"}], "private"=>[{"version"=>4, "addr"=>"172.31.6.133"}]}, :flavor => {"id" => "1"}, :image => {"id" => "image1"}, :key_name => "keypair", :state => "ACTIVE"})) + + @node = TestResource.new({:id => "server-4", :name => "server-4", :chef_environment => "_default", :fqdn => "testfqdnnode.us", :run_list => [], :tags => [], :platform => "ubuntu", :platform_family => "debian"}) + + Chef::Node.stub(:list).and_return({"server-4" => @node}) + instance.config[:chef_data] = true + end + + it "lists formatted list of resources on chef data option set" do + instance.ui.should_receive(:list).with(["Instance ID", "Name", "Public IP", "Private IP", "Flavor", "Image", "Keypair", "State", "Chef Node Name", "Environment", "FQDN", "Runlist", "Tags", "Platform", "resource-1", "ubuntu01", "172.31.6.132", "172.31.6.133", "1", "image1", "keypair", "ACTIVE", "", "", "", "", "", "", "resource-2", "windows2008", "172.31.6.132", nil, "id2", "image2", "keypair", "ACTIVE", "", "", "", "", "", "", "server-4", "server-4", "172.31.6.132", "172.31.6.133", "1", "image1", "keypair", "ACTIVE", "server-4", "_default", "testfqdnnode.us", "[]", "[]", "ubuntu"], :uneven_columns_across, 14) + + instance.run + end + + it "lists formatted list of resources on chef-data and chef-node-attribute option set" do + instance.config[:chef_node_attribute] = "platform_family" + @node.should_receive(:attribute?).with("platform_family").and_return(true) + + instance.ui.should_receive(:list).with(["Instance ID", "Name", "Public IP", "Private IP", "Flavor", "Image", "Keypair", "State", "Chef Node Name", "Environment", "FQDN", "Runlist", "Tags", "Platform", "platform_family", "resource-1", "ubuntu01", "172.31.6.132", "172.31.6.133", "1", "image1", "keypair", "ACTIVE", "", "", "", "", "", "", "", "resource-2", "windows2008", "172.31.6.132", nil, "id2", "image2", "keypair", "ACTIVE", "", "", "", "", "", "", "", "server-4", "server-4", "172.31.6.132", "172.31.6.133", "1", "image1", "keypair", "ACTIVE", "server-4", "_default", "testfqdnnode.us", "[]", "[]", "ubuntu", "debian"], :uneven_columns_across, 15) + + instance.run + end + + it "raise error on invalid chef-node-attribute set" do + instance.config[:chef_node_attribute] = "invalid_attribute" + @node.should_receive(:attribute?).with("invalid_attribute").and_return(false) + instance.ui.should_receive(:error).with("The Node does not have a invalid_attribute attribute.") + expect { instance.run }.to raise_error + end + + it "not display chef-data on chef-node-attribute set but chef-data option missing" do + instance.config[:chef_data] = false + instance.config[:chef_node_attribute] = "platform_family" + + instance.ui.should_not_receive(:list).with(["Instance ID", "Name", "Public IP", "Private IP", "Flavor", "Image", "Keypair", "State", "Chef Node Name", "Environment", "FQDN", "Runlist", "Tags", "Platform", "resource-1", "ubuntu01", "172.31.6.132", "172.31.6.133", "1", "image1", "keypair", "ACTIVE", "", "", "", "", "", "", "resource-2", "windows2008", "172.31.6.132", nil, "id2", "image2", "keypair", "ACTIVE", "", "", "", "", "", "", "server-4", "server-4", "172.31.6.132", "172.31.6.133", "1", "image1", "keypair", "ACTIVE", "server-4", "_default", "testfqdnnode.us", "[]", "[]", "ubuntu"], :uneven_columns_across, 14) + + instance.ui.should_receive(:list).with(["Instance ID", "Name", "Public IP", "Private IP", "Flavor", "Image", "Keypair", "State", "resource-1", "ubuntu01", "172.31.6.132", "172.31.6.133", "1", "image1", "keypair", "ACTIVE", "resource-2", "windows2008", "172.31.6.132", nil, "id2", "image2", "keypair", "ACTIVE", "server-4", "server-4", "172.31.6.132", "172.31.6.133", "1", "image1", "keypair", "ACTIVE"], :uneven_columns_across, 8) + + instance.run + end + end end end \ No newline at end of file From 923921cd33d03fcafb20eac6ae0c72af137b5210 Mon Sep 17 00:00:00 2001 From: siddheshwar-more Date: Tue, 10 Sep 2013 12:49:29 +0530 Subject: [PATCH 6/6] Updated rspec tests for server create --- spec/unit/openstack_server_create_spec.rb | 224 ++++++++++++---------- 1 file changed, 122 insertions(+), 102 deletions(-) diff --git a/spec/unit/openstack_server_create_spec.rb b/spec/unit/openstack_server_create_spec.rb index 4a9b9b7b..5f72975f 100644 --- a/spec/unit/openstack_server_create_spec.rb +++ b/spec/unit/openstack_server_create_spec.rb @@ -1,5 +1,6 @@ # Author:: Prabhu Das () # Author:: Mukta Aphale () +# Author:: Siddheshwar More () # Copyright:: Copyright (c) 2013 Opscode, Inc. require File.expand_path('../../spec_helper', __FILE__) @@ -10,130 +11,149 @@ describe Chef::Knife::Cloud::OpenstackServerCreate do it_behaves_like Chef::Knife::Cloud::Command, Chef::Knife::Cloud::OpenstackServerCreate.new it_behaves_like Chef::Knife::Cloud::ServerCreateCommand, Chef::Knife::Cloud::OpenstackServerCreate.new - - let (:instance) {Chef::Knife::Cloud::OpenstackServerCreate.new} - - before(:each) do - instance.stub(:exit) - end - + describe "#create_service_instance" do it "return OpenstackService instance" do + instance = Chef::Knife::Cloud::OpenstackServerCreate.new expect(instance.create_service_instance).to be_an_instance_of(Chef::Knife::Cloud::OpenstackService) end end - describe "#validate!" do + describe "#validate_params!" do before(:each) do - Chef::Config[:knife][:openstack_username] = "testuser" - Chef::Config[:knife][:openstack_password] = "testpassword" - Chef::Config[:knife][:openstack_auth_url] = "tsturl" + @instance = Chef::Knife::Cloud::OpenstackServerCreate.new + @instance.ui.stub(:error) + Chef::Config[:knife][:bootstrap_protocol] = "ssh" + Chef::Config[:knife][:identity_file] = "identity_file" + Chef::Config[:knife][:image_os_type] = "linux" + Chef::Config[:knife][:openstack_ssh_key_id] = "openstack_ssh_key" end - it "validate openstack mandatory options" do - expect {instance.validate!}.to_not raise_error + after(:all) do + Chef::Config[:knife].delete(:bootstrap_protocol) + Chef::Config[:knife].delete(:identity_file) + Chef::Config[:knife].delete(:image_os_type) + Chef::Config[:knife].delete(:openstack_ssh_key_id) end - it "raise error on openstack_username missing and exit immediately." do - Chef::Config[:knife].delete(:openstack_username) - instance.ui.should_receive(:error).with("You did not provide a valid 'Openstack Username' value.") - expect { instance.validate! }.to raise_error(Chef::Knife::Cloud::CloudExceptions::ValidationError) + it "run sucessfully on all params exist" do + expect { @instance.validate_params! }.to_not raise_error end - it "raise error on openstack_auth_url missing and exit immediately." do - Chef::Config[:knife].delete(:openstack_auth_url) - instance.ui.should_receive(:error).with("You did not provide a valid 'Openstack Auth Url' value.") - expect { instance.validate! }.to raise_error(Chef::Knife::Cloud::CloudExceptions::ValidationError) + it "raise error if ssh key is missing" do + Chef::Config[:knife].delete(:openstack_ssh_key_id) + expect { @instance.validate_params! }.to raise_error(Chef::Knife::Cloud::CloudExceptions::ValidationError, " You must provide SSH Key..") end - - it "validates ssh params" do - Chef::Config[:knife][:image_os_type] = "linux" - Chef::Config[:knife][:bootstrap_protocol] = "ssh" - instance.ui.should_receive(:error).with("You must provide either Identity file or SSH Password.") - expect { instance.validate_params! }.to raise_error(Chef::Knife::Cloud::CloudExceptions::ValidationError) + end + + describe "#before_exec_command" do + before(:each) do + @instance = Chef::Knife::Cloud::OpenstackServerCreate.new + @instance.ui.stub(:error) + @instance.config[:chef_node_name] = "chef_node_name" + Chef::Config[:knife][:image] = "image" + Chef::Config[:knife][:flavor] = "flavor" + Chef::Config[:knife][:openstack_security_groups] = "openstack_security_groups" + Chef::Config[:knife][:server_create_timeout] = "server_create_timeout" + Chef::Config[:knife][:openstack_ssh_key_id] = "openstack_ssh_key" end - it "raise_error on invalid image_os_type params" do - Chef::Config[:knife][:ssh_password] = "ssh_password" - Chef::Config[:knife][:openstack_ssh_key_id] = "ssh_key" - Chef::Config[:knife][:image_os_type] = "other_than_windows_linux" - instance.ui.should_receive(:error).with("You must provide --image-os-type option [windows/linux]") - expect { instance.validate_params! }.to raise_error(Chef::Knife::Cloud::CloudExceptions::ValidationError) + after(:all) do + Chef::Config[:knife].delete(:image) + Chef::Config[:knife].delete(:flavor) + Chef::Config[:knife].delete(:openstack_ssh_key_id) + Chef::Config[:knife].delete(:openstack_security_groups) + Chef::Config[:knife].delete(:server_create_timeout) end - it "raise_error on mising image_os_type params" do - Chef::Config[:knife][:image_os_type] = "other_than_windows_linux" - Chef::Config[:knife][:ssh_password] = "ssh_password" - Chef::Config[:knife][:openstack_ssh_key_id] = "ssh_key" - instance.ui.should_receive(:error).with("You must provide --image-os-type option [windows/linux]") - expect { instance.validate_params! }.to raise_error(Chef::Knife::Cloud::CloudExceptions::ValidationError) + it "set create_options" do + @instance.service = double + @instance.service.should_receive(:create_server_dependencies) + @instance.before_exec_command + @instance.create_options[:server_def][:name].should == @instance.config[:chef_node_name] + @instance.create_options[:server_def][:image_ref].should == Chef::Config[:knife][:image] + @instance.create_options[:server_def][:security_groups].should == Chef::Config[:knife][:openstack_security_groups] + @instance.create_options[:server_def][:flavor_ref].should == Chef::Config[:knife][:flavor] + @instance.create_options[:server_create_timeout].should == Chef::Config[:knife][:server_create_timeout] end + end - context "bootstrap protocol: Ssh " do - before(:each) do - Chef::Config[:knife][:bootstrap_protocol] = "ssh" - Chef::Config[:knife][:image_os_type] = 'linux' - end - - it "raise error when neither identity file nor SSH password is provided and exits immediately." do - Chef::Config[:knife][:identity_file] = nil - Chef::Config[:knife][:ssh_password] = nil - instance.ui.should_receive(:error).with("You must provide either Identity file or SSH Password.") - expect { instance.validate_params! }.to raise_error(Chef::Knife::Cloud::CloudExceptions::ValidationError) - end - - it "raise error when Identity file is provided but SSH key is not provided and exits immediately." do - Chef::Config[:knife][:identity_file] = "identity_file_path" - Chef::Config[:knife][:openstack_ssh_key_id] = nil - instance.ui.should_receive(:error).with("You must provide SSH Key.") - expect { instance.validate_params! }.to raise_error(Chef::Knife::Cloud::CloudExceptions::ValidationError) - end - - it "validates gracefully when SSH password is provided." do - Chef::Config[:knife][:identity_file] = nil - Chef::Config[:knife][:ssh_password] = "ssh_password" - instance.validate_params! - end - - it "validates gracefully when both Identity file and SSH key are provided." do - Chef::Config[:knife][:identity_file] = "identity_file_path" - Chef::Config[:knife][:openstack_ssh_key_id] = "ssh_key" - instance.validate! - end - - it "when no ssh User is provided , the default value should be 'root'." do - Chef::Config[:knife][:ssh_password] = "ssh_password" - instance.configure_chef - expect(instance.config[:ssh_user]).to eq('root') - instance.validate! - end + describe "#after_exec_command" do + before(:each) do + @instance = Chef::Knife::Cloud::OpenstackServerCreate.new + @instance.stub(:msg_pair) end - context "bootstrap protocol: Winrm " do - before(:each) do - instance.configure_chef - instance.config[:bootstrap_protocol] = 'winrm' - Chef::Config[:knife][:image_os_type] = 'windows' - end - - it "validates gracefully when winrm User and Winrm password are provided." do - instance.config[:winrm_user] = "winrm_user" - Chef::Config[:knife][:winrm_password] = "winrm_password" - instance.validate! - end - - it "when no winrm User is provided , the default value should be 'Administrator'." do - Chef::Config[:knife][:winrm_password] = "winrm_password" - expect(instance.config[:winrm_user]).to eq('Administrator') - instance.validate! - end - - it "raise error when winrm password is not provided and exits immediately." do - Chef::Config[:knife][:winrm_password] = nil - instance.config[:winrm_password] = nil - instance.ui.should_receive(:error).with("You must provide Winrm Password.") - expect { instance.validate_params! }.to raise_error(Chef::Knife::Cloud::CloudExceptions::ValidationError) - end + after(:all) do + Chef::Config[:knife].delete(:openstack_floating_ip) end + + it "don't set openstack_floating_ip on missing openstack_floating_ip option" do + #default openstack_floating_ip is '-1' + Chef::Config[:knife][:openstack_floating_ip] = "-1" + @instance.service = Chef::Knife::Cloud::Service.new + @instance.server = double + @instance.server.should_receive(:flavor).and_return({"id" => "2"}) + @instance.server.should_receive(:image).and_return({"id" => "image_id"}) + @instance.server.should_not_receive(:associate_address) + @instance.server.stub(:addresses).and_return({"public"=>[{"version"=>4, "addr"=>"127.0.1.1"}]}) + @instance.should_receive(:bootstrap) + @instance.after_exec_command + end + + it "set openstack_floating_ip on openstack_floating_ip option" do + Chef::Config[:knife][:openstack_floating_ip] = nil + @instance.service = Chef::Knife::Cloud::Service.new + @instance.server = double + @instance.server.should_receive(:flavor).and_return({"id" => "2"}) + @instance.server.should_receive(:image).and_return({"id" => "image_id"}) + @instance.server.stub(:addresses).and_return({"public"=>[{"version"=>4, "addr"=>"127.0.1.1"}]}) + @instance.should_receive(:bootstrap) + connection = double + @instance.service.stub(:connection).and_return(double) + free_floating = Object.new + free_floating.define_singleton_method(:fixed_ip) { return nil } + free_floating.define_singleton_method(:ip) { return "127.0.0.1" } + @instance.service.connection.should_receive(:addresses).and_return([free_floating]) + @instance.server.should_receive(:associate_address).with(free_floating.ip) + @instance.after_exec_command + end + + it "raise error on unavailability of free_floating ip" do + Chef::Config[:knife][:openstack_floating_ip] = nil + @instance.service = Chef::Knife::Cloud::Service.new + @instance.ui.stub(:fatal) + @instance.server = double + @instance.server.should_receive(:flavor).and_return({"id" => "2"}) + @instance.server.should_receive(:image).and_return({"id" => "image_id"}) + @instance.server.stub(:addresses).and_return({"public"=>[{"version"=>4, "addr"=>"127.0.1.1"}]}) + @instance.should_not_receive(:bootstrap) + connection = double + @instance.service.stub(:connection).and_return(double) + free_floating = Object.new + free_floating.define_singleton_method(:fixed_ip) { return "127.0.0.1" } + @instance.service.connection.should_receive(:addresses).and_return([free_floating]) + @instance.server.should_not_receive(:associate_address) + expect { @instance.after_exec_command }.to raise_error(Chef::Knife::Cloud::CloudExceptions::ServerSetupError, "Unable to assign a Floating IP from allocated IPs.") + end + end + + describe "#before_bootstrap" do + before(:each) do + @instance = Chef::Knife::Cloud::OpenstackServerCreate.new + @instance.server = double + end + + it "set bootstrap_ip" do + @instance.server.stub(:addresses).and_return({"public"=>[{"version"=>4, "addr"=>"127.0.0.1"}]}) + @instance.before_bootstrap + @instance.config[:bootstrap_ip_address].should == "127.0.0.1" + end + + it "raise error on nil bootstrap_ip" do + @instance.ui.stub(:error) + @instance.server.stub(:addresses).and_return({"public"=>[{"version"=>4, "addr"=>nil}]}) + expect { @instance.before_bootstrap }.to raise_error(Chef::Knife::Cloud::CloudExceptions::BootstrapError, "No IP address available for bootstrapping.") + end end end