inspec 0.14.8 → 0.15.0

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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -2
  3. data/bin/inspec +3 -4
  4. data/examples/inheritance/README.md +19 -0
  5. data/examples/inheritance/controls/example.rb +11 -0
  6. data/examples/inheritance/inspec.yml +10 -0
  7. data/lib/bundles/inspec-compliance/cli.rb +1 -4
  8. data/lib/bundles/inspec-supermarket/cli.rb +1 -4
  9. data/lib/inspec/dsl.rb +48 -55
  10. data/lib/inspec/profile.rb +6 -2
  11. data/lib/inspec/profile_context.rb +21 -8
  12. data/lib/inspec/runner.rb +17 -12
  13. data/lib/inspec/runner_rspec.rb +1 -0
  14. data/lib/inspec/version.rb +1 -1
  15. data/lib/resources/apache.rb +20 -18
  16. data/lib/resources/apache_conf.rb +92 -90
  17. data/lib/resources/apt.rb +92 -90
  18. data/lib/resources/audit_policy.rb +35 -33
  19. data/lib/resources/auditd_conf.rb +41 -39
  20. data/lib/resources/auditd_rules.rb +155 -153
  21. data/lib/resources/bond.rb +1 -1
  22. data/lib/resources/bridge.rb +97 -95
  23. data/lib/resources/command.rb +47 -45
  24. data/lib/resources/csv.rb +23 -21
  25. data/lib/resources/directory.rb +1 -1
  26. data/lib/resources/etc_group.rb +116 -114
  27. data/lib/resources/file.rb +1 -1
  28. data/lib/resources/gem.rb +39 -37
  29. data/lib/resources/group.rb +100 -98
  30. data/lib/resources/host.rb +103 -101
  31. data/lib/resources/inetd_conf.rb +42 -40
  32. data/lib/resources/ini.rb +15 -13
  33. data/lib/resources/interface.rb +106 -104
  34. data/lib/resources/iptables.rb +36 -34
  35. data/lib/resources/json.rb +64 -62
  36. data/lib/resources/kernel_module.rb +30 -28
  37. data/lib/resources/kernel_parameter.rb +44 -42
  38. data/lib/resources/limits_conf.rb +41 -39
  39. data/lib/resources/login_def.rb +38 -36
  40. data/lib/resources/mount.rb +43 -41
  41. data/lib/resources/mysql.rb +67 -65
  42. data/lib/resources/mysql_conf.rb +89 -87
  43. data/lib/resources/mysql_session.rb +46 -44
  44. data/lib/resources/npm.rb +35 -33
  45. data/lib/resources/ntp_conf.rb +44 -42
  46. data/lib/resources/oneget.rb +46 -44
  47. data/lib/resources/os.rb +22 -20
  48. data/lib/resources/os_env.rb +47 -45
  49. data/lib/resources/package.rb +213 -211
  50. data/lib/resources/parse_config.rb +59 -57
  51. data/lib/resources/passwd.rb +89 -87
  52. data/lib/resources/pip.rb +60 -58
  53. data/lib/resources/port.rb +352 -350
  54. data/lib/resources/postgres.rb +26 -24
  55. data/lib/resources/postgres_conf.rb +66 -64
  56. data/lib/resources/postgres_session.rb +47 -45
  57. data/lib/resources/processes.rb +56 -54
  58. data/lib/resources/registry_key.rb +150 -148
  59. data/lib/resources/script.rb +30 -28
  60. data/lib/resources/security_policy.rb +56 -54
  61. data/lib/resources/service.rb +638 -636
  62. data/lib/resources/shadow.rb +98 -96
  63. data/lib/resources/ssh_conf.rb +58 -56
  64. data/lib/resources/user.rb +363 -361
  65. data/lib/resources/windows_feature.rb +46 -44
  66. data/lib/resources/xinetd.rb +111 -109
  67. data/lib/resources/yaml.rb +16 -14
  68. data/lib/resources/yum.rb +107 -105
  69. data/lib/utils/base_cli.rb +18 -0
  70. data/test/helper.rb +2 -2
  71. data/test/unit/profile_context_test.rb +1 -1
  72. data/test/unit/resources/file_test.rb +1 -1
  73. data/test/unit/resources/mount_test.rb +1 -1
  74. metadata +5 -2
@@ -4,38 +4,40 @@
4
4
  # author: Dominik Richter
5
5
  # license: All rights reserved
6
6
 
7
- class Script < Cmd
8
- name 'script'
9
- desc 'Use the script InSpec audit resource to test a Windows PowerShell script on the Microsoft Windows platform.'
10
- example "
11
- script = <<-EOH
12
- # you powershell script
13
- EOH
7
+ module Inspec::Resources
8
+ class Script < Cmd
9
+ name 'script'
10
+ desc 'Use the script InSpec audit resource to test a Windows PowerShell script on the Microsoft Windows platform.'
11
+ example "
12
+ script = <<-EOH
13
+ # you powershell script
14
+ EOH
14
15
 
15
- describe script(script) do
16
- its('matcher') { should eq 'output' }
17
- end
18
- "
16
+ describe script(script) do
17
+ its('matcher') { should eq 'output' }
18
+ end
19
+ "
19
20
 
20
- def initialize(script)
21
- unless inspec.os.windows?
22
- return skip_resource 'The `script` resource is not supported on your OS yet.'
23
- end
21
+ def initialize(script)
22
+ unless inspec.os.windows?
23
+ return skip_resource 'The `script` resource is not supported on your OS yet.'
24
+ end
24
25
 
25
- # encodes a script as base64 to run as powershell encodedCommand
26
- # this comes with performance issues: @see https://gist.github.com/fnichol/7b20596b950e65fb96f9
27
- require 'winrm'
28
- script = WinRM::PowershellScript.new(script)
29
- cmd = "powershell -encodedCommand #{script.encoded}"
30
- super(cmd)
31
- end
26
+ # encodes a script as base64 to run as powershell encodedCommand
27
+ # this comes with performance issues: @see https://gist.github.com/fnichol/7b20596b950e65fb96f9
28
+ require 'winrm'
29
+ script = WinRM::PowershellScript.new(script)
30
+ cmd = "powershell -encodedCommand #{script.encoded}"
31
+ super(cmd)
32
+ end
32
33
 
33
- # we cannot determine if a command exists, because that does not work for scripts
34
- def exist?
35
- nil
36
- end
34
+ # we cannot determine if a command exists, because that does not work for scripts
35
+ def exist?
36
+ nil
37
+ end
37
38
 
38
- def to_s
39
- 'Script'
39
+ def to_s
40
+ 'Script'
41
+ end
40
42
  end
41
43
  end
@@ -13,70 +13,72 @@
13
13
  # All local GPO parameters can be examined via Registry, but not all security
14
14
  # parameters. Therefore we need a combination of Registry and secedit output
15
15
 
16
- class SecurityPolicy < Inspec.resource(1)
17
- name 'security_policy'
18
- desc 'Use the security_policy InSpec audit resource to test security policies on the Microsoft Windows platform.'
19
- example "
20
- describe security_policy do
21
- its('SeNetworkLogonRight') { should eq '*S-1-5-11' }
16
+ module Inspec::Resources
17
+ class SecurityPolicy < Inspec.resource(1)
18
+ name 'security_policy'
19
+ desc 'Use the security_policy InSpec audit resource to test security policies on the Microsoft Windows platform.'
20
+ example "
21
+ describe security_policy do
22
+ its('SeNetworkLogonRight') { should eq '*S-1-5-11' }
23
+ end
24
+ "
25
+ def initialize
26
+ @loaded = false
27
+ @policy = nil
28
+ @exit_status = nil
22
29
  end
