puppet 0.16.0 → 0.18.4

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 (185) hide show
  1. data/CHANGELOG +98 -0
  2. data/Rakefile +5 -1
  3. data/bin/puppet +1 -1
  4. data/bin/puppetca +25 -11
  5. data/bin/puppetd +189 -66
  6. data/bin/puppetdoc +79 -62
  7. data/bin/puppetmasterd +93 -49
  8. data/bin/puppetrun +385 -0
  9. data/conf/redhat/client.init +5 -2
  10. data/conf/redhat/fileserver.conf +1 -1
  11. data/conf/redhat/lsb-config.patch +51 -0
  12. data/conf/redhat/puppet.spec +45 -18
  13. data/conf/redhat/puppetd.conf +32 -4
  14. data/conf/redhat/server.init +5 -2
  15. data/conf/solaris/pkginfo +7 -0
  16. data/conf/solaris/smf/puppetd.xml +77 -0
  17. data/conf/solaris/smf/puppetmasterd.xml +77 -0
  18. data/conf/solaris/smf/svc-puppetd +66 -0
  19. data/conf/solaris/smf/svc-puppetmasterd +62 -0
  20. data/examples/code/failers/noobjectrvalue +1 -0
  21. data/examples/code/snippets/deepclassheirarchy.pp +23 -0
  22. data/examples/code/snippets/defineoverrides.pp +17 -0
  23. data/examples/code/snippets/emptyexec.pp +3 -0
  24. data/examples/code/snippets/selectorvalues.pp +6 -1
  25. data/examples/code/snippets/tagged.pp +35 -0
  26. data/ext/ldap/puppet.schema +2 -2
  27. data/install.rb +4 -2
  28. data/lib/puppet.rb +206 -15
  29. data/lib/puppet/client.rb +30 -20
  30. data/lib/puppet/client/ca.rb +2 -2
  31. data/lib/puppet/client/dipper.rb +5 -9
  32. data/lib/puppet/client/master.rb +224 -44
  33. data/lib/puppet/client/pelement.rb +54 -9
  34. data/lib/puppet/client/proxy.rb +3 -2
  35. data/lib/puppet/client/reporter.rb +34 -0
  36. data/lib/puppet/client/runner.rb +17 -0
  37. data/lib/puppet/config.rb +136 -55
  38. data/lib/puppet/daemon.rb +59 -37
  39. data/lib/puppet/element.rb +2 -1
  40. data/lib/puppet/event.rb +14 -3
  41. data/lib/puppet/filetype.rb +28 -19
  42. data/lib/puppet/log.rb +297 -132
  43. data/lib/puppet/metric.rb +31 -131
  44. data/lib/puppet/networkclient.rb +73 -46
  45. data/lib/puppet/parameter.rb +49 -1
  46. data/lib/puppet/parsedfile.rb +32 -12
  47. data/lib/puppet/parser/ast.rb +6 -1
  48. data/lib/puppet/parser/ast/astarray.rb +32 -6
  49. data/lib/puppet/parser/ast/collection.rb +91 -0
  50. data/lib/puppet/parser/ast/compdef.rb +2 -2
  51. data/lib/puppet/parser/ast/component.rb +24 -11
  52. data/lib/puppet/parser/ast/function.rb +50 -0
  53. data/lib/puppet/parser/ast/hostclass.rb +70 -22
  54. data/lib/puppet/parser/ast/node.rb +17 -8
  55. data/lib/puppet/parser/ast/nodedef.rb +1 -1
  56. data/lib/puppet/parser/ast/objectdef.rb +28 -10
  57. data/lib/puppet/parser/ast/selector.rb +4 -1
  58. data/lib/puppet/parser/functions.rb +145 -0
  59. data/lib/puppet/parser/interpreter.rb +243 -86
  60. data/lib/puppet/parser/lexer.rb +5 -4
  61. data/lib/puppet/parser/parser.rb +586 -505
  62. data/lib/puppet/parser/scope.rb +337 -187
  63. data/lib/puppet/rails.rb +115 -0
  64. data/lib/puppet/rails/database.rb +40 -0
  65. data/lib/puppet/rails/host.rb +83 -0
  66. data/lib/puppet/rails/rails_object.rb +42 -0
  67. data/lib/puppet/rails/rails_parameter.rb +5 -0
  68. data/lib/puppet/reports/rrdgraph.rb +20 -0
  69. data/lib/puppet/reports/tagmail.rb +94 -0
  70. data/lib/puppet/server.rb +20 -4
  71. data/lib/puppet/server/authconfig.rb +14 -3
  72. data/lib/puppet/server/authstore.rb +2 -2
  73. data/lib/puppet/server/ca.rb +23 -11
  74. data/lib/puppet/server/filebucket.rb +10 -10
  75. data/lib/puppet/server/fileserver.rb +4 -8
  76. data/lib/puppet/server/master.rb +19 -22
  77. data/lib/puppet/server/pelement.rb +28 -16
  78. data/lib/puppet/server/report.rb +184 -0
  79. data/lib/puppet/server/runner.rb +62 -0
  80. data/lib/puppet/server/servlet.rb +23 -9
  81. data/lib/puppet/sslcertificates/ca.rb +25 -1
  82. data/lib/puppet/statechange.rb +34 -53
  83. data/lib/puppet/storage.rb +1 -2
  84. data/lib/puppet/transaction.rb +305 -133
  85. data/lib/puppet/transaction/report.rb +42 -0
  86. data/lib/puppet/transportable.rb +57 -33
  87. data/lib/puppet/type.rb +260 -127
  88. data/lib/puppet/type/component.rb +9 -21
  89. data/lib/puppet/type/cron.rb +367 -116
  90. data/lib/puppet/type/exec.rb +15 -16
  91. data/lib/puppet/type/group.rb +9 -1
  92. data/lib/puppet/type/nameservice.rb +2 -5
  93. data/lib/puppet/type/nameservice/netinfo.rb +3 -0
  94. data/lib/puppet/type/nameservice/objectadd.rb +23 -10
  95. data/lib/puppet/type/nameservice/pw.rb +16 -3
  96. data/lib/puppet/type/package.rb +25 -75
  97. data/lib/puppet/type/package/apple.rb +15 -1
  98. data/lib/puppet/type/package/apt.rb +37 -2
  99. data/lib/puppet/type/package/blastwave.rb +136 -0
  100. data/lib/puppet/type/package/dpkg.rb +4 -4
  101. data/lib/puppet/type/package/gem.rb +119 -0
  102. data/lib/puppet/type/package/openbsd.rb +7 -6
  103. data/lib/puppet/type/package/ports.rb +7 -2
  104. data/lib/puppet/type/package/rpm.rb +1 -1
  105. data/lib/puppet/type/package/sun.rb +23 -9
  106. data/lib/puppet/type/package/sunfreeware.rb +7 -0
  107. data/lib/puppet/type/package/yum.rb +16 -9
  108. data/lib/puppet/type/parsedtype.rb +7 -5
  109. data/lib/puppet/type/parsedtype/mount.rb +55 -34
  110. data/lib/puppet/type/parsedtype/port.rb +7 -1
  111. data/lib/puppet/type/parsedtype/sshkey.rb +6 -16
  112. data/lib/puppet/type/pfile.rb +115 -23
  113. data/lib/puppet/type/pfile/checksum.rb +18 -5
  114. data/lib/puppet/type/pfile/content.rb +2 -2
  115. data/lib/puppet/type/pfile/ensure.rb +3 -3
  116. data/lib/puppet/type/pfile/group.rb +2 -2
  117. data/lib/puppet/type/pfile/source.rb +28 -17
  118. data/lib/puppet/type/pfile/target.rb +25 -17
  119. data/lib/puppet/type/pfilebucket.rb +25 -6
  120. data/lib/puppet/type/schedule.rb +6 -6
  121. data/lib/puppet/type/service.rb +24 -14
  122. data/lib/puppet/type/service/debian.rb +1 -1
  123. data/lib/puppet/type/service/redhat.rb +13 -10
  124. data/lib/puppet/type/service/smf.rb +3 -3
  125. data/lib/puppet/type/state.rb +1 -2
  126. data/lib/puppet/type/symlink.rb +3 -4
  127. data/lib/puppet/type/user.rb +22 -10
  128. data/lib/puppet/type/yumrepo.rb +6 -1
  129. data/lib/puppet/type/zone.rb +595 -0
  130. data/lib/puppet/util.rb +58 -12
  131. data/test/client/client.rb +2 -2
  132. data/test/client/master.rb +92 -3
  133. data/test/client/pelement.rb +99 -0
  134. data/test/executables/puppetbin.rb +3 -4
  135. data/test/executables/puppetca.rb +3 -3
  136. data/test/executables/puppetd.rb +3 -3
  137. data/test/executables/puppetmasterd.rb +1 -5
  138. data/test/executables/puppetmodule.rb +2 -2
  139. data/test/language/ast.rb +200 -11
  140. data/test/language/functions.rb +245 -0
  141. data/test/language/interpreter.rb +155 -6
  142. data/test/language/lexer.rb +35 -2
  143. data/test/language/node.rb +48 -1
  144. data/test/language/parser.rb +250 -1
  145. data/test/language/rails.rb +105 -0
  146. data/test/language/scope.rb +304 -10
  147. data/test/language/snippets.rb +54 -5
  148. data/test/language/transportable.rb +60 -28
  149. data/test/other/config.rb +214 -1
  150. data/test/other/events.rb +67 -9
  151. data/test/other/log.rb +31 -5
  152. data/test/other/metrics.rb +23 -21
  153. data/test/other/parsedfile.rb +29 -2
  154. data/test/other/puppet.rb +79 -0
  155. data/test/other/report.rb +106 -0
  156. data/test/other/storage.rb +2 -2
  157. data/test/other/transactions.rb +128 -2
  158. data/test/puppet/utiltest.rb +10 -5
  159. data/test/puppettest.rb +193 -21
  160. data/test/server/authstore.rb +13 -4
  161. data/test/server/bucket.rb +33 -8
  162. data/test/server/ca.rb +44 -6
  163. data/test/server/master.rb +6 -7
  164. data/test/server/pelement.rb +15 -5
  165. data/test/server/report.rb +93 -0
  166. data/test/server/runner.rb +107 -0
  167. data/test/server/server.rb +28 -1
  168. data/test/types/cron.rb +339 -31
  169. data/test/types/file.rb +256 -24
  170. data/test/types/filebucket.rb +6 -2
  171. data/test/types/filesources.rb +41 -92
  172. data/test/types/group.rb +31 -1
  173. data/test/types/host.rb +2 -1
  174. data/test/types/mount.rb +18 -1
  175. data/test/types/package.rb +200 -18
  176. data/test/types/service.rb +5 -1
  177. data/test/types/sshkey.rb +2 -1
  178. data/test/types/symlink.rb +3 -2
  179. data/test/types/type.rb +180 -1
  180. data/test/types/user.rb +65 -27
  181. data/test/types/yumrepo.rb +15 -0
  182. data/test/types/zone.rb +437 -0
  183. metadata +43 -4
  184. data/bin/cf2puppet +0 -186
  185. data/conf/redhat/puppetmasterd.conf +0 -5
