chef 13.5.3 → 13.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/bin/chef-shell +2 -0
  4. data/distro/powershell/chef/chef.psm1 +23 -2
  5. data/lib/chef/application/client.rb +1 -1
  6. data/lib/chef/chef_fs/config.rb +1 -1
  7. data/lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb +5 -0
  8. data/lib/chef/client.rb +3 -0
  9. data/lib/chef/cookbook/synchronizer.rb +2 -4
  10. data/lib/chef/data_bag.rb +4 -0
  11. data/lib/chef/deprecated.rb +10 -0
  12. data/lib/chef/knife/client_delete.rb +1 -1
  13. data/lib/chef/knife/node_delete.rb +1 -1
  14. data/lib/chef/knife/node_run_list_add.rb +1 -1
  15. data/lib/chef/knife/node_run_list_remove.rb +1 -1
  16. data/lib/chef/knife/role_env_run_list_add.rb +1 -1
  17. data/lib/chef/knife/role_run_list_add.rb +1 -1
  18. data/lib/chef/mixin/user_context.rb +1 -1
  19. data/lib/chef/platform/rebooter.rb +7 -3
  20. data/lib/chef/provider/dsc_script.rb +5 -1
  21. data/lib/chef/provider/package.rb +35 -4
  22. data/lib/chef/provider/package/apt.rb +7 -0
  23. data/lib/chef/provider/package/chocolatey.rb +24 -8
  24. data/lib/chef/provider/package/dnf.rb +14 -5
  25. data/lib/chef/provider/package/dnf/dnf_helper.py +10 -0
  26. data/lib/chef/provider/package/dnf/python_helper.rb +15 -0
  27. data/lib/chef/provider/package/rpm.rb +5 -0
  28. data/lib/chef/provider/package/windows.rb +15 -0
  29. data/lib/chef/provider/package/yum.rb +4 -20
  30. data/lib/chef/provider/package/zypper.rb +5 -1
  31. data/lib/chef/provider/route.rb +1 -1
  32. data/lib/chef/provider/windows_task.rb +19 -4
  33. data/lib/chef/provider/zypper_repository.rb +100 -12
  34. data/lib/chef/resource/deploy.rb +6 -0
  35. data/lib/chef/resource/dnf_package.rb +9 -2
  36. data/lib/chef/resource/windows_task.rb +12 -7
  37. data/lib/chef/resource/zypper_package.rb +1 -0
  38. data/lib/chef/resource/zypper_repository.rb +1 -0
  39. data/lib/chef/util/dsc/lcm_output_parser.rb +57 -2
  40. data/lib/chef/util/dsc/local_configuration_manager.rb +16 -16
  41. data/lib/chef/version.rb +1 -1
  42. data/spec/functional/rebooter_spec.rb +22 -11
  43. data/spec/functional/resource/windows_task_spec.rb +25 -0
  44. data/spec/unit/chef_fs/data_handler/data_bag_item_data_handler.rb +79 -0
  45. data/spec/unit/client_spec.rb +11 -0
  46. data/spec/unit/cookbook/synchronizer_spec.rb +30 -0
  47. data/spec/unit/knife/data_bag_create_spec.rb +8 -0
  48. data/spec/unit/mixin/user_context_spec.rb +1 -2
  49. data/spec/unit/provider/package/chocolatey_spec.rb +3 -1
  50. data/spec/unit/provider/package/rubygems_spec.rb +5 -0
  51. data/spec/unit/provider/package/zypper_spec.rb +8 -0
  52. data/spec/unit/provider/remote_file/network_file_spec.rb +1 -1
  53. data/spec/unit/provider/route_spec.rb +2 -0
  54. data/spec/unit/provider/windows_task_spec.rb +28 -0
  55. data/spec/unit/provider/zypper_repository_spec.rb +124 -0
  56. data/spec/unit/provider_resolver_spec.rb +4 -1
  57. data/spec/unit/resource/windows_task_spec.rb +8 -2
  58. data/spec/unit/resource/zypper_repository_spec.rb +11 -9
  59. data/spec/unit/util/dsc/lcm_output_parser_spec.rb +102 -18
  60. data/spec/unit/util/dsc/local_configuration_manager_spec.rb +2 -1
  61. metadata +6 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bac3c67c9e66c16a65ba7d66b4ae611a1f5a444c