23
- "
24
- def initialize
25
- @loaded = false
26
- @policy = nil
27
- @exit_status = nil
28
- end
29
-
30
- # load security content
31
- def load
32
- # export the security policy
33
- cmd = inspec.command('secedit /export /cfg win_secpol.cfg')
34
- return nil if cmd.exit_status.to_i != 0
35
30
 
36
- # store file content
37
- cmd = inspec.command('Get-Content win_secpol.cfg')
38
- @exit_status = cmd.exit_status.to_i
39
- return nil if @exit_status != 0
40
- @policy = cmd.stdout
41
- @loaded = true
31
+ # load security content
32
+ def load
33
+ # export the security policy
34
+ cmd = inspec.command('secedit /export /cfg win_secpol.cfg')
35
+ return nil if cmd.exit_status.to_i != 0
42
36
 
43
- # returns self
44
- self
37
+ # store file content
38
+ cmd = inspec.command('Get-Content win_secpol.cfg')
39
+ @exit_status = cmd.exit_status.to_i
40
+ return nil if @exit_status != 0
41
+ @policy = cmd.stdout
42
+ @loaded = true
45
43
 
46
- ensure
47
- # delete temp file
48
- inspec.command('Remove-Item win_secpol.cfg').exit_status.to_i
49
- end
44
+ # returns self
45
+ self
50
46
 
51
- def method_missing(method)
52
- # load data if needed
53
- if @loaded == false
54
- load
47
+ ensure
48
+ # delete temp file
49
+ inspec.command('Remove-Item win_secpol.cfg').exit_status.to_i
55
50
  end
56
51
 
57
- # find line with key
58
- key = Regexp.escape(method.to_s)
59
- target = ''
60
- @policy.each_line {|s|
61
- target = s.strip if s =~ /^\s*#{key}\s*=\s*(.*)\b/
62
- }
52
+ def method_missing(method)
53
+ # load data if needed
54
+ if @loaded == false
55
+ load
56
+ end
63
57
 
64
- # extract variable value
65
- result = target.match(/[=]{1}\s*(?<value>.*)/)
58
+ # find line with key
59
+ key = Regexp.escape(method.to_s)
60
+ target = ''
61
+ @policy.each_line {|s|
62
+ target = s.strip if s =~ /^\s*#{key}\s*=\s*(.*)\b/
63
+ }
66
64
 
67
- if !result.nil?
68
- val = result[:value]
69
- val = val.to_i if val =~ /^\d+$/
70
- else
71
- # TODO: we may need to return skip or failure if the
72
- # requested value is not available
73
- val = nil
74
- end
65
+ # extract variable value
66
+ result = target.match(/[=]{1}\s*(?<value>.*)/)
75
67
 
76
- val
77
- end
68
+ if !result.nil?
69
+ val = result[:value]
70
+ val = val.to_i if val =~ /^\d+$/
71
+ else
72
+ # TODO: we may need to return skip or failure if the
73
+ # requested value is not available
74
+ val = nil
75
+ end
76
+
77
+ val
78
+ end
78
79
 
79
- def to_s
80
- 'Security Policy'
80
+ def to_s
81
+ 'Security Policy'
82
+ end
81
83
  end
82
84
  end
@@ -4,728 +4,730 @@
4
4
  # author: Stephan Renatus
5
5
  # license: All rights reserved
6
6
 
7
- class Runlevels < Hash
8
- attr_accessor :owner
9
-
10
- def self.from_hash(owner, hash = {}, filter = nil)
11
- res = Runlevels.new(owner)
12
- filter = filter.first if filter.is_a?(Array) && filter.length <= 1
13
-
14
- ks = case filter
15
- when nil
16
- hash.keys
17
- when Regexp
18
- hash.keys.find_all { |x| x.to_s =~ filter }
19
- when Array
20
- f = filter.map(&:to_s)
21
- hash.keys.find_all { |x| f.include?(x.to_s) }
22
- when Numeric
23
- hash.keys.include?(filter) ? [filter] : []
24
- else
25
- hash.keys.find_all { |x| x == filter }
26
- end
27
-
28
- ks.each { |k| res[k] = hash[k] }
29
- res
30
- end
31
-
32
- def initialize(owner, default = false)
33
- @owner = owner
34
- super(default)
35
- end
7
+ module Inspec::Resources
8
+ class Runlevels < Hash
9
+ attr_accessor :owner
10
+
11
+ def self.from_hash(owner, hash = {}, filter = nil)
12
+ res = Runlevels.new(owner)
13
+ filter = filter.first if filter.is_a?(Array) && filter.length <= 1
14
+
15
+ ks = case filter
16
+ when nil
17
+ hash.keys
18
+ when Regexp
19
+ hash.keys.find_all { |x| x.to_s =~ filter }
20
+ when Array
21
+ f = filter.map(&:to_s)
22
+ hash.keys.find_all { |x| f.include?(x.to_s) }
23
+ when Numeric
24
+ hash.keys.include?(filter) ? [filter] : []
25
+ else
26
+ hash.keys.find_all { |x| x == filter }
27
+ end
28
+
29
+ ks.each { |k| res[k] = hash[k] }
30
+ res
31
+ end
36
32
 
37
- def filter(f)
38
- Runlevels.from_hash(owner, self, f)
39
- end
33
+ def initialize(owner, default = false)
34
+ @owner = owner
35
+ super(default)
36
+ end
40
37
 
41
- # Check if all runlevels are enabled
42
- #
43
- # @return [boolean] true if all runlevels are enabled
44
- def enabled?
45
- values.all?
46
- end
38
+ def filter(f)
39
+ Runlevels.from_hash(owner, self, f)
40
+ end
47
41
 
48
- # Check if all runlevels are disabled
49
- #
50
- # @return [boolean] true if all runlevels are disabled
51
- def disabled?
52
- !values.any?
53
- end
42
+ # Check if all runlevels are enabled
43
+ #
44
+ # @return [boolean] true if all runlevels are enabled
45
+ def enabled?
46
+ values.all?
47
+ end
54
48
 
55
- def to_s
56
- "#{owner} runlevels #{keys.join(', ')}"
57
- end
58
- end
49
+ # Check if all runlevels are disabled
50
+ #
51
+ # @return [boolean] true if all runlevels are disabled
52
+ def disabled?
53
+ !values.any?
54
+ end
59
55
 
60
- # We detect the init system for each operating system, based on the operating
61
- # system.
62
- #
63
- # Fedora 15 : systemd
64
- # RedHat 7 : systemd
65
- # Ubuntu 15.04 : systemd
66
- # Ubuntu < 15.04 : upstart
67
- #
68
- # TODO: extend the logic to detect the running init system, independently of OS
69
- class Service < Inspec.resource(1)
70
- name 'service'
71
- desc 'Use the service InSpec audit resource to test if the named service is installed, running and/or enabled.'
72
- example "
73
- describe service('service_name') do
74
- it { should be_installed }
75
- it { should be_enabled }
76
- it { should be_running }
77
- end
78
-
79
- describe service('service_name').runlevels(3, 5) do
80
- it { should be_enabled }
81
- end
82
- "
83
-
84
- attr_reader :service_ctl
85
-
86
- def initialize(service_name, service_ctl = nil)
87
- @service_name = service_name
88
- @service_mgmt = nil
89
- @service_ctl ||= service_ctl
90
- @cache = nil
91
- @service_mgmt = select_service_mgmt
92
-
93
- return skip_resource 'The `service` resource is not supported on your OS yet.' if @service_mgmt.nil?
56
+ def to_s
57
+ "#{owner} runlevels #{keys.join(', ')}"
58
+ end
94
59
  end
95
60
 
