summaryrefslogtreecommitdiffstats
path: root/lib/puppet
diff options
context:
space:
mode:
Diffstat (limited to 'lib/puppet')
-rw-r--r--lib/puppet/client/master.rb17
-rw-r--r--lib/puppet/client/reporter.rb14
-rw-r--r--lib/puppet/log.rb35
-rw-r--r--lib/puppet/metric.rb38
-rw-r--r--lib/puppet/parser/interpreter.rb4
-rw-r--r--lib/puppet/reports/tagmail.rb4
-rw-r--r--lib/puppet/transaction.rb124
-rw-r--r--lib/puppet/type.rb7
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]