1
require 'puppet/util/inifile'
4
# A property for one entry in a .ini-style file
5
class IniProperty < Puppet::Property
7
# A should property of :absent is the same as nil
8
if is.nil? && should == :absent
15
if safe_insync?(retrieve)
18
result = set(self.should)
20
resource.section[inikey] = nil
22
resource.section[inikey] = should
29
resource.section[inikey]
36
# Set the key associated with this property to KEY, instead
37
# of using the property's NAME
39
# Override the inikey instance method
40
# Is there a way to do this without resorting to strings ?
41
# Using a block fails because the block can't access
42
# the variable 'key' in the outer scope
43
self.class_eval("def inikey ; \"#{key.to_s}\" ; end")
3
Puppet::Type.newtype(:yumrepo) do
4
@doc = "The client-side description of a yum repository. Repository
5
configurations are found by parsing `/etc/yum.conf` and
6
the files indicated by the `reposdir` option in that file
7
(see `yum.conf(5)` for details).
9
Most parameters are identical to the ones documented
10
in the `yum.conf(5)` man page.
12
Continuation lines that yum supports (for the `baseurl`, for example)
13
are not supported. This type does not attempt to read or verify the
14
exinstence of files listed in the `include` attribute."
16
# Ensure yumrepos can be removed too.
48
18
# Doc string for properties that can be made 'absent'
49
19
ABSENT_DOC="Set this to `absent` to remove it from the file completely."
52
@doc = "The client-side description of a yum repository. Repository
53
configurations are found by parsing `/etc/yum.conf` and
54
the files indicated by the `reposdir` option in that file
55
(see `yum.conf(5)` for details).
57
Most parameters are identical to the ones documented
58
in the `yum.conf(5)` man page.
60
Continuation lines that yum supports (for the `baseurl`, for example)
61
are not supported. This type does not attempt to read or verify the
62
exinstence of files listed in the `include` attribute."
65
attr_accessor :filetype
66
# The writer is only used for testing, there should be no need
67
# to change yumconf or inifile in any other context
68
attr_accessor :yumconf
72
self.filetype = Puppet::Util::FileType.filetype(:flat)
76
@yumconf = "/etc/yum.conf"
78
# Where to put files for brand new sections
83
check = validproperties
85
inifile.each_section do |s|
86
next if s.name == "main"
87
obj = new(:name => s.name, :audit => check)
88
current_values = obj.retrieve
89
obj.eachproperty do |property|
90
if current_values[property].nil?
91
obj.delete(property.name)
93
property.should = current_values[property]
102
# Return the Puppet::Util::IniConfig::File for the whole yum config
106
main = @inifile['main']
107
raise Puppet::Error, "File #{yumconf} does not contain a main section" if main.nil?
108
reposdir = main['reposdir']
109
reposdir ||= "/etc/yum.repos.d, /etc/yum/repos.d"
110
reposdir.gsub!(/[\n,]/, " ")
111
reposdir.split.each do |dir|
112
Dir::glob("#{dir}/*.repo").each do |file|
113
@inifile.read(file) if ::File.file?(file)
116
reposdir.split.each do |dir|
117
if ::File.directory?(dir) && ::File.writable?(dir)
118
@defaultrepodir = dir
126
# Parse the yum config files. Only exposed for the tests
127
# Non-test code should use self.inifile to get at the
130
result = Puppet::Util::IniConfig::File.new
132
main = result['main']
133
raise Puppet::Error, "File #{yumconf} does not contain a main section" if main.nil?
134
reposdir = main['reposdir']
135
reposdir ||= "/etc/yum.repos.d, /etc/yum/repos.d"
136
reposdir.gsub!(/[\n,]/, " ")
137
reposdir.split.each do |dir|
138
Dir::glob("#{dir}/*.repo").each do |file|
139
result.read(file) if ::File.file?(file)
142
if @defaultrepodir.nil?
143
reposdir.split.each do |dir|
144
if ::File.directory?(dir) && ::File.writable?(dir)
145
@defaultrepodir = dir
153
# Return the Puppet::Util::IniConfig::Section with name NAME
154
# from the yum config
155
def self.section(name)
156
result = inifile[name]
160
path = ::File.join(@defaultrepodir, "#{name}.repo") unless @defaultrepodir.nil?
161
Puppet::info "create new repo #{name} in file #{path}"
162
result = inifile.add_section(name, path)
167
# Store all modifications back to disk
171
target_mode = 0644 # FIXME: should be configurable
172
inifile.each_file do |file|
173
current_mode = Puppet::FileSystem::File.new(file).stat.mode & 0777
174
unless current_mode == target_mode
175
Puppet::info "changing mode of #{file} from %03o to %03o" % [current_mode, target_mode]
176
::File.chmod(target_mode, file)
182
# This is only used during testing.
185
@yumconf = "/etc/yum.conf"
186
@defaultrepodir = nil
189
# Return the Puppet::Util::IniConfig::Section for this yumrepo resource
191
self.class.section(self[:name])
194
# Store modifications to this yumrepo resource back to disk
200
desc "The name of the repository. This corresponds to the
201
`repositoryid` parameter in `yum.conf(5)`."
205
newproperty(:descr, :parent => Puppet::IniProperty) do
206
desc "A human-readable description of the repository.
207
This corresponds to the name parameter in `yum.conf(5)`.
209
newvalue(:absent) { self.should = :absent }
214
newproperty(:mirrorlist, :parent => Puppet::IniProperty) do
215
desc "The URL that holds the list of mirrors for this repository.
217
newvalue(:absent) { self.should = :absent }
218
# Should really check that it's a valid URL
222
newproperty(:baseurl, :parent => Puppet::IniProperty) do
223
desc "The URL for this repository. #{ABSENT_DOC}"
224
newvalue(:absent) { self.should = :absent }
225
# Should really check that it's a valid URL
229
newproperty(:enabled, :parent => Puppet::IniProperty) do
230
desc "Whether this repository is enabled, as represented by a
231
`0` or `1`. #{ABSENT_DOC}"
232
newvalue(:absent) { self.should = :absent }
233
newvalue(/^(0|1)$/) { }
236
newproperty(:gpgcheck, :parent => Puppet::IniProperty) do
237
desc "Whether to check the GPG signature on packages installed
238
from this repository, as represented by a `0` or `1`.
240
newvalue(:absent) { self.should = :absent }
241
newvalue(/^(0|1)$/) { }
244
newproperty(:gpgkey, :parent => Puppet::IniProperty) do
245
desc "The URL for the GPG key with which packages from this
246
repository are signed. #{ABSENT_DOC}"
247
newvalue(:absent) { self.should = :absent }
248
# Should really check that it's a valid URL
252
newproperty(:include, :parent => Puppet::IniProperty) do
253
desc "The URL of a remote file containing additional yum configuration
254
settings. Puppet does not check for this file's existence or validity.
256
newvalue(:absent) { self.should = :absent }
257
# Should really check that it's a valid URL
261
newproperty(:exclude, :parent => Puppet::IniProperty) do
262
desc "List of shell globs. Matching packages will never be
263
considered in updates or installs for this repo.
265
newvalue(:absent) { self.should = :absent }
269
newproperty(:includepkgs, :parent => Puppet::IniProperty) do
270
desc "List of shell globs. If this is set, only packages
271
matching one of the globs will be considered for
272
update or install from this repo. #{ABSENT_DOC}"
273
newvalue(:absent) { self.should = :absent }
277
newproperty(:enablegroups, :parent => Puppet::IniProperty) do
278
desc "Whether yum will allow the use of package groups for this
279
repository, as represented by a `0` or `1`. #{ABSENT_DOC}"
280
newvalue(:absent) { self.should = :absent }
281
newvalue(/^(0|1)$/) { }
284
newproperty(:failovermethod, :parent => Puppet::IniProperty) do
285
desc "The failover methode for this repository; should be either
286
`roundrobin` or `priority`. #{ABSENT_DOC}"
287
newvalue(:absent) { self.should = :absent }
288
newvalue(%r{roundrobin|priority}) { }
291
newproperty(:keepalive, :parent => Puppet::IniProperty) do
292
desc "Whether HTTP/1.1 keepalive should be used with this repository, as
293
represented by a `0` or `1`. #{ABSENT_DOC}"
294
newvalue(:absent) { self.should = :absent }
295
newvalue(/^(0|1)$/) { }
298
newproperty(:http_caching, :parent => Puppet::IniProperty) do
299
desc "What to cache from this repository. #{ABSENT_DOC}"
300
newvalue(:absent) { self.should = :absent }
301
newvalue(%r(packages|all|none)) { }
304
newproperty(:timeout, :parent => Puppet::IniProperty) do
305
desc "Number of seconds to wait for a connection before timing
307
newvalue(:absent) { self.should = :absent }
308
newvalue(%r{[0-9]+}) { }
311
newproperty(:metadata_expire, :parent => Puppet::IniProperty) do
312
desc "Number of seconds after which the metadata will expire.
314
newvalue(:absent) { self.should = :absent }
315
newvalue(%r{[0-9]+}) { }
318
newproperty(:protect, :parent => Puppet::IniProperty) do
319
desc "Enable or disable protection for this repository. Requires
320
that the `protectbase` plugin is installed and enabled.
322
newvalue(:absent) { self.should = :absent }
323
newvalue(/^(0|1)$/) { }
326
newproperty(:priority, :parent => Puppet::IniProperty) do
327
desc "Priority of this repository from 1-99. Requires that
328
the `priorities` plugin is installed and enabled.
330
newvalue(:absent) { self.should = :absent }
331
newvalue(%r{[1-9][0-9]?}) { }
334
newproperty(:cost, :parent => Puppet::IniProperty) do
335
desc "Cost of this repository. #{ABSENT_DOC}"
336
newvalue(:absent) { self.should = :absent }
337
newvalue(%r{\d+}) { }
340
newproperty(:proxy, :parent => Puppet::IniProperty) do
341
desc "URL to the proxy server for this repository. #{ABSENT_DOC}"
342
newvalue(:absent) { self.should = :absent }
343
# Should really check that it's a valid URL
347
newproperty(:proxy_username, :parent => Puppet::IniProperty) do
348
desc "Username for this proxy. #{ABSENT_DOC}"
349
newvalue(:absent) { self.should = :absent }
353
newproperty(:proxy_password, :parent => Puppet::IniProperty) do
354
desc "Password for this proxy. #{ABSENT_DOC}"
355
newvalue(:absent) { self.should = :absent }
359
newproperty(:s3_enabled, :parent => Puppet::IniProperty) do
360
desc "Access the repo via S3. #{ABSENT_DOC}"
361
newvalue(:absent) { self.should = :absent }
362
newvalue(/^(0|1)$/) { }
365
newproperty(:sslcacert, :parent => Puppet::IniProperty) do
366
desc "Path to the directory containing the databases of the
367
certificate authorities yum should use to verify SSL certificates.
369
newvalue(:absent) { self.should = :absent }
373
newproperty(:sslverify, :parent => Puppet::IniProperty) do
374
desc "Should yum verify SSL certificates/hosts at all.
375
Possible values are 'True' or 'False'.
377
newvalue(:absent) { self.should = :absent }
378
newvalue(%r(True|False)) { }
381
newproperty(:sslclientcert, :parent => Puppet::IniProperty) do
382
desc "Path to the SSL client certificate yum should use to connect
383
to repos/remote sites. #{ABSENT_DOC}"
384
newvalue(:absent) { self.should = :absent }
388
newproperty(:sslclientkey, :parent => Puppet::IniProperty) do
389
desc "Path to the SSL client key yum should use to connect
390
to repos/remote sites. #{ABSENT_DOC}"
391
newvalue(:absent) { self.should = :absent }
20
# False can be false/0/no and True can be true/1/yes in yum.
21
YUM_BOOLEAN=/(True|False|0|1|No|Yes)/i
22
YUM_BOOLEAN_DOC="Valid values are: False/0/No or True/1/Yes."
24
VALID_SCHEMES = %w[file http https ftp]
26
newparam(:name, :namevar => true) do
27
desc "The name of the repository. This corresponds to the
28
`repositoryid` parameter in `yum.conf(5)`."
32
desc "The filename to write the yum repository to."
37
newproperty(:descr) do
38
desc "A human-readable description of the repository.
39
This corresponds to the name parameter in `yum.conf(5)`.
42
newvalues(/.*/, :absent)
45
newproperty(:mirrorlist) do
46
desc "The URL that holds the list of mirrors for this repository.
49
newvalues(/.*/, :absent)
51
next if value.to_s == 'absent'
52
parsed = URI.parse(value)
54
unless VALID_SCHEMES.include?(parsed.scheme)
55
raise "Must be a valid URL"
60
newproperty(:baseurl) do
61
desc "The URL for this repository. #{ABSENT_DOC}"
63
newvalues(/.*/, :absent)
65
next if value.to_s == 'absent'
67
value.split(/\s+/).each do |uri|
69
parsed = URI.parse(uri)
71
unless VALID_SCHEMES.include?(parsed.scheme)
72
raise "Must be a valid URL"
78
newproperty(:enabled) do
79
desc "Whether this repository is enabled.
83
newvalues(YUM_BOOLEAN, :absent)
86
newproperty(:gpgcheck) do
87
desc "Whether to check the GPG signature on packages installed
92
newvalues(YUM_BOOLEAN, :absent)
95
newproperty(:repo_gpgcheck) do
96
desc "Whether to check the GPG signature on repodata.
100
newvalues(YUM_BOOLEAN, :absent)
103
newproperty(:gpgkey) do
104
desc "The URL for the GPG key with which packages from this
105
repository are signed. #{ABSENT_DOC}"
107
newvalues(/.*/, :absent)
109
next if value.to_s == 'absent'
111
value.split(/\s+/).each do |uri|
113
parsed = URI.parse(uri)
115
unless VALID_SCHEMES.include?(parsed.scheme)
116
raise "Must be a valid URL"
122
newproperty(:include) do
123
desc "The URL of a remote file containing additional yum configuration
124
settings. Puppet does not check for this file's existence or validity.
127
newvalues(/.*/, :absent)
129
next if value.to_s == 'absent'
130
parsed = URI.parse(value)
132
unless VALID_SCHEMES.include?(parsed.scheme)
133
raise "Must be a valid URL"
138
newproperty(:exclude) do
139
desc "List of shell globs. Matching packages will never be
140
considered in updates or installs for this repo.
143
newvalues(/.*/, :absent)
146
newproperty(:includepkgs) do
147
desc "List of shell globs. If this is set, only packages
148
matching one of the globs will be considered for
149
update or install from this repo. #{ABSENT_DOC}"
151
newvalues(/.*/, :absent)
154
newproperty(:enablegroups) do
155
desc "Whether yum will allow the use of package groups for this
160
newvalues(YUM_BOOLEAN, :absent)
163
newproperty(:failovermethod) do
164
desc "The failover method for this repository; should be either
165
`roundrobin` or `priority`. #{ABSENT_DOC}"
167
newvalues(/roundrobin|priority/, :absent)
170
newproperty(:keepalive) do
171
desc "Whether HTTP/1.1 keepalive should be used with this repository.
175
newvalues(YUM_BOOLEAN, :absent)
178
newproperty(:http_caching) do
179
desc "What to cache from this repository. #{ABSENT_DOC}"
181
newvalues(/(packages|all|none)/, :absent)
184
newproperty(:timeout) do
185
desc "Number of seconds to wait for a connection before timing
188
newvalues(/[0-9]+/, :absent)
191
newproperty(:metadata_expire) do
192
desc "Number of seconds after which the metadata will expire.
195
newvalues(/[0-9]+/, :absent)
198
newproperty(:protect) do
199
desc "Enable or disable protection for this repository. Requires
200
that the `protectbase` plugin is installed and enabled.
204
newvalues(YUM_BOOLEAN, :absent)
207
newproperty(:priority) do
208
desc "Priority of this repository from 1-99. Requires that
209
the `priorities` plugin is installed and enabled.
212
newvalues(/.*/, :absent)
214
unless value == :absent or (1..99).include?(value.to_i)
215
fail("Must be within range 1-99")
220
newproperty(:cost) do
221
desc "Cost of this repository. #{ABSENT_DOC}"
223
newvalues(/\d+/, :absent)
226
newproperty(:proxy) do
227
desc "URL to the proxy server for this repository. #{ABSENT_DOC}"
229
newvalues(/.*/, :absent)
231
next if value.to_s == 'absent'
232
parsed = URI.parse(value)
234
unless VALID_SCHEMES.include?(parsed.scheme)
235
raise "Must be a valid URL"
240
newproperty(:proxy_username) do
241
desc "Username for this proxy. #{ABSENT_DOC}"
243
newvalues(/.*/, :absent)
246
newproperty(:proxy_password) do
247
desc "Password for this proxy. #{ABSENT_DOC}"
249
newvalues(/.*/, :absent)
252
newproperty(:s3_enabled) do
253
desc "Access the repo via S3.
257
newvalues(YUM_BOOLEAN, :absent)
260
newproperty(:sslcacert) do
261
desc "Path to the directory containing the databases of the
262
certificate authorities yum should use to verify SSL certificates.
265
newvalues(/.*/, :absent)
268
newproperty(:sslverify) do
269
desc "Should yum verify SSL certificates/hosts at all.
273
newvalues(YUM_BOOLEAN, :absent)
276
newproperty(:sslclientcert) do
277
desc "Path to the SSL client certificate yum should use to connect
278
to repos/remote sites. #{ABSENT_DOC}"
280
newvalues(/.*/, :absent)
283
newproperty(:sslclientkey) do
284
desc "Path to the SSL client key yum should use to connect
285
to repos/remote sites. #{ABSENT_DOC}"
287
newvalues(/.*/, :absent)
290
newproperty(:metalink) do
291
desc "Metalink for mirrors. #{ABSENT_DOC}"
293
newvalues(/.*/, :absent)
295
next if value.to_s == 'absent'
296
parsed = URI.parse(value)
298
unless VALID_SCHEMES.include?(parsed.scheme)
299
raise "Must be a valid URL"