96
- def select_service_mgmt # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
97
- os = inspec.os
98
- family = os[:family]
99
-
100
- # Ubuntu
101
- # @see: https://wiki.ubuntu.com/SystemdForUpstartUsers
102
- # Ubuntu 15.04 : Systemd
103
- # Systemd runs with PID 1 as /sbin/init.
104
- # Upstart runs with PID 1 as /sbin/upstart.
105
- # Ubuntu < 15.04 : Upstart
106
- # Upstart runs with PID 1 as /sbin/init.
107
- # Systemd runs with PID 1 as /lib/systemd/systemd.
108
- if %w{ubuntu}.include?(family)
109
- version = inspec.os[:release].to_f
110
- if version < 15.04
111
- Upstart.new(inspec, service_ctl)
112
- else
113
- Systemd.new(inspec, service_ctl)
61
+ # We detect the init system for each operating system, based on the operating
62
+ # system.
63
+ #
64
+ # Fedora 15 : systemd
65
+ # RedHat 7 : systemd
66
+ # Ubuntu 15.04 : systemd
67
+ # Ubuntu < 15.04 : upstart
68
+ #
69
+ # TODO: extend the logic to detect the running init system, independently of OS
70
+ class Service < Inspec.resource(1)
71
+ name 'service'
72
+ desc 'Use the service InSpec audit resource to test if the named service is installed, running and/or enabled.'
73
+ example "
74
+ describe service('service_name') do
75
+ it { should be_installed }
76
+ it { should be_enabled }
77
+ it { should be_running }
114
78
  end
115
- elsif %w{debian}.include?(family)
116
- version = inspec.os[:release].to_i
117
- if version > 7
118
- Systemd.new(inspec, service_ctl)
119
- else
120
- SysV.new(inspec, service_ctl || '/usr/sbin/service')
79
+
80
+ describe service('service_name').runlevels(3, 5) do
81
+ it { should be_enabled }
121
82
  end
122
- elsif %w{redhat fedora centos}.include?(family)
123
- version = inspec.os[:release].to_i
124
- if (%w{ redhat centos }.include?(family) && version >= 7) || (family == 'fedora' && version >= 15)
83
+ "
84
+
85
+ attr_reader :service_ctl
86
+
87
+ def initialize(service_name, service_ctl = nil)
88
+ @service_name = service_name
89
+ @service_mgmt = nil
90
+ @service_ctl ||= service_ctl
91
+ @cache = nil
92
+ @service_mgmt = select_service_mgmt
93
+
94
+ return skip_resource 'The `service` resource is not supported on your OS yet.' if @service_mgmt.nil?
95
+ end
96
+
97
+ def select_service_mgmt # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
98
+ os = inspec.os
99
+ family = os[:family]
100
+
101
+ # Ubuntu
102
+ # @see: https://wiki.ubuntu.com/SystemdForUpstartUsers
103
+ # Ubuntu 15.04 : Systemd
104
+ # Systemd runs with PID 1 as /sbin/init.
105
+ # Upstart runs with PID 1 as /sbin/upstart.
106
+ # Ubuntu < 15.04 : Upstart
107
+ # Upstart runs with PID 1 as /sbin/init.
108
+ # Systemd runs with PID 1 as /lib/systemd/systemd.
109
+ if %w{ubuntu}.include?(family)
110
+ version = inspec.os[:release].to_f
111
+ if version < 15.04
112
+ Upstart.new(inspec, service_ctl)
113
+ else
114
+ Systemd.new(inspec, service_ctl)
115
+ end
116
+ elsif %w{debian}.include?(family)
117
+ version = inspec.os[:release].to_i
118
+ if version > 7
119
+ Systemd.new(inspec, service_ctl)
120
+ else
121
+ SysV.new(inspec, service_ctl || '/usr/sbin/service')
122
+ end
123
+ elsif %w{redhat fedora centos}.include?(family)
124
+ version = inspec.os[:release].to_i
125
+ if (%w{ redhat centos }.include?(family) && version >= 7) || (family == 'fedora' && version >= 15)
126
+ Systemd.new(inspec, service_ctl)
127
+ else
128
+ SysV.new(inspec, service_ctl || '/sbin/service')
129
+ end
130
+ elsif %w{wrlinux}.include?(family)
131
+ SysV.new(inspec, service_ctl)
132
+ elsif %w{darwin}.include?(family)
133
+ LaunchCtl.new(inspec, service_ctl)
134
+ elsif os.windows?
135
+ WindowsSrv.new(inspec)
136
+ elsif %w{freebsd}.include?(family)
137
+ BSDInit.new(inspec, service_ctl)
138
+ elsif %w{arch opensuse}.include?(family)
125
139
  Systemd.new(inspec, service_ctl)
126
- else
127
- SysV.new(inspec, service_ctl || '/sbin/service')
140
+ elsif %w{aix}.include?(family)
141
+ SrcMstr.new(inspec)
142
+ elsif os.solaris?
143
+ Svcs.new(inspec)
128
144
  end
129
- elsif %w{wrlinux}.include?(family)
130
- SysV.new(inspec, service_ctl)
131
- elsif %w{darwin}.include?(family)
132
- LaunchCtl.new(inspec, service_ctl)
133
- elsif os.windows?
134
- WindowsSrv.new(inspec)
135
- elsif %w{freebsd}.include?(family)
136
- BSDInit.new(inspec, service_ctl)
137
- elsif %w{arch opensuse}.include?(family)
138
- Systemd.new(inspec, service_ctl)
139
- elsif %w{aix}.include?(family)
140
- SrcMstr.new(inspec)
141
- elsif os.solaris?
142
- Svcs.new(inspec)
143
145
  end
144
- end
145
146
 
146
- def info
147
- return nil if @service_mgmt.nil?
148
- @cache ||= @service_mgmt.info(@service_name)
149
- end
147
+ def info
148
+ return nil if @service_mgmt.nil?
149
+ @cache ||= @service_mgmt.info(@service_name)
150
+ end
150
151
 
151
- # verifies if the service is enabled
152
- def enabled?(_level = nil)
153
- return false if info.nil?
154
- info[:enabled]
155
- end
152
+ # verifies if the service is enabled
153
+ def enabled?(_level = nil)
154
+ return false if info.nil?
155
+ info[:enabled]
156
+ end
156
157
 
157
- # verifies the service is registered
158
- def installed?(_name = nil, _version = nil)
159
- return false if info.nil?
160
- info[:installed]
161
- end
158
+ # verifies the service is registered
159
+ def installed?(_name = nil, _version = nil)
160
+ return false if info.nil?
161
+ info[:installed]
162
+ end
162
163
 
163
- # verifies the service is currently running
164
- def running?(_under = nil)
165
- return false if info.nil?
166
- info[:running]
167
- end
164
+ # verifies the service is currently running
165
+ def running?(_under = nil)
166
+ return false if info.nil?
167
+ info[:running]
168
+ end
168
169
 
169
- # get all runlevels that are available and their configuration
170
- def runlevels(*args)
171
- return Runlevels.new(self) if info.nil? or info[:runlevels].nil?
172
- Runlevels.from_hash(self, info[:runlevels], args)
173
- end
170
+ # get all runlevels that are available and their configuration
171
+ def runlevels(*args)
172
+ return Runlevels.new(self) if info.nil? or info[:runlevels].nil?
173
+ Runlevels.from_hash(self, info[:runlevels], args)
174
+ end
174
175
 
175
- def to_s
176
- "Service #{@service_name}"
176
+ def to_s
177
+ "Service #{@service_name}"
178
+ end
177
179
  end
178
- end
179
180
 
180
- class ServiceManager
181
- attr_reader :inspec, :service_ctl
182
- def initialize(inspec, service_ctl = nil)
183
- @inspec = inspec
184
- @service_ctl ||= service_ctl
181
+ class ServiceManager
182
+ attr_reader :inspec, :service_ctl
183
+ def initialize(inspec, service_ctl = nil)
184
+ @inspec = inspec
185
+ @service_ctl ||= service_ctl
186
+ end
185
187
  end
186
- end
187
188
 
