summaryrefslogtreecommitdiff
path: root/chef/lib/chef/provider/package/yum.rb
blob: efd6fee0ad8f1d7f2efe374f9af64e80b3892aa9 (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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#
# Author:: Adam Jacob (<adam@opscode.com>)
# Copyright:: Copyright (c) 2008 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
#     http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

require 'chef/provider/package'
require 'chef/mixin/command'
require 'chef/resource/package'
require 'singleton'

class Chef
  class Provider
    class Package
      class Yum < Chef::Provider::Package  
      
        class YumCache
          include Chef::Mixin::Command
          include Singleton

          def initialize
            load_data
          end

          def stale?
            interval = Chef::Config[:interval].to_f

            # run once mode
            if interval == 0
              return false
            elsif (Time.now - @updated_at) > interval
              return true
            end

            false
          end
            
          def refresh
            if @data.empty?
              reload
            elsif stale?
               reload
            end
          end

          def load_data
            @data = Hash.new
            error = String.new

            helper = ::File.join(::File.dirname(__FILE__), 'yum-dump.py')
            status = popen4("python #{helper}", :waitlast => true) do |pid, stdin, stdout, stderr|
              stdout.each do |line|
                line.chomp!
                name, type, epoch, version, release, arch = line.split(',')
                type_sym = type.to_sym
                if !@data.has_key?(name)
                  @data[name] = Hash.new
                end
                @data[name][type_sym] = { :epoch => epoch, :version => version,
                                          :release => release, :arch => arch }
              end
              
              error = stderr.readlines
            end

            unless status.exitstatus == 0
              raise Chef::Exceptions::Package, "yum failed - #{status.inspect} - returns: #{error}"
            end

            @updated_at = Time.now
          end
          alias :reload :load_data

          def version(package_name, type)
            if (x = @data[package_name])
              if (y = x[type])
                return "#{y[:version]}-#{y[:release]}"
              end
            end

            nil
          end

          def installed_version(package_name)
            version(package_name, :installed)
          end

          def candidate_version(package_name)
            version(package_name, :available)
          end
         
          def flush
            @data.clear
          end
        end

        def initialize(node, new_resource)
          @yum = YumCache.instance
          super(node, new_resource)
        end
      
        def load_current_resource
          @current_resource = Chef::Resource::Package.new(@new_resource.name)
          @current_resource.package_name(@new_resource.package_name)
        
          Chef::Log.debug("Checking yum info for #{@new_resource.package_name}")
    
          @yum.refresh

          installed_version = @yum.installed_version(@new_resource.package_name)
          @candidate_version = @yum.candidate_version(@new_resource.package_name)
          
          @current_resource.version(installed_version)
          if candidate_version
            @candidate_version = candidate_version
          else
            @candidate_version = installed_version
          end
        
          @current_resource
        end

        def install_package(name, version)
          run_command(
            :command => "yum -q -y install #{name}-#{version}"
          )
          @yum.flush
        end
      
        def upgrade_package(name, version)
          # If we have a version, we can upgrade - otherwise, install
          if @current_resource.version
            run_command(
              :command => "yum -q -y update #{name}-#{version}"
            )   
            @yum.flush
          else
            install_package(name, version)
          end
        end

        def remove_package(name, version)
          if version
            run_command(
             :command => "yum -q -y remove #{name}-#{version}"
            )
          else
            run_command(
             :command => "yum -q -y remove #{name}"
            )
          end
            
          @yum.flush
        end
      
        def purge_package(name, version)
          remove_package(name, version)
        end
      
      end
    end
  end
end