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
@@ -1,5 +1,7 @@
1
+ require 'yaml'
2
+
1
3
  module Puppet
2
- class Server # :nodoc:
4
+ class Server
3
5
  class LoggerError < RuntimeError; end
4
6
 
5
7
  # Receive logs from remote hosts.
@@ -10,18 +12,27 @@ class Server # :nodoc:
10
12
 
11
13
  # accept a log message from a client, and route it accordingly
12
14
  def addlog(message, client = nil, clientip = nil)
15
+ unless message
16
+ raise Puppet::DevError, "Did not receive message"
17
+ end
18
+
19
+ Puppet.info message.inspect
13
20
  # if the client is set, then we're not local
14
21
  if client
15
22
  begin
16
- message = Marshal::load(CGI.unescape(message))
23
+ message = YAML.load(CGI.unescape(message))
17
24
  #message = message
18
25
  rescue => detail
19
26
  raise XMLRPC::FaultException.new(
20
- 1, "Could not unMarshal log message from %s" % client
27
+ 1, "Could not unYAML log message from %s" % client
21
28
  )
22
29
  end
23
30
  end
24
31
 
32
+ unless message
33
+ raise Puppet::DevError, "Could not resurrect message"
34
+ end
35
+
25
36
  # Mark it as remote, so it's not sent to syslog
26
37
  message.remote = true
27
38
 
@@ -40,4 +51,4 @@ class Server # :nodoc:
40
51
  end
41
52
  end
42
53
 
43
- # $Id: logger.rb 733 2005-10-28 21:28:59Z luke $
54
+ # $Id: logger.rb 846 2006-01-20 20:38:01Z luke $
@@ -3,6 +3,7 @@ require 'puppet'
3
3
  require 'puppet/parser/interpreter'
4
4
  require 'puppet/sslcertificates'
5
5
  require 'xmlrpc/server'
6
+ require 'yaml'
6
7
 
7
8
  module Puppet
8
9
  class Server
@@ -13,8 +14,26 @@ class Server
13
14
 
14
15
  @interface = XMLRPC::Service::Interface.new("puppetmaster") { |iface|
15
16
  iface.add_method("string getconfig(string)")
17
+ iface.add_method("int freshness()")
16
18
  }
17
19
 
20
+ def filetimeout
21
+ @interpreter.filetimeout
22
+ end
23
+
24
+ def filetimeout=(int)
25
+ @interpreter.filetimeout = int
26
+ end
27
+
28
+ # Tell a client whether there's a fresh config for it
29
+ def freshness(client = nil, clientip = nil)
30
+ if defined? @interpreter
31
+ return @interpreter.parsedate
32
+ else
33
+ return 0
34
+ end
35
+ end
36
+
18
37
  def initialize(hash = {})
19
38
 
20
39
  # FIXME this should all be s/:File/:Manifest/g or something
@@ -34,9 +53,11 @@ class Server
34
53
  @ca = nil
35
54
  end
36
55
 
56
+ @parsecheck = hash[:FileTimeout] || 15
57
+
37
58
  Puppet.debug("Creating interpreter")
38
59
 
39
- args = {:Manifest => @file}
60
+ args = {:Manifest => @file, :ParseCheck => @parsecheck}
40
61
 
41
62
  if hash.include?(:UseNodes)
42
63
  args[:UseNodes] = hash[:UseNodes]
@@ -57,7 +78,7 @@ class Server
57
78
  end
58
79
  end
59
80
 
60
- def getconfig(facts, client = nil, clientip = nil)
81
+ def getconfig(facts, format = "marshal", client = nil, clientip = nil)
61
82
  if @local
62
83
  # we don't need to do anything, since we should already
63
84
  # have raw objects
@@ -66,11 +87,26 @@ class Server
66
87
  Puppet.debug "Our client is remote"
67
88
 
68
89
  # XXX this should definitely be done in the protocol, somehow
