diff options
Diffstat (limited to 'lib/puppet')
-rw-r--r-- | lib/puppet/client/master.rb | 17 | ||||
-rw-r--r-- | lib/puppet/client/reporter.rb | 14 | ||||
-rw-r--r-- | lib/puppet/log.rb | 35 | ||||
-rw-r--r-- | lib/puppet/metric.rb | 38 | ||||
-rw-r--r-- | lib/puppet/parser/interpreter.rb | 4 | ||||
-rw-r--r-- | lib/puppet/reports/tagmail.rb | 4 | ||||
-rw-r--r-- | lib/puppet/transaction.rb | 124 | ||||
-rw-r--r-- | lib/puppet/type.rb | 7 |
8 files changed, 143 insertions, 100 deletions
diff --git a/lib/puppet/client/master.rb b/lib/puppet/client/master.rb index 6d57a310a..2544d3aef 100644 --- a/lib/puppet/client/master.rb +++ b/lib/puppet/client/master.rb @@ -76,12 +76,7 @@ class Puppet::Client::MasterClient < Puppet::Client raise Puppet::Error, "Cannot apply; objects not defined" end - # this is a gross hack... but i don't see a good way around it - # set all of the variables to empty - Puppet::Transaction.init - transaction = @objects.evaluate - transaction.toplevel = true if tags transaction.tags = tags @@ -104,16 +99,14 @@ class Puppet::Client::MasterClient < Puppet::Client ensure Puppet::Storage.store end - Puppet::Metric.gather - Puppet::Metric.tally - if Puppet[:rrdgraph] == true - Metric.store - Metric.graph - end if Puppet[:report] + report = transaction.report() + if Puppet[:rrdgraph] == true + report.graph() + end begin - reportclient().report(transaction) + reportclient().report(report) rescue => detail Puppet.err "Reporting failed: %s" % detail end diff --git a/lib/puppet/client/reporter.rb b/lib/puppet/client/reporter.rb index ff80f367d..b0101e2fa 100644 --- a/lib/puppet/client/reporter.rb +++ b/lib/puppet/client/reporter.rb @@ -13,24 +13,22 @@ class Puppet::Client::Reporter < Puppet::Client::ProxyClient super(hash) end - # Send our report. We get the transaction, and we convert it to a report + # Send our report. We get the transaction report and convert it to YAML # as appropriate. - def report(transaction) - # We receive an array of log events, and we need to convert them into - # a single big YAML file. - - array = transaction.report - - report = YAML.dump(array) + def report(transreport) + report = YAML.dump(transreport) unless self.local report = CGI.escape(report) end # Now send the report + file = nil benchmark(:info, "Sent transaction report") do file = @driver.report(report) end + + file end end diff --git a/lib/puppet/log.rb b/lib/puppet/log.rb index 85058840d..15a5b6331 100644 --- a/lib/puppet/log.rb +++ b/lib/puppet/log.rb @@ -32,11 +32,14 @@ module Puppet # See whether we match a given thing. def self.match?(obj) + # Convert single-word strings into symbols like :console and :syslog if obj.is_a? String and obj =~ /^\w+$/ obj = obj.downcase.intern end + @matches.each do |thing| - return true if thing === obj + # Search for direct matches or class matches + return true if thing === obj or thing == obj.class.to_s end return false end @@ -325,7 +328,6 @@ module Puppet end # Add the hostname to the source @driver.addlog(tmp) - sleep(0.5) rescue => detail if Puppet[:debug] puts detail.backtrace @@ -337,6 +339,23 @@ module Puppet end end + # Log to a transaction report. + newdesttype :report do + match "Puppet::Transaction::Report" + + def initialize(report) + @report = report + end + + def handle(msg) + # Only add messages from objects, since anything else is + # probably unrelated to this run. + if msg.objectsource? + @report.newlog(msg) + end + end + end + # Create a new log destination. def Log.newdestination(dest) # Each destination can only occur once. @@ -344,7 +363,6 @@ module Puppet return end - name, type = @desttypes.find do |name, klass| klass.match?(dest) end @@ -460,6 +478,15 @@ module Puppet Log.newmessage(self) end + # Was the source of this log an object? + def objectsource? + if defined? @objectsource and @objectsource + @objectsource + else + false + end + end + # If they pass a source in to us, we make sure it is a string, and # we retrieve any tags we can. def source=(source) @@ -467,8 +494,10 @@ module Puppet # is a bit of a stupid hack, specifically testing for elements, but # eh. if source.is_a?(Puppet::Element) and source.respond_to?(:path) + @objectsource = true @source = source.path else + @objectsource = false @source = source.to_s end unless defined? @tags and @tags diff --git a/lib/puppet/metric.rb b/lib/puppet/metric.rb index fb72c305b..4aa2fe3b2 100644 --- a/lib/puppet/metric.rb +++ b/lib/puppet/metric.rb @@ -4,7 +4,7 @@ require 'puppet' module Puppet # A class for handling metrics. This is currently ridiculously hackish. class Metric - def Metric.init + def self.init @@typemetrics = Hash.new { |typehash,typename| typehash[typename] = Hash.new(0) } @@ -14,12 +14,14 @@ module Puppet @@metrics = {} end - def Metric.clear - Metric.init + self.init + + def self.clear + self.init end - def Metric.gather - Metric.init + def self.gather + self.init # first gather stats about all of the types Puppet::Type.eachtype { |type| @@ -35,7 +37,7 @@ module Puppet # the rest of the metrics are injected directly by type.rb end - def Metric.add(type,instance,metric,count) + def self.add(type,instance,metric,count) return unless defined? @@typemetrics case metric when :outofsync: @@ -49,7 +51,7 @@ module Puppet end # we're currently throwing away the type and instance information - def Metric.addevents(type,instance,events) + def self.addevents(type,instance,events) return unless defined? @@eventmetrics events.each { |event| @@eventmetrics[event] += 1 @@ -57,25 +59,25 @@ module Puppet end # Iterate across all of the metrics - def Metric.each + def self.each @@metrics.each { |name,metric| yield metric } end # I'm nearly positive this method is used only for testing - def Metric.load(ary) + def self.load(ary) @@typemetrics = ary[0] @@eventmetrics = ary[1] end - def Metric.graph(range = nil) + def self.graph(range = nil) @@metrics.each { |name,metric| metric.graph(range) } end - def Metric.store(time = nil) + def self.store(time = nil) require 'RRD' unless time time = Time.now.to_i @@ -85,8 +87,8 @@ module Puppet } end - def Metric.tally - type = Metric.new("typecount","Types") + def self.tally + type = self.new("typecount","Types") type.newvalue("Number",@@typemetrics.length) metrics = { @@ -99,19 +101,19 @@ module Puppet total = Hash.new(0) @@typemetrics.each { |type,instancehash| name = type.name.to_s - instmet = Metric.new("type-" + name,name.capitalize) + instmet = self.new("type-" + name,name.capitalize) metrics.each { |symbol,label| instmet.newvalue(symbol.to_s,instancehash[symbol],label) total[symbol] += instancehash[symbol] } } - totalmet = Metric.new("typetotals","Type Totals") + totalmet = self.new("typetotals","Type Totals") metrics.each { |symbol,label| totalmet.newvalue(symbol.to_s,total[symbol],label) } - eventmet = Metric.new("events") + eventmet = self.new("events") total = 0 @@eventmetrics.each { |event,count| event = event.to_s @@ -158,7 +160,7 @@ module Puppet if label @label = label else - @label = name.capitalize + @label = name.to_s.capitalize end @values = [] @@ -171,7 +173,7 @@ module Puppet def newvalue(name,value,label = nil) unless label - label = name.capitalize + label = name.to_s.capitalize end @values.push [name,label,value] end diff --git a/lib/puppet/parser/interpreter.rb b/lib/puppet/parser/interpreter.rb index b383f7a90..9a0e47a52 100644 --- a/lib/puppet/parser/interpreter.rb +++ b/lib/puppet/parser/interpreter.rb @@ -422,8 +422,8 @@ module Puppet if @local @ast = @parser.parse else - @ast = benchmark(:info, "Parsed manifest") do - @parser.parse + benchmark(:info, "Parsed manifest") do + @ast = @parser.parse end end diff --git a/lib/puppet/reports/tagmail.rb b/lib/puppet/reports/tagmail.rb index e356b8ba8..16096f62f 100644 --- a/lib/puppet/reports/tagmail.rb +++ b/lib/puppet/reports/tagmail.rb @@ -36,9 +36,9 @@ Puppet::Server::Report.newreport(:tagmail) do |report| tags.each do |tag, emails| messages = nil if tag == "all" - messages = report + messages = report.logs else - messages = report.find_all do |log| + messages = report.logs.find_all do |log| log.tagged?(tag) end end diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb index 0281f16ed..03183e90f 100644 --- a/lib/puppet/transaction.rb +++ b/lib/puppet/transaction.rb @@ -6,7 +6,9 @@ require 'puppet/statechange' module Puppet class Transaction - attr_accessor :toplevel, :component, :objects, :tags, :ignoreschedules + attr_accessor :component, :objects, :tags, :ignoreschedules + + include Puppet::Util Puppet.config.setdefaults(:transaction, :tags => ["", "Tags to use to find objects. If this is set, then @@ -14,14 +16,6 @@ class Transaction Values must be comma-separated."] ) - # a bit of a gross hack; a global list of objects that have failed to sync, - # so that we can verify during later syncs that our dependencies haven't - # failed - def Transaction.init - @@failures = Hash.new(0) - Puppet::Metric.init - end - # Apply all changes for a child, returning a list of the events # generated. def apply(child) @@ -36,6 +30,7 @@ class Transaction if skip child.warning "Skipping because of failed dependencies" + @objectmetrics[:skipped] += 1 return [] end end @@ -72,7 +67,6 @@ class Transaction rescue => detail change.state.err "change from %s to %s failed: %s" % [change.state.is_to_s, change.state.should_to_s, detail] - #Puppet.err("%s failed: %s" % [change.to_s,detail]) @failures[child] += 1 next # FIXME this should support using onerror to determine @@ -90,6 +84,7 @@ class Transaction }.flatten.reject { |e| e.nil? } unless changes.empty? + @objectmetrics[:changed] += 1 # Record when we last synced child.cache(:synced, Time.now) end @@ -97,12 +92,6 @@ class Transaction childevents end - # for now, just store the changes for executing linearly - # later, we might execute them as we receive them - def change(change) - @changes.push change - end - # Find all of the changed objects. def changed? @changes.find_all { |change| change.changed }.collect { |change| @@ -133,10 +122,8 @@ class Transaction # collects all of the changes, executes them, and responds to any # necessary events. def evaluate - #Puppet.debug "Beginning transaction %s with %s changes" % - # [self.object_id, @changes.length] - @count = 0 + # Allow the tags to be overriden tags = self.tags || Puppet[:tags] if tags.nil? or tags == "" @@ -148,34 +135,46 @@ class Transaction end.flatten end - allevents = @objects.collect { |child| - events = nil - if (tags.nil? or child.tagged?(tags)) - if self.ignoreschedules or child.scheduled? - # Perform the actual changes - events = apply(child) + # Start logging. + Puppet::Log.newdestination(@report) - # Collect the targets of any subscriptions to those events - collecttargets(events) + begin + allevents = @objects.collect { |child| + events = nil + if (tags.nil? or child.tagged?(tags)) + if self.ignoreschedules or child.scheduled? + # Perform the actual changes + + seconds = thinmark do + events = apply(child) + end + + # Keep track of how long we spend in each type of object + @timemetrics[child.class.name] += seconds + + # Collect the targets of any subscriptions to those events + collecttargets(events) + else + child.debug "Not scheduled" + end else - child.debug "Not scheduled" + child.debug "Not tagged with %s" % tags.join(", ") end - else - child.debug "Not tagged with %s" % tags.join(", ") - end - # Now check to see if there are any events for this child - trigger(child) + # Now check to see if there are any events for this child + trigger(child) - # And return the events for collection - events - }.flatten.reject { |e| e.nil? } + # And return the events for collection + events + }.flatten.reject { |e| e.nil? } + ensure + # And then close the transaction log. + Puppet::Log.close(@report) + end Puppet.debug "Finishing transaction %s with %s changes" % [self.object_id, @count] - # Currently, we return the list of events, but really, this - # should be some kind of report allevents end @@ -188,33 +187,57 @@ class Transaction # and it should only receive an array def initialize(objects) @objects = objects - @toplevel = false + @objectmetrics = { + :total => @objects.length, + :outofsync => 0, # The number of objects that had changes + :changed => 0, # The number of objects fixed + :skipped => 0, # The number of objects skipped + :restarted => 0, # The number of objects triggered + :failedrestarts => 0 # The number of objects that fail a trigger + } + + # Metrics for distributing times across the different types. + @timemetrics = Hash.new(0) + + # The number of objects that were triggered in this run @triggered = Hash.new { |hash, key| hash[key] = Hash.new(0) } + # Targets of being triggered. @targets = Hash.new do |hash, key| hash[key] = {} end - # of course, this won't work on the second run - unless defined? @@failures - @toplevel = true - self.class.init - end - + # The changes we're performing @changes = [] + # The objects that have failed and the number of failures each. This + # is used for skipping objects because of failed dependencies. @failures = Hash.new do |h, key| h[key] = 0 end + + @report = Report.new end + # Generate a transaction report. def report - @changes.collect do |change| - change.report - end + @objectmetrics[:failed] = @failures.length + + # Add all of the metrics related to object count and status + @report.newmetric(:objects, @objectmetrics) + + # Record the relative time spent in each object. + @report.newmetric(:percentage_time, @timemetrics) + + # Then all of the change-related metrics + @report.newmetric(:changes, + :total => @changes.length + ) + + return @report end # Roll all completed changes back. @@ -287,10 +310,13 @@ class Transaction # to them in any way. begin obj.send(callback) + @objectmetrics[:restarted] += 1 rescue => detail obj.err "Failed to call %s on %s: %s" % [callback, obj, detail] + @objectmetrics[:failedrestarts] += 1 + if Puppet[:debug] puts detail.backtrace end @@ -314,4 +340,6 @@ class Transaction end end +require 'puppet/transaction/report' + # $Id$ diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb index cfd742ee7..e2aea5318 100644 --- a/lib/puppet/type.rb +++ b/lib/puppet/type.rb @@ -1847,12 +1847,6 @@ class Type < Puppet::Element changes += statechanges() end - if changes.length > 0 - # add one to the number of out-of-sync instances - Puppet::Metric.add(self.class,self,:outofsync,1) - end - #end - changes << @children.collect { |child| ch = child.evaluate child.cache(:checked, now) @@ -1866,7 +1860,6 @@ class Type < Puppet::Element changes.flatten! # now record how many changes we've resulted in - Puppet::Metric.add(self.class,self,:changes,changes.length) if changes.length > 0 self.debug "%s change(s)" % [changes.length] |