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,67 +1,112 @@
1
+ module Puppet
2
+ newtype(:exec) do
3
+ @doc = "Executes external commands. It is critical that all commands
4
+ executed using this mechanism can be run multiple times without
5
+ harm, i.e., they are *idempotent*. One useful way to create idempotent
6
+ commands is to use the *creates* parameter.
7
+
8
+ It is worth noting that ``exec`` is special, in that it is not
9
+ currently considered an error to have multiple ``exec`` instances
10
+ with the same name. This was done purely because it had to be this
11
+ way in order to get certain functionality, but it complicates things.
12
+ In particular, you will not be able to use ``exec`` instances that
13
+ share their commands with other instances as a dependency, since
14
+ Puppet has no way of knowing which instance you mean.
15
+
16
+ For example::
17
+
18
+ # defined in the production class
19
+ exec { \"make\":
20
+ cwd => \"/prod/build/dir\"
21
+ }
22
+
23
+ . etc. .
24
+
25
+ # defined in the test class
26
+ exec { \"make\":
27
+ cwd => \"/test/build/dir\"
28
+ }
29
+
30
+ Any other type would throw an error, complaining that you had
31
+ the same instance being managed in multiple places, but these are
32
+ obviously different images, so ``exec`` had to be treated specially.
33
+
34
+ It is recommended to avoid duplicate names whenever possible.
35
+
36
+ There is a strong tendency to use ``exec`` to do whatever work Puppet
37
+ can't already do; while this is obviously acceptable (and unavoidable)
38
+ in the short term, it is highly recommended to migrate work from ``exec``
39
+ to real Puppet element types as quickly as possible. If you find that
40
+ you are doing a lot of work with ``exec``, please at least notify
41
+ us at Reductive Labs what you are doing, and hopefully we can work with
42
+ you to get a native element type for the work you are doing. In general,
43
+ it is a Puppet bug if you need ``exec`` to do your work."
44
+
45
+ require 'open3'
46
+ require 'puppet/type/state'
47
+
48
+ newstate(:returns) do |state|
49
+ munge do |value|
50
+ value.to_s
51
+ end
1
52
 
2
- require 'open3'
3
- require 'puppet/type/state'
53
+ defaultto "0"
4
54
 
5
- module Puppet
6
- # okay, how do we deal with parameters that don't have operations
7
- # associated with them?
8
- class State
9
- # this always runs
10
- class Returns < Puppet::State
11
55
  attr_reader :output
12
-
13
- @doc = "The expected return code. An error will be returned if the
14
- executed command returns something else."
15
- @name = :returns
56
+ desc "The expected return code. An error will be returned if the
57
+ executed command returns something else. Defaults to 0."
16
58
 
17
59
  # Make output a bit prettier
18
60
  def change_to_s
19
61
  return "executed successfully"
20
62
  end
21
63
 
22
- # because this command always runs,
23
- # we're just using retrieve to verify that the command
24
- # exists and such
25
- def retrieve
26
- if file = @parent[:creates]
27
- if FileTest.exists?(file)
28
- @is = true
29
- @should = [true]
30
- return
31
- end
32
- end
33
-
64
+ # Verify that we have the executable
65
+ def checkexe
34
66
  cmd = self.parent[:command]
35
67
  if cmd =~ /^\//
36
68
  exe = cmd.split(/ /)[0]
37
69
  unless FileTest.exists?(exe)
