diff options
author | Rick Bradley <rick@rickbradley.com> | 2007-10-03 16:42:28 -0500 |
---|---|---|
committer | Rick Bradley <rick@rickbradley.com> | 2007-10-03 16:42:28 -0500 |
commit | 1334b786ac622a6094ba68b3e66fce3f5841deed (patch) | |
tree | 70692f08d0dcbb327bfdd899b019f559780c135a | |
parent | 3f90ddbfc7d20b631ca17f72e2d72d5e7ca00629 (diff) | |
parent | b727a95aa4b72ce057653101cf1f50fa49c4b0a8 (diff) | |
download | puppet-1334b786ac622a6094ba68b3e66fce3f5841deed.tar.gz puppet-1334b786ac622a6094ba68b3e66fce3f5841deed.tar.xz puppet-1334b786ac622a6094ba68b3e66fce3f5841deed.zip |
Merge branch 'master' of git://reductivelabs.com/puppet into routing
-rw-r--r-- | lib/puppet/module.rb | 13 | ||||
-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 | ||||
-rwxr-xr-x | spec/unit/other/modules.rb | 51 | ||||
-rwxr-xr-x | test/ral/types/package.rb | 3 |
6 files changed, 165 insertions, 72 deletions
diff --git a/lib/puppet/module.rb b/lib/puppet/module.rb index dc30d8167..45860c74d 100644 --- a/lib/puppet/module.rb +++ b/lib/puppet/module.rb @@ -27,8 +27,8 @@ class Puppet::Module return nil end - modpath = modulepath(environment).collect { |p| - File::join(p, modname) + modpath = modulepath(environment).collect { |path| + File::join(path, modname) }.find { |f| File::directory?(f) } return nil unless modpath @@ -72,10 +72,9 @@ class Puppet::Module # Otherwise, try to find manifests matching +pat+ relative to +cwd+ def self.find_manifests(start, options = {}) cwd = options[:cwd] || Dir.getwd - path, pat = split_path(start) - mod = find(path, options[:environment]) - if mod - return mod.manifests(pat) + module_name, pattern = split_path(start) + if module_name and mod = find(module_name, options[:environment]) + return mod.manifests(pattern) else abspat = File::expand_path(start, cwd) files = Dir.glob(abspat).reject { |f| FileTest.directory?(f) } @@ -87,6 +86,8 @@ class Puppet::Module end # Split the path into the module and the rest of the path. + # This method can and often does return nil, so anyone calling + # it needs to handle that. def self.split_path(path) if path =~ %r/^#{File::SEPARATOR}/ return nil 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) diff --git a/spec/unit/other/modules.rb b/spec/unit/other/modules.rb index f53c43e89..26ca3907d 100755 --- a/spec/unit/other/modules.rb +++ b/spec/unit/other/modules.rb @@ -108,22 +108,55 @@ describe Puppet::Module, " when searching for templates" do after { Puppet.settings.clear } end -describe Puppet::Module, " when searching for manifests" do - it "should return the manifests from the first found module" do - Puppet[:modulepath] = "/one:/two" - File.stubs(:directory?).returns(true) - Dir.expects(:glob).with("/one/mymod/manifests/init.pp").returns(%w{/one/mymod/manifests/init.pp}) - Puppet::Module.find_manifests("mymod/init.pp").should == ["/one/mymod/manifests/init.pp"] +describe Puppet::Module, " when searching for manifests when no module is found" do + before do + File.stubs(:find).returns(nil) end - it "should search the cwd if no module is found" do - Puppet[:modulepath] = "/one:/two" - File.stubs(:find).returns(nil) + it "should not look for modules when paths are fully qualified" do + Puppet.expects(:value).with(:modulepath).never + file = "/fully/qualified/file.pp" + Dir.stubs(:glob).with(file).returns([file]) + Puppet::Module.find_manifests(file) + end + + it "should directly return fully qualified files" do + file = "/fully/qualified/file.pp" + Dir.stubs(:glob).with(file).returns([file]) + Puppet::Module.find_manifests(file).should == [file] + end + + it "should match against provided fully qualified patterns" do + pattern = "/fully/qualified/pattern/*" + Dir.expects(:glob).with(pattern).returns(%w{my file list}) + Puppet::Module.find_manifests(pattern).should == %w{my file list} + end + + it "should look for files relative to the current directory" do cwd = Dir.getwd Dir.expects(:glob).with("#{cwd}/mymod/init.pp").returns(["#{cwd}/mymod/init.pp"]) Puppet::Module.find_manifests("mymod/init.pp").should == ["#{cwd}/mymod/init.pp"] end + it "should only return files, not directories" do + pattern = "/fully/qualified/pattern/*" + file = "/my/file" + dir = "/my/directory" + Dir.expects(:glob).with(pattern).returns([file, dir]) + FileTest.expects(:directory?).with(file).returns(false) + FileTest.expects(:directory?).with(dir).returns(true) + Puppet::Module.find_manifests(pattern).should == [file] + end +end + +describe Puppet::Module, " when searching for manifests in a found module" do + it "should return the manifests from the first found module" do + Puppet[:modulepath] = "/one:/two" + File.stubs(:directory?).returns(true) + Dir.expects(:glob).with("/one/mymod/manifests/init.pp").returns(%w{/one/mymod/manifests/init.pp}) + Puppet::Module.find_manifests("mymod/init.pp").should == ["/one/mymod/manifests/init.pp"] + end + it "should use the node environment if specified" do Puppet.settings.expects(:value).with(:modulepath, "myenv").returns("/env/modules") File.stubs(:directory?).returns(true) diff --git a/test/ral/types/package.rb b/test/ral/types/package.rb index 79b769c26..e97c6bd3c 100755 --- a/test/ral/types/package.rb +++ b/test/ral/types/package.rb @@ -120,6 +120,9 @@ class TestPackages < Test::Unit::TestCase # Make sure we can prefetch package information, rather than getting it one package at a time. def test_prefetch @type.providers_by_source.each do |provider| + # The yum provider can't be used if you're not root + next if provider.name == :yum && Process.euid != 0 + # First get a list of packages list = provider.instances |