summaryrefslogtreecommitdiffstats
path: root/lib/puppet
diff options
context:
space:
mode:
authorLuke Kanies <luke@madstop.com>2005-06-29 03:11:06 +0000
committerLuke Kanies <luke@madstop.com>2005-06-29 03:11:06 +0000
commit0c4254a9c1bad795a8bcc895cff74b6dd961ba44 (patch)
tree2d512a90e147d020486ff71591ad64202814ac06 /lib/puppet
parent573d3018a67521f37dbbd46e86c7d1d8b7bc2703 (diff)
downloadpuppet-0c4254a9c1bad795a8bcc895cff74b6dd961ba44.tar.gz
puppet-0c4254a9c1bad795a8bcc895cff74b6dd961ba44.tar.xz
puppet-0c4254a9c1bad795a8bcc895cff74b6dd961ba44.zip
metric testing and graphing now works in the library, although nothing has been done in the language
git-svn-id: https://reductivelabs.com/svn/puppet/library/trunk@314 980ebf18-57e1-0310-9a29-db15c13687c0
Diffstat (limited to 'lib/puppet')
-rw-r--r--lib/puppet/client.rb7
-rw-r--r--lib/puppet/event.rb2
-rw-r--r--lib/puppet/log.rb10
-rw-r--r--lib/puppet/metric.rb253
-rw-r--r--lib/puppet/transaction.rb1
-rw-r--r--lib/puppet/type.rb36
6 files changed, 303 insertions, 6 deletions
diff --git a/lib/puppet/client.rb b/lib/puppet/client.rb
index f1140ea4d..06808a4b4 100644
--- a/lib/puppet/client.rb
+++ b/lib/puppet/client.rb
@@ -10,6 +10,7 @@ require 'puppet/type'
require 'puppet/fact'
require 'puppet/transaction'
require 'puppet/transportable'
+require 'puppet/metric'
require 'http-access2'
require 'soap/rpc/driver'
require 'soap/rpc/httpserver'
@@ -80,6 +81,12 @@ module Puppet
#transaction = Puppet::Transaction.new(objects)
transaction.toplevel = true
transaction.evaluate
+ Puppet::Metric.gather
+ Puppet::Metric.tally
+ Metric.store
+ if @@config[:rrdgraph] == true
+ #Metric.store
+ end
self.shutdown
end
diff --git a/lib/puppet/event.rb b/lib/puppet/event.rb
index a8d818b39..86205591d 100644
--- a/lib/puppet/event.rb
+++ b/lib/puppet/event.rb
@@ -107,7 +107,7 @@ module Puppet
@object = args[:object]
@transaction = args[:transaction]
- Puppet.warning "New Event: '%s' => '%s'" %
+ Puppet.info "%s: %s" %
[@object,@event]
# initially, just stuff all instances into a central bucket
diff --git a/lib/puppet/log.rb b/lib/puppet/log.rb
index 9cfb80193..5f77e623c 100644
--- a/lib/puppet/log.rb
+++ b/lib/puppet/log.rb
@@ -47,12 +47,14 @@ module Puppet
def Log.create(level,*ary)
msg = ary.join(" ")
- if @@levels.index(@@loglevel) >= @@levels.index(level)
- Puppet::Log.new(
+ if @@levels.index(level) >= @@loglevel
+ return Puppet::Log.new(
:level => level,
:source => "Puppet",
:message => msg
)
+ else
+ return nil
end
end
@@ -86,11 +88,11 @@ module Puppet
level = level.intern
end
- unless @@loglevels.include?(level)
+ unless @@levels.include?(level)
raise "Invalid loglevel %s" % level
end
- @@loglevel = @@loglevels.index(level)
+ @@loglevel = @@levels.index(level)
end
def Log.newmessage(msg)
diff --git a/lib/puppet/metric.rb b/lib/puppet/metric.rb
new file mode 100644
index 000000000..d9696b601
--- /dev/null
+++ b/lib/puppet/metric.rb
@@ -0,0 +1,253 @@
+#!/usr/local/bin/ruby -w
+
+# $Id$
+
+# included so we can test object types
+require 'puppet'
+
+module Puppet
+ class Metric
+ def Metric.init
+ @@typemetrics = Hash.new { |typehash,type|
+ typehash[type] = Hash.new(0)
+ }
+
+ @@eventmetrics = Hash.new(0)
+
+ @@metrics = {}
+ end
+
+ def Metric.clear
+ @@metrics = {}
+ @@eventmetrics = nil
+ @@typemetrics = nil
+ end
+
+ def Metric.gather
+ metrics = Metric.init
+
+ # first gather stats about all of the types
+ Puppet::Type.eachtype { |type|
+ type.each { |instance|
+ metrics[type][:total] += 1
+ if instance.managed
+ metrics[type][:managed] += 1
+ end
+ }
+ }
+
+ # the rest of the metrics are injected directly by type.rb
+ end
+
+ def Metric.add(type,instance,metric,count)
+ return unless defined? @@typemetrics
+ case metric
+ when :outofsync:
+ @@typemetrics[type][metric] += count
+ when :changes:
+ @@typemetrics[type][:changed] += 1
+ @@typemetrics[type][:totalchanges] += count
+ else
+ raise "Unknown metric %s" % metric
+ end
+ end
+
+ # we're currently throwing away the type and instance information
+ def Metric.addevents(type,instance,events)
+ return unless defined? @@eventmetrics
+ events.each { |event|
+ @@eventmetrics[event] += 1
+ }
+ end
+
+ def Metric.each
+ @@metrics.each { |name,metric|
+ yield metric
+ }
+ end
+
+ def Metric.load(ary)
+ @@typemetrics = ary[0]
+ @@eventmetrics = ary[1]
+ end
+
+ def Metric.graph(range = nil)
+ @@metrics.each { |name,metric|
+ metric.graph(range)
+ }
+ end
+
+ def Metric.store(time = nil)
+ require 'RRD'
+ unless time
+ time = Time.now.to_i
+ end
+ @@metrics.each { |name,metric|
+ metric.store(time)
+ }
+ end
+
+ def Metric.tally
+ type = Metric.new("typecount","Types")
+ type.newvalue("Number",@@typemetrics.length)
+
+ metrics = {
+ :total => "Instances",
+ :managed => "Managed Instances",
+ :outofsync => "Out of Sync Instances",
+ :changed => "Changed Instances",
+ :totalchanges => "Total Number of Changes",
+ }
+ total = Hash.new(0)
+ @@typemetrics.each { |type,instancehash|
+ name = type.name.to_s
+ instmet = Metric.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")
+ metrics.each { |symbol,label|
+ totalmet.newvalue(symbol.to_s,total[symbol],label)
+ }
+
+ eventmet = Metric.new("events")
+ total = 0
+ @@eventmetrics.each { |event,count|
+ event = event.to_s
+ # add the specific event as a value, with the label being a
+ # capitalized version with s/_/ /g
+ eventmet.newvalue(
+ event,
+ count,
+ event.capitalize.gsub(/_/,' ')
+ )
+
+ total += count
+ }
+ eventmet.newvalue("total",total,"Event Total")
+ end
+
+ attr_accessor :type, :name, :value, :label
+
+
+ def create
+ dir = Puppet[:rrddir]
+ unless dir
+ raise "Cannot store metrics unless RRDDir is set"
+ end
+
+ unless FileTest.exist?(dir)
+ tmp = dir.sub(/^\//,'')
+ path = [File::SEPARATOR]
+ tmp.split(File::SEPARATOR).each { |dir|
+ path.push dir
+ unless FileTest.exist?(File.join(path))
+ Dir.mkdir(File.join(path))
+ end
+ }
+ end
+
+ unless FileTest.directory?(dir)
+ raise "%s must be a directory" % dir
+ end
+
+ path = self.path
+ args = [
+ path,
+ "--start", Time.now.to_i - 5,
+ "--step", "300", # XXX Defaulting to every five minutes, but prob bad
+ ]
+
+ @values.each { |value|
+ args.push "DS:%s:GAUGE:600:U:U" % value[0]
+ }
+ args.push "RRA:AVERAGE:0.5:1:300"
+
+ begin
+ RRD.create(*args)
+ rescue => detail
+ raise "Could not create RRD file %s: %s" % [path,detail]
+ end
+ end
+
+ def initialize(name,label = nil)
+ @name = name
+ if label
+ @label = label
+ else
+ @label = name.capitalize
+ end
+
+ @values = []
+ if @@metrics.include?(self.name)
+ raise "Somehow created two metrics with name %s" % self.name
+ else
+ @@metrics[self.name] = self
+ end
+ end
+
+ def newvalue(name,value,label = nil)
+ unless label
+ label = name.capitalize
+ end
+ @values.push [name,label,value]
+ end
+
+ def path
+ return File.join(Puppet[:rrddir],@name + ".rrd")
+ end
+
+ def graph(range = nil)
+ args = [self.path.sub(/rrd$/,"png")]
+ args.push("--title",self.label)
+ args.push("--imgformat","PNG")
+ args.push("--interlace")
+ colorstack = %w{#ff0000 #00ff00 #0000ff #099000 #000990 #f00990}
+ i = 0
+ defs = []
+ lines = []
+ @values.zip(colorstack).each { |value,color|
+ next if value.nil?
+ # this actually uses the data label
+ defs.push("DEF:%s=%s:%s:AVERAGE" % [value[0],self.path,value[0]])
+ lines.push("LINE3:%s%s:%s" % [value[0],color,value[1]])
+ }
+ args << defs
+ args << lines
+ args.flatten!
+ if range
+ args.push("--start",range[0],"--end",range[1])
+ end
+
+ begin
+ RRD.graph(*args)
+ rescue => detail
+ Puppet.err "Failed to graph %s: %s" % [self.name,detail]
+ exit
+ end
+ end
+
+ def store(time)
+ unless FileTest.exists?(File.join(Puppet[:rrddir],@name + ".rrd"))
+ self.create
+ end
+
+ # XXX this is not terribly error-resistant
+ args = [time]
+ @values.each { |value|
+ args.push value[2]
+ }
+ arg = args.join(":")
+ Puppet.debug "Updating %s with %s" % [self.name,arg]
+ begin
+ RRD.update(self.path,args.join(":"))
+ rescue => detail
+ Puppet.err "Failed to update %s: %s" % [self.name,detail]
+ exit
+ end
+ end
+ end
+end
diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb
index 1a3a7361a..03f965a76 100644
--- a/lib/puppet/transaction.rb
+++ b/lib/puppet/transaction.rb
@@ -23,6 +23,7 @@ class Transaction
# failed
def Transaction.init
@@failures = Hash.new(0)
+ Puppet::Metric.init
@@changed = []
end
#---------------------------------------------------------------
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
index 81c20ceec..6d74e4ef3 100644
--- a/lib/puppet/type.rb
+++ b/lib/puppet/type.rb
@@ -6,6 +6,7 @@
require 'puppet'
require 'puppet/element'
require 'puppet/event'
+require 'puppet/metric'
require 'puppet/type/state'
@@ -273,6 +274,15 @@ class Type < Puppet::Element
#---------------------------------------------------------------
#---------------------------------------------------------------
+ def Type.each
+ return unless defined? @objects
+ @objects.each { |instance|
+ yield instance
+ }
+ end
+ #---------------------------------------------------------------
+
+ #---------------------------------------------------------------
# all objects total
def Type.push(object)
@@allobjects.push object
@@ -581,11 +591,13 @@ class Type < Puppet::Element
#---------------------------------------------------------------
def sync
- self.collect { |child|
+ events = self.collect { |child|
child.sync
}.reject { |event|
! (event.is_a?(Symbol) or event.is_a?(String))
}.flatten
+
+ Puppet::Metric.addevents(self.class,self,events)
end
#---------------------------------------------------------------
@@ -602,6 +614,23 @@ class Type < Puppet::Element
#---------------------------------------------------------------
#---------------------------------------------------------------
+ def managed
+ if defined? @managed
+ return @managed
+ else
+ self.states.each { |state|
+ if state.should
+ @managed = true
+ else
+ @managed = false
+ end
+ }
+ end
+ return @managed
+ end
+ #---------------------------------------------------------------
+
+ #---------------------------------------------------------------
def states
Puppet.debug "%s has %s states" % [self,@states.length]
tmpstates = []
@@ -686,6 +715,8 @@ class Type < Puppet::Element
# this only operates on states, not states + children
self.retrieve
unless self.insync?
+ # add one to the number of out-of-sync instances
+ Puppet::Metric.add(self.class,self,:outofsync,1)
changes << self.states.find_all { |state|
! state.insync?
}.collect { |state|
@@ -697,6 +728,9 @@ class Type < Puppet::Element
#self.collect { |child|
# child.evaluate
#}
+
+ # now record how many changes we've resulted in
+ Puppet::Metric.add(self.class,self,:changes,changes.length)
return changes
end
#---------------------------------------------------------------