diff options
author | David Lutterkort <dlutter@redhat.com> | 2007-10-02 15:18:03 -0700 |
---|---|---|
committer | David Lutterkort <dlutter@redhat.com> | 2007-10-02 15:24:08 -0700 |
commit | 8722e439b71de005a56820b3e3cf704e3a5b5c8c (patch) | |
tree | e218cef4e4648121c24d974abdf7dd606c9cf168 /lib/puppet/provider/package | |
parent | fa643e61c7451c2c46623d2c801a42c6c7640e1e (diff) | |
download | puppet-8722e439b71de005a56820b3e3cf704e3a5b5c8c.tar.gz puppet-8722e439b71de005a56820b3e3cf704e3a5b5c8c.tar.xz puppet-8722e439b71de005a56820b3e3cf704e3a5b5c8c.zip |
Use external helper script to talk to yum; should avoid any more trouble with "yum list". Fixes trac #836
Signed-off-by: David Lutterkort <dlutter@redhat.com>
Diffstat (limited to 'lib/puppet/provider/package')
-rwxr-xr-x | lib/puppet/provider/package/rpm.rb | 75 | ||||
-rwxr-xr-x | lib/puppet/provider/package/yum.rb | 58 | ||||
-rw-r--r-- | lib/puppet/provider/package/yumhelper.py | 37 |
3 files changed, 113 insertions, 57 deletions
diff --git a/lib/puppet/provider/package/rpm.rb b/lib/puppet/provider/package/rpm.rb index a31e4edf6..6e0ba5070 100755 --- a/lib/puppet/provider/package/rpm.rb +++ b/lib/puppet/provider/package/rpm.rb @@ -5,15 +5,14 @@ Puppet::Type.type(:package).provide :rpm, :source => :rpm, :parent => Puppet::Pr binary." # The query format by which we identify installed packages - NVRFORMAT = "%{NAME}-%{VERSION}-%{RELEASE}" - - VERSIONSTRING = "%{VERSION}-%{RELEASE}" + NEVRAFORMAT = "%{NAME} %|EPOCH?{%{EPOCH}}:{0}| %{VERSION} %{RELEASE} %{ARCH}" + NEVRA_FIELDS = [:name, :epoch, :version, :release, :arch] commands :rpm => "rpm" if command('rpm') confine :true => begin - rpm('-ql', 'rpm') + rpm('--version') rescue Puppet::ExecutionFailure false else @@ -26,23 +25,11 @@ Puppet::Type.type(:package).provide :rpm, :source => :rpm, :parent => Puppet::Pr # list out all of the packages begin - execpipe("#{command(:rpm)} -qa --nosignature --nodigest --qf '%{NAME} #{VERSIONSTRING}\n'") { |process| - # our regex for matching dpkg output - regex = %r{^(\S+)\s+(\S+)} - fields = [:name, :ensure] - + execpipe("#{command(:rpm)} -qa --nosignature --nodigest --qf '#{NEVRAFORMAT}\n'") { |process| # now turn each returned line into a package object process.each { |line| - if match = regex.match(line) - hash = {} - fields.zip(match.captures) { |field,value| - hash[field] = value - } - hash[:provider] = self.name - packages << new(hash) - else - raise "failed to match rpm line %s" % line - end + hash = nevra_to_hash(line) + packages << new(hash) } } rescue Puppet::ExecutionFailure @@ -56,30 +43,21 @@ Puppet::Type.type(:package).provide :rpm, :source => :rpm, :parent => Puppet::Pr # a hash with entries :instance => fully versioned package name, and # :ensure => version-release def query - cmd = ["-q", @resource[:name], "--nosignature", "--nodigest", "--qf", "#{NVRFORMAT} #{VERSIONSTRING}\n"] - - begin - output = rpm(*cmd) - rescue Puppet::ExecutionFailure - return nil + unless @property_hash[:epoch] + cmd = ["-q", @resource[:name], "--nosignature", "--nodigest", "--qf", "#{NEVRAFORMAT}\n"] + + begin + output = rpm(*cmd) + rescue Puppet::ExecutionFailure + return nil + end + + # FIXME: We could actually be getting back multiple packages + # for multilib + @property_hash.update(self.class.nevra_to_hash(output)) end - regex = %r{^(\S+)\s+(\S+)} - fields = [:instance, :ensure] - attrs = {} - if match = regex.match(output) - fields.zip(match.captures) { |field,value| - attrs[field] = value - } - else - raise Puppet::DevError, - "Failed to match rpm output '%s'" % - output - end - - @nvr = attrs[:instance] - - return attrs + return @property_hash.dup end # Here we just retrieve the version from the file specified in the source. @@ -88,9 +66,9 @@ Puppet::Type.type(:package).provide :rpm, :source => :rpm, :parent => Puppet::Pr @resource.fail "RPMs must specify a package source" end - cmd = [command(:rpm), "-q", "--qf", "#{VERSIONSTRING}", "-p", "#{@resource[:source]}"] - version = execfail(cmd, Puppet::Error) - return version + cmd = [command(:rpm), "-q", "--qf", "#{NEVRAFORMAT}\n", "-p", "#{@resource[:source]}"] + h = nevra_to_hash(execfail(cmd, Puppet::Error)) + return h[:ensure] end def install @@ -125,6 +103,15 @@ Puppet::Type.type(:package).provide :rpm, :source => :rpm, :parent => Puppet::Pr query unless @nvr @nvr end + + def self.nevra_to_hash(line) + line.chomp! + hash = {} + NEVRA_FIELDS.zip(line.split) { |f, v| hash[f] = v } + hash[:provider] = self.name + hash[:ensure] = "#{hash[:version]}-#{hash[:release]}" + return hash + end end # $Id$ diff --git a/lib/puppet/provider/package/yum.rb b/lib/puppet/provider/package/yum.rb index 13863ee55..a9427061c 100755 --- a/lib/puppet/provider/package/yum.rb +++ b/lib/puppet/provider/package/yum.rb @@ -3,11 +3,17 @@ Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do has_feature :versionable - commands :yum => "yum", :rpm => "rpm" + commands :yum => "yum", :rpm => "rpm", :python => "python" + + YUMHELPER = File::join(File::dirname(__FILE__), "yumhelper.py") + + class << self + attr_reader :updates + end if command('rpm') confine :true => begin - rpm('-ql', 'rpm') + rpm('--version') rescue Puppet::ExecutionFailure false else @@ -17,8 +23,26 @@ Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do defaultfor :operatingsystem => [:fedora, :centos, :redhat] - def install + def self.prefetch(packages) + @updates = {} + if Process.euid != 0 + raise Puppet::Error, "The yum provider can only be used as root" + end + super + python(YUMHELPER).each_line do |l| + l.chomp! + next if l.empty? + if l[0,4] == "_pkg" + hash = nevra_to_hash(l[5..-1]) + [hash[:name], "#{hash[:name]}.#{hash[:arch]}"].each do |n| + @updates[n] ||= [] + @updates[n] << hash + end + end + end + end + def install should = @resource.should(:ensure) self.debug "Ensuring => #{should}" wanted = @resource[:name] @@ -27,6 +51,7 @@ Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do case should when true, false, Symbol # pass + should = nil else # Add the package version wanted += "-%s" % should @@ -34,26 +59,33 @@ Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do output = yum "-d", "0", "-e", "0", "-y", :install, wanted - unless self.query - raise Puppet::Error.new( - "Could not find package %s" % self.name - ) + is = self.query + unless is + raise Puppet::Error, "Could not find package %s" % self.name + end + + # FIXME: Should we raise an exception even if should == :latest + # and yum updated us to a version other than @param_hash[:ensure] ? + if should && should != is[:ensure] + raise Puppet::Error, "Failed to update to version #{should}, got version #{is[:ensure]} instead" end end # What's the latest package version available? def latest - output = yum "-d", "0", "-e", "0", :list, :available, @resource[:name] - - if output =~ /^#{Regexp.escape(@resource[:name])}\S+\s+(\S+)\s/ - return $1 + upd = self.class.updates[@resource[:name]] + unless upd.nil? + # FIXME: there could be more than one update for a package + # because of multiarch + upd = upd[0] + return "#{upd[:version]}-#{upd[:release]}" else # Yum didn't find updates, pretend the current # version is the latest - unless properties[:ensure] != :absent + if properties[:ensure] == :absent raise Puppet::DevError, "Tried to get latest on a missing package" end - return @property_hash[:ensure] + return properties[:ensure] end end diff --git a/lib/puppet/provider/package/yumhelper.py b/lib/puppet/provider/package/yumhelper.py new file mode 100644 index 000000000..1142401b9 --- /dev/null +++ b/lib/puppet/provider/package/yumhelper.py @@ -0,0 +1,37 @@ +# Python helper script to query for the packages that have +# pending updates. Called by the yum package provider +# +# (C) 2007 Red Hat Inc. +# David Lutterkort <dlutter @redhat.com> + +import yum +import sys + +OVERRIDE_OPTS = { + 'debuglevel': 0, + 'errorlevel': 0, + 'logfile': '/dev/null' +} + +def pkg_lists(): + my = yum.YumBase() + my.doConfigSetup() + + for k in OVERRIDE_OPTS.keys(): + if hasattr(my.conf, k): + setattr(my.conf, k, OVERRIDE_OPTS[k]) + else: + my.conf.setConfigOption(k, OVERRIDE_OPTS[k]) + + my.doTsSetup() + my.doRpmDBSetup() + return my.doPackageLists('updates') + +try: + ypl = pkg_lists() +except IOError, e: + print "_err IOError %d %s" % (e.errno, e) + sys.exit(1) + +for pkg in ypl.updates: + print "_pkg %s %s %s %s %s" % (pkg.name, pkg.epoch, pkg.version, pkg.release, pkg.arch) |