diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/chef/resource.rb | 20 | ||||
-rw-r--r-- | lib/chef/run_context.rb | 43 | ||||
-rw-r--r-- | lib/chef/runner.rb | 23 |
3 files changed, 85 insertions, 1 deletions
diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb index 43fc1f997d..634d00feef 100644 --- a/lib/chef/resource.rb +++ b/lib/chef/resource.rb @@ -209,6 +209,8 @@ class Chef # actions have been run. This is the default. # - `immediate`, `immediately`: Will run the action on the other resource # immediately (before any other action is run). + # - `immediately_before`: Will run the action on the other resource + # immediately *before* the action is actually run. # # @example Resource by string # file '/foo.txt' do @@ -251,9 +253,11 @@ class Chef notifies_delayed(action, resource) when 'immediate', 'immediately' notifies_immediately(action, resource) + when 'immediately_before' + notifies_immediately_before(action, resource) else raise ArgumentError, "invalid timing: #{timing} for notifies(#{action}, #{resources.inspect}, #{timing}) resource #{self} "\ - "Valid timings are: :delayed, :immediate, :immediately" + "Valid timings are: :delayed, :immediate, :immediately, :immediately_before" end end @@ -277,6 +281,8 @@ class Chef # actions have been run. This is the default. # - `immediate`, `immediately`: The action will run immediately following # the other resource being updated. + # - `immediately_before`: The action will run immediately before the + # other resource is updated. # # @example Resources by string # file '/foo.txt' do @@ -1238,6 +1244,9 @@ class Chef # resolve_resource_reference on each in turn, causing them to # resolve lazy/forward references. def resolve_notification_references + run_context.immediately_before_notifications(self).each { |n| + n.resolve_resource_reference(run_context.resource_collection) + } run_context.immediate_notifications(self).each { |n| n.resolve_resource_reference(run_context.resource_collection) } @@ -1247,6 +1256,11 @@ class Chef end # Helper for #notifies + def notifies_immediately_before(action, resource_spec) + run_context.notifies_immediately_before(Notification.new(resource_spec, action, self)) + end + + # Helper for #notifies def notifies_immediately(action, resource_spec) run_context.notifies_immediately(Notification.new(resource_spec, action, self)) end @@ -1341,6 +1355,10 @@ class Chef "#{declared_type}[#{@name}]" end + def immediately_before_notifications + run_context.immediately_before_notifications(self) + end + def immediate_notifications run_context.immediate_notifications(self) end diff --git a/lib/chef/run_context.rb b/lib/chef/run_context.rb index f7ab88f7e0..b725857bc5 100644 --- a/lib/chef/run_context.rb +++ b/lib/chef/run_context.rb @@ -104,6 +104,15 @@ class Chef # # + # A Hash containing the immediately_before notifications triggered by resources + # during the converge phase of the chef run. + # + # @return [Hash[String, Array[Chef::Resource::Notification]]] A hash from + # <notifying resource name> => <list of notifications it sent> + # + attr_reader :immediately_before_notification_collection + + # # A Hash containing the immediate notifications triggered by resources # during the converge phase of the chef run. # @@ -164,11 +173,26 @@ class Chef def initialize_child_state @audits = {} @resource_collection = Chef::ResourceCollection.new + @immediately_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] = []} end # + # Adds an immediately_before notification to the +immediately_before_notification_collection+. + # + # @param [Chef::Resource::Notification] The notification to add. + # + def notifies_immediately_before(notification) + nr = notification.notifying_resource + if nr.instance_of?(Chef::Resource) + immediately_before_notification_collection[nr.name] << notification + else + immediately_before_notification_collection[nr.declared_key] << notification + end + end + + # # Adds an immediate notification to the +immediate_notification_collection+. # # @param [Chef::Resource::Notification] The notification to add. @@ -197,6 +221,22 @@ class Chef end # + # Get the list of immediately_before notifications sent by the given resource. + # + # TODO seriously, this is actually wrong. resource.name is not unique, + # you need the type as well. + # + # @return [Array[Notification]] + # + def immediately_before_notifications(resource) + if resource.instance_of?(Chef::Resource) + return immediately_before_notification_collection[resource.name] + else + return immediately_before_notification_collection[resource.declared_key] + end + end + + # # Get the list of immediate notifications sent by the given resource. # # TODO seriously, this is actually wrong. resource.name is not unique, @@ -608,10 +648,13 @@ ERROR_MESSAGE immediate_notification_collection immediate_notification_collection= immediate_notifications + immediately_before_notification_collection + immediately_before_notifications include_recipe initialize_child_state load_recipe load_recipe_file + notifies_immediately_before notifies_immediately notifies_delayed parent_run_context diff --git a/lib/chef/runner.rb b/lib/chef/runner.rb index 6125fe59e1..50554dcdbc 100644 --- a/lib/chef/runner.rb +++ b/lib/chef/runner.rb @@ -46,6 +46,29 @@ class Chef # Determine the appropriate provider for the given resource, then # execute it. def run_action(resource, action, notification_type=nil, notifying_resource=nil) + + # If there are any immediately_before notifications, why-run the resource + # and notify anyone who needs notifying + if !run_context.immediately_before_notifications(resource).empty? + whyrun_before = Chef::Config[:why_run] + begin + Chef::Config[:why_run] = true + Chef::Log.info("#{resource} running why-run #{action} action to support immediately_before action") + resource.run_action(action, notification_type, notifying_resource) + ensure + Chef::Config[:why_run] = whyrun_before + end + + if resource.updated_by_last_action? + run_context.immediately_before_notifications(resource).each do |notification| + Chef::Log.info("#{resource} sending #{notification.action} action to #{notification.resource} (immediately_before)") + run_action(notification.resource, notification.action, :immediately_before, resource) + end + end + + end + + # Actually run the action for realsies resource.run_action(action, notification_type, notifying_resource) # Execute any immediate and queue up any delayed notifications |