# class Chef::Provider::Package::Yum

### Public Class Methods

new(new_resource, run_context) click to toggle source
Calls superclass method Chef::Mixin::GetSourceFromPackage.new

    # File lib/chef/provider/package/yum.rb, line 952
    def initialize(new_resource, run_context)
      super

      @yum = YumCache.instance
    end

### Public Instance Methods

action_upgrade() click to toggle source

Keep upgrades from trying to install an older candidate version. Can happen when a new version is installed then removed from a repository, now the older available version shows up as a viable install candidate.

Can be done in #upgrade_package but an upgraded from->to log message slips out

Hacky - better overall solution? Custom compare in Package provider?

Calls superclass method Chef::Provider::Package#action_upgrade

    # File lib/chef/provider/package/yum.rb, line 1155
    def action_upgrade
      # Could be uninstalled or have no candidate
      if @current_resource.version.nil? || candidate_version.nil?
        super
      # Ensure the candidate is newer
      elsif RPMVersion.parse(candidate_version) > RPMVersion.parse(@current_resource.version)
        super
      else
        Chef::Log.debug("#{@new_resource} is at the latest version - nothing to do")
      end
    end

allow_downgrade() click to toggle source

    # File lib/chef/provider/package/yum.rb, line 977
    def allow_downgrade
      if @new_resource.respond_to?("allow_downgrade")
        @new_resource.allow_downgrade
      else
        false
      end
    end

arch() click to toggle source

Extra attributes

    # File lib/chef/provider/package/yum.rb, line 961
    def arch
      if @new_resource.respond_to?("arch")
        @new_resource.arch
      else
        nil
      end
    end

flush_cache() click to toggle source

    # File lib/chef/provider/package/yum.rb, line 969
    def flush_cache
      if @new_resource.respond_to?("flush_cache")
        @new_resource.flush_cache
      else
        { :before => false, :after => false }
      end
    end

install_package(name, version) click to toggle source

    # File lib/chef/provider/package/yum.rb, line 1102
    def install_package(name, version)
      if @new_resource.source
        yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} localinstall #{@new_resource.source}")
      else
        # Work around yum not exiting with an error if a package doesn't exist for CHEF-2062
        if @yum.version_available?(name, version, arch)
          method = "install"
          log_method = "installing"

          # More Yum fun:
          #
          # yum install of an old name+version will exit(1)
          # yum install of an old name+version+arch will exit(0) for some reason
          #
          # Some packages can be installed multiple times like the kernel
          unless @yum.allow_multi_install.include?(name)
            if RPMVersion.parse(@current_resource.version) > RPMVersion.parse(version)
              # Unless they want this...
              if allow_downgrade
                method = "downgrade"
                log_method = "downgrading"
              else
                # we bail like yum when the package is older
                raise Chef::Exceptions::Package, "Installed package #{name}-#{@current_resource.version} is newer " +
                                                 "than candidate package #{name}-#{version}"
              end
            end
          end

          repo = @yum.package_repository(name, version, arch)
          Chef::Log.info("#{@new_resource} #{log_method} #{name}-#{version}#{yum_arch} from #{repo} repository")

          yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} #{method} #{name}-#{version}#{yum_arch}")
        else
          raise Chef::Exceptions::Package, "Version #{version} of #{name} not found. Did you specify both version " +
                                           "and release? (version-release, e.g. 1.84-10.fc6)"
        end
      end

      if flush_cache[:after]
        @yum.reload
      else
        @yum.reload_installed
      end
    end

load_current_resource() click to toggle source

