puppet 0.9.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (182) hide show
  1. data/CHANGELOG +0 -0
  2. data/COPYING +340 -0
  3. data/LICENSE +17 -0
  4. data/README +24 -0
  5. data/Rakefile +294 -0
  6. data/TODO +4 -0
  7. data/bin/cf2puppet +186 -0
  8. data/bin/puppet +176 -0
  9. data/bin/puppetca +213 -0
  10. data/bin/puppetd +246 -0
  11. data/bin/puppetdoc +184 -0
  12. data/bin/puppetmasterd +258 -0
  13. data/examples/code/allatonce +13 -0
  14. data/examples/code/assignments +11 -0
  15. data/examples/code/classing +35 -0
  16. data/examples/code/components +73 -0
  17. data/examples/code/execs +16 -0
  18. data/examples/code/failers/badclassnoparam +10 -0
  19. data/examples/code/failers/badclassparam +10 -0
  20. data/examples/code/failers/badcompnoparam +9 -0
  21. data/examples/code/failers/badcompparam +9 -0
  22. data/examples/code/failers/badtypeparam +3 -0
  23. data/examples/code/file.bl +11 -0
  24. data/examples/code/filedefaults +10 -0
  25. data/examples/code/fileparsing +116 -0
  26. data/examples/code/filerecursion +15 -0
  27. data/examples/code/functions +3 -0
  28. data/examples/code/groups +7 -0
  29. data/examples/code/head +30 -0
  30. data/examples/code/importing +8 -0
  31. data/examples/code/nodes +20 -0
  32. data/examples/code/one +8 -0
  33. data/examples/code/relationships +34 -0
  34. data/examples/code/selectors +28 -0
  35. data/examples/code/simpletests +11 -0
  36. data/examples/code/snippets/argumentdefaults +14 -0
  37. data/examples/code/snippets/casestatement +39 -0
  38. data/examples/code/snippets/classheirarchy.pp +15 -0
  39. data/examples/code/snippets/classincludes.pp +17 -0
  40. data/examples/code/snippets/classpathtest +11 -0
  41. data/examples/code/snippets/dirchmod +19 -0
  42. data/examples/code/snippets/failmissingexecpath.pp +13 -0
  43. data/examples/code/snippets/falsevalues.pp +3 -0
  44. data/examples/code/snippets/filecreate +11 -0
  45. data/examples/code/snippets/implicititeration +15 -0
  46. data/examples/code/snippets/multipleinstances +7 -0
  47. data/examples/code/snippets/namevartest +9 -0
  48. data/examples/code/snippets/scopetest +13 -0
  49. data/examples/code/snippets/selectorvalues.pp +22 -0
  50. data/examples/code/snippets/simpledefaults +5 -0
  51. data/examples/code/snippets/simpleselector +38 -0
  52. data/examples/code/svncommit +13 -0
  53. data/examples/root/bin/sleeper +69 -0
  54. data/examples/root/etc/configfile +0 -0
  55. data/examples/root/etc/debian-passwd +29 -0
  56. data/examples/root/etc/debian-syslog.conf +71 -0
  57. data/examples/root/etc/init.d/sleeper +65 -0
  58. data/examples/root/etc/otherfile +0 -0
  59. data/examples/root/etc/puppet/fileserver.conf +3 -0
  60. data/examples/root/etc/puppet/puppetmasterd.conf +10 -0
  61. data/ext/module:puppet +195 -0
  62. data/install.rb +270 -0
  63. data/lib/puppet.rb +249 -0
  64. data/lib/puppet/base64.rb +19 -0
  65. data/lib/puppet/client.rb +519 -0
  66. data/lib/puppet/config.rb +49 -0
  67. data/lib/puppet/daemon.rb +208 -0
  68. data/lib/puppet/element.rb +71 -0
  69. data/lib/puppet/event.rb +259 -0
  70. data/lib/puppet/log.rb +321 -0
  71. data/lib/puppet/metric.rb +250 -0
  72. data/lib/puppet/parsedfile.rb +38 -0
  73. data/lib/puppet/parser/ast.rb +1560 -0
  74. data/lib/puppet/parser/interpreter.rb +150 -0
  75. data/lib/puppet/parser/lexer.rb +226 -0
  76. data/lib/puppet/parser/parser.rb +1354 -0
  77. data/lib/puppet/parser/scope.rb +755 -0
  78. data/lib/puppet/server.rb +170 -0
  79. data/lib/puppet/server/authstore.rb +227 -0
  80. data/lib/puppet/server/ca.rb +140 -0
  81. data/lib/puppet/server/filebucket.rb +147 -0
  82. data/lib/puppet/server/fileserver.rb +477 -0
  83. data/lib/puppet/server/logger.rb +43 -0
  84. data/lib/puppet/server/master.rb +103 -0
  85. data/lib/puppet/server/servlet.rb +247 -0
  86. data/lib/puppet/sslcertificates.rb +737 -0
  87. data/lib/puppet/statechange.rb +150 -0
  88. data/lib/puppet/storage.rb +95 -0
  89. data/lib/puppet/transaction.rb +179 -0
  90. data/lib/puppet/transportable.rb +151 -0
  91. data/lib/puppet/type.rb +1354 -0
  92. data/lib/puppet/type/component.rb +141 -0
  93. data/lib/puppet/type/cron.rb +543 -0
  94. data/lib/puppet/type/exec.rb +316 -0
  95. data/lib/puppet/type/group.rb +152 -0
  96. data/lib/puppet/type/nameservice.rb +3 -0
  97. data/lib/puppet/type/nameservice/netinfo.rb +173 -0
  98. data/lib/puppet/type/nameservice/objectadd.rb +146 -0
  99. data/lib/puppet/type/nameservice/posix.rb +200 -0
  100. data/lib/puppet/type/package.rb +420 -0
  101. data/lib/puppet/type/package/apt.rb +70 -0
  102. data/lib/puppet/type/package/dpkg.rb +108 -0
  103. data/lib/puppet/type/package/rpm.rb +81 -0
  104. data/lib/puppet/type/package/sun.rb +117 -0
  105. data/lib/puppet/type/package/yum.rb +58 -0
  106. data/lib/puppet/type/pfile.rb +569 -0
  107. data/lib/puppet/type/pfile/checksum.rb +219 -0
  108. data/lib/puppet/type/pfile/create.rb +108 -0
  109. data/lib/puppet/type/pfile/group.rb +129 -0
  110. data/lib/puppet/type/pfile/mode.rb +131 -0
  111. data/lib/puppet/type/pfile/source.rb +264 -0
  112. data/lib/puppet/type/pfile/type.rb +31 -0
  113. data/lib/puppet/type/pfile/uid.rb +166 -0
  114. data/lib/puppet/type/pfilebucket.rb +80 -0
  115. data/lib/puppet/type/pprocess.rb +97 -0
  116. data/lib/puppet/type/service.rb +347 -0
  117. data/lib/puppet/type/service/base.rb +17 -0
  118. data/lib/puppet/type/service/debian.rb +50 -0
  119. data/lib/puppet/type/service/init.rb +145 -0
  120. data/lib/puppet/type/service/smf.rb +29 -0
  121. data/lib/puppet/type/state.rb +182 -0
  122. data/lib/puppet/type/symlink.rb +183 -0
  123. data/lib/puppet/type/tidy.rb +183 -0
  124. data/lib/puppet/type/typegen.rb +149 -0
  125. data/lib/puppet/type/typegen/filerecord.rb +243 -0
  126. data/lib/puppet/type/typegen/filetype.rb +316 -0
  127. data/lib/puppet/type/user.rb +290 -0
  128. data/lib/puppet/util.rb +138 -0
  129. data/test/certmgr/certmgr.rb +265 -0
  130. data/test/client/client.rb +203 -0
  131. data/test/executables/puppetbin.rb +53 -0
  132. data/test/executables/puppetca.rb +79 -0
  133. data/test/executables/puppetd.rb +71 -0
  134. data/test/executables/puppetmasterd.rb +153 -0
  135. data/test/executables/puppetmodule.rb +60 -0
  136. data/test/language/ast.rb +412 -0
  137. data/test/language/interpreter.rb +71 -0
  138. data/test/language/scope.rb +412 -0
  139. data/test/language/snippets.rb +445 -0
  140. data/test/other/events.rb +111 -0
  141. data/test/other/log.rb +195 -0
  142. data/test/other/metrics.rb +92 -0
  143. data/test/other/overrides.rb +115 -0
  144. data/test/other/parsedfile.rb +31 -0
  145. data/test/other/relationships.rb +113 -0
  146. data/test/other/state.rb +106 -0
  147. data/test/other/storage.rb +39 -0
  148. data/test/other/transactions.rb +235 -0
  149. data/test/parser/lexer.rb +120 -0
  150. data/test/parser/parser.rb +180 -0
  151. data/test/puppet/conffiles.rb +104 -0
  152. data/test/puppet/defaults.rb +100 -0
  153. data/test/puppet/error.rb +23 -0
  154. data/test/puppet/utiltest.rb +120 -0
  155. data/test/puppettest.rb +774 -0
  156. data/test/server/authstore.rb +209 -0
  157. data/test/server/bucket.rb +227 -0
  158. data/test/server/ca.rb +201 -0
  159. data/test/server/fileserver.rb +710 -0
  160. data/test/server/logger.rb +175 -0
  161. data/test/server/master.rb +150 -0
  162. data/test/server/server.rb +130 -0
  163. data/test/tagging/tagging.rb +80 -0
  164. data/test/test +51 -0
  165. data/test/types/basic.rb +119 -0
  166. data/test/types/component.rb +272 -0
  167. data/test/types/cron.rb +261 -0
  168. data/test/types/exec.rb +273 -0
  169. data/test/types/file.rb +616 -0
  170. data/test/types/filebucket.rb +167 -0
  171. data/test/types/fileignoresource.rb +287 -0
  172. data/test/types/filesources.rb +587 -0
  173. data/test/types/filetype.rb +162 -0
  174. data/test/types/group.rb +271 -0
  175. data/test/types/package.rb +205 -0
  176. data/test/types/query.rb +101 -0
  177. data/test/types/service.rb +100 -0
  178. data/test/types/symlink.rb +93 -0
  179. data/test/types/tidy.rb +124 -0
  180. data/test/types/type.rb +135 -0
  181. data/test/types/user.rb +371 -0
  182. metadata +243 -0
