rouster 0.7 → 0.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +0 -3
- data/README.md +7 -241
- data/Rakefile +18 -55
- data/Vagrantfile +8 -26
- data/lib/rouster.rb +183 -404
- data/lib/rouster/deltas.rb +118 -577
- data/lib/rouster/puppet.rb +34 -209
- data/lib/rouster/testing.rb +59 -366
- data/lib/rouster/tests.rb +19 -70
- data/path_helper.rb +7 -5
- data/rouster.gemspec +1 -3
- data/test/basic.rb +1 -4
- data/test/functional/deltas/test_get_groups.rb +2 -74
- data/test/functional/deltas/test_get_packages.rb +4 -86
- data/test/functional/deltas/test_get_ports.rb +1 -26
- data/test/functional/deltas/test_get_services.rb +4 -43
- data/test/functional/deltas/test_get_users.rb +2 -35
- data/test/functional/puppet/test_facter.rb +1 -41
- data/test/functional/puppet/test_get_puppet_star.rb +68 -0
- data/test/functional/test_caching.rb +1 -5
- data/test/functional/test_dirs.rb +0 -25
- data/test/functional/test_get.rb +6 -10
- data/test/functional/test_inspect.rb +1 -1
- data/test/functional/test_is_file.rb +1 -17
- data/test/functional/test_new.rb +22 -233
- data/test/functional/test_put.rb +11 -9
- data/test/functional/test_restart.rb +4 -1
- data/test/functional/test_run.rb +3 -2
- data/test/puppet/test_apply.rb +11 -13
- data/test/puppet/test_roles.rb +173 -0
- data/test/unit/test_new.rb +0 -88
- data/test/unit/test_parse_ls_string.rb +0 -67
- data/test/unit/testing/test_validate_file.rb +47 -39
- data/test/unit/testing/test_validate_package.rb +10 -36
- metadata +6 -46
- data/.reek +0 -63
- data/.travis.yml +0 -11
- data/Gemfile +0 -17
- data/Gemfile.lock +0 -102
- data/LICENSE +0 -9
- data/examples/aws.rb +0 -85
- data/examples/openstack.rb +0 -61
- data/examples/passthrough.rb +0 -71
- data/lib/rouster/vagrant.rb +0 -311
- data/plugins/aws.rb +0 -347
- data/plugins/openstack.rb +0 -136
- data/test/functional/deltas/test_get_crontab.rb +0 -161
- data/test/functional/deltas/test_get_os.rb +0 -68
- data/test/functional/test_is_in_file.rb +0 -40
- data/test/functional/test_passthroughs.rb +0 -94
- data/test/functional/test_validate_file.rb +0 -131
- data/test/unit/puppet/resources/puppet_run_with_failed_exec +0 -59
- data/test/unit/puppet/resources/puppet_run_with_successful_exec +0 -61
- data/test/unit/puppet/test_get_puppet_star.rb +0 -91
- data/test/unit/puppet/test_puppet_parsing.rb +0 -44
- data/test/unit/testing/resources/osx-launchd +0 -285
- data/test/unit/testing/resources/rhel-systemd +0 -46
- data/test/unit/testing/resources/rhel-systemv +0 -41
- data/test/unit/testing/resources/rhel-upstart +0 -20
- data/test/unit/testing/test_get_services.rb +0 -178
- data/test/unit/testing/test_validate_cron.rb +0 -78
- data/test/unit/testing/test_validate_port.rb +0 -103
data/lib/rouster/puppet.rb
CHANGED
@@ -5,6 +5,8 @@ require 'net/https'
|
|
5
5
|
require 'socket'
|
6
6
|
require 'uri'
|
7
7
|
|
8
|
+
# TODO use @cache_timeout to invalidate data cached here
|
9
|
+
|
8
10
|
class Rouster
|
9
11
|
|
10
12
|
##
|
@@ -16,17 +18,8 @@ class Rouster
|
|
16
18
|
# * [cache] - whether to store/return cached facter data, if available
|
17
19
|
# * [custom_facts] - whether to include custom facts in return (uses -p argument)
|
18
20
|
def facter(cache=true, custom_facts=true)
|
19
|
-
|
20
21
|
if cache.true? and ! self.facts.nil?
|
21
|
-
|
22
|
-
if self.cache_timeout and self.cache_timeout.is_a?(Integer) and (Time.now.to_i - self.cache[:facter]) > self.cache_timeout
|
23
|
-
@logger.debug(sprintf('invalidating [facter] cache, was [%s] old, allowed [%s]', (Time.now.to_i - self.cache[:facter]), self.cache_timeout))
|
24
|
-
self.facts = nil
|
25
|
-
else
|
26
|
-
@logger.debug(sprintf('using cached [facter] from [%s]', self.cache[:facter]))
|
27
|
-
return self.facts
|
28
|
-
end
|
29
|
-
|
22
|
+
return self.facts
|
30
23
|
end
|
31
24
|
|
32
25
|
raw = self.run(sprintf('facter %s', custom_facts.true? ? '-p' : ''))
|
@@ -38,35 +31,12 @@ class Rouster
|
|
38
31
|
end
|
39
32
|
|
40
33
|
if cache.true?
|
41
|
-
@logger.debug(sprintf('caching [facter] at [%s]', Time.now.asctime))
|
42
34
|
self.facts = res
|
43
|
-
self.cache[:facter] = Time.now.to_i
|
44
35
|
end
|
45
36
|
|
46
37
|
res
|
47
38
|
end
|
48
39
|
|
49
|
-
##
|
50
|
-
# did_exec_fire?
|
51
|
-
#
|
52
|
-
# given the name of an Exec resource, parse the output from the most recent puppet run
|
53
|
-
# and return true/false based on whether the exec in question was fired
|
54
|
-
def did_exec_fire?(resource_name, puppet_run = self.last_puppet_run)
|
55
|
-
# Notice: /Stage[main]//Exec[foo]/returns: executed successfully
|
56
|
-
# Error: /Stage[main]//Exec[bar]/returns: change from notrun to 0 failed: Could not find command '/bin/bar'
|
57
|
-
matchers = [
|
58
|
-
'Notice: /Stage\[.*\]//Exec\[%s\]/returns: executed successfully',
|
59
|
-
'Error: /Stage\[.*\]//Exec\[%s\]/returns: change from notrun to 0 failed'
|
60
|
-
]
|
61
|
-
|
62
|
-
matchers.each do |m|
|
63
|
-
matcher = sprintf(m, resource_name)
|
64
|
-
return true if puppet_run.match(matcher)
|
65
|
-
end
|
66
|
-
|
67
|
-
false
|
68
|
-
end
|
69
|
-
|
70
40
|
##
|
71
41
|
# get_catalog
|
72
42
|
#
|
@@ -83,11 +53,7 @@ class Rouster
|
|
83
53
|
# post https://<puppetmaster>/catalog/<node>?facts_format=pson&facts=<pson URL encoded> == ht to patrick@puppetlabs
|
84
54
|
certname = hostname.nil? ? self.run('hostname --fqdn').chomp : hostname
|
85
55
|
puppetmaster = puppetmaster.nil? ? 'puppet' : puppetmaster
|
86
|
-
facts = facts.nil? ? self.facter() : facts
|
87
|
-
|
88
|
-
%w(fqdn hostname operatingsystem operatingsystemrelease osfamily rubyversion).each do |required|
|
89
|
-
raise ArgumentError.new(sprintf('missing required fact[%s]', required)) unless facts.has_key?(required)
|
90
|
-
end
|
56
|
+
facts = facts.nil? ? self.facter() : facts # TODO check for presence of certain 'required' facts/datatype?
|
91
57
|
|
92
58
|
raise InternalError.new('need to finish conversion of facts to PSON')
|
93
59
|
facts.to_pson # this does not work, but needs to
|
@@ -114,17 +80,8 @@ class Rouster
|
|
114
80
|
# parameters
|
115
81
|
# * [input] - string to look at, defaults to self.get_output()
|
116
82
|
def get_puppet_errors(input=nil)
|
117
|
-
str
|
118
|
-
errors
|
119
|
-
errors_27 = str.scan(/35merr:.*/)
|
120
|
-
errors_30 = str.scan(/Error:.*/)
|
121
|
-
|
122
|
-
# TODO this is a little less than efficient, don't scan for 3.0 if you found 2.7
|
123
|
-
if errors_27.size > 0
|
124
|
-
errors = errors_27
|
125
|
-
else
|
126
|
-
errors = errors_30
|
127
|
-
end
|
83
|
+
str = input.nil? ? self.get_output() : input
|
84
|
+
errors = str.scan(/35merr:.*/)
|
128
85
|
|
129
86
|
errors.empty? ? nil : errors
|
130
87
|
end
|
@@ -137,17 +94,8 @@ class Rouster
|
|
137
94
|
# parameters
|
138
95
|
# * [input] - string to look at, defaults to self.get_output()
|
139
96
|
def get_puppet_notices(input=nil)
|
140
|
-
str
|
141
|
-
notices
|
142
|
-
notices_27 = str.scan(/36mnotice:.*/) # not sure when this stopped working
|
143
|
-
notices_30 = str.scan(/Notice:.*/)
|
144
|
-
|
145
|
-
# TODO this is a little less than efficient, don't scan for 3.0 if you found 2.7
|
146
|
-
if notices_27.size > 0
|
147
|
-
notices = notices_27
|
148
|
-
else
|
149
|
-
notices = notices_30
|
150
|
-
end
|
97
|
+
str = input.nil? ? self.get_output() : input
|
98
|
+
notices = str.scan(/36mnotice:.*/)
|
151
99
|
|
152
100
|
notices.empty? ? nil : notices
|
153
101
|
end
|
@@ -176,41 +124,13 @@ class Rouster
|
|
176
124
|
# returns hiera results from self
|
177
125
|
#
|
178
126
|
# parameters
|
179
|
-
# * <key>
|
180
|
-
# * [
|
181
|
-
|
182
|
-
# * [options] - any additional parameters to be passed to hiera directly
|
183
|
-
#
|
184
|
-
# note
|
185
|
-
# * if no facts are provided, facter() will be called - to really run hiera without facts, send an empty hash
|
186
|
-
# * this method is mostly useful on your puppet master, as your agents won't likely have /etc/puppet/hiera.yaml - to get data on another node, specify it's facts and call hiera on your ppm
|
187
|
-
def hiera(key, facts=nil, config='/etc/puppet/hiera.yaml', options=nil)
|
188
|
-
# TODO implement caching? where do we keep it? self.hiera{}? or self.deltas{} -- leaning towards #1
|
189
|
-
|
190
|
-
cmd = 'hiera'
|
127
|
+
# * <key> - hiera key to look up
|
128
|
+
# * [config] - path to hiera configuration -- this is only optional if you have a hiera.yaml file in ~/vagrant
|
129
|
+
def hiera(key, config=nil)
|
191
130
|
|
192
|
-
|
193
|
-
|
194
|
-
facts = self.facter()
|
195
|
-
end
|
196
|
-
|
197
|
-
if facts.keys.size > 0
|
198
|
-
scope_file = sprintf('/tmp/rouster-hiera_scope.%s.%s.json', $$, Time.now.to_i)
|
131
|
+
# TODO implement this
|
132
|
+
raise NotImplementedError.new()
|
199
133
|
|
200
|
-
File.write(scope_file, facts.to_json)
|
201
|
-
self.put(scope_file, scope_file)
|
202
|
-
File.delete(scope_file)
|
203
|
-
|
204
|
-
cmd << sprintf(' -j %s', scope_file)
|
205
|
-
end
|
206
|
-
|
207
|
-
cmd << sprintf(' -c %s', config) unless config.nil?
|
208
|
-
cmd << sprintf(' %s', options) unless options.nil?
|
209
|
-
cmd << sprintf(' %s', key)
|
210
|
-
|
211
|
-
raw = self.run(cmd)
|
212
|
-
|
213
|
-
JSON.parse(raw)
|
214
134
|
end
|
215
135
|
|
216
136
|
##
|
@@ -310,6 +230,7 @@ class Rouster
|
|
310
230
|
end
|
311
231
|
|
312
232
|
# remove all nil references
|
233
|
+
# TODO make this more rubyish
|
313
234
|
resources.each_key do |name|
|
314
235
|
resources[name].each_pair do |k,v|
|
315
236
|
unless v
|
@@ -318,14 +239,13 @@ class Rouster
|
|
318
239
|
end
|
319
240
|
end
|
320
241
|
|
242
|
+
|
321
243
|
results[:classes] = classes
|
322
244
|
results[:resources] = resources
|
323
245
|
|
324
246
|
results
|
325
247
|
end
|
326
248
|
|
327
|
-
# TODO: come up with better method names here.. remove_existing_certs() and remove_specific_cert() are not very descriptive
|
328
|
-
|
329
249
|
##
|
330
250
|
# remove_existing_certs
|
331
251
|
#
|
@@ -334,57 +254,16 @@ class Rouster
|
|
334
254
|
#
|
335
255
|
# parameters
|
336
256
|
# * <puppetmaster> - string/partial regex of certificate names to keep
|
337
|
-
def remove_existing_certs (
|
338
|
-
except = except.kind_of?(Array) ? except : [except] # need to move from <>.class.eql? to <>.kind_of? in a number of places
|
339
|
-
hosts = Array.new()
|
340
|
-
|
341
|
-
res = self.run('puppet cert list --all')
|
342
|
-
|
343
|
-
# TODO refactor this away from the hacky_break
|
344
|
-
res.each_line do |line|
|
345
|
-
hacky_break = false
|
346
|
-
|
347
|
-
except.each do |exception|
|
348
|
-
next if hacky_break
|
349
|
-
hacky_break = line.match(/#{exception}/)
|
350
|
-
end
|
351
|
-
|
352
|
-
next if hacky_break
|
353
|
-
|
354
|
-
host = $1 if line.match(/^\+\s"(.*?)"/)
|
355
|
-
|
356
|
-
hosts.push(host) unless host.nil? # only want to clear signed certs
|
357
|
-
end
|
358
|
-
|
359
|
-
hosts.each do |host|
|
360
|
-
self.run(sprintf('puppet cert --clean %s', host))
|
361
|
-
end
|
362
|
-
|
363
|
-
end
|
364
|
-
|
365
|
-
##
|
366
|
-
# remove_specific_cert
|
367
|
-
#
|
368
|
-
# ... removes a specific (or several specific) certificates, effectively the reverse of remove_existing_certs() - and again, really only useful when called on a puppet master
|
369
|
-
def remove_specific_cert (targets)
|
370
|
-
targets = targets.kind_of?(Array) ? targets : [targets]
|
257
|
+
def remove_existing_certs (puppetmaster)
|
371
258
|
hosts = Array.new()
|
372
259
|
|
373
260
|
res = self.run('puppet cert list --all')
|
374
261
|
|
375
262
|
res.each_line do |line|
|
376
|
-
|
377
|
-
|
378
|
-
targets.each do |target|
|
379
|
-
next unless hacky_break
|
380
|
-
hacky_break = line.match(/#{target}/)
|
381
|
-
end
|
382
|
-
|
383
|
-
next unless hacky_break
|
384
|
-
|
263
|
+
next if line.match(/#{puppetmaster}/)
|
385
264
|
host = $1 if line.match(/^\+\s"(.*?)"/)
|
386
|
-
hosts.push(host) unless host.nil?
|
387
265
|
|
266
|
+
hosts.push(host)
|
388
267
|
end
|
389
268
|
|
390
269
|
hosts.each do |host|
|
@@ -393,22 +272,15 @@ class Rouster
|
|
393
272
|
|
394
273
|
end
|
395
274
|
|
396
|
-
|
397
275
|
##
|
398
276
|
# run_puppet
|
399
277
|
#
|
400
278
|
# ... runs puppet on self, returns nothing
|
401
279
|
#
|
402
280
|
# currently supports 2 methods of running puppet:
|
403
|
-
# * master - runs 'puppet
|
281
|
+
# * master - runs '/sbin/service puppet once -t'
|
404
282
|
# * supported options
|
405
283
|
# * expected_exitcode - string/integer/array of acceptable exit code(s)
|
406
|
-
# * configtimeout - string/integer of the acceptable configtimeout value
|
407
|
-
# * environment - string of the environment to use
|
408
|
-
# * certname - string of the certname to use in place of the host fqdn
|
409
|
-
# * pluginsync - bool value if pluginsync should be used
|
410
|
-
# * server - string value of the puppetmasters fqdn / ip
|
411
|
-
# * additional_options - string of various options that would be passed to puppet
|
412
284
|
# * masterless - runs 'puppet apply <options>' after determining version of puppet running and adjusting arguments
|
413
285
|
# * supported options
|
414
286
|
# * expected_exitcode - string/integer/array of acceptable exit code(s)
|
@@ -416,80 +288,41 @@ class Rouster
|
|
416
288
|
# * manifest_file - string/array of strings of paths to manifest(s) to apply
|
417
289
|
# * manifest_dir - string/array of strings of directories containing manifest(s) to apply - is recursive
|
418
290
|
# * module_dir - path to module directory -- currently a required parameter, is this correct?
|
419
|
-
# * environment - string of the environment to use (default: production)
|
420
|
-
# * certname - string of the certname to use in place of the host fqdn (default: unused)
|
421
|
-
# * pluginsync - bool value if pluginsync should be used (default: true)
|
422
|
-
# * additional_options - string of various options that would be passed to puppet
|
423
291
|
#
|
424
292
|
# parameters
|
425
293
|
# * [mode] - method to run puppet, defaults to 'master'
|
426
294
|
# * [opts] - hash of additional options
|
427
|
-
def run_puppet(mode='master', passed_opts=
|
295
|
+
def run_puppet(mode='master', passed_opts=nil)
|
428
296
|
|
429
297
|
if mode.eql?('master')
|
430
298
|
opts = {
|
431
|
-
:expected_exitcode
|
432
|
-
:configtimeout => nil,
|
433
|
-
:environment => nil,
|
434
|
-
:certname => nil,
|
435
|
-
:server => nil,
|
436
|
-
:pluginsync => false,
|
437
|
-
:additional_options => nil
|
299
|
+
:expected_exitcode => 0
|
438
300
|
}.merge!(passed_opts)
|
439
301
|
|
440
|
-
|
441
|
-
cmd << sprintf(' --configtimeout %s', opts[:configtimeout]) unless opts[:configtimeout].nil?
|
442
|
-
cmd << sprintf(' --environment %s', opts[:environment]) unless opts[:environment].nil?
|
443
|
-
cmd << sprintf(' --certname %s', opts[:certname]) unless opts[:certname].nil?
|
444
|
-
cmd << sprintf(' --server %s', opts[:server]) unless opts[:server].nil?
|
445
|
-
cmd << ' --pluginsync' if opts[:pluginsync]
|
446
|
-
cmd << opts[:additional_options] unless opts[:additional_options].nil?
|
447
|
-
|
448
|
-
self.run(cmd, opts[:expected_exitcode])
|
302
|
+
self.run('/sbin/service puppet once -t', opts[:expected_exitcode])
|
449
303
|
|
450
304
|
elsif mode.eql?('masterless')
|
451
305
|
opts = {
|
452
|
-
:expected_exitcode
|
453
|
-
:hiera_config
|
454
|
-
:manifest_file
|
455
|
-
:manifest_dir
|
456
|
-
:module_dir
|
457
|
-
:environment => nil,
|
458
|
-
:certname => nil,
|
459
|
-
:pluginsync => false,
|
460
|
-
:additional_options => nil
|
306
|
+
:expected_exitcode => 2,
|
307
|
+
:hiera_config => nil,
|
308
|
+
:manifest_file => nil, # can be a string or array, will 'puppet apply' each
|
309
|
+
:manifest_dir => nil, # can be a string or array, will 'puppet apply' each module in the dir (recursively)
|
310
|
+
:module_dir => nil
|
461
311
|
}.merge!(passed_opts)
|
462
312
|
|
463
|
-
## validate arguments
|
464
|
-
|
313
|
+
## validate required arguments
|
314
|
+
raise InternalError.new(sprintf('invalid hiera config specified[%s]', opts[:hiera_config])) unless self.is_file?(opts[:hiera_config])
|
315
|
+
raise InternalError.new(sprintf('invalid module dir specified[%s]', opts[:module_dir])) unless self.is_dir?(opts[:module_dir])
|
465
316
|
|
466
|
-
|
467
|
-
if puppet_version > '3.0'
|
468
|
-
raise InternalError.new(sprintf('invalid hiera config specified[%s]', opts[:hiera_config])) unless self.is_file?(opts[:hiera_config])
|
469
|
-
else
|
470
|
-
@logger.error(sprintf('puppet version[%s] does not support --hiera_config, ignoring', puppet_version))
|
471
|
-
end
|
472
|
-
end
|
473
|
-
|
474
|
-
if opts[:module_dir]
|
475
|
-
raise InternalError.new(sprintf('invalid module dir specified[%s]', opts[:module_dir])) unless self.is_dir?(opts[:module_dir])
|
476
|
-
end
|
317
|
+
puppet_version = self.get_puppet_version() # hiera_config specification is only supported in >3.0
|
477
318
|
|
478
319
|
if opts[:manifest_file]
|
479
320
|
opts[:manifest_file] = opts[:manifest_file].class.eql?(Array) ? opts[:manifest_file] : [opts[:manifest_file]]
|
480
321
|
opts[:manifest_file].each do |file|
|
481
322
|
raise InternalError.new(sprintf('invalid manifest file specified[%s]', file)) unless self.is_file?(file)
|
482
323
|
|
483
|
-
|
484
|
-
cmd << sprintf(' --modulepath=%s', opts[:module_dir]) unless opts[:module_dir].nil?
|
485
|
-
cmd << sprintf(' --hiera_config=%s', opts[:hiera_config]) unless opts[:hiera_config].nil? or puppet_version < '3.0'
|
486
|
-
cmd << sprintf(' --environment %s', opts[:environment]) unless opts[:environment].nil?
|
487
|
-
cmd << sprintf(' --certname %s', opts[:certname]) unless opts[:certname].nil?
|
488
|
-
cmd << ' --pluginsync' if opts[:pluginsync]
|
489
|
-
cmd << sprintf(' %s', opts[:additional_options]) unless opts[:additional_options].nil?
|
490
|
-
cmd << sprintf(' %s', file)
|
324
|
+
self.run(sprintf('puppet apply %s --modulepath=%s %s', (puppet_version > '3.0') ? "--hiera_config=#{opts[:hiera_config]}" : '', opts[:module_dir], file), opts[:expected_exitcode])
|
491
325
|
|
492
|
-
self.last_puppet_run = self.run(cmd, opts[:expected_exitcode])
|
493
326
|
end
|
494
327
|
end
|
495
328
|
|
@@ -502,16 +335,8 @@ class Rouster
|
|
502
335
|
|
503
336
|
manifests.each do |m|
|
504
337
|
|
505
|
-
|
506
|
-
cmd << sprintf(' --modulepath=%s', opts[:module_dir]) unless opts[:module_dir].nil?
|
507
|
-
cmd << sprintf(' --hiera_config=%s', opts[:hiera_config]) unless opts[:hiera_config].nil? or puppet_version < '3.0'
|
508
|
-
cmd << sprintf(' --environment %s', opts[:environment]) unless opts[:environment].nil?
|
509
|
-
cmd << sprintf(' --certname %s', opts[:certname]) unless opts[:certname].nil?
|
510
|
-
cmd << ' --pluginsync' if opts[:pluginsync]
|
511
|
-
cmd << sprintf(' %s', opts[:additional_options]) unless opts[:additional_options].nil?
|
512
|
-
cmd << sprintf(' %s', m)
|
338
|
+
self.run(sprintf('puppet apply %s --modulepath=%s %s', (puppet_version > '3.0') ? "--hiera_config=#{opts[:hiera_config]}" : '', opts[:module_dir], m), opts[:expected_exitcode])
|
513
339
|
|
514
|
-
self.last_puppet_run = self.run(cmd, opts[:expected_exitcode])
|
515
340
|
end
|
516
341
|
|
517
342
|
end
|
@@ -524,4 +349,4 @@ class Rouster
|
|
524
349
|
|
525
350
|
end
|
526
351
|
|
527
|
-
end
|
352
|
+
end
|
data/lib/rouster/testing.rb
CHANGED
@@ -5,103 +5,6 @@ require 'rouster/deltas'
|
|
5
5
|
|
6
6
|
class Rouster
|
7
7
|
|
8
|
-
##
|
9
|
-
# validate_cron
|
10
|
-
#
|
11
|
-
# given the name of the user who owns crontab, the cron's command to execute and a hash of expectations, returns true|false whether cron matches expectations
|
12
|
-
#
|
13
|
-
# parameters
|
14
|
-
# * <user> - name of user who owns crontab
|
15
|
-
# * <name> - the cron's command to execute
|
16
|
-
# * <expectations> - hash of expectations, see examples
|
17
|
-
# * <fail_fast> - return false immediately on any failure (default is false)
|
18
|
-
#
|
19
|
-
# example expectations:
|
20
|
-
# 'username',
|
21
|
-
# '/home/username/test.pl', {
|
22
|
-
# :ensure => 'present',
|
23
|
-
# :minute => 1,
|
24
|
-
# :hour => 0,
|
25
|
-
# :dom => '*',
|
26
|
-
# :mon => '*',
|
27
|
-
# :dow => '*',
|
28
|
-
# }
|
29
|
-
#
|
30
|
-
# 'root',
|
31
|
-
# 'printf > /var/log/apache/error_log', {
|
32
|
-
# :minute => 59,
|
33
|
-
# :hour => [8, 12],
|
34
|
-
# :dom => '*',
|
35
|
-
# :mon => '*',
|
36
|
-
# :dow => '*',
|
37
|
-
# }
|
38
|
-
#
|
39
|
-
# supported keys:
|
40
|
-
# * :exists|:ensure -- defaults to present if not specified
|
41
|
-
# * :minute
|
42
|
-
# * :hour
|
43
|
-
# * :dom -- day of month
|
44
|
-
# * :mon -- month
|
45
|
-
# * :dow -- day of week
|
46
|
-
# * :constrain
|
47
|
-
def validate_cron(user, name, expectations, fail_fast=false)
|
48
|
-
if user.nil?
|
49
|
-
raise InternalError.new('no user specified constraint')
|
50
|
-
end
|
51
|
-
|
52
|
-
crontabs = self.get_crontab(user)
|
53
|
-
|
54
|
-
if expectations[:ensure].nil? and expectations[:exists].nil?
|
55
|
-
expectations[:ensure] = 'present'
|
56
|
-
end
|
57
|
-
|
58
|
-
if expectations.has_key?(:constrain)
|
59
|
-
expectations[:constrain] = expectations[:constrain].class.eql?(Array) ? expectations[:constrain] : [expectations[:constrain]]
|
60
|
-
|
61
|
-
expectations[:constrain].each do |constraint|
|
62
|
-
fact, expectation = constraint.split("\s")
|
63
|
-
unless meets_constraint?(fact, expectation)
|
64
|
-
@logger.info(sprintf('returning true for expectation [%s], did not meet constraint[%s/%s]', name, fact, expectation))
|
65
|
-
return true
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
expectations.delete(:constrain)
|
70
|
-
end
|
71
|
-
|
72
|
-
results = Hash.new()
|
73
|
-
local = nil
|
74
|
-
|
75
|
-
expectations.each do |k,v|
|
76
|
-
case k
|
77
|
-
when :ensure, :exists
|
78
|
-
if crontabs.has_key?(name)
|
79
|
-
if v.to_s.match(/absent|false/).nil?
|
80
|
-
local = true
|
81
|
-
else
|
82
|
-
local = false
|
83
|
-
end
|
84
|
-
else
|
85
|
-
local = v.to_s.match(/absent|false/).nil? ? false : true
|
86
|
-
end
|
87
|
-
when :minute, :hour, :dom, :mon, :dow
|
88
|
-
if crontabs.has_key?(name) and crontabs[name].has_key?(k) and crontabs[name][k].to_s.eql?(v.to_s)
|
89
|
-
local = true
|
90
|
-
else
|
91
|
-
local = false
|
92
|
-
end
|
93
|
-
else
|
94
|
-
raise InternalError.new(sprintf('unknown expectation[%s / %s]', k, v))
|
95
|
-
end
|
96
|
-
|
97
|
-
return false if local.eql?(false) and fail_fast.eql?(true)
|
98
|
-
results[k] = local
|
99
|
-
end
|
100
|
-
|
101
|
-
@logger.info("#{name} [#{expectations}] => #{results}")
|
102
|
-
results.find{|k,v| v.false? }.nil?
|
103
|
-
end
|
104
|
-
|
105
8
|
##
|
106
9
|
# validate_file
|
107
10
|
#
|
@@ -110,7 +13,6 @@ class Rouster
|
|
110
13
|
# parameters
|
111
14
|
# * <name> - full file name or relative (to ~vagrant)
|
112
15
|
# * <expectations> - hash of expectations, see examples
|
113
|
-
# * <fail_fast> - return false immediately on any failure (default is false)
|
114
16
|
#
|
115
17
|
# example expectations:
|
116
18
|
# '/sys/kernel/mm/redhat_transparent_hugepage/enabled', {
|
@@ -144,9 +46,9 @@ class Rouster
|
|
144
46
|
# * :owner
|
145
47
|
# * :group
|
146
48
|
# * :constrain
|
147
|
-
def validate_file(name, expectations,
|
49
|
+
def validate_file(name, expectations, cache=false)
|
148
50
|
|
149
|
-
if expectations[:ensure].nil? and expectations[:exists].nil?
|
51
|
+
if expectations[:ensure].nil? and expectations[:exists].nil?
|
150
52
|
expectations[:ensure] = 'file'
|
151
53
|
end
|
152
54
|
|
@@ -154,17 +56,9 @@ class Rouster
|
|
154
56
|
expectations[:constrain] = expectations[:constrain].class.eql?(Array) ? expectations[:constrain] : [expectations[:constrain]]
|
155
57
|
|
156
58
|
expectations[:constrain].each do |constraint|
|
157
|
-
|
158
|
-
|
159
|
-
if valid.nil?
|
160
|
-
raise InternalError.new(sprintf('invalid constraint[%s] specified', constraint))
|
161
|
-
end
|
162
|
-
|
163
|
-
fact = $1
|
164
|
-
expectation = $2
|
165
|
-
|
59
|
+
fact, expectation = constraint.split("\s")
|
166
60
|
unless meets_constraint?(fact, expectation)
|
167
|
-
@
|
61
|
+
@log.info(sprintf('returning true for expectation [%s], did not meet constraint[%s/%s]', name, fact, expectation))
|
168
62
|
return true
|
169
63
|
end
|
170
64
|
end
|
@@ -172,7 +66,7 @@ class Rouster
|
|
172
66
|
expectations.delete(:constrain)
|
173
67
|
end
|
174
68
|
|
175
|
-
properties = (expectations[:ensure].eql?('file')) ? self.file(name, cache) : self.dir(name, cache)
|
69
|
+
properties = (! expectations[:ensure].eql?('file')) ? self.file(name, cache) : self.dir(name, cache)
|
176
70
|
results = Hash.new()
|
177
71
|
local = nil
|
178
72
|
|
@@ -184,14 +78,6 @@ class Rouster
|
|
184
78
|
local = true
|
185
79
|
elsif properties.nil?
|
186
80
|
local = false
|
187
|
-
elsif v.to_s.match(/symlink|link/)
|
188
|
-
if expectations[:target].nil?
|
189
|
-
# don't validate the link path, just check whether we're a link
|
190
|
-
local = properties[:symlink?]
|
191
|
-
else
|
192
|
-
# validate the link path
|
193
|
-
local = properties[:target].eql?(expectations[:target])
|
194
|
-
end
|
195
81
|
else
|
196
82
|
case v
|
197
83
|
when 'dir', 'directory'
|
@@ -223,7 +109,7 @@ class Rouster
|
|
223
109
|
if properties[:directory?]
|
224
110
|
local = v.to_s.match(/absent|false/).nil?
|
225
111
|
else
|
226
|
-
local =
|
112
|
+
local = true
|
227
113
|
end
|
228
114
|
else
|
229
115
|
local = false
|
@@ -234,22 +120,10 @@ class Rouster
|
|
234
120
|
local = true
|
235
121
|
begin
|
236
122
|
self.run(sprintf("grep -c '%s' %s", regex, name))
|
237
|
-
rescue
|
123
|
+
rescue
|
238
124
|
local = false
|
239
125
|
end
|
240
|
-
|
241
|
-
end
|
242
|
-
when :notcontains, :doesntcontain # TODO determine the appropriate attribute title here
|
243
|
-
v = v.class.eql?(Array) ? v : [v]
|
244
|
-
v.each do |regex|
|
245
|
-
local = true
|
246
|
-
begin
|
247
|
-
self.run(sprintf("grep -c '%s' %s", regex, name))
|
248
|
-
local = false
|
249
|
-
rescue => e
|
250
|
-
local = true
|
251
|
-
end
|
252
|
-
break if local.false?
|
126
|
+
next if local.false?
|
253
127
|
end
|
254
128
|
when :mode, :permissions
|
255
129
|
if properties.nil?
|
@@ -282,19 +156,17 @@ class Rouster
|
|
282
156
|
local = false
|
283
157
|
end
|
284
158
|
when :type
|
285
|
-
# noop
|
286
|
-
when :target
|
287
|
-
# noop allowing ensure => 'link' / 'symlink' to specify their .. target
|
159
|
+
# noop
|
288
160
|
else
|
289
161
|
raise InternalError.new(sprintf('unknown expectation[%s / %s]', k, v))
|
290
162
|
end
|
291
163
|
|
292
|
-
return false if local.eql?(false) and fail_fast.eql?(true)
|
293
164
|
results[k] = local
|
294
165
|
end
|
295
166
|
|
296
|
-
@
|
167
|
+
@log.info(results)
|
297
168
|
results.find{|k,v| v.false? }.nil?
|
169
|
+
|
298
170
|
end
|
299
171
|
|
300
172
|
##
|
@@ -305,7 +177,6 @@ class Rouster
|
|
305
177
|
# paramaters
|
306
178
|
# * <name> - group name
|
307
179
|
# * <expectations> - hash of expectations, see examples
|
308
|
-
# * <fail_fast> - return false immediately on any failure (default is false)
|
309
180
|
#
|
310
181
|
# example expectations:
|
311
182
|
# 'root', {
|
@@ -327,7 +198,7 @@ class Rouster
|
|
327
198
|
# * :gid
|
328
199
|
# * :user|:users (string or array)
|
329
200
|
# * :constrain
|
330
|
-
def validate_group(name, expectations
|
201
|
+
def validate_group(name, expectations)
|
331
202
|
groups = self.get_groups(true)
|
332
203
|
|
333
204
|
if expectations[:ensure].nil? and expectations[:exists].nil?
|
@@ -340,7 +211,7 @@ class Rouster
|
|
340
211
|
expectations[:constrain].each do |constraint|
|
341
212
|
fact, expectation = constraint.split("\s")
|
342
213
|
unless meets_constraint?(fact, expectation)
|
343
|
-
@
|
214
|
+
@log.info(sprintf('returning true for expectation [%s], did not meet constraint[%s/%s]', name, fact, expectation))
|
344
215
|
return true
|
345
216
|
end
|
346
217
|
end
|
@@ -364,33 +235,25 @@ class Rouster
|
|
364
235
|
local = v.to_s.match(/absent|false/).nil? ? false : true
|
365
236
|
end
|
366
237
|
when :gid
|
367
|
-
|
368
|
-
local = v.to_s.eql?(groups[name][:gid].to_s)
|
369
|
-
else
|
370
|
-
local = false
|
371
|
-
end
|
238
|
+
local = v.to_s.eql?(groups[name][:gid].to_s)
|
372
239
|
when :user, :users
|
373
240
|
v = v.class.eql?(Array) ? v : [v]
|
374
241
|
v.each do |user|
|
375
|
-
|
376
|
-
local = groups[name][:users].member?(user)
|
377
|
-
else
|
378
|
-
local = false
|
379
|
-
end
|
242
|
+
local = groups[name][:users].member?(user)
|
380
243
|
break unless local.true? # need to make the return value smarter if we want to store data on which user failed
|
381
244
|
end
|
382
245
|
when :type
|
383
|
-
# noop
|
246
|
+
# noop
|
384
247
|
else
|
385
248
|
raise InternalError.new(sprintf('unknown expectation[%s / %s]', k, v))
|
386
249
|
end
|
387
250
|
|
388
|
-
return false if local.eql?(false) and fail_fast.eql?(true)
|
389
251
|
results[k] = local
|
390
252
|
end
|
391
253
|
|
392
|
-
@
|
254
|
+
@log.info(results.pretty_print_inspect())
|
393
255
|
results.find{|k,v| v.false? }.nil?
|
256
|
+
|
394
257
|
end
|
395
258
|
|
396
259
|
##
|
@@ -401,7 +264,6 @@ class Rouster
|
|
401
264
|
# parameters
|
402
265
|
# * <name> - package name
|
403
266
|
# * <expectations> - hash of expectations, see examples
|
404
|
-
# * <fail_fast> - return false immediately on any failure (default is false)
|
405
267
|
#
|
406
268
|
# example expectations:
|
407
269
|
# 'perl-Net-SNMP', {
|
@@ -422,7 +284,7 @@ class Rouster
|
|
422
284
|
# * :exists|ensure
|
423
285
|
# * :version (literal or basic comparison)
|
424
286
|
# * :constrain
|
425
|
-
def validate_package(name, expectations
|
287
|
+
def validate_package(name, expectations)
|
426
288
|
packages = self.get_packages(true)
|
427
289
|
|
428
290
|
if expectations[:ensure].nil? and expectations[:exists].nil?
|
@@ -435,7 +297,7 @@ class Rouster
|
|
435
297
|
expectations[:constrain].each do |constraint|
|
436
298
|
fact, expectation = constraint.split("\s")
|
437
299
|
unless meets_constraint?(fact, expectation)
|
438
|
-
@
|
300
|
+
@log.info(sprintf('returning true for expectation [%s], did not meet constraint[%s/%s]', name, fact, expectation))
|
439
301
|
return true
|
440
302
|
end
|
441
303
|
end
|
@@ -459,148 +321,26 @@ class Rouster
|
|
459
321
|
local = v.to_s.match(/absent|false/).nil? ? false : true
|
460
322
|
end
|
461
323
|
when :version
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
lps.each do |lp|
|
468
|
-
if v.split("\s").size > 1
|
469
|
-
## generic comparator functionality
|
470
|
-
comp, expectation = v.split("\s")
|
471
|
-
local = generic_comparator(lp[:version], comp, expectation)
|
472
|
-
break unless local.eql?(true)
|
473
|
-
else
|
474
|
-
local = ! v.to_s.match(/#{lp[:version]}/).nil?
|
475
|
-
break unless local.eql?(true)
|
476
|
-
end
|
477
|
-
end
|
324
|
+
if v.split("\s").size > 1
|
325
|
+
## generic comparator functionality
|
326
|
+
comp, expectation = v.split("\s")
|
327
|
+
local = generic_comparator(packages[name], comp, expectation)
|
478
328
|
else
|
479
|
-
local =
|
480
|
-
end
|
481
|
-
when :arch, :architecture
|
482
|
-
if packages.has_key?(name)
|
483
|
-
archs = []
|
484
|
-
lps = packages[name].is_a?(Array) ? packages[name] : [ packages[name] ]
|
485
|
-
lps.each { |p| archs << p[:arch] }
|
486
|
-
if v.is_a?(Array)
|
487
|
-
v.each do |arch|
|
488
|
-
local = archs.member?(arch)
|
489
|
-
break unless local.eql?(true) # fail fast - if we are looking for an arch that DNE, bail out
|
490
|
-
end
|
491
|
-
else
|
492
|
-
local = archs.member?(v)
|
493
|
-
end
|
329
|
+
local = ! v.to_s.match(/#{packages[name]}/).nil?
|
494
330
|
end
|
495
331
|
when :type
|
496
|
-
# noop
|
332
|
+
# noop
|
497
333
|
else
|
498
334
|
raise InternalError.new(sprintf('unknown expectation[%s / %s]', k, v))
|
499
335
|
end
|
500
336
|
|
501
|
-
return false if local.eql?(false) and fail_fast.eql?(true)
|
502
337
|
results[k] = local
|
503
338
|
end
|
504
339
|
|
505
340
|
# TODO figure out a good way to allow access to the entire hash, not just boolean -- for now just print at an info level
|
341
|
+
@log.info(results)
|
506
342
|
|
507
|
-
|
508
|
-
results.find{|k,v| v.false? }.nil?
|
509
|
-
end
|
510
|
-
|
511
|
-
# given a port nnumber and a hash of expectations, returns true|false whether port meets expectations
|
512
|
-
#
|
513
|
-
# parameters
|
514
|
-
# * <number> - port number
|
515
|
-
# * <expectations> - hash of expectations, see examples
|
516
|
-
#
|
517
|
-
# example expectations:
|
518
|
-
# '22', {
|
519
|
-
# :ensure => 'active',
|
520
|
-
# :protocol => 'tcp',
|
521
|
-
# :address => '0.0.0.0'
|
522
|
-
# },
|
523
|
-
#
|
524
|
-
# '1234', {
|
525
|
-
# :ensure => 'open',
|
526
|
-
# :address => '*',
|
527
|
-
# :constrain => 'is_virtual false'
|
528
|
-
# }
|
529
|
-
#
|
530
|
-
# supported keys:
|
531
|
-
# * :exists|ensure|state
|
532
|
-
# * :address
|
533
|
-
# * :protocol|proto
|
534
|
-
# * :constrain
|
535
|
-
def validate_port(number, expectations, fail_fast=false)
|
536
|
-
number = number.to_s
|
537
|
-
ports = self.get_ports(true)
|
538
|
-
|
539
|
-
if expectations[:ensure].nil? and expectations[:exists].nil? and expectations[:state].nil?
|
540
|
-
expectations[:ensure] = 'present'
|
541
|
-
end
|
542
|
-
|
543
|
-
if expectations[:protocol].nil? and expectations[:proto].nil?
|
544
|
-
expectations[:protocol] = 'tcp'
|
545
|
-
elsif ! expectations[:proto].nil?
|
546
|
-
expectations[:protocol] = expectations[:proto]
|
547
|
-
end
|
548
|
-
|
549
|
-
if expectations.has_key?(:constrain)
|
550
|
-
expectations[:constrain] = expectations[:constrain].class.eql?(Array) ? expectations[:constrain] : [expectations[:constrain]]
|
551
|
-
|
552
|
-
expectations[:constrain].each do |constraint|
|
553
|
-
fact, expectation = constraint.split("\s")
|
554
|
-
unless meets_constraint?(fact, expectation)
|
555
|
-
@logger.info(sprintf('returning true for expectation [%s], did not meet constraint[%s/%s]', name, fact, expectation))
|
556
|
-
return true
|
557
|
-
end
|
558
|
-
end
|
559
|
-
|
560
|
-
expectations.delete(:constrain)
|
561
|
-
end
|
562
|
-
|
563
|
-
results = Hash.new()
|
564
|
-
local = nil
|
565
|
-
|
566
|
-
expectations.each do |k,v|
|
567
|
-
case k
|
568
|
-
when :ensure, :exists, :state
|
569
|
-
if v.to_s.match(/absent|false|open/)
|
570
|
-
local = ports[expectations[:protocol]][number].nil?
|
571
|
-
else
|
572
|
-
local = ! ports[expectations[:protocol]][number].nil?
|
573
|
-
end
|
574
|
-
when :protocol, :proto
|
575
|
-
# TODO rewrite this in a less hacky way
|
576
|
-
if expectations[:ensure].to_s.match(/absent|false|open/) or expectations[:exists].to_s.match(/absent|false|open/) or expectations[:state].to_s.match(/absent|false|open/)
|
577
|
-
local = true
|
578
|
-
else
|
579
|
-
local = ports[v].has_key?(number)
|
580
|
-
end
|
581
|
-
|
582
|
-
when :address
|
583
|
-
lr = Array.new
|
584
|
-
if ports[expectations[:protocol]][number]
|
585
|
-
addresses = ports[expectations[:protocol]][number][:address]
|
586
|
-
addresses.each_key do |address|
|
587
|
-
lr.push(address.eql?(v.to_s))
|
588
|
-
end
|
589
|
-
|
590
|
-
local = ! lr.find{|e| e.true? }.nil? # this feels jankity
|
591
|
-
else
|
592
|
-
# this port isn't open in the first place, won't match any addresses we expect to see it on
|
593
|
-
local = false
|
594
|
-
end
|
595
|
-
else
|
596
|
-
raise InternalError.new(sprintf('unknown expectation[%s / %s]', k, v))
|
597
|
-
end
|
598
|
-
|
599
|
-
return false if local.eql?(false) and fail_fast.eql?(true)
|
600
|
-
results[k] = local
|
601
|
-
end
|
602
|
-
|
603
|
-
@logger.info("#{name} [#{expectations}] => #{results}")
|
343
|
+
# TODO should we implement a fail fast method? at least an option
|
604
344
|
results.find{|k,v| v.false? }.nil?
|
605
345
|
end
|
606
346
|
|
@@ -612,7 +352,6 @@ class Rouster
|
|
612
352
|
# parameters
|
613
353
|
# * <name> - service name
|
614
354
|
# * <expectations> - hash of expectations, see examples
|
615
|
-
# * <fail_fast> - return false immediately on any failure (default is false)
|
616
355
|
#
|
617
356
|
# example expectations:
|
618
357
|
# 'ntp', {
|
@@ -628,7 +367,7 @@ class Rouster
|
|
628
367
|
# * :exists|:ensure
|
629
368
|
# * :state,:status
|
630
369
|
# * :constrain
|
631
|
-
def validate_service(name, expectations
|
370
|
+
def validate_service(name, expectations)
|
632
371
|
services = self.get_services(true)
|
633
372
|
|
634
373
|
if expectations[:ensure].nil? and expectations[:exists].nil?
|
@@ -641,7 +380,7 @@ class Rouster
|
|
641
380
|
expectations[:constrain].each do |constraint|
|
642
381
|
fact, expectation = constraint.split("\s")
|
643
382
|
unless meets_constraint?(fact, expectation)
|
644
|
-
@
|
383
|
+
@log.info(sprintf('returning true for expectation [%s], did not meet constraint[%s/%s]', name, fact, expectation))
|
645
384
|
return true
|
646
385
|
end
|
647
386
|
end
|
@@ -665,23 +404,19 @@ class Rouster
|
|
665
404
|
local = v.to_s.match(/absent|false/).nil? ? false : true
|
666
405
|
end
|
667
406
|
when :state, :status
|
668
|
-
|
669
|
-
local = ! v.match(/#{services[name]}/).nil?
|
670
|
-
else
|
671
|
-
local = false
|
672
|
-
end
|
407
|
+
local = ! v.match(/#{services[name]}/).nil?
|
673
408
|
when :type
|
674
|
-
# noop
|
409
|
+
# noop
|
675
410
|
else
|
676
411
|
raise InternalError.new(sprintf('unknown expectation[%s / %s]', k, v))
|
677
412
|
end
|
678
413
|
|
679
|
-
return false if local.eql?(false) and fail_fast.eql?(true)
|
680
414
|
results[k] = local
|
681
415
|
end
|
682
416
|
|
683
|
-
@
|
417
|
+
@log.info(results.pretty_print_inspect())
|
684
418
|
results.find{|k,v| v.false? }.nil?
|
419
|
+
|
685
420
|
end
|
686
421
|
|
687
422
|
##
|
@@ -692,7 +427,6 @@ class Rouster
|
|
692
427
|
# parameters
|
693
428
|
# * <name> - user name
|
694
429
|
# * <expectations> - hash of expectations, see examples
|
695
|
-
# * <fail_fast> - return false immediately on any failure (default is false)
|
696
430
|
#
|
697
431
|
# example expectations:
|
698
432
|
# 'root' => {
|
@@ -718,7 +452,7 @@ class Rouster
|
|
718
452
|
# * :uid
|
719
453
|
# * :gid
|
720
454
|
# * :constrain
|
721
|
-
def validate_user(name, expectations
|
455
|
+
def validate_user(name, expectations)
|
722
456
|
users = self.get_users(true)
|
723
457
|
|
724
458
|
if expectations[:ensure].nil? and expectations[:exists].nil?
|
@@ -731,7 +465,7 @@ class Rouster
|
|
731
465
|
expectations[:constrain].each do |constraint|
|
732
466
|
fact, expectation = constraint.split("\s")
|
733
467
|
unless meets_constraint?(fact, expectation)
|
734
|
-
@
|
468
|
+
@log.info(sprintf('returning true for expectation [%s], did not meet constraint[%s/%s]', name, fact, expectation))
|
735
469
|
return true
|
736
470
|
end
|
737
471
|
end
|
@@ -761,47 +495,27 @@ class Rouster
|
|
761
495
|
break unless local.true?
|
762
496
|
end
|
763
497
|
when :gid
|
764
|
-
|
765
|
-
local = v.to_i.eql?(users[name][:gid].to_i)
|
766
|
-
else
|
767
|
-
local = false
|
768
|
-
end
|
498
|
+
local = v.to_i.eql?(users[name][:gid].to_i)
|
769
499
|
when :home
|
770
|
-
|
771
|
-
local = ! v.match(/#{users[name][:home]}/).nil?
|
772
|
-
else
|
773
|
-
local = false
|
774
|
-
end
|
500
|
+
local = ! v.match(/#{users[name][:home]}/).nil?
|
775
501
|
when :home_exists
|
776
|
-
|
777
|
-
local = ! v.to_s.match(/#{users[name][:home_exists].to_s}/).nil?
|
778
|
-
else
|
779
|
-
local = false
|
780
|
-
end
|
502
|
+
local = ! v.to_s.match(/#{users[name][:home_exists].to_s}/).nil?
|
781
503
|
when :shell
|
782
|
-
|
783
|
-
local = ! v.match(/#{users[name][:shell]}/).nil?
|
784
|
-
else
|
785
|
-
local = false
|
786
|
-
end
|
504
|
+
local = ! v.match(/#{users[name][:shell]}/).nil?
|
787
505
|
when :uid
|
788
|
-
|
789
|
-
local = v.to_i.eql?(users[name][:uid].to_i)
|
790
|
-
else
|
791
|
-
local = false
|
792
|
-
end
|
506
|
+
local = v.to_i.eql?(users[name][:uid].to_i)
|
793
507
|
when :type
|
794
|
-
# noop
|
508
|
+
# noop
|
795
509
|
else
|
796
510
|
raise InternalError.new(sprintf('unknown expectation[%s / %s]', k, v))
|
797
511
|
end
|
798
512
|
|
799
|
-
return false if local.eql?(false) and fail_fast.eql?(true)
|
800
513
|
results[k] = local
|
801
514
|
end
|
802
515
|
|
803
|
-
@
|
516
|
+
@log.info(results.pretty_print_inspect())
|
804
517
|
results.find{|k,v| v.false? }.nil?
|
518
|
+
|
805
519
|
end
|
806
520
|
|
807
521
|
## internal methods
|
@@ -814,59 +528,38 @@ class Rouster
|
|
814
528
|
# gets facts from node, and if fact expectation regex matches actual fact, returns true
|
815
529
|
#
|
816
530
|
# parameters
|
817
|
-
# * <
|
818
|
-
# * <expectation>
|
819
|
-
# * [cache]
|
820
|
-
def meets_constraint?(
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
# if we haven't loaded puppet.rb, we won't have access to facts/hiera lookups
|
826
|
-
@logger.warn('using constraints without loading [rouster/puppet] will not work, forcing no-op')
|
531
|
+
# * <fact> - fact
|
532
|
+
# * <expectation>
|
533
|
+
# * [cache]
|
534
|
+
def meets_constraint?(fact, expectation, cache=true)
|
535
|
+
|
536
|
+
unless self.respond_to?('facter')
|
537
|
+
# if we haven't loaded puppet.rb, we won't have access to facts
|
538
|
+
@log.warn('using constraints without loading [rouster/puppet] will not work, forcing no-op')
|
827
539
|
return false
|
828
540
|
end
|
829
541
|
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
if facts[key]
|
834
|
-
actual = facts[key]
|
835
|
-
else
|
836
|
-
# value is not a fact, lets try to find it in hiera
|
837
|
-
# TODO how to handle the fact that this will really only work on the puppetmaster
|
838
|
-
actual = self.hiera(key, facts)
|
839
|
-
end
|
542
|
+
expectation = expectation.to_s
|
543
|
+
facts = self.facter(cache)
|
840
544
|
|
841
545
|
res = nil
|
842
|
-
|
843
546
|
if expectation.split("\s").size > 1
|
844
547
|
## generic comparator functionality
|
845
548
|
comp, expectation = expectation.split("\s")
|
846
|
-
|
549
|
+
|
550
|
+
res = generic_comparator(facts[fact], comp, expectation)
|
551
|
+
|
847
552
|
else
|
848
|
-
res = !
|
553
|
+
res = ! expectation.match(/#{facts[fact]}/).nil?
|
554
|
+
@log.debug(sprintf('meets_constraint?(%s, %s): %s', fact, expectation, res.nil?))
|
849
555
|
end
|
850
556
|
|
851
|
-
@logger.debug(sprintf('meets_constraint?(%s, %s): %s', key, expectation, res.nil?))
|
852
557
|
res
|
853
558
|
end
|
854
559
|
|
855
|
-
##
|
856
|
-
# generic_comparator
|
857
|
-
#
|
858
|
-
# powers the 3 argument form of constraint (i.e. 'is_virtual != true', '<package_version> > 3.0', etc)
|
859
|
-
#
|
860
|
-
# should really be an eval{} of some sort (or would be in the perl world)
|
861
|
-
#
|
862
|
-
# parameters
|
863
|
-
# * <comparand1> - left side of the comparison
|
864
|
-
# * <comparator> - comparison to make
|
865
|
-
# * <comparand2> - right side of the comparison
|
866
560
|
def generic_comparator(comparand1, comparator, comparand2)
|
867
561
|
|
868
562
|
# TODO rewrite this as an eval so we don't have to support everything..
|
869
|
-
# TODO come up with mechanism to determine when is it appropriate to call .to_i vs. otherwise -- comparisons will mainly be numerical (?), but need to support text matching too
|
870
563
|
case comparator
|
871
564
|
when '!='
|
872
565
|
# ugh
|