the class that actually walks our resource/property tree, collects the changes, and performs them
@api private
Are there any failed resources in this transaction?
# File lib/puppet/transaction.rb, line 161 def any_failed? report.resource_statuses.values.detect { |status| status.failed? } end
Find all of the changed resources.
# File lib/puppet/transaction.rb, line 166 def changed? report.resource_statuses.values.find_all { |status| status.changed }.collect { |status| catalog.resource(status.resource) } 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.
# File lib/puppet/transaction.rb, line 80 def evaluate(&block) block ||= method(:eval_resource) generator = AdditionalResourceGenerator.new(@catalog, relationship_graph, @prioritizer) @catalog.vertices.each { |resource| generator.generate_additional_resources(resource) } perform_pre_run_checks Puppet.info "Applying configuration version '#{catalog.version}'" if catalog.version continue_while = lambda { !stop_processing? } post_evalable_providers = Set.new pre_process = lambda do |resource| prov_class = resource.provider.class post_evalable_providers << prov_class if prov_class.respond_to?(:post_resource_eval) prefetch_if_necessary(resource) # If we generated resources, we don't know what they are now # blocking, so we opt to recompute it, rather than try to track every # change that would affect the number. relationship_graph.clear_blockers if generator.eval_generate(resource) end providerless_types = [] overly_deferred_resource_handler = lambda do |resource| # We don't automatically assign unsuitable providers, so if there # is one, it must have been selected by the user. return if missing_tags?(resource) if resource.provider resource.err "Provider #{resource.provider.class.name} is not functional on this host" else providerless_types << resource.type end resource_status(resource).failed = true end canceled_resource_handler = lambda do |resource| resource_status(resource).skipped = true resource.debug "Transaction canceled, skipping" end teardown = lambda do # Just once per type. No need to punish the user. providerless_types.uniq.each do |type| Puppet.err "Could not find a suitable provider for #{type}" end post_evalable_providers.each do |provider| begin provider.post_resource_eval rescue => detail Puppet.log_exception(detail, "post_resource_eval failed for provider #{provider}") end end end relationship_graph.traverse(:while => continue_while, :pre_process => pre_process, :overly_deferred_resource_handler => overly_deferred_resource_handler, :canceled_resource_handler => canceled_resource_handler, :teardown => teardown) do |resource| if resource.is_a?(Puppet::Type::Component) Puppet.warning "Somehow left a component in the relationship graph" else resource.info "Starting to evaluate the resource" if Puppet[:evaltrace] and @catalog.host_config? seconds = thinmark { block.call(resource) } resource.info "Evaluated in %0.2f seconds" % seconds if Puppet[:evaltrace] and @catalog.host_config? end end Puppet.debug "Finishing transaction #{object_id}" end
Invoke the pre_run_check hook in every resource in the catalog. This should (only) be called by #evaluate before applying the catalog.
@see #evaluate @see Puppet::Type#pre_run_check @raise [Puppet::Error] If any pre-run checks failed. @return [void]
# File lib/puppet/transaction.rb, line 58 def perform_pre_run_checks prerun_errors = {} @catalog.vertices.each do |res| begin res.pre_run_check rescue Puppet::Error => detail prerun_errors[res] = detail end end unless prerun_errors.empty? prerun_errors.each do |res, detail| res.log_exception(detail) end raise Puppet::Error, "Some pre-run checks failed" end end
# File lib/puppet/transaction.rb, line 185 def prefetch_if_necessary(resource) provider_class = resource.provider.class return unless provider_class.respond_to?(:prefetch) and !prefetched_providers[resource.type][provider_class.name] resources = resources_by_provider(resource.type, provider_class.name) if provider_class == resource.class.defaultprovider providerless_resources = resources_by_provider(resource.type, nil) providerless_resources.values.each {|res| res.provider = provider_class.name} resources.merge! providerless_resources end prefetch(provider_class, resources) end
# File lib/puppet/transaction.rb, line 170 def relationship_graph catalog.relationship_graph(@prioritizer) end
# File lib/puppet/transaction.rb, line 174 def resource_status(resource) report.resource_statuses[resource.to_s] || add_resource_status(Puppet::Resource::Status.new(resource)) end
Wraps application run state check to flag need to interrupt processing
# File lib/puppet/transaction.rb, line 156 def stop_processing? Puppet::Application.stop_requested? && catalog.host_config? end
# File lib/puppet/transaction.rb, line 34 def initialize(catalog, report, prioritizer) @catalog = catalog @report = report || Puppet::Transaction::Report.new("apply", catalog.version, catalog.environment) @prioritizer = prioritizer @report.add_times(:config_retrieval, @catalog.retrieval_duration || 0) @event_manager = Puppet::Transaction::EventManager.new(self) @resource_harness = Puppet::Transaction::ResourceHarness.new(self) @prefetched_providers = Hash.new { |h,k| h[k] = {} } end