@@ -26,7 +26,7 @@ Puppet.type(:service).newsvctype(:debian, :init) do
26
26
 
27
27
  # If it's enabled, then it will print output showing removal of
28
28
  # links.
29
- if output =~ /etc\/rc\d.d/
29
+ if output =~ /etc\/rc[\dS].d|Nothing to do\./
30
30
  return :true
31
31
  else
32
32
  return :false
@@ -5,29 +5,32 @@ require 'puppet/type/service/init'
5
5
  Puppet.type(:service).newsvctype(:redhat, :init) do
6
6
  # Remove the symlinks
7
7
  def disable
8
- output = %x{chkconfig #{self[:name]} off 2>&1}
9
-
10
- unless $? == 0
8
+ begin
9
+ output = util_execute("/sbin/chkconfig #{self[:name]} off 2>&1")
10
+ output += util_execute("/sbin/chkconfig --del #{self[:name]} 2>&1")
11
+ rescue Puppet::ExecutionFailure
11
12
  raise Puppet::Error, "Could not disable %s: %s" %
12
13
  [self.name, output]
13
14
  end
14
15
  end
15
16
 
16
17
  def enabled?
17
- output = %x{chkconfig #{self[:name]} 2>&1}.chomp
18
- if $? == 0
19
- return :true
20
- else
18
+ begin
19
+ output = util_execute("/sbin/chkconfig #{self[:name]} 2>&1").chomp
20
+ rescue Puppet::ExecutionFailure
21
21
  return :false
22
22
  end
23
+
24
+ return :true
23
25
  end
24
26
 
25
27
  # Don't support them specifying runlevels; always use the runlevels
26
28
  # in the init scripts.
27
29
  def enable
28
- output = %x{chkconfig #{self[:name]} on 2>&1}
29
-
30
- unless $? == 0
30
+ begin
31
+ output = util_execute("/sbin/chkconfig --add #{self[:name]} 2>&1")
32
+ output += util_execute("/sbin/chkconfig #{self[:name]} on 2>&1")
33
+ rescue Puppet::ExecutionFailure
31
34
  raise Puppet::Error, "Could not enable %s: %s" %
32
35
  [self.name, output]
33
36
  end
@@ -45,7 +45,7 @@ Puppet.type(:service).newsvctype(:smf) do
45
45
  when "online":
46
46
  #self.warning "matched running %s" % line.inspect
47
47
  return :running
48
- when "offline", "disabled":
48
+ when "offline", "disabled", "uninitialized"
49
49
  #self.warning "matched stopped %s" % line.inspect
50
50
  return :stopped
51
51
  when "legacy_run":
@@ -53,7 +53,7 @@ Puppet.type(:service).newsvctype(:smf) do
53
53
  "Cannot manage legacy services through SMF"
54
54
  else
55
55
  raise Puppet::Error,
56
- "Unmanageable state %s on service %s" %
56
+ "Unmanageable state '%s' on service %s" %
57
57
  [value, self.name]
58
58
  end
59
59
  end
@@ -71,4 +71,4 @@ Puppet.type(:service).newsvctype(:smf) do
71
71
  end
72
72
  end
73
73
 
74
- # $Id: smf.rb 1113 2006-04-17 16:15:33Z luke $
74
+ # $Id: smf.rb 1375 2006-07-06 17:59:30Z luke $
@@ -109,7 +109,6 @@ class State < Puppet::Parameter
109
109
  when :present: (@parent.class.name.to_s + "_created").intern
110
110
  when :absent: (@parent.class.name.to_s + "_removed").intern
111
111
  else
112
- warning self.should.inspect
113
112
  (@parent.class.name.to_s + "_changed").intern
114
113
  end
115
114
 
@@ -391,4 +390,4 @@ class State < Puppet::Parameter
391
390
  end
392
391
  end
393
392
 
394
- # $Id: state.rb 1124 2006-04-20 07:00:10Z luke $
393
+ # $Id: state.rb 1136 2006-04-26 16:14:47Z luke $
@@ -5,7 +5,7 @@ require 'puppet/type/pfile'
5
5
  module Puppet
6
6
  newtype(:symlink) do
7
7
  @doc = "Create symbolic links to existing files. **This type is deprecated;
8
- use file_ instead.**"
8
+ use file instead.**"
9
9
  #newstate(:ensure) do
10
10
  ensurable do
11
11
  require 'etc'
@@ -104,7 +104,7 @@ module Puppet
104
104
  newparam(:recurse) do
105
105
  desc "If target is a directory, recursively create
106
106
  directories (using `file`'s `source` parameter) and link all
107
- contained files. For instance::
107
+ contained files. For instance:
108
108
 
109
109
  # The Solaris Blastwave repository installs everything
110
110
  # in /opt/csw; link it into /usr/local
@@ -170,7 +170,6 @@ module Puppet
170
170
  }
171
171
 
172
172
  dir = Puppet.type(:file).implicitcreate(args)
173
- dir.parent = @parent
174
173
  @parent.push dir
175
174
  @setparent = true
176
175
  end
@@ -184,4 +183,4 @@ module Puppet
184
183
  end # Puppet.type(:symlink)
185
184
  end
186
185
 
187
- # $Id: symlink.rb 1098 2006-04-10 22:13:10Z luke $
186
+ # $Id: symlink.rb 1300 2006-06-19 19:12:54Z luke $
@@ -246,7 +246,11 @@ module Puppet
246
246
  if @parent[:membership] == :inclusive
247
247
  @should.sort.join(",")
248
248
  else
249
- (@is + @should).uniq.sort.join(",")
249
+ members = @should
250
+ if @is.is_a?(Array)
251
+ members += @is
252
+ end
253
+ members.uniq.sort.join(",")
250
254
  end
251
255
  end
252
256
 
@@ -261,6 +265,9 @@ module Puppet
261
265
  unless defined? @is and @is
262
266
  return false
263
267
  end
268
+ unless @is.class == @should.class
269
+ return false
270
+ end
264
271
  return @is.sort == @should.sort
265
272
  end
266
273
 
@@ -272,16 +279,9 @@ module Puppet
272
279
 
273
280
  def sync
274
281
  if respond_to? :setgrouplist
275
- groups = nil
276
- if @parent[:membership] == :inclusive
277
- groups = @should
278
- else
279
- groups = (@is + @should).uniq
280
- end
281
-
282
282
  # Pass them the group list, so that the :membership logic
283
283
  # is all in this class, not in parent classes.
284
- setgrouplist(groups)
284
+ setgrouplist(self.should)
285
285
  return :user_modified
286
286
  else
287
287
  super
@@ -331,6 +331,14 @@ module Puppet
331
331
  defaultto :minimum
332
332
  end
333
333
 
334
+ newparam(:allowdupe) do
335
+ desc "Whether to allow duplicate UIDs."
336
+
337
+ newvalues(:true, :false)
338
+
339
+ defaultto false
340
+ end
341
+
334
342
  @doc = "Manage users. Currently can create and modify users, but
335
343
  cannot delete them. Theoretically all of the parameters are
336
344
  optional, but if no parameters are specified the comment will
@@ -376,6 +384,10 @@ module Puppet
376
384
  }
377
385
  end
378
386
 
387
+ if @states.include?(:groups) and groups = @states[:groups].should.split(",")
388
+ autos += groups
389
+ end
390
+
379
391
  autos
380
392
  end
381
393
 
@@ -441,4 +453,4 @@ module Puppet
441
453
  end
442
454
  end
443
455
 
444
- # $Id: user.rb 1125 2006-04-20 19:38:48Z luke $
456
+ # $Id: user.rb 1416 2006-07-21 19:05:30Z luke $
@@ -22,7 +22,11 @@ module Puppet
22
22
  result = nil
23
23
  else
24
24
  result = set
25
- parent.section[inikey] = should
25
+ if should == :absent
26
+ parent.section[inikey] = nil
27
+ else
28
+ parent.section[inikey] = should
29
+ end
26
30
  end
27
31
  return result
28
32
  end
@@ -163,6 +167,7 @@ module Puppet
163
167
  @inifile = nil
164
168
  @yumconf = "/etc/yum.conf"
165
169
  @defaultrepodir = nil
170
+ super
166
171
  end
167
172
 
168
173
  # Return the Puppet::IniConfig::Section for this yumrepo element
@@ -0,0 +1,595 @@
1
+ Puppet::Type.newtype(:zone) do
2
+ @doc = "Solaris zones."
3
+
4
+ # These states modify the zone configuration, and they need to provide
5
+ # the text separately from syncing it, so all config statements can be rolled
6
+ # into a single creation statement.
7
+ class ZoneConfigState < Puppet::State
8
+ # Perform the config operation.
9
+ def sync
10
+ @parent.cfg self.configtext
11
+ end
12
+ end
13
+
14
+ # Those states that can have multiple instances.
15
+ class ZoneMultiConfigState < ZoneConfigState
16
+ def configtext
17
+ list = @should
18
+
19
+ unless @is.is_a? Symbol
20
+ if @is.is_a? Array
21
+ list += @is
22
+ else
23
+ if @is
24
+ list << @is
25
+ end
26
+ end
27
+ end
28
+
29
+ # Some hackery so we can test whether @is is an array or a symbol
30
+ if @is.is_a? Array
31
+ tmpis = @is
32
+ else
33
+ if @is
34
+ tmpis = [@is]
35
+ else
36
+ tmpis = []
37
+ end
38
+ end
39
+
40
+ rms = []
41
+ adds = []
42
+ # Collect the modifications to make
43
+ list.sort.uniq.collect do |obj|
44
+ # Skip objectories that are configured and should be
45
+ next if tmpis.include?(obj) and @should.include?(obj)
46
+
47
+ if tmpis.include?(obj)
48
+ rms << obj
49
+ else
50
+ adds << obj
51
+ end
52
+ end
53
+
54
+ # And then perform all of the removals before any of the adds.
55
+ (rms.collect { |o| rm(o) } + adds.collect { |o| add(o) }).join("\n")
56
+ end
57
+
58
+ # We want all specified directories to be included.
59
+ def insync?
60
+ if @is.is_a? Array and @should.is_a? Array
61
+ @is.sort == @should.sort
62
+ else
63
+ @is == @should
64
+ end
65
+ end
66
+ end
67
+
68
+ ensurable do
69
+ desc "The running state of the zone. The valid states directly reflect
70
+ the states that ``zoneadm`` provides. The states are linear,
71
+ in that a zone must be ``configured`` then ``installed``, and
72
+ only then can be ``running``. Note also that ``halt`` is currently
73
+ used to stop zones."
74
+
75
+ @states = {}
76
+
77
+ def self.newvalue(name, hash)
78
+ if @parametervalues.is_a? Hash
79
+ @parametervalues = []
80
+ end
81
+
82
+ @parametervalues << name
83
+
84
+ @states[name] = hash
85
+ hash[:name] = name
86
+ end
87
+
88
+ newvalue :absent, :down => :destroy
89
+ newvalue :configured, :up => :configure, :down => :uninstall
90
+ newvalue :installed, :up => :install, :down => :stop
91
+ newvalue :running, :up => :start
92
+
93
+ defaultto :running
94
+
95
+ def self.valueindex(value)
96
+ @parametervalues.index(value)
97
+ end
98
+
99
+ # Return all of the states between two listed values, exclusive
100
+ # of the first item.
101
+ def self.valueslice(first, second)
102
+ findex = sindex = nil
103
+ unless findex = @parametervalues.index(first)
104
+ raise ArgumentError, "'%s' is not a valid zone state" % first
105
+ end
106
+ unless sindex = @parametervalues.index(second)
107
+ raise ArgumentError, "'%s' is not a valid zone state" % first
108
+ end
109
+ list = nil
110
+
111
+ # Apparently ranges are unidirectional, so we have to reverse
112
+ # the range op twice.
113
+ if findex > sindex
114
+ list = @parametervalues[sindex..findex].collect do |name|
115
+ @states[name]
116
+ end.reverse
117
+ else
118
+ list = @parametervalues[findex..sindex].collect do |name|
119
+ @states[name]
120
+ end
121
+ end
122
+
123
+ # The first result is the current state, so don't return it.
124
+ list[1..-1]
125
+ end
126
+
127
+ def is=(value)
128
+ value = value.intern if value.is_a? String
129
+ @is = value
130
+ end
131
+
132
+ def sync
133
+ method = nil
134
+ if up?
135
+ dir = :up
136
+ else
137
+ dir = :down
138
+ end
139
+
140
+ # We need to get the state we're currently in and just call
141
+ # everything between it and us.
142
+ states = self.class.valueslice(self.is, self.should)
143
+
144
+ states.each do |st|
145
+ if method = st[dir]
146
+ warned = false
147
+ while @parent.processing?
148
+ unless warned
149
+ info "Waiting for zone to finish processing"
150
+ warned = true
151
+ end
152
+ sleep 1
153
+ end
154
+ @parent.send(method)
155
+ else
156
+ raise Puppet::DevError, "Cannot move %s from %s" %
157
+ [dir, st[:name]]
158
+ end
159
+ end
160
+
161
+ return ("zone_" + self.should.to_s).intern
162
+ end
163
+
164
+ # Are we moving up the state tree?
165
+ def up?
166
+ self.class.valueindex(self.is) < self.class.valueindex(self.should)
167
+ end
168
+ end
169
+
170
+ newparam(:name) do
171
+ desc "The name of the zone."
172
+
173
+ isnamevar
174
+ end
175
+
176
+ newparam(:id) do
177
+ desc "The numerical ID of the zone. This number is autogenerated
178
+ and cannot be changed."
179
+ end
180
+
181
+ newstate(:ip, ZoneMultiConfigState) do
182
+ require 'ipaddr'
183
+
184
+ desc "The IP address of the zone. IP addresses must be specified
185
+ with the interface, separated by a colon, e.g.: bge0:192.168.0.1.
186
+ For multiple interfaces, specify them in an array."
187
+
188
+ validate do |value|
189
+ unless value =~ /:/
190
+ raise ArgumentError,
191
+ "IP addresses must specify the interface and the address, separated by a colon."
192
+ end
193
+
194
+ interface, address = value.split(':')
195
+
196
+ begin
197
+ IPAddr.new(address)
198
+ rescue ArgumentError
199
+ raise ArgumentError, "'%s' is an invalid IP address" % address
200
+ end
201
+ end
202
+
203
+ # Add a directory to our list of inherited directories.
204
+ def add(str)
205
+ interface, ip = ipsplit(str)
206
+ "add net
207
+ set address=#{ip}
208
+ set physical=#{interface}
209
+ end
210
+ "
211
+ end
212
+
213
+ # Convert a string into the component interface and address
214
+ def ipsplit(str)
215
+ interface, address = str.split(':')
216
+ return interface, address
217
+ end
218
+
219
+ def rm(str)
220
+ interface, ip = ipsplit(str)
221
+ # Reality seems to disagree with the documentation here; the docs
222
+ # specify that braces are required, but they're apparently only
223
+ # required if you're specifying multiple values.
224
+ "remove net address=#{ip}"
225
+ end
226
+ end
227
+
228
+ newstate(:autoboot, ZoneConfigState) do
229
+ desc "Whether the zone should automatically boot."
230
+
231
+ defaultto true
232
+
233
+ newvalue(:true) {}
234
+ newvalue(:false) {}
235
+
236
+ def configtext
237
+ "set autoboot=#{self.should}"
238
+ end
239
+ end
240
+
241
+ newstate(:pool, ZoneConfigState) do
242
+ desc "The resource pool for this zone."
243
+
244
+ def configtext
245
+ "set pool=#{self.should}"
246
+ end
247
+ end
248
+
249
+ newstate(:inherit, ZoneMultiConfigState) do
250
+ desc "The list of directories that the zone inherits from the global
251
+ zone. All directories must be fully qualified."
252
+
253
+ validate do |value|
254
+ unless value =~ /^\//
255
+ raise ArgumentError, "The zone base must be fully qualified"
256
+ end
257
+ end
258
+
259
+ # Add a directory to our list of inherited directories.
260
+ def add(dir)
261
+ "add inherit-pkg-dir\nset dir=#{dir}\nend"
262
+ end
263
+
264
+ def rm(dir)
265
+ # Reality seems to disagree with the documentation here; the docs
266
+ # specify that braces are required, but they're apparently only
267
+ # required if you're specifying multiple values.
268
+ "remove inherit-pkg-dir dir=#{dir}"
269
+ end
270
+
271
+ def should
272
+ @should
273
+ end
274
+ end
275
+
276
+ # Specify the sysidcfg file. This is pretty hackish, because it's
277
+ # only used to boot the zone the very first time.
278
+ newparam(:sysidcfg) do
279
+ desc %{The text to go into the sysidcfg file when the zone is first
280
+ booted. The best way is to use a template:
281
+
282
+ # $templatedir/sysidcfg
283
+ system_locale=en_US
284
+ timezone=GMT
285
+ terminal=xterms
286
+ security_policy=NONE
287
+ root_password=<%= password %>
288
+ timeserver=localhost
289
+ name_service=DNS {domain_name=<%= domain %>
290
+ name_server=<%= nameserver %>}
291
+ network_interface=primary {hostname=<%= name %>
292
+ ip_address=<%= ip %>
293
+ netmask=<%= netmask %>
294
+ protocol_ipv6=no
295
+ default_route=<%= defaultroute %>}
296
+ nfs4_domain=dynamic
297
+
298
+ And then call that:
299
+
300
+ zone { myzone:
301
+ ip => "bge0:192.168.0.23",
302
+ sysidcfg => template(sysidcfg),
303
+ path => "/opt/zones/myzone"
304
+ }
305
+
306
+ The sysidcfg only matters on the first booting of the zone,
307
+ so Puppet only checks for it at that time.
308
+ }
309
+ end
310
+
311
+ newparam(:path) do
312
+ desc "The root of the zone's filesystem. Must be a fully qualified
313
+ file name. If you include '%s' in the path, then it will be
314
+ replaced with the zone's name. At this point, you cannot use
315
+ Puppet to move a zone."
316
+
317
+ validate do |value|
318
+ unless value =~ /^\//
319
+ raise ArgumentError, "The zone base must be fully qualified"
320
+ end
321
+ end
322
+
323
+ munge do |value|
324
+ if value =~ /%s/
325
+ value % @parent[:name]
326
+ else
327
+ value
328
+ end
329
+ end
330
+ end
331
+
332
+ # If Puppet is also managing the base dir or its parent dir, list them
333
+ # both as prerequisites.
334
+ autorequire(:file) do
335
+ if @parameters.include? :path
336
+ [@parameters[:path].value, File.dirname(@parameters[:path].value)]
337
+ else
338
+ nil
339
+ end
340
+ end
341
+
342
+ # Convert the output of a list into a hash
343
+ def self.line2hash(line)
344
+ fields = [:id, :name, :ensure, :path]
345
+
346
+ hash = {}
347
+ line.split(":").each_with_index { |value, index|
348
+ hash[fields[index]] = value
349
+ }
350
+
351
+ # Configured but not installed zones do not have IDs
352
+ if hash[:id] == "-"
353
+ hash.delete(:id)
354
+ end
355
+
356
+ return hash
357
+ end
358
+
359
+ def self.list
360
+ %x{/usr/sbin/zoneadm list -cp}.split("\n").collect do |line|
361
+ hash = line2hash(line)
362
+
363
+ obj = nil
364
+ unless obj = @objects[hash[:name]]
365
+ obj = create(:name => hash[:name])
366
+ end
367
+
368
+ obj.setstatus(hash)
369
+
370
+ obj
371
+ end
372
+ end
373
+
374
+ # Execute a configuration string. Can't be private because it's called
375
+ # by the states.
376
+ def cfg(str)
377
+ debug "Executing '%s' in zone %s" % [str, self[:name]]
378
+ IO.popen("/usr/sbin/zonecfg -z %s -f - 2>&1" % self[:name], "w") do |pipe|
379
+ pipe.puts str
380
+ end
381
+
382
+ unless $? == 0
383
+ raise ArgumentError, "Failed to apply configuration"
384
+ end
385
+ end
386
+
387
+ # Perform all of our configuration steps.
388
+ def configure
389
+ # If the thing is entirely absent, then we need to create the config.
390
+ str = %{create -b
391
+ set zonepath=%s
392
+ } % self[:path]
393
+
394
+ # Then perform all of our configuration steps.
395
+ @states.each do |name, state|
396
+ if state.is_a? ZoneConfigState and ! state.insync?
397
+ str += state.configtext + "\n"
398
+ end
399
+ end
400
+
401
+ str += "commit\n"
402
+ cfg(str)
403
+ end
404
+
405
+ def destroy
406
+ begin
407
+ execute("/usr/sbin/zonecfg -z #{self[:name]} delete -F")
408
+ rescue Puppet::ExecutionFailure => detail
409
+ self.fail "Could not destroy zone: %s" % detail
410
+ end
411
+ end
412
+
413
+ def install
414
+ begin
415
+ execute("/usr/sbin/zoneadm -z #{self[:name]} install")
416
+ rescue Puppet::ExecutionFailure => detail
417
+ self.fail "Could not install zone: %s" % detail
418
+ end
419
+ end
420
+
421
+ # We need a way to test whether a zone is in process. Our 'ensure'
422
+ # state models the static states, but we need to handle the temporary ones.
423
+ def processing?
424
+ if hash = statushash()
425
+ case hash[:ensure]
426
+ when "incomplete", "ready", "shutting_down"
427
+ true
428
+ else
429
+ false
430
+ end
431
+ else
432
+ false
433
+ end
434
+ end
435
+
436
+ def retrieve
437
+ if hash = statushash()
438
+ setstatus(hash)
439
+
440
+ # Now retrieve the configuration itself and set appropriately.
441
+ getconfig()
442
+ else
443
+ @states.each do |name, state|
444
+ state.is = :absent
445
+ end
446
+ end
447
+ end
448
+
449
+ # Take the results of a listing and set everything appropriately.
450
+ def setstatus(hash)
451
+ hash.each do |param, value|
452
+ next if param == :name
453
+ case self.class.attrtype(param)
454
+ when :state:
455
+ self.is = [param, value]
456
+ else
457
+ self[param] = value
458
+ end
459
+ end
460
+
461
+ # For any configured items that are not found, mark absent.
462
+ @states.each do |name, st|
463
+ next unless st.is_a? ZoneConfigState
464
+
465
+ unless hash.has_key? st.name
466
+ st.is = :absent
467
+ end
468
+ end
469
+ end
470
+
471
+ def start
472
+ # Check the sysidcfg stuff
473
+ if cfg = self[:sysidcfg]
474
+ path = File.join(self[:path], "root", "etc", "sysidcfg")
475
+
476
+ unless File.exists?(path)
477
+ begin
478
+ File.open(path, "w", 0600) do |f|
479
+ f.puts cfg
480
+ end
481
+ rescue => detail
482
+ if Puppet[:debug]
483
+ puts detail.stacktrace
484
+ end
485
+ raise Puppet::Error, "Could not create sysidcfg: %s" % detail
486
+ end
487
+ end
488
+ end
489
+
490
+ begin
491
+ execute("/usr/sbin/zoneadm -z #{self[:name]} boot")
492
+ rescue Puppet::ExecutionFailure => detail
493
+ self.fail "Could not start zone: %s" % detail
494
+ end
495
+ end
496
+
497
+ def stop
498
+ begin
499
+ execute("/usr/sbin/zoneadm -z #{self[:name]} halt")
500
+ rescue Puppet::ExecutionFailure => detail
501
+ self.fail "Could not halt zone: %s" % detail
502
+ end
503
+ end
504
+
505
+ def unconfigure
506
+ begin
507
+ execute("/usr/sbin/zonecfg -z #{self[:name]} delete -F")
508
+ rescue Puppet::ExecutionFailure => detail
509
+ self.fail "Could not unconfigure zone: %s" % detail
510
+ end
511
+ end
512
+
513
+ def uninstall
514
+ begin
515
+ execute("/usr/sbin/zoneadm -z #{self[:name]} uninstall -F")
516
+ rescue Puppet::ExecutionFailure => detail
517
+ self.fail "Could not halt zone: %s" % detail
518
+ end
519
+ end
520
+
521
+ private
522
+
523
+ # Turn the results of getconfig into status information.
524
+ def config2status(config)
525
+ config.each do |name, value|
526
+ case name
527
+ when :autoboot:
528
+ self.is = [:autoboot, value.intern]
529
+ when :zonepath:
530
+ # Nothing; this is set in the zoneadm list command
531
+ when :pool:
532
+ self.is = [:pool, value]
533
+ when "inherit-pkg-dir":
534
+ dirs = value.collect do |hash|
535
+ hash[:dir]
536
+ end
537
+
538
+ self.is = [:inherit, dirs]
539
+ when "net":
540
+ vals = value.collect do |hash|
541
+ "%s:%s" % [hash[:physical], hash[:address]]
542
+ end
543
+ self.is = [:ip, vals]
544
+ end
545
+ end
546
+ end
547
+
548
+ # Collect the configuration of the zone.
549
+ def getconfig
550
+ output = execute("/usr/sbin/zonecfg -z %s info" % self[:name])
551
+
552
+ name = nil
553
+ current = nil
554
+ hash = {}
555
+ output.split("\n").each do |line|
556
+ case line
557
+ when /^(\S+):\s*$/:
558
+ name = $1
559
+ current = nil # reset it
560
+ when /^(\S+):\s*(.+)$/:
561
+ hash[$1.intern] = $2
562
+ #self.is = [$1.intern, $2]
563
+ when /^\s+(\S+):\s*(.+)$/:
564
+ if name
565
+ unless hash.include? name
566
+ hash[name] = []
567
+ end
568
+
569
+ unless current
570
+ current = {}
571
+ hash[name] << current
572
+ end
573
+ current[$1.intern] = $2
574
+ else
575
+ err "Ignoring '%s'" % line
576
+ end
577
+ else
578
+ debug "Ignoring zone output '%s'" % line
579
+ end
580
+ end
581
+ config2status(hash)
582
+ end
583
+
584
+ def statushash
585
+ begin
586
+ output = execute("/usr/sbin/zoneadm -z #{self[:name]} list -p 2>/dev/null")
587
+ rescue Puppet::ExecutionFailure => detail
588
+ return nil
589
+ end
590
+
591
+ return self.class.line2hash(output.chomp)
592
+ end
593
+ end
594
+
595
+ # $Id: zone.rb 1386 2006-07-11 18:38:42Z luke $