class Chef::RunContext
Value object that loads and tracks the context of a Chef
run
Attributes
Handle to the global action_collection
of executed actions for reporting / data_collector /etc
@return [Chef::ActionCollection]
A Hash containing the before notifications triggered by resources during the converge phase of the chef run.
@return [Hash[String, Array]] A hash from
<notifying resource name> => <list of notifications it sent>
The set of cookbooks involved in this run
@return [Chef::CookbookCollection]
@return [Hash<Symbol,Object>]
@return [Symbol, nil]
An Array containing the delayed (end of run) notifications triggered by resources during the converge phase of the chef run.
@return [Array] An array of notification objects
A Hash containing the delayed (end of run) notifications triggered by resources during the converge phase of the chef run.
@return [Hash[String, Array]] A hash from
<notifying resource name> => <list of notifications it sent>
Event dispatcher for this run.
@return [Chef::EventDispatch::Dispatcher]
A Hash containing the immediate notifications triggered by resources during the converge phase of the chef run.
@return [Hash[String, Array]] A hash from
<notifying resource name> => <list of notifications it sent>
Handle to the global input_collection
of inspec input files for the compliance phase
@return [Chef::Compliance::inputCollection]
A child of the root Chef::Log
logging object.
@return Mixlib::Log::Child A child logger
The node for this run
@return [Chef::Node]
The parent run context.
@return [Chef::RunContext] The parent run context, or ‘nil` if this is the
root context.
Handle to the global profile_collection
of inspec profiles for the compliance phase
@return [Chef::Compliance::ProfileCollection]
Hash of factoids for a reboot request.
@return [Hash]
The collection of resources intended to be converged (and able to be notified).
@return [Chef::ResourceCollection]
@see CookbookCompiler
Common rest object for using to talk to the Chef
Server, this strictly ‘validates’ utf8 and will throw. (will be nil on solo-legacy runs)
@return [Chef::ServerAPI]
Common rest object for using to talk to the Chef
Server, this has utf8 sanitization turned on and will replace invalid utf8 with valid characters. (will be nil on solo-legacy runs)
@return [Chef::ServerAPI]
Pointer back to the Chef::Runner
that created this
A Set keyed by the string name, of all the resources that are updated. We do not track actions or individual resource objects, since this matches the behavior of the notification collections which are keyed by Strings.
Handle to the global waiver_collection
of inspec waiver files for the compliance phase
@return [Chef::Compliance::WaiverCollection]
Public Class Methods
Source
# File lib/chef/run_context.rb, line 222 def initialize(node = nil, cookbook_collection = nil, events = nil, logger = nil) @events = events @logger = logger || Chef::Log.with_child self.node = node if node self.cookbook_collection = cookbook_collection if cookbook_collection @definitions = {} @loaded_recipes_hash = {} @loaded_attributes_hash = {} @reboot_info = {} @cookbook_compiler = nil @input_collection = Chef::Compliance::InputCollection.new(events) @waiver_collection = Chef::Compliance::WaiverCollection.new(events) @profile_collection = Chef::Compliance::ProfileCollection.new(events) @default_secret_service = nil @default_secret_config = {} initialize_child_state end
Creates a new Chef::RunContext
object and populates its fields. This object gets used by the Chef
Server to generate a fully compiled recipe list for a node.
@param node [Chef::Node] The node to run against. @param cookbook_collection
[Chef::CookbookCollection] The cookbooks
involved in this run.
@param events [EventDispatch::Dispatcher] The event dispatcher for this
run.
Public Instance Methods
Source
# File lib/chef/run_context.rb, line 319 def add_delayed_action(notification) if delayed_actions.any? { |existing_notification| existing_notification.duplicates?(notification) } logger.info( "#{notification.notifying_resource} not queuing delayed action #{notification.action} on #{notification.resource}"\ " (delayed), as it's already been queued") else delayed_actions << notification end end
Adds a delayed action to the delayed_actions
collection
Source
# File lib/chef/run_context.rb, line 332 def before_notifications(resource) key = resource.is_a?(String) ? resource : resource.declared_key before_notification_collection[key] end
Get the list of before notifications sent by the given resource.
@return [Array]
Source
# File lib/chef/run_context.rb, line 648 def cancel_reboot logger.info "Changing reboot status from #{reboot_info.inspect} to {}" @reboot_info = {} end
Cancels a pending reboot
Source
# File lib/chef/run_context.rb, line 246 def cookbook_collection=(cookbook_collection) @cookbook_collection = cookbook_collection node.set_cookbook_attribute end
Source
# File lib/chef/run_context.rb, line 680 def create_child ChildRunContext.new(self) end
Create a child RunContext
.
Source
# File lib/chef/run_context.rb, line 364 def delayed_notifications(resource) key = resource.is_a?(String) ? resource : resource.declared_key delayed_notification_collection[key] end
Get the list of delayed (end of run) notifications sent by the given resource.
@return [Array]
Source
# File lib/chef/run_context.rb, line 591 def has_cookbook_file_in_cookbook?(cookbook, cb_file_name) cookbook = cookbook_collection[cookbook] cookbook.has_cookbook_file_for_node?(node, cb_file_name) end
Find out if the cookbook has the given file.
@param cookbook [String] Cookbook
name. @param cb_file_name [String] File name.
@return [Boolean] ‘true` if the file is in the cookbook, `false`
otherwise.
Source
# File lib/chef/run_context.rb, line 576 def has_template_in_cookbook?(cookbook, template_name) cookbook = cookbook_collection[cookbook] cookbook.has_template_for_node?(node, template_name) end
Find out if the cookbook has the given template.
@param cookbook [String] Cookbook
name. @param template_name [String] Template name.
@return [Boolean] ‘true` if the template is in the cookbook, `false`
otherwise.
Source
# File lib/chef/run_context.rb, line 341 def immediate_notifications(resource) key = resource.is_a?(String) ? resource : resource.declared_key immediate_notification_collection[key] end
Get the list of immediate notifications sent by the given resource.
@return [Array]
Source
# File lib/chef/run_context.rb, line 382 def include_recipe(*recipe_names, current_cookbook: nil) result_recipes = [] recipe_names.flatten.each do |recipe_name| if result = load_recipe(recipe_name, current_cookbook: current_cookbook) result_recipes << result end end result_recipes end
Evaluates the recipes recipe_names
. Used by DSL::IncludeRecipe
@param recipe_names [Array] The list of recipe names (e.g.
'my_cookbook' or 'my_cookbook::my_resource').
@param current_cookbook The cookbook we are currently running in.
Source
# File lib/chef/run_context.rb, line 265 def initialize_child_state @resource_collection = Chef::ResourceCollection.new(self) @before_notification_collection = Hash.new { |h, k| h[k] = [] } @immediate_notification_collection = Hash.new { |h, k| h[k] = [] } @delayed_notification_collection = Hash.new { |h, k| h[k] = [] } @delayed_actions = [] @updated_resources = Set.new end
Initialize state that applies to both Chef::RunContext
and Chef::ChildRunContext
Source
# File lib/chef/run_context.rb, line 257 def load(run_list_expansion) @cookbook_compiler = CookbookCompiler.new(self, run_list_expansion, events) cookbook_compiler.compile end
Triggers the compile phase of the chef run.
@param run_list_expansion [Chef::RunList::RunListExpansion] The run list. @see Chef::RunContext::CookbookCompiler
Source
# File lib/chef/run_context.rb, line 407 def load_recipe(recipe_name, current_cookbook: nil) logger.trace("Loading recipe #{recipe_name} via include_recipe") cookbook_name, recipe_short_name = Chef::Recipe.parse_recipe_name(recipe_name, current_cookbook: current_cookbook) if unreachable_cookbook?(cookbook_name) # CHEF-4367 logger.warn(<<~ERROR_MESSAGE) MissingCookbookDependency: Recipe `#{recipe_name}` is not in the run_list, and cookbook '#{cookbook_name}' is not a dependency of any cookbook in the run_list. To load this recipe, first add a dependency of the cookbook '#{cookbook_name}' into the metadata of the cookbook which depends on '#{cookbook_name}'. ERROR_MESSAGE end if loaded_fully_qualified_recipe?(cookbook_name, recipe_short_name) logger.trace("I am not loading #{recipe_name}, because I have already seen it.") false else loaded_recipe(cookbook_name, recipe_short_name) node.loaded_recipe(cookbook_name, recipe_short_name) cookbook = cookbook_collection[cookbook_name] cookbook.load_recipe(recipe_short_name, self) end end
Evaluates the recipe recipe_name
. Used by DSL::IncludeRecipe
TODO I am sort of confused why we have both this and include_recipe
…
I don't see anything different beyond accepting and returning an array of recipes.
@param recipe_name [Array] The recipe name (e.g ‘my_cookbook’ or
'my_cookbook::my_resource').
@param current_cookbook [String] The cookbook we are currently running in.
@return A truthy value if the load occurred; ‘false` if already loaded.
Source
# File lib/chef/run_context.rb, line 442 def load_recipe_file(recipe_file) unless File.exist?(recipe_file) raise Chef::Exceptions::RecipeNotFound, "could not find recipe file #{recipe_file}" end logger.trace("Loading recipe file #{recipe_file}") recipe = Chef::Recipe.new("@recipe_files", recipe_file, self) recipe.from_file(recipe_file) recipe end
Load the given recipe from a filename.
@param recipe_file [String] The recipe filename.
@return [Chef::Recipe] The loaded recipe.
@raise [Chef::Exceptions::RecipeNotFound] If the file does not exist.
Source
# File lib/chef/run_context.rb, line 559 def loaded_attribute(cookbook, attribute_file) loaded_attributes_hash["#{cookbook}::#{attribute_file}"] = true end
Mark a given attribute file as having been loaded.
@param cookbook [String] Cookbook
name. @param attribute_file [String] Attribute file name.
Source
# File lib/chef/run_context.rb, line 502 def loaded_attributes loaded_attributes_hash.keys end
A list of all attributes files that have been loaded.
Stored internally using a Hash, so order is predictable.
TODO is the above statement true in a 1.9+ ruby world? Is it relevant?
@return [Array] A list of attribute file names in fully qualified
form, e.g. the "nginx" will be given as "nginx::default".
Source
# File lib/chef/run_context.rb, line 549 def loaded_fully_qualified_attribute?(cookbook, attribute_file) loaded_attributes_hash.key?("#{cookbook}::#{attribute_file}") end
Find out if a given attribute file has been loaded.
@param cookbook [String] Cookbook
name. @param attribute_file [String] Attribute file name.
@return [Boolean] ‘true` if the recipe has been loaded, `false` otherwise.
Source
# File lib/chef/run_context.rb, line 514 def loaded_fully_qualified_recipe?(cookbook, recipe) loaded_recipes_hash.key?("#{cookbook}::#{recipe}") end
Find out if a given recipe has been loaded.
@param cookbook [String] Cookbook
name. @param recipe [String] Recipe
name.
@return [Boolean] ‘true` if the recipe has been loaded, `false` otherwise.
Source
Source
# File lib/chef/run_context.rb, line 526 def loaded_recipe?(recipe) cookbook, recipe_name = Chef::Recipe.parse_recipe_name(recipe) loaded_fully_qualified_recipe?(cookbook, recipe_name) end
Find out if a given recipe has been loaded.
@param recipe [String] Recipe
name. “nginx” and “nginx::default” yield
the same results.
@return [Boolean] ‘true` if the recipe has been loaded, `false` otherwise.
Source
# File lib/chef/run_context.rb, line 488 def loaded_recipes loaded_recipes_hash.keys end
A list of all recipes that have been loaded.
This is stored internally as a Hash, so ordering is predictable.
TODO is the above statement true in a 1.9+ ruby world? Is it relevant?
@return [Array] A list of recipes in fully qualified form, e.g.
the recipe "nginx" will be given as "nginx::default".
@see loaded_recipe?
To determine if a particular recipe has been loaded.
Source
# File lib/chef/run_context.rb, line 241 def node=(node) @node = node node.run_context = self end
Source
# File lib/chef/run_context.rb, line 279 def notifies_before(notification) # Note for the future, notification.notifying_resource may be an instance # of Chef::Resource::UnresolvedSubscribes when calling {Resource#subscribes} # with a string value. if unified_mode && updated_resources.include?(notification.notifying_resource.declared_key) raise Chef::Exceptions::UnifiedModeBeforeSubscriptionEarlierResource.new(notification) end before_notification_collection[notification.notifying_resource.declared_key] << notification end
Adds an before notification to the before_notification_collection
.
@param [Chef::Resource::Notification] notification The notification to add.
Source
# File lib/chef/run_context.rb, line 307 def notifies_delayed(notification) # Note for the future, notification.notifying_resource may be an instance # of Chef::Resource::UnresolvedSubscribes when calling {Resource#subscribes} # with a string value. if unified_mode && updated_resources.include?(notification.notifying_resource.declared_key) add_delayed_action(notification) end delayed_notification_collection[notification.notifying_resource.declared_key] << notification end
Adds a delayed notification to the delayed_notification_collection
.
@param [Chef::Resource::Notification] notification The notification to add.
Source
# File lib/chef/run_context.rb, line 295 def notifies_immediately(notification) # Note for the future, notification.notifying_resource may be an instance # of Chef::Resource::UnresolvedSubscribes when calling {Resource#subscribes} # with a string value. immediate_notification_collection[notification.notifying_resource.declared_key] << notification end
Adds an immediate notification to the immediate_notification_collection
.
@param [Chef::Resource::Notification] notification The notification to add.
Source
# File lib/chef/run_context.rb, line 620 def open_stream(name: nil, **options) stream = EventDispatch::EventsOutputStream.new(events, name: name, **options) if block_given? begin yield stream ensure stream.close end else stream end end
Open a stream object that can be printed into and will dispatch to events
@param name [String] The name of the stream. @param options [Hash] Other options for the stream.
@return [EventDispatch::EventsOutputStream] The created stream.
@yield If a block is passed, it will be run and the stream will be closed
afterwards.
@yieldparam stream [EventDispatch::EventsOutputStream] The created stream.
Source
# File lib/chef/run_context.rb, line 657 def reboot_requested? reboot_info.size > 0 end
Checks to see if a reboot has been requested @return [Boolean]
Source
# File lib/chef/run_context.rb, line 640 def request_reboot(reboot_info) logger.info "Changing reboot status from #{self.reboot_info.inspect} to #{reboot_info.inspect}" @reboot_info = reboot_info end
there are options for how to handle multiple calls to these functions:
-
first call always wins (never change
reboot_info
once set). -
last call always wins (happily change
reboot_info
whenever). -
raise an exception on the first conflict.
-
disable reboot after this run if anyone ever calls :cancel.
-
raise an exception on any second call.
-
?
Source
# File lib/chef/run_context.rb, line 466 def resolve_attribute(cookbook_name, attr_file_name) cookbook = cookbook_collection[cookbook_name] raise Chef::Exceptions::CookbookNotFound, "could not find cookbook #{cookbook_name} while loading attribute #{name}" unless cookbook attribute_filename = cookbook.attribute_filenames_by_short_filename[attr_file_name] raise Chef::Exceptions::AttributeNotFound, "could not find filename for attribute #{attr_file_name} in cookbook #{cookbook_name}" unless attribute_filename attribute_filename end
Look up an attribute filename.
@param cookbook_name [String] The cookbook name of the attribute file. @param attr_file_name [String] The attribute file’s name (not path).
@return [String] The filename.
@see DSL::IncludeAttribute#include_attribute
@raise [Chef::Exceptions::CookbookNotFound] If the cookbook could not be found. @raise [Chef::Exceptions::AttributeNotFound] If the attribute file could not be found.
Source
# File lib/chef/run_context.rb, line 350 def reverse_immediate_notifications(resource) immediate_notification_collection.map do |k, v| v.select do |n| (n.resource.is_a?(String) && n.resource == resource.declared_key) || n.resource == resource end end.flatten end
Get the list of immediate notifications pending to the given resource
@return [Array]
Source
# File lib/chef/run_context.rb, line 109 def root_run_context rc = self rc = rc.parent_run_context until rc.parent_run_context.nil? rc end
The root run context.
@return [Chef::RunContext] The root run context.
Source
# File lib/chef/run_context.rb, line 665 def transport @transport ||= Chef::TrainTransport.new(logger).build_transport end
Remote transport from Train
@return [Train::Plugins::Transport] The child class for our train transport.
Source
# File lib/chef/run_context.rb, line 673 def transport_connection @transport_connection ||= transport&.connection end
Remote connection object from Train
@return [Train::Plugins::Transport::BaseConnection]
Source
# File lib/chef/run_context.rb, line 604 def unreachable_cookbook?(cookbook_name) cookbook_compiler.unreachable_cookbook?(cookbook_name) end
Find out whether the given cookbook is in the cookbook dependency graph.
@param cookbook_name [String] Cookbook
name.
@return [Boolean] ‘true` if the cookbook is reachable, `false` otherwise.
@see Chef::CookbookCompiler#unreachable_cookbook?