class Chef::PolicyBuilder::ExpandNodeObject
ExpandNodeObject
is the “classic” policy builder implementation. It expands the run_list on a node object and then queries the chef-server to find the correct set of cookbooks, given version constraints of the node's environment.
Note that this class should only be used via PolicyBuilder::Dynamic
and not instantiated directly.
Attributes
Public Class Methods
# File lib/chef/policy_builder/expand_node_object.rb, line 50 def initialize(node_name, ohai_data, json_attribs, override_runlist, events) @node_name = node_name @ohai_data = ohai_data @json_attribs = json_attribs @override_runlist = override_runlist @events = events @node = nil @run_list_expansion = nil end
Public Instance Methods
# File lib/chef/policy_builder/expand_node_object.rb, line 250 def api_service @api_service ||= Chef::ServerAPI.new(config[:chef_server_url], { version_class: Chef::CookbookManifestVersions }) end
Applies environment, external JSON attributes, and override run list to the node, Then expands the run_list.
Returns¶ ↑
- node<Chef::Node>
-
The modified node object. node is modified in place.
# File lib/chef/policy_builder/expand_node_object.rb, line 124 def build_node # Allow user to override the environment of a node by specifying # a config parameter. if Chef::Config[:environment] && !Chef::Config[:environment].chomp.empty? node.chef_environment(Chef::Config[:environment]) end # consume_external_attrs may add items to the run_list. Save the # expanded run_list, which we will pass to the server later to # determine which versions of cookbooks to use. node.reset_defaults_and_overrides node.consume_external_attrs(ohai_data, @json_attribs) setup_run_list_override expand_run_list Chef::Log.info("Run List is [#{node.run_list}]") Chef::Log.info("Run List expands to [#{@expanded_run_list_with_versions.join(', ')}]") events.node_load_completed(node, @expanded_run_list_with_versions, Chef::Config) events.run_list_expanded(@run_list_expansion) node end
# File lib/chef/policy_builder/expand_node_object.rb, line 255 def config Chef::Config end
Expands the node's run list. Stores the run_list_expansion
object for later use.
# File lib/chef/policy_builder/expand_node_object.rb, line 151 def expand_run_list @run_list_expansion = if Chef::Config[:solo_legacy_mode] node.expand!("disk") else node.expand!("server") end # @run_list_expansion is a RunListExpansion. # # Convert @expanded_run_list, which is an # Array of Hashes of the form # {:name => NAME, :version_constraint => Chef::VersionConstraint }, # into @expanded_run_list_with_versions, an # Array of Strings of the form # "#{NAME}@#{VERSION}" @expanded_run_list_with_versions = @run_list_expansion.recipes.with_version_constraints_strings @run_list_expansion rescue Exception => e # TODO: wrap/munge exception with useful error output. events.run_list_expand_failed(node, e) raise end
# File lib/chef/policy_builder/expand_node_object.rb, line 115 def finish_load_node(node) @node = node end
Ensures runlist override contains RunListItem instances
# File lib/chef/policy_builder/expand_node_object.rb, line 235 def runlist_override_sanity_check! # Convert to array and remove whitespace if override_runlist.is_a?(String) @override_runlist = override_runlist.split(",").map { |e| e.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
This method injects the run_context
and into the Chef
class.
NOTE: This is duplicated with the Policyfile
implementation. If it gets any more complicated, it needs to be moved elsewhere.
@param run_context
[Chef::RunContext] the run_context
to inject
# File lib/chef/policy_builder/expand_node_object.rb, line 67 def setup_chef_class(run_context) Chef.set_run_context(run_context) end
This not only creates the run_context
but this is where we kick off compiling the entire expanded run_list, loading all the libraries, resources, attribute files and recipes, and constructing the entire resource collection. (FIXME: break up creating the run_context
and compiling the cookbooks)
# File lib/chef/policy_builder/expand_node_object.rb, line 76 def setup_run_context(specific_recipes = nil, run_context = nil) run_context ||= Chef::RunContext.new run_context.events = events run_context.node = node cookbook_collection = if Chef::Config[:solo_legacy_mode] Chef::Cookbook::FileVendor.fetch_from_disk(Chef::Config[:cookbook_path]) cl = Chef::CookbookLoader.new(Chef::Config[:cookbook_path]) cl.load_cookbooks Chef::CookbookCollection.new(cl) else Chef::Cookbook::FileVendor.fetch_from_remote(api_service) cookbook_hash = sync_cookbooks Chef::CookbookCollection.new(cookbook_hash) end cookbook_collection.validate! cookbook_collection.install_gems(events) run_context.cookbook_collection = cookbook_collection # TODO: move this into the cookbook_compilation_start hook setup_chef_class(run_context) events.cookbook_compilation_start(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 events.cookbook_compilation_complete(run_context) run_context end
Internal public API
# File lib/chef/policy_builder/expand_node_object.rb, line 224 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
Sync_cookbooks eagerly loads all files except files and templates. It returns the cookbook_hash – the return result from /environments/#{node.chef_environment}/cookbook_versions, which we will use for our run_context.
Returns¶ ↑
- Hash
-
The hash of cookbooks with download URLs as given by the server
# File lib/chef/policy_builder/expand_node_object.rb, line 181 def sync_cookbooks Chef::Log.trace("Synchronizing cookbooks") begin events.cookbook_resolution_start(@expanded_run_list_with_versions) cookbook_hash = api_service.post("environments/#{node.chef_environment}/cookbook_versions", { run_list: @expanded_run_list_with_versions }) cookbook_hash = cookbook_hash.inject({}) do |memo, (key, value)| memo[key] = Chef::CookbookVersion.from_hash(value) memo end rescue Exception => e # TODO: wrap/munge exception to provide helpful error output events.cookbook_resolution_failed(@expanded_run_list_with_versions, e) raise else events.cookbook_resolution_complete(cookbook_hash) end synchronizer = Chef::CookbookSynchronizer.new(cookbook_hash, events) if temporary_policy? synchronizer.remove_obsoleted_files = false end synchronizer.sync_cookbooks # register the file cache path in the cookbook path so that CookbookLoader actually picks up the synced cookbooks Chef::Config[:cookbook_path] = File.join(Chef::Config[:file_cache_path], "cookbooks") cookbook_hash 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.
# File lib/chef/policy_builder/expand_node_object.rb, line 216 def temporary_policy? node.override_runlist_set? end