summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chef.gemspec2
-rw-r--r--lib/chef/application.rb9
-rw-r--r--lib/chef/application/client.rb4
-rw-r--r--lib/chef/client.rb6
-rw-r--r--lib/chef/run_context.rb11
-rw-r--r--spec/integration/client/client_spec.rb77
-rw-r--r--spec/unit/application/client_spec.rb1
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