diff options
author | Lamont Granquist <lamont@scriptkiddie.org> | 2019-06-17 21:07:08 -0700 |
---|---|---|
committer | Lamont Granquist <lamont@scriptkiddie.org> | 2019-08-12 11:29:16 -0700 |
commit | 35a63ddc192e50c45f6e94a3b270ed0e75c93668 (patch) | |
tree | fed93952978c3b75febae5d90f80e1f0cd5fcc8b /lib/chef/run_context.rb | |
parent | 84da5f7a45d7ccba250d160626e6da8762a7f222 (diff) | |
download | chef-35a63ddc192e50c45f6e94a3b270ed0e75c93668.tar.gz |
Add unified_mode switch for resources
This is inspired by "use_inline_resources".
Setting `unified_mode false` in a resource would be the existing
behavior with separate compile/converge phases.
Setting `unified_mode true` in a resource will eliminate the converge
phase. Reverse notifications and delayed notifications will still
fire. The resource action will behave like all resources are executing
at compile time.
As a aside, notifications have never worked for resources firing at
compile time. This implementation gets that behavior correct so
that notifications will work.
Of course forward immediate notifications to resources not yet declared will not
be possible.
Setting `resource_unified_mode_default true` in `Chef::Config` would
turn off the split compile/converge mode for every custom resource.
NOTE: This does not affect recipe mode at all.
Signed-off-by: Lamont Granquist <lamont@scriptkiddie.org>
Diffstat (limited to 'lib/chef/run_context.rb')
-rw-r--r-- | lib/chef/run_context.rb | 78 |
1 files changed, 54 insertions, 24 deletions
diff --git a/lib/chef/run_context.rb b/lib/chef/run_context.rb index eb211dc5a5..7a5924a3c7 100644 --- a/lib/chef/run_context.rb +++ b/lib/chef/run_context.rb @@ -26,12 +26,16 @@ require_relative "recipe" require_relative "run_context/cookbook_compiler" require_relative "event_dispatch/events_output_stream" require_relative "train_transport" +require_relative "exceptions" require "forwardable" unless defined?(Forwardable) +require "set" unless defined?(Set) class Chef # Value object that loads and tracks the context of a Chef run class RunContext + extend Forwardable + # # Global state # @@ -72,14 +76,12 @@ class Chef # attr_reader :definitions - # # Event dispatcher for this run. # # @return [Chef::EventDispatch::Dispatcher] # attr_accessor :events - # # Hash of factoids for a reboot request. # # @return [Hash] @@ -90,7 +92,6 @@ class Chef # Scoped state # - # # The parent run context. # # @return [Chef::RunContext] The parent run context, or `nil` if this is the @@ -98,7 +99,6 @@ class Chef # attr_reader :parent_run_context - # # The root run context. # # @return [Chef::RunContext] The root run context. @@ -109,7 +109,6 @@ class Chef rc end - # # The collection of resources intended to be converged (and able to be # notified). # @@ -119,8 +118,12 @@ class Chef # attr_reader :resource_collection - attr_accessor :action_collection + # Handle to the global action_collection of executed actions for reporting / data_collector /etc + # + # @return [Chef::ActionCollection # + attr_accessor :action_collection + # Pointer back to the Chef::Runner that created this # attr_accessor :runner @@ -129,7 +132,6 @@ class Chef # Notification handling # - # # A Hash containing the before notifications triggered by resources # during the converge phase of the chef run. # @@ -138,7 +140,6 @@ class Chef # attr_reader :before_notification_collection - # # A Hash containing the immediate notifications triggered by resources # during the converge phase of the chef run. # @@ -147,7 +148,6 @@ class Chef # attr_reader :immediate_notification_collection - # # A Hash containing the delayed (end of run) notifications triggered by # resources during the converge phase of the chef run. # @@ -156,7 +156,6 @@ class Chef # attr_reader :delayed_notification_collection - # # An Array containing the delayed (end of run) notifications triggered by # resources during the converge phase of the chef run. # @@ -164,7 +163,16 @@ class Chef # attr_reader :delayed_actions + # 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. + # + attr_reader :updated_resources + + # @return [Boolean] If the resource_collection is in unified_mode (no separate converge phase) # + def_delegator :resource_collection, :unified_mode + # A child of the root Chef::Log logging object. # # @return Mixlib::Log::Child A child logger @@ -190,7 +198,6 @@ class Chef @loaded_attributes_hash = {} @reboot_info = {} @cookbook_compiler = nil - @delayed_actions = [] initialize_child_state end @@ -221,6 +228,7 @@ class Chef @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 # @@ -232,6 +240,10 @@ class Chef # 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 @@ -256,11 +268,13 @@ class Chef # 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 action to the +delayed_actions+. + # Adds a delayed action to the delayed_actions collection # def add_delayed_action(notification) if delayed_actions.any? { |existing_notification| existing_notification.duplicates?(notification) } @@ -271,32 +285,45 @@ class Chef end end - # # Get the list of before notifications sent by the given resource. # # @return [Array[Notification]] # def before_notifications(resource) - before_notification_collection[resource.declared_key] + key = resource.is_a?(String) ? resource : resource.declared_key + before_notification_collection[key] end - # # Get the list of immediate notifications sent by the given resource. # # @return [Array[Notification]] # def immediate_notifications(resource) - immediate_notification_collection[resource.declared_key] + key = resource.is_a?(String) ? resource : resource.declared_key + immediate_notification_collection[key] end + # Get the list of immeidate notifications pending to the given resource + # + # @return [Array[Notification]] # + 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 delayed (end of run) notifications sent by the given # resource. # # @return [Array[Notification]] # def delayed_notifications(resource) - delayed_notification_collection[resource.declared_key] + key = resource.is_a?(String) ? resource : resource.declared_key + delayed_notification_collection[key] end # @@ -666,9 +693,9 @@ class Chef rest= rest_clean rest_clean= - unreachable_cookbook? transport transport_connection + unreachable_cookbook? } def initialize(parent_run_context) @@ -681,8 +708,10 @@ class Chef end CHILD_STATE = %w{ - create_child add_delayed_action + before_notification_collection + before_notifications + create_child delayed_actions delayed_notification_collection delayed_notification_collection= @@ -690,21 +719,22 @@ class Chef immediate_notification_collection immediate_notification_collection= immediate_notifications - before_notification_collection - before_notifications include_recipe initialize_child_state load_recipe load_recipe_file notifies_before - notifies_immediately notifies_delayed + notifies_immediately parent_run_context - root_run_context resource_collection resource_collection= + reverse_immediate_notifications + root_run_context runner runner= + unified_mode + updated_resources }.map(&:to_sym) # Verify that we didn't miss any methods |