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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -3
  3. data/README.md +7 -241
  4. data/Rakefile +18 -55
  5. data/Vagrantfile +8 -26
  6. data/lib/rouster.rb +183 -404
  7. data/lib/rouster/deltas.rb +118 -577
  8. data/lib/rouster/puppet.rb +34 -209
  9. data/lib/rouster/testing.rb +59 -366
  10. data/lib/rouster/tests.rb +19 -70
  11. data/path_helper.rb +7 -5
  12. data/rouster.gemspec +1 -3
  13. data/test/basic.rb +1 -4
  14. data/test/functional/deltas/test_get_groups.rb +2 -74
  15. data/test/functional/deltas/test_get_packages.rb +4 -86
  16. data/test/functional/deltas/test_get_ports.rb +1 -26
  17. data/test/functional/deltas/test_get_services.rb +4 -43
  18. data/test/functional/deltas/test_get_users.rb +2 -35
  19. data/test/functional/puppet/test_facter.rb +1 -41
  20. data/test/functional/puppet/test_get_puppet_star.rb +68 -0
  21. data/test/functional/test_caching.rb +1 -5
  22. data/test/functional/test_dirs.rb +0 -25
  23. data/test/functional/test_get.rb +6 -10
  24. data/test/functional/test_inspect.rb +1 -1
  25. data/test/functional/test_is_file.rb +1 -17
  26. data/test/functional/test_new.rb +22 -233
  27. data/test/functional/test_put.rb +11 -9
  28. data/test/functional/test_restart.rb +4 -1
  29. data/test/functional/test_run.rb +3 -2
  30. data/test/puppet/test_apply.rb +11 -13
  31. data/test/puppet/test_roles.rb +173 -0
  32. data/test/unit/test_new.rb +0 -88
  33. data/test/unit/test_parse_ls_string.rb +0 -67
  34. data/test/unit/testing/test_validate_file.rb +47 -39
  35. data/test/unit/testing/test_validate_package.rb +10 -36
  36. metadata +6 -46
  37. data/.reek +0 -63
  38. data/.travis.yml +0 -11
  39. data/Gemfile +0 -17
  40. data/Gemfile.lock +0 -102
  41. data/LICENSE +0 -9
  42. data/examples/aws.rb +0 -85
  43. data/examples/openstack.rb +0 -61
  44. data/examples/passthrough.rb +0 -71
  45. data/lib/rouster/vagrant.rb +0 -311
  46. data/plugins/aws.rb +0 -347
  47. data/plugins/openstack.rb +0 -136
  48. data/test/functional/deltas/test_get_crontab.rb +0 -161
  49. data/test/functional/deltas/test_get_os.rb +0 -68
  50. data/test/functional/test_is_in_file.rb +0 -40
  51. data/test/functional/test_passthroughs.rb +0 -94
  52. data/test/functional/test_validate_file.rb +0 -131
  53. data/test/unit/puppet/resources/puppet_run_with_failed_exec +0 -59
  54. data/test/unit/puppet/resources/puppet_run_with_successful_exec +0 -61
  55. data/test/unit/puppet/test_get_puppet_star.rb +0 -91
  56. data/test/unit/puppet/test_puppet_parsing.rb +0 -44
  57. data/test/unit/testing/resources/osx-launchd +0 -285
  58. data/test/unit/testing/resources/rhel-systemd +0 -46
  59. data/test/unit/testing/resources/rhel-systemv +0 -41
  60. data/test/unit/testing/resources/rhel-upstart +0 -20
  61. data/test/unit/testing/test_get_services.rb +0 -178
  62. data/test/unit/testing/test_validate_cron.rb +0 -78
  63. data/test/unit/testing/test_validate_port.rb +0 -103
@@ -1,119 +1,12 @@
1
1
  require sprintf('%s/../../%s', File.dirname(File.expand_path(__FILE__)), 'path_helper')
2
2
 
3
- # deltas.rb - get information about crontabs, groups, packages, ports, services and users inside a Vagrant VM
3
+ # deltas.rb - get information about groups, packages, services and users inside a Vagrant VM
4
4
  require 'rouster'
5
5
  require 'rouster/tests'
6
6
 