188
- # @see: http://www.freedesktop.org/software/systemd/man/systemctl.html
189
- # @see: http://www.freedesktop.org/software/systemd/man/systemd-system.conf.html
190
- class Systemd < ServiceManager
191
- def initialize(inspec, service_ctl = nil)
192
- @service_ctl = service_ctl || 'systemctl'
193
- super
194
- end
189
+ # @see: http://www.freedesktop.org/software/systemd/man/systemctl.html
190
+ # @see: http://www.freedesktop.org/software/systemd/man/systemd-system.conf.html
191
+ class Systemd < ServiceManager
192
+ def initialize(inspec, service_ctl = nil)
193
+ @service_ctl = service_ctl || 'systemctl'
194
+ super
195
+ end
195
196
 
196
- def info(service_name)
197
- cmd = inspec.command("#{service_ctl} show --all #{service_name}")
198
- return nil if cmd.exit_status.to_i != 0
199
-
200
- # parse data
201
- params = SimpleConfig.new(
202
- cmd.stdout.chomp,
203
- assignment_re: /^\s*([^=]*?)\s*=\s*(.*?)\s*$/,
204
- multiple_values: false,
205
- ).params
206
-
207
- # LoadState values eg. loaded, not-found
208
- installed = params['LoadState'] == 'loaded'
209
- # test via 'systemctl is-active service'
210
- # SubState values running
211
- running = params['SubState'] == 'running'
212
- # test via systemctl --quiet is-enabled
213
- # ActiveState values eg.g inactive, active
214
- enabled = params['UnitFileState'] == 'enabled'
215
-
216
- {
217
- name: params['Id'],
218
- description: params['Description'],
219
- installed: installed,
220
- running: running,
221
- enabled: enabled,
222
- type: 'systemd',
223
- }
197
+ def info(service_name)
198
+ cmd = inspec.command("#{service_ctl} show --all #{service_name}")
199
+ return nil if cmd.exit_status.to_i != 0
200
+
201
+ # parse data
202
+ params = SimpleConfig.new(
203
+ cmd.stdout.chomp,
204
+ assignment_re: /^\s*([^=]*?)\s*=\s*(.*?)\s*$/,
205
+ multiple_values: false,
206
+ ).params
207
+
208
+ # LoadState values eg. loaded, not-found
209
+ installed = params['LoadState'] == 'loaded'
210
+ # test via 'systemctl is-active service'
211
+ # SubState values running
212
+ running = params['SubState'] == 'running'
213
+ # test via systemctl --quiet is-enabled
214
+ # ActiveState values eg.g inactive, active
215
+ enabled = params['UnitFileState'] == 'enabled'
216
+
217
+ {
218
+ name: params['Id'],
219
+ description: params['Description'],
220
+ installed: installed,
221
+ running: running,
222
+ enabled: enabled,
223
+ type: 'systemd',
224
+ }
225
+ end
224
226
  end
225
- end
226
227
 
227
- # AIX services
228
- class SrcMstr < ServiceManager
229
- attr_reader :name
230
-
231
- def info(service_name)
232
- @name = service_name
233
- running = status?
234
- return nil if running.nil?
235
-
236
- {
237
- name: service_name,
238
- description: nil,
239
- installed: true,
240
- running: running,
241
- enabled: enabled?,
242
- type: 'srcmstr',
243
- }
244
- end
228
+ # AIX services
229
+ class SrcMstr < ServiceManager
230
+ attr_reader :name
245
231
 
246
- private
232
+ def info(service_name)
233
+ @name = service_name
234
+ running = status?
235
+ return nil if running.nil?
247
236
 
248
- def status?
249
- status_cmd = inspec.command("lssrc -s #{@name}")
250
- return nil if status_cmd.exit_status.to_i != 0
251
- status_cmd.stdout.split(/\n/).last.chomp =~ /active$/ ? true : false
252
- end
237
+ {
238
+ name: service_name,
239
+ description: nil,
240
+ installed: true,
241
+ running: running,
242
+ enabled: enabled?,
243
+ type: 'srcmstr',
244
+ }
245
+ end
253
246
 
254
- def enabled?
255
- enabled_rc_tcpip? || enabled_inittab?
256
- end
247
+ private
257
248
 
258
- # #rubocop:disable Style/TrailingComma
259
- def enabled_rc_tcpip?
260
- inspec.command(
261
- "grep -v ^# /etc/rc.tcpip | grep 'start ' | grep -Eq '(/{0,1}| )#{name} '",
262
- ).exit_status == 0
263
- end
249
+ def status?
250
+ status_cmd = inspec.command("lssrc -s #{@name}")
251
+ return nil if status_cmd.exit_status.to_i != 0
252
+ status_cmd.stdout.split(/\n/).last.chomp =~ /active$/ ? true : false
253
+ end
264
254
 
265
- def enabled_inittab?
266
- inspec.command("lsitab #{name}").exit_status == 0
267
- end
268
- end
255
+ def enabled?
256
+ enabled_rc_tcpip? || enabled_inittab?
257
+ end
269
258
 
270
- # @see: http://upstart.ubuntu.com
271
- class Upstart < ServiceManager
272
- def initialize(service_name, service_ctl = nil)
273
- @service_ctl = service_ctl || 'initctl'
274
- super
275
- end
259
+ # #rubocop:disable Style/TrailingComma
260
+ def enabled_rc_tcpip?
261
+ inspec.command(
262
+ "grep -v ^# /etc/rc.tcpip | grep 'start ' | grep -Eq '(/{0,1}| )#{name} '",
263
+ ).exit_status == 0
264
+ end
276
265
 
277
- def info(service_name)
278
- # get the status of upstart service
279
- status = inspec.command("#{service_ctl} status #{service_name}")
280
-
281
- # fallback for systemv services, those are not handled via `initctl`
282
- return SysV.new(inspec).info(service_name) if status.exit_status.to_i != 0
283
-
284
- # @see: http://upstart.ubuntu.com/cookbook/#job-states
285
- # grep for running to indicate the service is there
286
- running = !status.stdout[%r{start/running}].nil?
287
-
288
- {
289
- name: service_name,
290
- description: nil,
291
- installed: true,
292
- running: running,
293
- enabled: info_enabled(status, service_name),
294
- type: 'upstart',
295
- }
266
+ def enabled_inittab?
267
+ inspec.command("lsitab #{name}").exit_status == 0
268
+ end
296
269
  end
297
270
 
298
- private
299
-
300
- def info_enabled(status, service_name)
301
- # check if a service is enabled
302
- # http://upstart.ubuntu.com/cookbook/#determine-if-a-job-is-disabled
303
- # $ initctl show-config $job | grep -q "^ start on" && echo enabled || echo disabled
304
- # Ubuntu 10.04 show-config is not supported
305
- # @see http://manpages.ubuntu.com/manpages/maverick/man8/initctl.8.html
306
- support_for_show_config = Gem::Version.new('1.3')
307
-
308
- if version >= support_for_show_config
309
- config = inspec.command("#{service_ctl} show-config #{service_name}").stdout
310
- else # use config file as fallback
311
- config = inspec.file("/etc/init/#{service_name}.conf").content
271
+ # @see: http://upstart.ubuntu.com
272
+ class Upstart < ServiceManager
273
+ def initialize(service_name, service_ctl = nil)
274
+ @service_ctl = service_ctl || 'initctl'
275
+ super
312
276
  end
313
277
 
