summaryrefslogtreecommitdiffstats
path: root/lib/puppet/transaction.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/puppet/transaction.rb')
-rw-r--r--lib/puppet/transaction.rb606
1 files changed, 303 insertions, 303 deletions
diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb
index d70e06c85..dcd9aad0a 100644
--- a/lib/puppet/transaction.rb
+++ b/lib/puppet/transaction.rb
@@ -6,355 +6,355 @@ require 'puppet/util/tagging'
require 'puppet/application'
class Puppet::Transaction
- require 'puppet/transaction/change'
- require 'puppet/transaction/event'
- require 'puppet/transaction/event_manager'
- require 'puppet/transaction/resource_harness'
- require 'puppet/resource/status'
+ require 'puppet/transaction/change'
+ require 'puppet/transaction/event'
+ require 'puppet/transaction/event_manager'
+ require 'puppet/transaction/resource_harness'
+ require 'puppet/resource/status'
- attr_accessor :component, :catalog, :ignoreschedules
- attr_accessor :sorted_resources, :configurator
+ attr_accessor :component, :catalog, :ignoreschedules
+ attr_accessor :sorted_resources, :configurator
- # The report, once generated.
- attr_accessor :report
+ # The report, once generated.
+ attr_accessor :report
- # Routes and stores any events and subscriptions.
- attr_reader :event_manager
+ # Routes and stores any events and subscriptions.
+ attr_reader :event_manager
- # Handles most of the actual interacting with resources
- attr_reader :resource_harness
+ # Handles most of the actual interacting with resources
+ attr_reader :resource_harness
- include Puppet::Util
- include Puppet::Util::Tagging
+ include Puppet::Util
+ include Puppet::Util::Tagging
- # Wraps application run state check to flag need to interrupt processing
- def stop_processing?
- Puppet::Application.stop_requested?
- end
-
- # Add some additional times for reporting
- def add_times(hash)
- hash.each do |name, num|
- report.add_times(name, num)
- end
- end
-
- # Are there any failed resources in this transaction?
- def any_failed?
- report.resource_statuses.values.detect { |status| status.failed? }
- end
-
- # Apply all changes for a resource
- def apply(resource, ancestor = nil)
- status = resource_harness.evaluate(resource)
- add_resource_status(status)
- event_manager.queue_events(ancestor || resource, status.events)
- rescue => detail
- resource.err "Could not evaluate: #{detail}"
- end
+ # Wraps application run state check to flag need to interrupt processing
+ def stop_processing?
+ Puppet::Application.stop_requested?
+ end
- # Find all of the changed resources.
- def changed?
- report.resource_statuses.values.find_all { |status| status.changed }.collect { |status| catalog.resource(status.resource) }
+ # Add some additional times for reporting
+ def add_times(hash)
+ hash.each do |name, num|
+ report.add_times(name, num)
end
-
- # Copy an important relationships from the parent to the newly-generated
- # child resource.
- def make_parent_child_relationship(resource, children)
- depthfirst = resource.depthfirst?
-
- children.each do |gen_child|
- if depthfirst
- edge = [gen_child, resource]
- else
- edge = [resource, gen_child]
- end
- relationship_graph.add_vertex(gen_child)
-
- unless relationship_graph.edge?(edge[1], edge[0])
- relationship_graph.add_edge(*edge)
- else
- resource.debug "Skipping automatic relationship to #{gen_child}"
- end
- end
+ end
+
+ # Are there any failed resources in this transaction?
+ def any_failed?
+ report.resource_statuses.values.detect { |status| status.failed? }
+ end
+
+ # Apply all changes for a resource
+ def apply(resource, ancestor = nil)
+ status = resource_harness.evaluate(resource)
+ add_resource_status(status)
+ event_manager.queue_events(ancestor || resource, status.events)
+ rescue => detail
+ resource.err "Could not evaluate: #{detail}"
+ end
+
+ # Find all of the changed resources.
+ def changed?
+ report.resource_statuses.values.find_all { |status| status.changed }.collect { |status| catalog.resource(status.resource) }
+ end
+
+ # Copy an important relationships from the parent to the newly-generated
+ # child resource.
+ def make_parent_child_relationship(resource, children)
+ depthfirst = resource.depthfirst?
+
+ children.each do |gen_child|
+ if depthfirst
+ edge = [gen_child, resource]
+ else
+ edge = [resource, gen_child]
+ end
+ relationship_graph.add_vertex(gen_child)
+
+ unless relationship_graph.edge?(edge[1], edge[0])
+ relationship_graph.add_edge(*edge)
+ else
+ resource.debug "Skipping automatic relationship to #{gen_child}"
+ end
end
-
- # See if the resource generates new resources at evaluation time.
- def eval_generate(resource)
- generate_additional_resources(resource, :eval_generate)
- end
-
- # Evaluate a single resource.
- def eval_resource(resource, ancestor = nil)
- if skip?(resource)
- resource_status(resource).skipped = true
- else
- eval_children_and_apply_resource(resource, ancestor)
- end
-
- # Check to see if there are any events queued for this resource
- event_manager.process_events(resource)
+ end
+
+ # See if the resource generates new resources at evaluation time.
+ def eval_generate(resource)
+ generate_additional_resources(resource, :eval_generate)
+ end
+
+ # Evaluate a single resource.
+ def eval_resource(resource, ancestor = nil)
+ if skip?(resource)
+ resource_status(resource).skipped = true
+ else
+ eval_children_and_apply_resource(resource, ancestor)
end
- def eval_children_and_apply_resource(resource, ancestor = nil)
- resource_status(resource).scheduled = true
+ # Check to see if there are any events queued for this resource
+ event_manager.process_events(resource)
+ end
- # We need to generate first regardless, because the recursive
- # actions sometimes change how the top resource is applied.
- children = eval_generate(resource)
-
- if ! children.empty? and resource.depthfirst?
- children.each do |child|
- # The child will never be skipped when the parent isn't
- eval_resource(child, ancestor || resource)
- end
- end
+ def eval_children_and_apply_resource(resource, ancestor = nil)
+ resource_status(resource).scheduled = true
- # Perform the actual changes
- apply(resource, ancestor)
+ # We need to generate first regardless, because the recursive
+ # actions sometimes change how the top resource is applied.
+ children = eval_generate(resource)
- if ! children.empty? and ! resource.depthfirst?
- children.each do |child|
- eval_resource(child, ancestor || resource)
- end
- end
+ if ! children.empty? and resource.depthfirst?
+ children.each do |child|
+ # The child will never be skipped when the parent isn't
+ eval_resource(child, ancestor || resource)
+ end
end
- # This method does all the actual work of running a transaction. It
- # collects all of the changes, executes them, and responds to any
- # necessary events.
- def evaluate
- # Start logging.
- Puppet::Util::Log.newdestination(@report)
-
- prepare
-
- Puppet.info "Applying configuration version '#{catalog.version}'" if catalog.version
-
- begin
- @sorted_resources.each do |resource|
- next if stop_processing?
- if resource.is_a?(Puppet::Type::Component)
- Puppet.warning "Somehow left a component in the relationship graph"
- next
- end
- ret = nil
- seconds = thinmark do
- ret = eval_resource(resource)
- end
-
- resource.info "Evaluated in %0.2f seconds" % seconds if Puppet[:evaltrace] and @catalog.host_config?
- ret
- end
- ensure
- # And then close the transaction log.
- Puppet::Util::Log.close(@report)
- end
-
- Puppet.debug "Finishing transaction #{object_id}"
- end
+ # Perform the actual changes
+ apply(resource, ancestor)
- def events
- event_manager.events
+ if ! children.empty? and ! resource.depthfirst?
+ children.each do |child|
+ eval_resource(child, ancestor || resource)
+ end
end
+ end
- def failed?(resource)
- s = resource_status(resource) and s.failed?
- end
+ # This method does all the actual work of running a transaction. It
+ # collects all of the changes, executes them, and responds to any
+ # necessary events.
+ def evaluate
+ # Start logging.
+ Puppet::Util::Log.newdestination(@report)
- # Does this resource have any failed dependencies?
- def failed_dependencies?(resource)
- # First make sure there are no failed dependencies. To do this,
- # we check for failures in any of the vertexes above us. It's not
- # enough to check the immediate dependencies, which is why we use
- # a tree from the reversed graph.
- found_failed = false
- relationship_graph.dependencies(resource).each do |dep|
- next unless failed?(dep)
- resource.notice "Dependency #{dep} has failures: #{resource_status(dep).failed}"
- found_failed = true
- end
+ prepare
- found_failed
- end
+ Puppet.info "Applying configuration version '#{catalog.version}'" if catalog.version
- # A general method for recursively generating new resources from a
- # resource.
- def generate_additional_resources(resource, method)
- return [] unless resource.respond_to?(method)
- begin
- made = resource.send(method)
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- resource.err "Failed to generate additional resources using '#{method}': #{detail}"
+ begin
+ @sorted_resources.each do |resource|
+ next if stop_processing?
+ if resource.is_a?(Puppet::Type::Component)
+ Puppet.warning "Somehow left a component in the relationship graph"
+ next
end
- return [] unless made
- made = [made] unless made.is_a?(Array)
- made.uniq.find_all do |res|
- begin
- res.tag(*resource.tags)
- @catalog.add_resource(res) do |r|
- r.finish
- make_parent_child_relationship(resource, [r])
-
- # Call 'generate' recursively
- generate_additional_resources(r, method)
- end
- true
- rescue Puppet::Resource::Catalog::DuplicateResourceError
- res.info "Duplicate generated resource; skipping"
- false
- end
+ ret = nil
+ seconds = thinmark do
+ ret = eval_resource(resource)
end
- end
- # Collect any dynamically generated resources. This method is called
- # before the transaction starts.
- def generate
- list = @catalog.vertices
- newlist = []
- while ! list.empty?
- list.each do |resource|
- newlist += generate_additional_resources(resource, :generate)
- end
- list = newlist
- newlist = []
- end
+ resource.info "Evaluated in %0.2f seconds" % seconds if Puppet[:evaltrace] and @catalog.host_config?
+ ret
+ end
+ ensure
+ # And then close the transaction log.
+ Puppet::Util::Log.close(@report)
end
- # Generate a transaction report.
- def generate_report
- @report.calculate_metrics
- @report
+ Puppet.debug "Finishing transaction #{object_id}"
+ end
+
+ def events
+ event_manager.events
+ end
+
+ def failed?(resource)
+ s = resource_status(resource) and s.failed?
+ end
+
+ # Does this resource have any failed dependencies?
+ def failed_dependencies?(resource)
+ # First make sure there are no failed dependencies. To do this,
+ # we check for failures in any of the vertexes above us. It's not
+ # enough to check the immediate dependencies, which is why we use
+ # a tree from the reversed graph.
+ found_failed = false
+ relationship_graph.dependencies(resource).each do |dep|
+ next unless failed?(dep)
+ resource.notice "Dependency #{dep} has failures: #{resource_status(dep).failed}"
+ found_failed = true
end
- # Should we ignore tags?
- def ignore_tags?
- ! (@catalog.host_config? or Puppet[:name] == "puppet")
- end
+ found_failed
+ end
- # this should only be called by a Puppet::Type::Component resource now
- # and it should only receive an array
- def initialize(catalog)
- @catalog = catalog
-
- @report = Report.new
-
- @event_manager = Puppet::Transaction::EventManager.new(self)
-
- @resource_harness = Puppet::Transaction::ResourceHarness.new(self)
+ # A general method for recursively generating new resources from a
+ # resource.
+ def generate_additional_resources(resource, method)
+ return [] unless resource.respond_to?(method)
+ begin
+ made = resource.send(method)
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ resource.err "Failed to generate additional resources using '#{method}': #{detail}"
end
-
- # Prefetch any providers that support it. We don't support prefetching
- # types, just providers.
- def prefetch
- prefetchers = {}
- @catalog.vertices.each do |resource|
- if provider = resource.provider and provider.class.respond_to?(:prefetch)
- prefetchers[provider.class] ||= {}
- prefetchers[provider.class][resource.name] = resource
- end
- end
-
- # Now call prefetch, passing in the resources so that the provider instances can be replaced.
- prefetchers.each do |provider, resources|
- Puppet.debug "Prefetching #{provider.name} resources for #{provider.resource_type.name}"
- begin
- provider.prefetch(resources)
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Could not prefetch #{provider.resource_type.name} provider '#{provider.name}': #{detail}"
- end
+ return [] unless made
+ made = [made] unless made.is_a?(Array)
+ made.uniq.find_all do |res|
+ begin
+ res.tag(*resource.tags)
+ @catalog.add_resource(res) do |r|
+ r.finish
+ make_parent_child_relationship(resource, [r])
+
+ # Call 'generate' recursively
+ generate_additional_resources(r, method)
end
+ true
+ rescue Puppet::Resource::Catalog::DuplicateResourceError
+ res.info "Duplicate generated resource; skipping"
+ false
+ end
end
-
- # Prepare to evaluate the resources in a transaction.
- def prepare
- # Now add any dynamically generated resources
- generate
-
- # Then prefetch. It's important that we generate and then prefetch,
- # so that any generated resources also get prefetched.
- prefetch
-
- # This will throw an error if there are cycles in the graph.
- @sorted_resources = relationship_graph.topsort
+ end
+
+ # Collect any dynamically generated resources. This method is called
+ # before the transaction starts.
+ def generate
+ list = @catalog.vertices
+ newlist = []
+ while ! list.empty?
+ list.each do |resource|
+ newlist += generate_additional_resources(resource, :generate)
+ end
+ list = newlist
+ newlist = []
end
-
- def relationship_graph
- catalog.relationship_graph
+ end
+
+ # Generate a transaction report.
+ def generate_report
+ @report.calculate_metrics
+ @report
+ end
+
+ # Should we ignore tags?
+ def ignore_tags?
+ ! (@catalog.host_config? or Puppet[:name] == "puppet")
+ end
+
+ # this should only be called by a Puppet::Type::Component resource now
+ # and it should only receive an array
+ def initialize(catalog)
+ @catalog = catalog
+
+ @report = Report.new
+
+ @event_manager = Puppet::Transaction::EventManager.new(self)
+
+ @resource_harness = Puppet::Transaction::ResourceHarness.new(self)
+ end
+
+ # Prefetch any providers that support it. We don't support prefetching
+ # types, just providers.
+ def prefetch
+ prefetchers = {}
+ @catalog.vertices.each do |resource|
+ if provider = resource.provider and provider.class.respond_to?(:prefetch)
+ prefetchers[provider.class] ||= {}
+ prefetchers[provider.class][resource.name] = resource
+ end
end
- # Send off the transaction report.
- def send_report
- begin
- report = generate_report
- rescue => detail
- Puppet.err "Could not generate report: #{detail}"
- return
- end
-
- puts report.summary if Puppet[:summarize]
-
- if Puppet[:report]
- begin
- report.save
- rescue => detail
- Puppet.err "Reporting failed: #{detail}"
- end
- end
+ # Now call prefetch, passing in the resources so that the provider instances can be replaced.
+ prefetchers.each do |provider, resources|
+ Puppet.debug "Prefetching #{provider.name} resources for #{provider.resource_type.name}"
+ begin
+ provider.prefetch(resources)
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Could not prefetch #{provider.resource_type.name} provider '#{provider.name}': #{detail}"
+ end
end
+ end
- def add_resource_status(status)
- report.add_resource_status status
- end
+ # Prepare to evaluate the resources in a transaction.
+ def prepare
+ # Now add any dynamically generated resources
+ generate
- def resource_status(resource)
- report.resource_statuses[resource.to_s] || add_resource_status(Puppet::Resource::Status.new(resource))
- end
+ # Then prefetch. It's important that we generate and then prefetch,
+ # so that any generated resources also get prefetched.
+ prefetch
- # Is the resource currently scheduled?
- def scheduled?(resource)
- self.ignoreschedules or resource_harness.scheduled?(resource_status(resource), resource)
- end
+ # This will throw an error if there are cycles in the graph.
+ @sorted_resources = relationship_graph.topsort
+ end
- # Should this resource be skipped?
- def skip?(resource)
- if missing_tags?(resource)
- resource.debug "Not tagged with #{tags.join(", ")}"
- elsif ! scheduled?(resource)
- resource.debug "Not scheduled"
- elsif failed_dependencies?(resource)
- resource.warning "Skipping because of failed dependencies"
- elsif resource.virtual?
- resource.debug "Skipping because virtual"
- else
- return false
- end
- true
- end
-
- # The tags we should be checking.
- def tags
- self.tags = Puppet[:tags] unless defined?(@tags)
-
- super
- end
+ def relationship_graph
+ catalog.relationship_graph
+ end
- def handle_qualified_tags( qualified )
- # The default behavior of Puppet::Util::Tagging is
- # to split qualified tags into parts. That would cause
- # qualified tags to match too broadly here.
- return
+ # Send off the transaction report.
+ def send_report
+ begin
+ report = generate_report
+ rescue => detail
+ Puppet.err "Could not generate report: #{detail}"
+ return
end
- # Is this resource tagged appropriately?
- def missing_tags?(resource)
- return false if ignore_tags?
- return false if tags.empty?
+ puts report.summary if Puppet[:summarize]
- not resource.tagged?(*tags)
+ if Puppet[:report]
+ begin
+ report.save
+ rescue => detail
+ Puppet.err "Reporting failed: #{detail}"
+ end
+ end
+ end
+
+ def add_resource_status(status)
+ report.add_resource_status status
+ end
+
+ def resource_status(resource)
+ report.resource_statuses[resource.to_s] || add_resource_status(Puppet::Resource::Status.new(resource))
+ end
+
+ # Is the resource currently scheduled?
+ def scheduled?(resource)
+ self.ignoreschedules or resource_harness.scheduled?(resource_status(resource), resource)
+ end
+
+ # Should this resource be skipped?
+ def skip?(resource)
+ if missing_tags?(resource)
+ resource.debug "Not tagged with #{tags.join(", ")}"
+ elsif ! scheduled?(resource)
+ resource.debug "Not scheduled"
+ elsif failed_dependencies?(resource)
+ resource.warning "Skipping because of failed dependencies"
+ elsif resource.virtual?
+ resource.debug "Skipping because virtual"
+ else
+ return false
end
+ true
+ end
+
+ # The tags we should be checking.
+ def tags
+ self.tags = Puppet[:tags] unless defined?(@tags)
+
+ super
+ end
+
+ def handle_qualified_tags( qualified )
+ # The default behavior of Puppet::Util::Tagging is
+ # to split qualified tags into parts. That would cause
+ # qualified tags to match too broadly here.
+ return
+ end
+
+ # Is this resource tagged appropriately?
+ def missing_tags?(resource)
+ return false if ignore_tags?
+ return false if tags.empty?
+
+ not resource.tagged?(*tags)
+ end
end
require 'puppet/transaction/report'