4
- data.tar.gz: 59ed93bbf14a7ac6decee44bb162516194704e90
3
+ metadata.gz: 061c506cbf2b89efb7f6cd0a3c34c3899fedf6e1
4
+ data.tar.gz: a5a41b7f39a7fa9bb3a0144d73ce16ebb9785051
5
5
  SHA512:
6
- metadata.gz: 4ddc48aa325b0f0c2c036a0d82d0a13fd6cabcd9a7b947bfdb1dfd442d74f966a910ed197b09babb56491f8e1bc02e01d00bf1cc1fbf7487e813ec34247f9870
7
- data.tar.gz: 6e9025a3314ae89811819c131a0c281a3e5aafbc9f8e397a3648d32e5cb2c561cc5142c1d671b7dcb6d024f1fc3ac8b2e3060264069430e34fdd26bad8aa87a2
6
+ metadata.gz: b639f26cb03a65f90db1bd19a40d9acbcffc4dba82a24aa99ea7307f82c90ec78814924eb064b377f4876cbfe79131ae6b2f77295d3112b34a5c7d4de2ee546d
7
+ data.tar.gz: e0d4542426510bb753a270016498566c8111566f3304c3d20dc091217950814cdaf36f2fc1e2e9682a84ea481b8f7d02ffffa64526e5e6705fa7b21d3feb1b83
data/VERSION CHANGED
@@ -1 +1 @@
1
- 13.5.3
1
+ 13.6.0
@@ -23,6 +23,8 @@ begin
23
23
  rescue LoadError
24
24
  end
25
25
 
26
+ Encoding.default_external = Encoding::UTF_8
27
+
26
28
  require "irb"
27
29
  require "irb/completion"
28
30
  require "irb/ext/save-history"
@@ -282,6 +282,24 @@ function Run-ExecutableAndWait($AppPath, $ArgumentString) {
282
282
  break
283
283
  }
284
284
  }
285
+ } else {
286
+ # For some reason, you can't read from the read-end of the read-pipe before the write end has started
287
+ # to write. Otherwise the process just blocks forever and never returns from the read. So we peek
288
+ # at the pipe until there is something. But don't peek too eagerly. This is stupid stupid stupid.
289
+ # There must be a way to do this without having to peek at a pipe first but I have not found it.
290
+ #
291
+ # Note to the future intrepid soul who wants to fix this:
292
+ # 0) This is related to unreasonable CPU usage by the wrapper PS script on a 1 VCPU VM (either Hyper-V
293
+ # or VirtualBox) running a consumer Windows SKU (Windows 10 for example...). Test it there.
294
+ # 1) Maybe this entire script is unnecessary and the bugs mentioned below have been fixed or don't need
295
+ # to be supported.
296
+ # 2) The server and consumer windows schedulers have different defaults. I had a hard time reproducing
297
+ # any issue on a win 2008 on win 2012 server default setup. See the "foreground application scheduler
298
+ # priority" setting to see if it's relevant.
299
+ # 3) This entire endeavor is silly anyway - why are we reimplementing process forking all over? Maybe try
300
+ # to get the folks above to accept patches instead of extending this crazy script.
301
+ Start-Sleep -s 1
302
+ # Start-Sleep -m 100
285
303
  }
286
304
 
