puppet 0.9.2 → 0.13.0

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 (213) hide show
  1. data/CHANGELOG +58 -0
  2. data/README +21 -18
  3. data/Rakefile +176 -36
  4. data/bin/puppet +34 -48
  5. data/bin/puppetca +41 -28
  6. data/bin/puppetd +87 -65
  7. data/bin/puppetdoc +99 -23
  8. data/bin/puppetmasterd +72 -91
  9. data/conf/redhat/client.init +80 -0
  10. data/conf/redhat/client.sysconfig +11 -0
  11. data/conf/redhat/fileserver.conf +12 -0
  12. data/conf/redhat/puppet.spec +130 -0
  13. data/conf/redhat/server.init +89 -0
  14. data/conf/redhat/server.sysconfig +9 -0
  15. data/examples/code/allatonce +2 -2
  16. data/examples/code/assignments +1 -1
  17. data/examples/code/classing +2 -2
  18. data/examples/code/components +2 -2
  19. data/examples/code/file.bl +5 -5
  20. data/examples/code/filedefaults +2 -2
  21. data/examples/code/fileparsing +1 -1
  22. data/examples/code/filerecursion +1 -1
  23. data/examples/code/functions +1 -1
  24. data/examples/code/groups +1 -1
  25. data/examples/code/importing +1 -1
  26. data/examples/code/nodes +1 -1
  27. data/examples/code/one +1 -1
  28. data/examples/code/relationships +2 -2
  29. data/examples/code/simpletests +5 -5
  30. data/examples/code/snippets/argumentdefaults +2 -2
  31. data/examples/code/snippets/casestatement +16 -8
  32. data/examples/code/snippets/classheirarchy.pp +4 -4
  33. data/examples/code/snippets/classincludes.pp +4 -4
  34. data/examples/code/snippets/classpathtest +2 -2
  35. data/examples/code/snippets/componentmetaparams.pp +11 -0
  36. data/examples/code/snippets/dirchmod +5 -5
  37. data/examples/code/snippets/emptyclass.pp +9 -0
  38. data/examples/code/snippets/failmissingexecpath.pp +1 -1
  39. data/examples/code/snippets/falsevalues.pp +1 -1
  40. data/examples/code/snippets/filecreate +5 -5
  41. data/examples/code/snippets/implicititeration +5 -5
  42. data/examples/code/snippets/multipleinstances +4 -4
  43. data/examples/code/snippets/namevartest +3 -3
  44. data/examples/code/snippets/scopetest +1 -1
  45. data/examples/code/snippets/selectorvalues.pp +3 -3
  46. data/examples/code/snippets/simpledefaults +2 -2
  47. data/examples/code/snippets/simpleselector +5 -5
  48. data/examples/code/snippets/singleary.pp +19 -0
  49. data/examples/root/etc/init.d/sleeper +3 -2
  50. data/ext/emacs/puppet-mode-init.el +6 -0
  51. data/ext/emacs/puppet-mode.el +189 -0
  52. data/ext/ldap/puppet.schema +17 -0
  53. data/ext/{module:puppet → module_puppet} +30 -31
  54. data/ext/vim/filetype.vim +9 -0
  55. data/ext/vim/puppet.vim +87 -0
  56. data/install.rb +63 -30
  57. data/lib/puppet.rb +216 -122
  58. data/lib/puppet/client.rb +51 -416
  59. data/lib/puppet/client/ca.rb +17 -0
  60. data/lib/puppet/client/dipper.rb +78 -0
  61. data/lib/puppet/client/file.rb +20 -0
  62. data/lib/puppet/client/log.rb +17 -0
  63. data/lib/puppet/client/master.rb +246 -0
  64. data/lib/puppet/client/proxy.rb +27 -0
  65. data/lib/puppet/client/status.rb +7 -0
  66. data/lib/puppet/config.rb +563 -13
  67. data/lib/puppet/daemon.rb +50 -22
  68. data/lib/puppet/element.rb +4 -4
  69. data/lib/puppet/event-loop.rb +1 -0
  70. data/lib/puppet/event-loop/better-definers.rb +367 -0
  71. data/lib/puppet/event-loop/event-loop.rb +355 -0
  72. data/lib/puppet/event-loop/signal-system.rb +220 -0
  73. data/lib/puppet/event.rb +9 -11
  74. data/lib/puppet/filetype.rb +195 -0
  75. data/lib/puppet/log.rb +35 -12
  76. data/lib/puppet/metric.rb +2 -2
  77. data/lib/puppet/networkclient.rb +145 -0
  78. data/lib/puppet/parameter.rb +335 -0
  79. data/lib/puppet/parser/ast.rb +42 -1453
  80. data/lib/puppet/parser/ast/astarray.rb +88 -0
  81. data/lib/puppet/parser/ast/branch.rb +47 -0
  82. data/lib/puppet/parser/ast/caseopt.rb +66 -0
  83. data/lib/puppet/parser/ast/casestatement.rb +78 -0
  84. data/lib/puppet/parser/ast/classdef.rb +78 -0
  85. data/lib/puppet/parser/ast/compdef.rb +111 -0
  86. data/lib/puppet/parser/ast/component.rb +105 -0
  87. data/lib/puppet/parser/ast/hostclass.rb +82 -0
  88. data/lib/puppet/parser/ast/leaf.rb +86 -0
  89. data/lib/puppet/parser/ast/node.rb +103 -0
  90. data/lib/puppet/parser/ast/nodedef.rb +68 -0
  91. data/lib/puppet/parser/ast/objectdef.rb +336 -0
  92. data/lib/puppet/parser/ast/objectparam.rb +30 -0
  93. data/lib/puppet/parser/ast/objectref.rb +76 -0
  94. data/lib/puppet/parser/ast/selector.rb +60 -0
  95. data/lib/puppet/parser/ast/typedefaults.rb +45 -0
  96. data/lib/puppet/parser/ast/vardef.rb +44 -0
  97. data/lib/puppet/parser/interpreter.rb +31 -14
  98. data/lib/puppet/parser/lexer.rb +2 -4
  99. data/lib/puppet/parser/parser.rb +332 -242
  100. data/lib/puppet/parser/scope.rb +55 -38
  101. data/lib/puppet/server.rb +43 -44
  102. data/lib/puppet/server/authstore.rb +3 -6
  103. data/lib/puppet/server/ca.rb +5 -2
  104. data/lib/puppet/server/filebucket.rb +2 -4
  105. data/lib/puppet/server/fileserver.rb +28 -12
  106. data/lib/puppet/server/logger.rb +15 -4
  107. data/lib/puppet/server/master.rb +62 -7
  108. data/lib/puppet/sslcertificates.rb +41 -607
  109. data/lib/puppet/sslcertificates/ca.rb +291 -0
  110. data/lib/puppet/sslcertificates/certificate.rb +283 -0
  111. data/lib/puppet/statechange.rb +6 -1
  112. data/lib/puppet/storage.rb +67 -56
  113. data/lib/puppet/transaction.rb +25 -9
  114. data/lib/puppet/transportable.rb +102 -22
  115. data/lib/puppet/type.rb +1096 -315
  116. data/lib/puppet/type/component.rb +30 -21
  117. data/lib/puppet/type/cron.rb +409 -448
  118. data/lib/puppet/type/exec.rb +234 -174
  119. data/lib/puppet/type/group.rb +65 -82
  120. data/lib/puppet/type/nameservice.rb +247 -3
  121. data/lib/puppet/type/nameservice/netinfo.rb +29 -40
  122. data/lib/puppet/type/nameservice/objectadd.rb +52 -66
  123. data/lib/puppet/type/nameservice/posix.rb +6 -194
  124. data/lib/puppet/type/package.rb +447 -295
  125. data/lib/puppet/type/package/apt.rb +51 -50
  126. data/lib/puppet/type/package/bsd.rb +82 -0
  127. data/lib/puppet/type/package/dpkg.rb +85 -88
  128. data/lib/puppet/type/package/rpm.rb +67 -63
  129. data/lib/puppet/type/package/sun.rb +119 -98
  130. data/lib/puppet/type/package/yum.rb +41 -37
  131. data/lib/puppet/type/parsedtype.rb +295 -0
  132. data/lib/puppet/type/parsedtype/host.rb +143 -0
  133. data/lib/puppet/type/parsedtype/port.rb +232 -0
  134. data/lib/puppet/type/parsedtype/sshkey.rb +129 -0
  135. data/lib/puppet/type/pfile.rb +484 -460
  136. data/lib/puppet/type/pfile/checksum.rb +237 -181
  137. data/lib/puppet/type/pfile/content.rb +67 -0
  138. data/lib/puppet/type/pfile/ensure.rb +212 -0
  139. data/lib/puppet/type/pfile/group.rb +106 -105
  140. data/lib/puppet/type/pfile/mode.rb +98 -101
  141. data/lib/puppet/type/pfile/source.rb +228 -209
  142. data/lib/puppet/type/pfile/type.rb +18 -21
  143. data/lib/puppet/type/pfile/uid.rb +127 -130
  144. data/lib/puppet/type/pfilebucket.rb +68 -63
  145. data/lib/puppet/type/schedule.rb +341 -0
  146. data/lib/puppet/type/service.rb +351 -255
  147. data/lib/puppet/type/service/base.rb +9 -14
  148. data/lib/puppet/type/service/debian.rb +32 -38
  149. data/lib/puppet/type/service/init.rb +130 -130
  150. data/lib/puppet/type/service/smf.rb +48 -20
  151. data/lib/puppet/type/state.rb +229 -16
  152. data/lib/puppet/type/symlink.rb +51 -63
  153. data/lib/puppet/type/tidy.rb +105 -102
  154. data/lib/puppet/type/user.rb +118 -180
  155. data/lib/puppet/util.rb +100 -6
  156. data/test/certmgr/certmgr.rb +0 -1
  157. data/test/client/client.rb +4 -4
  158. data/test/executables/puppetbin.rb +7 -14
  159. data/test/executables/puppetca.rb +18 -24
  160. data/test/executables/puppetd.rb +7 -16
  161. data/test/executables/puppetmasterd.rb +7 -9
  162. data/test/executables/puppetmodule.rb +11 -16
  163. data/test/language/ast.rb +11 -7
  164. data/test/language/interpreter.rb +1 -1
  165. data/test/language/scope.rb +2 -0
  166. data/test/language/snippets.rb +30 -5
  167. data/test/language/transportable.rb +77 -0
  168. data/test/other/config.rb +316 -0
  169. data/test/other/events.rb +22 -21
  170. data/test/other/log.rb +14 -14
  171. data/test/other/metrics.rb +4 -8
  172. data/test/other/overrides.rb +5 -5
  173. data/test/other/relationships.rb +4 -2
  174. data/test/other/storage.rb +64 -3
  175. data/test/other/transactions.rb +20 -20
  176. data/test/parser/parser.rb +7 -4
  177. data/test/puppet/conffiles.rb +12 -12
  178. data/test/puppet/defaults.rb +13 -11
  179. data/test/puppet/utiltest.rb +14 -11
  180. data/test/puppettest.rb +156 -48
  181. data/test/server/bucket.rb +2 -2
  182. data/test/server/fileserver.rb +6 -6
  183. data/test/server/logger.rb +19 -11
  184. data/test/server/master.rb +33 -4
  185. data/test/server/server.rb +2 -7
  186. data/test/types/basic.rb +5 -7
  187. data/test/types/component.rb +22 -18
  188. data/test/types/cron.rb +111 -44
  189. data/test/types/exec.rb +116 -59
  190. data/test/types/file.rb +262 -137
  191. data/test/types/filebucket.rb +13 -15
  192. data/test/types/fileignoresource.rb +12 -16
  193. data/test/types/filesources.rb +73 -48
  194. data/test/types/filetype.rb +13 -15
  195. data/test/types/group.rb +15 -13
  196. data/test/types/host.rb +146 -0
  197. data/test/types/package.rb +74 -63
  198. data/test/types/port.rb +139 -0
  199. data/test/types/query.rb +8 -8
  200. data/test/types/schedule.rb +335 -0
  201. data/test/types/service.rb +137 -21
  202. data/test/types/sshkey.rb +140 -0
  203. data/test/types/symlink.rb +3 -5
  204. data/test/types/tidy.rb +5 -14
  205. data/test/types/type.rb +67 -11
  206. data/test/types/user.rb +25 -23
  207. metadata +186 -122
  208. data/lib/puppet/type/pfile/create.rb +0 -108
  209. data/lib/puppet/type/pprocess.rb +0 -97
  210. data/lib/puppet/type/typegen.rb +0 -149
  211. data/lib/puppet/type/typegen/filerecord.rb +0 -243
  212. data/lib/puppet/type/typegen/filetype.rb +0 -316
  213. data/test/other/state.rb +0 -106