314
- # disregard if the config does not exist
315
- return nil if config.nil?
316
- enabled = !config[/^\s*start on/].nil?
317
-
318
- # implement fallback for Ubuntu 10.04
319
- if inspec.os[:family] == 'ubuntu' &&
320
- inspec.os[:release].to_f >= 10.04 &&
321
- inspec.os[:release].to_f < 12.04 &&
322
- status.exit_status == 0
323
- enabled = true
278
+ def info(service_name)
279
+ # get the status of upstart service
280
+ status = inspec.command("#{service_ctl} status #{service_name}")
281
+
282
+ # fallback for systemv services, those are not handled via `initctl`
283
+ return SysV.new(inspec).info(service_name) if status.exit_status.to_i != 0
284
+
285
+ # @see: http://upstart.ubuntu.com/cookbook/#job-states
286
+ # grep for running to indicate the service is there
287
+ running = !status.stdout[%r{start/running}].nil?
288
+
289
+ {
290
+ name: service_name,
291
+ description: nil,
292
+ installed: true,
293
+ running: running,
294
+ enabled: info_enabled(status, service_name),
295
+ type: 'upstart',
296
+ }
324
297
  end
325
298
 
326
- enabled
327
- end
299
+ private
328
300
 
329
- def version
330
- @version ||= (
331
- out = inspec.command("#{service_ctl} --version").stdout
332
- Gem::Version.new(out[/\(upstart ([^\)]+)\)/, 1])
333
- )
334
- end
335
- end
301
+ def info_enabled(status, service_name)
302
+ # check if a service is enabled
303
+ # http://upstart.ubuntu.com/cookbook/#determine-if-a-job-is-disabled
304
+ # $ initctl show-config $job | grep -q "^ start on" && echo enabled || echo disabled
305
+ # Ubuntu 10.04 show-config is not supported
306
+ # @see http://manpages.ubuntu.com/manpages/maverick/man8/initctl.8.html
307
+ support_for_show_config = Gem::Version.new('1.3')
336
308
 
337
- class SysV < ServiceManager
338
- RUNLEVELS = { 0=>false, 1=>false, 2=>false, 3=>false, 4=>false, 5=>false, 6=>false }.freeze
309
+ if version >= support_for_show_config
310
+ config = inspec.command("#{service_ctl} show-config #{service_name}").stdout
311
+ else # use config file as fallback
312
+ config = inspec.file("/etc/init/#{service_name}.conf").content
313
+ end
339
314
 
340
- def initialize(service_name, service_ctl = nil)
341
- @service_ctl = service_ctl || 'service'
342
- super
343
- end
315
+ # disregard if the config does not exist
316
+ return nil if config.nil?
317
+ enabled = !config[/^\s*start on/].nil?
344
318
 
