diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/chef/resource_builder.rb | 2 | ||||
-rw-r--r-- | lib/chef/resource_collection.rb | 50 | ||||
-rw-r--r-- | lib/chef/run_context.rb | 26 | ||||
-rw-r--r-- | lib/chef/runner.rb | 40 |
4 files changed, 93 insertions, 25 deletions
diff --git a/lib/chef/resource_builder.rb b/lib/chef/resource_builder.rb index f3ca2e95ad..138e401d5c 100644 --- a/lib/chef/resource_builder.rb +++ b/lib/chef/resource_builder.rb @@ -137,7 +137,7 @@ class Chef @prior_resource ||= begin key = "#{type}[#{name}]" - run_context.resource_collection.lookup(key) + run_context.resource_collection.lookup_local(key) rescue Chef::Exceptions::ResourceNotFound nil end diff --git a/lib/chef/resource_collection.rb b/lib/chef/resource_collection.rb index 6c5b4289d8..1429c25d7f 100644 --- a/lib/chef/resource_collection.rb +++ b/lib/chef/resource_collection.rb @@ -33,9 +33,12 @@ class Chef extend Forwardable attr_reader :resource_set, :resource_list - private :resource_set, :resource_list + attr_accessor :run_context - def initialize + protected :resource_set, :resource_list + + def initialize(run_context = nil) + @run_context = run_context @resource_set = ResourceSet.new @resource_list = ResourceList.new end @@ -79,11 +82,50 @@ class Chef resource_list_methods = Enumerable.instance_methods + [:iterator, :all_resources, :[], :each, :execute_each_resource, :each_index, :empty?] - - [:find] # find needs to run on the set - resource_set_methods = [:lookup, :find, :resources, :keys, :validate_lookup_spec!] + [:find] # find overridden below + resource_set_methods = [:resources, :keys, :validate_lookup_spec!] def_delegators :resource_list, *resource_list_methods def_delegators :resource_set, *resource_set_methods + def lookup_local(key) + resource_set.lookup(key) + end + + def find_local(*args) + resource_set.find(*args) + end + + def lookup(key) + if run_context.nil? + lookup_local(key) + else + lookup_recursive(run_context, key) + end + end + + def find(*args) + if run_context.nil? + find_local(*args) + else + find_recursive(run_context, *args) + end + end + + private + + def lookup_recursive(rc, key) + rc.resource_collection.resource_set.lookup(key) + rescue Chef::Exceptions::ResourceNotFound + raise if rc.parent_run_context.nil? + lookup_recursive(rc.parent_run_context, key) + end + + def find_recursive(rc, *args) + rc.resource_collection.resource_set.find(*args) + rescue Chef::Exceptions::ResourceNotFound + raise if rc.parent_run_context.nil? + find_recursive(rc.parent_run_context, *args) + end end end diff --git a/lib/chef/run_context.rb b/lib/chef/run_context.rb index cb3338d3de..29c936a932 100644 --- a/lib/chef/run_context.rb +++ b/lib/chef/run_context.rb @@ -130,6 +130,14 @@ 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. + # + # @return [Array[Chef::Resource::Notification]] An array of notification objects + # + attr_reader :delayed_actions + # 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. # @@ -152,6 +160,7 @@ class Chef @loaded_attributes_hash = {} @reboot_info = {} @cookbook_compiler = nil + @delayed_actions = [] initialize_child_state end @@ -172,10 +181,11 @@ class Chef # def initialize_child_state @audits = {} - @resource_collection = Chef::ResourceCollection.new + @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 = [] end # @@ -221,6 +231,18 @@ class Chef end # + # Adds a delayed action to the +delayed_actions+. + # + def add_delayed_action(notification) + if delayed_actions.any? { |existing_notification| existing_notification.duplicates?(notification) } + Chef::Log.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 + + # # Get the list of before notifications sent by the given resource. # # TODO seriously, this is actually wrong. resource.name is not unique, @@ -640,6 +662,8 @@ ERROR_MESSAGE audits audits= create_child + add_delayed_action + delayed_actions delayed_notification_collection delayed_notification_collection= delayed_notifications diff --git a/lib/chef/runner.rb b/lib/chef/runner.rb index ce128203f2..cd5615bcec 100644 --- a/lib/chef/runner.rb +++ b/lib/chef/runner.rb @@ -30,13 +30,14 @@ class Chef attr_reader :run_context - attr_reader :delayed_actions - include Chef::Mixin::ParamsValidate def initialize(run_context) - @run_context = run_context - @delayed_actions = [] + @run_context = run_context + end + + def delayed_actions + @run_context.delayed_actions end def events @@ -48,16 +49,11 @@ class Chef def run_action(resource, action, notification_type = nil, notifying_resource = nil) # If there are any before notifications, why-run the resource # and notify anyone who needs notifying - # TODO cheffish has a bug where it passes itself instead of the run_context to us, so doesn't have before_notifications. Fix there, update dependency requirement, and remove this if statement. - before_notifications = run_context.before_notifications(resource) if run_context.respond_to?(:before_notifications) - if before_notifications && !before_notifications.empty? - whyrun_before = Chef::Config[:why_run] - begin - Chef::Config[:why_run] = true + before_notifications = run_context.before_notifications(resource) || [] + unless before_notifications.empty? + forced_why_run do Chef::Log.info("#{resource} running why-run #{action} action to support before action") resource.run_action(action, notification_type, notifying_resource) - ensure - Chef::Config[:why_run] = whyrun_before end if resource.updated_by_last_action? @@ -65,8 +61,8 @@ class Chef Chef::Log.info("#{resource} sending #{notification.action} action to #{notification.resource} (before)") run_action(notification.resource, notification.action, :before, resource) end + resource.updated_by_last_action(false) end - end # Actually run the action for realsies @@ -82,12 +78,8 @@ class Chef end run_context.delayed_notifications(resource).each do |notification| - if delayed_actions.any? { |existing_notification| existing_notification.duplicates?(notification) } - Chef::Log.info( "#{resource} not queuing delayed action #{notification.action} on #{notification.resource}"\ - " (delayed), as it's already been queued") - else - delayed_actions << notification - end + # send the notification to the run_context of the receiving resource + notification.resource.run_context.add_delayed_action(notification) end end end @@ -137,5 +129,15 @@ class Chef rescue Exception => e e end + + # helper to run a block of code with why_run forced to true and then restore it correctly + def forced_why_run + saved = Chef::Config[:why_run] + Chef::Config[:why_run] = true + yield + ensure + Chef::Config[:why_run] = saved + end + end end |