Standard Provider methods for Parent

    # File lib/chef/provider/package/yum.rb, line 1026
    def load_current_resource
      if flush_cache[:before]
        @yum.reload
      end

      if @new_resource.options
        repo_control = []
        @new_resource.options.split.each do |opt|
          if opt =~ %r{--(enable|disable)repo=.+}
            repo_control << opt
          end
        end

        if repo_control.size > 0
          @yum.enable_extra_repo_control(repo_control.join(" "))
        else
          @yum.disable_extra_repo_control
        end
      else
        @yum.disable_extra_repo_control
      end

      # At this point package_name could be:
      #
      # 1) a package name, eg: "foo"
      # 2) a package name.arch, eg: "foo.i386"
      # 3) or a dependency, eg: "foo >= 1.1"

      # Check if we have name or name+arch which has a priority over a dependency
      unless @yum.package_available?(@new_resource.package_name)
        # If they aren't in the installed packages they could be a dependency
        parse_dependency
      end

      # Don't overwrite an existing arch
      unless arch
        parse_arch
      end

      @current_resource = Chef::Resource::Package.new(@new_resource.name)
      @current_resource.package_name(@new_resource.package_name)

      if @new_resource.source
        unless ::File.exists?(@new_resource.source)
          raise Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}"
        end

        Chef::Log.debug("#{@new_resource} checking rpm status")
        shell_out!("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@new_resource.source}", :timeout => Chef::Config[:yum_timeout]).stdout.each_line do |line|
          case line
          when /([\w\d_.-]+)\s([\w\d_.-]+)/
            @current_resource.package_name($1)
            @new_resource.version($2)
          end
        end
      end

      if @new_resource.version
        new_resource = "#{@new_resource.package_name}-#{@new_resource.version}#{yum_arch}"
      else
        new_resource = "#{@new_resource.package_name}#{yum_arch}"
      end

      Chef::Log.debug("#{@new_resource} checking yum info for #{new_resource}")

      installed_version = @yum.installed_version(@new_resource.package_name, arch)
      @current_resource.version(installed_version)

      @candidate_version = @yum.candidate_version(@new_resource.package_name, arch)

      Chef::Log.debug("#{@new_resource} installed version: #{installed_version || "(none)"} candidate version: " +
                      "#{@candidate_version || "(none)"}")

      @current_resource
    end

purge_package(name, version) click to toggle source

    # File lib/chef/provider/package/yum.rb, line 1185
    def purge_package(name, version)
      remove_package(name, version)
    end

remove_package(name, version) click to toggle source

    # File lib/chef/provider/package/yum.rb, line 1171
    def remove_package(name, version)
      if version
        yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} remove #{name}-#{version}#{yum_arch}")
      else
        yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} remove #{name}#{yum_arch}")
      end

      if flush_cache[:after]
        @yum.reload
      else
        @yum.reload_installed
      end
    end

upgrade_package(name, version) click to toggle source

    # File lib/chef/provider/package/yum.rb, line 1167
    def upgrade_package(name, version)
      install_package(name, version)
    end

yum_arch() click to toggle source

Helpers

    # File lib/chef/provider/package/yum.rb, line 988
    def yum_arch
      arch ? ".#{arch}" : nil
    end

yum_command(command) click to toggle source

    # File lib/chef/provider/package/yum.rb, line 992
    def yum_command(command)
      status, stdout, stderr = output_of_command(command, {:timeout => Chef::Config[:yum_timeout]})

      # This is fun: rpm can encounter errors in the %post/%postun scripts which aren't
      # considered fatal - meaning the rpm is still successfully installed. These issue
      # cause yum to emit a non fatal warning but still exit(1). As there's currently no
      # way to suppress this behavior and an exit(1) will break a Chef run we make an
      # effort to trap these and re-run the same install command - it will either fail a
      # second time or succeed.
      #
      # A cleaner solution would have to be done in python and better hook into
      # yum/rpm to handle exceptions as we see fit.
      if status.exitstatus == 1
        stdout.each_line do |l|
          # rpm-4.4.2.3 lib/psm.c line 2182
          if l =~ %r{^error: %(post|postun)\(.*\) scriptlet failed, exit status \d+$}
            Chef::Log.warn("#{@new_resource} caught non-fatal scriptlet issue: \"#{l}\". Can't trust yum exit status " +
                           "so running install again to verify.")
            status, stdout, stderr = output_of_command(command, {:timeout => Chef::Config[:yum_timeout]})
            break
          end
        end
      end

      if status.exitstatus > 0
        command_output = "STDOUT: #{stdout}"
        command_output << "STDERR: #{stderr}"
        handle_command_failures(status, command_output, {})
      end
    end