require 'puppet/provider/package'
require '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
Copyright 2K16 - 2K18 Indonesian Hacker Rulez