69
- begin
70
- facts = Marshal::load(CGI.unescape(facts))
71
- rescue => detail
90
+ case format
91
+ when "marshal":
92
+ begin
93
+ facts = Marshal::load(CGI.unescape(facts))
94
+ rescue => detail
95
+ raise XMLRPC::FaultException.new(
96
+ 1, "Could not rebuild facts"
97
+ )
98
+ end
99
+ when "yaml":
100
+ begin
101
+ facts = YAML.load(CGI.unescape(facts))
102
+ rescue => detail
103
+ raise XMLRPC::FaultException.new(
104
+ 1, "Could not rebuild facts"
105
+ )
106
+ end
107
+ else
72
108
  raise XMLRPC::FaultException.new(
73
- 1, "Could not rebuild facts"
109
+ 1, "Unavailable config format %s" % format
74
110
  )
75
111
  end
76
112
  end
@@ -95,7 +131,26 @@ class Server
95
131
  if @local
96
132
  return retobjects
97
133
  else
98
- return CGI.escape(Marshal::dump(retobjects))
134
+ str = nil
135
+ case format
136
+ when "marshal":
137
+ str = Marshal::dump(retobjects)
138
+ when "yaml":
139
+ str = YAML.dump(retobjects)
140
+ else
141
+ raise XMLRPC::FaultException.new(
142
+ 1, "Unavailable config format %s" % format
143
+ )
144
+ end
145
+ return CGI.escape(str)
146
+ end
147
+ end
148
+
149
+ def local?
150
+ if defined? @local and @local
151
+ return true
152
+ else
153
+ return false
99
154
  end
100
155
  end
101
156
  end
@@ -1,46 +1,44 @@
1
- #!/usr/bin/ruby -w
2
-
3
- #--------------------
4
- # the puppet client
5
- #
6
- # $Id: sslcertificates.rb 720 2005-10-21 06:16:43Z luke $
7
-
1
+ # The library for manipulating SSL certs.
8
2
 
9
3
  require 'puppet'
10
- require 'openssl'
11
-
12
- module Puppet
13
- module SSLCertificates
14
- def self.mkdir(dir)
15
- # this is all a bunch of stupid hackery
16
- unless FileTest.exists?(dir)
17
- comp = Puppet::Type::Component.create(
18
- :name => "certdir creation"
19
- )
20
- path = ['']
21
-
22
- dir.split(File::SEPARATOR).each { |d|
23
- path << d
24
- if FileTest.exists?(File.join(path))
25
- unless FileTest.directory?(File.join(path))
26
- raise "%s exists but is not a directory" % File.join(path)
27
- end
28
- else
29
- obj = Puppet::Type.type(:file).create(
30
- :name => File.join(path),
31
- :mode => "750",
32
- :create => "directory"
33
- )
34
4
 
35
- comp.push obj
36
- end
37
- }
38
- trans = comp.evaluate
39
- trans.evaluate
40
- end
5
+ begin
6
+ require 'openssl'
7
+ rescue LoadError
8
+ raise Puppet::Error, "You must have the Ruby openssl library installed"
9
+ end
41
10
 
42
- Puppet::Type.allclear
43
- end
11
+ module Puppet::SSLCertificates
12
+ # def self.mkdir(dir)
13
+ # # this is all a bunch of stupid hackery
14
+ # unless FileTest.exists?(dir)
15
+ # comp = Puppet.type(:component).create(
16
+ # :name => "certdir creation"
17
+ # )
18
+ # path = ['']
19
+ #
20
+ # dir.split(File::SEPARATOR).each { |d|
21
+ # path << d
22
+ # if FileTest.exists?(File.join(path))
23
+ # unless FileTest.directory?(File.join(path))
24
+ # raise "%s exists but is not a directory" % File.join(path)
25
+ # end
26
+ # else
27
+ # obj = Puppet::Type.type(:file).create(
28
+ # :name => File.join(path),
29
+ # :mode => "750",
30
+ # :ensure => "directory"
31
+ # )
32
+ #
33
+ # comp.push obj
34
+ # end
35
+ # }
36
+ # trans = comp.evaluate
37
+ # trans.evaluate
38
+ # end
39
+ #
40
+ # Puppet::Type.allclear
41
+ # end
44
42
 
45
43
  #def self.mkcert(type, name, days, issuercert, issuername, serial, publickey)
46
44
  def self.mkcert(hash)
@@ -166,572 +164,8 @@ module SSLCertificates
166
164
 
167
165
  return hashpath
168
166
  end
