1
require 'puppet/util/inifile'
3
Puppet::Type.type(:yumrepo).provide(:inifile) do
4
desc 'Manage yum repos'
6
PROPERTIES = Puppet::Type.type(:yumrepo).validproperties
8
# @return [Array<Puppet::Providers>] Return all the providers built up from
9
# discovered content on the local node.
12
# Iterate over each section of our virtual file.
13
virtual_inifile.each_section do |section|
14
attributes_hash = {:name => section.name, :ensure => :present, :provider => :yumrepo}
15
# We need to build up a attributes hash
16
section.entries.each do |key, value|
18
if valid_property?(key)
19
# We strip the values here to handle cases where distros set values
20
# like enabled = 1 with spaces.
21
attributes_hash[key] = value
23
attributes_hash[:descr] = value
26
instances << new(attributes_hash)
31
# @param resources [Array<Puppet::Resource>] Resources to prefetch.
32
# @return [Array<Puppet::Resource>] Resources with providers set.
33
def self.prefetch(resources)
35
resources.keys.each do |name|
36
if provider = repos.find { |repo| repo.name == name }
37
resources[name].provider = provider
42
# Return a list of existing directories that could contain repo files. Fail if none found.
43
# @param conf [String] Configuration file to look for directories in.
44
# @param dirs [Array] Default locations for yum repos.
45
# @return [Array] Directories that were found to exist on the node.
46
def self.reposdir(conf='/etc/yum.conf', dirs=['/etc/yum.repos.d', '/etc/yum/repos.d'])
47
reposdir = find_conf_value('reposdir', conf)
48
dirs << reposdir if reposdir
50
# We can't use the below due to Ruby 1.8.7
51
# dirs.select! { |dir| Puppet::FileSystem.exist?(dir) }
52
dirs.delete_if { |dir| ! Puppet::FileSystem.exist?(dir) }
54
fail('No yum directories were found on the local filesystem')
60
# Helper method to look up specific values in ini style files.
61
# @todo Migrate this into Puppet::Util::IniConfig.
62
# @param value [String] Value to look for in the configuration file.
63
# @param conf [String] Configuration file to check for value.
64
# @return [String] The value of a looked up key from the configuration file.
65
def self.find_conf_value(value, conf='/etc/yum.conf')
66
if Puppet::FileSystem.exist?(conf)
67
contents = Puppet::FileSystem.read(conf)
68
match = /^#{value}\s*=\s*(.*)/.match(contents)
71
return match.captures[0] if match
74
# Build a virtual inifile by reading in numerous .repo
75
# files into a single virtual file to ease manipulation.
76
# @return [Puppet::Util::IniConfig::File] The virtual inifile representing
77
# multiple real files.
78
def self.virtual_inifile
80
@virtual = Puppet::Util::IniConfig::File.new
81
reposdir.each do |dir|
82
Dir.glob("#{dir}/*.repo").each do |file|
83
@virtual.read(file) if Puppet::FileSystem.file?(file)
90
# @param key [String] The property to look up.
91
# @return [Boolean] Returns true if the property is defined in the type.
92
def self.valid_property?(key)
93
PROPERTIES.include?(key)
96
# We need to return a valid section from the larger virtual inifile here,
97
# which we do by first looking it up and then creating a new section for
98
# the appropriate name if none was found.
99
# @param name [String] Section name to lookup in the virtual inifile.
100
# @return [Puppet::Util::IniConfig] The IniConfig section
101
def self.section(name)
102
result = self.virtual_inifile[name]
103
# Create a new section if not found.
105
# Previously we did an .each on reposdir with the effect that we
106
# constantly created and overwrote result until the last entry of
107
# the array. This was done because the ordering is
108
# [defaults, custom] for reposdir and we want to use the custom if
109
# we have it and the defaults if not.
110
path = ::File.join(reposdir.last, "#{name}.repo")
111
Puppet.info("create new repo #{name} in file #{path}")
112
result = self.virtual_inifile.add_section(name, path)
117
# Here we store all modifications to disk, forcing the output file to 0644 if it differs.
120
inifile = self.virtual_inifile
124
inifile.each_file do |file|
125
current_mode = Puppet::FileSystem.stat(file).mode & 0777
126
unless current_mode == target_mode
127
Puppet.info "changing mode of #{file} from %03o to %03o" % [current_mode, target_mode]
128
Puppet::FileSystem.chmod(target_mode, file)
135
@property_hash[:ensure] = :present
137
new_section = current_section
139
# We fetch a list of properties from the type, then iterate
140
# over them, avoiding ensure. We're relying on .should to
141
# check if the property has been set and should be modified,
142
# and if so we set it in the virtual inifile.
143
PROPERTIES.each do |property|
144
next if property == :ensure
147
if value = @resource.should(property)
148
self.send("#{property}=", value)
153
# @return [Boolean] Returns true if ensure => present.
155
@property_hash[:ensure] == :present
158
# We don't actually destroy the file here, merely mark it for
159
# destruction in the section.
162
# Flag file for deletion on flush.
163
current_section.destroy=(true)
173
# Generate setters and getters for our INI properties.
174
PROPERTIES.each do |property|
175
# The ensure property uses #create, #exists, and #destroy we can't generate
176
# meaningful setters and getters for this
177
next if property == :ensure
179
define_method(property) do
180
get_property(property)
183
define_method("#{property}=") do |value|
184
set_property(property, value)
188
# Map the yumrepo 'descr' type property to the 'name' INI property.
190
if ! @property_hash.has_key?(:descr)
191
@property_hash[:descr] = current_section['name']
193
value = @property_hash[:descr]
194
value.nil? ? :absent : value
198
value = (value == :absent ? nil : value)
199
current_section['name'] = value
200
@property_hash[:descr] = value
205
def get_property(property)
206
if ! @property_hash.has_key?(property)
207
@property_hash[property] = current_section[property.to_s]
209
value = @property_hash[property]
210
value.nil? ? :absent : value
213
def set_property(property, value)
214
value = (value == :absent ? nil : value)
215
current_section[property.to_s] = value
216
@property_hash[property] = value
221
self.class.section(name)
225
self.class.section(self.name)