rouster 0.7 → 0.41
Sign up to get free protection for your applications and to get access to all the features.
- 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
|