diff options
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | DOC_CHANGES.md | 63 | ||||
-rw-r--r-- | chef-config/lib/chef-config/config.rb | 6 | ||||
-rw-r--r-- | lib/chef/application/client.rb | 6 | ||||
-rw-r--r-- | lib/chef/policy_builder/policyfile.rb | 36 | ||||
-rw-r--r-- | spec/unit/application/client_spec.rb | 15 | ||||
-rw-r--r-- | spec/unit/policy_builder/policyfile_spec.rb | 106 |
7 files changed, 211 insertions, 23 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 4df36163fd..7c83dbed88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,8 @@ of partial templates. * [**Joel Handwell**](https://github.com/joelhandwell): [pr#3821](https://github.com/chef/chef/pull/3821) Human friendly elapsed time in log +* [pr#3928](https://github.com/chef/chef/pull/3928) Add named run list support when using policyfiles +* [pr#3913](https://github.com/chef/chef/pull/3913) Add `policy_name`and `policy_group` fields to the node object * [pr#3875](https://github.com/chef/chef/pull/3875) Patch Win32::Registry#delete_key, #delete_value to use wide (W) APIs * [pr#3850](https://github.com/chef/chef/pull/3850) Patch Win32::Registry#write to fix encoding errors * [pr#3837](https://github.com/chef/chef/pull/3837) refactor remote_directory provider for mem+perf improvement diff --git a/DOC_CHANGES.md b/DOC_CHANGES.md index 4c07dea872..0b467f2570 100644 --- a/DOC_CHANGES.md +++ b/DOC_CHANGES.md @@ -6,6 +6,69 @@ Example Doc Change: Description of the required change. --> +### client.rb named run list setting + +Policyfiles allow for multiple named run lists to be specified. To use +them in chef-client, one can either specify them on the command line +with: + +``` +chef-client --named-run-list NAME +``` + +or use the short option: + +``` +chef-client -n NAME +``` + +or specify the named run list in client.rb: + +```ruby +named_run_list "NAME" +``` + +NOTE: ChefDK has supported named run lists in policyfiles for a few +releases, but is affected by a bug where named run lists can be deleted +from a Policyfile.lock.json during the upload. The fix will likely be +included in ChefDK 0.8.0. See: https://github.com/chef/chef-dk/pull/520 + +### client.rb policyfile settings + +Chef client can be configured to run in policyfile mode by setting +`policy_name` and `policy_group` in client.rb. In order to use +policyfiles, _both_ settings should be set. Example: + +```ruby +policy_name "appserver" +policy_group "staging" +``` + +As of Chef Client 12.5, when used in conjunction with Chef Server 12.3, +these settings can instead be set directly on the node object. Setting +them via the node JSON as described below will result in Chef Client +creating the node object with these settings. + +### `chef-client -j JSON` + +Chef client node JSON can now be used to specify the policyfile settings +`policy_name` and `policy_group`, like so: + +```json +{ + "policy_name": "appserver", + "policy_group": "staging" +} +``` + +Doing so will cause `chef-client` to switch to policyfile mode +automatically (i.e., the `use_policy` flag in `client.rb` is not +required). + +Users who wish to take advantage of this functionality should upgrade +the Chef Server to at least 12.3, which is the first Chef Server release +capable of storing `policy_name` and `policy_group` in the node data. + ### PSCredential Support for `dsc_script` `dsc_script` now supports the use of `ps_credential` to create a PSCredential diff --git a/chef-config/lib/chef-config/config.rb b/chef-config/lib/chef-config/config.rb index 76ee589ff9..32058f283a 100644 --- a/chef-config/lib/chef-config/config.rb +++ b/chef-config/lib/chef-config/config.rb @@ -356,6 +356,12 @@ module ChefConfig default :policy_name, nil default :policy_group, nil + # Policyfiles can have multiple run lists, via the named run list feature. + # Generally this will be set by a CLI option via Chef::Application::Client, + # but it could be set in client.rb if desired. + + default :named_run_list, nil + # During initial development, users were required to set `use_policyfile true` # in `client.rb` to opt-in to policyfile use. Chef Client now examines # configuration, node json, and the stored node to determine if policyfile diff --git a/lib/chef/application/client.rb b/lib/chef/application/client.rb index 73eda81343..148257ab89 100644 --- a/lib/chef/application/client.rb +++ b/lib/chef/application/client.rb @@ -160,6 +160,12 @@ class Chef::Application::Client < Chef::Application :description => "Set the client key file location", :proc => nil + option :named_run_list, + :short => "-n NAMED_RUN_LIST", + :long => "--named-run-list NAMED_RUN_LIST", + :description => "Use a policyfile's named run list instead of the default run list", + :default => nil + option :environment, :short => '-E ENVIRONMENT', :long => '--environment ENVIRONMENT', diff --git a/lib/chef/policy_builder/policyfile.rb b/lib/chef/policy_builder/policyfile.rb index 69ef485e14..bb9593eb36 100644 --- a/lib/chef/policy_builder/policyfile.rb +++ b/lib/chef/policy_builder/policyfile.rb @@ -170,6 +170,8 @@ class Chef # # @return [RunListExpansionIsh] A RunListExpansion duck-type. def expand_run_list + CookbookCacheCleaner.instance.skip_removal = true if named_run_list_requested? + node.run_list(run_list) node.automatic_attrs[:roles] = [] node.automatic_attrs[:recipes] = run_list_expansion_ish.recipes @@ -253,7 +255,14 @@ class Chef # @api private def run_list - policy["run_list"] + if named_run_list_requested? + named_run_list or + raise ConfigurationError, + "Policy '#{retrieved_policy_name}' revision '#{revision_id}' does not have named_run_list '#{named_run_list_name}'" + + "(available named_run_lists: [#{available_named_run_lists.join(', ')}])" + else + policy["run_list"] + end end # @api private @@ -441,6 +450,11 @@ class Chef end # @api private + def revision_id + policy["revision_id"] + end + + # @api private def http_api @api_service ||= Chef::REST.new(config[:chef_server_url]) end @@ -462,6 +476,26 @@ class Chef Chef.set_run_context(run_context) end + def retrieved_policy_name + policy["name"] + end + + def named_run_list + policy["named_run_lists"] && policy["named_run_lists"][named_run_list_name] + end + + def available_named_run_lists + (policy["named_run_lists"] || {}).keys + end + + def named_run_list_requested? + !!Chef::Config[:named_run_list] + end + + def named_run_list_name + Chef::Config[:named_run_list] + end + def compat_mode_manifest_for(cookbook_name, lock_data) xyz_version = lock_data["dotted_decimal_identifier"] rel_url = "cookbooks/#{cookbook_name}/#{xyz_version}" diff --git a/spec/unit/application/client_spec.rb b/spec/unit/application/client_spec.rb index 64a6bcc9d2..831a3fc19e 100644 --- a/spec/unit/application/client_spec.rb +++ b/spec/unit/application/client_spec.rb @@ -47,6 +47,19 @@ describe Chef::Application::Client, "reconfigure" do expect(app).to receive(:set_specific_recipes).and_return(true) app.reconfigure end + + context "when given a named_run_list" do + + before do + ARGV.replace( %w[ --named-run-list arglebargle-example ] ) + app.reconfigure + end + + it "sets named_run_list in Chef::Config" do + expect(Chef::Config[:named_run_list]).to eq("arglebargle-example") + end + + end end describe "when configured to not fork the client process" do @@ -237,7 +250,7 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config end it "should throw an exception" do - expect { @app.reconfigure }.to raise_error + expect { app.reconfigure }.to raise_error(Chef::Exceptions::PIDFileLockfileMatch) end end end diff --git a/spec/unit/policy_builder/policyfile_spec.rb b/spec/unit/policy_builder/policyfile_spec.rb index 9a39161648..b656a66ec3 100644 --- a/spec/unit/policy_builder/policyfile_spec.rb +++ b/spec/unit/policy_builder/policyfile_spec.rb @@ -76,8 +76,11 @@ describe Chef::PolicyBuilder::Policyfile do let(:policyfile_run_list) { ["recipe[example1::default]", "recipe[example2::server]"] } - let(:parsed_policyfile_json) do + let(:basic_valid_policy_data) do { + "name" => "example-policy", + "revision_id" => "123abc", + "run_list" => policyfile_run_list, "cookbook_locks" => { @@ -90,6 +93,8 @@ describe Chef::PolicyBuilder::Policyfile do } end + let(:parsed_policyfile_json) { basic_valid_policy_data } + let(:err_namespace) { Chef::PolicyBuilder::Policyfile } it "configures a Chef HTTP API client" do @@ -498,34 +503,93 @@ describe Chef::PolicyBuilder::Policyfile do expect(node["override_key"]).to be_nil end - it "applies ohai data" do - expect(ohai_data).to_not be_empty # ensure test is testing something - ohai_data.each do |key, value| - expect(node.automatic_attrs[key]).to eq(value) + describe "setting attribute values" do + + before do + policy_builder.build_node end - end - it "applies attributes from json file" do - expect(node["custom_attr"]).to eq("custom_attr_value") - end + it "resets default and override data" do + expect(node["default_key"]).to be_nil + expect(node["override_key"]).to be_nil + end - it "applies attributes from the policyfile" do - expect(node["policyfile_default_attr"]).to eq("policyfile_default_value") - expect(node["policyfile_override_attr"]).to eq("policyfile_override_value") - end + it "applies ohai data" do + expect(ohai_data).to_not be_empty # ensure test is testing something + ohai_data.each do |key, value| + expect(node.automatic_attrs[key]).to eq(value) + end + end - it "sets the policyfile's run_list on the node object" do - expect(node.run_list).to eq(policyfile_run_list) - end + it "applies attributes from json file" do + expect(node["custom_attr"]).to eq("custom_attr_value") + end - it "creates node.automatic_attrs[:roles]" do - expect(node.automatic_attrs[:roles]).to eq([]) - end + it "applies attributes from the policyfile" do + expect(node["policyfile_default_attr"]).to eq("policyfile_default_value") + expect(node["policyfile_override_attr"]).to eq("policyfile_override_value") + end + + it "sets the policyfile's run_list on the node object" do + expect(node.run_list).to eq(policyfile_run_list) + end - it "create node.automatic_attrs[:recipes]" do - expect(node.automatic_attrs[:recipes]).to eq(["example1::default", "example2::server"]) + it "creates node.automatic_attrs[:roles]" do + expect(node.automatic_attrs[:roles]).to eq([]) + end + + it "create node.automatic_attrs[:recipes]" do + expect(node.automatic_attrs[:recipes]).to eq(["example1::default", "example2::server"]) + end end + context "when a named run_list is given" do + + before do + Chef::Config[:named_run_list] = "deploy-app" + end + + context "and the named run_list is not present in the policy" do + + it "raises a ConfigurationError" do + err_class = Chef::PolicyBuilder::Policyfile::ConfigurationError + err_text = "Policy 'example-policy' revision '123abc' does not have named_run_list 'deploy-app'(available named_run_lists: [])" + expect { policy_builder.build_node }.to raise_error(err_class, err_text) + end + + end + + context "and the named run_list is present in the policy" do + + let(:parsed_policyfile_json) do + basic_valid_policy_data.dup.tap do |p| + p["named_run_lists"] = { + "deploy-app" => [ "recipe[example1::default]" ] + } + end + end + + before do + policy_builder.build_node + end + + it "sets the run list to the desired named run list" do + expect(policy_builder.run_list).to eq([ "recipe[example1::default]" ]) + expected_expansion = Chef::PolicyBuilder::Policyfile::RunListExpansionIsh.new([ "example1::default" ], []) + expect(policy_builder.run_list_expansion).to eq(expected_expansion) + expect(policy_builder.run_list_with_versions_for_display).to eq(["example1::default@2.3.5 (168d210)"]) + expect(node.run_list).to eq([ Chef::RunList::RunListItem.new("recipe[example1::default]") ]) + expect(node[:roles]).to eq( [] ) + expect(node[:recipes]).to eq( ["example1::default"] ) + end + + it "disables the cookbook cache cleaner" do + expect(Chef::CookbookCacheCleaner.instance.skip_removal).to be(true) + end + + end + + end end |