rouster 0.7 → 0.41

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