@@ -0,0 +1,17 @@
1
+ class Puppet::Client::CAClient < Puppet::Client::ProxyClient
2
+ @drivername = :CA
3
+
4
+ # set up the appropriate interface methods
5
+ @handler = Puppet::Server::CA
6
+ self.mkmethods
7
+
8
+ def initialize(hash = {})
9
+ if hash.include?(:CA)
10
+ hash[:CA] = Puppet::Server::CA.new()
11
+ end
12
+
13
+ super(hash)
14
+ end
15
+ end
16
+
17
+ # $Id: ca.rb 848 2006-01-24 06:01:58Z luke $
@@ -0,0 +1,78 @@
1
+ module Puppet
2
+ class Client
3
+ # The client class for filebuckets.
4
+ class Dipper < Puppet::Client
5
+ @drivername = :Bucket
6
+
7
+ def initialize(hash = {})
8
+ if hash.include?(:Path)
9
+ bucket = Puppet::Server::FileBucket.new(
10
+ :Bucket => hash[:Path]
11
+ )
12
+ hash.delete(:Path)
13
+ hash[:Bucket] = bucket
14
+ end
15
+
16
+ super(hash)
17
+ end
18
+
19
+ def backup(file)
20
+ unless FileTest.exists?(file)
21
+ raise(BucketError, "File %s does not exist" % file, caller)
22
+ end
23
+ contents = File.open(file) { |of| of.read }
24
+
25
+ string = Base64.encode64(contents)
26
+ #puts "string is created"
27
+
28
+ sum = @driver.addfile(string,file)
29
+ #puts "file %s is added" % file
30
+ return sum
31
+ end
32
+
33
+ def restore(file,sum)
34
+ restore = true
35
+ if FileTest.exists?(file)
36
+ contents = File.open(file) { |of| of.read }
37
+
38
+ cursum = Digest::MD5.hexdigest(contents)
39
+
40
+ # if the checksum has changed...
41
+ # this might be extra effort
42
+ if cursum == sum
43
+ restore = false
44
+ end
45
+ end
46
+
47
+ if restore
48
+ #puts "Restoring %s" % file
49
+ if tmp = @driver.getfile(sum)
50
+ newcontents = Base64.decode64(tmp)
51
+ newsum = Digest::MD5.hexdigest(newcontents)
52
+ changed = nil
53
+ unless FileTest.writable?(file)
54
+ changed = File.stat(file).mode
55
+ File.chmod(changed | 0200, file)
56
+ end
57
+ File.open(file,File::WRONLY|File::TRUNC) { |of|
58
+ of.print(newcontents)
59
+ }
60
+ if changed
61
+ File.chmod(changed, file)
62
+ end
63
+ else
64
+ Puppet.err "Could not find file with checksum %s" % sum
65
+ return nil
66
+ end
67
+ #puts "Done"
68
+ return newsum
69
+ else
70
+ return nil
71
+ end
72
+
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ # $Id: dipper.rb 848 2006-01-24 06:01:58Z luke $
@@ -0,0 +1,20 @@
1
+ class Puppet::Client::FileClient < Puppet::Client::ProxyClient
2
+ @drivername = :FileServer
3
+
4
+ # set up the appropriate interface methods
5
+ @handler = Puppet::Server::FileServer
6
+
7
+ self.mkmethods
8
+
9
+ def initialize(hash = {})
10
+ if hash.include?(:FileServer)
11
+ unless hash[:FileServer].is_a?(Puppet::Server::FileServer)
12
+ raise Puppet::DevError, "Must pass an actual FS object"
13
+ end
14
+ end
15
+
16
+ super(hash)
17
+ end
18
+ end
19
+
20
+ # $Id: file.rb 848 2006-01-24 06:01:58Z luke $
@@ -0,0 +1,17 @@
1
+ class Puppet::Client::LogClient < Puppet::Client::ProxyClient
2
+ @drivername = :Logger
3
+
4
+ # set up the appropriate interface methods
5
+ @handler = Puppet::Server::Logger
6
+ self.mkmethods
7
+
8
+ def initialize(hash = {})
9
+ if hash.include?(:Logger)
10
+ hash[:Logger] = Puppet::Server::Logger.new()
11
+ end
12
+
13
+ super(hash)
14
+ end
15
+ end
16
+
17
+ # $Id: log.rb 848 2006-01-24 06:01:58Z luke $
@@ -0,0 +1,246 @@
1
+ # The client for interacting with the puppetmaster config server.
2
+ class Puppet::Client::MasterClient < Puppet::Client
3
+ @drivername = :Master
4
+
5
+ def self.facts
6
+ facts = {}
7
+ Facter.each { |name,fact|
8
+ facts[name] = fact.downcase
9
+ }
10
+
11
+ facts
12
+ end
13
+
14
+ # This method is how the client receives the tree of Transportable
15
+ # objects. For now, just descend into the tree and perform and
16
+ # necessary manipulations.
17
+ def apply
18
+ Puppet.notice "Beginning configuration run"
19
+ dostorage()
20
+ unless defined? @objects
21
+ raise Puppet::Error, "Cannot apply; objects not defined"
22
+ end
23
+
24
+ #Puppet.err :yay
25
+ #p @objects
26
+ #Puppet.err :mark
27
+ #@objects = @objects.to_type
28
+ # this is a gross hack... but i don't see a good way around it
29
+ # set all of the variables to empty
30
+ Puppet::Transaction.init
31
+
32
+ # For now we just evaluate the top-level object, but eventually
33
+ # there will be schedules and such associated with each object,
34
+ # and probably with the container itself.
35
+ transaction = @objects.evaluate
36
+ #transaction = Puppet::Transaction.new(objects)
37
+ transaction.toplevel = true
38
+ begin
39
+ transaction.evaluate
40
+ rescue Puppet::Error => detail
41
+ Puppet.err "Could not apply complete configuration: %s" %
42
+ detail
43
+ rescue => detail
44
+ Puppet.err "Found a bug: %s" % detail
45
+ if Puppet[:debug]
46
+ puts detail.backtrace
47
+ end
48
+ ensure
49
+ Puppet::Storage.store
50
+ end
51
+ Puppet::Metric.gather
52
+ Puppet::Metric.tally
53
+ if Puppet[:rrdgraph] == true
54
+ Metric.store
55
+ Metric.graph
56
+ end
57
+ Puppet.notice "Finished configuration run"
58
+
59
+ return transaction
60
+ end
61
+
62
+ # Cache the config
63
+ def cache(text)
64
+ Puppet.info "Caching configuration at %s" % self.cachefile
65
+ confdir = File.dirname(Puppet[:localconfig])
66
+ unless FileTest.exists?(confdir)
67
+ Puppet.recmkdir(confdir, 0770)
68
+ end
69
+ File.open(self.cachefile + ".tmp", "w", 0660) { |f|
70
+ f.print text
71
+ }
72
+ File.rename(self.cachefile + ".tmp", self.cachefile)
73
+ end
74
+
75
+ def cachefile
76
+ unless defined? @cachefile
77
+ @cachefile = Puppet[:localconfig] + ".yaml"
78
+ end
79
+ @cachefile
80
+ end
81
+
82
+ # Initialize and load storage
83
+ def dostorage
84
+ begin
85
+ Puppet::Storage.init
86
+ Puppet::Storage.load
87
+ rescue => detail
88
+ Puppet.err "Corrupt state file %s: %s" % [Puppet[:statefile], detail]
89
+ begin
90
+ File.unlink(Puppet[:statefile])
91
+ retry
92
+ rescue => detail
93
+ raise Puppet::Error.new("Cannot remove %s: %s" %
94
+ [Puppet[statefile], detail])
95
+ end
96
+ end
97
+ end
98
+
99
+ # Check whether our configuration is up to date
100
+ def fresh?
101
+ unless defined? @configstamp
102
+ return false
103
+ end
104
+
105
+ # We're willing to give a 2 second drift
106
+ if @driver.freshness - @configstamp < 1
107
+ return true
108
+ else
109
+ return false
110
+ end
111
+ end
112
+
113
+ # Retrieve the config from a remote server. If this fails, then
114
+ # use the cached copy.
115
+ def getconfig
116
+ if self.fresh?
117
+ Puppet.info "Config is up to date"
118
+ return
119
+ end
120
+ Puppet.debug("getting config")
121
+ dostorage()
122
+
123
+ facts = self.class.facts
124
+
125
+ unless facts.length > 0
126
+ raise Puppet::ClientError.new(
127
+ "Could not retrieve any facts"
128
+ )
129
+ end
130
+
131
+ objects = nil
132
+ if @local
133
+ # If we're local, we don't have to do any of the conversion
134
+ # stuff.
135
+ objects = @driver.getconfig(facts, "yaml")
136
+ @configstamp = Time.now.to_i
137
+
138
+ if objects == ""
139
+ raise Puppet::Error, "Could not retrieve configuration"
140
+ end
141
+ else
142
+ textobjects = ""
143
+
144
+ textfacts = CGI.escape(YAML.dump(facts))
145
+
146
+ # error handling for this is done in the network client
147
+ begin
148
+ textobjects = @driver.getconfig(textfacts, "yaml")
149
+ rescue => detail
150
+ Puppet.err "Could not retrieve configuration: %s" % detail
151
+ end
152
+
153
+ fromcache = false
154
+ if textobjects == ""
155
+ textobjects = self.retrievecache
156
+ if textobjects == ""
157
+ raise Puppet::Error.new(
158
+ "Cannot connect to server and there is no cached configuration"
159
+ )
160
+ end
161
+ Puppet.notice "Could not get config; using cached copy"
162
+ fromcache = true
163
+ end
164
+
165
+ begin
166
+ textobjects = CGI.unescape(textobjects)
167
+ @configstamp = Time.now.to_i
168
+ rescue => detail
169
+ raise Puppet::Error, "Could not CGI.unescape configuration"
170
+ end
171
+
172
+ if @cache and ! fromcache
173
+ self.cache(textobjects)
174
+ end
175
+
176
+ begin
177
+ objects = YAML.load(textobjects)
178
+ rescue => detail
179
+ raise Puppet::Error,
180
+ "Could not understand configuration: %s" %
181
+ detail.to_s
182
+ end
183
+ end
184
+
185
+ unless objects.is_a?(Puppet::TransBucket)
186
+ raise NetworkClientError,
187
+ "Invalid returned objects of type %s" % objects.class
188
+ end
189
+
190
+ if classes = objects.classes
191
+ self.setclasses(classes)
192
+ else
193
+ Puppet.info "No classes to store"
194
+ end
195
+
196
+ # Clear all existing objects, so we can recreate our stack.
197
+ if defined? @objects
198
+ Puppet::Type.allclear
199
+ end
200
+ @objects = nil
201
+
202
+ # First create the default scheduling objects
203
+ Puppet.type(:schedule).mkdefaultschedules
204
+
205
+ # Now convert the objects to real Puppet objects
206
+ @objects = objects.to_type
207
+
208
+ if @objects.nil?
209
+ raise Puppet::Error, "Configuration could not be processed"
210
+ end
211
+ #@objects = objects
212
+
213
+ # and perform any necessary final actions before we evaluate.
214
+ Puppet::Type.finalize
215
+
216
+ return @objects
217
+ end
218
+
219
+ # Retrieve the cached config
220
+ def retrievecache
221
+ if FileTest.exists?(self.cachefile)
222
+ return File.read(self.cachefile)
223
+ else
224
+ return ""
225
+ end
226
+ end
227
+
228
+ # The code that actually runs the configuration.
229
+ def run
230
+ self.getconfig
231
+ self.apply
232
+ end
233
+
234
+ def setclasses(ary)
235
+ begin
236
+ File.open(Puppet[:classfile], "w") { |f|
237
+ f.puts ary.join("\n")
238
+ }
239
+ rescue => detail
240
+ Puppet.err "Could not create class file %s: %s" %
241
+ [Puppet[:classfile], detail]
242
+ end
243
+ end
244
+ end
245
+
246
+ # $Id: master.rb 872 2006-02-07 17:07:15Z luke $
@@ -0,0 +1,27 @@
1
+ # unlike the other client classes (again, this design sucks) this class
2
+ # is basically just a proxy class -- it calls its methods on the driver
3
+ # and that's about it
4
+ class Puppet::Client::ProxyClient < Puppet::Client
5
+ def self.mkmethods
6
+ interface = @handler.interface
7
+ namespace = interface.prefix
8
+
9
+ interface.methods.each { |ary|
10
+ method = ary[0]
11
+ Puppet.debug "%s: defining %s.%s" % [self, namespace, method]
12
+ self.send(:define_method,method) { |*args|
13
+ begin
14
+ @driver.send(method, *args)
15
+ rescue XMLRPC::FaultException => detail
16
+ #Puppet.err "Could not call %s.%s: %s" %
17
+ # [namespace, method, detail.faultString]
18
+ #raise NetworkClientError,
19
+ # "XMLRPC Error: %s" % detail.faultString
20
+ raise NetworkClientError, detail.faultString
21
+ end
22
+ }
23
+ }
24
+ end
25
+ end
26
+
27
+ # $Id: proxy.rb 848 2006-01-24 06:01:58Z luke $
@@ -0,0 +1,7 @@
1
+ class Puppet::Client::StatusClient < Puppet::Client::ProxyClient
2
+ # set up the appropriate interface methods
3
+ @handler = Puppet::Server::ServerStatus
4
+ self.mkmethods
5
+ end
6
+
7
+ # $Id: status.rb 848 2006-01-24 06:01:58Z luke $
@@ -1,17 +1,183 @@
1
- module Puppet # :nodoc:
1
+ module Puppet
2
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] = {}
3
+ class Config
4
+ include Enumerable
5
+
6
+ # Retrieve a config value
7
+ def [](param)
8
+ param = convert(param)
9
+ if @config.include?(param)
10
+ if @config[param]
11
+ val = @config[param].value
12
+ return val
13
+ end
14
+ else
15
+ raise ArgumentError, "Invalid argument %s" % param
16
+ end
17
+ end
18
+
19
+ # Set a config value. This doesn't set the defaults, it sets the value itself.
20
+ def []=(param, value)
21
+ param = convert(param)
22
+ unless @config.include?(param)
23
+ raise Puppet::Error, "Unknown configuration parameter %s" % param.inspect
24
+ end
25
+ unless @order.include?(param)
26
+ @order << param
27
+ end
28
+ @config[param].value = value
29
+ end
30
+
31
+ # A simplified equality operator.
32
+ def ==(other)
33
+ self.each { |myname, myobj|
34
+ unless other[myname] == myobj.value
35
+ return false
36
+ end
37
+ }
38
+
39
+ return true
40
+ end
41
+
42
+ # Generate the list of valid arguments, in a format that GetoptLong can
43
+ # understand, and add them to the passed option list.
44
+ def addargs(options)
45
+ require 'getoptlong'
46
+ # Add all of the config parameters as valid options.
47
+ self.each { |param, obj|
48
+ if self.boolean?(param)
49
+ options << ["--#{param}", GetoptLong::NO_ARGUMENT]
50
+ options << ["--no-#{param}", GetoptLong::NO_ARGUMENT]
51
+ else
52
+ options << ["--#{param}", GetoptLong::REQUIRED_ARGUMENT]
53
+ end
54
+ }
55
+
56
+ return options
57
+ end
58
+
59
+ # Turn the config into a transaction and apply it
60
+ def apply
61
+ trans = self.to_transportable
62
+ begin
63
+ comp = trans.to_type
64
+ trans = comp.evaluate
65
+ trans.evaluate
66
+ comp.remove
67
+ rescue => detail
68
+ puts detail.backtrace
69
+ Puppet.err "Could not configure myself: %s" % detail
9
70
  end
