summaryrefslogtreecommitdiffstats
path: root/lib/puppet/provider/package/rpm.rb
blob: 72dc260a4e58b28a8f80cea717ec15e118a74e5a (plain)
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
require 'puppet/provider/package'
# RPM packaging.  Should work anywhere that has rpm installed.
Puppet::Type.type(:package).provide :rpm, :source => :rpm, :parent => Puppet::Provider::Package do
  desc "RPM packaging support; should work anywhere with a working `rpm`
    binary."

  has_feature :versionable

  # The query format by which we identify installed packages
  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('--version')
      rescue Puppet::ExecutionFailure
        false
      else
        true
      end
  end

  def self.instances
    packages = []

    # rpm < 4.1 don't support --nosignature
    output = rpm "--version"
    sig = "--nosignature"
    if output =~ /RPM version (([123].*)|(4\.0.*))/
      sig = ""
    end

    # list out all of the packages
    begin
      execpipe("#{command(:rpm)} -qa #{sig} --nodigest --qf '#{NEVRAFORMAT}\n'") { |process|
        # now turn each returned line into a package object
        process.each { |line|
          hash = nevra_to_hash(line)
          packages << new(hash)
        }
      }
    rescue Puppet::ExecutionFailure
      raise Puppet::Error, "Failed to list packages"
    end

    packages
  end

  # Find the fully versioned package name and the version alone. Returns
  # a hash with entries :instance => fully versioned package name, and
  # :ensure => version-release
  def query
    #NOTE: Prior to a fix for issue 1243, this method potentially returned a cached value
    #IF YOU CALL THIS METHOD, IT WILL CALL RPM
    #Use get(:property) to check if cached values are available
    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))

    @property_hash.dup
  end

  # Here we just retrieve the version from the file specified in the source.
  def latest
    unless source = @resource[:source]
      @resource.fail "RPMs must specify a package source"
    end

    cmd = [command(:rpm), "-q", "--qf", "#{NEVRAFORMAT}\n", "-p", "#{@resource[:source]}"]
    h = self.class.nevra_to_hash(execfail(cmd, Puppet::Error))
    h[:ensure]
  end

  def install
    source = nil
    unless source = @resource[:source]
      @resource.fail "RPMs must specify a package source"
    end
    # RPM gets pissy if you try to install an already
    # installed package
    if @resource.should(:ensure) == @property_hash[:ensure] or
      @resource.should(:ensure) == :latest && @property_hash[:ensure] == latest
      return
    end

    flag = "-i"
    flag = "-U" if @property_hash[:ensure] and @property_hash[:ensure] != :absent

    rpm flag, "--oldpackage", source
  end

  def uninstall
    query unless get(:arch)
    nvr = "#{get(:name)}-#{get(:version)}-#{get(:release)}"
    arch = ".#{get(:arch)}"
    # If they specified an arch in the manifest, erase that Otherwise,
    # erase the arch we got back from the query. If multiple arches are
    # installed and only the package name is specified (without the
    # arch), this will uninstall all of them on successive runs of the
    # client, one after the other
    if @resource[:name][-arch.size, arch.size] == arch
      nvr += arch
    else
      nvr += ".#{get(:arch)}"
    end
    rpm "-e", nvr
  end

  def update
    self.install
  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]}"
    hash
  end
end