puppet 0.13.1 → 0.13.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puppet might be problematic. Click here for more details.
- data/CHANGELOG +4 -0
- data/Rakefile +2 -2
- data/bin/puppet +29 -0
- data/bin/puppetd +35 -1
- data/conf/redhat/puppet.spec +1 -1
- data/lib/puppet.rb +1 -1
- data/lib/puppet/client/master.rb +34 -3
- data/lib/puppet/filetype.rb +6 -2
- data/lib/puppet/networkclient.rb +4 -1
- data/lib/puppet/parameter.rb +35 -38
- data/lib/puppet/parser/ast/node.rb +1 -0
- data/lib/puppet/parser/interpreter.rb +129 -2
- data/lib/puppet/parser/scope.rb +44 -6
- data/lib/puppet/type.rb +47 -37
- data/lib/puppet/type/cron.rb +25 -10
- data/lib/puppet/type/exec.rb +165 -71
- data/lib/puppet/type/nameservice.rb +2 -17
- data/lib/puppet/type/package.rb +31 -7
- data/lib/puppet/type/package/sun.rb +11 -6
- data/lib/puppet/type/parsedtype.rb +94 -60
- data/lib/puppet/type/parsedtype/host.rb +5 -12
- data/lib/puppet/type/parsedtype/port.rb +53 -32
- data/lib/puppet/type/parsedtype/sshkey.rb +8 -4
- data/lib/puppet/type/pfile.rb +6 -4
- data/lib/puppet/type/pfile/ensure.rb +1 -6
- data/lib/puppet/type/state.rb +34 -74
- data/lib/puppet/type/symlink.rb +30 -19
- data/lib/puppet/type/user.rb +63 -11
- data/lib/puppet/util.rb +54 -60
- data/test/client/master.rb +72 -0
- data/test/language/interpreter.rb +94 -0
- data/test/other/log.rb +8 -1
- data/test/puppet/utiltest.rb +101 -1
- data/test/test +12 -5
- data/test/types/cron.rb +21 -1
- data/test/types/exec.rb +46 -2
- data/test/types/group.rb +15 -3
- data/test/types/host.rb +43 -4
- data/test/types/port.rb +67 -6
- data/test/types/sshkey.rb +45 -4
- data/test/types/symlink.rb +4 -4
- data/test/types/type.rb +41 -3
- data/test/types/user.rb +23 -2
- metadata +3 -2
data/lib/puppet/parser/scope.rb
CHANGED
@@ -169,9 +169,16 @@ module Puppet
|
|
169
169
|
# Evaluate a specific node's code. This method will normally be called
|
170
170
|
# on the top-level scope, but it actually evaluates the node at the
|
171
171
|
# appropriate scope.
|
172
|
-
def evalnode(names, facts)
|
173
|
-
|
172
|
+
def evalnode(names, facts, classes = nil, parent = nil)
|
173
|
+
# First make sure there aren't any other node scopes lying around
|
174
|
+
self.nodeclean
|
174
175
|
|
176
|
+
# If they've passed classes in, then just generate from there.
|
177
|
+
if classes
|
178
|
+
return self.gennode(names, facts, classes, parent)
|
179
|
+
end
|
180
|
+
|
181
|
+
scope = code = nil
|
175
182
|
# Find a node that matches one of our names
|
176
183
|
names.each { |node|
|
177
184
|
if hash = @nodetable[node]
|
@@ -187,9 +194,6 @@ module Puppet
|
|
187
194
|
names.join(" or ")
|
188
195
|
end
|
189
196
|
|
190
|
-
# First make sure there aren't any other node scopes lying around
|
191
|
-
self.nodeclean
|
192
|
-
|
193
197
|
# We need to do a little skullduggery here. We want a
|
194
198
|
# temporary scope, because we don't want this scope to
|
195
199
|
# show up permanently in the scope tree -- otherwise we could
|
@@ -221,6 +225,40 @@ module Puppet
|
|
221
225
|
return objects
|
222
226
|
end
|
223
227
|
|
228
|
+
# Pull in all of the appropriate classes and evaluate them. It'd
|
229
|
+
# be nice if this didn't know quite so much about how AST::Node
|
230
|
+
# operated internally.
|
231
|
+
def gennode(names, facts, classes, parent)
|
232
|
+
name = names.shift
|
233
|
+
arghash = {
|
234
|
+
:name => name,
|
235
|
+
:code => AST::ASTArray.new(:pin => "[]")
|
236
|
+
}
|
237
|
+
|
238
|
+
if parent
|
239
|
+
arghash[:parentclass] = parent
|
240
|
+
end
|
241
|
+
|
242
|
+
# Create the node
|
243
|
+
node = AST::Node.new(arghash)
|
244
|
+
node.keyword = "node"
|
245
|
+
node.name = name
|
246
|
+
|
247
|
+
# Now evaluate it, which evaluates the parent but doesn't really
|
248
|
+
# do anything else but does return the nodescope
|
249
|
+
scope = node.safeevaluate(self)
|
250
|
+
|
251
|
+
# And now evaluate each set klass within the nodescope.
|
252
|
+
classes.each { |klass|
|
253
|
+
if code = scope.lookuptype(klass)
|
254
|
+
Puppet.warning "evaluating %s" % klass
|
255
|
+
code.safeevaluate(scope, {}, klass, klass)
|
256
|
+
end
|
257
|
+
}
|
258
|
+
|
259
|
+
return scope.to_trans
|
260
|
+
end
|
261
|
+
|
224
262
|
# Retrieve a specific node. This is used in ast.rb to find a
|
225
263
|
# parent node and in findnode to retrieve and evaluate a node.
|
226
264
|
def node(name)
|
@@ -773,4 +811,4 @@ module Puppet
|
|
773
811
|
end
|
774
812
|
end
|
775
813
|
|
776
|
-
# $Id: scope.rb
|
814
|
+
# $Id: scope.rb 909 2006-02-14 06:21:04Z luke $
|
data/lib/puppet/type.rb
CHANGED
@@ -452,6 +452,8 @@ class Type < Puppet::Element
|
|
452
452
|
|
453
453
|
@@metaparamhash ||= {}
|
454
454
|
@@metaparams.each { |p| @@metaparamhash[name] = p }
|
455
|
+
|
456
|
+
return param
|
455
457
|
end
|
456
458
|
|
457
459
|
def self.eachmetaparam
|
@@ -486,6 +488,8 @@ class Type < Puppet::Element
|
|
486
488
|
if param.isnamevar?
|
487
489
|
@namevar = param.name
|
488
490
|
end
|
491
|
+
|
492
|
+
return param
|
489
493
|
end
|
490
494
|
|
491
495
|
# Create a new state.
|
@@ -896,13 +900,17 @@ class Type < Puppet::Element
|
|
896
900
|
# in order resolve other questions, such as finding a package
|
897
901
|
# in a list
|
898
902
|
def managed?
|
899
|
-
|
903
|
+
# Once an object is managed, it always stays managed; but an object
|
904
|
+
# that is listed as unmanaged might become managed later in the process,
|
905
|
+
# so we have to check that every time
|
906
|
+
if defined? @managed and @managed
|
900
907
|
return @managed
|
901
908
|
else
|
902
909
|
@managed = false
|
903
910
|
states.each { |state|
|
904
911
|
if state.should and ! state.class.unmanaged
|
905
912
|
@managed = true
|
913
|
+
break
|
906
914
|
end
|
907
915
|
}
|
908
916
|
return @managed
|
@@ -1103,10 +1111,16 @@ class Type < Puppet::Element
|
|
1103
1111
|
|
1104
1112
|
return retobj
|
1105
1113
|
else
|
1114
|
+
# If only one of the objects is being managed, then merge them
|
1115
|
+
if retobj.managed?
|
1116
|
+
raise Puppet::Error, "%s '%s' is already being managed" %
|
1117
|
+
[self.name, name]
|
1118
|
+
else
|
1119
|
+
retobj.merge(hash)
|
1120
|
+
return retobj
|
1121
|
+
end
|
1106
1122
|
# We will probably want to support merging of some kind in
|
1107
1123
|
# the future, but for now, just throw an error.
|
1108
|
-
raise Puppet::Error, "%s '%s' is already being managed" %
|
1109
|
-
[self.name, name]
|
1110
1124
|
#retobj.merge(hash)
|
1111
1125
|
|
1112
1126
|
#return retobj
|
@@ -1337,6 +1351,13 @@ class Type < Puppet::Element
|
|
1337
1351
|
if self.respond_to?(:validate)
|
1338
1352
|
self.validate
|
1339
1353
|
end
|
1354
|
+
|
1355
|
+
# Ensure defaults to present for managed objects, but not otherwise.
|
1356
|
+
# Because of this complication, we can't use normal defaulting mechanisms
|
1357
|
+
# if ! @states.include?(:ensure) and self.managed? and
|
1358
|
+
# self.class.validstate?(:ensure)
|
1359
|
+
# self[:ensure] = :present
|
1360
|
+
# end
|
1340
1361
|
end
|
1341
1362
|
|
1342
1363
|
# Figure out of there are any objects we can automatically add as
|
@@ -1354,12 +1375,19 @@ class Type < Puppet::Element
|
|
1354
1375
|
|
1355
1376
|
# Collect the current prereqs
|
1356
1377
|
list.each { |dep|
|
1357
|
-
|
1358
|
-
|
1378
|
+
obj = nil
|
1379
|
+
# Support them passing objects directly, to save some effort.
|
1380
|
+
if dep.is_a? Puppet::Type
|
1381
|
+
type = dep.class.name
|
1382
|
+
obj = dep
|
1383
|
+
else
|
1384
|
+
# Skip autorequires that we aren't managing
|
1385
|
+
next unless obj = typeobj[dep]
|
1386
|
+
end
|
1359
1387
|
|
1360
1388
|
# Skip autorequires that we already require
|
1361
1389
|
next if self.requires?(obj)
|
1362
|
-
self.info "Auto-requiring %s" % obj.name
|
1390
|
+
#self.info "Auto-requiring %s %s" % [obj.class.name, obj.name]
|
1363
1391
|
|
1364
1392
|
self[:require] = [type, dep]
|
1365
1393
|
}
|
@@ -1469,8 +1497,14 @@ class Type < Puppet::Element
|
|
1469
1497
|
next if self.attrset?(type, klass.name)
|
1470
1498
|
|
1471
1499
|
obj = self.newattr(type, klass)
|
1472
|
-
|
1473
|
-
|
1500
|
+
value = obj.default
|
1501
|
+
unless value.nil?
|
1502
|
+
#self.debug "defaulting %s to %s" % [obj.name, obj.default]
|
1503
|
+
obj.value = value
|
1504
|
+
else
|
1505
|
+
#self.debug "No default for %s" % obj.name
|
1506
|
+
self.delete(obj.name)
|
1507
|
+
end
|
1474
1508
|
}
|
1475
1509
|
|
1476
1510
|
end
|
@@ -1493,7 +1527,7 @@ class Type < Puppet::Element
|
|
1493
1527
|
value = [value]
|
1494
1528
|
end
|
1495
1529
|
|
1496
|
-
if oldvals = @states[param].shouldorig
|
1530
|
+
if @states.include?(param) and oldvals = @states[param].shouldorig
|
1497
1531
|
unless oldvals.is_a?(Array)
|
1498
1532
|
oldvals = [oldvals]
|
1499
1533
|
end
|
@@ -1521,6 +1555,9 @@ class Type < Puppet::Element
|
|
1521
1555
|
self[param] = value
|
1522
1556
|
end
|
1523
1557
|
}
|
1558
|
+
|
1559
|
+
# Set the defaults again, just in case.
|
1560
|
+
self.setdefaults
|
1524
1561
|
end
|
1525
1562
|
|
1526
1563
|
# derive the instance name based on class.namevar
|
@@ -1654,23 +1691,9 @@ class Type < Puppet::Element
|
|
1654
1691
|
@evalcount = 0
|
1655
1692
|
end
|
1656
1693
|
@@retrieved[self] += 1
|
1657
|
-
# if we're a metaclass and we've already evaluated once...
|
1658
|
-
#if self.metaclass and @evalcount > 0
|
1659
|
-
# return
|
1660
|
-
#end
|
1661
1694
|
@evalcount += 1
|
1662
1695
|
|
1663
|
-
#changes = @children.collect { |child|
|
1664
|
-
# child.evaluate
|
1665
|
-
#}
|
1666
|
-
|
1667
1696
|
changes = []
|
1668
|
-
# collect all of the changes from children and states
|
1669
|
-
#if self.class.depthfirst?
|
1670
|
-
# changes << self.collect { |child|
|
1671
|
-
# child.evaluate
|
1672
|
-
# }
|
1673
|
-
#end
|
1674
1697
|
|
1675
1698
|
# this only operates on states, not states + children
|
1676
1699
|
# it's important that we call retrieve() on the type instance,
|
@@ -1694,16 +1717,6 @@ class Type < Puppet::Element
|
|
1694
1717
|
child.cache(:checked, now)
|
1695
1718
|
ch
|
1696
1719
|
}
|
1697
|
-
#unless self.class.depthfirst?
|
1698
|
-
# changes << self.collect { |child|
|
1699
|
-
# child.evaluate
|
1700
|
-
# }
|
1701
|
-
#end
|
1702
|
-
# collect changes and return them
|
1703
|
-
# these changes could be from child objects or from contained states
|
1704
|
-
#self.collect { |child|
|
1705
|
-
# child.evaluate
|
1706
|
-
#}
|
1707
1720
|
|
1708
1721
|
if self.class.depthfirst?
|
1709
1722
|
changes += statechanges()
|
@@ -1716,9 +1729,6 @@ class Type < Puppet::Element
|
|
1716
1729
|
if changes.length > 0
|
1717
1730
|
self.info "%s change(s)" %
|
1718
1731
|
[changes.length]
|
1719
|
-
#changes.each { |change|
|
1720
|
-
# self.debug "change: %s" % change.state.name
|
1721
|
-
#}
|
1722
1732
|
end
|
1723
1733
|
self.cache(:checked, now)
|
1724
1734
|
return changes.flatten
|
@@ -2199,4 +2209,4 @@ require 'puppet/type/user'
|
|
2199
2209
|
require 'puppet/type/tidy'
|
2200
2210
|
require 'puppet/type/parsedtype'
|
2201
2211
|
|
2202
|
-
# $Id: type.rb
|
2212
|
+
# $Id: type.rb 914 2006-02-15 21:04:14Z luke $
|
data/lib/puppet/type/cron.rb
CHANGED
@@ -103,6 +103,11 @@ module Puppet
|
|
103
103
|
# a boolean of whether to do alpha checking, and if so requires
|
104
104
|
# the ary against which to do the checking.
|
105
105
|
munge do |value|
|
106
|
+
# Support 'absent' as a value, so that they can remove
|
107
|
+
# a value
|
108
|
+
if value == "absent" or value == :absent
|
109
|
+
return :absent
|
110
|
+
end
|
106
111
|
return value unless self.class.boundaries
|
107
112
|
lower, upper = self.class.boundaries
|
108
113
|
retval = nil
|
@@ -135,7 +140,10 @@ module Puppet
|
|
135
140
|
provided to the command varies by local system rules, and it is
|
136
141
|
best to always provide a fully qualified command. The user's
|
137
142
|
profile is not sourced when the command is run, so if the
|
138
|
-
user's environment is desired it should be sourced manually.
|
143
|
+
user's environment is desired it should be sourced manually.
|
144
|
+
|
145
|
+
All cron parameters support ``absent`` as a value; this will
|
146
|
+
remove any existing values for that field."
|
139
147
|
end
|
140
148
|
|
141
149
|
newstate(:minute, CronParam) do
|
@@ -178,12 +186,13 @@ module Puppet
|
|
178
186
|
|
179
187
|
newparam(:name) do
|
180
188
|
desc "The symbolic name of the cron job. This name
|
181
|
-
is used for human reference only and is generated
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
189
|
+
is used for human reference only and is generated automatically
|
190
|
+
for cron jobs found on the system. This generally won't
|
191
|
+
matter, as Puppet will do its best to match existing cron jobs
|
192
|
+
against specified jobs (and Puppet adds a tag to cron jobs it
|
193
|
+
adds), but it is at least possible that converting from
|
194
|
+
unmanaged jobs to managed jobs might require manual
|
195
|
+
intervention."
|
187
196
|
|
188
197
|
isnamevar
|
189
198
|
end
|
@@ -487,7 +496,9 @@ module Puppet
|
|
487
496
|
|
488
497
|
def exists?
|
489
498
|
val = false
|
490
|
-
if @states.include?(:command) and
|
499
|
+
if @states.include?(:command) and
|
500
|
+
@states[:command].is != :absent and
|
501
|
+
! @states[:command].is.nil?
|
491
502
|
val = true
|
492
503
|
end
|
493
504
|
return val
|
@@ -523,10 +534,14 @@ module Puppet
|
|
523
534
|
|
524
535
|
return "# Puppet Name: %s\n" % self.name +
|
525
536
|
self.class.fields.collect { |f|
|
526
|
-
hash[f]
|
537
|
+
if hash[f] and hash[f] != :absent
|
538
|
+
hash[f]
|
539
|
+
else
|
540
|
+
"*"
|
541
|
+
end
|
527
542
|
}.join(" ")
|
528
543
|
end
|
529
544
|
end
|
530
545
|
end
|
531
546
|
|
532
|
-
# $Id: cron.rb
|
547
|
+
# $Id: cron.rb 910 2006-02-15 07:20:36Z luke $
|
data/lib/puppet/type/exec.rb
CHANGED
@@ -17,14 +17,16 @@ module Puppet
|
|
17
17
|
|
18
18
|
# defined in the production class
|
19
19
|
exec { \"make\":
|
20
|
-
cwd => \"/prod/build/dir\"
|
20
|
+
cwd => \"/prod/build/dir\",
|
21
|
+
path => \"/usr/bin:/usr/sbin:/bin\"
|
21
22
|
}
|
22
23
|
|
23
24
|
. etc. .
|
24
25
|
|
25
26
|
# defined in the test class
|
26
27
|
exec { \"make\":
|
27
|
-
cwd => \"/test/build/dir\"
|
28
|
+
cwd => \"/test/build/dir\",
|
29
|
+
path => \"/usr/bin:/usr/sbin:/bin\"
|
28
30
|
}
|
29
31
|
|
30
32
|
Any other type would throw an error, complaining that you had
|
@@ -45,6 +47,19 @@ module Puppet
|
|
45
47
|
require 'open3'
|
46
48
|
require 'puppet/type/state'
|
47
49
|
|
50
|
+
# Create a new check mechanism. It's basically just a parameter that provides
|
51
|
+
# one extra 'check' method.
|
52
|
+
def self.newcheck(name, &block)
|
53
|
+
@checks ||= {}
|
54
|
+
|
55
|
+
check = newparam(name, &block)
|
56
|
+
@checks[name] = check
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.checks
|
60
|
+
@checks.keys
|
61
|
+
end
|
62
|
+
|
48
63
|
newstate(:returns) do |state|
|
49
64
|
munge do |value|
|
50
65
|
value.to_s
|
@@ -96,25 +111,14 @@ module Puppet
|
|
96
111
|
end
|
97
112
|
end
|
98
113
|
|
99
|
-
#
|
100
|
-
# we're just using retrieve to verify that the command
|
101
|
-
# exists and such
|
114
|
+
# First verify that all of our checks pass.
|
102
115
|
def retrieve
|
103
|
-
|
104
|
-
if FileTest.exists?(file)
|
105
|
-
@is = true
|
106
|
-
@should = [true]
|
107
|
-
return
|
108
|
-
end
|
109
|
-
end
|
116
|
+
# Default to somethinng
|
110
117
|
|
111
|
-
if
|
112
|
-
|
113
|
-
# won't sync
|
114
|
-
self.is = self.should
|
118
|
+
if @parent.check
|
119
|
+
self.is = :notrun
|
115
120
|
else
|
116
|
-
|
117
|
-
self.is = nil
|
121
|
+
self.is = self.should
|
118
122
|
end
|
119
123
|
end
|
120
124
|
|
@@ -129,53 +133,24 @@ module Puppet
|
|
129
133
|
tmppath = ENV["PATH"]
|
130
134
|
|
131
135
|
event = :executed_command
|
132
|
-
begin
|
133
|
-
# Do our chdir
|
134
|
-
Dir.chdir(dir) {
|
135
|
-
if self.parent[:path]
|
136
|
-
ENV["PATH"] = self.parent[:path].join(":")
|
137
|
-
end
|
138
136
|
|
139
|
-
|
140
|
-
# handlers correctly
|
141
|
-
Puppet::Util.asuser(@parent[:user], @parent[:group]) {
|
142
|
-
# capture both stdout and stderr
|
143
|
-
if @parent[:user]
|
144
|
-
unless defined? @@alreadywarned
|
145
|
-
Puppet.warning(
|
146
|
-
"Cannot capture STDERR when running as another user"
|
147
|
-
)
|
148
|
-
@@alreadywarned = true
|
149
|
-
end
|
150
|
-
@output = %x{#{self.parent[:command]}}
|
151
|
-
else
|
152
|
-
@output = %x{#{self.parent[:command]} 2>&1}
|
153
|
-
end
|
154
|
-
}
|
155
|
-
status = $?
|
137
|
+
@output, status = @parent.run(self.parent[:command])
|
156
138
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
139
|
+
loglevel = @parent[:loglevel]
|
140
|
+
if status.exitstatus.to_s != self.should.to_s
|
141
|
+
err("%s returned %s instead of %s" %
|
142
|
+
[self.parent[:command], status.exitstatus, self.should.to_s])
|
161
143
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
end
|
166
|
-
|
167
|
-
# and log
|
168
|
-
@output.split(/\n/).each { |line|
|
169
|
-
self.send(loglevel, line)
|
170
|
-
}
|
171
|
-
}
|
172
|
-
rescue Errno::ENOENT => detail
|
173
|
-
self.fail detail.to_s
|
174
|
-
ensure
|
175
|
-
# reset things to how we found them
|
176
|
-
ENV["PATH"] = tmppath
|
144
|
+
# if we've had a failure, up the log level
|
145
|
+
loglevel = :err
|
146
|
+
event = :failed_command
|
177
147
|
end
|
178
148
|
|
149
|
+
# and log
|
150
|
+
@output.split(/\n/).each { |line|
|
151
|
+
self.send(loglevel, line)
|
152
|
+
}
|
153
|
+
|
179
154
|
return event
|
180
155
|
end
|
181
156
|
end
|
@@ -276,7 +251,7 @@ module Puppet
|
|
276
251
|
end
|
277
252
|
end
|
278
253
|
|
279
|
-
|
254
|
+
newcheck(:refreshonly) do
|
280
255
|
desc "The command should only be run as a
|
281
256
|
refresh mechanism for when a dependent object is changed. It only
|
282
257
|
makes sense to use this option when this command depends on some
|
@@ -295,9 +270,15 @@ module Puppet
|
|
295
270
|
}
|
296
271
|
|
297
272
|
"
|
273
|
+
|
274
|
+
# We always fail this test, because we're only supposed to run
|
275
|
+
# on refresh.
|
276
|
+
def check
|
277
|
+
false
|
278
|
+
end
|
298
279
|
end
|
299
280
|
|
300
|
-
|
281
|
+
newcheck(:creates) do
|
301
282
|
desc "A file that this command creates. If this
|
302
283
|
parameter is provided, then the command will only be run
|
303
284
|
if the specified file does not exist.
|
@@ -319,6 +300,59 @@ module Puppet
|
|
319
300
|
self.fail "'creates' files must be fully qualified."
|
320
301
|
end
|
321
302
|
end
|
303
|
+
|
304
|
+
# If the file exists, return false (i.e., don't run the command),
|
305
|
+
# else return true
|
306
|
+
def check
|
307
|
+
return ! FileTest.exists?(self.value)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
newcheck(:unless) do
|
312
|
+
desc "If this parameter is set, then this +exec+ will run unless
|
313
|
+
the command returns 0. For example::
|
314
|
+
|
315
|
+
exec { \"/bin/echo root >> /usr/lib/cron/cron.allow\":
|
316
|
+
path => \"/usr/bin:/usr/sbin:/bin\",
|
317
|
+
unless => \"grep root /usr/lib/cron/cron.allow 2>/dev/null\"
|
318
|
+
}
|
319
|
+
|
320
|
+
This would add +root+ to the cron.allow file (on Solaris) unless
|
321
|
+
+grep+ determines it's already there.
|
322
|
+
|
323
|
+
Note that this command follows the same rules as the main command,
|
324
|
+
which is to say that it must be fully qualified if the path is not set.
|
325
|
+
"
|
326
|
+
|
327
|
+
# Return true if the command does not return 0.
|
328
|
+
def check
|
329
|
+
output, status = @parent.run(self.value)
|
330
|
+
|
331
|
+
return status.exitstatus != 0
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
newcheck(:onlyif) do
|
336
|
+
desc "If this parameter is set, then this +exec+ will only run if
|
337
|
+
the command returns 0. For example::
|
338
|
+
|
339
|
+
exec { \"logrotate\":
|
340
|
+
path => \"/usr/bin:/usr/sbin:/bin\",
|
341
|
+
onlyif => \"test `du /var/log/messages | cut -f1` -gt 100000\"
|
342
|
+
}
|
343
|
+
|
344
|
+
This would run +logrotate+ only if that test returned true.
|
345
|
+
|
346
|
+
Note that this command follows the same rules as the main command,
|
347
|
+
which is to say that it must be fully qualified if the path is not set.
|
348
|
+
"
|
349
|
+
|
350
|
+
# Return true if the command returns 0.
|
351
|
+
def check
|
352
|
+
output, status = @parent.run(self.value)
|
353
|
+
|
354
|
+
return status.exitstatus == 0
|
355
|
+
end
|
322
356
|
end
|
323
357
|
|
324
358
|
# Exec names are not isomorphic with the objects.
|
@@ -341,19 +375,38 @@ module Puppet
|
|
341
375
|
reqs << self[:cwd]
|
342
376
|
end
|
343
377
|
|
344
|
-
|
378
|
+
[:command, :onlyif, :unless].each { |param|
|
379
|
+
next unless tmp = self[param]
|
345
380
|
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
381
|
+
# And search the command line for files, adding any we find. This
|
382
|
+
# will also catch the command itself if it's fully qualified. It might
|
383
|
+
# not be a bad idea to add unqualified files, but, well, that's a
|
384
|
+
# bit more annoying to do.
|
385
|
+
reqs += tmp.scan(%r{(#{File::SEPARATOR}\S+)})
|
386
|
+
}
|
387
|
+
|
388
|
+
# For some reason, the += isn't causing a flattening
|
389
|
+
reqs.flatten!
|
353
390
|
|
354
391
|
reqs
|
355
392
|
end
|
356
393
|
|
394
|
+
# Verify that we pass all of the checks.
|
395
|
+
def check
|
396
|
+
self.class.checks.each { |check|
|
397
|
+
if @parameters.include?(check)
|
398
|
+
if @parameters[check].check
|
399
|
+
self.debug "%s returned true" % check
|
400
|
+
else
|
401
|
+
self.debug "%s returned false" % check
|
402
|
+
return false
|
403
|
+
end
|
404
|
+
end
|
405
|
+
}
|
406
|
+
|
407
|
+
return true
|
408
|
+
end
|
409
|
+
|
357
410
|
def output
|
358
411
|
if self.state(:returns).nil?
|
359
412
|
return nil
|
@@ -367,10 +420,51 @@ module Puppet
|
|
367
420
|
self.state(:returns).sync
|
368
421
|
end
|
369
422
|
|
423
|
+
# Run a command.
|
424
|
+
def run(command)
|
425
|
+
output = nil
|
426
|
+
status = nil
|
427
|
+
tmppath = ENV["PATH"]
|
428
|
+
dir = self[:cwd] || Dir.pwd
|
429
|
+
begin
|
430
|
+
# Do our chdir
|
431
|
+
Dir.chdir(dir) {
|
432
|
+
if self[:path]
|
433
|
+
ENV["PATH"] = self[:path].join(":")
|
434
|
+
end
|
435
|
+
|
436
|
+
# The user and group default to nil, which 'asuser'
|
437
|
+
# handlers correctly
|
438
|
+
Puppet::Util.asuser(self[:user], self[:group]) {
|
439
|
+
# capture both stdout and stderr
|
440
|
+
if self[:user]
|
441
|
+
unless defined? @@alreadywarned
|
442
|
+
Puppet.warning(
|
443
|
+
"Cannot capture STDERR when running as another user"
|
444
|
+
)
|
445
|
+
@@alreadywarned = true
|
446
|
+
end
|
447
|
+
output = %x{#{command}}
|
448
|
+
else
|
449
|
+
output = %x{#{command} 2>&1}
|
450
|
+
end
|
451
|
+
}
|
452
|
+
status = $?.dup
|
453
|
+
}
|
454
|
+
rescue Errno::ENOENT => detail
|
455
|
+
self.fail detail.to_s
|
456
|
+
ensure
|
457
|
+
# reset things to how we found them
|
458
|
+
ENV["PATH"] = tmppath
|
459
|
+
end
|
460
|
+
|
461
|
+
return output, status
|
462
|
+
end
|
463
|
+
|
370
464
|
def to_s
|
371
465
|
"exec(%s)" % self.name
|
372
466
|
end
|
373
467
|
end
|
374
468
|
end
|
375
469
|
|
376
|
-
# $Id: exec.rb
|
470
|
+
# $Id: exec.rb 907 2006-02-13 21:58:40Z luke $
|