10
- super
11
71
  end
12
72
 
13
- def initialize(file)
73
+ # Is our parameter a boolean parameter?
74
+ def boolean?(param)
75
+ param = convert(param)
76
+ if @config.include?(param) and @config[param].kind_of? CBoolean
77
+ return true
78
+ else
79
+ return false
80
+ end
81
+ end
82
+
83
+ # Remove all set values.
84
+ def clear
85
+ @config.each { |name, obj|
86
+ obj.clear
87
+ }
88
+ end
89
+
90
+ def convert(param)
91
+ case param
92
+ when String: return param.intern
93
+ when Symbol: return param
94
+ else
95
+ raise ArgumentError, "Invalid param type %s" % param.class
96
+ end
97
+ end
98
+
99
+ def each
100
+ @order.each { |name|
101
+ if @config.include?(name)
102
+ yield name, @config[name]
103
+ else
104
+ raise Puppet::DevError, "%s is in the order but does not exist" % name
105
+ end
106
+ }
107
+ end
108
+
109
+ # Iterate over each section name.
110
+ def eachsection
111
+ yielded = []
112
+ @order.each { |name|
113
+ if @config.include?(name)
114
+ section = @config[name].section
115
+ unless yielded.include? section
116
+ yield section
117
+ yielded << section
118
+ end
119
+ else
120
+ raise Puppet::DevError, "%s is in the order but does not exist" % name
121
+ end
122
+ }
123
+ end
124
+
125
+ # Return an object by name.
126
+ def element(param)
127
+ param = convert(param)
128
+ @config[param]
129
+ end
130
+
131
+ # Handle a command-line argument.
132
+ def handlearg(opt, value = nil)
133
+ if value == "true"
134
+ value = true
135
+ end
136
+ if value == "false"
137
+ value = false
138
+ end
139
+ str = opt.sub(/^--/,'')
140
+ bool = true
141
+ newstr = str.sub(/^no-/, '')
142
+ if newstr != str
143
+ str = newstr
144
+ bool = false
145
+ end
146
+ if self.valid?(str)
147
+ if self.boolean?(str)
148
+ self[str] = bool
149
+ else
150
+ self[str] = value
151
+ end
152
+
153
+ # Mark that this was set on the cli, so it's not overridden if the config
154
+ # gets reread.
155
+ @config[str.intern].setbycli = true
156
+ else
157
+ raise ArgumentError, "Invalid argument %s" % opt
158
+ end
159
+ end
160
+
161
+ # Create a new config object
162
+ def initialize
163
+ @order = []
164
+ @config = {}
165
+ end
166
+
167
+ # Return all of the parameters associated with a given section.
168
+ def params(section)
169
+ section = section.intern if section.is_a? String
170
+ @config.find_all { |name, obj|
171
+ obj.section == section
172
+ }.collect { |name, obj|
173
+ name
174
+ }
175
+ end
176
+
177
+ # Parse a configuration file.
178
+ def parse(file)
14
179
  text = nil
