inspec/lib/resources/package.rb

170 lines
4.1 KiB
Ruby
Raw Normal View History

2015-09-08 22:05:05 +00:00
# encoding: utf-8
2015-10-06 16:55:44 +00:00
# author: Christoph Hartmann
# author: Dominik Richter
2015-09-08 22:05:05 +00:00
# Resource to determine package information
#
# Usage:
# describe package('nginx') do
# it { should be_installed }
# end
2015-10-26 03:04:18 +00:00
class Package < Inspec.resource(1)
2015-09-08 22:05:05 +00:00
name 'package'
def initialize(package_name = nil)
@package_name = package_name
@name = @package_name
@cache = nil
# select package manager
@pkgman = nil
2015-10-26 03:04:18 +00:00
case inspec.os[:family]
2015-09-08 22:05:05 +00:00
when 'ubuntu', 'debian'
2015-10-26 03:04:18 +00:00
@pkgman = Deb.new(inspec)
when 'redhat', 'fedora', 'centos', 'opensuse'
2015-10-26 03:04:18 +00:00
@pkgman = Rpm.new(inspec)
2015-09-08 22:05:05 +00:00
when 'arch'
2015-10-26 03:04:18 +00:00
@pkgman = Pacman.new(inspec)
2015-09-08 22:05:05 +00:00
when 'darwin'
2015-10-26 03:04:18 +00:00
@pkgman = Brew.new(inspec)
2015-09-18 08:49:46 +00:00
when 'windows'
2015-10-26 03:04:18 +00:00
@pkgman = WindowsPkg.new(inspec)
2015-09-08 22:05:05 +00:00
else
return skip_resource 'The `package` resource is not supported on your OS yet.'
2015-09-08 22:05:05 +00:00
end
end
# returns true if the package is installed
2015-09-23 13:57:41 +00:00
def installed?(_provider = nil, _version = nil)
return false if info.nil?
info[:installed] == true
2015-09-08 22:05:05 +00:00
end
# returns the package description
def info
return @cache if !@cache.nil?
return nil if @pkgman.nil?
2015-09-08 22:05:05 +00:00
@pkgman.info(@package_name)
end
# return the package version
def version
info = @pkgman.info(@package_name)
return nil if info.nil?
info[:version]
end
def to_s
"System Package #{@package_name}"
2015-09-08 22:05:05 +00:00
end
end
class PkgManagement
2015-10-26 03:04:18 +00:00
attr_reader :inspec
def initialize(inspec)
@inspec = inspec
2015-09-08 22:05:05 +00:00
end
end
# Debian / Ubuntu
class Deb < PkgManagement
def info(package_name)
2015-10-26 03:04:18 +00:00
cmd = inspec.command("dpkg -s #{package_name}")
2015-09-08 22:05:05 +00:00
return nil if cmd.exit_status.to_i != 0
params = SimpleConfig.new(
cmd.stdout.chomp,
assignment_re: /^\s*([^:]*?)\s*:\s*(.*?)\s*$/,
multiple_values: false,
2015-09-08 22:05:05 +00:00
).params
{
name: params['Package'],
installed: true,
version: params['Version'],
type: 'deb',
2015-09-08 22:05:05 +00:00
}
end
end
# RHEL family
class Rpm < PkgManagement
def info(package_name)
2015-10-26 03:04:18 +00:00
cmd = inspec.command("rpm -qia #{package_name}")
# CentOS does not return an error code if the package is not installed,
# therefore we need to check for emptyness
return nil if cmd.exit_status.to_i != 0 || cmd.stdout.chomp.empty?
2015-09-08 22:05:05 +00:00
params = SimpleConfig.new(
cmd.stdout.chomp,
assignment_re: /^\s*([^:]*?)\s*:\s*(.*?)\s*$/,
multiple_values: false,
2015-09-08 22:05:05 +00:00
).params
{
name: params['Name'],
installed: true,
version: params['Version'],
type: 'rpm',
2015-09-08 22:05:05 +00:00
}
end
end
# MacOS / Darwin implementation
class Brew < PkgManagement
def info(package_name)
2015-10-26 03:04:18 +00:00
cmd = inspec.command("brew info --json=v1 #{package_name}")
2015-09-08 22:05:05 +00:00
return nil if cmd.exit_status.to_i != 0
# parse data
pkg = JSON.parse(cmd.stdout)[0]
{
name: "#{pkg.name}",
installed: true,
version: "#{pkg.installed.version}",
type: 'brew',
2015-09-08 22:05:05 +00:00
}
end
end
# Arch Linux
class Pacman < PkgManagement
def info(package_name)
2015-10-26 03:04:18 +00:00
cmd = inspec.command("pacman -Qi #{package_name}")
2015-09-08 22:05:05 +00:00
return nil if cmd.exit_status.to_i != 0
params = SimpleConfig.new(
cmd.stdout.chomp,
assignment_re: /^\s*([^:]*?)\s*:\s*(.*?)\s*$/,
multiple_values: false,
2015-09-08 22:05:05 +00:00
).params
{
name: params['Name'],
installed: true,
version: params['Version'],
type: 'pacman',
2015-09-08 22:05:05 +00:00
}
end
end
2015-09-18 08:49:46 +00:00
# Determines the installed packages on Windows
# Currently we use 'Get-WmiObject -Class Win32_Product' as a detection method
# TODO: evaluate if alternative methods as proposed by Microsoft are still valid:
# @see: http://blogs.technet.com/b/heyscriptingguy/archive/2013/11/15/use-powershell-to-find-installed-software.aspx
class WindowsPkg < PkgManagement
def info(package_name)
# Find the package
2015-10-26 03:04:18 +00:00
cmd = inspec.command("Get-WmiObject -Class Win32_Product | Where-Object {$_.Name -eq '#{package_name}'} | Select-Object -Property Name,Version,Vendor,PackageCode,Caption,Description | ConvertTo-Json")
2015-09-18 08:49:46 +00:00
begin
package = JSON.parse(cmd.stdout)
rescue JSON::ParserError => _e
return nil
end
{
name: package['Name'],
installed: true,
version: package['Version'],
type: 'windows',
}
end
end