mirror of
https://github.com/inspec/inspec
synced 2024-11-27 23:20:33 +00:00
Merge pull request #455 from chef/dr/runlevel
add runlevel support for System V services
This commit is contained in:
commit
f01b865d94
2 changed files with 122 additions and 16 deletions
|
@ -4,13 +4,59 @@
|
||||||
# author: Stephan Renatus
|
# author: Stephan Renatus
|
||||||
# license: All rights reserved
|
# license: All rights reserved
|
||||||
|
|
||||||
# Usage:
|
class Runlevels < Hash
|
||||||
# describe service('dhcp') do
|
attr_accessor :owner
|
||||||
# it { should be_enabled }
|
|
||||||
# it { should be_installed }
|
def self.from_hash(owner, hash = {}, filter = nil)
|
||||||
# it { should be_running }
|
res = Runlevels.new(owner)
|
||||||
# end
|
filter = filter.first if filter.is_a?(Array) && filter.length <= 1
|
||||||
#
|
|
||||||
|
ks = case filter
|
||||||
|
when nil
|
||||||
|
hash.keys
|
||||||
|
when Regexp
|
||||||
|
hash.keys.find_all { |x| x.to_s =~ filter }
|
||||||
|
when Array
|
||||||
|
f = filter.map(&:to_s)
|
||||||
|
hash.keys.find_all { |x| f.include?(x.to_s) }
|
||||||
|
when Numeric
|
||||||
|
hash.keys.include?(filter) ? [filter] : []
|
||||||
|
else
|
||||||
|
hash.keys.find_all { |x| x == filter }
|
||||||
|
end
|
||||||
|
|
||||||
|
ks.each { |k| res[k] = hash[k] }
|
||||||
|
res
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(owner, default = false)
|
||||||
|
@owner = owner
|
||||||
|
super(default)
|
||||||
|
end
|
||||||
|
|
||||||
|
def filter(f)
|
||||||
|
Runlevels.from_hash(owner, self, f)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Check if all runlevels are enabled
|
||||||
|
#
|
||||||
|
# @return [boolean] true if all runlevels are enabled
|
||||||
|
def enabled?
|
||||||
|
values.all?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Check if all runlevels are disabled
|
||||||
|
#
|
||||||
|
# @return [boolean] true if all runlevels are disabled
|
||||||
|
def disabled?
|
||||||
|
!values.any?
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"#{owner} runlevels #{keys.join(', ')}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# We detect the init system for each operating system, based on the operating
|
# We detect the init system for each operating system, based on the operating
|
||||||
# system.
|
# system.
|
||||||
#
|
#
|
||||||
|
@ -29,6 +75,10 @@ class Service < Inspec.resource(1)
|
||||||
it { should be_enabled }
|
it { should be_enabled }
|
||||||
it { should be_running }
|
it { should be_running }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe service('service_name').runlevels(3, 5) do
|
||||||
|
it { should be_enabled }
|
||||||
|
end
|
||||||
"
|
"
|
||||||
|
|
||||||
attr_reader :service_ctl
|
attr_reader :service_ctl
|
||||||
|
@ -98,7 +148,7 @@ class Service < Inspec.resource(1)
|
||||||
@cache ||= @service_mgmt.info(@service_name)
|
@cache ||= @service_mgmt.info(@service_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
# verifies the service is enabled
|
# verifies if the service is enabled
|
||||||
def enabled?(_level = nil)
|
def enabled?(_level = nil)
|
||||||
return false if info.nil?
|
return false if info.nil?
|
||||||
info[:enabled]
|
info[:enabled]
|
||||||
|
@ -116,6 +166,12 @@ class Service < Inspec.resource(1)
|
||||||
info[:running]
|
info[:running]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# get all runlevels that are available and their configuration
|
||||||
|
def runlevels(*args)
|
||||||
|
return Runlevels.new(self) if info.nil? or info[:runlevels].nil?
|
||||||
|
Runlevels.from_hash(self, info[:runlevels], args)
|
||||||
|
end
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
"Service #{@service_name}"
|
"Service #{@service_name}"
|
||||||
end
|
end
|
||||||
|
@ -275,6 +331,8 @@ class Upstart < ServiceManager
|
||||||
end
|
end
|
||||||
|
|
||||||
class SysV < ServiceManager
|
class SysV < ServiceManager
|
||||||
|
RUNLEVELS = { 0=>false, 1=>false, 2=>false, 3=>false, 4=>false, 5=>false, 6=>false }.freeze
|
||||||
|
|
||||||
def initialize(service_name, service_ctl = nil)
|
def initialize(service_name, service_ctl = nil)
|
||||||
@service_ctl ||= 'service'
|
@service_ctl ||= 'service'
|
||||||
super
|
super
|
||||||
|
@ -296,10 +354,15 @@ class SysV < ServiceManager
|
||||||
# on rhel via: 'chkconfig --list', is not installed by default
|
# on rhel via: 'chkconfig --list', is not installed by default
|
||||||
# bash: for i in `find /etc/rc*.d -name S*`; do basename $i | sed -r 's/^S[0-9]+//'; done | sort | uniq
|
# bash: for i in `find /etc/rc*.d -name S*`; do basename $i | sed -r 's/^S[0-9]+//'; done | sort | uniq
|
||||||
enabled_services_cmd = inspec.command('find /etc/rc*.d -name S*')
|
enabled_services_cmd = inspec.command('find /etc/rc*.d -name S*')
|
||||||
enabled_services = enabled_services_cmd.stdout.split("\n").select { |line|
|
service_line = %r{rc(?<runlevel>[0-6])\.d/S[^/]*?#{Regexp.escape service_name}$}
|
||||||
/(^.*#{service_name}.*)/.match(line)
|
all_services = enabled_services_cmd.stdout.split("\n").map { |line|
|
||||||
}
|
service_line.match(line)
|
||||||
enabled = !enabled_services.empty?
|
}.compact
|
||||||
|
enabled = !all_services.empty?
|
||||||
|
|
||||||
|
# Determine a list of runlevels which this service is activated for
|
||||||
|
runlevels = RUNLEVELS.dup
|
||||||
|
all_services.each { |x| runlevels[x[:runlevel].to_i] = true }
|
||||||
|
|
||||||
# check if service is really running
|
# check if service is really running
|
||||||
# service throws an exit code if the service is not installed or
|
# service throws an exit code if the service is not installed or
|
||||||
|
@ -313,6 +376,7 @@ class SysV < ServiceManager
|
||||||
installed: true,
|
installed: true,
|
||||||
running: running,
|
running: running,
|
||||||
enabled: enabled,
|
enabled: enabled,
|
||||||
|
runlevels: runlevels,
|
||||||
type: 'sysv',
|
type: 'sysv',
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,6 +6,7 @@ require 'helper'
|
||||||
require 'inspec/resource'
|
require 'inspec/resource'
|
||||||
|
|
||||||
describe 'Inspec::Resources::Service' do
|
describe 'Inspec::Resources::Service' do
|
||||||
|
let(:runlevels) { {0=>false, 1=>false, 2=>true, 3=>true, 4=>true, 5=>true, 6=>false} }
|
||||||
|
|
||||||
# windows
|
# windows
|
||||||
it 'verify service parsing' do
|
it 'verify service parsing' do
|
||||||
|
@ -58,7 +59,7 @@ describe 'Inspec::Resources::Service' do
|
||||||
# centos 6 with sysv
|
# centos 6 with sysv
|
||||||
it 'verify centos 6 package parsing' do
|
it 'verify centos 6 package parsing' do
|
||||||
resource = MockLoader.new(:centos6).load_resource('service', 'sshd')
|
resource = MockLoader.new(:centos6).load_resource('service', 'sshd')
|
||||||
srv = { name: 'sshd', description: nil, installed: true, running: true, enabled: true, type: 'sysv' }
|
srv = { name: 'sshd', description: nil, installed: true, running: true, enabled: true, runlevels: runlevels, type: 'sysv' }
|
||||||
_(resource.info).must_equal srv
|
_(resource.info).must_equal srv
|
||||||
_(resource.installed?).must_equal true
|
_(resource.installed?).must_equal true
|
||||||
_(resource.enabled?).must_equal true
|
_(resource.enabled?).must_equal true
|
||||||
|
@ -67,7 +68,7 @@ describe 'Inspec::Resources::Service' do
|
||||||
|
|
||||||
it 'verify centos 6 package parsing with default sysv_service' do
|
it 'verify centos 6 package parsing with default sysv_service' do
|
||||||
resource = MockLoader.new(:centos6).load_resource('sysv_service', 'sshd')
|
resource = MockLoader.new(:centos6).load_resource('sysv_service', 'sshd')
|
||||||
srv = { name: 'sshd', description: nil, installed: true, running: true, enabled: true, type: 'sysv' }
|
srv = { name: 'sshd', description: nil, installed: true, running: true, enabled: true, runlevels: runlevels, type: 'sysv' }
|
||||||
_(resource.info).must_equal srv
|
_(resource.info).must_equal srv
|
||||||
_(resource.installed?).must_equal true
|
_(resource.installed?).must_equal true
|
||||||
_(resource.enabled?).must_equal true
|
_(resource.enabled?).must_equal true
|
||||||
|
@ -125,7 +126,7 @@ describe 'Inspec::Resources::Service' do
|
||||||
# debian 7 with systemv
|
# debian 7 with systemv
|
||||||
it 'verify debian 7 package parsing' do
|
it 'verify debian 7 package parsing' do
|
||||||
resource = MockLoader.new(:debian7).load_resource('service', 'sshd')
|
resource = MockLoader.new(:debian7).load_resource('service', 'sshd')
|
||||||
srv = { name: 'sshd', description: nil, installed: true, running: true, enabled: true, type: 'sysv' }
|
srv = { name: 'sshd', description: nil, installed: true, running: true, enabled: true, runlevels: runlevels, type: 'sysv' }
|
||||||
_(resource.info).must_equal srv
|
_(resource.info).must_equal srv
|
||||||
_(resource.installed?).must_equal true
|
_(resource.installed?).must_equal true
|
||||||
_(resource.enabled?).must_equal true
|
_(resource.enabled?).must_equal true
|
||||||
|
@ -173,7 +174,7 @@ describe 'Inspec::Resources::Service' do
|
||||||
# wrlinux
|
# wrlinux
|
||||||
it 'verify wrlinux package parsing' do
|
it 'verify wrlinux package parsing' do
|
||||||
resource = MockLoader.new(:wrlinux).load_resource('service', 'sshd')
|
resource = MockLoader.new(:wrlinux).load_resource('service', 'sshd')
|
||||||
srv = { name: 'sshd', description: nil, installed: true, running: true, enabled: true, type: 'sysv' }
|
srv = { name: 'sshd', description: nil, installed: true, running: true, enabled: true, runlevels: runlevels, type: 'sysv' }
|
||||||
_(resource.info).must_equal srv
|
_(resource.info).must_equal srv
|
||||||
_(resource.installed?).must_equal true
|
_(resource.installed?).must_equal true
|
||||||
_(resource.enabled?).must_equal true
|
_(resource.enabled?).must_equal true
|
||||||
|
@ -187,4 +188,45 @@ describe 'Inspec::Resources::Service' do
|
||||||
_(resource.installed?).must_equal false
|
_(resource.installed?).must_equal false
|
||||||
_(resource.info).must_equal nil
|
_(resource.info).must_equal nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# runlevel detection
|
||||||
|
describe 'runlevels on centos 6 (system V)' do
|
||||||
|
let(:service) { MockLoader.new(:centos6).load_resource('service', 'sshd') }
|
||||||
|
|
||||||
|
it 'grabs all runlevels' do
|
||||||
|
service.runlevels.keys.must_equal [0, 1, 2, 3, 4, 5, 6]
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'grabs runlevels via filter nil' do
|
||||||
|
service.runlevels(nil).keys.must_equal [0, 1, 2, 3, 4, 5, 6]
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'grabs runlevels by number' do
|
||||||
|
service.runlevels(3).keys.must_equal [3]
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'grabs runlevels by multiple numbers' do
|
||||||
|
service.runlevels(3, 4, 8).keys.must_equal [3, 4]
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'grabs runlevels via regex' do
|
||||||
|
service.runlevels(/[5-9]/).keys.must_equal [5, 6]
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'checks enabled true if all services are enabled' do
|
||||||
|
service.runlevels(2, 4).enabled?.must_equal true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'checks enabled false if some services are not enabled' do
|
||||||
|
service.runlevels(1, 4).enabled?.must_equal false
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'checks disabled true if all services are disabled' do
|
||||||
|
service.runlevels(0, 1).disabled?.must_equal true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'checks disabled false if some services are not disabled' do
|
||||||
|
service.runlevels(0, 4).enabled?.must_equal false
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue