summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLamont Granquist <lamont@scriptkiddie.org>2021-06-22 21:07:56 -0700
committerLamont Granquist <lamont@scriptkiddie.org>2021-06-22 21:13:30 -0700
commit18be6b87551174018628ad8f190c3e20add29ec7 (patch)
treea14b81ce616c6fc6b9f05fbbc24ba55cf7dd037e
parentf88e0578fddabd9ac235d0709bc0a1d41d4a6b28 (diff)
downloadchef-18be6b87551174018628ad8f190c3e20add29ec7.tar.gz
Support override run_lists in policyfiles
This extends override run_lists to work with policyfiles Signed-off-by: Lamont Granquist <lamont@scriptkiddie.org>
-rw-r--r--lib/chef/policy_builder/policyfile.rb82
-rw-r--r--spec/unit/policy_builder/dynamic_spec.rb5
-rw-r--r--spec/unit/policy_builder/policyfile_spec.rb33
3 files changed, 71 insertions, 49 deletions
diff --git a/lib/chef/policy_builder/policyfile.rb b/lib/chef/policy_builder/policyfile.rb
index 35282bf915..ec2082d159 100644
--- a/lib/chef/policy_builder/policyfile.rb
+++ b/lib/chef/policy_builder/policyfile.rb
@@ -81,10 +81,12 @@ class Chef
attr_reader :ohai_data
attr_reader :json_attribs
attr_reader :run_context
+ attr_reader :override_runlist
def initialize(node_name, ohai_data, json_attribs, override_runlist, events)
@node_name = node_name
@ohai_data = ohai_data
+ @override_runlist = override_runlist
@json_attribs = json_attribs
@events = events
@@ -94,10 +96,6 @@ class Chef
raise UnsupportedFeature, "Policyfile does not support chef-solo. Use #{ChefUtils::Dist::Infra::CLIENT} local mode instead."
end
- if override_runlist
- raise UnsupportedFeature, "Policyfile does not support override run lists. Use named run_lists instead."
- end
-
if json_attribs && json_attribs.key?("run_list")
raise UnsupportedFeature, "Policyfile does not support setting the run_list in json data."
end
@@ -107,19 +105,6 @@ class Chef
end
end
- ## API Compat ##
- # Methods related to unsupported features
-
- # Override run_list is not supported.
- def original_runlist
- nil
- end
-
- # Override run_list is not supported.
- def override_runlist
- nil
- end
-
# Policyfile gives you the run_list already expanded, but users of this
# class may expect to get a run_list expansion compatible object by
# calling this method.
@@ -152,13 +137,15 @@ class Chef
node.consume_external_attrs(ohai_data, json_attribs)
+ setup_run_list_override
+
expand_run_list
apply_policyfile_attributes
Chef::Log.info("Run List is [#{run_list}]")
- Chef::Log.info("Run List expands to [#{run_list_with_versions_for_display.join(", ")}]")
+ Chef::Log.info("Run List expands to [#{run_list_with_versions_for_display(run_list).join(", ")}]")
- events.node_load_completed(node, run_list_with_versions_for_display, Chef::Config)
+ events.node_load_completed(node, run_list_with_versions_for_display(run_list), Chef::Config)
events.run_list_expanded(run_list_expansion_ish)
# we must do this after `node.consume_external_attrs`
@@ -194,6 +181,11 @@ class Chef
events.cookbook_compilation_start(run_context)
run_context.load(run_list_expansion_ish)
+ if specific_recipes
+ specific_recipes.each do |recipe_file|
+ run_context.load_recipe_file(recipe_file)
+ end
+ end
events.cookbook_compilation_complete(run_context)
@@ -231,21 +223,13 @@ class Chef
cookbooks_to_sync
end
- # Whether or not this is a temporary policy. Since PolicyBuilder doesn't
- # support override_runlist, this is always false.
- #
- # @return [false]
- def temporary_policy?
- false
- end
-
## Internal Public API ##
# @api private
#
# Generates an array of strings with recipe names including version and
# identifier info.
- def run_list_with_versions_for_display
+ def run_list_with_versions_for_display(run_list)
run_list.map do |recipe_spec|
cookbook, recipe = parse_recipe_spec(recipe_spec)
lock_data = cookbook_lock_for(cookbook)
@@ -287,7 +271,7 @@ class Chef
# @api private
def parse_recipe_spec(recipe_spec)
- rmatch = recipe_spec.match(/recipe\[([^:]+)::([^:]+)\]/)
+ rmatch = recipe_spec.to_s.match(/recipe\[([^:]+)::([^:]+)\]/)
if rmatch.nil?
raise PolicyfileError, "invalid recipe specification #{recipe_spec} in Policyfile from #{policyfile_location}"
else
@@ -301,7 +285,10 @@ class Chef
end
# @api private
+ # @return [Array<String>]
def run_list
+ return override_runlist.map(&:to_s) if override_runlist
+
if named_run_list_requested?
named_run_list || raise(ConfigurationError,
"Policy '#{retrieved_policy_name}' revision '#{revision_id}' does not have named_run_list '#{named_run_list_name}'" +
@@ -458,7 +445,7 @@ class Chef
# should be reduced to a single call.
def cookbooks_to_sync
@cookbook_to_sync ||= begin
- events.cookbook_resolution_start(run_list_with_versions_for_display)
+ events.cookbook_resolution_start(run_list_with_versions_for_display(policy["run_list"]))
cookbook_versions_by_name = cookbook_locks.inject({}) do |cb_map, (name, lock_data)|
cb_map[name] = manifest_for(name, lock_data)
@@ -470,7 +457,7 @@ class Chef
end
rescue Exception => e
# TODO: wrap/munge exception to provide helpful error output
- events.cookbook_resolution_failed(run_list_with_versions_for_display, e)
+ events.cookbook_resolution_failed(run_list_with_versions_for_display(policy["run_list"]), e)
raise
end
@@ -509,6 +496,13 @@ class Chef
Chef::Config
end
+ # Indicates whether the policy is temporary, which means an
+ # override_runlist was provided. Chef::Client uses this to decide whether
+ # to do the final node save at the end of the run or not.
+ def temporary_policy?
+ node.override_runlist_set?
+ end
+
private
# This method injects the run_context and into the Chef class.
@@ -567,6 +561,32 @@ class Chef
Chef::CookbookVersion.from_cb_artifact_data(raw_manifest)
end
+ def setup_run_list_override
+ unless override_runlist.nil?
+ runlist_override_sanity_check!
+ node.override_runlist = override_runlist
+ Chef::Log.warn "Run List override has been provided."
+ Chef::Log.warn "Original Run List: [#{node.primary_runlist}]"
+ Chef::Log.warn "Overridden Run List: [#{node.run_list}]"
+ end
+ end
+
+ # Ensures runlist override contains RunListItem instances
+ def runlist_override_sanity_check!
+ # Convert to array and remove whitespace
+ if override_runlist.is_a?(String)
+ @override_runlist = override_runlist.split(",").map(&:strip)
+ end
+ @override_runlist = [override_runlist].flatten.compact
+ override_runlist.map! do |item|
+ if item.is_a?(Chef::RunList::RunListItem)
+ item
+ else
+ Chef::RunList::RunListItem.new(item)
+ end
+ end
+ end
+
end
end
end
diff --git a/spec/unit/policy_builder/dynamic_spec.rb b/spec/unit/policy_builder/dynamic_spec.rb
index d61dec4bc8..c886f5d5e7 100644
--- a/spec/unit/policy_builder/dynamic_spec.rb
+++ b/spec/unit/policy_builder/dynamic_spec.rb
@@ -55,11 +55,6 @@ describe Chef::PolicyBuilder::Dynamic do
expect(policy_builder).to respond_to(:load_node)
end
- it "forwards #original_runlist" do
- expect(implementation).to receive(:original_runlist)
- policy_builder.original_runlist
- end
-
it "forwards #run_context" do
expect(implementation).to receive(:run_context)
policy_builder.run_context
diff --git a/spec/unit/policy_builder/policyfile_spec.rb b/spec/unit/policy_builder/policyfile_spec.rb
index 6be0da8f4d..0f19bca070 100644
--- a/spec/unit/policy_builder/policyfile_spec.rb
+++ b/spec/unit/policy_builder/policyfile_spec.rb
@@ -146,10 +146,6 @@ describe Chef::PolicyBuilder::Policyfile do
Chef::PolicyBuilder::Policyfile.new(node_name, ohai_data, json_attribs, override_runlist, events)
end
- it "always gives `false` for #temporary_policy?" do
- expect(initialize_pb.temporary_policy?).to be_falsey
- end
-
context "chef-solo" do
before { Chef::Config[:solo_legacy_mode] = true }
@@ -161,8 +157,8 @@ describe Chef::PolicyBuilder::Policyfile do
context "when given an override run_list" do
let(:override_runlist) { "recipe[foo],recipe[bar]" }
- it "errors on create" do
- expect { initialize_pb }.to raise_error(err_namespace::UnsupportedFeature)
+ it "does not error" do
+ expect { initialize_pb }.not_to raise_error
end
end
@@ -323,7 +319,7 @@ describe Chef::PolicyBuilder::Policyfile do
"example2::server@4.2.0 (feab40e)",
]
- expect(policy_builder.run_list_with_versions_for_display).to eq(expected)
+ expect(policy_builder.run_list_with_versions_for_display(policy_builder.run_list)).to eq(expected)
end
it "generates a RunListExpansion-alike object for feeding to the CookbookCompiler" do
@@ -577,11 +573,9 @@ describe Chef::PolicyBuilder::Policyfile do
expect(node.automatic_attrs[:policy_name]).to eq("policy_name_from_node_json")
expect(node.automatic_attrs[:policy_group]).to eq("policy_group_from_node_json")
expect(node.automatic_attrs[:chef_environment]).to eq("policy_group_from_node_json")
-
end
end
-
end
it "resets default and override data" do
@@ -664,7 +658,7 @@ describe Chef::PolicyBuilder::Policyfile 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(policy_builder.run_list_with_versions_for_display(policy_builder.run_list)).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"] )
@@ -675,7 +669,22 @@ describe Chef::PolicyBuilder::Policyfile do
end
end
+ end
+
+ context "when an override run_list is given" do
+ let(:override_runlist) { [ "recipe[example2::server]" ] }
+ before do
+ policy_builder.build_node
+ end
+
+ it "gives `true` for #temporary_policy?" do
+ expect(policy_builder.temporary_policy?).to be true
+ end
+
+ it "returns the override_runlist for the run_list" do
+ expect(policy_builder.run_list).to eql override_runlist
+ end
end
describe "hoisting attribute values" do
@@ -826,6 +835,7 @@ describe Chef::PolicyBuilder::Policyfile do
end
include_examples "fetching cookbooks when they exist"
+
end
end
@@ -863,10 +873,7 @@ describe Chef::PolicyBuilder::Policyfile do
end
end
-
end
end
-
end
-
end