287
305
  if ($global:LASTEXITCODE -ne [Chef.Kernel32]::STILL_ACTIVE) {
@@ -434,9 +452,12 @@ Export-ModuleMember -function chef-solo
434
452
  Export-ModuleMember -function chef-windows-service
435
453
  Export-ModuleMember -function knife
436
454
 
437
- # To debug this module, uncomment the line below and then run the following.
455
+ # To debug this module, uncomment the line below
438
456
  # Export-ModuleMember -function Run-RubyCommand
457
+
458
+ # Then run the following to reload the module. Use puts_argv as a helpful debug executable.
439
459
  # Remove-Module chef
440
460
  # Import-Module chef
441
- # "puts ARGV" | Out-File C:\opscode\chef\bin\puts_args
461
+ # "puts ARGV" | Out-File C:\opscode\chef\bin\puts_args -Encoding ASCII
462
+ # Copy-Item C:\opscode\chef\bin\ohai.bat C:\opscode\chef\bin\puts_args.bat
442
463
  # Run-RubyCommand puts_args 'Here' "are" some '"very interesting"' 'arguments[to]' "`"try out`""
@@ -501,7 +501,7 @@ class Chef::Application::Client < Chef::Application
501
501
  # we need to sleep again after reconfigure to avoid stampeding when logrotate runs out of cron
502
502
  if signal == RECONFIGURE_SIGNAL
503
503
  reconfigure
504
- interval_sleep(sleep)
504
+ interval_sleep(sec)
505
505
  end
506
506
  else
507
507
  sleep(sec)
@@ -66,7 +66,7 @@ class Chef
66
66
  # upgrade/migration of older Chef Servers, so they should be considered
67
67
  # frozen in time.
68
68
 
69
- CHEF_11_OSS_STATIC_OBJECTS = %w{cookbooks cookbook_artifacts data_bags environments roles}.freeze
69
+ CHEF_11_OSS_STATIC_OBJECTS = %w{cookbooks data_bags environments roles}.freeze
70
70
  CHEF_11_OSS_DYNAMIC_OBJECTS = %w{clients nodes users}.freeze
71
71
  RBAC_OBJECT_NAMES = %w{acls containers groups }.freeze
72
72
  CHEF_12_OBJECTS = %w{ cookbook_artifacts policies policy_groups client_keys }.freeze
@@ -5,6 +5,8 @@ class Chef
5
5
  module ChefFS
6
6
  module DataHandler
7
7
  class DataBagItemDataHandler < DataHandlerBase
8
+ RESERVED_NAMES = /node|role|environment|client/
9
+
8
10
  def normalize(data_bag_item, entry)
9
11
  # If it's wrapped with raw_data, unwrap it.
10
12
  if data_bag_item["json_class"] == "Chef::DataBagItem" && data_bag_item["raw_data"]
@@ -43,6 +45,7 @@ class Chef
43
45
  end
44
46
 
45
47
  # Verify that the JSON hash for this type has a key that matches its name.
48
+ # Also check that the data bag name is not a reserved search index name.
46
49
  #
47
50
  # @param object [Object] JSON hash of the object
48
51
  # @param entry [Chef::ChefFS::FileSystem::BaseFSObject] filesystem object we are verifying
@@ -52,6 +55,8 @@ class Chef
52
55
  base_name = remove_dot_json(entry.name)
53
56
  if object["raw_data"]["id"] != base_name
54
57
  yield("ID in #{entry.path_for_printing} must be '#{base_name}' (is '#{object['raw_data']['id']}')")
58
+ elsif entry.parent.name =~ RESERVED_NAMES
59
+ yield("Data bag name ('#{entry.parent.name}') must not match #{RESERVED_NAMES.inspect}")
55
60
  end
56
61
  end
57
62
 
@@ -605,6 +605,9 @@ class Chef
605
605
  filter = Chef::Config[:minimal_ohai] ? %w{fqdn machinename hostname platform platform_version os os_version} : nil
606
606
  ohai.all_plugins(filter)
607
607
  events.ohai_completed(node)
608
+ rescue Ohai::Exceptions::CriticalPluginFailure => e
609
+ Chef::Log.error("Critical Ohai plugins failed: #{e.message}")
610
+ exit(false)
608
611
  end
609
612
 
610
613
  #
@@ -154,6 +154,7 @@ class Chef
154
154
 
155
155
  queue = Chef::Util::ThreadedJobQueue.new
156
156
 
157
+ Chef::Log.warn("skipping cookbook synchronization! DO NOT LEAVE THIS ENABLED IN PRODUCTION!!!") if Chef::Config[:skip_cookbook_sync]
157
158
  files.each do |file|
158
159
  queue << lambda do |lock|
159
160
  full_file_path = sync_file(file)
@@ -279,10 +280,7 @@ class Chef
279
280
  end
280
281
 
281
282
  def cached_copy_up_to_date?(local_path, expected_checksum)
282
- if Chef::Config[:skip_cookbook_sync]
283
- Chef::Log.warn "skipping cookbook synchronization! DO NOT LEAVE THIS ENABLED IN PRODUCTION!!!"
284
- return true
285
- end
283
+ return true if Chef::Config[:skip_cookbook_sync]
286
284
  if cache.has_key?(local_path)
287
285
  current_checksum = CookbookVersion.checksum_cookbook_file(cache.load(local_path, false))
288
286
  expected_checksum == current_checksum
@@ -33,6 +33,7 @@ class Chef
33
33
  include Chef::Mixin::ParamsValidate
34
34
 
35
35
  VALID_NAME = /^[\.\-[:alnum:]_]+$/
36
+ RESERVED_NAMES = /node|role|environment|client/
36
37
 
37
38
  attr_accessor :chef_server_rest
38
39
 
@@ -40,6 +41,9 @@ class Chef
40
41
  unless name =~ VALID_NAME
41
42
  raise Exceptions::InvalidDataBagName, "DataBags must have a name matching #{VALID_NAME.inspect}, you gave #{name.inspect}"
42
43
  end
44
+ if name =~ RESERVED_NAMES
45
+ raise Exceptions::InvalidDataBagName, "DataBags may not have a name matching #{RESERVED_NAMES.inspect}, you gave #{name.inspect}"
46
+ end
43
47
  end
44
48
 
45
49
  # Create a new Chef::DataBag
@@ -258,6 +258,16 @@ class Chef
258
258
  end
259
259
  end
260
260
 
261
+ class DeployResource < Base
262
+ def id
263
+ 21
264
+ end
265
+
266
+ def target
267
+ "deploy_resource.html"
268
+ end
269
+ end
270
+
261
271
  # id 3694 was deleted
262
272
 
263
273
  class Generic < Base
@@ -32,7 +32,7 @@ class Chef
32
32
  :long => "--delete-validators",
33
33
  :description => "Force deletion of client if it's a validator"
34
34
 
35
- banner "knife client delete [CLIENT[,CLIENT]] (options)"
35
+ banner "knife client delete [CLIENT [CLIENT]] (options)"
36
36
 
37
37
  def run
38
38
  if @name_args.length == 0
@@ -27,7 +27,7 @@ class Chef
27
27
  require "chef/json_compat"
28
28
  end
29
29
 
30
- banner "knife node delete [NODE[,NODE]] (options)"
30
+ banner "knife node delete [NODE [NODE]] (options)"
31
31
 
32
32
  def run
33
33
  if @name_args.length == 0
@@ -27,7 +27,7 @@ class Chef
27
27
  require "chef/json_compat"
28
28
  end
29
29
 
30
- banner "knife node run_list add [NODE] [ENTRY[,ENTRY]] (options)"
30
+ banner "knife node run_list add [NODE] [ENTRY [ENTRY]] (options)"
31
31
 
32
32
  option :after,
33
33
  :short => "-a ITEM",
@@ -27,7 +27,7 @@ class Chef
27
27
  require "chef/json_compat"
28
28
  end
29
29
 
30
- banner "knife node run_list remove [NODE] [ENTRY[,ENTRY]] (options)"
30
+ banner "knife node run_list remove [NODE] [ENTRY [ENTRY]] (options)"
31
31
 
32
32
  def run
33
33
  node = Chef::Node.load(@name_args[0])
@@ -27,7 +27,7 @@ class Chef
27
27
  require "chef/json_compat"
28
28
  end
29
29
 
30
- banner "knife role env_run_list add [ROLE] [ENVIRONMENT] [ENTRY[,ENTRY]] (options)"
30
+ banner "knife role env_run_list add [ROLE] [ENVIRONMENT] [ENTRY [ENTRY]] (options)"
31
31
 
32
32
  option :after,
33
33
  :short => "-a ITEM",
@@ -27,7 +27,7 @@ class Chef
27
27
  require "chef/json_compat"
28
28
  end
29
29
 
30
- banner "knife role run_list add [ROLE] [ENTRY[,ENTRY]] (options)"
30
+ banner "knife role run_list add [ROLE] [ENTRY [ENTRY]] (options)"
31
31
 
32
32
  option :after,
33
33
  :short => "-a ITEM",
@@ -23,7 +23,7 @@ class Chef
23
23
  module UserContext
24
24
 
25
25
  def with_user_context(user, password, domain = nil, &block)
26
- if node["platform_family"] != "windows"
26
+ unless Chef::Platform.windows?
27
27
  raise Exceptions::UnsupportedPlatform, "User context impersonation is supported only on the Windows platform"
28
28
  end
29
29
 
@@ -33,14 +33,18 @@ class Chef
33
33
  def reboot!(node)
34
34
  reboot_info = node.run_context.reboot_info
35
35
 
36
- cmd = if Chef::Platform.windows?
36
+ cmd = case
37
+ when Chef::Platform.windows?
37
38
  # should this do /f as well? do we then need a minimum delay to let apps quit?
38
39
  # Use explicit path to shutdown.exe, to protect against https://github.com/chef/chef/issues/5594
39
40
  windows_shutdown_path = "#{ENV['SYSTEMROOT']}/System32/shutdown.exe"
40
41
  "#{windows_shutdown_path} /r /t #{reboot_info[:delay_mins] * 60} /c \"#{reboot_info[:reason]}\""
42
+ when node["os"] == "solaris2"
43
+ # SysV-flavored shutdown
44
+ "shutdown -i6 -g#{reboot_info[:delay_mins]} -y \"#{reboot_info[:reason]}\" &"
41
45
  else
42
- # probably Linux-only.
43
- "shutdown -r +#{reboot_info[:delay_mins]} \"#{reboot_info[:reason]}\""
46
+ # Linux/BSD/Mac/AIX and other systems with BSD-ish shutdown
47
+ "shutdown -r +#{reboot_info[:delay_mins]} \"#{reboot_info[:reason]}\" &"
44
48
  end
45
49
 
46
50
  msg = "Rebooting server at a recipe's request. Details: #{reboot_info.inspect}"
@@ -161,7 +161,11 @@ class Chef
161
161
  if resource.changes_state?
162
162
  # We ignore the last log message because it only contains the time it took, which looks weird
163
163
  cleaned_messages = resource.change_log[0..-2].map { |c| c.sub(/^#{Regexp.escape(resource.name)}/, "").strip }
164
- "converge DSC resource #{resource.name} by #{cleaned_messages.find_all { |c| c != '' }.join("\n")}"
164
+ unless cleaned_messages.empty?
165
+ "converge DSC resource #{resource.name} by #{cleaned_messages.find_all { |c| c != '' }.join("\n")}"
166
+ else
167
+ "converge DSC resource #{resource.name}"
168
+ end
165
169
  else
166
170
  # This is needed because a dsc script can have resources that are both converged and not
167
171
  "converge DSC resource #{resource.name} by doing nothing because it is already converged"
@@ -323,10 +323,38 @@ class Chef
323
323
  #
324
324
  # Note that most likely we need a spaceship operator on versions that subclasses can implement
325
325
  # and we should have `version_compare(v1, v2)` that returns `v1 <=> v2`.
326
+
327
+ # This method performs a strict equality check between two strings representing version numbers
326
328
  #
329
+ # This function will eventually be deprecated in favour of the below version_equals function.
330
+
327
331
  def target_version_already_installed?(current_version, target_version)
328
- return false unless current_version && target_version
329
- current_version == target_version
332
+ version_equals?(current_version, target_version)
333
+ end
334
+
335
+ # Note that most likely we need a spaceship operator on versions that subclasses can implement
336
+ # and we should have `version_compare(v1, v2)` that returns `v1 <=> v2`.
337
+
338
+ # This method performs a strict equality check between two strings representing version numbers
339
+ #
340
+ def version_equals?(v1, v2)
341
+ return false unless v1 && v2
342
+ v1 == v2
343
+ end
344
+
345
+ # This function compares two version numbers and returns 'spaceship operator' style results, ie:
346
+ # if v1 < v2 then return -1
347
+ # if v1 = v2 then return 0
348
+ # if v1 > v2 then return 1
349
+ # if v1 and v2 are not comparable then return nil
350
+ #
351
+ # By default, this function will use Gem::Version comparison. Subclasses can reimplement this method
352
+ # for package-management system specific versions.
353
+ def version_compare(v1, v2)
354
+ gem_v1 = Gem::Version.new(v1)
355
+ gem_v2 = Gem::Version.new(v2)
356
+
357
+ gem_v1 <=> gem_v2
330
358
  end
331
359
 
332
360
  # Check the current_version against the new_resource.version, possibly using fuzzy
@@ -439,16 +467,19 @@ class Chef
439
467
  each_package do |package_name, new_version, current_version, candidate_version|
440
468
  case action
441
469
  when :upgrade
442
- if target_version_already_installed?(current_version, new_version)
470
+ if version_equals?(current_version, new_version)
443
471
  # this is an odd use case
444
472
  Chef::Log.debug("#{new_resource} #{package_name} #{new_version} is already installed -- you are equality pinning with an :upgrade action, this may be deprecated in the future")
445
473
  target_version_array.push(nil)
446
- elsif target_version_already_installed?(current_version, candidate_version)
474
+ elsif version_equals?(current_version, candidate_version)
447
475
  Chef::Log.debug("#{new_resource} #{package_name} #{candidate_version} is already installed")
448
476
  target_version_array.push(nil)
449
477
  elsif candidate_version.nil?
450
478
  Chef::Log.debug("#{new_resource} #{package_name} has no candidate_version to upgrade to")
451
479
  target_version_array.push(nil)
480
+ elsif version_compare(current_version, candidate_version) == 1 && !new_resource.allow_downgrade
481
+ Chef::Log.debug("#{new_resource} #{package_name} has installed version #{current_version}, which is newer than available version #{candidate_version}. Skipping...)")
482
+ target_version_array.push(nil)
452
483
  else
453
484
  Chef::Log.debug("#{new_resource} #{package_name} is out of date, will upgrade to #{candidate_version}")
454
485
  target_version_array.push(candidate_version)
@@ -127,6 +127,13 @@ class Chef
127
127
 
128
128
  private
129
129
 
130
+ def version_compare(v1, v2)
131
+ gem_v1 = v1.gsub(/[_+]/, "+" => "-", "_" => "-") unless v1.nil?
132
+ gem_v2 = v2.gsub(/[_+]/, "+" => "-", "_" => "-") unless v2.nil?
133
+
134
+ Gem::Version.new(gem_v1) <=> Gem::Version.new(gem_v2)
135
+ end
136
+
130
137
  # Runs command via shell_out with magic environment to disable
131
138
  # interactive prompts. Command is run with default localization rather
132
139
  # than forcing locale to "C", so command output may not be stable.
@@ -141,6 +141,17 @@ EOS
141
141
 
142
142
  private
143
143
 
144
+ def version_compare(v1, v2)
145
+ if v1 == "latest" || v2 == "latest"
146
+ return 0
147
+ end
148
+
149
+ gem_v1 = Gem::Version.new(v1)
150
+ gem_v2 = Gem::Version.new(v2)
151
+
152
+ gem_v1 <=> gem_v2
153
+ end
154
+
144
155
  # Magic to find where chocolatey is installed in the system, and to
145
156
  # return the full path of choco.exe
146
157
  #
@@ -226,15 +237,20 @@ EOS
226
237
  #
227
238
  # @return [Hash] name-to-version mapping of available packages
228
239
  def available_packages
229
- @available_packages ||=
230
- begin
231
- cmd = [ "list -r #{package_name_array.join ' '}" ]
232
- cmd.push( "-source #{new_resource.source}" ) if new_resource.source
233
- raw = parse_list_output(*cmd)
234
- raw.keys.each_with_object({}) do |name, available|
235
- available[name] = desired_name_versions[name] || raw[name]
240
+ return @available_packages if @available_packages
241
+ @available_packages = {}
242
+ package_name_array.each do |pkg|
243
+ available_versions =
244
+ begin
245
+ cmd = [ "list -r #{pkg}" ]
246
+ cmd.push( "-source #{new_resource.source}" ) if new_resource.source
247
+ raw = parse_list_output(*cmd)
248
+ raw.keys.each_with_object({}) do |name, available|
249
+ available[name] = desired_name_versions[name] || raw[name]
250
+ end
236
251
  end
237
- end
252
+ @available_packages.merge! available_versions
253
+ end
238
254
  @available_packages
239
255
  end
240
256
 
@@ -35,13 +35,18 @@ class Chef
35
35
  use_multipackage_api
36
36
  use_package_name_for_source
37
37
 
38
- provides :package, platform_family: %w{fedora amazon} do
39
- which("dnf") && shell_out("rpm -q dnf").stdout =~ /^dnf-[1-9]/
40
- end
38
+ # all rhel variants >= 8 will use DNF
39
+ provides :package, platform_family: "rhel", platform_version: ">= 8"
40
+
41
+ # fedora >= 22 uses DNF
42
+ provides :package, platform: "fedora", platform_version: ">= 22"
41
43
 
42
- provides :package, platform_family: %w{rhel}, platform_version: ">= 8"
44
+ # amazon will eventually use DNF
45
+ provides :package, platform: "amazon" do
46
+ which("dnf")
47
+ end
43
48
 
44
- provides :dnf_package, os: "linux"
49
+ provides :dnf_package
45
50
 
46
51
  #
47
52
  # Most of the magic in this class happens in the python helper script. The ruby side of this
@@ -126,6 +131,10 @@ class Chef
126
131
  end
127
132
  end
128
133
 
134
+ def version_compare(v1, v2)
135
+ python_helper.compare_versions(v1, v2)
136
+ end
137
+
129
138
  # @returns Array<Version>
130
139
  def available_version(index)
131
140
  @available_version ||= []
@@ -26,6 +26,14 @@ def flushcache():
26
26
  pass
27
27
  get_sack().load_system_repo(build_cache=True)
28
28
 
29
+ def versioncompare(versions):
30
+ sack = get_sack()
31
+ if (versions[0] is None) or (versions[1] is None):
32
+ sys.stdout.write('0\n')
33
+ else:
34
+ evr_comparison = sack.evr_cmp(versions[0], versions[1])
35
+ sys.stdout.write('{}\n'.format(evr_comparison))
36
+
29
37
  def query(command):
30
38
  sack = get_sack()
31
39
 
@@ -86,5 +94,7 @@ while 1:
86
94
  query(command)
87
95
  elif command['action'] == "flushcache":
88
96
  flushcache()
97
+ elif command['action'] == "versioncompare":
98
+ versioncompare(command['versions'])
89
99
  else:
90
100
  raise RuntimeError("bad command")