summaryrefslogtreecommitdiffstats
path: root/lib/puppet/provider/package/rpm.rb
blob: 6d5adf2ef2ce996a1c4ede9db3971b670268eec5 (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
133
134
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

        return 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))

        return @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))
        return 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"
        if @property_hash[:ensure] and @property_hash[:ensure] != :absent
            flag = "-U"
        end

        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]}"
        return hash
    end
end