169
-
170
-
171
-
172
- class CA
173
- attr_accessor :keyfile, :file, :config, :dir, :cert
174
-
175
- @@params = [
176
- :certdir,
177
- :publickeydir,
178
- :privatekeydir,
179
- :cadir,
180
- :cakey,
181
- :cacert,
182
- :capass,
183
- :capub,
184
- :csrdir,
185
- :signeddir,
186
- :serial,
187
- :privatedir,
188
- :ca_crl_days,
189
- :ca_days,
190
- :ca_md,
191
- :req_bits,
192
- :keylength,
193
- :autosign
194
- ]
195
-
196
- @@defaults = {
197
- :certdir => [:ssldir, "certs"],
198
- :publickeydir => [:ssldir, "public_keys"],
199
- :privatekeydir => [:ssldir, "private_keys"],
200
- :cadir => [:ssldir, "ca"],
201
- :cacert => [:cadir, "ca_crt.pem"],
202
- :cakey => [:cadir, "ca_key.pem"],
203
- :capub => [:cadir, "ca_pub.pem"],
204
- :csrdir => [:cadir, "requests"],
205
- :signeddir => [:cadir, "signed"],
206
- :capass => [:cadir, "ca.pass"],
207
- :serial => [:cadir, "serial"],
208
- :privatedir => [:ssldir, "private"],
209
- :passfile => [:privatedir, "password"],
210
- :autosign => [:puppetconf, "autosign.conf"],
211
- :ca_crl_days => 365,
212
- :ca_days => 1825,
213
- :ca_md => "md5",
214
- :req_bits => 2048,
215
- :keylength => 1024,
216
- }
217
-
218
- @@params.each { |param|
219
- Puppet.setdefault(param,@@defaults[param])
220
- }
221
-
222
- def certfile
223
- @config[:cacert]
224
- end
225
-
226
- def host2csrfile(hostname)
227
- File.join(Puppet[:csrdir], [hostname, "pem"].join("."))
228
- end
229
-
230
- # this stores signed certs in a directory unrelated to
231
- # normal client certs
232
- def host2certfile(hostname)
233
- File.join(Puppet[:signeddir], [hostname, "pem"].join("."))
234
- end
235
-
236
- def thing2name(thing)
237
- thing.subject.to_a.find { |ary|
238
- ary[0] == "CN"
239
- }[1]
240
- end
241
-
242
- def initialize(hash = {})
243
- self.setconfig(hash)
244
-
245
- self.getcert
246
- unless FileTest.exists?(@config[:serial])
247
- File.open(@config[:serial], "w") { |f|
248
- f << "%04X" % 1
249
- }
250
- end
251
-
252
- if Puppet[:capass] and ! FileTest.exists?(Puppet[:capass])
253
- self.genpass
254
- end
255
- end
256
-
257
- def genpass
258
- pass = ""
259
- 20.times { pass += (rand(74) + 48).chr }
260
-
261
- unless @config[:capass]
262
- raise "No passfile"
263
- end
264
- Puppet::SSLCertificates.mkdir(File.dirname(@config[:capass]))
265
- File.open(@config[:capass], "w", 0600) { |f| f.print pass }
266
- return pass
267
- end
268
-
269
- def getcert
270
- if FileTest.exists?(@config[:cacert])
271
- @cert = OpenSSL::X509::Certificate.new(
272
- File.read(@config[:cacert])
273
- )
274
- else
275
- self.mkrootcert
276
- end
277
- end
278
-
279
- def getclientcsr(host)
280
- csrfile = host2csrfile(host)
281
- unless File.exists?(csrfile)
282
- return nil
283
- end
284
-
285
- return OpenSSL::X509::Request.new(File.read(csrfile))
286
- end
287
-
288
- def getclientcert(host)
289
- certfile = host2certfile(host)
290
- unless File.exists?(certfile)
291
- return [nil, nil]
292
- end
293
-
294
- return [OpenSSL::X509::Certificate.new(File.read(certfile)), @cert]
295
- end
296
-
297
- def list
298
- return Dir.entries(Puppet[:csrdir]).reject { |file|
299
- file =~ /^\.+$/
300
- }.collect { |file|
301
- file.sub(/\.pem$/, '')
302
- }
303
- end
304
-
305
- def mkrootcert
306
- cert = Certificate.new(
307
- :name => "CAcert",
308
- :cert => @config[:cacert],
309
- :encrypt => @config[:passfile],
310
- :key => @config[:cakey],
311
- :selfsign => true,
312
- :length => 1825,
313
- :type => :ca
314
- )
315
- @cert = cert.mkselfsigned
316
- File.open(@config[:cacert], "w", 0660) { |f|
317
- f.puts @cert.to_pem
318
- }
319
- @key = cert.key
320
- return cert
321
- end
322
-
323
- def removeclientcsr(host)
324
- csrfile = host2csrfile(host)
325
- unless File.exists?(csrfile)
326
- raise Puppet::Error, "No certificate request for %s" % host
327
- end
328
-
329
- File.unlink(csrfile)
330
- end
331
-
332
- def setconfig(hash)
333
- @config = {}
334
- @@params.each { |param|
335
- if hash.include?(param)
336
- begin
337
- @config[param] = hash[param]
338
- Puppet[param] = hash[param]
339
- hash.delete(param)
340
- rescue => detail
341
- puts detail
342
- exit
343
- end
344
- else
345
- begin
346
- @config[param] = Puppet[param]
347
- rescue => detail
348
- puts detail
349
- exit
350
- end
351
- end
352
- }
353
-
354
- if hash.include?(:password)
355
- @config[:password] = hash[:password]
356
- hash.delete(:password)
357
- end
358
-
359
- if hash.length > 0
360
- raise ArgumentError, "Unknown parameters %s" % hash.keys.join(",")
361
- end
362
-
363
- [:cadir, :csrdir, :signeddir].each { |dir|
364
- unless @config[dir]
365
- raise "%s is undefined" % dir
366
- end
367
- unless FileTest.exists?(@config[dir])
368
- Puppet::SSLCertificates.mkdir(@config[dir])
369
- end
370
- }
371
- end
372
-
373
- def sign(csr)
374
- unless csr.is_a?(OpenSSL::X509::Request)
375
- raise Puppet::Error,
376
- "CA#sign only accepts OpenSSL::X509::Request objects, not %s" %
377
- csr.class
378
- end
379
-
380
- unless csr.verify(csr.public_key)
381
- raise Puppet::Error, "CSR sign verification failed"
382
- end
383
-
384
- # i should probably check key length...
385
-
386
- # read the ca cert in
387
- cacert = OpenSSL::X509::Certificate.new(
388
- File.read(@config[:cacert])
389
- )
390
-
391
- cakey = nil
392
- if @config[:password]
393
- cakey = OpenSSL::PKey::RSA.new(
394
- File.read(@config[:cakey]), @config[:password]
395
- )
396
- else
397
- cakey = OpenSSL::PKey::RSA.new(
398
- File.read(@config[:cakey])
399
- )
400
- end
401
-
402
- unless cacert.check_private_key(cakey)
403
- raise Puppet::Error, "CA Certificate is invalid"
404
- end
405
-
406
- serial = File.read(@config[:serial]).chomp.hex
407
- newcert = SSLCertificates.mkcert(
408
- :type => :server,
409
- :name => csr.subject,
410
- :days => @config[:ca_days],
411
- :issuer => cacert,
412
- :serial => serial,
413
- :publickey => csr.public_key
414
- )
415
-
416
- # increment the serial
417
- File.open(@config[:serial], "w") { |f|
418
- f << "%04X" % (serial + 1)
419
- }
420
-
421
- newcert.sign(cakey, OpenSSL::Digest::SHA1.new)
422
-
423
- self.storeclientcert(newcert)
424
-
425
- return [newcert, cacert]
426
- end
427
-
428
- def storeclientcsr(csr)
429
- host = thing2name(csr)
430
-
431
- csrfile = host2csrfile(host)
432
- if File.exists?(csrfile)
433
- raise Puppet::Error, "Certificate request for %s already exists" % host
434
- end
435
-
436
- File.open(csrfile, "w", 0660) { |f|
437
- f.print csr.to_pem
438
- }
439
- end
440
-
441
- def storeclientcert(cert)
442
- host = thing2name(cert)
443
-
444
- certfile = host2certfile(host)
445
- if File.exists?(certfile)
446
- Puppet.notice "Overwriting signed certificate %s for %s" %
447
- [certfile, host]
448
- end
449
-
450
- File.open(certfile, "w", 0660) { |f|
451
- f.print cert.to_pem
452
- }
453
- end
454
-
455
- end
456
-
457
- class Certificate
458
- attr_accessor :certfile, :keyfile, :name, :dir, :hash, :type
459
- attr_accessor :key, :cert, :csr, :cacert
460
-
461
- @@params2names = {
462
- :name => "CN",
463
- :state => "ST",
464
- :country => "C",
465
- :email => "emailAddress",
466
- :org => "O",
467
- :city => "L",
468
- :ou => "OU"
469
- }
470
-
471
- def certname
472
- OpenSSL::X509::Name.new self.subject
473
- end
474
-
475
- def delete
476
- [@certfile,@keyfile].each { |file|
477
- if FileTest.exists?(file)
478
- File.unlink(file)
479
- end
480
- }
481
-
482
- if defined? @hash and @hash
483
- if FileTest.symlink?(@hash)
484
- File.unlink(@hash)
485
- end
486
- end
487
- end
488
-
489
- def exists?
490
- return FileTest.exists?(@certfile)
491
- end
492
-
493
- def getkey
494
- unless FileTest.exists?(@keyfile)
495
- self.mkkey()
496
- end
497
- if @password
498
- @key = OpenSSL::PKey::RSA.new(
499
- File.read(@keyfile),
500
- @password
501
- )
502
- else
503
- @key = OpenSSL::PKey::RSA.new(
504
- File.read(@keyfile)
505
- )
506
- end
507
- end
508
-
509
- def initialize(hash)
510
- unless hash.include?(:name)
511
- raise "You must specify the common name for the certificate"
512
- end
513
- @name = hash[:name]
514
-
515
- # init a few variables
516
- @cert = @key = @csr = nil
517
-
518
- if hash.include?(:cert)
519
- @certfile = hash[:cert]
520
- @dir = File.dirname(@certfile)
521
- else
522
- @dir = hash[:dir] || Puppet[:certdir]
523
- @certfile = File.join(@dir, @name)
524
- end
525
-
526
- @cacertfile ||= File.join(Puppet[:certdir], "ca.pem")
527
-
528
- unless FileTest.directory?(@dir)
529
- Puppet::SSLCertificates.mkdir(@dir)
530
- end
531
-
532
- unless @certfile =~ /\.pem$/
533
- @certfile += ".pem"
534
- end
535
- @keyfile = hash[:key] || File.join(
536
- Puppet[:privatekeydir], [@name,"pem"].join(".")
537
- )
538
- unless FileTest.directory?(@dir)
539
- Puppet::SSLCertificates.mkdir(@dir)
540
- end
541
-
542
- [@keyfile].each { |file|
543
- dir = File.dirname(file)
544
-
545
- unless FileTest.directory?(dir)
546
- Puppet::SSLCertificates.mkdir(dir)
547
- end
548
- }
549
-
550
- @days = hash[:length] || 365
551
- @selfsign = hash[:selfsign] || false
552
- @encrypt = hash[:encrypt] || false
553
- @replace = hash[:replace] || false
554
- @issuer = hash[:issuer] || nil
555
-
556
- if hash.include?(:type)
557
- case hash[:type]
558
- when :ca, :client, :server: @type = hash[:type]
559
- else
560
- raise "Invalid Cert type %s" % hash[:type]
561
- end
562
- else
563
- @type = :client
564
- end
565
-
566
- @params = {:name => @name}
567
- [:state, :country, :email, :org, :ou].each { |param|
568
- if hash.include?(param)
569
- @params[param] = hash[param]
570
- end
571
- }
572
-
573
- if @encrypt
574
- if @encrypt =~ /^\//
575
- File.open(@encrypt) { |f|
576
- @password = f.read.chomp
577
- }
578
- else
579
- raise ":encrypt must be a path to a pass phrase file"
580
- end
581
- else
582
- @password = nil
583
- end
584
-
585
- if hash.include?(:selfsign)
586
- @selfsign = hash[:selfsign]
587
- else
588
- @selfsign = false
589
- end
590
- end
591
-
592
- # this only works for servers, not for users
593
- def mkcsr
594
- unless defined? @key and @key
595
- self.getkey
596
- end
597
-
598
- name = OpenSSL::X509::Name.new self.subject
599
-
600
- @csr = OpenSSL::X509::Request.new
601
- @csr.version = 0
602
- @csr.subject = name
603
- @csr.public_key = @key.public_key
604
- @csr.sign(@key, OpenSSL::Digest::SHA1.new)
605
-
606
- #File.open(@csrfile, "w") { |f|
607
- # f << @csr.to_pem
608
- #}
609
-
610
- unless @csr.verify(@key.public_key)
611
- raise Puppet::Error, "CSR sign verification failed"
612
- end
613
-
614
- return @csr
615
- end
616
-
617
- def mkkey
618
- # @key is the file
619
-
620
- @key = OpenSSL::PKey::RSA.new(1024)
621
- # { |p,n|
622
- # case p
623
- # when 0; Puppet.info "key info: ." # BN_generate_prime
624
- # when 1; Puppet.info "key info: +" # BN_generate_prime
625
- # when 2; Puppet.info "key info: *" # searching good prime,
626
- # # n = #of try,
627
- # # but also data from BN_generate_prime
628
- # when 3; Puppet.info "key info: \n" # found good prime, n==0 - p, n==1 - q,
629
- # # but also data from BN_generate_prime
630
- # else; Puppet.info "key info: *" # BN_generate_prime
631
- # end
632
- # }
633
-
634
- if @password
635
- #passwdproc = proc { @password }
636
- keytext = @key.export(
637
- OpenSSL::Cipher::DES.new(:EDE3, :CBC),
638
- @password
639
- )
640
- File.open(@keyfile, "w", 0400) { |f|
641
- f << keytext
642
- }
643
- else
644
- File.open(@keyfile, "w", 0400) { |f|
645
- f << @key.to_pem
646
- }
647
- end
648
-
649
- #cmd = "#{ossl} genrsa -out #{@key} 1024"
650
- end
651
-
652
- def mkselfsigned
653
- unless defined? @key and @key
654
- self.getkey
655
- end
656
-
657
- if defined? @cert and @cert
658
- raise Puppet::Error, "Cannot replace existing certificate"
659
- end
660
-
661
- args = {
662
- :name => self.certname,
663
- :days => @days,
664
- :issuer => nil,
665
- :serial => 0x0,
666
- :publickey => @key.public_key
667
- }
668
- if @type
669
- args[:type] = @type
670
- else
671
- args[:type] = :server
672
- end
673
- @cert = SSLCertificates.mkcert(args)
674
-
675
- @cert.sign(@key, OpenSSL::Digest::SHA1.new) if @selfsign
676
-
677
- return @cert
678
- end
679
-
680
- def subject(string = false)
681
- subj = @@params2names.collect { |param, name|
682
- if @params.include?(param)
683
- [name, @params[param]]
684
- end
685
- }.reject { |ary| ary.nil? }
686
-
687
- if string
688
- return "/" + subj.collect { |ary|
689
- "%s=%s" % ary
690
- }.join("/") + "/"
691
- else
692
- return subj
693
- end
694
- end
695
-
696
- # verify that we can track down the cert chain or whatever
697
- def verify
698
- "openssl verify -verbose -CAfile /home/luke/.puppet/ssl/certs/ca.pem -purpose sslserver culain.madstop.com.pem"
699
- end
700
-
701
- def write
702
- files = {
703
- @certfile => @cert,
704
- @keyfile => @key,
705
- }
706
- if defined? @cacert
707
- files[@cacertfile] = @cacert
708
- end
709
-
710
- files.each { |file,thing|
711
- if defined? thing and thing
712
- if FileTest.exists?(file)
713
- next
714
- end
715
-
716
- text = nil
717
-
718
- if thing.is_a?(OpenSSL::PKey::RSA) and @password
719
- text = thing.export(
720
- OpenSSL::Cipher::DES.new(:EDE3, :CBC),
721
- @password
722
- )
723
- else
724
- text = thing.to_pem
725
- end
726
-
727
- File.open(file, "w", 0660) { |f| f.print text }
728
- end
729
- }
730
-
731
- if defined? @cacert
732
- SSLCertificates.mkhash(Puppet[:certdir], @cacert, @cacertfile)
733
- end
734
- end
735
- end
736
- end
167
+ require 'puppet/sslcertificates/certificate'
168
+ require 'puppet/sslcertificates/ca'
737
169
  end
170
+
171
+ # $Id: sslcertificates.rb 873 2006-02-07 23:12:33Z luke $