diff options
-rw-r--r-- | chef.gemspec | 2 | ||||
-rw-r--r-- | lib/chef/application.rb | 9 | ||||
-rw-r--r-- | lib/chef/application/client.rb | 4 | ||||
-rw-r--r-- | lib/chef/client.rb | 6 | ||||
-rw-r--r-- | lib/chef/run_context.rb | 11 | ||||
-rw-r--r-- | spec/integration/client/client_spec.rb | 77 | ||||
-rw-r--r-- | spec/unit/application/client_spec.rb | 1 |
7 files changed, 104 insertions, 6 deletions
diff --git a/chef.gemspec b/chef.gemspec index 4a05be1d11..63acbba8ac 100644 --- a/chef.gemspec +++ b/chef.gemspec @@ -14,7 +14,7 @@ Gem::Specification.new do |s| s.add_dependency "mime-types", "~> 1.25" s.add_dependency "mixlib-config", "~> 2.0" - s.add_dependency "mixlib-cli", "~> 1.3" + s.add_dependency "mixlib-cli", "~> 1.4" s.add_dependency "mixlib-log", "~> 1.3" s.add_dependency "mixlib-authentication", "~> 1.3" s.add_dependency "mixlib-shellout", "~> 1.2" diff --git a/lib/chef/application.rb b/lib/chef/application.rb index c1fc3a78a4..98bdedff7f 100644 --- a/lib/chef/application.rb +++ b/lib/chef/application.rb @@ -196,12 +196,17 @@ class Chef::Application end # Initializes Chef::Client instance and runs it - def run_chef_client + def run_chef_client(specific_recipes = []) Chef::Application.setup_server_connectivity + override_runlist = config[:override_runlist] + if specific_recipes.size > 0 + override_runlist ||= [] + end @chef_client = Chef::Client.new( @chef_client_json, - :override_runlist => config[:override_runlist] + :override_runlist => config[:override_runlist], + :specific_recipes => specific_recipes ) @chef_client_json = nil diff --git a/lib/chef/application/client.rb b/lib/chef/application/client.rb index a04b4f1cf6..de644b5f31 100644 --- a/lib/chef/application/client.rb +++ b/lib/chef/application/client.rb @@ -230,6 +230,8 @@ class Chef::Application::Client < Chef::Application def reconfigure super + Chef::Config[:specific_recipes] = cli_arguments.map { |file| File.expand_path(file) } + Chef::Config[:chef_server_url] = config[:chef_server_url] if config.has_key? :chef_server_url Chef::Config.local_mode = config[:local_mode] if config.has_key?(:local_mode) @@ -309,7 +311,7 @@ class Chef::Application::Client < Chef::Application Chef::Log.debug("Splay sleep #{splay} seconds") sleep splay end - run_chef_client + run_chef_client(Chef::Config[:specific_recipes]) if Chef::Config[:interval] Chef::Log.debug("Sleeping for #{Chef::Config[:interval]} seconds") unless SELF_PIPE.empty? diff --git a/lib/chef/client.rb b/lib/chef/client.rb index 6a39395bb6..31def49a3d 100644 --- a/lib/chef/client.rb +++ b/lib/chef/client.rb @@ -146,6 +146,7 @@ class Chef @events = EventDispatch::Dispatcher.new(*event_handlers) @override_runlist = args.delete(:override_runlist) + @specific_recipes = args.delete(:specific_recipes) runlist_override_sanity_check! end @@ -248,6 +249,11 @@ class Chef run_status.run_context = run_context run_context.load(@run_list_expansion) + if @specific_recipes + @specific_recipes.each do |recipe_file| + run_context.load_recipe_file(recipe_file) + end + end assert_cookbook_path_not_empty(run_context) run_context end diff --git a/lib/chef/run_context.rb b/lib/chef/run_context.rb index 4d431116f9..2ed29a2e34 100644 --- a/lib/chef/run_context.rb +++ b/lib/chef/run_context.rb @@ -152,6 +152,17 @@ class Chef end end + def load_recipe_file(recipe_file) + if !File.exist?(recipe_file) + raise Chef::Exceptions::RecipeNotFound, "could not find recipe file #{recipe_file}" + end + + Chef::Log.debug("Loading Recipe File #{recipe_file}") + recipe = Chef::Recipe.new('@recipe_files', recipe_file, self) + recipe.from_file(recipe_file) + recipe + end + # Looks up an attribute file given the +cookbook_name+ and # +attr_file_name+. Used by DSL::IncludeAttribute def resolve_attribute(cookbook_name, attr_file_name) diff --git a/spec/integration/client/client_spec.rb b/spec/integration/client/client_spec.rb index ffdded10e8..a114924666 100644 --- a/spec/integration/client/client_spec.rb +++ b/spec/integration/client/client_spec.rb @@ -101,14 +101,87 @@ EOM it "should complete with success even with a client key" do file 'config/client.rb', <<EOM local_mode true -client_key "#{path_to('mykey.pem')}" -cookbook_path "#{path_to('cookbooks')}" +client_key #{path_to('mykey.pem').inspect} +cookbook_path #{path_to('cookbooks').inspect} EOM chef_dir = File.join(File.dirname(__FILE__), "..", "..", "..", "bin") result = shell_out("chef-client -c \"#{path_to('config/client.rb')}\" -o 'x::default'", :cwd => chef_dir) result.error! end + + it "should run recipes specified directly on the command line" do + file 'config/client.rb', <<EOM +local_mode true +client_key #{path_to('mykey.pem').inspect} +cookbook_path #{path_to('cookbooks').inspect} +EOM + + file 'arbitrary.rb', <<EOM +file #{path_to('tempfile.txt').inspect} do + content '1' +end +EOM + + file 'arbitrary2.rb', <<EOM +file #{path_to('tempfile2.txt').inspect} do + content '2' +end +EOM + + chef_dir = File.join(File.dirname(__FILE__), "..", "..", "..", "bin") + result = shell_out("chef-client -c \"#{path_to('config/client.rb')}\" #{path_to('arbitrary.rb')} #{path_to('arbitrary2.rb')}", :cwd => chef_dir) + result.error! + + IO.read(path_to('tempfile.txt')).should == '1' + IO.read(path_to('tempfile2.txt')).should == '2' + end + + it "should run recipes specified as relative paths directly on the command line" do + file 'config/client.rb', <<EOM +local_mode true +client_key #{path_to('mykey.pem').inspect} +cookbook_path #{path_to('cookbooks').inspect} +EOM + + file 'arbitrary.rb', <<EOM +file #{path_to('tempfile.txt').inspect} do + content '1' +end +EOM + + chef_dir = File.join(File.dirname(__FILE__), "..", "..", "..", "bin") + result = shell_out("#{chef_dir}/chef-client -c \"#{path_to('config/client.rb')}\" arbitrary.rb", :cwd => path_to('')) + result.error! + + IO.read(path_to('tempfile.txt')).should == '1' + end + + it "should run recipes specified directly on the command line AFTER recipes in the run list" do + file 'config/client.rb', <<EOM +local_mode true +client_key #{path_to('mykey.pem').inspect} +cookbook_path #{path_to('cookbooks').inspect} +EOM + + file 'cookbooks/x/recipes/constant_definition.rb', <<EOM +class ::Blah + THECONSTANT = '1' +end +EOM + file 'arbitrary.rb', <<EOM +file #{path_to('tempfile.txt').inspect} do + content ::Blah::THECONSTANT +end +EOM + + chef_dir = File.join(File.dirname(__FILE__), "..", "..", "..", "bin") + result = shell_out("#{chef_dir}/chef-client -c \"#{path_to('config/client.rb')}\" -o x::constant_definition arbitrary.rb", :cwd => path_to('')) + result.error! + + IO.read(path_to('tempfile.txt')).should == '1' + end + end it "should complete with success when passed the -z flag" do diff --git a/spec/unit/application/client_spec.rb b/spec/unit/application/client_spec.rb index c4387890cd..219a894cc6 100644 --- a/spec/unit/application/client_spec.rb +++ b/spec/unit/application/client_spec.rb @@ -26,6 +26,7 @@ describe Chef::Application::Client, "reconfigure" do @app.stub!(:configure_opt_parser).and_return(true) @app.stub!(:configure_chef).and_return(true) @app.stub!(:configure_logging).and_return(true) + @app.cli_arguments = [] Chef::Config[:interval] = 10 Chef::Config[:once] = false |