chef 0.10.2 → 0.10.4.rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/distro/common/html/chef-client.8.html +4 -4
- data/distro/common/html/knife-cookbook.1.html +5 -3
- data/distro/common/html/knife-node.1.html +4 -4
- data/distro/common/man/man1/knife-cookbook.1 +5 -1
- data/distro/common/man/man1/knife-node.1 +1 -1
- data/distro/common/markdown/man1/knife-cookbook-site.mkd +3 -3
- data/distro/common/markdown/man1/knife-cookbook.mkd +7 -0
- data/distro/common/markdown/man1/knife-node.mkd +4 -3
- data/distro/common/markdown/man1/knife-ssh.mkd +2 -0
- data/lib/chef/application.rb +1 -0
- data/lib/chef/cookbook_loader.rb +18 -0
- data/lib/chef/cookbook_uploader.rb +1 -1
- data/lib/chef/data_bag.rb +14 -2
- data/lib/chef/data_bag_item.rb +8 -2
- data/lib/chef/encrypted_data_bag_item.rb +19 -6
- data/lib/chef/environment.rb +12 -6
- data/lib/chef/exceptions.rb +1 -0
- data/lib/chef/knife.rb +0 -28
- data/lib/chef/knife/bootstrap.rb +7 -0
- data/lib/chef/knife/bootstrap/archlinux-gems.erb +14 -12
- data/lib/chef/knife/bootstrap/centos5-gems.erb +8 -5
- data/lib/chef/knife/bootstrap/fedora13-gems.erb +2 -0
- data/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb +16 -9
- data/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb +6 -3
- data/lib/chef/knife/client_bulk_delete.rb +28 -6
- data/lib/chef/knife/cookbook_site_install.rb +2 -2
- data/lib/chef/knife/cookbook_upload.rb +71 -0
- data/lib/chef/knife/core/bootstrap_context.rb +13 -3
- data/lib/chef/knife/core/cookbook_scm_repo.rb +2 -3
- data/lib/chef/knife/core/node_presenter.rb +5 -2
- data/lib/chef/knife/help.rb +13 -12
- data/lib/chef/knife/help_topics.rb +4 -0
- data/lib/chef/knife/ssh.rb +25 -4
- data/lib/chef/mixin/create_path.rb +3 -2
- data/lib/chef/mixin/get_source_from_package.rb +42 -0
- data/lib/chef/mixin/language.rb +8 -11
- data/lib/chef/monkey_patches/numeric.rb +9 -1
- data/lib/chef/monkey_patches/string.rb +21 -0
- data/lib/chef/platform.rb +2 -1
- data/lib/chef/provider.rb +1 -1
- data/lib/chef/provider/git.rb +16 -3
- data/lib/chef/provider/group/suse.rb +53 -0
- data/lib/chef/provider/mount/mount.rb +28 -20
- data/lib/chef/provider/package/apt.rb +39 -24
- data/lib/chef/provider/package/dpkg.rb +5 -2
- data/lib/chef/provider/package/easy_install.rb +2 -2
- data/lib/chef/provider/package/freebsd.rb +5 -2
- data/lib/chef/provider/package/macports.rb +4 -4
- data/lib/chef/provider/package/rpm.rb +4 -1
- data/lib/chef/provider/package/rubygems.rb +3 -0
- data/lib/chef/provider/package/solaris.rb +3 -0
- data/lib/chef/provider/package/yum-dump.py +239 -81
- data/lib/chef/provider/package/yum.rb +977 -110
- data/lib/chef/provider/package/zypper.rb +20 -3
- data/lib/chef/provider/remote_directory.rb +0 -1
- data/lib/chef/provider/service/arch.rb +35 -28
- data/lib/chef/provider/service/systemd.rb +102 -0
- data/lib/chef/provider/service/upstart.rb +8 -2
- data/lib/chef/providers.rb +2 -0
- data/lib/chef/resource.rb +31 -2
- data/lib/chef/resource/git.rb +9 -0
- data/lib/chef/resource/mount.rb +1 -2
- data/lib/chef/resource/yum_package.rb +20 -0
- data/lib/chef/rest.rb +1 -1
- data/lib/chef/role.rb +1 -1
- data/lib/chef/run_context.rb +3 -3
- data/lib/chef/runner.rb +15 -2
- data/lib/chef/shell_out.rb +1 -1
- data/lib/chef/shell_out/windows.rb +2 -2
- data/lib/chef/solr_query.rb +1 -1
- data/lib/chef/tasks/chef_repo.rake +1 -1
- data/lib/chef/version.rb +1 -1
- metadata +425 -441
@@ -6,9 +6,9 @@
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
7
|
# you may not use this file except in compliance with the License.
|
8
8
|
# You may obtain a copy of the License at
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# Unless required by applicable law or agreed to in writing, software
|
13
13
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
14
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
@@ -20,154 +20,913 @@ require 'chef/provider/package'
|
|
20
20
|
require 'chef/mixin/command'
|
21
21
|
require 'chef/resource/package'
|
22
22
|
require 'singleton'
|
23
|
+
require 'chef/mixin/get_source_from_package'
|
24
|
+
|
23
25
|
|
24
26
|
class Chef
|
25
27
|
class Provider
|
26
28
|
class Package
|
27
29
|
class Yum < Chef::Provider::Package
|
28
30
|
|
29
|
-
class
|
30
|
-
|
31
|
-
include Singleton
|
31
|
+
class RPMUtils
|
32
|
+
class << self
|
32
33
|
|
33
|
-
|
34
|
-
|
34
|
+
# RPM::Version version_parse equivalent
|
35
|
+
def version_parse(evr)
|
36
|
+
return if evr.nil?
|
37
|
+
|
38
|
+
epoch = nil
|
39
|
+
# assume this is a version
|
40
|
+
version = evr
|
41
|
+
release = nil
|
42
|
+
|
43
|
+
lead = 0
|
44
|
+
tail = evr.size
|
45
|
+
|
46
|
+
if evr =~ %r{^([\d]+):}
|
47
|
+
epoch = $1.to_i
|
48
|
+
lead = $1.length + 1
|
49
|
+
elsif evr[0].ord == ":".ord
|
50
|
+
epoch = 0
|
51
|
+
lead = 1
|
52
|
+
end
|
53
|
+
|
54
|
+
if evr =~ %r{:?.*-(.*)$}
|
55
|
+
release = $1
|
56
|
+
tail = evr.length - release.length - lead - 1
|
57
|
+
|
58
|
+
if release.empty?
|
59
|
+
release = nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
version = evr[lead,tail]
|
64
|
+
if version.empty?
|
65
|
+
version = nil
|
66
|
+
end
|
67
|
+
|
68
|
+
[ epoch, version, release ]
|
69
|
+
end
|
70
|
+
|
71
|
+
# verify
|
72
|
+
def isalnum(x)
|
73
|
+
isalpha(x) or isdigit(x)
|
74
|
+
end
|
75
|
+
|
76
|
+
def isalpha(x)
|
77
|
+
v = x.ord
|
78
|
+
(v >= 65 and v <= 90) or (v >= 97 and v <= 122)
|
79
|
+
end
|
80
|
+
|
81
|
+
def isdigit(x)
|
82
|
+
v = x.ord
|
83
|
+
v >= 48 and v <= 57
|
84
|
+
end
|
85
|
+
|
86
|
+
# based on the reference spec in lib/rpmvercmp.c in rpm 4.9.0
|
87
|
+
def rpmvercmp(x, y)
|
88
|
+
# easy! :)
|
89
|
+
return 0 if x == y
|
90
|
+
|
91
|
+
if x.nil?
|
92
|
+
x = ""
|
93
|
+
end
|
94
|
+
|
95
|
+
if y.nil?
|
96
|
+
y = ""
|
97
|
+
end
|
98
|
+
|
99
|
+
# not so easy :(
|
100
|
+
#
|
101
|
+
# takes 2 strings like
|
102
|
+
#
|
103
|
+
# x = "1.20.b18.el5"
|
104
|
+
# y = "1.20.b17.el5"
|
105
|
+
#
|
106
|
+
# breaks into purely alpha and numeric segments and compares them using
|
107
|
+
# some rules
|
108
|
+
#
|
109
|
+
# * 10 > 1
|
110
|
+
# * 1 > a
|
111
|
+
# * z > a
|
112
|
+
# * Z > A
|
113
|
+
# * z > Z
|
114
|
+
# * leading zeros are ignored
|
115
|
+
# * separators (periods, commas) are ignored
|
116
|
+
# * "1.20.b18.el5.extrastuff" > "1.20.b18.el5"
|
117
|
+
|
118
|
+
x_pos = 0 # overall string element reference position
|
119
|
+
x_pos_max = x.length - 1 # number of elements in string, starting from 0
|
120
|
+
x_seg_pos = 0 # segment string element reference position
|
121
|
+
x_comp = nil # segment to compare
|
122
|
+
|
123
|
+
y_pos = 0
|
124
|
+
y_seg_pos = 0
|
125
|
+
y_pos_max = y.length - 1
|
126
|
+
y_comp = nil
|
127
|
+
|
128
|
+
while (x_pos <= x_pos_max and y_pos <= y_pos_max)
|
129
|
+
# first we skip over anything non alphanumeric
|
130
|
+
while (x_pos <= x_pos_max) and (isalnum(x[x_pos]) == false)
|
131
|
+
x_pos += 1 # +1 over pos_max if end of string
|
132
|
+
end
|
133
|
+
while (y_pos <= y_pos_max) and (isalnum(y[y_pos]) == false)
|
134
|
+
y_pos += 1
|
135
|
+
end
|
136
|
+
|
137
|
+
# if we hit the end of either we are done matching segments
|
138
|
+
if (x_pos == x_pos_max + 1) or (y_pos == y_pos_max + 1)
|
139
|
+
break
|
140
|
+
end
|
141
|
+
|
142
|
+
# we are now at the start of a alpha or numeric segment
|
143
|
+
x_seg_pos = x_pos
|
144
|
+
y_seg_pos = y_pos
|
145
|
+
|
146
|
+
# grab segment so we can compare them
|
147
|
+
if isdigit(x[x_seg_pos].ord)
|
148
|
+
x_seg_is_num = true
|
149
|
+
|
150
|
+
# already know it's a digit
|
151
|
+
x_seg_pos += 1
|
152
|
+
|
153
|
+
# gather up our digits
|
154
|
+
while (x_seg_pos <= x_pos_max) and isdigit(x[x_seg_pos])
|
155
|
+
x_seg_pos += 1
|
156
|
+
end
|
157
|
+
# copy the segment but not the unmatched character that x_seg_pos will
|
158
|
+
# refer to
|
159
|
+
x_comp = x[x_pos,x_seg_pos - x_pos]
|
160
|
+
|
161
|
+
while (y_seg_pos <= y_pos_max) and isdigit(y[y_seg_pos])
|
162
|
+
y_seg_pos += 1
|
163
|
+
end
|
164
|
+
y_comp = y[y_pos,y_seg_pos - y_pos]
|
165
|
+
else
|
166
|
+
# we are comparing strings
|
167
|
+
x_seg_is_num = false
|
168
|
+
|
169
|
+
while (x_seg_pos <= x_pos_max) and isalpha(x[x_seg_pos])
|
170
|
+
x_seg_pos += 1
|
171
|
+
end
|
172
|
+
x_comp = x[x_pos,x_seg_pos - x_pos]
|
173
|
+
|
174
|
+
while (y_seg_pos <= y_pos_max) and isalpha(y[y_seg_pos])
|
175
|
+
y_seg_pos += 1
|
176
|
+
end
|
177
|
+
y_comp = y[y_pos,y_seg_pos - y_pos]
|
178
|
+
end
|
179
|
+
|
180
|
+
# if y_seg_pos didn't advance in the above loop it means the segments are
|
181
|
+
# different types
|
182
|
+
if y_pos == y_seg_pos
|
183
|
+
# numbers always win over letters
|
184
|
+
return x_seg_is_num ? 1 : -1
|
185
|
+
end
|
186
|
+
|
187
|
+
# move the ball forward before we mess with the segments
|
188
|
+
x_pos += x_comp.length # +1 over pos_max if end of string
|
189
|
+
y_pos += y_comp.length
|
190
|
+
|
191
|
+
# we are comparing numbers - simply convert them
|
192
|
+
if x_seg_is_num
|
193
|
+
x_comp = x_comp.to_i
|
194
|
+
y_comp = y_comp.to_i
|
195
|
+
end
|
196
|
+
|
197
|
+
# compares ints or strings
|
198
|
+
# don't return if equal - try the next segment
|
199
|
+
if x_comp > y_comp
|
200
|
+
return 1
|
201
|
+
elsif x_comp < y_comp
|
202
|
+
return -1
|
203
|
+
end
|
204
|
+
|
205
|
+
# if we've reached here than the segments are the same - try again
|
206
|
+
end
|
207
|
+
|
208
|
+
# we must have reached the end of one or both of the strings and they
|
209
|
+
# matched up until this point
|
210
|
+
|
211
|
+
# segments matched completely but the segment separators were different -
|
212
|
+
# rpm reference code treats these as equal.
|
213
|
+
if (x_pos == x_pos_max + 1) and (y_pos == y_pos_max + 1)
|
214
|
+
return 0
|
215
|
+
end
|
216
|
+
|
217
|
+
# the most unprocessed characters left wins
|
218
|
+
if (x_pos_max - x_pos) > (y_pos_max - y_pos)
|
219
|
+
return 1
|
220
|
+
else
|
221
|
+
return -1
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
end # self
|
226
|
+
end # RPMUtils
|
227
|
+
|
228
|
+
class RPMVersion
|
229
|
+
include Comparable
|
230
|
+
|
231
|
+
def initialize(*args)
|
232
|
+
if args.size == 1
|
233
|
+
@e, @v, @r = RPMUtils.version_parse(args[0])
|
234
|
+
elsif args.size == 3
|
235
|
+
@e = args[0].to_i
|
236
|
+
@v = args[1]
|
237
|
+
@r = args[2]
|
238
|
+
else
|
239
|
+
raise ArgumentError, "Expecting either 'epoch-version-release' or 'epoch, " +
|
240
|
+
"version, release'"
|
241
|
+
end
|
242
|
+
end
|
243
|
+
attr_reader :e, :v, :r
|
244
|
+
alias :epoch :e
|
245
|
+
alias :version :v
|
246
|
+
alias :release :r
|
247
|
+
|
248
|
+
def self.parse(*args)
|
249
|
+
self.new(*args)
|
250
|
+
end
|
251
|
+
|
252
|
+
def <=>(y)
|
253
|
+
compare_versions(y)
|
254
|
+
end
|
255
|
+
|
256
|
+
def compare(y)
|
257
|
+
compare_versions(y, false)
|
258
|
+
end
|
259
|
+
|
260
|
+
def partial_compare(y)
|
261
|
+
compare_versions(y, true)
|
262
|
+
end
|
263
|
+
|
264
|
+
# RPM::Version rpm_version_to_s equivalent
|
265
|
+
def to_s
|
266
|
+
if @r.nil?
|
267
|
+
@v
|
268
|
+
else
|
269
|
+
"#{@v}-#{@r}"
|
270
|
+
end
|
35
271
|
end
|
36
272
|
|
37
|
-
def
|
38
|
-
|
273
|
+
def evr
|
274
|
+
"#{@e}:#{@v}-#{@r}"
|
275
|
+
end
|
276
|
+
|
277
|
+
private
|
278
|
+
|
279
|
+
# Rough RPM::Version rpm_version_cmp equivalent - except much slower :)
|
280
|
+
#
|
281
|
+
# partial lets epoch and version segment equality be good enough to return equal, eg:
|
282
|
+
#
|
283
|
+
# 2:1.2-1 == 2:1.2
|
284
|
+
# 2:1.2-1 == 2:
|
285
|
+
#
|
286
|
+
def compare_versions(y, partial=false)
|
287
|
+
x = self
|
288
|
+
|
289
|
+
# compare epoch
|
290
|
+
if (x.e.nil? == false and x.e > 0) and y.e.nil?
|
291
|
+
return 1
|
292
|
+
elsif x.e.nil? and (y.e.nil? == false and y.e > 0)
|
293
|
+
return -1
|
294
|
+
elsif x.e.nil? == false and y.e.nil? == false
|
295
|
+
if x.e < y.e
|
296
|
+
return -1
|
297
|
+
elsif x.e > y.e
|
298
|
+
return 1
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
# compare version
|
303
|
+
if partial and (x.v.nil? or y.v.nil?)
|
304
|
+
return 0
|
305
|
+
elsif x.v.nil? == false and y.v.nil?
|
306
|
+
return 1
|
307
|
+
elsif x.v.nil? and y.v.nil? == false
|
308
|
+
return -1
|
309
|
+
elsif x.v.nil? == false and y.v.nil? == false
|
310
|
+
cmp = RPMUtils.rpmvercmp(x.v, y.v)
|
311
|
+
return cmp if cmp != 0
|
312
|
+
end
|
313
|
+
|
314
|
+
# compare release
|
315
|
+
if partial and (x.r.nil? or y.r.nil?)
|
316
|
+
return 0
|
317
|
+
elsif x.r.nil? == false and y.r.nil?
|
318
|
+
return 1
|
319
|
+
elsif x.r.nil? and y.r.nil? == false
|
320
|
+
return -1
|
321
|
+
elsif x.r.nil? == false and y.r.nil? == false
|
322
|
+
cmp = RPMUtils.rpmvercmp(x.r, y.r)
|
323
|
+
return cmp
|
324
|
+
end
|
325
|
+
|
326
|
+
return 0
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
class RPMPackage
|
331
|
+
include Comparable
|
332
|
+
|
333
|
+
def initialize(*args)
|
334
|
+
if args.size == 4
|
335
|
+
@n = args[0]
|
336
|
+
@version = RPMVersion.new(args[1])
|
337
|
+
@a = args[2]
|
338
|
+
@provides = args[3]
|
339
|
+
elsif args.size == 6
|
340
|
+
@n = args[0]
|
341
|
+
e = args[1].to_i
|
342
|
+
v = args[2]
|
343
|
+
r = args[3]
|
344
|
+
@version = RPMVersion.new(e,v,r)
|
345
|
+
@a = args[4]
|
346
|
+
@provides = args[5]
|
347
|
+
else
|
348
|
+
raise ArgumentError, "Expecting either 'name, epoch-version-release, arch, provides' " +
|
349
|
+
"or 'name, epoch, version, release, arch, provides'"
|
350
|
+
end
|
351
|
+
|
352
|
+
# We always have one, ourselves!
|
353
|
+
if @provides.empty?
|
354
|
+
@provides = [ RPMProvide.new(@n, @version.evr, :==) ]
|
355
|
+
end
|
356
|
+
end
|
357
|
+
attr_reader :n, :a, :version, :provides
|
358
|
+
alias :name :n
|
359
|
+
alias :arch :a
|
360
|
+
|
361
|
+
def <=>(y)
|
362
|
+
compare(y)
|
363
|
+
end
|
364
|
+
|
365
|
+
def compare(y)
|
366
|
+
x = self
|
367
|
+
|
368
|
+
# easy! :)
|
369
|
+
return 0 if x.nevra == y.nevra
|
370
|
+
|
371
|
+
# compare name
|
372
|
+
if x.n.nil? == false and y.n.nil?
|
373
|
+
return 1
|
374
|
+
elsif x.n.nil? and y.n.nil? == false
|
375
|
+
return -1
|
376
|
+
elsif x.n.nil? == false and y.n.nil? == false
|
377
|
+
if x.n < y.n
|
378
|
+
return -1
|
379
|
+
elsif x.n > y.n
|
380
|
+
return 1
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
# compare version
|
385
|
+
if x.version > y.version
|
386
|
+
return 1
|
387
|
+
elsif x.version < y.version
|
388
|
+
return -1
|
389
|
+
end
|
390
|
+
|
391
|
+
# compare arch
|
392
|
+
if x.a.nil? == false and y.a.nil?
|
393
|
+
return 1
|
394
|
+
elsif x.a.nil? and y.a.nil? == false
|
395
|
+
return -1
|
396
|
+
elsif x.a.nil? == false and y.a.nil? == false
|
397
|
+
if x.a < y.a
|
398
|
+
return -1
|
399
|
+
elsif x.a > y.a
|
400
|
+
return 1
|
401
|
+
end
|
402
|
+
end
|
39
403
|
|
40
|
-
|
41
|
-
|
404
|
+
return 0
|
405
|
+
end
|
406
|
+
|
407
|
+
def to_s
|
408
|
+
nevra
|
409
|
+
end
|
410
|
+
|
411
|
+
def nevra
|
412
|
+
"#{@n}-#{@version.evr}.#{@a}"
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
# Simple implementation from rpm and ruby-rpm reference code
|
417
|
+
class RPMDependency
|
418
|
+
def initialize(*args)
|
419
|
+
if args.size == 3
|
420
|
+
@name = args[0]
|
421
|
+
@version = RPMVersion.new(args[1])
|
422
|
+
# Our requirement to other dependencies
|
423
|
+
@flag = args[2] || :==
|
424
|
+
elsif args.size == 5
|
425
|
+
@name = args[0]
|
426
|
+
e = args[1].to_i
|
427
|
+
v = args[2]
|
428
|
+
r = args[3]
|
429
|
+
@version = RPMVersion.new(e,v,r)
|
430
|
+
@flag = args[4] || :==
|
431
|
+
else
|
432
|
+
raise ArgumentError, "Expecting either 'name, epoch-version-release, flag' or " +
|
433
|
+
"'name, epoch, version, release, flag'"
|
434
|
+
end
|
435
|
+
end
|
436
|
+
attr_reader :name, :version, :flag
|
437
|
+
|
438
|
+
# Parses 2 forms:
|
439
|
+
#
|
440
|
+
# "mtr >= 2:0.71-3.0"
|
441
|
+
# "mta"
|
442
|
+
def self.parse(string)
|
443
|
+
if string =~ %r{^(\S+)\s+(>|>=|=|==|<=|<)\s+(\S+)$}
|
444
|
+
name = $1
|
445
|
+
if $2 == "="
|
446
|
+
flag = :==
|
447
|
+
else
|
448
|
+
flag = :"#{$2}"
|
449
|
+
end
|
450
|
+
version = $3
|
451
|
+
|
452
|
+
return self.new(name, version, flag)
|
453
|
+
else
|
454
|
+
name = string
|
455
|
+
return self.new(name, nil, nil)
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
# Test if another RPMDependency satisfies our requirements
|
460
|
+
def satisfy?(y)
|
461
|
+
unless y.kind_of?(RPMDependency)
|
462
|
+
raise ArgumentError, "Expecting an RPMDependency object"
|
463
|
+
end
|
464
|
+
|
465
|
+
x = self
|
466
|
+
|
467
|
+
# Easy!
|
468
|
+
if x.name != y.name
|
42
469
|
return false
|
43
|
-
|
470
|
+
end
|
471
|
+
|
472
|
+
# Partial compare
|
473
|
+
#
|
474
|
+
# eg: x.version 2.3 == y.version 2.3-1
|
475
|
+
sense = x.version.partial_compare(y.version)
|
476
|
+
|
477
|
+
# Thanks to rpmdsCompare() rpmds.c
|
478
|
+
if sense < 0 and (x.flag == :> || x.flag == :>=) || (y.flag == :<= || y.flag == :<)
|
479
|
+
return true
|
480
|
+
elsif sense > 0 and (x.flag == :< || x.flag == :<=) || (y.flag == :>= || y.flag == :>)
|
481
|
+
return true
|
482
|
+
elsif sense == 0 and (
|
483
|
+
((x.flag == :== or x.flag == :<= or x.flag == :>=) and (y.flag == :== or y.flag == :<= or y.flag == :>=)) or
|
484
|
+
(x.flag == :< and y.flag == :<) or
|
485
|
+
(x.flag == :> and y.flag == :>)
|
486
|
+
)
|
44
487
|
return true
|
45
488
|
end
|
46
489
|
|
47
|
-
false
|
490
|
+
return false
|
48
491
|
end
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
492
|
+
end
|
493
|
+
|
494
|
+
class RPMProvide < RPMDependency; end
|
495
|
+
class RPMRequire < RPMDependency; end
|
496
|
+
|
497
|
+
class RPMDbPackage < RPMPackage
|
498
|
+
# <rpm parts>, installed, available
|
499
|
+
def initialize(*args)
|
500
|
+
# state
|
501
|
+
@available = args.pop
|
502
|
+
@installed = args.pop
|
503
|
+
super(*args)
|
504
|
+
end
|
505
|
+
attr_reader :available, :installed
|
506
|
+
end
|
507
|
+
|
508
|
+
# Simple storage for RPMPackage objects - keeps them unique and sorted
|
509
|
+
class RPMDb
|
510
|
+
def initialize
|
511
|
+
# package name => [ RPMPackage, RPMPackage ] of different versions
|
512
|
+
@rpms = Hash.new
|
513
|
+
# package nevra => RPMPackage for lookups
|
514
|
+
@index = Hash.new
|
515
|
+
# provide name (aka feature) => [RPMPackage, RPMPackage] each providing this feature
|
516
|
+
@provides = Hash.new
|
517
|
+
# RPMPackages listed as available
|
518
|
+
@available = Set.new
|
519
|
+
# RPMPackages listed as installed
|
520
|
+
@installed = Set.new
|
521
|
+
end
|
522
|
+
|
523
|
+
def [](package_name)
|
524
|
+
self.lookup(package_name)
|
525
|
+
end
|
526
|
+
|
527
|
+
# Lookup package_name and return a descending array of package objects
|
528
|
+
def lookup(package_name)
|
529
|
+
pkgs = @rpms[package_name]
|
530
|
+
if pkgs
|
531
|
+
return pkgs.sort.reverse
|
532
|
+
else
|
533
|
+
return nil
|
55
534
|
end
|
56
535
|
end
|
57
536
|
|
58
|
-
def
|
59
|
-
@
|
60
|
-
|
537
|
+
def lookup_provides(provide_name)
|
538
|
+
@provides[provide_name]
|
539
|
+
end
|
540
|
+
|
541
|
+
# Using the package name as a key, and nevra for an index, keep a unique list of packages.
|
542
|
+
# The available/installed state can be overwritten for existing packages.
|
543
|
+
def push(*args)
|
544
|
+
args.flatten.each do |new_rpm|
|
545
|
+
unless new_rpm.kind_of?(RPMDbPackage)
|
546
|
+
raise ArgumentError, "Expecting an RPMDbPackage object"
|
547
|
+
end
|
61
548
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
549
|
+
@rpms[new_rpm.n] ||= Array.new
|
550
|
+
|
551
|
+
# we may already have this one, like when the installed list is refreshed
|
552
|
+
idx = @index[new_rpm.nevra]
|
553
|
+
if idx
|
554
|
+
# grab the existing package if it's not
|
555
|
+
curr_rpm = idx
|
556
|
+
else
|
557
|
+
@rpms[new_rpm.n] << new_rpm
|
558
|
+
|
559
|
+
new_rpm.provides.each do |provide|
|
560
|
+
@provides[provide.name] ||= Array.new
|
561
|
+
@provides[provide.name] << new_rpm
|
73
562
|
end
|
74
|
-
|
75
|
-
|
563
|
+
|
564
|
+
curr_rpm = new_rpm
|
76
565
|
end
|
77
|
-
|
78
|
-
error = stderr.readlines
|
79
|
-
end
|
80
566
|
|
81
|
-
|
82
|
-
|
567
|
+
# Track the nevra -> RPMPackage association to avoid having to compare versions
|
568
|
+
# with @rpms[new_rpm.n] on the next round
|
569
|
+
@index[new_rpm.nevra] = curr_rpm
|
570
|
+
|
571
|
+
# these are overwritten for existing packages
|
572
|
+
if new_rpm.available
|
573
|
+
@available << curr_rpm
|
574
|
+
end
|
575
|
+
if new_rpm.installed
|
576
|
+
@installed << curr_rpm
|
577
|
+
end
|
83
578
|
end
|
579
|
+
end
|
84
580
|
|
85
|
-
|
581
|
+
def <<(*args)
|
582
|
+
self.push(args)
|
86
583
|
end
|
87
|
-
alias :reload :load_data
|
88
584
|
|
89
|
-
def
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
585
|
+
def clear
|
586
|
+
@rpms.clear
|
587
|
+
@index.clear
|
588
|
+
@provides.clear
|
589
|
+
clear_available
|
590
|
+
clear_installed
|
591
|
+
end
|
592
|
+
|
593
|
+
def clear_available
|
594
|
+
@available.clear
|
595
|
+
end
|
596
|
+
|
597
|
+
def clear_installed
|
598
|
+
@installed.clear
|
599
|
+
end
|
600
|
+
|
601
|
+
def size
|
602
|
+
@rpms.size
|
603
|
+
end
|
604
|
+
alias :length :size
|
605
|
+
|
606
|
+
def available_size
|
607
|
+
@available.size
|
608
|
+
end
|
609
|
+
|
610
|
+
def installed_size
|
611
|
+
@installed.size
|
612
|
+
end
|
613
|
+
|
614
|
+
def available?(package)
|
615
|
+
@available.include?(package)
|
616
|
+
end
|
617
|
+
|
618
|
+
def installed?(package)
|
619
|
+
@installed.include?(package)
|
620
|
+
end
|
621
|
+
|
622
|
+
def whatprovides(rpmdep)
|
623
|
+
unless rpmdep.kind_of?(RPMDependency)
|
624
|
+
raise ArgumentError, "Expecting an RPMDependency object"
|
625
|
+
end
|
626
|
+
|
627
|
+
what = []
|
628
|
+
|
629
|
+
packages = lookup_provides(rpmdep.name)
|
630
|
+
if packages
|
631
|
+
packages.each do |pkg|
|
632
|
+
pkg.provides.each do |provide|
|
633
|
+
if provide.satisfy?(rpmdep)
|
634
|
+
what << pkg
|
95
635
|
end
|
96
|
-
else
|
97
|
-
# no arch specified - take the first match
|
98
|
-
z = y.to_a[0][1]
|
99
|
-
return "#{z[:version]}-#{z[:release]}"
|
100
636
|
end
|
101
637
|
end
|
102
638
|
end
|
103
639
|
|
104
|
-
|
640
|
+
return what
|
105
641
|
end
|
642
|
+
end
|
106
643
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
644
|
+
# Cache for our installed and available packages, pulled in from yum-dump.py
|
645
|
+
class YumCache
|
646
|
+
include Chef::Mixin::Command
|
647
|
+
include Singleton
|
648
|
+
|
649
|
+
def initialize
|
650
|
+
@rpmdb = RPMDb.new
|
651
|
+
|
652
|
+
# Next time @rpmdb is accessed:
|
653
|
+
# :all - Trigger a run of "yum-dump.py --options --installed-provides", updates
|
654
|
+
# yum's cache and parses options from /etc/yum.conf. Pulls in Provides
|
655
|
+
# dependency data for installed packages only - this data is slow to
|
656
|
+
# gather.
|
657
|
+
# :provides - Same as :all but pulls in Provides data for available packages as well.
|
658
|
+
# Used as a last resort when we can't find a Provides match.
|
659
|
+
# :installed - Trigger a run of "yum-dump.py --installed", only reads the local rpm
|
660
|
+
# db. Used between client runs for a quick refresh.
|
661
|
+
# :none - Do nothing, a call to one of the reload methods is required.
|
662
|
+
@next_refresh = :all
|
663
|
+
|
664
|
+
@allow_multi_install = []
|
665
|
+
|
666
|
+
# these are for subsequent runs if we are on an interval
|
667
|
+
Chef::Client.when_run_starts do
|
668
|
+
YumCache.instance.reload
|
669
|
+
end
|
670
|
+
end
|
671
|
+
|
672
|
+
# Cache management
|
673
|
+
#
|
116
674
|
|
117
|
-
|
118
|
-
|
119
|
-
|
675
|
+
def refresh
|
676
|
+
case @next_refresh
|
677
|
+
when :none
|
678
|
+
return nil
|
679
|
+
when :installed
|
680
|
+
reset_installed
|
681
|
+
# fast
|
682
|
+
opts=" --installed"
|
683
|
+
when :all
|
684
|
+
reset
|
685
|
+
# medium
|
686
|
+
opts=" --options --installed-provides"
|
687
|
+
when :provides
|
688
|
+
reset
|
689
|
+
# slow!
|
690
|
+
opts=" --options --all-provides"
|
691
|
+
else
|
692
|
+
raise ArgumentError, "Unexpected value in next_refresh: #{@next_refresh}"
|
693
|
+
end
|
694
|
+
|
695
|
+
one_line = false
|
696
|
+
error = nil
|
697
|
+
|
698
|
+
helper = ::File.join(::File.dirname(__FILE__), 'yum-dump.py')
|
699
|
+
|
700
|
+
status = popen4("/usr/bin/python #{helper}#{opts}", :waitlast => true) do |pid, stdin, stdout, stderr|
|
701
|
+
stdout.each do |line|
|
702
|
+
one_line = true
|
703
|
+
|
704
|
+
line.chomp!
|
705
|
+
|
706
|
+
if line =~ %r{\[option (.*)\] (.*)}
|
707
|
+
if $1 == "installonlypkgs"
|
708
|
+
@allow_multi_install = $2.split
|
120
709
|
else
|
121
|
-
|
710
|
+
raise Chef::Exceptions::Package, "Strange, unknown option line '#{line}' from yum-dump.py"
|
122
711
|
end
|
712
|
+
next
|
713
|
+
end
|
123
714
|
|
124
|
-
|
715
|
+
if line =~ %r{^(\S+) ([0-9]+) (\S+) (\S+) (\S+) \[(.*)\] ([i,a,r])$}
|
716
|
+
name = $1
|
717
|
+
epoch = $2
|
718
|
+
version = $3
|
719
|
+
release = $4
|
720
|
+
arch = $5
|
721
|
+
provides = parse_provides($6)
|
722
|
+
type = $7
|
723
|
+
else
|
724
|
+
Chef::Log.warn("Problem parsing line '#{line}' from yum-dump.py! " +
|
725
|
+
"Please check your yum configuration.")
|
726
|
+
next
|
125
727
|
end
|
126
728
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
729
|
+
case type
|
730
|
+
when "i"
|
731
|
+
# if yum-dump was called with --installed this may not be true, but it's okay
|
732
|
+
# since we don't touch the @available Set in reload_installed
|
733
|
+
available = false
|
734
|
+
installed = true
|
735
|
+
when "a"
|
736
|
+
available = true
|
737
|
+
installed = false
|
738
|
+
when "r"
|
739
|
+
available = true
|
740
|
+
installed = true
|
133
741
|
end
|
742
|
+
|
743
|
+
pkg = RPMDbPackage.new(name, epoch, version, release, arch, provides, installed, available)
|
744
|
+
@rpmdb << pkg
|
134
745
|
end
|
746
|
+
|
747
|
+
error = stderr.readlines
|
135
748
|
end
|
136
749
|
|
137
|
-
|
750
|
+
if status.exitstatus != 0
|
751
|
+
raise Chef::Exceptions::Package, "Yum failed - #{status.inspect} - returns: #{error}"
|
752
|
+
else
|
753
|
+
unless one_line
|
754
|
+
Chef::Log.warn("Odd, no output from yum-dump.py. Please check " +
|
755
|
+
"your yum configuration.")
|
756
|
+
end
|
757
|
+
end
|
758
|
+
|
759
|
+
# A reload method must be called before the cache is altered
|
760
|
+
@next_refresh = :none
|
138
761
|
end
|
139
762
|
|
140
|
-
def
|
141
|
-
|
763
|
+
def reload
|
764
|
+
@next_refresh = :all
|
142
765
|
end
|
143
766
|
|
144
|
-
def
|
145
|
-
|
767
|
+
def reload_installed
|
768
|
+
@next_refresh = :installed
|
146
769
|
end
|
147
770
|
|
148
|
-
def
|
149
|
-
@
|
771
|
+
def reload_provides
|
772
|
+
@next_refresh = :provides
|
773
|
+
end
|
774
|
+
|
775
|
+
def reset
|
776
|
+
@rpmdb.clear
|
777
|
+
end
|
778
|
+
|
779
|
+
def reset_installed
|
780
|
+
@rpmdb.clear_installed
|
781
|
+
end
|
782
|
+
|
783
|
+
# Querying the cache
|
784
|
+
#
|
785
|
+
|
786
|
+
def package_available?(package_name)
|
787
|
+
refresh
|
788
|
+
if @rpmdb.lookup(package_name)
|
789
|
+
true
|
790
|
+
else
|
791
|
+
false
|
792
|
+
end
|
793
|
+
end
|
794
|
+
|
795
|
+
# Returns a array of packages satisfying an RPMDependency
|
796
|
+
def packages_from_require(rpmdep)
|
797
|
+
refresh
|
798
|
+
@rpmdb.whatprovides(rpmdep)
|
799
|
+
end
|
800
|
+
|
801
|
+
def version_available?(package_name, desired_version, arch=nil)
|
802
|
+
version(package_name, arch, true, false) do |v|
|
803
|
+
return true if desired_version == v
|
804
|
+
end
|
805
|
+
|
806
|
+
return false
|
807
|
+
end
|
808
|
+
|
809
|
+
def available_version(package_name, arch=nil)
|
810
|
+
version(package_name, arch, true, false)
|
811
|
+
end
|
812
|
+
alias :candidate_version :available_version
|
813
|
+
|
814
|
+
def installed_version(package_name, arch=nil)
|
815
|
+
version(package_name, arch, false, true)
|
150
816
|
end
|
151
|
-
|
817
|
+
|
818
|
+
def allow_multi_install
|
819
|
+
refresh
|
820
|
+
@allow_multi_install
|
821
|
+
end
|
822
|
+
|
823
|
+
private
|
824
|
+
def version(package_name, arch=nil, is_available=false, is_installed=false)
|
825
|
+
refresh
|
826
|
+
packages = @rpmdb[package_name]
|
827
|
+
if packages
|
828
|
+
packages.each do |pkg|
|
829
|
+
if is_available
|
830
|
+
next unless @rpmdb.available?(pkg)
|
831
|
+
end
|
832
|
+
if is_installed
|
833
|
+
next unless @rpmdb.installed?(pkg)
|
834
|
+
end
|
835
|
+
if arch
|
836
|
+
next unless pkg.arch == arch
|
837
|
+
end
|
838
|
+
|
839
|
+
if block_given?
|
840
|
+
yield pkg.version.to_s
|
841
|
+
else
|
842
|
+
# first match is latest version
|
843
|
+
return pkg.version.to_s
|
844
|
+
end
|
845
|
+
end
|
846
|
+
end
|
847
|
+
|
848
|
+
if block_given?
|
849
|
+
return self
|
850
|
+
else
|
851
|
+
return nil
|
852
|
+
end
|
853
|
+
end
|
854
|
+
|
855
|
+
# Parse provides from yum-dump.py output
|
856
|
+
def parse_provides(string)
|
857
|
+
ret = []
|
858
|
+
# ['atk = 1.12.2-1.fc6', 'libatk-1.0.so.0']
|
859
|
+
string.split(", ").each do |seg|
|
860
|
+
# 'atk = 1.12.2-1.fc6'
|
861
|
+
if seg =~ %r{^'(.*)'$}
|
862
|
+
ret << RPMProvide.parse($1)
|
863
|
+
end
|
864
|
+
end
|
865
|
+
|
866
|
+
return ret
|
867
|
+
end
|
868
|
+
|
869
|
+
end # YumCache
|
870
|
+
|
871
|
+
include Chef::Mixin::GetSourceFromPackage
|
152
872
|
|
153
873
|
def initialize(new_resource, run_context)
|
154
874
|
super
|
875
|
+
|
155
876
|
@yum = YumCache.instance
|
156
877
|
end
|
157
878
|
|
879
|
+
# Extra attributes
|
880
|
+
#
|
881
|
+
|
158
882
|
def arch
|
159
883
|
if @new_resource.respond_to?("arch")
|
160
|
-
@new_resource.arch
|
884
|
+
@new_resource.arch
|
161
885
|
else
|
162
886
|
nil
|
163
887
|
end
|
164
888
|
end
|
165
889
|
|
890
|
+
def flush_cache
|
891
|
+
if @new_resource.respond_to?("flush_cache")
|
892
|
+
@new_resource.flush_cache
|
893
|
+
else
|
894
|
+
{ :before => false, :after => false }
|
895
|
+
end
|
896
|
+
end
|
897
|
+
|
898
|
+
def allow_downgrade
|
899
|
+
if @new_resource.respond_to?("allow_downgrade")
|
900
|
+
@new_resource.allow_downgrade
|
901
|
+
else
|
902
|
+
false
|
903
|
+
end
|
904
|
+
end
|
905
|
+
|
906
|
+
# Helpers
|
907
|
+
#
|
908
|
+
|
166
909
|
def yum_arch
|
167
910
|
arch ? ".#{arch}" : nil
|
168
911
|
end
|
169
912
|
|
913
|
+
# Standard Provider methods for Parent
|
914
|
+
#
|
915
|
+
|
170
916
|
def load_current_resource
|
917
|
+
if flush_cache[:before]
|
918
|
+
@yum.reload
|
919
|
+
end
|
920
|
+
|
921
|
+
unless @yum.package_available?(@new_resource.package_name)
|
922
|
+
parse_dependency
|
923
|
+
end
|
924
|
+
|
925
|
+
# Don't overwrite an existing arch
|
926
|
+
unless arch
|
927
|
+
parse_arch
|
928
|
+
end
|
929
|
+
|
171
930
|
@current_resource = Chef::Resource::Package.new(@new_resource.name)
|
172
931
|
@current_resource.package_name(@new_resource.package_name)
|
173
932
|
|
@@ -188,73 +947,181 @@ class Chef
|
|
188
947
|
end
|
189
948
|
end
|
190
949
|
|
191
|
-
|
950
|
+
if @new_resource.version
|
951
|
+
new_resource = "#{@new_resource.package_name}-#{@new_resource.version}#{yum_arch}"
|
952
|
+
else
|
953
|
+
new_resource = "#{@new_resource.package_name}#{yum_arch}"
|
954
|
+
end
|
192
955
|
|
193
|
-
@yum
|
956
|
+
Chef::Log.debug("#{@new_resource} checking yum info for #{new_resource}")
|
194
957
|
|
195
958
|
installed_version = @yum.installed_version(@new_resource.package_name, arch)
|
959
|
+
@current_resource.version(installed_version)
|
960
|
+
|
196
961
|
@candidate_version = @yum.candidate_version(@new_resource.package_name, arch)
|
197
962
|
|
198
|
-
@
|
199
|
-
|
200
|
-
@candidate_version = candidate_version
|
201
|
-
else
|
202
|
-
@candidate_version = installed_version
|
203
|
-
end
|
204
|
-
Chef::Log.debug("#{@new_resource} installed version: #{installed_version} candidate version: #{candidate_version}")
|
963
|
+
Chef::Log.debug("#{@new_resource} installed version: #{installed_version || "(none)"} candidate version: " +
|
964
|
+
"#{@candidate_version || "(none)"}")
|
205
965
|
|
206
966
|
@current_resource
|
207
967
|
end
|
208
968
|
|
209
969
|
def install_package(name, version)
|
210
|
-
if @new_resource.source
|
970
|
+
if @new_resource.source
|
211
971
|
run_command_with_systems_locale(
|
212
|
-
:command => "yum -d0 -e0 -y
|
972
|
+
:command => "yum -d0 -e0 -y#{expand_options(@new_resource.options)} localinstall #{@new_resource.source}"
|
213
973
|
)
|
214
974
|
else
|
215
975
|
# Work around yum not exiting with an error if a package doesn't exist for CHEF-2062
|
216
|
-
if @yum.version_available?(name, version,
|
976
|
+
if @yum.version_available?(name, version, arch)
|
977
|
+
method = "install"
|
978
|
+
|
979
|
+
# More Yum fun:
|
980
|
+
#
|
981
|
+
# yum install of an old name+version will exit(1)
|
982
|
+
# yum install of an old name+version+arch will exit(0) for some reason
|
983
|
+
#
|
984
|
+
# Some packages can be installed multiple times like the kernel
|
985
|
+
unless @yum.allow_multi_install.include?(name)
|
986
|
+
if RPMVersion.parse(@current_resource.version) > RPMVersion.parse(version)
|
987
|
+
# Unless they want this...
|
988
|
+
if allow_downgrade
|
989
|
+
method = "downgrade"
|
990
|
+
else
|
991
|
+
# we bail like yum when the package is older
|
992
|
+
raise Chef::Exceptions::Package, "Installed package #{name}-#{@current_resource.version} is newer " +
|
993
|
+
"than candidate package #{name}-#{version}"
|
994
|
+
end
|
995
|
+
end
|
996
|
+
end
|
997
|
+
|
217
998
|
run_command_with_systems_locale(
|
218
|
-
:command => "yum -d0 -e0 -y
|
999
|
+
:command => "yum -d0 -e0 -y#{expand_options(@new_resource.options)} #{method} #{name}-#{version}#{yum_arch}"
|
219
1000
|
)
|
220
1001
|
else
|
221
|
-
raise
|
1002
|
+
raise Chef::Exceptions::Package, "Version #{version} of #{name} not found. Did you specify both version " +
|
1003
|
+
"and release? (version-release, e.g. 1.84-10.fc6)"
|
222
1004
|
end
|
223
1005
|
end
|
224
|
-
|
1006
|
+
if flush_cache[:after]
|
1007
|
+
@yum.reload
|
1008
|
+
else
|
1009
|
+
@yum.reload_installed
|
1010
|
+
end
|
225
1011
|
end
|
226
1012
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
1013
|
+
# Keep upgrades from trying to install an older candidate version. Can happen when a new
|
1014
|
+
# version is installed then removed from a repository, now the older available version
|
1015
|
+
# shows up as a viable install candidate.
|
1016
|
+
#
|
1017
|
+
# Can be done in upgrade_package but an upgraded from->to log message slips out
|
1018
|
+
#
|
1019
|
+
# Hacky - better overall solution? Custom compare in Package provider?
|
1020
|
+
def action_upgrade
|
1021
|
+
# Ensure the candidate is newer
|
1022
|
+
if RPMVersion.parse(candidate_version) > RPMVersion.parse(@current_resource.version)
|
1023
|
+
super
|
1024
|
+
# Candidate is older
|
235
1025
|
else
|
236
|
-
|
1026
|
+
Chef::Log.debug("#{@new_resource} is at the latest version - nothing to do")
|
237
1027
|
end
|
238
1028
|
end
|
239
1029
|
|
1030
|
+
def upgrade_package(name, version)
|
1031
|
+
install_package(name, version)
|
1032
|
+
end
|
1033
|
+
|
240
1034
|
def remove_package(name, version)
|
241
1035
|
if version
|
242
1036
|
run_command_with_systems_locale(
|
243
|
-
:command => "yum -d0 -e0 -y
|
1037
|
+
:command => "yum -d0 -e0 -y#{expand_options(@new_resource.options)} remove #{name}-#{version}#{yum_arch}"
|
244
1038
|
)
|
245
1039
|
else
|
246
1040
|
run_command_with_systems_locale(
|
247
|
-
:command => "yum -d0 -e0 -y
|
1041
|
+
:command => "yum -d0 -e0 -y#{expand_options(@new_resource.options)} remove #{name}#{yum_arch}"
|
248
1042
|
)
|
249
1043
|
end
|
250
|
-
|
251
|
-
|
1044
|
+
if flush_cache[:after]
|
1045
|
+
@yum.reload
|
1046
|
+
else
|
1047
|
+
@yum.reload_installed
|
1048
|
+
end
|
252
1049
|
end
|
253
1050
|
|
254
1051
|
def purge_package(name, version)
|
255
1052
|
remove_package(name, version)
|
256
1053
|
end
|
257
1054
|
|
1055
|
+
private
|
1056
|
+
|
1057
|
+
def parse_arch
|
1058
|
+
# Allow for foo.x86_64 style package_name like yum uses in it's output
|
1059
|
+
#
|
1060
|
+
if @new_resource.package_name =~ %r{^(.*)\.(.*)$}
|
1061
|
+
new_package_name = $1
|
1062
|
+
new_arch = $2
|
1063
|
+
# foo.i386 and foo.beta1 are both valid package names or expressions of an arch.
|
1064
|
+
# Ensure we don't have an existing package matching package_name, then ensure we at
|
1065
|
+
# least have a match for the new_package+new_arch before we overwrite. If neither
|
1066
|
+
# then fall through to standard package handling.
|
1067
|
+
if (@yum.installed_version(@new_resource.package_name).nil? and @yum.candidate_version(@new_resource.package_name).nil?) and
|
1068
|
+
(@yum.installed_version(new_package_name, new_arch) or @yum.candidate_version(new_package_name, new_arch))
|
1069
|
+
@new_resource.package_name(new_package_name)
|
1070
|
+
@new_resource.arch(new_arch)
|
1071
|
+
end
|
1072
|
+
end
|
1073
|
+
end
|
1074
|
+
|
1075
|
+
# If we don't have the package we could have been passed a 'whatprovides' feature
|
1076
|
+
#
|
1077
|
+
# eg: yum install "perl(Config)"
|
1078
|
+
# yum install "mtr = 2:0.71-3.1"
|
1079
|
+
# yum install "mtr > 2:0.71"
|
1080
|
+
#
|
1081
|
+
# We support resolving these out of the Provides data imported from yum-dump.py and
|
1082
|
+
# matching them up with an actual package so the standard resource handling can apply.
|
1083
|
+
#
|
1084
|
+
# There is currently no support for filename matching.
|
1085
|
+
def parse_dependency
|
1086
|
+
# Transform the package_name into a requirement
|
1087
|
+
yum_require = RPMRequire.parse(@new_resource.package_name)
|
1088
|
+
# and gather all the packages that have a Provides feature satisfying the requirement.
|
1089
|
+
# It could be multiple be we can only manage one
|
1090
|
+
packages = @yum.packages_from_require(yum_require)
|
1091
|
+
|
1092
|
+
if packages.empty?
|
1093
|
+
# Don't bother if we are just ensuring a package is removed - we don't need Provides data
|
1094
|
+
actions = Array(@new_resource.action)
|
1095
|
+
unless actions.size == 1 and (actions[0] == :remove || actions[0] == :purge)
|
1096
|
+
Chef::Log.debug("#{@new_resource} couldn't match #{@new_resource.package_name} in " +
|
1097
|
+
"installed Provides, loading available Provides - this may take a moment")
|
1098
|
+
@yum.reload_provides
|
1099
|
+
packages = @yum.packages_from_require(yum_require)
|
1100
|
+
end
|
1101
|
+
end
|
1102
|
+
|
1103
|
+
unless packages.empty?
|
1104
|
+
new_package_name = packages.first.name
|
1105
|
+
Chef::Log.debug("#{@new_resource} no package found for #{@new_resource.package_name} " +
|
1106
|
+
"but matched Provides for #{new_package_name}")
|
1107
|
+
|
1108
|
+
# Ensure it's not the same package under a different architecture
|
1109
|
+
unique_names = []
|
1110
|
+
packages.each do |pkg|
|
1111
|
+
unique_names << "#{pkg.name}-#{pkg.version.evr}"
|
1112
|
+
end
|
1113
|
+
unique_names.uniq!
|
1114
|
+
|
1115
|
+
if unique_names.size > 1
|
1116
|
+
Chef::Log.warn("#{@new_resource} matched multiple Provides for #{@new_resource.package_name} " +
|
1117
|
+
"but we can only use the first match: #{new_package_name}. Please use a more " +
|
1118
|
+
"specific version.")
|
1119
|
+
end
|
1120
|
+
|
1121
|
+
@new_resource.package_name(new_package_name)
|
1122
|
+
end
|
1123
|
+
end
|
1124
|
+
|
258
1125
|
end
|
259
1126
|
end
|
260
1127
|
end
|