2017-02-03 20:42:55 +00:00
|
|
|
# encoding: utf-8
|
|
|
|
# copyright: 2017, Chef Software, Inc. <legal@chef.io>
|
|
|
|
# author: Joshua Timberman
|
|
|
|
# author: Alex Pop
|
|
|
|
|
|
|
|
require 'utils/filter'
|
|
|
|
|
|
|
|
module Inspec::Resources
|
|
|
|
class Packages < Inspec.resource(1)
|
|
|
|
name 'packages'
|
|
|
|
desc 'Use the packages InSpec audit resource to test properties for multiple packages installed on the system'
|
|
|
|
example "
|
|
|
|
describe packages(/xserver-xorg.*/) do
|
|
|
|
its('entries') { should be_empty }
|
|
|
|
end
|
|
|
|
describe packages('vim').entries.length do
|
|
|
|
it { should be > 1 }
|
|
|
|
end
|
|
|
|
describe packages(/vi.+/).where { status != 'installed' } do
|
|
|
|
its('statuses') { should be_empty }
|
|
|
|
end
|
|
|
|
"
|
|
|
|
|
|
|
|
def initialize(pattern)
|
2017-02-13 13:13:22 +00:00
|
|
|
os = inspec.os
|
|
|
|
if os.debian?
|
|
|
|
@pkgs = Debs.new(inspec)
|
2017-02-14 13:24:48 +00:00
|
|
|
elsif os.redhat? || %w{suse amazon fedora}.include?(os[:family])
|
2017-02-13 13:13:22 +00:00
|
|
|
@pkgs = Rpms.new(inspec)
|
|
|
|
else
|
|
|
|
return skip_resource "The packages resource is not yet supported on OS #{inspec.os.name}"
|
|
|
|
end
|
2017-02-10 10:33:21 +00:00
|
|
|
|
2017-02-03 20:42:55 +00:00
|
|
|
@pattern = pattern_regexp(pattern)
|
2017-02-13 13:13:22 +00:00
|
|
|
all_pkgs = @pkgs.build_package_list
|
2017-02-03 20:42:55 +00:00
|
|
|
@list = all_pkgs.find_all do |hm|
|
2017-02-10 10:33:21 +00:00
|
|
|
hm[:name] =~ @pattern
|
2017-02-03 20:42:55 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def to_s
|
|
|
|
"Packages #{@pattern.class == String ? @pattern : @pattern.inspect}"
|
|
|
|
end
|
|
|
|
|
|
|
|
filter = FilterTable.create
|
|
|
|
filter.add_accessor(:where)
|
|
|
|
.add_accessor(:entries)
|
|
|
|
.add(:statuses, field: 'status', style: :simple)
|
|
|
|
.add(:names, field: 'name')
|
|
|
|
.add(:versions, field: 'version')
|
|
|
|
.connect(self, :filtered_packages)
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def pattern_regexp(p)
|
|
|
|
if p.class == String
|
|
|
|
Regexp.new(Regexp.escape(p))
|
|
|
|
elsif p.class == Regexp
|
|
|
|
p
|
|
|
|
else
|
2017-02-10 10:33:21 +00:00
|
|
|
raise 'Invalid name argument to packages resource, please use a "string" or /regexp/'
|
2017-02-03 20:42:55 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def filtered_packages
|
2017-02-13 13:13:22 +00:00
|
|
|
warn "The packages resource is not yet supported on OS #{inspec.os.name}" if resource_skipped
|
2017-02-03 20:42:55 +00:00
|
|
|
@list
|
|
|
|
end
|
2017-02-13 13:13:22 +00:00
|
|
|
end
|
2017-02-03 20:42:55 +00:00
|
|
|
|
2017-02-13 13:13:22 +00:00
|
|
|
class PkgsManagement
|
|
|
|
PackageStruct = Struct.new(:status, :name, :version)
|
|
|
|
attr_reader :inspec
|
|
|
|
def initialize(inspec)
|
|
|
|
@inspec = inspec
|
|
|
|
end
|
|
|
|
end
|
2017-02-03 20:42:55 +00:00
|
|
|
|
2017-02-13 13:13:22 +00:00
|
|
|
# Debian / Ubuntu
|
|
|
|
class Debs < PkgsManagement
|
|
|
|
def build_package_list
|
2017-02-14 13:24:48 +00:00
|
|
|
# use two spaces as delimiter in case any of the fields has a space in it
|
|
|
|
command = "dpkg-query -W -f='${db:Status-Abbrev} ${Package} ${Version}\\n'"
|
2017-02-03 20:42:55 +00:00
|
|
|
cmd = inspec.command(command)
|
2017-02-13 13:13:22 +00:00
|
|
|
all = cmd.stdout.split("\n")
|
2017-02-03 20:42:55 +00:00
|
|
|
return [] if all.nil?
|
|
|
|
all.map do |m|
|
2017-02-14 13:24:48 +00:00
|
|
|
a = m.split(/ {2,}/)
|
2017-02-03 20:42:55 +00:00
|
|
|
a[0] = 'installed' if a[0] =~ /^.i/
|
|
|
|
a[2] = a[2].split(':').last
|
2017-02-13 13:13:22 +00:00
|
|
|
PackageStruct.new(*a)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# RedHat family
|
|
|
|
class Rpms < PkgsManagement
|
|
|
|
def build_package_list
|
2017-02-14 13:24:48 +00:00
|
|
|
# use two spaces as delimiter in case any of the fields has a space in it
|
|
|
|
command = "rpm -qa --queryformat '%{NAME} %{VERSION}-%{RELEASE}\\n'"
|
2017-02-13 13:13:22 +00:00
|
|
|
cmd = inspec.command(command)
|
|
|
|
all = cmd.stdout.split("\n")
|
|
|
|
return [] if all.nil?
|
|
|
|
all.map do |m|
|
2017-02-14 13:24:48 +00:00
|
|
|
a = m.split(' ')
|
2017-02-13 13:13:22 +00:00
|
|
|
a.unshift('installed')
|
|
|
|
PackageStruct.new(*a)
|
2017-02-03 20:42:55 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|