summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--DOC_CHANGES.md63
-rw-r--r--chef-config/lib/chef-config/config.rb6
-rw-r--r--lib/chef/application/client.rb6
-rw-r--r--lib/chef/policy_builder/policyfile.rb36
-rw-r--r--spec/unit/application/client_spec.rb15
-rw-r--r--spec/unit/policy_builder/policyfile_spec.rb106
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