38
- raise TypeError.new(
70
+ self.fail(
39
71
  "Could not find executable %s" % exe
40
72
  )
41
73
  end
42
74
  unless FileTest.executable?(exe)
43
- raise TypeError.new(
75
+ self.fail(
44
76
  "%s is not executable" % exe
45
77
  )
46
78
  end
47
79
  elsif path = self.parent[:path]
48
80
  exe = cmd.split(/ /)[0]
49
81
  tmppath = ENV["PATH"]
50
- ENV["PATH"] = self.parent[:path]
82
+ ENV["PATH"] = self.parent[:path].join(":")
51
83
 
52
84
  path = %{which #{exe}}.chomp
53
85
  if path == ""
54
- raise TypeError.new(
86
+ self.fail(
55
87
  "Could not find command '%s'" % exe
56
88
  )
57
89
  end
58
90
  ENV["PATH"] = tmppath
59
91
  else
60
- raise TypeError.new(
92
+ self.fail(
61
93
  "%s is somehow not qualified with no search path" %
62
94
  self.parent[:command]
63
95
  )
64
96
  end
97
+ end
98
+
99
+ # because this command always runs,
100
+ # we're just using retrieve to verify that the command
101
+ # exists and such
102
+ def retrieve
103
+ if file = @parent[:creates]
104
+ if FileTest.exists?(file)
105
+ @is = true
106
+ @should = [true]
107
+ return
108
+ end
109
+ end
65
110
 
66
111
  if self.parent[:refreshonly]
67
112
  # if refreshonly is enabled, then set things so we
@@ -77,27 +122,24 @@ module Puppet
77
122
  def sync
78
123
  olddir = nil
79
124
 
125
+ self.checkexe
126
+
80
127
  # We need a dir to change to, even if it's just the cwd
81
128
  dir = self.parent[:cwd] || Dir.pwd
82
129
  tmppath = ENV["PATH"]
83
130
 
131
+ event = :executed_command
84
132
  begin
85
133
  # Do our chdir
86
134
  Dir.chdir(dir) {
87
- ENV["PATH"] = self.parent[:path]
135
+ if self.parent[:path]
136
+ ENV["PATH"] = self.parent[:path].join(":")
137
+ end
88
138
 
89
139
  # The user and group default to nil, which 'asuser'
90
140
  # handlers correctly
91
141
  Puppet::Util.asuser(@parent[:user], @parent[:group]) {
92
142
  # capture both stdout and stderr
93
-
94
- #stdin, stdout, stderr = Open3.popen3(self.parent[:command])
95
- #@output = stdout.read
96
- #err = stderr.read
97
-
98
- #stderr = Puppet::Util.capture_stderr {
99
- # @output = %x{#{self.parent[:command]}}
100
- #}
101
143
  if @parent[:user]
102
144
  unless defined? @@alreadywarned
103
145
  Puppet.warning(
@@ -109,12 +151,6 @@ module Puppet
109
151
  else
110
152
  @output = %x{#{self.parent[:command]} 2>&1}
111
153
  end
112
-
113
- #if err != ""
114
- # stderr.split(/\n/).each { |line|
115
- # self.send(:err, line)
116
- # }
117
- #end
118
154
  }
119
155
  status = $?
120
156
 
@@ -125,6 +161,7 @@ module Puppet
125
161
 
126
162
  # if we've had a failure, up the log level
127
163
  loglevel = :err
164
+ event = :failed_command
128
165
  end
129
166
 
130
167
  # and log
@@ -133,131 +170,76 @@ module Puppet
133
170
  }
134
171
  }
135
172
  rescue Errno::ENOENT => detail
136
- raise Puppet::Error, detail.to_s
173
+ self.fail detail.to_s
137
174
  ensure
138
175
  # reset things to how we found them
139
176
  ENV["PATH"] = tmppath
140
177
  end
141
178
 
142
- return :executed_command
179
+ return event
143
180
  end
144
181
  end
145
- end
146
182
 
147
- class Type
148
- class Exec < Type
149
- # this is kind of hackish, using the return value as the
150
- # state, but apparently namevars can't also be states
151
- # who knew?
152
- @states = [
153
- Puppet::State::Returns
154
- ]
155
-
156
- @parameters = [
157
- :path,
158
- :user,
159
- :group,
160
- :creates,
161
- :cwd,
162
- :refreshonly,
163
- :command
164
- ]
165
-
166
- @paramdoc[:path] = "The search path used for command execution.
167
- Commands must be fully qualified if no path is specified."
168
- @paramdoc[:user] = "The user to run the command as. Note that if you use
169
- this then any error output is not currently captured. This is mostly
170
- because of a bug within Ruby."
171
- @paramdoc[:group] = "The group to run the command as."
172
- @paramdoc[:cwd] = "The directory from which to run the command. If
173
- this directory does not exist, the command will fail."
174
- @paramdoc[:refreshonly] = "The command should only be run as a
175
- refresh mechanism for when a dependent object is changed."
176
- @paramdoc[:command] = "The actual command to execute."
177
- @paramdoc[:creates] = "A file that this command creates. If this
178
- parameter is provided, then the command will only be run
179
- if the specified file does not exist."
180
-
181
- @doc = "Executes external commands. It is critical that all commands
182
- executed using this mechanism can be run multiple times without
183
- harm, i.e., they are *idempotent*. One useful way to create idempotent
184
- commands is to use the *creates* parameter.
185
-
186
- It is worth nothing that ``exec`` is special, in that it is not
187
- currently considered an error to have multiple ``exec`` instances
188
- with the same name. This was done purely because it had to be this
189
- way in order to get certain functionality, but it complicates things.
190
- In particular, you will not be able to use ``exec`` instances that
191
- share their commands with other instances as a dependency, since
192
- Puppet has no way of knowing which instance you mean.
193
-
194
- It is recommended to avoid duplicate names whenever possible."
195
- @name = :exec
196
- @namevar = :command
197
-
198
- # Exec names are not isomorphic with the objects.
199
- @isomorphic = false
200
-
201
- def initialize(hash)
202
- # default to erroring on a non-zero return
203
- if hash.include?("returns")
204
- if hash["returns"].is_a?(Fixnum)
205
- hash["returns"] = hash["returns"].to_s
206
- end
207
- elsif hash.include?(:returns)
208
- if hash[:returns].is_a?(Fixnum)
209
- hash[:returns] = hash[:returns].to_s
210
- end
211
- else
212
- hash[:returns] = "0"
213
- end
214
-
215
- super
183
+ newparam(:command) do
184
+ isnamevar
185
+ desc "The actual command to execute. Must either be fully qualified
186
+ or a search path for the command must be provided. If the command
187
+ succeeds, any output produced will be logged at the instance's
188
+ normal log level (usually ``notice``), but if the command fails
189
+ (meaning its return code does not match the specified code) then
190
+ any output is logged at the ``err`` log level."
191
+ end
216
192
 
217
- if self[:command].nil?
218
- raise TypeError.new("Somehow the command is nil")
219
- end
193
+ newparam(:path) do
194
+ desc "The search path used for command execution.
195
+ Commands must be fully qualified if no path is specified. Paths
196
+ can be specified as an array or as a colon-separated list."
220
197
 
221
- # if we're not fully qualified, require a path
222
- if self[:command] !~ /^\//
223
- if self[:path].nil?
224
- raise TypeError,
225
- "both unqualifed and specified no search path"
226
- end
227
- end
198
+ # Support both arrays and colon-separated fields.
199
+ def value=(*values)
200
+ @value = values.collect { |val|
201
+ val.split(":")
202
+ }.flatten
228
203
  end
204
+ end
229
205
 
230
- def output
231
- if self.state(:returns).nil?
232
- return nil
233
- else
234
- return self.state(:returns).output
235
- end
236
- end
206
+ newparam(:user) do
207
+ desc "The user to run the command as. Note that if you
208
+ use this then any error output is not currently captured. This
209
+ is because of a bug within Ruby."
237
210
 
238
- # FIXME if they try to set this and fail, then we should probably
239
- # fail the entire exec, right?
240
- def paramcreates=(file)
241
- unless file =~ %r{^#{File::SEPARATOR}}
242
- raise Puppet::Error, "'creates' files must be fully qualified."
211
+ munge do |user|
212
+ unless Process.uid == 0
213
+ self.fail "Only root can execute commands as other users"
243
214
  end
244
- @parameters[:creates] = file
245
- end
215
+ require 'etc'
246
216
 
247
- def paramcwd=(dir)
248
- if dir.is_a?(Array)
249
- dir = dir[0]
217
+ method = :getpwnam
218
+ case user
219
+ when Integer
220
+ method = :getpwuid
221
+ when /^\d+$/
222
+ user = user.to_i
223
+ method = :getpwuid
250
224
  end
251
-
252
- unless File.directory?(dir)
253
- raise Puppet::Error, "Directory '%s' does not exist" % dir
225
+ begin
226
+ Etc.send(method, user)
227
+ rescue ArgumentError
228
+ self.fail "No such user %s" % user
254
229
  end
255
230
 
256
- @parameters[:cwd] = dir
231
+ return user
257
232
  end
233
+ end
234
+
235
+ newparam(:group) do
236
+ desc "The group to run the command as. This seems to work quite
237
+ haphazardly on different platforms -- it is a platform issue
238
+ not a Ruby or Puppet one, since the same variety exists when
239
+ running commnands as different users in the shell."
258
240
 
259
241
  # Execute the command as the specified group
260
- def paramgroup=(group)
242
+ munge do |group|
261
243
  require 'etc'
262
244
  method = :getgrnam
263
245
  case group
@@ -270,47 +252,125 @@ module Puppet
270
252
  begin
271
253
  Etc.send(method, group)
272
254
  rescue ArgumentError
273
- raise Puppet::Error, "No such group %s" % group
255
+ self.fail "No such group %s" % group
274
256
  end
275
257
 
276
- @parameters[:group] = group
258
+ group
277
259
  end
260
+ end
278
261
 
279
- # Execute the command as the specified user
280
- def paramuser=(user)
281
- unless Process.uid == 0
282
- raise Puppet::Error,
283
- "Only root can execute commands as other users"
262
+ newparam(:cwd) do
263
+ desc "The directory from which to run the command. If
264
+ this directory does not exist, the command will fail."
265
+
266
+ munge do |dir|
267
+ if dir.is_a?(Array)
268
+ dir = dir[0]
284
269
  end
285
- require 'etc'
286
270
 
287
- method = :getpwnam
288
- case user
289
- when Integer
290
- method = :getpwuid
291
- when /^\d+$/
292
- user = user.to_i
293
- method = :getpwuid
271
+ unless File.directory?(dir)
272
+ self.fail "Directory '%s' does not exist" % dir
294
273
  end
295
- begin
296
- Etc.send(method, user)
297
- rescue ArgumentError
298
- raise Puppet::Error, "No such user %s" % user
274
+
275
+ dir
276
+ end
277
+ end
278
+
279
+ newparam(:refreshonly) do
280
+ desc "The command should only be run as a
281
+ refresh mechanism for when a dependent object is changed. It only
282
+ makes sense to use this option when this command depends on some
283
+ other object; it is useful for triggering an action::
284
+
285
+ # Pull down the main aliases file
286
+ file { \"/etc/aliases\":
287
+ source => \"puppet://server/module/aliases\"
288
+ }
289
+
290
+ # Rebuild the database, but only when the file changes
291
+ exec { newaliases:
292
+ path => [\"/usr/bin\", \"/usr/sbin\"],
293
+ require => file[\"/etc/aliases\"],
294
+ refreshonly => true
295
+ }
296
+
297
+ "
298
+ end
299
+
300
+ newparam(:creates) do
301
+ desc "A file that this command creates. If this
302
+ parameter is provided, then the command will only be run
303
+ if the specified file does not exist.
304
+
305
+ ::
306
+
307
+ exec { \"tar xf /my/tar/file.tar\":
308
+ cwd => \"/var/tmp\",
309
+ creates => \"/var/tmp/myfile\",
310
+ path => [\"/usr/bin\", \"/usr/sbin\"]
311
+ }
312
+
313
+ "
314
+
315
+ # FIXME if they try to set this and fail, then we should probably
316
+ # fail the entire exec, right?
317
+ validate do |file|
318
+ unless file =~ %r{^#{File::SEPARATOR}}
319
+ self.fail "'creates' files must be fully qualified."
299
320
  end
321
+ end
322
+ end
323
+
324
+ # Exec names are not isomorphic with the objects.
325
+ @isomorphic = false
326
+
327
+ validate do
328
+ # if we're not fully qualified, require a path
329
+ if self[:command] !~ /^\//
330
+ if self[:path].nil?
331
+ self.fail "both unqualifed and specified no search path"
332
+ end
333
+ end
334
+ end
335
+
336
+ autorequire(:file) do
337
+ reqs = []
300
338
 
301
- @parameters[:user] = user
339
+ # Stick the cwd in there if we have it
340
+ if self[:cwd]
341
+ reqs << self[:cwd]
302
342
  end
303
343
 
304
- # this might be a very, very bad idea...
305
- def refresh
306
- self.state(:returns).sync
344
+ tmp = self[:command].dup
345
+
346
+ # And search the command line for files, adding any we find. This
347
+ # will also catch the command itself if it's fully qualified. It might
348
+ # not be a bad idea to add unqualified files, but, well, that's a
349
+ # bit more annoying to do.
350
+ while tmp.sub!(%r{(#{File::SEPARATOR}\S+)}, '')
351
+ reqs << $1
307
352
  end
308
353
 
309
- def to_s
310
- "exec(%s)" % self.name
354
+ reqs
355
+ end
356
+
357
+ def output
358
+ if self.state(:returns).nil?
359
+ return nil
360
+ else
361
+ return self.state(:returns).output
311
362
  end
312
363
  end
364
+
365
+ # this might be a very, very bad idea...
366
+ def refresh
367
+ self.state(:returns).sync
368
+ end
369
+
370
+ def to_s
371
+ "exec(%s)" % self.name
372
+ end
313
373
  end
314
374
  end
315
375
 
316
- # $Id: exec.rb 743 2005-11-16 21:39:31Z luke $
376
+ # $Id: exec.rb 841 2006-01-18 17:24:15Z luke $