@@ -0,0 +1,321 @@
1
+ require 'syslog'
2
+
3
+ module Puppet # :nodoc:
4
+ # Pass feedback to the user. Log levels are modeled after syslog's, and it is
5
+ # expected that that will be the most common log destination. Supports
6
+ # multiple destinations, one of which is a remote server.
7
+ class Log
8
+ PINK=""
9
+ GREEN=""
10
+ YELLOW=""
11
+ SLATE=""
12
+ ORANGE=""
13
+ BLUE=""
14
+ RESET=""
15
+
16
+ @levels = [:debug,:info,:notice,:warning,:err,:alert,:emerg,:crit]
17
+ @loglevel = 2
18
+
19
+ @colors = {
20
+ :debug => SLATE,
21
+ :info => GREEN,
22
+ :notice => PINK,
23
+ :warning => ORANGE,
24
+ :err => YELLOW,
25
+ :alert => BLUE,
26
+ :emerg => RESET,
27
+ :crit => RESET
28
+ }
29
+
30
+ @destinations = {:syslog => Syslog.open("puppet")}
31
+
32
+ # Reset all logs to basics. Basically just closes all files and undefs
33
+ # all of the other objects.
34
+ def Log.close(dest = nil)
35
+ if dest
36
+ if @destinations.include?(dest)
37
+ Puppet.warning "Closing %s" % dest
38
+ if @destinations.respond_to?(:close)
39
+ @destinations[dest].close
40
+ end
41
+ @destinations.delete(dest)
42
+ end
43
+ else
44
+ @destinations.each { |type, dest|
45
+ if dest.respond_to?(:flush)
46
+ dest.flush
47
+ end
48
+ if dest.respond_to?(:close)
49
+ dest.close
50
+ end
51
+ }
52
+ @destinations = {}
53
+ end
54
+
55
+ Puppet.info "closed"
56
+ end
57
+
58
+ # Flush any log destinations that support such operations.
59
+ def Log.flush
60
+ @destinations.each { |type, dest|
61
+ if dest.respond_to?(:flush)
62
+ dest.flush
63
+ end
64
+ }
65
+ end
66
+
67
+ # Create a new log message. The primary role of this method is to
68
+ # avoid creating log messages below the loglevel.
69
+ def Log.create(hash)
70
+ if @levels.index(hash[:level]) >= @loglevel
71
+ return Puppet::Log.new(hash)
72
+ else
73
+ return nil
74
+ end
75
+ end
76
+
77
+ # Yield each valid level in turn
78
+ def Log.eachlevel
79
+ @levels.each { |level| yield level }
80
+ end
81
+
82
+ # Return the current log level.
83
+ def Log.level
84
+ return @levels[@loglevel]
85
+ end
86
+
87
+ # Set the current log level.
88
+ def Log.level=(level)
89
+ unless level.is_a?(Symbol)
90
+ level = level.intern
91
+ end
92
+
93
+ unless @levels.include?(level)
94
+ raise Puppet::DevError, "Invalid loglevel %s" % level
95
+ end
96
+
97
+ @loglevel = @levels.index(level)
98
+ end
99
+
100
+ # Create a new log destination.
101
+ def Log.newdestination(dest)
102
+ # Each destination can only occur once.
103
+ if @destinations.include?(dest)
104
+ return
105
+ end
106
+
107
+ case dest
108
+ when "syslog", :syslog
109
+ if Syslog.opened?
110
+ Syslog.close
111
+ end
112
+ @destinations[:syslog] = Syslog.open("puppet")
113
+ when /^\// # files
114
+ Puppet.info "opening %s as a log" % dest
115
+ # first make sure the directory exists
116
+ unless FileTest.exist?(File.dirname(dest))
117
+ begin
118
+ Puppet.recmkdir(File.dirname(dest))
119
+ Puppet.info "Creating log directory %s" %
120
+ File.dirname(dest)
121
+ rescue => detail
122
+ Log.destination = :console
123
+ Puppet.err "Could not create log directory: %s" %
124
+ detail
125
+ return
126
+ end
127
+ end
128
+
129
+ begin
130
+ # create the log file, if it doesn't already exist
131
+ file = File.open(dest,File::WRONLY|File::CREAT|File::APPEND)
132
+ rescue => detail
133
+ Log.destination = :console
134
+ Puppet.err "Could not create log file: %s" %
135
+ detail
136
+ return
137
+ end
138
+ @destinations[dest] = file
139
+ when "console", :console
140
+ @destinations[:console] = :console
141
+ when Puppet::Server::Logger
142
+ @destinations[dest] = dest
143
+ else
144
+ Puppet.info "Treating %s as a hostname" % dest
145
+ args = {}
146
+ if dest =~ /:(\d+)/
147
+ args[:Port] = $1
148
+ args[:Server] = dest.sub(/:\d+/, '')
149
+ else
150
+ args[:Server] = dest
151
+ end
152
+ @destinations[dest] = Puppet::Client::LogClient.new(args)
153
+ end
154
+ end
155
+
156
+ # Route the actual message. FIXME There are lots of things this method should
157
+ # do, like caching, storing messages when there are not yet destinations,
158
+ # a bit more.
159
+ # It's worth noting that there's a potential for a loop here, if
160
+ # the machine somehow gets the destination set as itself.
161
+ def Log.newmessage(msg)
162
+ @destinations.each { |type, dest|
163
+ case dest
164
+ when Module # This is the Syslog module
165
+ next if msg.remote
166
+ # XXX Syslog currently has a bug that makes it so you
167
+ # cannot log a message with a '%' in it. So, we get rid
168
+ # of them.
169
+ if msg.source == "Puppet"
170
+ dest.send(msg.level, msg.to_s.gsub("%", '%%'))
171
+ else
172
+ dest.send(msg.level, "(%s) %s" %
173
+ [msg.source.to_s.gsub("%", ""), msg.to_s.gsub("%", '%%')]
174
+ )
175
+ end
176
+ when File:
177
+ dest.puts("%s %s (%s): %s" %
178
+ [msg.time, msg.source, msg.level, msg.to_s])
179
+ when :console
180
+ if msg.source == "Puppet"
181
+ puts @colors[msg.level] + "%s: %s" % [
182
+ msg.level, msg.to_s
183
+ ] + RESET
184
+ else
185
+ puts @colors[msg.level] + "%s: %s: %s" % [
186
+ msg.level, msg.source, msg.to_s
187
+ ] + RESET
188
+ end
189
+ when Puppet::Client::LogClient
190
+ unless msg.is_a?(String) or msg.remote
191
+ unless defined? @hostname
192
+ @hostname = Facter["hostname"].value
193
+ end
194
+ unless defined? @domain
195
+ @domain = Facter["domain"].value
196
+ if @domain
197
+ @hostname += "." + @domain
198
+ end
199
+ end
200
+ if msg.source =~ /^\//
201
+ msg.source = @hostname + ":" + msg.source
202
+ elsif msg.source == "Puppet"
203
+ msg.source = @hostname + " " + msg.source
204
+ else
205
+ msg.source = @hostname + " " + msg.source
206
+ end
207
+ begin
208
+ #puts "would have sent %s" % msg
209
+ #puts "would have sent %s" %
210
+ # CGI.escape(Marshal::dump(msg))
211
+ begin
212
+ tmp = CGI.escape(Marshal::dump(msg))
213
+ rescue => detail
214
+ puts "Could not dump: %s" % detail.to_s
215
+ return
216
+ end
217
+ # Add the hostname to the source
218
+ dest.addlog(tmp)
219
+ #dest.addlog(msg.to_s)
220
+ sleep(0.5)
221
+ rescue => detail
222
+ Puppet.err detail
223
+ @destinations.delete(type)
224
+ end
225
+ end
226
+ else
227
+ raise Puppet::Error, "Invalid log destination %s" % dest
228
+ #puts "Invalid log destination %s" % dest.inspect
229
+ end
230
+ }
231
+ end
232
+
233
+ # Reopen all of our logs.
234
+ def Log.reopen
235
+ types = @destinations.keys
236
+ @destinations.each { |type, dest|
237
+ if dest.respond_to?(:close)
238
+ dest.close
239
+ end
240
+ }
241
+ @destinations.clear
242
+ # We need to make sure we always end up with some kind of destination
243
+ begin
244
+ types.each { |type|
245
+ Log.newdestination(type)
246
+ }
247
+ rescue => detail
248
+ if @destinations.empty?
249
+ Log.newdestination(:syslog)
250
+ Puppet.err detail.to_s
251
+ end
252
+ end
253
+ end
254
+
255
+ # Is the passed level a valid log level?
256
+ def self.validlevel?(level)
257
+ @levels.include?(level)
258
+ end
259
+
260
+ attr_accessor :level, :message, :time, :tags, :remote
261
+ attr_reader :source
262
+
263
+ def initialize(args)
264
+ unless args.include?(:level) && args.include?(:message)
265
+ raise Puppet::DevError, "Puppet::Log called incorrectly"
266
+ end
267
+
268
+ if args[:level].class == String
269
+ @level = args[:level].intern
270
+ elsif args[:level].class == Symbol
271
+ @level = args[:level]
272
+ else
273
+ raise Puppet::DevError,
274
+ "Level is not a string or symbol: #{args[:level].class}"
275
+ end
276
+ @message = args[:message].to_s
277
+ @time = Time.now
278
+ # this should include the host name, and probly lots of other
279
+ # stuff, at some point
280
+ unless self.class.validlevel?(level)
281
+ raise Puppet::DevError, "Invalid message level #{level}"
282
+ end
283
+
284
+ if args.include?(:tags)
285
+ @tags = args[:tags]
286
+ end
287
+
288
+ if args.include?(:source)
289
+ self.source = args[:source]
290
+ else
291
+ @source = "Puppet"
292
+ end
293
+
294
+ Log.newmessage(self)
295
+ end
296
+
297
+ # If they pass a source in to us, we make sure it is a string, and
298
+ # we retrieve any tags we can.
299
+ def source=(source)
300
+ # We can't store the actual source, we just store the path. This
301
+ # is a bit of a stupid hack, specifically testing for elements, but
302
+ # eh.
303
+ if source.is_a?(Puppet::Element) and source.respond_to?(:path)
304
+ @source = source.path
305
+ else
306
+ @source = source.to_s
307
+ end
308
+ unless defined? @tags and @tags
309
+ if source.respond_to?(:tags)
310
+ @tags = source.tags
311
+ end
312
+ end
313
+ end
314
+
315
+ def to_s
316
+ return @message
317
+ end
318
+ end
319
+ end
320
+
321
+ # $Id: log.rb 742 2005-11-16 17:12:11Z luke $
@@ -0,0 +1,250 @@
1
+ # included so we can test object types
2
+ require 'puppet'
3
+
4
+ module Puppet # :nodoc:
5
+ # A class for handling metrics. This is currently ridiculously hackish.
6
+ class Metric
7
+ def Metric.init
8
+ @@typemetrics = Hash.new { |typehash,typename|
9
+ typehash[typename] = Hash.new(0)
10
+ }
11
+
12
+ @@eventmetrics = Hash.new(0)
13
+
14
+ @@metrics = {}
15
+ end
16
+
17
+ def Metric.clear
18
+ Metric.init
19
+ end
20
+
21
+ def Metric.gather
22
+ Metric.init
23
+
24
+ # first gather stats about all of the types
25
+ Puppet::Type.eachtype { |type|
26
+ type.each { |instance|
27
+ hash = @@typemetrics[type]
28
+ hash[:total] += 1
29
+ if instance.managed?
30
+ hash[:managed] += 1
31
+ end
32
+ }
33
+ }
34
+
35
+ # the rest of the metrics are injected directly by type.rb
36
+ end
37
+
38
+ def Metric.add(type,instance,metric,count)
39
+ return unless defined? @@typemetrics
40
+ case metric
41
+ when :outofsync:
42
+ @@typemetrics[type][metric] += count
43
+ when :changes:
44
+ @@typemetrics[type][:changed] += 1
45
+ @@typemetrics[type][:totalchanges] += count
46
+ else
47
+ raise Puppet::DevError, "Unknown metric %s" % metric
48
+ end
49
+ end
50
+
51
+ # we're currently throwing away the type and instance information
52
+ def Metric.addevents(type,instance,events)
53
+ return unless defined? @@eventmetrics
54
+ events.each { |event|
55
+ @@eventmetrics[event] += 1
56
+ }
57
+ end
58
+
59
+ # Iterate across all of the metrics
60
+ def Metric.each
61
+ @@metrics.each { |name,metric|
62
+ yield metric
63
+ }
64
+ end
65
+
66
+ # I'm nearly positive this method is used only for testing
67
+ def Metric.load(ary)
68
+ @@typemetrics = ary[0]
69
+ @@eventmetrics = ary[1]
70
+ end
71
+
72
+ def Metric.graph(range = nil)
73
+ @@metrics.each { |name,metric|
74
+ metric.graph(range)
75
+ }
76
+ end
77
+
78
+ def Metric.store(time = nil)
79
+ require 'RRD'
80
+ unless time
81
+ time = Time.now.to_i
82
+ end
83
+ @@metrics.each { |name,metric|
84
+ metric.store(time)
85
+ }
86
+ end
87
+
88
+ def Metric.tally
89
+ type = Metric.new("typecount","Types")
90
+ type.newvalue("Number",@@typemetrics.length)
91
+
92
+ metrics = {
93
+ :total => "Instances",
94
+ :managed => "Managed Instances",
95
+ :outofsync => "Out of Sync Instances",
96
+ :changed => "Changed Instances",
97
+ :totalchanges => "Total Number of Changes",
98
+ }
99
+ total = Hash.new(0)
100
+ @@typemetrics.each { |type,instancehash|
101
+ name = type.name.to_s
102
+ instmet = Metric.new("type-" + name,name.capitalize)
103
+ metrics.each { |symbol,label|
104
+ instmet.newvalue(symbol.to_s,instancehash[symbol],label)
105
+ total[symbol] += instancehash[symbol]
106
+ }
107
+ }
108
+
109
+ totalmet = Metric.new("typetotals","Type Totals")
110
+ metrics.each { |symbol,label|
111
+ totalmet.newvalue(symbol.to_s,total[symbol],label)
112
+ }
113
+
114
+ eventmet = Metric.new("events")
115
+ total = 0
116
+ @@eventmetrics.each { |event,count|
117
+ event = event.to_s
118
+ # add the specific event as a value, with the label being a
119
+ # capitalized version with s/_/ /g
120
+ eventmet.newvalue(
121
+ event,
122
+ count,
123
+ event.capitalize.gsub(/_/,' ')
124
+ )
125
+
126
+ total += count
127
+ }
128
+ eventmet.newvalue("total",total,"Event Total")
129
+ end
130
+
131
+ attr_accessor :type, :name, :value, :label
132
+
133
+
134
+ def create
135
+ dir = Puppet[:rrddir]
136
+ unless dir
137
+ raise "Cannot store metrics unless RRDDir is set"
138
+ end
139
+
140
+ unless FileTest.exist?(dir)
141
+ tmp = dir.sub(/^\//,'')
142
+ path = [File::SEPARATOR]
143
+ tmp.split(File::SEPARATOR).each { |d|
144
+ path.push d
145
+ unless FileTest.exist?(File.join(path))
146
+ Dir.mkdir(File.join(path))
147
+ end
148
+ }
149
+ end
150
+
151
+ unless FileTest.directory?(dir)
152
+ raise Puppet::Error.new("%s must be a directory" % dir)
153
+ end
154
+
155
+ path = self.path
156
+ args = [
157
+ path,
158
+ "--start", Time.now.to_i - 5,
159
+ "--step", "300", # XXX Defaulting to every five minutes, but prob bad
160
+ ]
161
+
162
+ @values.each { |value|
163
+ args.push "DS:%s:GAUGE:600:U:U" % value[0]
164
+ }
165
+ args.push "RRA:AVERAGE:0.5:1:300"
166
+
167
+ begin
168
+ RRD.create(*args)
169
+ rescue => detail
170
+ raise "Could not create RRD file %s: %s" % [path,detail]
171
+ end
172
+ end
173
+
174
+ def initialize(name,label = nil)
175
+ @name = name
176
+ if label
177
+ @label = label
178
+ else
179
+ @label = name.capitalize
180
+ end
181
+
182
+ @values = []
183
+ if @@metrics.include?(self.name)
184
+ raise "Somehow created two metrics with name %s" % self.name
185
+ else
186
+ @@metrics[self.name] = self
187
+ end
188
+ end
189
+
190
+ def newvalue(name,value,label = nil)
191
+ unless label
192
+ label = name.capitalize
193
+ end
194
+ @values.push [name,label,value]
195
+ end
196
+
197
+ def path
198
+ return File.join(Puppet[:rrddir],@name + ".rrd")
199
+ end
200
+
201
+ def graph(range = nil)
202
+ args = [self.path.sub(/rrd$/,"png")]
203
+ args.push("--title",self.label)
204
+ args.push("--imgformat","PNG")
205
+ args.push("--interlace")
206
+ colorstack = %w{#ff0000 #00ff00 #0000ff #099000 #000990 #f00990}
207
+ i = 0
208
+ defs = []
209
+ lines = []
210
+ @values.zip(colorstack).each { |value,color|
211
+ next if value.nil?
212
+ # this actually uses the data label
213
+ defs.push("DEF:%s=%s:%s:AVERAGE" % [value[0],self.path,value[0]])
214
+ lines.push("LINE3:%s%s:%s" % [value[0],color,value[1]])
215
+ }
216
+ args << defs
217
+ args << lines
218
+ args.flatten!
219
+ if range
220
+ args.push("--start",range[0],"--end",range[1])
221
+ end
222
+
223
+ begin
224
+ RRD.graph(*args)
225
+ rescue => detail
226
+ Puppet.err "Failed to graph %s: %s" % [self.name,detail]
227
+ end
228
+ end
229
+
230
+ def store(time)
231
+ unless FileTest.exists?(File.join(Puppet[:rrddir],@name + ".rrd"))
232
+ self.create
233
+ end
234
+
235
+ # XXX this is not terribly error-resistant
236
+ args = [time]
237
+ @values.each { |value|
238
+ args.push value[2]
239
+ }
240
+ arg = args.join(":")
241
+ begin
242
+ RRD.update(self.path,args.join(":"))
243
+ rescue => detail
244
+ raise Puppet::Error, "Failed to update %s: %s" % [self.name,detail]
245
+ end
246
+ end
247
+ end
248
+ end
249
+
250
+ # $Id: metric.rb 732 2005-10-28 05:39:59Z luke $