180
+ @file = file
15
181
 
16
182
  begin
17
183
  text = File.read(file)
@@ -29,21 +195,405 @@ class Config < Hash
29
195
  }
30
196
 
31
197
  section = "puppet"
198
+ metas = %w{owner group mode}
199
+ values = Hash.new { |hash, key| hash[key] = {} }
32
200
  text.split(/\n/).each { |line|
33
201
  case line
34
202
  when /^\[(\w+)\]$/: section = $1 # Section names
35
203
  when /^\s*#/: next # Skip comments
36
204
  when /^\s*$/: next # Skip blanks
37
- when /^\s*(\w+)\s+(.+)$/: # settings
38
- var = $1
205
+ when /^\s*(\w+)\s*=\s*(.+)$/: # settings
206
+ var = $1.intern
39
207
  value = $2
40
- self[section][var] = value
208
+
209
+ # Mmm, "special" attributes
210
+ if metas.include?(var.to_s)
211
+ unless values.include?(section)
212
+ values[section] = {}
213
+ end
214
+ values[section][var.to_s] = value
215
+ next
216
+ end
217
+
218
+ # Don't override set parameters, since the file is parsed
219
+ # after cli arguments are handled.
220
+ unless @config.include?(var) and @config[var].setbycli
221
+ Puppet.debug "%s: Setting %s to '%s'" % [section, var, value]
222
+ self[var] = value
223
+ end
224
+ @config[var].section = section
225
+
226
+ metas.each { |meta|
227
+ if values[section][meta]
228
+ if @config[var].respond_to?(meta + "=")
229
+ @config[var].send(meta + "=", values[section][meta])
230
+ end
231
+ end
232
+ }
41
233
  else
42
234
  raise Puppet::Error, "Could not match line %s" % line
43
235
  end
44
236
  }
