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.
- data/CHANGELOG +0 -0
- data/COPYING +340 -0
- data/LICENSE +17 -0
- data/README +24 -0
- data/Rakefile +294 -0
- data/TODO +4 -0
- data/bin/cf2puppet +186 -0
- data/bin/puppet +176 -0
- data/bin/puppetca +213 -0
- data/bin/puppetd +246 -0
- data/bin/puppetdoc +184 -0
- data/bin/puppetmasterd +258 -0
- data/examples/code/allatonce +13 -0
- data/examples/code/assignments +11 -0
- data/examples/code/classing +35 -0
- data/examples/code/components +73 -0
- data/examples/code/execs +16 -0
- data/examples/code/failers/badclassnoparam +10 -0
- data/examples/code/failers/badclassparam +10 -0
- data/examples/code/failers/badcompnoparam +9 -0
- data/examples/code/failers/badcompparam +9 -0
- data/examples/code/failers/badtypeparam +3 -0
- data/examples/code/file.bl +11 -0
- data/examples/code/filedefaults +10 -0
- data/examples/code/fileparsing +116 -0
- data/examples/code/filerecursion +15 -0
- data/examples/code/functions +3 -0
- data/examples/code/groups +7 -0
- data/examples/code/head +30 -0
- data/examples/code/importing +8 -0
- data/examples/code/nodes +20 -0
- data/examples/code/one +8 -0
- data/examples/code/relationships +34 -0
- data/examples/code/selectors +28 -0
- data/examples/code/simpletests +11 -0
- data/examples/code/snippets/argumentdefaults +14 -0
- data/examples/code/snippets/casestatement +39 -0
- data/examples/code/snippets/classheirarchy.pp +15 -0
- data/examples/code/snippets/classincludes.pp +17 -0
- data/examples/code/snippets/classpathtest +11 -0
- data/examples/code/snippets/dirchmod +19 -0
- data/examples/code/snippets/failmissingexecpath.pp +13 -0
- data/examples/code/snippets/falsevalues.pp +3 -0
- data/examples/code/snippets/filecreate +11 -0
- data/examples/code/snippets/implicititeration +15 -0
- data/examples/code/snippets/multipleinstances +7 -0
- data/examples/code/snippets/namevartest +9 -0
- data/examples/code/snippets/scopetest +13 -0
- data/examples/code/snippets/selectorvalues.pp +22 -0
- data/examples/code/snippets/simpledefaults +5 -0
- data/examples/code/snippets/simpleselector +38 -0
- data/examples/code/svncommit +13 -0
- data/examples/root/bin/sleeper +69 -0
- data/examples/root/etc/configfile +0 -0
- data/examples/root/etc/debian-passwd +29 -0
- data/examples/root/etc/debian-syslog.conf +71 -0
- data/examples/root/etc/init.d/sleeper +65 -0
- data/examples/root/etc/otherfile +0 -0
- data/examples/root/etc/puppet/fileserver.conf +3 -0
- data/examples/root/etc/puppet/puppetmasterd.conf +10 -0
- data/ext/module:puppet +195 -0
- data/install.rb +270 -0
- data/lib/puppet.rb +249 -0
- data/lib/puppet/base64.rb +19 -0
- data/lib/puppet/client.rb +519 -0
- data/lib/puppet/config.rb +49 -0
- data/lib/puppet/daemon.rb +208 -0
- data/lib/puppet/element.rb +71 -0
- data/lib/puppet/event.rb +259 -0
- data/lib/puppet/log.rb +321 -0
- data/lib/puppet/metric.rb +250 -0
- data/lib/puppet/parsedfile.rb +38 -0
- data/lib/puppet/parser/ast.rb +1560 -0
- data/lib/puppet/parser/interpreter.rb +150 -0
- data/lib/puppet/parser/lexer.rb +226 -0
- data/lib/puppet/parser/parser.rb +1354 -0
- data/lib/puppet/parser/scope.rb +755 -0
- data/lib/puppet/server.rb +170 -0
- data/lib/puppet/server/authstore.rb +227 -0
- data/lib/puppet/server/ca.rb +140 -0
- data/lib/puppet/server/filebucket.rb +147 -0
- data/lib/puppet/server/fileserver.rb +477 -0
- data/lib/puppet/server/logger.rb +43 -0
- data/lib/puppet/server/master.rb +103 -0
- data/lib/puppet/server/servlet.rb +247 -0
- data/lib/puppet/sslcertificates.rb +737 -0
- data/lib/puppet/statechange.rb +150 -0
- data/lib/puppet/storage.rb +95 -0
- data/lib/puppet/transaction.rb +179 -0
- data/lib/puppet/transportable.rb +151 -0
- data/lib/puppet/type.rb +1354 -0
- data/lib/puppet/type/component.rb +141 -0
- data/lib/puppet/type/cron.rb +543 -0
- data/lib/puppet/type/exec.rb +316 -0
- data/lib/puppet/type/group.rb +152 -0
- data/lib/puppet/type/nameservice.rb +3 -0
- data/lib/puppet/type/nameservice/netinfo.rb +173 -0
- data/lib/puppet/type/nameservice/objectadd.rb +146 -0
- data/lib/puppet/type/nameservice/posix.rb +200 -0
- data/lib/puppet/type/package.rb +420 -0
- data/lib/puppet/type/package/apt.rb +70 -0
- data/lib/puppet/type/package/dpkg.rb +108 -0
- data/lib/puppet/type/package/rpm.rb +81 -0
- data/lib/puppet/type/package/sun.rb +117 -0
- data/lib/puppet/type/package/yum.rb +58 -0
- data/lib/puppet/type/pfile.rb +569 -0
- data/lib/puppet/type/pfile/checksum.rb +219 -0
- data/lib/puppet/type/pfile/create.rb +108 -0
- data/lib/puppet/type/pfile/group.rb +129 -0
- data/lib/puppet/type/pfile/mode.rb +131 -0
- data/lib/puppet/type/pfile/source.rb +264 -0
- data/lib/puppet/type/pfile/type.rb +31 -0
- data/lib/puppet/type/pfile/uid.rb +166 -0
- data/lib/puppet/type/pfilebucket.rb +80 -0
- data/lib/puppet/type/pprocess.rb +97 -0
- data/lib/puppet/type/service.rb +347 -0
- data/lib/puppet/type/service/base.rb +17 -0
- data/lib/puppet/type/service/debian.rb +50 -0
- data/lib/puppet/type/service/init.rb +145 -0
- data/lib/puppet/type/service/smf.rb +29 -0
- data/lib/puppet/type/state.rb +182 -0
- data/lib/puppet/type/symlink.rb +183 -0
- data/lib/puppet/type/tidy.rb +183 -0
- data/lib/puppet/type/typegen.rb +149 -0
- data/lib/puppet/type/typegen/filerecord.rb +243 -0
- data/lib/puppet/type/typegen/filetype.rb +316 -0
- data/lib/puppet/type/user.rb +290 -0
- data/lib/puppet/util.rb +138 -0
- data/test/certmgr/certmgr.rb +265 -0
- data/test/client/client.rb +203 -0
- data/test/executables/puppetbin.rb +53 -0
- data/test/executables/puppetca.rb +79 -0
- data/test/executables/puppetd.rb +71 -0
- data/test/executables/puppetmasterd.rb +153 -0
- data/test/executables/puppetmodule.rb +60 -0
- data/test/language/ast.rb +412 -0
- data/test/language/interpreter.rb +71 -0
- data/test/language/scope.rb +412 -0
- data/test/language/snippets.rb +445 -0
- data/test/other/events.rb +111 -0
- data/test/other/log.rb +195 -0
- data/test/other/metrics.rb +92 -0
- data/test/other/overrides.rb +115 -0
- data/test/other/parsedfile.rb +31 -0
- data/test/other/relationships.rb +113 -0
- data/test/other/state.rb +106 -0
- data/test/other/storage.rb +39 -0
- data/test/other/transactions.rb +235 -0
- data/test/parser/lexer.rb +120 -0
- data/test/parser/parser.rb +180 -0
- data/test/puppet/conffiles.rb +104 -0
- data/test/puppet/defaults.rb +100 -0
- data/test/puppet/error.rb +23 -0
- data/test/puppet/utiltest.rb +120 -0
- data/test/puppettest.rb +774 -0
- data/test/server/authstore.rb +209 -0
- data/test/server/bucket.rb +227 -0
- data/test/server/ca.rb +201 -0
- data/test/server/fileserver.rb +710 -0
- data/test/server/logger.rb +175 -0
- data/test/server/master.rb +150 -0
- data/test/server/server.rb +130 -0
- data/test/tagging/tagging.rb +80 -0
- data/test/test +51 -0
- data/test/types/basic.rb +119 -0
- data/test/types/component.rb +272 -0
- data/test/types/cron.rb +261 -0
- data/test/types/exec.rb +273 -0
- data/test/types/file.rb +616 -0
- data/test/types/filebucket.rb +167 -0
- data/test/types/fileignoresource.rb +287 -0
- data/test/types/filesources.rb +587 -0
- data/test/types/filetype.rb +162 -0
- data/test/types/group.rb +271 -0
- data/test/types/package.rb +205 -0
- data/test/types/query.rb +101 -0
- data/test/types/service.rb +100 -0
- data/test/types/symlink.rb +93 -0
- data/test/types/tidy.rb +124 -0
- data/test/types/type.rb +135 -0
- data/test/types/user.rb +371 -0
- metadata +243 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
module Puppet # :nodoc:
|
2
|
+
# The class for handling configuration files.
|
3
|
+
class Config < Hash
|
4
|
+
# Slight override, since we can't seem to have a subclass where all instances
|
5
|
+
# have the same default block.
|
6
|
+
def [](section)
|
7
|
+
unless self.has_key?(section)
|
8
|
+
self[section] = {}
|
9
|
+
end
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(file)
|
14
|
+
text = nil
|
15
|
+
|
16
|
+
begin
|
17
|
+
text = File.read(file)
|
18
|
+
rescue Errno::ENOENT
|
19
|
+
raise Puppet::Error, "No such file %s" % file
|
20
|
+
rescue Errno::EACCES
|
21
|
+
raise Puppet::Error, "Permission denied to file %s" % file
|
22
|
+
end
|
23
|
+
|
24
|
+
# Store it for later, in a way that we can test and such.
|
25
|
+
@file = Puppet::ParsedFile.new(file)
|
26
|
+
|
27
|
+
@values = Hash.new { |names, name|
|
28
|
+
names[name] = {}
|
29
|
+
}
|
30
|
+
|
31
|
+
section = "puppet"
|
32
|
+
text.split(/\n/).each { |line|
|
33
|
+
case line
|
34
|
+
when /^\[(\w+)\]$/: section = $1 # Section names
|
35
|
+
when /^\s*#/: next # Skip comments
|
36
|
+
when /^\s*$/: next # Skip blanks
|
37
|
+
when /^\s*(\w+)\s+(.+)$/: # settings
|
38
|
+
var = $1
|
39
|
+
value = $2
|
40
|
+
self[section][var] = value
|
41
|
+
else
|
42
|
+
raise Puppet::Error, "Could not match line %s" % line
|
43
|
+
end
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# $Id: config.rb 738 2005-10-31 22:50:09Z luke $
|
@@ -0,0 +1,208 @@
|
|
1
|
+
# helper functions for daemons
|
2
|
+
|
3
|
+
require 'puppet'
|
4
|
+
|
5
|
+
module Puppet # :nodoc:
|
6
|
+
# A module that handles operations common to all daemons.
|
7
|
+
module Daemon
|
8
|
+
# Put the daemon into the background.
|
9
|
+
def daemonize
|
10
|
+
if pid = fork()
|
11
|
+
Process.detach(pid)
|
12
|
+
exit(0)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Get rid of console logging
|
16
|
+
Puppet::Log.close(:console)
|
17
|
+
|
18
|
+
Process.setsid
|
19
|
+
Dir.chdir("/")
|
20
|
+
begin
|
21
|
+
$stdin.reopen "/dev/null"
|
22
|
+
$stdout.reopen "/dev/null", "a"
|
23
|
+
$stderr.reopen $stdout
|
24
|
+
Puppet::Log.reopen
|
25
|
+
rescue => detail
|
26
|
+
File.open("/tmp/daemonout", "w") { |f|
|
27
|
+
f.puts "Could not start %s: %s" % [$0, detail]
|
28
|
+
}
|
29
|
+
Puppet.err "Could not start %s: %s" % [$0, detail]
|
30
|
+
exit(12)
|
31
|
+
end
|
32
|
+
|
33
|
+
name = $0.gsub(/.+#{File::SEPARATOR}/,'')
|
34
|
+
@pidfile = File.join(Puppet[:puppetvar], name + ".pid")
|
35
|
+
if FileTest.exists?(@pidfile)
|
36
|
+
Puppet.info "Deleting old pid file"
|
37
|
+
begin
|
38
|
+
File.unlink(@pidfile)
|
39
|
+
rescue Errno::EACCES
|
40
|
+
Puppet.err "Could not delete old PID file; cannot create new one"
|
41
|
+
return
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
begin
|
46
|
+
File.open(@pidfile, "w") { |f| f.puts $$ }
|
47
|
+
rescue => detail
|
48
|
+
Puppet.err "Could not create PID file: %s" % detail
|
49
|
+
end
|
50
|
+
Puppet.info "pid file is %s" % @pidfile
|
51
|
+
end
|
52
|
+
|
53
|
+
def fqdn
|
54
|
+
unless defined? @fqdn and @fqdn
|
55
|
+
hostname = Facter["hostname"].value
|
56
|
+
domain = Facter["domain"].value
|
57
|
+
@fqdn = [hostname, domain].join(".")
|
58
|
+
end
|
59
|
+
return @fqdn
|
60
|
+
end
|
61
|
+
|
62
|
+
def httplog
|
63
|
+
args = []
|
64
|
+
# yuck; separate http logs
|
65
|
+
file = nil
|
66
|
+
if self.is_a?(Puppet::Server)
|
67
|
+
file = Puppet[:masterhttplog]
|
68
|
+
else
|
69
|
+
file = Puppet[:httplog]
|
70
|
+
end
|
71
|
+
|
72
|
+
unless FileTest.exists?(File.dirname(file))
|
73
|
+
Puppet.recmkdir(File.dirname(file))
|
74
|
+
end
|
75
|
+
args << file
|
76
|
+
if Puppet[:debug]
|
77
|
+
args << WEBrick::Log::DEBUG
|
78
|
+
end
|
79
|
+
|
80
|
+
log = WEBrick::Log.new(*args)
|
81
|
+
|
82
|
+
return log
|
83
|
+
end
|
84
|
+
|
85
|
+
def readcert
|
86
|
+
return unless @secureinit
|
87
|
+
# verify we've got all of the certs set up and such
|
88
|
+
|
89
|
+
if defined? @cert and defined? @key and @cert and @key
|
90
|
+
return true
|
91
|
+
end
|
92
|
+
|
93
|
+
# we are not going to encrypt our key, but we need at a minimum
|
94
|
+
# a keyfile and a certfile
|
95
|
+
@certfile = File.join(Puppet[:certdir], [@fqdn, "pem"].join("."))
|
96
|
+
@cacertfile = File.join(Puppet[:certdir], ["ca", "pem"].join("."))
|
97
|
+
@keyfile = File.join(Puppet[:privatekeydir], [@fqdn, "pem"].join("."))
|
98
|
+
@publickeyfile = File.join(Puppet[:publickeydir], [@fqdn, "pem"].join("."))
|
99
|
+
|
100
|
+
if File.exists?(@keyfile)
|
101
|
+
# load the key
|
102
|
+
@key = OpenSSL::PKey::RSA.new(File.read(@keyfile))
|
103
|
+
else
|
104
|
+
return false
|
105
|
+
end
|
106
|
+
|
107
|
+
if File.exists?(@certfile)
|
108
|
+
if File.exists?(@cacertfile)
|
109
|
+
@cacert = OpenSSL::X509::Certificate.new(File.read(@cacertfile))
|
110
|
+
else
|
111
|
+
raise Puppet::Error, "Found cert file with no ca cert file"
|
112
|
+
end
|
113
|
+
@cert = OpenSSL::X509::Certificate.new(File.read(@certfile))
|
114
|
+
else
|
115
|
+
return false
|
116
|
+
end
|
117
|
+
return true
|
118
|
+
end
|
119
|
+
|
120
|
+
def requestcert
|
121
|
+
retrieved = false
|
122
|
+
# create the directories involved
|
123
|
+
[Puppet[:certdir], Puppet[:privatekeydir], Puppet[:csrdir],
|
124
|
+
Puppet[:publickeydir]].each { |dir|
|
125
|
+
unless FileTest.exists?(dir)
|
126
|
+
Puppet.recmkdir(dir, 0770)
|
127
|
+
end
|
128
|
+
}
|
129
|
+
|
130
|
+
if self.readcert
|
131
|
+
Puppet.info "Certificate already exists; not requesting"
|
132
|
+
return true
|
133
|
+
end
|
134
|
+
|
135
|
+
unless defined? @key and @key
|
136
|
+
# create a new one and store it
|
137
|
+
Puppet.info "Creating a new SSL key at %s" % @keyfile
|
138
|
+
@key = OpenSSL::PKey::RSA.new(Puppet[:keylength])
|
139
|
+
File.open(@keyfile, "w", 0660) { |f| f.print @key.to_pem }
|
140
|
+
File.open(@publickeyfile, "w", 0660) { |f|
|
141
|
+
f.print @key.public_key.to_pem
|
142
|
+
}
|
143
|
+
end
|
144
|
+
|
145
|
+
unless defined? @driver
|
146
|
+
Puppet.err "Cannot request a certificate without a defined target"
|
147
|
+
return false
|
148
|
+
end
|
149
|
+
|
150
|
+
Puppet.info "Creating a new certificate request for %s" % @fqdn
|
151
|
+
name = OpenSSL::X509::Name.new([["CN", @fqdn]])
|
152
|
+
|
153
|
+
@csr = OpenSSL::X509::Request.new
|
154
|
+
@csr.version = 0
|
155
|
+
@csr.subject = name
|
156
|
+
@csr.public_key = @key.public_key
|
157
|
+
@csr.sign(@key, OpenSSL::Digest::MD5.new)
|
158
|
+
|
159
|
+
Puppet.info "Requesting certificate"
|
160
|
+
|
161
|
+
begin
|
162
|
+
cert, cacert = @driver.getcert(@csr.to_pem)
|
163
|
+
rescue => detail
|
164
|
+
raise Puppet::Error.new("Certificate retrieval failed: %s" %
|
165
|
+
detail)
|
166
|
+
end
|
167
|
+
|
168
|
+
if cert.nil? or cert == ""
|
169
|
+
return nil
|
170
|
+
end
|
171
|
+
File.open(@certfile, "w", 0660) { |f| f.print cert }
|
172
|
+
File.open(@cacertfile, "w", 0660) { |f| f.print cacert }
|
173
|
+
begin
|
174
|
+
@cert = OpenSSL::X509::Certificate.new(cert)
|
175
|
+
@cacert = OpenSSL::X509::Certificate.new(cacert)
|
176
|
+
retrieved = true
|
177
|
+
rescue => detail
|
178
|
+
raise Puppet::Error.new(
|
179
|
+
"Invalid certificate: %s" % detail
|
180
|
+
)
|
181
|
+
end
|
182
|
+
|
183
|
+
unless @cert.check_private_key(@key)
|
184
|
+
raise Puppet::DevError, "Received invalid certificate"
|
185
|
+
end
|
186
|
+
return retrieved
|
187
|
+
end
|
188
|
+
|
189
|
+
# Shut down our server
|
190
|
+
def shutdown
|
191
|
+
# Remove our pid file
|
192
|
+
if defined? @pidfile and @pidfile and FileTest.exists?(@pidfile)
|
193
|
+
begin
|
194
|
+
File.unlink(@pidfile)
|
195
|
+
rescue => detail
|
196
|
+
Puppet.err "Could not remove PID file %s: %s" % [@pidfile, detail]
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# And close all logs
|
201
|
+
Puppet::Log.close
|
202
|
+
|
203
|
+
super
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# $Id: daemon.rb 732 2005-10-28 05:39:59Z luke $
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# included so we can test object types
|
2
|
+
require 'puppet'
|
3
|
+
|
4
|
+
# the base class for both types and states
|
5
|
+
# very little functionality; basically just defines the interface
|
6
|
+
# and provides a few simple across-the-board functions like 'noop'
|
7
|
+
class Puppet::Element
|
8
|
+
include Puppet
|
9
|
+
attr_writer :noop
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_accessor :doc, :nodoc
|
13
|
+
end
|
14
|
+
|
15
|
+
# all of our subclasses must respond to each of these methods...
|
16
|
+
@@interface_methods = [
|
17
|
+
:retrieve, :insync?, :sync, :evaluate
|
18
|
+
]
|
19
|
+
|
20
|
+
# so raise an error if a method that isn't overridden gets called
|
21
|
+
@@interface_methods.each { |method|
|
22
|
+
self.send(:define_method,method) {
|
23
|
+
raise Puppet::DevError, "%s has not overridden %s" %
|
24
|
+
[self.class,method]
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
Puppet::Util.logmethods(self, true)
|
29
|
+
|
30
|
+
# for testing whether we should actually do anything
|
31
|
+
def noop
|
32
|
+
unless defined? @noop
|
33
|
+
@noop = false
|
34
|
+
end
|
35
|
+
return @noop || Puppet[:noop] || false
|
36
|
+
end
|
37
|
+
|
38
|
+
# return the full path to us, for logging and rollback
|
39
|
+
# some classes (e.g., FileTypeRecords) will have to override this
|
40
|
+
def path
|
41
|
+
unless defined? @path
|
42
|
+
if defined? @parent and @parent
|
43
|
+
if self.is_a?(Puppet::Type::Component)
|
44
|
+
@path = [@parent.path, self.name]
|
45
|
+
else
|
46
|
+
@path = [@parent.path, self.class.name.to_s + "=" + self.name]
|
47
|
+
end
|
48
|
+
else
|
49
|
+
# The top-level name is always puppet[top], so we don't bother with
|
50
|
+
# that. And we don't add the hostname here, it gets added
|
51
|
+
# in the log server thingy.
|
52
|
+
if self.name == "puppet[top]"
|
53
|
+
@path = ["/"]
|
54
|
+
else
|
55
|
+
# We assume that if we don't have a parent that we should not
|
56
|
+
# cache the path
|
57
|
+
if self.is_a?(Puppet::Type::Component)
|
58
|
+
@path = [self.name]
|
59
|
+
else
|
60
|
+
@path = [self.class.name.to_s + "=" + self.name]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
return @path.join("/")
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
# $Id: element.rb 742 2005-11-16 17:12:11Z luke $
|
data/lib/puppet/event.rb
ADDED
@@ -0,0 +1,259 @@
|
|
1
|
+
require 'puppet'
|
2
|
+
require 'puppet/type'
|
3
|
+
|
4
|
+
module Puppet
|
5
|
+
# events are transient packets of information; they result in one or more (or none)
|
6
|
+
# subscriptions getting triggered, and then they get cleared
|
7
|
+
# eventually, these will be passed on to some central event system
|
8
|
+
class Event
|
9
|
+
include Puppet
|
10
|
+
|
11
|
+
# subscriptions are permanent associations determining how different
|
12
|
+
# objects react to an event
|
13
|
+
class Subscription
|
14
|
+
include Puppet
|
15
|
+
attr_accessor :event, :callback
|
16
|
+
|
17
|
+
# Remove the existing subscriptions and such
|
18
|
+
def self.clear
|
19
|
+
self.init
|
20
|
+
end
|
21
|
+
|
22
|
+
# Remove a subscription
|
23
|
+
def self.delete(sub)
|
24
|
+
type, name = sub.targetarray
|
25
|
+
if @dependencies[type][name].include?(sub)
|
26
|
+
@dependencies[type][name].delete(sub)
|
27
|
+
end
|
28
|
+
|
29
|
+
type, name = sub.sourcearray
|
30
|
+
if @subscriptions[type][name].include?(sub)
|
31
|
+
@subscriptions[type][name].delete(sub)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Initialize our class variables. This is in a method so it can
|
36
|
+
# be called to clear the variables, too.
|
37
|
+
def self.init
|
38
|
+
# A hash of subscriptions and another of dependencies, organized by
|
39
|
+
# type, then by name. I'm storing them all here, so that I don't
|
40
|
+
# have to store the subscriptions with the individual objects,
|
41
|
+
# which makes creating and destroying objects as necessary much
|
42
|
+
# easier.
|
43
|
+
@subscriptions = Hash.new { |hash, key|
|
44
|
+
hash[key] = Hash.new { |shash, skey|
|
45
|
+
# Each object has an array of subscriptions
|
46
|
+
shash[skey] = []
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
@dependencies = Hash.new { |hash, key|
|
51
|
+
hash[key] = Hash.new { |shash, skey|
|
52
|
+
# Each object has an array of subscriptions
|
53
|
+
shash[skey] = []
|
54
|
+
}
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
self.init
|
59
|
+
|
60
|
+
# Store the new subscription in a central hash.
|
61
|
+
def self.newsub(sub)
|
62
|
+
# The dependencies map allows me to look up a subscription by
|
63
|
+
# target -- find out which objects a given object is subscribed
|
64
|
+
# to, and thus find out which objects that given object depends
|
65
|
+
# upon.
|
66
|
+
# DEPENDENCIES == TARGET
|
67
|
+
ttype, tname = sub.targetarray
|
68
|
+
@dependencies[ttype][tname] << sub
|
69
|
+
|
70
|
+
# Subscriptions are the list of subscriptions for a given object,
|
71
|
+
# i.e., the list of all objects that care about a given object's
|
72
|
+
# events.
|
73
|
+
# SUBSCRIPTION == SOURCE
|
74
|
+
stype, sname = sub.sourcearray
|
75
|
+
@subscriptions[stype][sname] << sub
|
76
|
+
end
|
77
|
+
|
78
|
+
# Trigger the subscriptions related to an event, and then pass it up
|
79
|
+
# as appropriate
|
80
|
+
def self.trigger(source, event, transaction)
|
81
|
+
type, name = self.split(source)
|
82
|
+
|
83
|
+
@subscriptions[type][name].each { |sub|
|
84
|
+
if sub.match?(event)
|
85
|
+
sub.trigger(transaction)
|
86
|
+
end
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
# Look up an object by type and name. This is used because we
|
91
|
+
# store symbolic links in our subscription hash rather than storing
|
92
|
+
# actual object references.
|
93
|
+
def self.retrieve(ary)
|
94
|
+
type, name = ary
|
95
|
+
typeobj = Puppet::Type.type(type)
|
96
|
+
|
97
|
+
unless typeobj
|
98
|
+
return nil
|
99
|
+
end
|
100
|
+
|
101
|
+
obj = typeobj[name]
|
102
|
+
return obj
|
103
|
+
end
|
104
|
+
|
105
|
+
# Split an object into its type and name
|
106
|
+
def self.split(object)
|
107
|
+
return [object.class.name, object.name]
|
108
|
+
end
|
109
|
+
|
110
|
+
# Retrieve all of the subscriptions that result in a dependency.
|
111
|
+
# We return the whole dependency here, because it is being returned
|
112
|
+
# to the object that made the subscription.
|
113
|
+
def self.dependencies(target)
|
114
|
+
type, name = self.split(target)
|
115
|
+
return @dependencies[type][name]
|
116
|
+
end
|
117
|
+
|
118
|
+
# Return all objects that are subscribed to us. We are only willing
|
119
|
+
# to return the object, not the subscription object, because the
|
120
|
+
# source shouldn't need to know things like the event or method that
|
121
|
+
# we're subscribed to.
|
122
|
+
def self.subscribers(source)
|
123
|
+
type, name = self.split(source)
|
124
|
+
return @subscriptions[type][name].collect { |sub|
|
125
|
+
sub.target
|
126
|
+
}
|
127
|
+
end
|
128
|
+
|
129
|
+
# The hash here must include the target and source objects, the event,
|
130
|
+
# and the callback to call.
|
131
|
+
def initialize(hash)
|
132
|
+
hash.each { |param,value|
|
133
|
+
# assign each value appropriately
|
134
|
+
# this is probably wicked-slow
|
135
|
+
self.send(param.to_s + "=",value)
|
136
|
+
}
|
137
|
+
|
138
|
+
self.class.newsub(self)
|
139
|
+
#Puppet.debug "New Subscription: '%s' => '%s'" %
|
140
|
+
# [@source,@event]
|
141
|
+
end
|
142
|
+
|
143
|
+
# Determine whether the passed event matches our event
|
144
|
+
def match?(event)
|
145
|
+
if event == :NONE or @event == :NONE
|
146
|
+
return false
|
147
|
+
elsif @event == :ALL_EVENTS or event == :ALL_EVENTS or event == @event
|
148
|
+
return true
|
149
|
+
else
|
150
|
+
return false
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# The source is the event source.
|
155
|
+
def source=(object)
|
156
|
+
type, name = self.class.split(object)
|
157
|
+
@source = [type, name]
|
158
|
+
end
|
159
|
+
|
160
|
+
def source
|
161
|
+
self.class.retrieve(@source)
|
162
|
+
end
|
163
|
+
|
164
|
+
def sourcearray
|
165
|
+
@source
|
166
|
+
end
|
167
|
+
|
168
|
+
# The target is the object who will receive the callbacks, i.e.,
|
169
|
+
# a source generates an event, which results in a callback on the
|
170
|
+
# target.
|
171
|
+
def target=(object)
|
172
|
+
type, name = self.class.split(object)
|
173
|
+
@target = [type, name]
|
174
|
+
end
|
175
|
+
|
176
|
+
def target
|
177
|
+
self.class.retrieve(@target)
|
178
|
+
end
|
179
|
+
|
180
|
+
def targetarray
|
181
|
+
@target
|
182
|
+
end
|
183
|
+
|
184
|
+
# Trigger a subscription, which basically calls the associated method
|
185
|
+
# on the target object.
|
186
|
+
def trigger(transaction)
|
187
|
+
event = nil
|
188
|
+
|
189
|
+
if @event == :NONE
|
190
|
+
# just ignore these subscriptions
|
191
|
+
return
|
192
|
+
end
|
193
|
+
|
194
|
+
if transaction.triggered?(self.target, @callback) > 0
|
195
|
+
Puppet.debug "%s has already run" % self
|
196
|
+
else
|
197
|
+
# We need to call the method, so that it gets retrieved
|
198
|
+
# as a real object.
|
199
|
+
target = self.target
|
200
|
+
#Puppet.debug "'%s' matched '%s'; triggering '%s' on '%s'" %
|
201
|
+
# [@source,@event,@method,target]
|
202
|
+
begin
|
203
|
+
if target.respond_to?(@callback)
|
204
|
+
event = target.send(@callback)
|
205
|
+
else
|
206
|
+
Puppet.debug(
|
207
|
+
"'%s' of type '%s' does not respond to '%s'" %
|
208
|
+
[target,target.class,@callback.inspect]
|
209
|
+
)
|
210
|
+
end
|
211
|
+
rescue => detail
|
212
|
+
# um, what the heck do i do when an object fails to
|
213
|
+
# refresh? shouldn't that result in the transaction
|
214
|
+
# rolling back? the 'onerror' metaparam will be used
|
215
|
+
# to determine behaviour in that case
|
216
|
+
Puppet.err "'%s' failed to %s: '%s'" %
|
217
|
+
[target,@callback,detail]
|
218
|
+
raise
|
219
|
+
#raise "We need to roll '%s' transaction back" %
|
220
|
+
#transaction
|
221
|
+
end
|
222
|
+
transaction.triggered(target, @callback)
|
223
|
+
end
|
224
|
+
return event
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
attr_accessor :event, :source, :transaction
|
229
|
+
|
230
|
+
@@events = []
|
231
|
+
|
232
|
+
@@subscriptions = []
|
233
|
+
|
234
|
+
def initialize(args)
|
235
|
+
unless args.include?(:event) and args.include?(:source)
|
236
|
+
raise Puppet::DevError, "Event.new called incorrectly"
|
237
|
+
end
|
238
|
+
|
239
|
+
@change = args[:change]
|
240
|
+
@event = args[:event]
|
241
|
+
@source = args[:source]
|
242
|
+
@transaction = args[:transaction]
|
243
|
+
|
244
|
+
#Puppet.info "%s: %s(%s)" %
|
245
|
+
#Puppet.info "%s: %s changed from %s to %s" %
|
246
|
+
# [@object,@state.name, @state.is,@state.should]
|
247
|
+
|
248
|
+
# initially, just stuff all instances into a central bucket
|
249
|
+
# to be handled as a batch
|
250
|
+
#@@events.push self
|
251
|
+
end
|
252
|
+
|
253
|
+
def to_s
|
254
|
+
self.event.to_s
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
# $Id: event.rb 710 2005-10-01 19:57:07Z luke $
|