345
- def info(service_name)
346
- # check if service is installed
347
- # read all available services via ls /etc/init.d/
348
- srvlist = inspec.command('ls -1 /etc/init.d/')
349
- return nil if srvlist.exit_status != 0
350
-
351
- # check if the service is in list
352
- service = srvlist.stdout.split("\n").select { |srv| srv == service_name }
353
-
354
- # abort if we could not find any service
355
- return nil if service.empty?
356
-
357
- # read all enabled services from runlevel
358
- # on rhel via: 'chkconfig --list', is not installed by default
359
- # bash: for i in `find /etc/rc*.d -name S*`; do basename $i | sed -r 's/^S[0-9]+//'; done | sort | uniq
360
- enabled_services_cmd = inspec.command('find /etc/rc*.d -name S*')
361
- service_line = %r{rc(?<runlevel>[0-6])\.d/S[^/]*?#{Regexp.escape service_name}$}
362
- all_services = enabled_services_cmd.stdout.split("\n").map { |line|
363
- service_line.match(line)
364
- }.compact
365
- enabled = !all_services.empty?
366
-
367
- # Determine a list of runlevels which this service is activated for
368
- runlevels = RUNLEVELS.dup
369
- all_services.each { |x| runlevels[x[:runlevel].to_i] = true }
370
-
371
- # check if service is really running
372
- # service throws an exit code if the service is not installed or
373
- # not enabled
374
-
375
- cmd = inspec.command("#{service_ctl} #{service_name} status")
376
- running = cmd.exit_status == 0
377
- {
378
- name: service_name,
379
- description: nil,
380
- installed: true,
381
- running: running,
382
- enabled: enabled,
383
- runlevels: runlevels,
384
- type: 'sysv',
385
- }
386
- end
387
- end
388
-
389
- # @see: https://www.freebsd.org/doc/en/articles/linux-users/startup.html
390
- # @see: https://www.freebsd.org/cgi/man.cgi?query=rc.conf&sektion=5
391
- class BSDInit < ServiceManager
392
- def initialize(service_name, service_ctl = nil)
393
- @service_ctl = service_ctl || 'service'
394
- super
395
- end
319
+ # implement fallback for Ubuntu 10.04
320
+ if inspec.os[:family] == 'ubuntu' &&
321
+ inspec.os[:release].to_f >= 10.04 &&
322
+ inspec.os[:release].to_f < 12.04 &&
323
+ status.exit_status == 0
324
+ enabled = true
325
+ end
396
326
 
397
- def info(service_name)
398
- # check if service is enabled
399
- # services are enabled in /etc/rc.conf and /etc/defaults/rc.conf
400
- # via #{service_name}_enable="YES"
401
- # service SERVICE status returns the following result if not activated:
402
- # Cannot 'status' sshd. Set sshd_enable to YES in /etc/rc.conf or use 'onestatus' instead of 'status'.
403
- # gather all enabled services
404
- cmd = inspec.command("#{service_ctl} -e")
405
- return nil if cmd.exit_status != 0
406
-
407
- # search for the service
408
- srv = /(^.*#{service_name}$)/.match(cmd.stdout)
409
- return nil if srv.nil? || srv[0].nil?
410
- enabled = true
411
-
412
- # check if the service is running
413
- # if the service is not available or not running, we always get an error code
414
- cmd = inspec.command("#{service_ctl} #{service_name} onestatus")
415
- running = cmd.exit_status == 0
416
-
417
- {
418
- name: service_name,
419
- description: nil,
420
- installed: true,
421
- running: running,
422
- enabled: enabled,
423
- type: 'bsd-init',
424
- }
425
- end
426
- end
327
+ enabled
328
+ end
427
329
 
428
- class Runit < ServiceManager
429
- def initialize(service_name, service_ctl = nil)
430
- @service_ctl = service_ctl || 'sv'
431
- super
330
+ def version
331
+ @version ||= (
332
+ out = inspec.command("#{service_ctl} --version").stdout
333
+ Gem::Version.new(out[/\(upstart ([^\)]+)\)/, 1])
334
+ )
335
+ end
432
336
  end
433
337
 
434
- # rubocop:disable Style/DoubleNegation
435
- def info(service_name)
436
- # get the status of runit service
437
- cmd = inspec.command("#{service_ctl} status #{service_name}")
438
- # return nil unless cmd.exit_status == 0 # NOTE(sr) why do we do this?
439
-
440
- installed = cmd.exit_status == 0
441
- running = installed && !!(cmd.stdout =~ /^run:/)
442
- enabled = installed && (running || !!(cmd.stdout =~ /normally up/) || !!(cmd.stdout =~ /want up/))
443
-
444
- {
445
- name: service_name,
446
- description: nil,
447
- installed: installed,
448
- running: running,
449
- enabled: enabled,
450
- type: 'runit',
451
- }
452
- end
453
- end
338
+ class SysV < ServiceManager
339
+ RUNLEVELS = { 0=>false, 1=>false, 2=>false, 3=>false, 4=>false, 5=>false, 6=>false }.freeze
454
340
 
455
- # MacOS / Darwin
456
- # new launctl on macos 10.10
457
- class LaunchCtl < ServiceManager
458
- def initialize(service_name, service_ctl = nil)
459
- @service_ctl = service_ctl || 'launchctl'
460
- super
461
- end
341
+ def initialize(service_name, service_ctl = nil)
342
+ @service_ctl = service_ctl || 'service'
343
+ super
344
+ end
462
345
 
463
- def info(service_name)
464
- # get the status of upstart service
465
- cmd = inspec.command("#{service_ctl} list")
466
- return nil if cmd.exit_status != 0
467
-
468
- # search for the service
469
- srv = /(^.*#{service_name}.*)/.match(cmd.stdout)
470
- return nil if srv.nil? || srv[0].nil?
471
-
472
- # extract values from service
473
- parsed_srv = /^(?<pid>[0-9-]+)\t(?<exit>[0-9]+)\t(?<name>\S*)$/.match(srv[0])
474
- enabled = !parsed_srv['name'].nil? # it's in the list
475
-
476
- # check if the service is running
477
- pid = parsed_srv['pid']
478
- running = pid != '-'
479
-
480
- # extract service label
481
- srv = parsed_srv['name'] || service_name
482
-
483
- {
484
- name: srv,
485
- description: nil,
486
- installed: true,
487
- running: running,
488
- enabled: enabled,
489
- type: 'darwin',
490
- }
346
+ def info(service_name)
347
+ # check if service is installed
348
+ # read all available services via ls /etc/init.d/
349
+ srvlist = inspec.command('ls -1 /etc/init.d/')
350
+ return nil if srvlist.exit_status != 0
351
+
352
+ # check if the service is in list
353
+ service = srvlist.stdout.split("\n").select { |srv| srv == service_name }
354
+
355
+ # abort if we could not find any service
356
+ return nil if service.empty?
357
+
358
+ # read all enabled services from runlevel
359
+ # on rhel via: 'chkconfig --list', is not installed by default
360
+ # bash: for i in `find /etc/rc*.d -name S*`; do basename $i | sed -r 's/^S[0-9]+//'; done | sort | uniq
361
+ enabled_services_cmd = inspec.command('find /etc/rc*.d -name S*')
362
+ service_line = %r{rc(?<runlevel>[0-6])\.d/S[^/]*?#{Regexp.escape service_name}$}
363
+ all_services = enabled_services_cmd.stdout.split("\n").map { |line|
364
+ service_line.match(line)
365
+ }.compact
366
+ enabled = !all_services.empty?
367
+
368
+ # Determine a list of runlevels which this service is activated for
369
+ runlevels = RUNLEVELS.dup
370
+ all_services.each { |x| runlevels[x[:runlevel].to_i] = true }
371
+
372
+ # check if service is really running
373
+ # service throws an exit code if the service is not installed or
374
+ # not enabled
375
+
376
+ cmd = inspec.command("#{service_ctl} #{service_name} status")
377
+ running = cmd.exit_status == 0
378
+ {
379
+ name: service_name,
380
+ description: nil,
381
+ installed: true,
382
+ running: running,
383
+ enabled: enabled,
384
+ runlevels: runlevels,
385
+ type: 'sysv',
386
+ }
387
+ end
491
388
  end
492
- end
493
389
 
494
- # Determine the service state from Windows
495
- # Uses Powershell to retrieve the information
496
- class WindowsSrv < ServiceManager
497
- # Determine service details
498
- # PS: Get-Service -Name 'dhcp'| Select-Object -Property Name, DisplayName, Status | ConvertTo-Json
499
- # {
500
- # "Name": "dhcp",
501
- # "DisplayName": "DHCP Client",
502
- # "Status": 4
503
- # }
504
- #
505
- # Until StartMode is not added to Get-Service, we need to do a workaround
506
- # @see: https://connect.microsoft.com/PowerShell/feedback/details/424948/i-would-like-to-see-the-property-starttype-added-to-get-services
507
- # Use the following powershell to determine the start mode
508
- # PS: Get-WmiObject -Class Win32_Service | Where-Object {$_.Name -eq $name -or $_.DisplayName -eq $name} | Select-Object -Prop
509
- # erty Name, StartMode, State, Status | ConvertTo-Json
510
- # {
511
- # "Name": "Dhcp",
512
- # "StartMode": "Auto",
513
- # "State": "Running",
514
- # "Status": "OK"
515
- # }
516
- #
517
- # Windows Services have the following status code:
518
- # @see: https://msdn.microsoft.com/en-us/library/windows/desktop/ms685996(v=vs.85).aspx
519
- # - 1: Stopped
520
- # - 2: Starting
521
- # - 3: Stopping
522
- # - 4: Running
523
- # - 5: Continue Pending
524
- # - 6: Pause Pending
525
- # - 7: Paused
526
- def info(service_name)
527
- cmd = inspec.command("New-Object -Type PSObject | Add-Member -MemberType NoteProperty -Name Service -Value (Get-Service -Name #{service_name}| Select-Object -Property Name, DisplayName, Status) -PassThru | Add-Member -MemberType NoteProperty -Name WMI -Value (Get-WmiObject -Class Win32_Service | Where-Object {$_.Name -eq '#{service_name}' -or $_.DisplayName -eq '#{service_name}'} | Select-Object -Property StartMode) -PassThru | ConvertTo-Json")
528
-
529
- # cannot rely on exit code for now, successful command returns exit code 1
530
- # return nil if cmd.exit_status != 0
531
- # try to parse json
532
- begin
533
- service = JSON.parse(cmd.stdout)
534
- rescue JSON::ParserError => _e
535
- return nil
536
- end
537
-
538
- # check that we got a response
539
- return nil if service.nil? || service['Service'].nil?
540
-
541
- {
542
- name: service['Service']['Name'],
543
- description: service['Service']['DisplayName'],
544
- installed: true,
545
- running: service_running?(service),
546
- enabled: service_enabled?(service),
547
- type: 'windows',
548
- }
549
- end
390
+ # @see: https://www.freebsd.org/doc/en/articles/linux-users/startup.html
391
+ # @see: https://www.freebsd.org/cgi/man.cgi?query=rc.conf&sektion=5
392
+ class BSDInit < ServiceManager
393
+ def initialize(service_name, service_ctl = nil)
394
+ @service_ctl = service_ctl || 'service'
395
+ super
396
+ end
550
397
 
551
- private
398
+ def info(service_name)
399
+ # check if service is enabled
400
+ # services are enabled in /etc/rc.conf and /etc/defaults/rc.conf
401
+ # via #{service_name}_enable="YES"
402
+ # service SERVICE status returns the following result if not activated:
403
+ # Cannot 'status' sshd. Set sshd_enable to YES in /etc/rc.conf or use 'onestatus' instead of 'status'.
404
+ # gather all enabled services
405
+ cmd = inspec.command("#{service_ctl} -e")
406
+ return nil if cmd.exit_status != 0
407
+
408
+ # search for the service
409
+ srv = /(^.*#{service_name}$)/.match(cmd.stdout)
410
+ return nil if srv.nil? || srv[0].nil?
411
+ enabled = true
552
412
 
553
- # detect if service is enabled
554
- def service_enabled?(service)
555
- !service['WMI'].nil? &&
556
- !service['WMI']['StartMode'].nil? &&
557
- service['WMI']['StartMode'] == 'Auto'
413
+ # check if the service is running
414
+ # if the service is not available or not running, we always get an error code
415
+ cmd = inspec.command("#{service_ctl} #{service_name} onestatus")
416
+ running = cmd.exit_status == 0
417
+
418
+ {
419
+ name: service_name,
420
+ description: nil,
421
+ installed: true,
422
+ running: running,
423
+ enabled: enabled,
424
+ type: 'bsd-init',
425
+ }
426
+ end
558
427
  end
559
428
 
560
- # detect if service is running
561
- def service_running?(service)
562
- !service['Service']['Status'].nil? && service['Service']['Status'] == 4
563
- end
564
- end
429
+ class Runit < ServiceManager
430
+ def initialize(service_name, service_ctl = nil)
431
+ @service_ctl = service_ctl || 'sv'
432
+ super
433
+ end
565
434
 
566
- # Solaris services
567
- class Svcs < ServiceManager
568
- def initialize(service_name, service_ctl = nil)
569
- @service_ctl = service_ctl || 'svcs'
570
- super
435
+ # rubocop:disable Style/DoubleNegation
436
+ def info(service_name)
437
+ # get the status of runit service
438
+ cmd = inspec.command("#{service_ctl} status #{service_name}")
439
+ # return nil unless cmd.exit_status == 0 # NOTE(sr) why do we do this?
440
+
441
+ installed = cmd.exit_status == 0
442
+ running = installed && !!(cmd.stdout =~ /^run:/)
443
+ enabled = installed && (running || !!(cmd.stdout =~ /normally up/) || !!(cmd.stdout =~ /want up/))
444
+
445
+ {
446
+ name: service_name,
447
+ description: nil,
448
+ installed: installed,
449
+ running: running,
450
+ enabled: enabled,
451
+ type: 'runit',
452
+ }
453
+ end
571
454
  end
572
455
 
573
- def info(service_name)
574
- # get the status of runit service
575
- cmd = inspec.command("#{service_ctl} -l #{service_name}")
576
- return nil if cmd.exit_status != 0
577
-
578
- params = SimpleConfig.new(
579
- cmd.stdout.chomp,
580
- assignment_re: /^(\w+)\s*(.*)$/,
581
- multiple_values: false,
582
- ).params
583
-
584
- installed = cmd.exit_status == 0
585
- running = installed && (params['state'] == 'online')
586
- enabled = installed && (params['enabled'] == 'true')
587
-
588
- {
589
- name: service_name,
590
- description: params['name'],
591
- installed: installed,
592
- running: running,
593
- enabled: enabled,
594
- type: 'svcs',
595
- }
456
+ # MacOS / Darwin
457
+ # new launctl on macos 10.10
458
+ class LaunchCtl < ServiceManager
459
+ def initialize(service_name, service_ctl = nil)
460
+ @service_ctl = service_ctl || 'launchctl'
461
+ super
462
+ end
463
+
464
+ def info(service_name)
465
+ # get the status of upstart service
466
+ cmd = inspec.command("#{service_ctl} list")
467
+ return nil if cmd.exit_status != 0
468
+
469
+ # search for the service
470
+ srv = /(^.*#{service_name}.*)/.match(cmd.stdout)
471
+ return nil if srv.nil? || srv[0].nil?
472
+
473
+ # extract values from service
474
+ parsed_srv = /^(?<pid>[0-9-]+)\t(?<exit>[0-9]+)\t(?<name>\S*)$/.match(srv[0])
475
+ enabled = !parsed_srv['name'].nil? # it's in the list
476
+
477
+ # check if the service is running
478
+ pid = parsed_srv['pid']
479
+ running = pid != '-'
480
+
481
+ # extract service label
482
+ srv = parsed_srv['name'] || service_name
483
+
484
+ {
485
+ name: srv,
486
+ description: nil,
487
+ installed: true,
488
+ running: running,
489
+ enabled: enabled,
490
+ type: 'darwin',
491
+ }
492
+ end
596
493
  end
597
- end
598
494
 
599
- # specific resources for specific service managers
495
+ # Determine the service state from Windows
496
+ # Uses Powershell to retrieve the information
497
+ class WindowsSrv < ServiceManager
498
+ # Determine service details
499
+ # PS: Get-Service -Name 'dhcp'| Select-Object -Property Name, DisplayName, Status | ConvertTo-Json
500
+ # {
501
+ # "Name": "dhcp",
502
+ # "DisplayName": "DHCP Client",
503
+ # "Status": 4
504
+ # }
505
+ #
506
+ # Until StartMode is not added to Get-Service, we need to do a workaround
507
+ # @see: https://connect.microsoft.com/PowerShell/feedback/details/424948/i-would-like-to-see-the-property-starttype-added-to-get-services
508
+ # Use the following powershell to determine the start mode
509
+ # PS: Get-WmiObject -Class Win32_Service | Where-Object {$_.Name -eq $name -or $_.DisplayName -eq $name} | Select-Object -Prop
510
+ # erty Name, StartMode, State, Status | ConvertTo-Json
511
+ # {
512
+ # "Name": "Dhcp",
513
+ # "StartMode": "Auto",
514
+ # "State": "Running",
515
+ # "Status": "OK"
516
+ # }
517
+ #
518
+ # Windows Services have the following status code:
519
+ # @see: https://msdn.microsoft.com/en-us/library/windows/desktop/ms685996(v=vs.85).aspx
520
+ # - 1: Stopped
521
+ # - 2: Starting
522
+ # - 3: Stopping
523
+ # - 4: Running
524
+ # - 5: Continue Pending
525
+ # - 6: Pause Pending
526
+ # - 7: Paused
527
+ def info(service_name)
528
+ cmd = inspec.command("New-Object -Type PSObject | Add-Member -MemberType NoteProperty -Name Service -Value (Get-Service -Name #{service_name}| Select-Object -Property Name, DisplayName, Status) -PassThru | Add-Member -MemberType NoteProperty -Name WMI -Value (Get-WmiObject -Class Win32_Service | Where-Object {$_.Name -eq '#{service_name}' -or $_.DisplayName -eq '#{service_name}'} | Select-Object -Property StartMode) -PassThru | ConvertTo-Json")
529
+
530
+ # cannot rely on exit code for now, successful command returns exit code 1
531
+ # return nil if cmd.exit_status != 0
532
+ # try to parse json
533
+ begin
534
+ service = JSON.parse(cmd.stdout)
535
+ rescue JSON::ParserError => _e
536
+ return nil
537
+ end
600
538
 
601
- class SystemdService < Service
602
- name 'systemd_service'
603
- desc 'Use the systemd_service InSpec audit resource to test if the named service (controlled by systemd) is installed, running and/or enabled.'
604
- example "
605
- # to override service mgmt auto-detection
606
- describe systemd_service('service_name') do
607
- it { should be_installed }
608
- it { should be_enabled }
609
- it { should be_running }
539
+ # check that we got a response
540
+ return nil if service.nil? || service['Service'].nil?
541
+
542
+ {
543
+ name: service['Service']['Name'],
544
+ description: service['Service']['DisplayName'],
545
+ installed: true,
546
+ running: service_running?(service),
547
+ enabled: service_enabled?(service),
548
+ type: 'windows',
549
+ }
610
550
  end
611
551
 
612
- # to set a non-standard systemctl path
613
- describe systemd_service('service_name', '/path/to/systemctl') do
614
- it { should be_running }
552
+ private
553
+
554
+ # detect if service is enabled
555
+ def service_enabled?(service)
556
+ !service['WMI'].nil? &&
557
+ !service['WMI']['StartMode'].nil? &&
558
+ service['WMI']['StartMode'] == 'Auto'
615
559
  end
616
- "
617
560
 
618
- def select_service_mgmt
619
- Systemd.new(inspec, service_ctl)
561
+ # detect if service is running
562
+ def service_running?(service)
563
+ !service['Service']['Status'].nil? && service['Service']['Status'] == 4
564
+ end
620
565
  end
621
- end
622
566
 
623
- class UpstartService < Service
624
- name 'upstart_service'
625
- desc 'Use the upstart_service InSpec audit resource to test if the named service (controlled by upstart) is installed, running and/or enabled.'
626
- example "
627
- # to override service mgmt auto-detection
628
- describe upstart_service('service_name') do
629
- it { should be_installed }
630
- it { should be_enabled }
631
- it { should be_running }
567
+ # Solaris services
568
+ class Svcs < ServiceManager
569
+ def initialize(service_name, service_ctl = nil)
570
+ @service_ctl = service_ctl || 'svcs'
571
+ super
632
572
  end
633
573
 
634
- # to set a non-standard initctl path
635
- describe upstart_service('service_name', '/path/to/initctl') do
636
- it { should be_running }
574
+ def info(service_name)
575
+ # get the status of runit service
576
+ cmd = inspec.command("#{service_ctl} -l #{service_name}")
577
+ return nil if cmd.exit_status != 0
578
+
579
+ params = SimpleConfig.new(
580
+ cmd.stdout.chomp,
581
+ assignment_re: /^(\w+)\s*(.*)$/,
582
+ multiple_values: false,
583
+ ).params
584
+
585
+ installed = cmd.exit_status == 0
586
+ running = installed && (params['state'] == 'online')
587
+ enabled = installed && (params['enabled'] == 'true')
588
+
589
+ {
590
+ name: service_name,
591
+ description: params['name'],
592
+ installed: installed,
593
+ running: running,
594
+ enabled: enabled,
595
+ type: 'svcs',
596
+ }
637
597
  end
638
- "
639
-
640
- def select_service_mgmt
641
- Upstart.new(inspec, service_ctl)
642
598
  end
643
- end
644
599
 
645
- class SysVService < Service
646
- name 'sysv_service'
647
- desc 'Use the sysv_service InSpec audit resource to test if the named service (controlled by SysV) is installed, running and/or enabled.'
648
- example "
649
- # to override service mgmt auto-detection
650
- describe sysv_service('service_name') do
651
- it { should be_installed }
652
- it { should be_enabled }
653
- it { should be_running }
654
- end
600
+ # specific resources for specific service managers
655
601
 
656
- # to set a non-standard service path
657
- describe sysv_service('service_name', '/path/to/service') do
658
- it { should be_running }
659
- end
660
- "
602
+ class SystemdService < Service
603
+ name 'systemd_service'
604
+ desc 'Use the systemd_service InSpec audit resource to test if the named service (controlled by systemd) is installed, running and/or enabled.'
605
+ example "
606
+ # to override service mgmt auto-detection
607
+ describe systemd_service('service_name') do
608
+ it { should be_installed }
609
+ it { should be_enabled }
610
+ it { should be_running }
611
+ end
661
612
 
662
- def select_service_mgmt
663
- SysV.new(inspec, service_ctl)
664
- end
665
- end
613
+ # to set a non-standard systemctl path
614
+ describe systemd_service('service_name', '/path/to/systemctl') do
615
+ it { should be_running }
616
+ end
617
+ "
666
618
 
667
- class BSDService < Service
668
- name 'bsd_service'
669
- desc 'Use the bsd_service InSpec audit resource to test if the named service (controlled by BSD init) is installed, running and/or enabled.'
670
- example "
671
- # to override service mgmt auto-detection
672
- describe bsd_service('service_name') do
673
- it { should be_installed }
674
- it { should be_enabled }
675
- it { should be_running }
619
+ def select_service_mgmt
620
+ Systemd.new(inspec, service_ctl)
676
621
  end
622
+ end
677
623
 
678
- # to set a non-standard service path
679
- describe bsd_service('service_name', '/path/to/service') do
680
- it { should be_running }
681
- end
682
- "
624
+ class UpstartService < Service
625
+ name 'upstart_service'
626
+ desc 'Use the upstart_service InSpec audit resource to test if the named service (controlled by upstart) is installed, running and/or enabled.'
627
+ example "
628
+ # to override service mgmt auto-detection
629
+ describe upstart_service('service_name') do
630
+ it { should be_installed }
631
+ it { should be_enabled }
632
+ it { should be_running }
633
+ end
683
634
 
684
- def select_service_mgmt
685
- BSDInit.new(inspec, service_ctl)
686
- end
687
- end
635
+ # to set a non-standard initctl path
636
+ describe upstart_service('service_name', '/path/to/initctl') do
637
+ it { should be_running }
638
+ end
639
+ "
688
640
 
689
- class LaunchdService < Service
690
- name 'launchd_service'
691
- desc 'Use the launchd_service InSpec audit resource to test if the named service (controlled by launchd) is installed, running and/or enabled.'
692
- example "
693
- # to override service mgmt auto-detection
694
- describe launchd_service('service_name') do
695
- it { should be_installed }
696
- it { should be_enabled }
697
- it { should be_running }
641
+ def select_service_mgmt
642
+ Upstart.new(inspec, service_ctl)
698
643
  end
644
+ end
699
645
 
700
- # to set a non-standard launchctl path
701
- describe launchd_service('service_name', '/path/to/launchctl') do
702
- it { should be_running }
703
- end
704
- "
646
+ class SysVService < Service
647
+ name 'sysv_service'
648
+ desc 'Use the sysv_service InSpec audit resource to test if the named service (controlled by SysV) is installed, running and/or enabled.'
649
+ example "
650
+ # to override service mgmt auto-detection
651
+ describe sysv_service('service_name') do
652
+ it { should be_installed }
653
+ it { should be_enabled }
654
+ it { should be_running }
655
+ end
705
656
 
706
- def select_service_mgmt
707
- LaunchCtl.new(inspec, service_ctl)
657
+ # to set a non-standard service path
658
+ describe sysv_service('service_name', '/path/to/service') do
659
+ it { should be_running }
660
+ end
661
+ "
662
+
663
+ def select_service_mgmt
664
+ SysV.new(inspec, service_ctl)
665
+ end
708
666
  end
709
- end
710
667
 
711
- class RunitService < Service
712
- name 'runit_service'
713
- desc 'Use the runit_service InSpec audit resource to test if the named service (controlled by runit) is installed, running and/or enabled.'
714
- example "
715
- # to override service mgmt auto-detection
716
- describe runit_service('service_name') do
717
- it { should be_installed }
718
- it { should be_enabled }
719
- it { should be_running }
668
+ class BSDService < Service
669
+ name 'bsd_service'
670
+ desc 'Use the bsd_service InSpec audit resource to test if the named service (controlled by BSD init) is installed, running and/or enabled.'
671
+ example "
672
+ # to override service mgmt auto-detection
673
+ describe bsd_service('service_name') do
674
+ it { should be_installed }
675
+ it { should be_enabled }
676
+ it { should be_running }
677
+ end
678
+
679
+ # to set a non-standard service path
680
+ describe bsd_service('service_name', '/path/to/service') do
681
+ it { should be_running }
682
+ end
683
+ "
684
+
685
+ def select_service_mgmt
686
+ BSDInit.new(inspec, service_ctl)
720
687
  end
688
+ end
689
+
690
+ class LaunchdService < Service
691
+ name 'launchd_service'
692
+ desc 'Use the launchd_service InSpec audit resource to test if the named service (controlled by launchd) is installed, running and/or enabled.'
693
+ example "
694
+ # to override service mgmt auto-detection
695
+ describe launchd_service('service_name') do
696
+ it { should be_installed }
697
+ it { should be_enabled }
698
+ it { should be_running }
699
+ end
721
700
 
722
- # to set a non-standard sv path
723
- describe runit_service('service_name', '/path/to/sv') do
724
- it { should be_running }
701
+ # to set a non-standard launchctl path
702
+ describe launchd_service('service_name', '/path/to/launchctl') do
703
+ it { should be_running }
704
+ end
705
+ "
706
+
707
+ def select_service_mgmt
708
+ LaunchCtl.new(inspec, service_ctl)
725
709
  end
726
- "
710
+ end
711
+
712
+ class RunitService < Service
713
+ name 'runit_service'
714
+ desc 'Use the runit_service InSpec audit resource to test if the named service (controlled by runit) is installed, running and/or enabled.'
715
+ example "
716
+ # to override service mgmt auto-detection
717
+ describe runit_service('service_name') do
718
+ it { should be_installed }
719
+ it { should be_enabled }
720
+ it { should be_running }
721
+ end
722
+
723
+ # to set a non-standard sv path
724
+ describe runit_service('service_name', '/path/to/sv') do
725
+ it { should be_running }
726
+ end
727
+ "
727
728
 
728
- def select_service_mgmt
729
- Runit.new(inspec, service_ctl)
729
+ def select_service_mgmt
730
+ Runit.new(inspec, service_ctl)
731
+ end
730
732
  end
731
733
  end