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
|
require_relative '../../../puppet/provider/package'
require_relative '../../../puppet/util/package'
Puppet::Type.type(:package).provide :aix, :parent => Puppet::Provider::Package do
desc "Installation from an AIX software directory, using the AIX `installp`
command. The `source` parameter is required for this provider, and should
be set to the absolute path (on the puppet agent machine) of a directory
containing one or more BFF package files.
The `installp` command will generate a table of contents file (named `.toc`)
in this directory, and the `name` parameter (or resource title) that you
specify for your `package` resource must match a package name that exists
in the `.toc` file.
Note that package downgrades are *not* supported; if your resource specifies
a specific version number and there is already a newer version of the package
installed on the machine, the resource will fail with an error message."
# The commands we are using on an AIX box are installed standard
# (except nimclient) nimclient needs the bos.sysmgt.nim.client fileset.
commands :lslpp => "/usr/bin/lslpp",
:installp => "/usr/sbin/installp"
# AIX supports versionable packages with and without a NIM server
has_feature :versionable
confine :operatingsystem => [ :aix ]
defaultfor :operatingsystem => :aix
attr_accessor :latest_info
STATE_CODE = {
'A' => :applied,
'B' => :broken,
'C' => :committed,
'E' => :efix_locked,
'O' => :obsolete,
'?' => :inconsistent,
}.freeze
def self.srclistcmd(source)
[ command(:installp), "-L", "-d", source ]
end
def self.prefetch(packages)
raise Puppet::Error, _("The aix provider can only be used by root") if Process.euid != 0
return unless packages.detect { |name, package| package.should(:ensure) == :latest }
sources = packages.collect { |name, package| package[:source] }.uniq.compact
updates = {}
sources.each do |source|
execute(self.srclistcmd(source)).each_line do |line|
if line =~ /^[^#][^:]*:([^:]*):([^:]*)/
current = {}
current[:name] = $1
current[:version] = $2
current[:source] = source
if updates.key?(current[:name])
previous = updates[current[:name]]
updates[current[:name]] = current unless Puppet::Util::Package.versioncmp(previous[:version], current[:version]) == 1
else
updates[current[:name]] = current
end
end
end
end
packages.each do |name, package|
if updates.key?(name)
package.provider.latest_info = updates[name]
end
end
end
def uninstall
# Automatically process dependencies when installing/uninstalling
# with the -g option to installp.
installp "-gu", @resource[:name]
# installp will return an exit code of zero even if it didn't uninstall
# anything... so let's make sure it worked.
unless query().nil?
self.fail _("Failed to uninstall package '%{name}'") % { name: @resource[:name] }
end
end
def install(useversion = true)
source = @resource[:source]
unless source
self.fail _("A directory is required which will be used to find packages")
end
pkg = @resource[:name]
pkg += " #{@resource.should(:ensure)}" if (! @resource.should(:ensure).is_a? Symbol) and useversion
output = installp "-acgwXY", "-d", source, pkg
# If the package is superseded, it means we're trying to downgrade and we
# can't do that.
if output =~ /^#{Regexp.escape(@resource[:name])}\s+.*\s+Already superseded by.*$/
self.fail _("aix package provider is unable to downgrade packages")
end
pkg_info = query
if pkg_info && [:broken, :inconsistent].include?(pkg_info[:status])
self.fail _("Package '%{name}' is in a %{status} state and requires manual intervention") % { name: @resource[:name], status: pkg_info[:status] }
end
end
def self.pkglist(hash = {})
cmd = [command(:lslpp), "-qLc"]
name = hash[:pkgname]
if name
cmd << name
end
begin
list = execute(cmd).scan(/^[^#][^:]*:([^:]*):([^:]*):[^:]*:[^:]*:([^:])/).collect { |n,e,s|
e = :absent if [:broken, :inconsistent].include?(STATE_CODE[s])
{ :name => n, :ensure => e, :status => STATE_CODE[s], :provider => self.name }
}
rescue Puppet::ExecutionFailure => detail
if hash[:pkgname]
return nil
else
raise Puppet::Error, _("Could not list installed Packages: %{detail}") % { detail: detail }, detail.backtrace
end
end
if hash[:pkgname]
return list.shift
else
return list
end
end
def self.instances
pkglist.collect do |hash|
new(hash)
end
end
def latest
upd = latest_info
unless upd.nil?
return "#{upd[:version]}"
else
raise Puppet::DevError, _("Tried to get latest on a missing package") if properties[:ensure] == :absent
return properties[:ensure]
end
end
def query
self.class.pkglist(:pkgname => @resource[:name])
end
def update
self.install(false)
end
end
|