45
237
  end
238
+
239
+ # Create a new element. The value is passed in because it's used to determine
240
+ # what kind of element we're creating, but the value itself might be either
241
+ # a default or a value, so we can't actually assign it.
242
+ def newelement(param, desc, value)
243
+ param = convert(param)
244
+ mod = nil
245
+ case value
246
+ when true, false, "true", "false":
247
+ mod = CBoolean
248
+ when /^\$/, /^\//:
249
+ mod = CFile
250
+ when String, Integer, Float: # nothing
251
+ else
252
+ raise Puppet::Error, "Invalid value '%s' for %s" % [value, param]
253
+ end
254
+ element = CElement.new(param, desc)
255
+ element.parent = self
256
+ if mod
257
+ element.extend(mod)
258
+ end
259
+
260
+ @order << param
261
+
262
+ return element
263
+ end
264
+
265
+ # Iterate across all of the objects in a given section.
266
+ def persection(section)
267
+ self.each { |name, obj|
268
+ if obj.section == section
269
+ yield obj
270
+ end
271
+ }
272
+ end
273
+
274
+ # Get a list of objects per section
275
+ def sectionlist
276
+ sectionlist = []
277
+ self.each { |name, obj|
278
+ section = obj.section || "puppet"
279
+ sections[section] ||= []
280
+ unless sectionlist.include?(section)
281
+ sectionlist << section
282
+ end
283
+ sections[section] << obj
284
+ }
285
+
286
+ return sectionlist, sections
287
+ end
288
+
289
+ # Convert a single section into transportable objects.
290
+ def section_to_transportable(section, done)
291
+ objects = []
292
+ persection(section) { |obj|
293
+ [:owner, :group].each { |type|
294
+ if obj.respond_to? type and val = obj.send(type)
295
+ # Skip owners and groups we've already done, but tag them with
296
+ # our section if necessary
297
+ if done[type].include?(val)
298
+ next unless defined? @section and @section
299
+
300
+ tags = done[type][val].tags
301
+ unless tags.include?(@section)
302
+ done[type][val].tags = tags << @section
303
+ end
304
+ else
305
+ newobj = TransObject.new(val, type.to_s)
306
+ newobj[:ensure] = "exists"
307
+ done[type] << newobj
308
+ end
309
+ end
310
+ }
311
+
312
+ if obj.respond_to? :to_transportable
313
+ unless done[:file].include? obj.value
314
+ trans = obj.to_transportable
315
+ # transportable could return nil
316
+ next unless trans
317
+ objects << trans
318
+ done[:file] << obj.value
319
+ end
320
+ end
321
+ }
322
+
323
+ bucket = Puppet::TransBucket.new
324
+ bucket.autoname = true
325
+ bucket.name = "autosection-%s" % bucket.object_id
326
+ bucket.type = section
327
+ bucket.push(*objects)
328
+ bucket.keyword = "class"
329
+
330
+ return bucket
331
+ end
332
+
333
+ # Set a bunch of defaults in a given section. The sections are actually pretty
334
+ # pointless, but they help break things up a bit, anyway.
335
+ def setdefaults(section, *defs)
336
+ section = section.intern unless section.is_a? Symbol
337
+ #hash.each { |param, value|
338
+ defs.each { |param, value, desc|
339
+ param = convert(param)
340
+ if @config.include?(param) and @config[param].default
341
+ raise Puppet::Error, "Default %s is already defined" % param
342
+ end
343
+ unless @config.include?(param)
344
+ @config[param] = newelement(param, desc, value)
345
+ end
346
+ @config[param].default = value
347
+ @config[param].section = section
348
+ }
349
+ end
350
+
351
+ # Convert our list of objects into a component that can be applied.
352
+ def to_component
353
+ transport = self.to_transportable
354
+ return transport.to_type
355
+ end
356
+
357
+ # Convert our list of objects into a configuration file.
358
+ def to_config
359
+ str = %{The configuration file for #{Puppet.name}. Note that this file
360
+ is likely to have unused configuration parameters in it; any parameter that's
361
+ valid anywhere in Puppet can be in any config file, even if it's not used.
362
+
363
+ Every section can specify three special parameters: owner, group, and mode.
364
+ These parameters affect the required permissions of any files specified after
365
+ their specification. Puppet will sometimes use these parameters to check its
366
+ own configured state, so they can be used to make Puppet a bit more self-managing.
367
+
368
+ Note also that the section names are entirely for human-level organizational
369
+ purposes; they don't provide separate namespaces. All parameters are in a
370
+ single namespace.
371
+
372
+ Generated on #{Time.now}.
373
+
374
+ }.gsub(/^/, "# ")
375
+
376
+ eachsection do |section|
377
+ str += "[#{section}]\n"
378
+ persection(section) do |obj|
379
+ str += obj.to_config + "\n"
380
+ end
381
+ end
382
+
383
+ return str
384
+ end
385
+
386
+ # Convert our configuration into a list of transportable objects.
387
+ def to_transportable
388
+ done = {
389
+ :owner => [],
390
+ :group => [],
391
+ :file => []
392
+ }
393
+
394
+ topbucket = Puppet::TransBucket.new
395
+ if defined? @file and @file
396
+ topbucket.name = @file
397
+ else
398
+ topbucket.name = "configtop"
399
+ end
400
+ topbucket.type = "puppetconfig"
401
+ topbucket.top = true
402
+ topbucket.autoname = true
403
+
404
+ # Now iterate over each section
405
+ eachsection do |section|
406
+ topbucket.push section_to_transportable(section, done)
407
+ end
408
+
409
+ topbucket
410
+ end
411
+
412
+ # Convert to a parseable manifest
413
+ def to_manifest
414
+ transport = self.to_transportable
415
+
416
+ manifest = transport.to_manifest + "\n"
417
+ eachsection { |section|
418
+ manifest += "include #{section}\n"
419
+ }
420
+
421
+ return manifest
422
+ end
423
+
424
+ def valid?(param)
425
+ param = convert(param)
426
+ @config.has_key?(param)
427
+ end
428
+
429
+ # The base element type.
430
+ class CElement
431
+ attr_accessor :name, :section, :default, :parent, :desc, :setbycli
432
+
433
+ # Unset any set value.
434
+ def clear
435
+ @value = nil
436
+ end
437
+
438
+ # Create the new element. Pretty much just sets the name.
439
+ def initialize(name, desc, value = nil)
440
+ @name = name
441
+ @desc = desc.gsub(/^\s*/, '')
442
+ if value
443
+ @value = value
444
+ end
445
+ end
446
+
447
+ def set?
448
+ if defined? @value and ! @value.nil?
449
+ return true
450
+ else
451
+ return false
452
+ end
453
+ end
454
+
455
+ # Convert the object to a config statement.
456
+ def to_config
457
+ str = @desc.gsub(/^/, "# ") + "\n"
458
+
459
+ # Add in a statement about the default.
460
+ if defined? @default and @default
461
+ str += "# The default value is '%s'.\n" % @default
462
+ end
463
+
464
+ line = "%s = %s" % [@name, self.value]
465
+
466
+ # If the value has not been overridden, then print it out commented
467
+ # and unconverted, so it's clear that that's the default and how it
468
+ # works.
469
+ if defined? @value and ! @value.nil?
470
+ line = "%s = %s" % [@name, self.value]
471
+ else
472
+ line = "# %s = %s" % [@name, @default]
473
+ end
474
+
475
+ str += line + "\n"
476
+
477
+ str.gsub(/^/, " ")
478
+ end
479
+
480
+ # Retrieves the value, or if it's not set, retrieves the default.
481
+ def value
482
+ retval = nil
483
+ if defined? @value and ! @value.nil?
484
+ retval = @value
485
+ elsif defined? @default
486
+ retval = @default
487
+ else
488
+ return nil
489
+ end
490
+
491
+ if respond_to?(:convert)
492
+ return convert(retval)
493
+ else
494
+ return retval
495
+ end
496
+ end
497
+
498
+ # Set the value.
499
+ def value=(value)
500
+ if respond_to?(:validate)
501
+ validate(value)
502
+ end
503
+ if respond_to?(:munge)
504
+ @value = munge(value)
505
+ else
506
+ @value = value
507
+ end
508
+ end
509
+ end
510
+
511
+ # A file.
512
+ module CFile
513
+ attr_accessor :owner, :group, :mode
514
+
515
+ def convert(value)
516
+ return value unless value
517
+ return value unless value.is_a? String
518
+ if value =~ /\$(\w+)/
519
+ parent = $1
520
+ if pval = @parent[parent]
521
+ newval = value.sub(/\$#{parent}/, pval)
522
+ return File.join(newval.split("/"))
523
+ else
524
+ raise Puppet::DevError, "Could not find value for %s" % parent
525
+ end
526
+ else
527
+ return value
528
+ end
529
+ end
530
+
531
+ # Set the type appropriately. Yep, a hack. This supports either naming
532
+ # the variable 'dir', or adding a slash at the end.
533
+ def munge(value)
534
+ if value.to_s =~ /\/$/
535
+ @type = :directory
536
+ return value.sub(/\/$/, '')
537
+ end
538
+ return value
539
+ end
540
+
541
+ # Return the appropriate type.
542
+ def type
543
+ value = self.value
544
+ if @name.to_s =~ /dir/
545
+ return :directory
546
+ elsif value.to_s =~ /\/$/
547
+ return :directory
548
+ elsif value.is_a? String
549
+ return :file
550
+ else
551
+ return nil
552
+ end
553
+ end
554
+
555
+ # Convert the object to a TransObject instance.
556
+ def to_transportable
557
+ type = self.type
558
+ return nil unless type
559
+ obj = Puppet::TransObject.new(self.value, "file")
560
+ obj[:ensure] = type
561
+ [:owner, :group, :mode].each { |var|
562
+ if value = self.send(var)
563
+ obj[var] = value
564
+ end
565
+ }
566
+ if self.section
567
+ obj.tags = ["puppet", "configuration", self.section]
568
+ end
569
+ obj
570
+ end
571
+
572
+ # Make sure any provided variables look up to something.
573
+ def validate(value)
574
+ return true unless value.is_a? String
575
+ value.scan(/\$(\w+)/) { |name|
576
+ name = name[0]
577
+ unless @parent[name]
578
+ raise Puppet::Error, "'%s' is unset" % name
579
+ end
580
+ }
581
+ end
582
+ end
583
+
584
+ # A simple boolean.
585
+ module CBoolean
586
+ def munge(value)
587
+ case value
588
+ when true, "true": return true
589
+ when false, "false": return false
590
+ else
591
+ raise Puppet::Error, "Invalid value '%s' for %s" %
592
+ [value.inspect, @name]
593
+ end
594
+ end
595
+ end
46
596
  end
47
597
  end
48
598
 
49
- # $Id: config.rb 738 2005-10-31 22:50:09Z luke $
599
+ # $Id: config.rb 873 2006-02-07 23:12:33Z luke $