1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
|
# frozen_string_literal: true
# Packaging using Peter Bonivart's pkgutil program.
Puppet::Type.type(:package).provide :pkgutil, :parent => :sun, :source => :sun do
desc "Package management using Peter Bonivart's ``pkgutil`` command on Solaris."
pkgutil_bin = "pkgutil"
if FileTest.executable?("/opt/csw/bin/pkgutil")
pkgutil_bin = "/opt/csw/bin/pkgutil"
end
confine 'os.family' => :solaris
has_command(:pkguti, pkgutil_bin) do
environment :HOME => ENV.fetch('HOME', nil)
end
def self.healthcheck
unless Puppet::FileSystem.exist?("/var/opt/csw/pkgutil/admin")
Puppet.notice _("It is highly recommended you create '/var/opt/csw/pkgutil/admin'.")
Puppet.notice _("See /var/opt/csw/pkgutil")
end
correct_wgetopts = false
["/opt/csw/etc/pkgutil.conf", "/etc/opt/csw/pkgutil.conf"].each do |confpath|
File.open(confpath) do |conf|
conf.each_line { |line| correct_wgetopts = true if line =~ /^\s*wgetopts\s*=.*(-nv|-q|--no-verbose|--quiet)/ }
end
end
unless correct_wgetopts
Puppet.notice _("It is highly recommended that you set 'wgetopts=-nv' in your pkgutil.conf.")
end
end
def self.instances(hash = {})
healthcheck
# Use the available pkg list (-a) to work out aliases
aliases = {}
availlist.each do |pkg|
aliases[pkg[:name]] = pkg[:alias]
end
# The -c pkglist lists installed packages
pkginsts = []
output = pkguti(["-c"])
parse_pkglist(output).each do |pkg|
pkg.delete(:avail)
pkginsts << new(pkg)
# Create a second instance with the alias if it's different
pkgalias = aliases[pkg[:name]]
next unless pkgalias and pkg[:name] != pkgalias
apkg = pkg.dup
apkg[:name] = pkgalias
pkginsts << new(apkg)
end
pkginsts
end
# Turns a pkgutil -a listing into hashes with the common alias, full
# package name and available version
def self.availlist
output = pkguti ["-a"]
output.split("\n").filter_map do |line|
next if line =~ /^common\s+package/ # header of package list
next if noise?(line)
if line =~ /\s*(\S+)\s+(\S+)\s+(.*)/
{ :alias => Regexp.last_match(1), :name => Regexp.last_match(2), :avail => Regexp.last_match(3) }
else
Puppet.warning _("Cannot match %{line}") % { line: line }
end
end
end
# Turn our pkgutil -c listing into a hash for a single package.
def pkgsingle(resource)
# The --single option speeds up the execution, because it queries
# the package management system for one package only.
command = ["-c", "--single", resource[:name]]
self.class.parse_pkglist(run_pkgutil(resource, command), { :justme => resource[:name] })
end
# Turn our pkgutil -c listing into a bunch of hashes.
def self.parse_pkglist(output, hash = {})
output = output.split("\n")
if output[-1] == "Not in catalog"
Puppet.warning _("Package not in pkgutil catalog: %{package}") % { package: hash[:justme] }
return nil
end
list = output.filter_map do |line|
next if line =~ /installed\s+catalog/ # header of package list
next if noise?(line)
pkgsplit(line)
end
if hash[:justme]
# Single queries may have been for an alias so return the name requested
if list.any?
list[-1][:name] = hash[:justme]
list[-1]
end
else
list.reject! { |h| h[:ensure] == :absent }
list
end
end
# Identify common types of pkgutil noise as it downloads catalogs etc
def self.noise?(line)
return true if line =~ /^#/
return true if line =~ /^Checking integrity / # use_gpg
return true if line =~ /^gpg: / # gpg verification
return true if line =~ /^=+> / # catalog fetch
return true if line =~ /\d+:\d+:\d+ URL:/ # wget without -q
false
end
# Split the different lines into hashes.
def self.pkgsplit(line)
if line =~ /\s*(\S+)\s+(\S+)\s+(.*)/
hash = {}
hash[:name] = Regexp.last_match(1)
hash[:ensure] = if Regexp.last_match(2) == "notinst"
:absent
else
Regexp.last_match(2)
end
hash[:avail] = Regexp.last_match(3)
if hash[:avail] =~ /^SAME\s*$/
hash[:avail] = hash[:ensure]
end
# Use the name method, so it works with subclasses.
hash[:provider] = name
hash
else
Puppet.warning _("Cannot match %{line}") % { line: line }
nil
end
end
def run_pkgutil(resource, *args)
# Allow source to be one or more URLs pointing to a repository that all
# get passed to pkgutil via one or more -t options
if resource[:source]
sources = [resource[:source]].flatten
pkguti(*[sources.map { |src| ["-t", src] }, *args].flatten)
else
pkguti(*args.flatten)
end
end
def install
run_pkgutil @resource, "-y", "-i", @resource[:name]
end
# Retrieve the version from the current package file.
def latest
hash = pkgsingle(@resource)
hash[:avail] if hash
end
def query
hash = pkgsingle(@resource)
hash || { :ensure => :absent }
end
def update
run_pkgutil @resource, "-y", "-u", @resource[:name]
end
def uninstall
run_pkgutil @resource, "-y", "-r", @resource[:name]
end
end
|