From 0e410df69d46559f852dc10e4bf7551950037c33 Mon Sep 17 00:00:00 2001 From: Stephan Renatus Date: Wed, 20 Jan 2016 14:33:24 +0100 Subject: [PATCH] add *_service overrides, allowing for different control binaries --- lib/resources/service.rb | 165 +++++++++++++++++++++++++--- test/unit/resources/service_test.rb | 10 ++ 2 files changed, 159 insertions(+), 16 deletions(-) diff --git a/lib/resources/service.rb b/lib/resources/service.rb index 55fbb20f2..964089cea 100644 --- a/lib/resources/service.rb +++ b/lib/resources/service.rb @@ -34,10 +34,10 @@ class Service < Inspec.resource(1) @service_name = service_name @service_mgmt = nil @cache = nil - select_package_manager + select_service_ctl end - def select_package_manager # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity + def select_service_ctl # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity family = inspec.os[:family] case family @@ -117,17 +117,22 @@ class Service < Inspec.resource(1) end class ServiceManager - attr_reader :inspec - def initialize(inspec) + attr_reader :inspec, :service_ctl + def initialize(inspec, service_ctl = nil) @inspec = inspec + @service_ctl = service_ctl end end # @see: http://www.freedesktop.org/software/systemd/man/systemctl.html # @see: http://www.freedesktop.org/software/systemd/man/systemd-system.conf.html class Systemd < ServiceManager + def initialize(inspec, service_ctl = 'systemctl') + super + end + def info(service_name) - cmd = inspec.command("systemctl show --all #{service_name}") + cmd = inspec.command("#{service_ctl} show --all #{service_name}") return nil if cmd.exit_status.to_i != 0 # parse data @@ -206,9 +211,13 @@ end # @see: http://upstart.ubuntu.com class Upstart < ServiceManager + def initialize(service_name, service_ctl = 'initctl') + super + end + def info(service_name) # get the status of upstart service - status = inspec.command("initctl status #{service_name}") + status = inspec.command("#{service_ctl} status #{service_name}") # fallback for systemv services, those are not handled via `initctl` return SysV.new(inspec).info(service_name) if status.exit_status.to_i != 0 @@ -235,7 +244,7 @@ class Upstart < ServiceManager # $ initctl show-config $job | grep -q "^ start on" && echo enabled || echo disabled # Ubuntu 10.04 show-config is not supported # @see http://manpages.ubuntu.com/manpages/maverick/man8/initctl.8.html - config = inspec.command("initctl show-config #{service_name}") + config = inspec.command("#{service_ctl} show-config #{service_name}") enabled = !config.stdout[/^\s*start on/].nil? # implement fallback for Ubuntu 10.04 @@ -251,6 +260,10 @@ class Upstart < ServiceManager end class SysV < ServiceManager + def initialize(service_name, service_ctl = 'service') + super + end + def info(service_name) # check if service is installed # read all available services via ls /etc/init.d/ @@ -270,19 +283,21 @@ class SysV < ServiceManager enabled_services = enabled_services_cmd.stdout.split("\n").select { |line| /(^.*#{service_name}.*)/.match(line) } - enabled_services.empty? ? enabled = false : enabled = true + enabled = !enabled_services.empty? # check if service is really running # service throws an exit code if the service is not installed or # not enabled + # FIXME(sr) # on debian service is located /usr/sbin/service, on centos it is located here /sbin/service - service_cmd = 'service' - service_cmd = '/usr/sbin/service' if inspec.os[:family] == 'debian' - service_cmd = '/sbin/service' if inspec.os[:family] == 'centos' + # service_cmd = 'service' + # service_cmd = '/usr/sbin/service' if inspec.os[:family] == 'debian' + # service_cmd = '/sbin/service' if inspec.os[:family] == 'centos' + # NOTE(sr) It's all in PATH, isn't it? - cmd = inspec.command("#{service_cmd} #{service_name} status") - cmd.exit_status == 0 ? (running = true) : (running = false) + cmd = inspec.command("#{service_ctl} #{service_name} status") + running = cmd.exit_status == 0 { name: service_name, description: nil, @@ -297,6 +312,10 @@ end # @see: https://www.freebsd.org/doc/en/articles/linux-users/startup.html # @see: https://www.freebsd.org/cgi/man.cgi?query=rc.conf&sektion=5 class BSDInit < ServiceManager + def initialize(service_name, service_ctl = 'service') + super + end + def info(service_name) # check if service is enabled # services are enabled in /etc/rc.conf and /etc/defaults/rc.conf @@ -304,7 +323,7 @@ class BSDInit < ServiceManager # service SERVICE status returns the following result if not activated: # Cannot 'status' sshd. Set sshd_enable to YES in /etc/rc.conf or use 'onestatus' instead of 'status'. # gather all enabled services - cmd = inspec.command('service -e') + cmd = inspec.command("#{service_ctl} -e") return nil if cmd.exit_status != 0 # search for the service @@ -314,7 +333,7 @@ class BSDInit < ServiceManager # check if the service is running # if the service is not available or not running, we always get an error code - cmd = inspec.command("service #{service_name} onestatus") + cmd = inspec.command("#{service_ctl} #{service_name} onestatus") cmd.exit_status == 0 ? (running = true) : (running = false) { @@ -331,9 +350,13 @@ end # MacOS / Darwin # new launctl on macos 10.10 class LaunchCtl < ServiceManager + def initialize(service_name, service_ctl = 'launchctl') + super + end + def info(service_name) # get the status of upstart service - cmd = inspec.command('launchctl list') + cmd = inspec.command("#{service_ctl} list") return nil if cmd.exit_status != 0 # search for the service @@ -442,3 +465,113 @@ class WindowsSrv < ServiceManager end end end + +class SystemdService < Service + name 'systemd_service' + desc 'Use the systemd_service InSpec audit resource to test if the named service (controlled by systemd) is installed, running and/or enabled.' + example " + # to override service mgmt auto-detection + describe systemd_service('service_name') do + it { should be_installed } + it { should be_enabled } + it { should be_running } + end + + # to set a non-standard systemctl path + describe systemd_service('service_name', '/path/to/systemctl') do + it { should be_running } + end + " + + def select_service_ctl + @service_mgmt = Systemd.new(inspec) + end +end + +class UpstartService < Service + name 'upstart_service' + desc 'Use the upstart_service InSpec audit resource to test if the named service (controlled by upstart) is installed, running and/or enabled.' + example " + # to override service mgmt auto-detection + describe upstart_service('service_name') do + it { should be_installed } + it { should be_enabled } + it { should be_running } + end + + # to set a non-standard initctl path + describe upstart_service('service_name', '/path/to/initctl') do + it { should be_running } + end + " + + def select_service_ctl + @service_mgmt = Upstart.new(inspec) + end +end + +class SysVService < Service + name 'sysv_service' + desc 'Use the sysv_service InSpec audit resource to test if the named service (controlled by SysV) is installed, running and/or enabled.' + example " + # to override service mgmt auto-detection + describe sysv_service('service_name') do + it { should be_installed } + it { should be_enabled } + it { should be_running } + end + + # to set a non-standard service path + describe sysv_service('service_name', '/path/to/service') do + it { should be_running } + end + " + + def select_service_ctl + @service_mgmt = SysV.new(inspec) + end +end + +class BSDService < Service + name 'bsd_service' + desc 'Use the bsd_service InSpec audit resource to test if the named service (controlled by BSD init) is installed, running and/or enabled.' + example " + # to override service mgmt auto-detection + describe bsd_service('service_name') do + it { should be_installed } + it { should be_enabled } + it { should be_running } + end + + # to set a non-standard service path + describe bsd_service('service_name', '/path/to/service') do + it { should be_running } + end + " + + def select_service_ctl + @service_mgmt = BSDInit.new(inspec) + end +end + +class LaunchdService < Service + name 'launchd_service' + desc 'Use the launchd_service InSpec audit resource to test if the named service (controlled by launchd) is installed, running and/or enabled.' + example " + # to override service mgmt auto-detection + describe launchd_service('service_name') do + it { should be_installed } + it { should be_enabled } + it { should be_running } + end + + # to set a non-standard launchctl path + describe launchd_service('service_name', '/path/to/launchctl') do + it { should be_running } + end + " + + def select_service_ctl + @service_mgmt = LaunchCtl.new(inspec) + end +end diff --git a/test/unit/resources/service_test.rb b/test/unit/resources/service_test.rb index 696d97d7a..d52468793 100644 --- a/test/unit/resources/service_test.rb +++ b/test/unit/resources/service_test.rb @@ -37,6 +37,16 @@ describe 'Inspec::Resources::Service' do _(resource.running?).must_equal true end + # ubuntu 15.04 with systemd_service + it 'verify ubuntu package parsing with systemd_service' do + resource = MockLoader.new(:ubuntu1504).load_resource('systemd_service', 'sshd') + srv = { name: 'sshd.service', description: 'OpenSSH server daemon', installed: true, running: true, enabled: true, type: 'systemd' } + _(resource.info).must_equal srv + _(resource.installed?).must_equal true + _(resource.enabled?).must_equal true + _(resource.running?).must_equal true + end + # centos 6 with systemv it 'verify centos 6 package parsing' do resource = MockLoader.new(:centos6).load_resource('service', 'sshd')