7
- class Rouster
8
-
9
- ##
10
- # get_crontab
11
- #
12
- # runs `crontab -l <user>` and parses output, returns hash:
13
- # {
14
- # user => {
15
- # command => {
16
- # :minute => minute,
17
- # :hour => hour,
18
- # :dom => dom, # day of month
19
- # :mon => mon, # month
20
- # :dow => dow, # day of week
21
- # }
22
- # }
23
- # }
24
- #
25
- # the hash will contain integers (not strings) for numerical values -- all but '*'
26
- #
27
- # parameters
28
- # * <user> - name of user who owns crontab for examination -- or '*' to determine list of users and iterate over them to find all cron jobs
29
- # * [cache] - boolean controlling whether or not retrieved/parsed data is cached, defaults to true
30
- def get_crontab(user='root', cache=true)
31
-
32
- if cache and self.deltas[:crontab].class.eql?(Hash)
33
-
34
- if self.cache_timeout and self.cache_timeout.is_a?(Integer) and (Time.now.to_i - self.cache[:crontab]) > self.cache_timeout
35
- @logger.debug(sprintf('invalidating [crontab] cache, was [%s] old, allowed [%s]', (Time.now.to_i - self.cache[:crontab]), self.cache_timeout))
36
- self.deltas.delete(:crontab)
37
- end
38
-
39
- if self.deltas.has_key?(:crontab) and self.deltas[:crontab].has_key?(user)
40
- @logger.debug(sprintf('using cached [crontab] from [%s]', self.cache[:crontab]))
41
- return self.deltas[:crontab][user]
42
- elsif self.deltas.has_key?(:crontab) and user.eql?('*')
43
- @logger.debug(sprintf('using cached [crontab] from [%s]', self.cache[:crontab]))
44
- return self.deltas[:crontab]
45
- else
46
- # noop fallthrough to gather data to cache
47
- end
48
-
49
- end
50
-
51
- res = Hash.new
52
- users = nil
53
-
54
- if user.eql?('*')
55
- users = self.get_users().keys
56
- else
57
- users = [user]
58
- end
59
-
60
- users.each do |u|
61
- begin
62
- raw = self.run(sprintf('crontab -u %s -l', u))
63
- rescue RemoteExecutionError => e
64
- # crontab throws a non-0 exit code if there is no crontab for the specified user
65
- res[u] ||= Hash.new
66
- next
67
- end
68
-
69
- raw.split("\n").each do |line|
70
- next if line.match(/^#|^\s+$/)
71
- elements = line.split("\s")
72
-
73
- if elements.size < 5
74
- # this is usually (only?) caused by ENV_VARIABLE=VALUE directives
75
- @logger.debug(sprintf('line [%s] did not match format expectations for a crontab entry, skipping', line))
76
- next
77
- end
78
-
79
- command = elements[5..elements.size].join(' ')
80
-
81
- res[u] ||= Hash.new
82
-
83
- if res[u][command].class.eql?(Hash)
84
- unique = elements.join('')
85
- command = sprintf('%s-duplicate.%s', command, unique)
86
- @logger.info(sprintf('duplicate crontab command found, adding hash key[%s]', command))
87
- end
88
-
89
- res[u][command] = Hash.new
90
- res[u][command][:minute] = elements[0]
91
- res[u][command][:hour] = elements[1]
92
- res[u][command][:dom] = elements[2]
93
- res[u][command][:mon] = elements[3]
94
- res[u][command][:dow] = elements[4]
95
- end
96
- end
97
-
98
- if cache
99
- @logger.debug(sprintf('caching [crontab] at [%s]', Time.now.asctime))
100
-
101
- if ! user.eql?('*')
102
- self.deltas[:crontab] ||= Hash.new
103
- self.deltas[:crontab][user] ||= Hash.new
104
- self.deltas[:crontab][user] = res[user]
105
- else
106
- self.deltas[:crontab] ||= Hash.new
107
- self.deltas[:crontab] = res
108
- end
109
-
110
- self.cache[:crontab] = Time.now.to_i
111
-
112
- end
113
-
114
- return user.eql?('*') ? res : res[user]
115
- end
7
+ # TODO use @cache_timeout to invalidate data cached here
116
8
 
9
+ class Rouster
117
10
  ##
118
11
  # get_groups
119
12
  #
@@ -127,91 +20,34 @@ class Rouster
127
20
  #
128
21
  # parameters
129
22
  # * [cache] - boolean controlling whether data retrieved/parsed is cached, defaults to true
130
- # * [deep] - boolean controlling whether get_users() is called in order to correctly populate res[group][:users]
131
- def get_groups(cache=true, deep=true)
132
-
23
+ def get_groups(cache=true)
133
24
  if cache and ! self.deltas[:groups].nil?
134
-
135
- if self.cache_timeout and self.cache_timeout.is_a?(Integer) and (Time.now.to_i - self.cache[:groups]) > self.cache_timeout
136
- @logger.debug(sprintf('invalidating [groups] cache, was [%s] old, allowed [%s]', (Time.now.to_i - self.cache[:groups]), self.cache_timeout))
137
- self.deltas.delete(:groups)
138
- else
139
- @logger.debug(sprintf('using cached [groups] from [%s]', self.cache[:groups]))
140
- return self.deltas[:groups]
141
- end
142
-
25
+ return self.deltas[:groups]
143
26
  end
144
27
 
145
28
  res = Hash.new()
146
29
 
147
- {
148
- :file => self.run('cat /etc/group'),
149
- :dynamic => self.run('getent group', [0,127]),
150
- }.each_pair do |source, raw|
151
-
152
- raw.split("\n").each do |line|
153
- next unless line.match(/\w+:\w+:\w+/)
154
-
155
- data = line.split(':')
156
-
157
- group = data[0]
158
- gid = data[2]
159
-
160
- # this works in some cases, deep functionality picks up the others
161
- users = data[3].nil? ? ['NONE'] : data[3].split(',')
162
-
163
- if res.has_key?(group)
164
- @logger.debug(sprintf('for[%s] old GID[%s] new GID[%s]', group, gid, res[group][:users])) unless gid.eql?(res[group][:gid])
165
- @logger.debug(sprintf('for[%s] old users[%s] new users[%s]', group, users)) unless users.eql?(res[group][:users])
166
- end
167
-
168
- res[group] = Hash.new() # i miss autovivification
169
- res[group][:gid] = gid
170
- res[group][:users] = users
171
- res[group][:source] = source
172
- end
173
-
174
- end
175
-
176
- groups = res
177
-
178
- if deep
179
- users = self.get_users(cache)
30
+ raw = self.run('cat /etc/group')
180
31
 
181
- known_valid_gids = groups.keys.map { |g| groups[g][:gid] } # no need to calculate this in every loop
32
+ raw.split("\n").each do |line|
33
+ next unless line.match(/\w+:\w+:\w+/)
182
34
 
183
- # TODO better, much better -- since the number of users/groups is finite and usually small, this is a low priority
184
- users.each_key do |user|
185
- # iterate over each user to get their gid
186
- gid = users[user][:gid]
35
+ data = line.split(':')
187
36
 
188
- unless known_valid_gids.member?(gid)
189
- @logger.warn(sprintf('found user[%s] with unknown GID[%s], known GIDs[%s]', user, gid, known_valid_gids))
190
- next
191
- end
192
-
193
- ## do this more efficiently
194
- groups.each_key do |group|
195
- # iterate over each group to find the matching gid
196
- if gid.eql?(groups[group][:gid])
197
- if groups[group][:users].eql?(['NONE'])
198
- groups[group][:users] = []
199
- end
200
- groups[group][:users] << user unless groups[group][:users].member?(user)
201
- end
202
-
203
- end
37
+ group = data[0]
38
+ gid = data[2]
39
+ users = data[3].nil? ? ['NONE'] : data[3].split(',')
204
40
 
205
- end
41
+ res[group] = Hash.new() # i miss autovivification
42
+ res[group][:gid] = gid
43
+ res[group][:users] = users
206
44
  end
207
45
 
208
46
  if cache
209
- @logger.debug(sprintf('caching [groups] at [%s]', Time.now.asctime))
210
- self.deltas[:groups] = groups
211
- self.cache[:groups] = Time.now.to_i
47
+ self.deltas[:groups] = res
212
48
  end
213
49
 
214
- groups
50
+ res
215
51
  end
216
52
 
217
53
  ##
@@ -230,22 +66,14 @@ class Rouster
230
66
  #
231
67
  # supported OS
232
68
  # * OSX - runs `pkgutil --pkgs` and `pkgutil --pkg-info=<package>` (if deep)
233
- # * RedHat - runs `rpm -qa --qf "%{n}@%{v}@%{arch}\n"` (does not support deep)
69
+ # * RedHat - runs `rpm -qa`
234
70
  # * Solaris - runs `pkginfo` and `pkginfo -l <package>` (if deep)
235
- # * Ubuntu - runs `dpkg-query -W -f='${Package}\@${Version}\@${Architecture}\n'` (does not support deep)
71
+ # * Ubuntu - runs `dpkg --get-selections` and `dpkg -s <package>` (if deep)
236
72
  #
237
73
  # raises InternalError if unsupported operating system
238
74
  def get_packages(cache=true, deep=true)
239
75
  if cache and ! self.deltas[:packages].nil?
240
-
241
- if self.cache_timeout and self.cache_timeout.is_a?(Integer) and (Time.now.to_i - self.cache[:packages]) > self.cache_timeout
242
- @logger.debug(sprintf('invalidating [packages] cache, was [%s] old, allowed [%s]', (Time.now.to_i - self.cache[:packages]), self.cache_timeout))
243
- self.deltas.delete(:packages)
244
- else
245
- @logger.debug(sprintf('using cached [packages] from [%s]', self.cache[:packages]))
246
- return self.deltas[:packages]
247
- end
248
-
76
+ return self.deltas[:packages]
249
77
  end
250
78
 
251
79
  res = Hash.new()
@@ -256,93 +84,53 @@ class Rouster
256
84
 
257
85
  raw = self.run('pkgutil --pkgs')
258
86
  raw.split("\n").each do |line|
259
- name = line
260
- arch = '?'
261
- version = '?'
262
87
 
263
88
  if deep
264
89
  # can get install time, volume and location as well
265
- local_res = self.run(sprintf('pkgutil --pkg-info=%s', name))
266
- version = $1 if local_res.match(/version\:\s+(.*?)$/)
267
- end
268
-
269
- if res.has_key?(name)
270
- # different architecture of an already known package
271
- @logger.debug(sprintf('found package with already known name[%s], value[%s], new line[%s], turning into array', name, res[name], line))
272
- new_element = { :version => version, :arch => arch }
273
- res[name] = [ res[name], new_element ]
90
+ local_res = self.run(sprintf('pkgutil --pkg-info=%s', line))
91
+ local = $1 if local_res.match(/version\:\s+(.*?)$/)
274
92
  else
275
- res[name] = { :version => version, :arch => arch }
93
+ local = '?'
276
94
  end
277
95
 
96
+ res[line] = local
278
97
  end
279
98
 
280
99
  elsif os.eql?(:solaris)
281
100
  raw = self.run('pkginfo')
282
101
  raw.split("\n").each do |line|
283
- next if line.match(/(.*?)\s+(.*?)\s(.*)$/).nil?
284
- name = $2
285
- arch = '?'
286
- version = '?'
102
+ next if line.match(/(.*?)\s+(.*?)\s(.*)$/).empty?
287
103
 
288
104
  if deep
289
- begin
290
- # who throws non-0 exit codes when querying for legit package information? solaris does.
291
- local_res = self.run(sprintf('pkginfo -l %s', name))
292
- arch = $1 if local_res.match(/ARCH\:\s+(.*?)$/)
293
- version = $1 if local_res.match(/VERSION\:\s+(.*?)$/)
294
- rescue
295
- arch = '?' if arch.nil?
296
- version = '?' if arch.nil?
297
- end
298
- end
299
-
300
- if res.has_key?(name)
301
- # different architecture of an already known package
302
- @logger.debug(sprintf('found package with already known name[%s], value[%s], new line[%s], turning into array', name, res[name], line))
303
- new_element = { :version => version, :arch => arch }
304
- res[name] = [ res[name], new_element ]
105
+ local_res = self.run(sprintf('pkginfo -l %s', $2))
106
+ local = $1 if local_res.match(/VERSION\:\s+(.*?)$/i)
305
107
  else
306
- res[name] = { :version => version, :arch => arch }
108
+ local = '?'
307
109
  end
110
+
111
+ res[$2] = local
308
112
  end
309
113
 
310
- elsif os.eql?(:ubuntu) or os.eql?(:debian)
311
- raw = self.run("dpkg-query -W -f='${Package}@${Version}@${Architecture}\n'")
114
+ elsif os.eql?(:ubuntu)
115
+ raw = self.run('dpkg --get-selections')
312
116
  raw.split("\n").each do |line|
313
- next if line.match(/(.*?)\@(.*?)\@(.*)/).nil?
314
- name = $1
315
- version = $2
316
- arch = $3
317
-
318
- if res.has_key?(name)
319
- # different architecture of an already known package
320
- @logger.debug(sprintf('found package with already known name[%s], value[%s], new line[%s], turning into array', name, res[name], line))
321
- new_element = { :version => version, :arch => arch }
322
- res[name] = [ res[name], new_element ]
117
+ next if line.match(/^(.*?)\s/).nil?
118
+
119
+ if deep
120
+ local_res = self.run(sprintf('dpkg -s %s', $1))
121
+ local = $1 if local_res.match(/Version\:\s(.*?)$/)
323
122
  else
324
- res[name] = { :version => version, :arch => arch }
123
+ local = '?'
325
124
  end
326
125
 
126
+ res[$1] = local
327
127
  end
328
128
 
329
- elsif os.eql?(:rhel)
330
- raw = self.run('rpm -qa --qf "%{n}@%{v}@%{arch}\n"')
129
+ elsif os.eql?(:redhat)
130
+ raw = self.run('rpm -qa')
331
131
  raw.split("\n").each do |line|
332
- next if line.match(/(.*?)\@(.*?)\@(.*)/).nil?
333
- name = $1
334
- version = $2
335
- arch = $3
336
-
337
- if res.has_key?(name)
338
- # different architecture of an already known package
339
- @logger.debug(sprintf('found package with already known name[%s], value[%s], new line[%s], turning into array', name, res[name], line))
340
- new_element = { :version => version, :arch => arch }
341
- res[name] = [ res[name], new_element ]
342
- else
343
- res[name] = { :version => version, :arch => arch }
344
- end
345
-
132
+ next if line.match(/(.*?)-(\d*\..*)/).nil? # ht petersen.allen
133
+ res[$1] = $2
346
134
  end
347
135
 
348
136
  else
@@ -350,9 +138,7 @@ class Rouster
350
138
  end
351
139
 
352
140
  if cache
353
- @logger.debug(sprintf('caching [packages] at [%s]', Time.now.asctime))
354
141
  self.deltas[:packages] = res
355
- self.cache[:packages] = Time.now.to_i
356
142
  end
357
143
 
358
144
  res
@@ -374,7 +160,7 @@ class Rouster
374
160
  # * [cache] - boolean controlling whether data retrieved/parsed is cached, defaults to true
375
161
  #
376
162
  # supported OS
377
- # * RedHat, Ubuntu - runs `netstat -ln`
163
+ # * RedHat - runs `netstat -ln` -- TODO will this work on other operating systems too?
378
164
  #
379
165
  # raises InternalError if unsupported operating system
380
166
  def get_ports(cache=false)
@@ -382,19 +168,13 @@ class Rouster
382
168
  # TODO improve ipv6 support
383
169
 
384
170
  if cache and ! self.deltas[:ports].nil?
385
- if self.cache_timeout and self.cache_timeout.is_a?(Integer) and (Time.now.to_i - self.cache[:ports]) > self.cache_timeout
386
- @logger.debug(sprintf('invalidating [ports] cache, was [%s] old, allowed [%s]', (Time.now.to_i - self.cache[:ports]), self.cache_timeout))
387
- self.deltas.delete(:ports)
388
- else
389
- @logger.debug(sprintf('using cached [ports] from [%s]', self.cache[:ports]))
390
- return self.deltas[:ports]
391
- end
171
+ return self.deltas[:ports]
392
172
  end
393
173
 
394
174
  res = Hash.new()
395
175
  os = self.os_type()
396
176
 
397
- if os.eql?(:rhel) or os.eql?(:ubuntu) or os.eql?(:debian)
177
+ if os.eql?(:redhat)
398
178
 
399
179
  raw = self.run('netstat -ln')
400
180
 
@@ -413,14 +193,13 @@ class Rouster
413
193
  res[protocol][port][:address][address] = state
414
194
 
415
195
  end
196
+
416
197
  else
417
198
  raise InternalError.new(sprintf('unable to get port information from VM operating system[%s]', os))
418
199
  end
419
200
 
420
201
  if cache
421
- @logger.debug(sprintf('caching [ports] at [%s]', Time.now.asctime))
422
202
  self.deltas[:ports] = res
423
- self.cache[:ports] = Time.now.to_i
424
203
  end
425
204
 
426
205
  res
@@ -431,306 +210,97 @@ class Rouster
431
210
  #
432
211
  # runs an OS appropriate command to gather service information, returns hash:
433
212
  # {
434
- # serviceN => mode # exists|installed|operational|running|stopped|unsure
213
+ # serviceN => mode # running|stopped|unsure
435
214
  # }
436
215
  #
437
216
  # parameters
438
- # * [cache] - boolean controlling whether data retrieved/parsed is cached, defaults to true
439
- # * [humanize] - boolean controlling whether data retrieved is massaged into simplified names or returned mostly as retrieved
440
- # * [type] - symbol indicating which service controller to query, defaults to :all
441
- # * [seed] - test hook to seed the output of service commands
217
+ # * [cache] - boolean controlling whether data retrieved/parsed is cached, defaults to true
442
218
  #
443
- # supported OS and types
444
- # * OSX - :launchd
445
- # * RedHat - :systemv or :upstart
446
- # * Solaris - :smf
447
- # * Ubuntu - :systemv or :upstart
219
+ # supported OS
220
+ # * OSX - runs `launchctl list`
221
+ # * RedHat - runs `/sbin/service --status-all`
222
+ # * Solaris - runs `svcs`
223
+ # * Ubuntu - runs `service --status-all`
448
224
  #
449
- # notes
450
- # * raises InternalError if unsupported operating system
451
- # * OSX, Solaris and Ubuntu/Debian will only return running|stopped|unsure, the exists|installed|operational modes are RHEL/CentOS only
452
-
453
- def get_services(cache=true, humanize=true, type=:all, seed=nil)
225
+ # raises InternalError if unsupported operating system
226
+ def get_services(cache=true)
454
227
  if cache and ! self.deltas[:services].nil?
455
-
456
- if self.cache_timeout and self.cache_timeout.is_a?(Integer) and (Time.now.to_i - self.cache[:services]) > self.cache_timeout
457
- @logger.debug(sprintf('invalidating [services] cache, was [%s] old, allowed [%s]', (Time.now.to_i - self.cache[:services]), self.cache_timeout))
458
- self.deltas.delete(:services)
459
- else
460
- @logger.debug(sprintf('using cached [services] from [%s]', self.cache[:services]))
461
- return self.deltas[:services]
462
- end
463
-
228
+ return self.deltas[:services]
464
229
  end
465
230
 
466
231
  res = Hash.new()
467
- os = self.os_type
468
-
469
- commands = {
470
- :osx => {
471
- :launchd => 'launchctl list',
472
- },
473
- :solaris => {
474
- :smf => 'svcs -a',
475
- },
476
-
477
- # TODO we really need to implement something like osfamily
478
- :ubuntu => {
479
- :systemv => 'service --status-all 2>&1',
480
- :upstart => 'initctl list',
481
- },
482
- :debian => {
483
- :systemv => 'service --status-all 2>&1',
484
- :upstart => 'initctl list',
485
- },
486
- :rhel => {
487
- :systemd => 'systemctl list-units --type=service --no-pager',
488
- :systemv => 'service --status-all',
489
- :upstart => 'initctl list',
490
- },
491
-
492
- :invalid => {
493
- :invalid => 'invalid',
494
- },
495
- }
496
-
497
- if type.eql?(:all)
498
- type = commands[os].keys
499
- end
500
-
501
- type = type.class.eql?(Array) ? type : [ type ]
502
232
 
503
- type.each do |provider|
233
+ os = self.os_type
504
234
 
505
- raise InternalError.new(sprintf('unable to get service information from VM operating system[%s]', os)) if provider.eql?(:invalid)
506
- raise ArgumentError.new(sprintf('unable to find command provider[%s] for [%s]', provider, os)) if commands[os][provider].nil?
235
+ if os.eql?(:osx)
507
236
 
508
- unless seed or self.is_in_path?(commands[os][provider].split(' ').first)
509
- @logger.info(sprintf('skipping provider[%s], not in $PATH[%s]', provider, commands[os][provider]))
510
- next
511
- end
237
+ raw = self.run('launchctl list')
238
+ raw.split("\n").each do |line|
239
+ next if line.match(/(?:\S*?)\s+(\S*?)\s+(\S*)$/).nil?
512
240
 
513
- @logger.info(sprintf('get_services using provider [%s] on [%s]', provider, os))
241
+ service = $2
242
+ mode = $1
514
243
 
515
- # TODO while this is true, what if self.user is 'root'.. -- the problem is we don't have self.user, and we store this data differently depending on self.passthrough?
516
- @logger.warn('gathering service information typically works better with sudo, which is currently not being used') unless self.uses_sudo?
244
+ if mode.match(/^\d/)
245
+ mode = 'running'
246
+ else
247
+ mode = 'stopped'
248
+ end
517
249
 
518
- # TODO come up with a better test hook -- real problem is that we can't seed 'raw' with different values per iteration
519
- raw = seed.nil? ? self.run(commands[os][provider]) : seed
250
+ res[service] = mode
251
+ end
520
252
 
521
- if os.eql?(:osx)
253
+ elsif os.eql?(:solaris)
522
254
 
523
- raw.split("\n").each do |line|
524
- next if line.match(/(?:\S*?)\s+(\S*?)\s+(\S+)$/).nil?
525
- tokens = line.split("\s")
526
- service = tokens[-1]
527
- mode = tokens[0]
255
+ raw = self.run('svcs')
256
+ raw.split("\n").each do |line|
257
+ next if line.match(/(.*?)\s+(?:.*?)\s+(.*?)$/).nil?
528
258
 
529
- if humanize # should we do this with a .freeze instead?
530
- if mode.match(/^\d/)
531
- mode = 'running'
532
- elsif mode.match(/-/)
533
- mode = 'stopped'
534
- else
535
- next # this should handle the banner "PID Status Label"
536
- end
537
- end
259
+ service = $2
260
+ mode = $1
538
261
 
539
- res[service] = mode
262
+ if mode.match(/online/)
263
+ mode = 'running'
264
+ elsif mode.match(/legacy_run/)
265
+ mode = 'running'
266
+ elsif mode.match(//)
267
+ mode = 'stopped'
540
268
  end
541
269
 
542
- elsif os.eql?(:solaris)
270
+ res[service] = mode
543
271
 
544
- raw.split("\n").each do |line|
545
- next if line.match(/(.*?)\s+(?:.*?)\s+(.*?)$/).nil?
546
-
547
- service = $2
548
- mode = $1
549
-
550
- if humanize
551
- if mode.match(/^online/)
552
- mode = 'running'
553
- elsif mode.match(/^legacy_run/)
554
- mode = 'running'
555
- elsif mode.match(/^disabled/)
556
- mode = 'stopped'
557
- end
558
-
559
- if service.match(/^svc:\/.*\/(.*?):.*/)
560
- # turning 'svc:/network/cswpuppetd:default' into 'cswpuppetd'
561
- service = $1
562
- elsif service.match(/^lrc:\/.*?\/.*\/(.*)/)
563
- # turning 'lrc:/etc/rcS_d/S50sk98Sol' into 'S50sk98Sol'
564
- service = $1
565
- end
566
- end
567
-
568
- res[service] = mode
272
+ end
569
273
 
570
- end
274
+ elsif os.eql?(:ubuntu)
571
275
 
572
- elsif os.eql?(:ubuntu) or os.eql?(:debian)
573
-
574
- raw.split("\n").each do |line|
575
- if provider.eql?(:systemv)
576
- next if line.match(/\[(.*?)\]\s+(.*)$/).nil?
577
- mode = $1
578
- service = $2
579
-
580
- if humanize
581
- mode = 'stopped' if mode.match('-')
582
- mode = 'running' if mode.match('\+')
583
- mode = 'unsure' if mode.match('\?')
584
- end
585
-
586
- res[service] = mode
587
- elsif provider.eql?(:upstart)
588
- if line.match(/(.*?)\s.*?(.*?),/)
589
- # tty (/dev/tty3) start/running, process 1601
590
- # named start/running, process 8959
591
- service = $1
592
- mode = $2
593
- elsif line.match(/(.*?)\s(.*)/)
594
- # rcS stop/waiting
595
- service = $1
596
- mode = $2
597
- else
598
- @logger.warn("unable to process upstart line[#{line}], skipping")
599
- next
600
- end
601
-
602
- if humanize
603
- mode = 'stopped' if mode.match('stop/waiting')
604
- mode = 'running' if mode.match('start/running')
605
- mode = 'unsure' unless mode.eql?('stopped') or mode.eql?('running')
606
- end
607
-
608
- res[service] = mode
609
- end
610
- end
276
+ raw = self.run('service --status-all 2>&1')
277
+ raw.split("\n").each do |line|
278
+ next if line.match(/\[(.*?)\]\s+(.*)$/).nil?
279
+ mode = $1
280
+ service = $2
611
281
 
612
- elsif os.eql?(:rhel)
613
-
614
- raw.split("\n").each do |line|
615
- if provider.eql?(:systemv)
616
- if humanize
617
- if line.match(/^(\w+?)\sis\s(.*)$/)
618
- # <service> is <state>
619
- name = $1
620
- state = $2
621
- res[name] = state
622
-
623
- if state.match(/^not/)
624
- # this catches 'Kdump is not operational'
625
- res[name] = 'stopped'
626
- end
627
-
628
- elsif line.match(/^(\w+?)\s\(pid.*?\)\sis\s(\w+)$/)
629
- # <service> (pid <pid> [pid]) is <state>...
630
- res[$1] = $2
631
- elsif line.match(/^(\w+?)\sis\s(\w+)\.*$/) # not sure this is actually needed
632
- @logger.debug('triggered supposedly unnecessary regex')
633
- # <service> is <state>. whatever
634
- res[$1] = $2
635
- elsif line.match(/razor_daemon:\s(\w+).*$/)
636
- # razor_daemon: running [pid 11325]
637
- # razor_daemon: no instances running
638
- res['razor_daemon'] = $1.eql?('running') ? $1 : 'stopped'
639
- elsif line.match(/^(\w+?)\:.*?(\w+)$/)
640
- # <service>: whatever <state>
641
- res[$1] = $2
642
- elsif line.match(/^(\w+?):.*?\sis\snot\srunning\.$/)
643
- # ip6tables: Firewall is not running.
644
- res[$1] = 'stopped'
645
- elsif line.match(/^(\w+?)\s.*?\s(.*)$/)
646
- # netconsole module not loaded
647
- state = $2
648
- res[$1] = $2.match(/not/) ? 'stopped' : 'running'
649
- elsif line.match(/^(\w+)\s(\w+).*$/)
650
- # <process> <state> whatever
651
- res[$1] = $2
652
- else
653
- # original regex implementation, if we didn't match anything else, failover to this
654
- next if line.match(/^([^\s:]*).*\s(\w*)(?:\.?){3}$/).nil?
655
- res[$1] = $2
656
- end
657
- else
658
- next if line.match(/^([^\s:]*).*\s(\w*)(?:\.?){3}$/).nil?
659
- res[$1] = $2
660
- end
661
- elsif provider.eql?(:upstart)
662
-
663
- if line.match(/(.*?)\s.*?(.*?),/)
664
- # tty (/dev/tty3) start/running, process 1601
665
- # named start/running, process 8959
666
- service = $1
667
- mode = $2
668
- elsif line.match(/(.*?)\s(.*)/)
669
- # rcS stop/waiting
670
- service = $1
671
- mode = $2
672
- else
673
- @logger.warn("unable to process upstart line[#{line}], skipping")
674
- next
675
- end
676
-
677
- if humanize
678
- mode = 'stopped' if mode.match('stop/waiting')
679
- mode = 'running' if mode.match('start/running')
680
- mode = 'unsure' unless mode.eql?('stopped') or mode.eql?('running')
681
- end
682
-
683
- res[service] = mode unless res.has_key?(service)
684
-
685
- elsif provider.eql?(:systemd)
686
- # UNIT LOAD ACTIVE SUB DESCRIPTION
687
- # nfs-utils.service loaded inactive dead NFS server and client services
688
- # crond.service loaded active running Command Scheduler
689
-
690
- if line.match(/^\W*(.*?)\.service\s+(?:.*?)\s+(.*?)\s+(.*?)\s+(?:.*?)$/) # 5 space separated characters
691
- service = $1
692
- active = $2
693
- sub = $3
694
-
695
- if humanize
696
- mode = sub.match('running') ? 'running' : 'stopped'
697
- mode = 'unsure' unless mode.eql?('stopped') or mode.eql?('running')
698
- end
699
-
700
- res[service] = mode
701
- else
702
- # not logging here, there is a bunch of garbage output at the end of the output that we can't seem to suppress
703
- next
704
- end
705
-
706
- end
282
+ mode = 'stopped' if mode.match('-')
283
+ mode = 'running' if mode.match('\+')
284
+ mode = 'unsure' if mode.match('\?')
707
285
 
708
- end
709
- else
710
- raise InternalError.new(sprintf('unable to get service information from VM operating system[%s]', os))
286
+ res[service] = mode
711
287
  end
712
288
 
289
+ elsif os.eql?(:redhat)
713
290
 
714
- # end of provider processing
715
- end
716
-
717
- # issue #63 handling
718
- # TODO should we consider using symbols here instead?
719
- allowed_modes = %w(exists installed operational running stopped unsure)
720
- failover_mode = 'unsure'
721
-
722
- if humanize
723
- res.each_pair do |k,v|
724
- next if allowed_modes.member?(v)
725
- @logger.debug(sprintf('replacing service[%s] status of [%s] with [%s] for uniformity', k, v, failover_mode))
726
- res[k] = failover_mode
291
+ raw = self.run('/sbin/service --status-all')
292
+ raw.split("\n").each do |line|
293
+ # TODO tighten this up
294
+ next if line.match(/^([^\s\:]*).*\s(\w*)(?:\.?){3}$/).nil?
295
+ res[$1] = $2
727
296
  end
297
+
298
+ else
299
+ raise InternalError.new(sprintf('unable to get service information from VM operating system[%s]', os))
728
300
  end
729
301
 
730
302
  if cache
731
- @logger.debug(sprintf('caching [services] at [%s]', Time.now.asctime))
732
303
  self.deltas[:services] = res
733
- self.cache[:services] = Time.now.to_i
734
304
  end
735
305
 
736
306
  res
@@ -753,61 +323,32 @@ class Rouster
753
323
  # * [cache] - boolean controlling whether data retrieved/parsed is cached, defaults to true
754
324
  def get_users(cache=true)
755
325
  if cache and ! self.deltas[:users].nil?
756
-
757
- if self.cache_timeout and self.cache_timeout.is_a?(Integer) and (Time.now.to_i - self.cache[:users]) > self.cache_timeout
758
- @logger.debug(sprintf('invalidating [users] cache, was [%s] old, allowed [%s]', (Time.now.to_i - self.cache[:users]), self.cache_timeout))
759
- self.deltas.delete(:users)
760
- else
761
- @logger.debug(sprintf('using cached [users] from [%s]', self.cache[:users]))
762
- return self.deltas[:users]
763
- end
764
-
326
+ return self.deltas[:users]
765
327
  end
766
328
 
767
329
  res = Hash.new()
768
330
 
769
- {
770
- :file => self.run('cat /etc/passwd'),
771
- :dynamic => self.run('getent passwd', [0,127]),
772
- }.each do |source, raw|
331
+ raw = self.run('cat /etc/passwd')
773
332
 
774
- raw.split("\n").each do |line|
775
- next if line.match(/(\w+)(?::\w+){3,}/).nil?
776
-
777
- user = $1
778
- data = line.split(':')
779
-
780
- shell = data[-1]
781
- home = data[-2]
782
- home_exists = self.is_dir?(data[-2])
783
- uid = data[2]
784
- gid = data[3]
785
-
786
- if res.has_key?(user)
787
- @logger.info(sprintf('for[%s] old shell[%s], new shell[%s]', res[user][:shell], shell)) unless shell.eql?(res[user][:shell])
788
- @logger.info(sprintf('for[%s] old home[%s], new home[%s]', res[user][:home], home)) unless home.eql?(res[user][:home])
789
- @logger.info(sprintf('for[%s] old home_exists[%s], new home_exists[%s]', res[user][:home_exists], home_exists)) unless home_exists.eql?(res[user][:home_exists])
790
- @logger.info(sprintf('for[%s] old UID[%s], new UID[%s]', res[user][:uid], uid)) unless uid.eql?(res[user][:uid])
791
- @logger.info(sprintf('for[%s] old GID[%s], new GID[%s]', res[user][:gid], gid)) unless gid.eql?(res[user][:gid])
792
- end
333
+ raw.split("\n").each do |line|
334
+ next if line.match(/(\w+)(?::\w+){3,}/).nil?
793
335
 
794
- res[user] = Hash.new()
795
- res[user][:shell] = shell
796
- res[user][:home] = home
797
- res[user][:home_exists] = home_exists
798
- res[user][:uid] = uid
799
- res[user][:gid] = gid
800
- res[user][:source] = source
801
- end
336
+ user = $1
337
+ data = line.split(':')
338
+
339
+ res[user] = Hash.new()
340
+ res[user][:shell] = data[-1]
341
+ res[user][:home] = data[-2]
342
+ res[user][:home_exists] = self.is_dir?(data[-2])
343
+ res[user][:uid] = data[2]
344
+ res[user][:gid] = data[3]
802
345
  end
803
346
 
804
347
  if cache
805
- @logger.debug(sprintf('caching [users] at [%s]', Time.now.asctime))
806
348
  self.deltas[:users] = res
807
- self.cache[:users] = Time.now.to_i
808
349
  end
809
350
 
810
351
  res
811
352
  end
812
353
 
813
- end
354
+ end