chef 12.18.31-universal-mingw32 → 12.19.33-universal-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (305) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +5 -4
  3. data/README.md +12 -13
  4. data/VERSION +1 -1
  5. data/acceptance/Gemfile +4 -4
  6. data/acceptance/Gemfile.lock +70 -69
  7. data/chef-universal-mingw32.gemspec +2 -3
  8. data/chef.gemspec +6 -6
  9. data/lib/chef/api_client.rb +8 -10
  10. data/lib/chef/api_client_v1.rb +9 -11
  11. data/lib/chef/application/apply.rb +8 -10
  12. data/lib/chef/application/client.rb +1 -1
  13. data/lib/chef/application/exit_code.rb +3 -5
  14. data/lib/chef/application/knife.rb +2 -2
  15. data/lib/chef/application/windows_service.rb +29 -30
  16. data/lib/chef/application/windows_service_manager.rb +1 -1
  17. data/lib/chef/audit/audit_event_proxy.rb +2 -2
  18. data/lib/chef/audit/control_group_data.rb +1 -1
  19. data/lib/chef/chef_class.rb +1 -0
  20. data/lib/chef/chef_fs/chef_fs_data_store.rb +5 -7
  21. data/lib/chef/chef_fs/command_line.rb +15 -16
  22. data/lib/chef/chef_fs/data_handler/client_data_handler.rb +1 -1
  23. data/lib/chef/chef_fs/data_handler/container_data_handler.rb +1 -1
  24. data/lib/chef/chef_fs/data_handler/cookbook_data_handler.rb +1 -1
  25. data/lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb +1 -1
  26. data/lib/chef/chef_fs/data_handler/environment_data_handler.rb +1 -1
  27. data/lib/chef/chef_fs/data_handler/group_data_handler.rb +1 -1
  28. data/lib/chef/chef_fs/data_handler/node_data_handler.rb +1 -1
  29. data/lib/chef/chef_fs/data_handler/organization_data_handler.rb +1 -1
  30. data/lib/chef/chef_fs/data_handler/role_data_handler.rb +1 -1
  31. data/lib/chef/chef_fs/data_handler/user_data_handler.rb +1 -1
  32. data/lib/chef/chef_fs/file_pattern.rb +2 -2
  33. data/lib/chef/chef_fs/file_system.rb +1 -1
  34. data/lib/chef/chef_fs/file_system/chef_server/cookbook_dir.rb +5 -6
  35. data/lib/chef/chef_fs/file_system/chef_server/cookbook_file.rb +8 -10
  36. data/lib/chef/chef_fs/file_system/chef_server/data_bags_dir.rb +8 -10
  37. data/lib/chef/chef_fs/file_system/chef_server/nodes_dir.rb +10 -12
  38. data/lib/chef/chef_fs/file_system/chef_server/policies_dir.rb +28 -30
  39. data/lib/chef/chef_fs/file_system/chef_server/policy_group_entry.rb +1 -1
  40. data/lib/chef/chef_fs/file_system/chef_server/rest_list_dir.rb +27 -29
  41. data/lib/chef/chef_fs/file_system/chef_server/rest_list_entry.rb +18 -24
  42. data/lib/chef/chef_fs/file_system/memory/memory_file.rb +1 -1
  43. data/lib/chef/chef_fs/file_system/multiplexed_dir.rb +10 -12
  44. data/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir.rb +10 -12
  45. data/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_entry.rb +9 -13
  46. data/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir.rb +2 -0
  47. data/lib/chef/chef_fs/file_system/repository/cookbooks_dir.rb +1 -1
  48. data/lib/chef/chef_fs/file_system/repository/nodes_dir.rb +3 -0
  49. data/lib/chef/chef_fs/parallelizer.rb +9 -11
  50. data/lib/chef/cookbook/cookbook_version_loader.rb +25 -31
  51. data/lib/chef/cookbook/metadata.rb +26 -26
  52. data/lib/chef/cookbook/syntax_check.rb +1 -1
  53. data/lib/chef/cookbook_version.rb +3 -3
  54. data/lib/chef/data_bag.rb +1 -1
  55. data/lib/chef/data_bag_item.rb +3 -3
  56. data/lib/chef/data_collector.rb +3 -4
  57. data/lib/chef/decorator.rb +1 -1
  58. data/lib/chef/deprecated.rb +30 -0
  59. data/lib/chef/dsl/audit.rb +2 -2
  60. data/lib/chef/dsl/declare_resource.rb +1 -1
  61. data/lib/chef/dsl/platform_introspection.rb +29 -31
  62. data/lib/chef/dsl/reboot_pending.rb +1 -1
  63. data/lib/chef/dsl/resources.rb +6 -8
  64. data/lib/chef/encrypted_data_bag_item.rb +2 -2
  65. data/lib/chef/environment.rb +9 -11
  66. data/lib/chef/event_loggers/windows_eventlog.rb +1 -1
  67. data/lib/chef/exceptions.rb +4 -1
  68. data/lib/chef/file_access_control/unix.rb +14 -14
  69. data/lib/chef/file_access_control/windows.rb +1 -1
  70. data/lib/chef/formatters/error_inspectors/api_error_formatting.rb +4 -5
  71. data/lib/chef/formatters/error_mapper.rb +6 -6
  72. data/lib/chef/http/api_versions.rb +50 -0
  73. data/lib/chef/http/validate_content_length.rb +2 -2
  74. data/lib/chef/json_compat.rb +6 -10
  75. data/lib/chef/key.rb +5 -5
  76. data/lib/chef/knife.rb +4 -4
  77. data/lib/chef/knife/cookbook_site_install.rb +2 -2
  78. data/lib/chef/knife/core/cookbook_scm_repo.rb +2 -2
  79. data/lib/chef/knife/core/gem_glob_loader.rb +1 -1
  80. data/lib/chef/knife/core/status_presenter.rb +1 -1
  81. data/lib/chef/knife/core/ui.rb +19 -25
  82. data/lib/chef/knife/data_bag_secret_options.rb +1 -1
  83. data/lib/chef/knife/deps.rb +32 -34
  84. data/lib/chef/knife/help.rb +1 -1
  85. data/lib/chef/knife/list.rb +1 -1
  86. data/lib/chef/knife/search.rb +2 -2
  87. data/lib/chef/knife/ssh.rb +37 -27
  88. data/lib/chef/knife/ssl_check.rb +1 -1
  89. data/lib/chef/knife/user_delete.rb +1 -1
  90. data/lib/chef/mash.rb +1 -1
  91. data/lib/chef/mixin/command.rb +2 -2
  92. data/lib/chef/mixin/create_path.rb +3 -5
  93. data/lib/chef/mixin/from_file.rb +2 -2
  94. data/lib/chef/mixin/get_source_from_package.rb +2 -2
  95. data/lib/chef/mixin/notifying_block.rb +7 -9
  96. data/lib/chef/mixin/params_validate.rb +3 -3
  97. data/lib/chef/mixin/securable.rb +1 -1
  98. data/lib/chef/mixin/shell_out.rb +23 -3
  99. data/lib/chef/mixin/unformatter.rb +2 -2
  100. data/lib/chef/mixin/uris.rb +4 -6
  101. data/lib/chef/mixin/versioned_api.rb +69 -0
  102. data/lib/chef/mixin/which.rb +25 -8
  103. data/lib/chef/mixin/windows_architecture_helper.rb +2 -2
  104. data/lib/chef/mixin/xml_escape.rb +3 -5
  105. data/lib/chef/monkey_patches/webrick-utils.rb +1 -1
  106. data/lib/chef/node.rb +8 -8
  107. data/lib/chef/node/attribute.rb +4 -4
  108. data/lib/chef/node/common_api.rb +5 -7
  109. data/lib/chef/org.rb +10 -12
  110. data/lib/chef/platform/provider_mapping.rb +7 -7
  111. data/lib/chef/platform/query_helpers.rb +1 -1
  112. data/lib/chef/policy_builder/policyfile.rb +1 -0
  113. data/lib/chef/property.rb +31 -0
  114. data/lib/chef/provider/batch.rb +1 -1
  115. data/lib/chef/provider/breakpoint.rb +1 -1
  116. data/lib/chef/provider/cookbook_file.rb +3 -3
  117. data/lib/chef/provider/cron.rb +38 -38
  118. data/lib/chef/provider/deploy.rb +81 -81
  119. data/lib/chef/provider/deploy/revision.rb +3 -5
  120. data/lib/chef/provider/directory.rb +32 -32
  121. data/lib/chef/provider/dsc_resource.rb +22 -6
  122. data/lib/chef/provider/env.rb +28 -28
  123. data/lib/chef/provider/env/windows.rb +1 -1
  124. data/lib/chef/provider/erl_call.rb +13 -13
  125. data/lib/chef/provider/execute.rb +5 -2
  126. data/lib/chef/provider/file.rb +49 -51
  127. data/lib/chef/provider/git.rb +55 -55
  128. data/lib/chef/provider/http_request.rb +36 -36
  129. data/lib/chef/provider/launchd.rb +2 -2
  130. data/lib/chef/provider/link.rb +50 -50
  131. data/lib/chef/provider/log.rb +2 -2
  132. data/lib/chef/provider/mdadm.rb +25 -25
  133. data/lib/chef/provider/mount/aix.rb +2 -2
  134. data/lib/chef/provider/mount/mount.rb +2 -2
  135. data/lib/chef/provider/ohai.rb +1 -1
  136. data/lib/chef/provider/osx_profile.rb +23 -23
  137. data/lib/chef/provider/package.rb +74 -56
  138. data/lib/chef/provider/package/aix.rb +55 -52
  139. data/lib/chef/provider/package/apt.rb +15 -13
  140. data/lib/chef/provider/package/cab.rb +49 -20
  141. data/lib/chef/provider/package/chocolatey.rb +9 -10
  142. data/lib/chef/provider/package/dnf.rb +20 -18
  143. data/lib/chef/provider/package/dnf/dnf_helper.py +1 -1
  144. data/lib/chef/provider/package/dnf/python_helper.rb +63 -26
  145. data/lib/chef/provider/package/dnf/version.rb +1 -1
  146. data/lib/chef/provider/package/dpkg.rb +8 -9
  147. data/lib/chef/provider/package/easy_install.rb +22 -22
  148. data/lib/chef/provider/package/freebsd/base.rb +10 -10
  149. data/lib/chef/provider/package/freebsd/pkg.rb +15 -15
  150. data/lib/chef/provider/package/freebsd/pkgng.rb +13 -15
  151. data/lib/chef/provider/package/freebsd/port.rb +7 -7
  152. data/lib/chef/provider/package/homebrew.rb +11 -10
  153. data/lib/chef/provider/package/ips.rb +18 -23
  154. data/lib/chef/provider/package/macports.rb +23 -23
  155. data/lib/chef/provider/package/msu.rb +11 -11
  156. data/lib/chef/provider/package/openbsd.rb +25 -22
  157. data/lib/chef/provider/package/pacman.rb +16 -16
  158. data/lib/chef/provider/package/paludis.rb +26 -27
  159. data/lib/chef/provider/package/portage.rb +22 -22
  160. data/lib/chef/provider/package/powershell.rb +17 -17
  161. data/lib/chef/provider/package/rpm.rb +25 -25
  162. data/lib/chef/provider/package/rubygems.rb +60 -60
  163. data/lib/chef/provider/package/smartos.rb +16 -16
  164. data/lib/chef/provider/package/solaris.rb +44 -44
  165. data/lib/chef/provider/package/windows.rb +3 -3
  166. data/lib/chef/provider/package/windows/exe.rb +6 -6
  167. data/lib/chef/provider/package/windows/msi.rb +6 -6
  168. data/lib/chef/provider/package/yum.rb +318 -268
  169. data/lib/chef/provider/package/yum/rpm_utils.rb +34 -34
  170. data/lib/chef/provider/package/yum/yum_cache.rb +12 -12
  171. data/lib/chef/provider/package/zypper.rb +11 -11
  172. data/lib/chef/provider/powershell_script.rb +15 -7
  173. data/lib/chef/provider/reboot.rb +10 -10
  174. data/lib/chef/provider/registry_key.rb +39 -39
  175. data/lib/chef/provider/remote_directory.rb +3 -3
  176. data/lib/chef/provider/remote_file.rb +3 -3
  177. data/lib/chef/provider/route.rb +1 -1
  178. data/lib/chef/provider/ruby_block.rb +3 -3
  179. data/lib/chef/provider/script.rb +42 -6
  180. data/lib/chef/provider/service.rb +49 -49
  181. data/lib/chef/provider/service/solaris.rb +1 -1
  182. data/lib/chef/provider/service/systemd.rb +1 -1
  183. data/lib/chef/provider/subversion.rb +39 -39
  184. data/lib/chef/provider/systemd_unit.rb +2 -0
  185. data/lib/chef/provider/template.rb +3 -3
  186. data/lib/chef/provider/user.rb +42 -42
  187. data/lib/chef/provider/whyrun_safe_ruby_block.rb +4 -4
  188. data/lib/chef/resource.rb +27 -16
  189. data/lib/chef/resource/apt_repository.rb +0 -1
  190. data/lib/chef/resource/chef_gem.rb +1 -1
  191. data/lib/chef/resource/dnf_package.rb +6 -3
  192. data/lib/chef/resource/dsc_resource.rb +9 -1
  193. data/lib/chef/resource/execute.rb +70 -6
  194. data/lib/chef/resource/file/verification/systemd_unit.rb +67 -0
  195. data/lib/chef/resource/freebsd_package.rb +1 -1
  196. data/lib/chef/resource/gem_package.rb +1 -1
  197. data/lib/chef/resource/launchd.rb +13 -1
  198. data/lib/chef/resource/package.rb +2 -2
  199. data/lib/chef/resource/registry_key.rb +1 -1
  200. data/lib/chef/resource/yum_package.rb +12 -3
  201. data/lib/chef/resource/yum_repository.rb +0 -1
  202. data/lib/chef/resource_collection/resource_collection_serialization.rb +3 -3
  203. data/lib/chef/resource_collection/resource_set.rb +2 -2
  204. data/lib/chef/resource_reporter.rb +1 -1
  205. data/lib/chef/run_context.rb +3 -3
  206. data/lib/chef/run_list/run_list_item.rb +1 -1
  207. data/lib/chef/run_list/versioned_recipe_list.rb +6 -6
  208. data/lib/chef/server_api.rb +2 -0
  209. data/lib/chef/server_api_versions.rb +40 -0
  210. data/lib/chef/shell.rb +1 -1
  211. data/lib/chef/shell/ext.rb +3 -3
  212. data/lib/chef/shell/shell_session.rb +1 -1
  213. data/lib/chef/user.rb +9 -11
  214. data/lib/chef/user_v1.rb +9 -11
  215. data/lib/chef/util/diff.rb +1 -1
  216. data/lib/chef/util/dsc/lcm_output_parser.rb +1 -1
  217. data/lib/chef/util/selinux.rb +1 -1
  218. data/lib/chef/util/windows/net_group.rb +18 -30
  219. data/lib/chef/util/windows/net_use.rb +7 -11
  220. data/lib/chef/util/windows/net_user.rb +11 -17
  221. data/lib/chef/util/windows/volume.rb +9 -15
  222. data/lib/chef/version.rb +1 -1
  223. data/lib/chef/version_class.rb +1 -1
  224. data/lib/chef/win32/api.rb +4 -6
  225. data/lib/chef/win32/api/file.rb +25 -31
  226. data/lib/chef/win32/api/installer.rb +2 -2
  227. data/lib/chef/win32/file.rb +4 -6
  228. data/lib/chef/win32/registry.rb +9 -9
  229. data/lib/chef/win32/security.rb +2 -2
  230. data/lib/chef/win32/security/acl.rb +2 -2
  231. data/lib/chef/win32/unicode.rb +2 -2
  232. data/lib/chef/win32/version.rb +1 -1
  233. data/spec/data/prefer_metadata_json/metadata.json +51 -0
  234. data/spec/data/prefer_metadata_json/metadata.rb +6 -0
  235. data/spec/data/prefer_metadata_json/recipes/default.rb +0 -0
  236. data/spec/functional/knife/ssh_spec.rb +5 -5
  237. data/spec/functional/resource/batch_spec.rb +5 -1
  238. data/spec/functional/resource/dsc_script_spec.rb +2 -4
  239. data/spec/functional/resource/execute_spec.rb +17 -0
  240. data/spec/functional/resource/user/dscl_spec.rb +2 -4
  241. data/spec/integration/client/client_spec.rb +33 -0
  242. data/spec/integration/recipes/recipe_dsl_spec.rb +58 -58
  243. data/spec/spec_helper.rb +4 -0
  244. data/spec/support/chef_helpers.rb +5 -7
  245. data/spec/support/platform_helpers.rb +6 -0
  246. data/spec/support/platforms/prof/gc.rb +4 -6
  247. data/spec/support/shared/context/client.rb +1 -1
  248. data/spec/support/shared/functional/execute_resource.rb +150 -0
  249. data/spec/support/shared/functional/windows_script.rb +74 -4
  250. data/spec/support/shared/unit/execute_resource.rb +37 -0
  251. data/spec/support/shared/unit/provider/file.rb +10 -0
  252. data/spec/unit/cookbook/cookbook_version_loader_spec.rb +9 -0
  253. data/spec/unit/cookbook/syntax_check_spec.rb +8 -2
  254. data/spec/unit/http/api_versions_spec.rb +69 -0
  255. data/spec/unit/knife/ssh_spec.rb +34 -36
  256. data/spec/unit/mixin/versioned_api_spec.rb +107 -0
  257. data/spec/unit/mixin/which.rb +160 -0
  258. data/spec/unit/platform_spec.rb +28 -1
  259. data/spec/unit/provider/deploy_spec.rb +1 -1
  260. data/spec/unit/provider/directory_spec.rb +10 -0
  261. data/spec/unit/provider/dsc_resource_spec.rb +175 -0
  262. data/spec/unit/provider/execute_spec.rb +0 -1
  263. data/spec/unit/provider/launchd_spec.rb +2 -2
  264. data/spec/unit/provider/package/aix_spec.rb +22 -22
  265. data/spec/unit/provider/package/apt_spec.rb +27 -27
  266. data/spec/unit/provider/package/cab_spec.rb +59 -5
  267. data/spec/unit/provider/package/dnf/python_helper_spec.rb +29 -0
  268. data/spec/unit/provider/package/dpkg_spec.rb +16 -16
  269. data/spec/unit/provider/package/easy_install_spec.rb +18 -18
  270. data/spec/unit/provider/package/freebsd/pkg_spec.rb +15 -15
  271. data/spec/unit/provider/package/freebsd/pkgng_spec.rb +9 -9
  272. data/spec/unit/provider/package/freebsd/port_spec.rb +9 -9
  273. data/spec/unit/provider/package/homebrew_spec.rb +9 -9
  274. data/spec/unit/provider/package/ips_spec.rb +37 -31
  275. data/spec/unit/provider/package/macports_spec.rb +10 -10
  276. data/spec/unit/provider/package/openbsd_spec.rb +10 -10
  277. data/spec/unit/provider/package/pacman_spec.rb +6 -6
  278. data/spec/unit/provider/package/paludis_spec.rb +7 -7
  279. data/spec/unit/provider/package/portage_spec.rb +6 -7
  280. data/spec/unit/provider/package/rpm_spec.rb +23 -23
  281. data/spec/unit/provider/package/rubygems_spec.rb +38 -38
  282. data/spec/unit/provider/package/solaris_spec.rb +15 -15
  283. data/spec/unit/provider/package/windows_spec.rb +2 -1
  284. data/spec/unit/provider/package/yum_spec.rb +51 -43
  285. data/spec/unit/provider/package/zypper_spec.rb +34 -34
  286. data/spec/unit/provider/package_spec.rb +8 -0
  287. data/spec/unit/provider/remote_file/sftp_spec.rb +3 -3
  288. data/spec/unit/provider/route_spec.rb +7 -1
  289. data/spec/unit/provider/script_spec.rb +49 -6
  290. data/spec/unit/resource/dsc_resource_spec.rb +6 -0
  291. data/spec/unit/resource/execute_spec.rb +214 -0
  292. data/spec/unit/resource/file/verification/systemd_unit_spec.rb +103 -0
  293. data/spec/unit/resource/freebsd_package_spec.rb +2 -2
  294. data/spec/unit/resource/package_spec.rb +5 -0
  295. data/spec/unit/resource/yum_package_spec.rb +42 -1
  296. data/spec/unit/resource_reporter_spec.rb +1 -1
  297. data/spec/unit/resource_spec.rb +18 -0
  298. data/spec/unit/server_api_versions_spec.rb +44 -0
  299. data/spec/unit/util/selinux_spec.rb +3 -14
  300. data/spec/unit/win32/error_spec.rb +67 -0
  301. data/spec/unit/win32/security_spec.rb +66 -0
  302. data/tasks/changelog.rb +1 -1
  303. data/tasks/dependencies.rb +20 -4
  304. metadata +39 -18
  305. data/lib/chef/monkey_patches/net-ssh-multi.rb +0 -141
@@ -33,24 +33,24 @@ class Chef
33
33
  provides :smartos_package, os: "solaris2", platform_family: "smartos"
34
34
 
35
35
  def load_current_resource
36
- Chef::Log.debug("#{@new_resource} loading current resource")
37
- @current_resource = Chef::Resource::Package.new(@new_resource.name)
38
- @current_resource.package_name(@new_resource.package_name)
39
- check_package_state(@new_resource.package_name)
40
- @current_resource # modified by check_package_state
36
+ Chef::Log.debug("#{new_resource} loading current resource")
37
+ @current_resource = Chef::Resource::Package.new(new_resource.name)
38
+ current_resource.package_name(new_resource.package_name)
39
+ check_package_state(new_resource.package_name)
40
+ current_resource # modified by check_package_state
41
41
  end
42
42
 
43
43
  def check_package_state(name)
44
- Chef::Log.debug("#{@new_resource} checking package #{name}")
44
+ Chef::Log.debug("#{new_resource} checking package #{name}")
45
45
  version = nil
46
- info = shell_out_with_timeout!("/opt/local/sbin/pkg_info", "-E", "#{name}*", :env => nil, :returns => [0, 1])
46
+ info = shell_out_compact_timeout!("/opt/local/sbin/pkg_info", "-E", "#{name}*", env: nil, returns: [0, 1])
47
47
 
48
48
  if info.stdout
49
- version = info.stdout[/^#{@new_resource.package_name}-(.+)/, 1]
49
+ version = info.stdout[/^#{new_resource.package_name}-(.+)/, 1]
50
50
  end
51
51
 
52
52
  if version
53
- @current_resource.version(version)
53
+ current_resource.version(version)
54
54
  end
55
55
  end
56
56
 
@@ -58,7 +58,7 @@ class Chef
58
58
  return @candidate_version if @candidate_version
59
59
  name = nil
60
60
  version = nil
61
- pkg = shell_out_with_timeout!("/opt/local/bin/pkgin", "se", new_resource.package_name, :env => nil, :returns => [0, 1])
61
+ pkg = shell_out_compact_timeout!("/opt/local/bin/pkgin", "se", new_resource.package_name, env: nil, returns: [0, 1])
62
62
  pkg.stdout.each_line do |line|
63
63
  case line
64
64
  when /^#{new_resource.package_name}/
@@ -70,20 +70,20 @@ class Chef
70
70
  end
71
71
 
72
72
  def install_package(name, version)
73
- Chef::Log.debug("#{@new_resource} installing package #{name} version #{version}")
73
+ Chef::Log.debug("#{new_resource} installing package #{name} version #{version}")
74
74
  package = "#{name}-#{version}"
75
- out = shell_out_with_timeout!("/opt/local/bin/pkgin", "-y", "install", package, :env => nil)
75
+ out = shell_out_compact_timeout!("/opt/local/bin/pkgin", "-y", "install", package, env: nil)
76
76
  end
77
77
 
78
78
  def upgrade_package(name, version)
79
- Chef::Log.debug("#{@new_resource} upgrading package #{name} version #{version}")
79
+ Chef::Log.debug("#{new_resource} upgrading package #{name} version #{version}")
80
80
  install_package(name, version)
81
81
  end
82
82
 
83
83
  def remove_package(name, version)
84
- Chef::Log.debug("#{@new_resource} removing package #{name} version #{version}")
85
- package = "#{name}"
86
- out = shell_out_with_timeout!("/opt/local/bin/pkgin", "-y", "remove", package, :env => nil)
84
+ Chef::Log.debug("#{new_resource} removing package #{name} version #{version}")
85
+ package = name.to_s
86
+ out = shell_out_compact_timeout!("/opt/local/bin/pkgin", "-y", "remove", package, env: nil)
87
87
  end
88
88
 
89
89
  end
@@ -33,45 +33,45 @@ class Chef
33
33
 
34
34
  # def initialize(*args)
35
35
  # super
36
- # @current_resource = Chef::Resource::Package.new(@new_resource.name)
36
+ # @current_resource = Chef::Resource::Package.new(new_resource.name)
37
37
  # end
38
38
  def define_resource_requirements
39
39
  super
40
40
  requirements.assert(:install) do |a|
41
- a.assertion { @new_resource.source }
42
- a.failure_message Chef::Exceptions::Package, "Source for package #{@new_resource.name} required for action install"
41
+ a.assertion { new_resource.source }
42
+ a.failure_message Chef::Exceptions::Package, "Source for package #{new_resource.name} required for action install"
43
43
  end
44
44
  requirements.assert(:all_actions) do |a|
45
- a.assertion { !@new_resource.source || @package_source_found }
46
- a.failure_message Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}"
47
- a.whyrun "would assume #{@new_resource.source} would be have previously been made available"
45
+ a.assertion { !new_resource.source || @package_source_found }
46
+ a.failure_message Chef::Exceptions::Package, "Package #{new_resource.name} not found: #{new_resource.source}"
47
+ a.whyrun "would assume #{new_resource.source} would be have previously been made available"
48
48
  end
49
49
  end
50
50
 
51
51
  def load_current_resource
52
- @current_resource = Chef::Resource::Package.new(@new_resource.name)
53
- @current_resource.package_name(@new_resource.package_name)
52
+ @current_resource = Chef::Resource::Package.new(new_resource.name)
53
+ current_resource.package_name(new_resource.package_name)
54
54
 
55
- if @new_resource.source
56
- @package_source_found = ::File.exists?(@new_resource.source)
55
+ if new_resource.source
56
+ @package_source_found = ::File.exist?(new_resource.source)
57
57
  if @package_source_found
58
- Chef::Log.debug("#{@new_resource} checking pkg status")
59
- shell_out_with_timeout("pkginfo -l -d #{@new_resource.source} #{@new_resource.package_name}").stdout.each_line do |line|
58
+ Chef::Log.debug("#{new_resource} checking pkg status")
59
+ shell_out_compact_timeout("pkginfo", "-l", "-d", new_resource.source, new_resource.package_name).stdout.each_line do |line|
60
60
  case line
61
61
  when /VERSION:\s+(.+)/
62
- @new_resource.version($1)
62
+ new_resource.version($1)
63
63
  end
64
64
  end
65
65
  end
66
66
  end
67
67
 
68
- Chef::Log.debug("#{@new_resource} checking install state")
69
- status = shell_out_with_timeout("pkginfo -l #{@current_resource.package_name}")
68
+ Chef::Log.debug("#{new_resource} checking install state")
69
+ status = shell_out_compact_timeout("pkginfo", "-l", current_resource.package_name)
70
70
  status.stdout.each_line do |line|
71
71
  case line
72
72
  when /VERSION:\s+(.+)/
73
- Chef::Log.debug("#{@new_resource} version #{$1} is already installed")
74
- @current_resource.version($1)
73
+ Chef::Log.debug("#{new_resource} version #{$1} is already installed")
74
+ current_resource.version($1)
75
75
  end
76
76
  end
77
77
 
@@ -79,56 +79,56 @@ class Chef
79
79
  raise Chef::Exceptions::Package, "pkginfo failed - #{status.inspect}!"
80
80
  end
81
81
 
82
- @current_resource
82
+ current_resource
83
83
  end
84
84
 
85
85
  def candidate_version
86
86
  return @candidate_version if @candidate_version
87
- status = shell_out_with_timeout("pkginfo -l -d #{@new_resource.source} #{new_resource.package_name}")
87
+ status = shell_out_compact_timeout("pkginfo", "-l", "-d", new_resource.source, new_resource.package_name)
88
88
  status.stdout.each_line do |line|
89
89
  case line
90
90
  when /VERSION:\s+(.+)/
91
91
  @candidate_version = $1
92
- @new_resource.version($1)
93
- Chef::Log.debug("#{@new_resource} setting install candidate version to #{@candidate_version}")
92
+ new_resource.version($1)
93
+ Chef::Log.debug("#{new_resource} setting install candidate version to #{@candidate_version}")
94
94
  end
95
95
  end
96
96
  unless status.exitstatus == 0
97
- raise Chef::Exceptions::Package, "pkginfo -l -d #{@new_resource.source} - #{status.inspect}!"
97
+ raise Chef::Exceptions::Package, "pkginfo -l -d #{new_resource.source} - #{status.inspect}!"
98
98
  end
99
99
  @candidate_version
100
100
  end
101
101
 
102
102
  def install_package(name, version)
103
- Chef::Log.debug("#{@new_resource} package install options: #{@new_resource.options}")
104
- if @new_resource.options.nil?
105
- if ::File.directory?(@new_resource.source) # CHEF-4469
106
- command = "pkgadd -n -d #{@new_resource.source} #{@new_resource.package_name}"
107
- else
108
- command = "pkgadd -n -d #{@new_resource.source} all"
109
- end
110
- shell_out_with_timeout!(command)
111
- Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}")
103
+ Chef::Log.debug("#{new_resource} package install options: #{options}")
104
+ if options.nil?
105
+ command = if ::File.directory?(new_resource.source) # CHEF-4469
106
+ [ "pkgadd", "-n", "-d", new_resource.source, new_resource.package_name ]
107
+ else
108
+ [ "pkgadd", "-n", "-d", new_resource.source, "all" ]
109
+ end
110
+ shell_out_compact_timeout!(command)
111
+ Chef::Log.debug("#{new_resource} installed version #{new_resource.version} from: #{new_resource.source}")
112
112
  else
113
- if ::File.directory?(@new_resource.source) # CHEF-4469
114
- command = "pkgadd -n#{expand_options(@new_resource.options)} -d #{@new_resource.source} #{@new_resource.package_name}"
115
- else
116
- command = "pkgadd -n#{expand_options(@new_resource.options)} -d #{@new_resource.source} all"
117
- end
118
- shell_out_with_timeout!(command)
119
- Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}")
113
+ command = if ::File.directory?(new_resource.source) # CHEF-4469
114
+ [ "pkgadd", "-n", options, "-d", new_resource.source, new_resource.package_name ]
115
+ else
116
+ [ "pkgadd", "-n", options, "-d", new_resource.source, "all" ]
117
+ end
118
+ shell_out_compact_timeout!(*command)
119
+ Chef::Log.debug("#{new_resource} installed version #{new_resource.version} from: #{new_resource.source}")
120
120
  end
121
121
  end
122
122
 
123
- alias_method :upgrade_package, :install_package
123
+ alias upgrade_package install_package
124
124
 
125
125
  def remove_package(name, version)
126
- if @new_resource.options.nil?
127
- shell_out_with_timeout!( "pkgrm -n #{name}" )
128
- Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}")
126
+ if options.nil?
127
+ shell_out_compact_timeout!( "pkgrm", "-n", name )
128
+ Chef::Log.debug("#{new_resource} removed version #{new_resource.version}")
129
129
  else
130
- shell_out_with_timeout!( "pkgrm -n#{expand_options(@new_resource.options)} #{name}" )
131
- Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}")
130
+ shell_out_compact_timeout!( "pkgrm", "-n", options, name )
131
+ Chef::Log.debug("#{new_resource} removed version #{new_resource.version}")
132
132
  end
133
133
  end
134
134
 
@@ -104,8 +104,8 @@ class Chef
104
104
  return :nsis
105
105
  end
106
106
 
107
- if io.tell() < filesize
108
- io.seek(io.tell() - overlap)
107
+ if io.tell < filesize
108
+ io.seek(io.tell - overlap)
109
109
  end
110
110
  end
111
111
 
@@ -195,7 +195,7 @@ class Chef
195
195
  end
196
196
 
197
197
  def downloadable_file_missing?
198
- !new_resource.source.nil? && uri_scheme?(new_resource.source) && !::File.exists?(source_location)
198
+ !new_resource.source.nil? && uri_scheme?(new_resource.source) && !::File.exist?(source_location)
199
199
  end
200
200
 
201
201
  def resource_for_provider
@@ -69,10 +69,10 @@ class Chef
69
69
  def remove_package
70
70
  uninstall_version = new_resource.version || current_installed_version
71
71
  uninstall_entries.select { |entry| [uninstall_version].flatten.include?(entry.display_version) }
72
- .map { |version| version.uninstall_string }.uniq.each do |uninstall_string|
73
- Chef::Log.debug("Registry provided uninstall string for #{new_resource} is '#{uninstall_string}'")
74
- shell_out!(uninstall_command(uninstall_string), { :timeout => new_resource.timeout, :returns => new_resource.returns })
75
- end
72
+ .map(&:uninstall_string).uniq.each do |uninstall_string|
73
+ Chef::Log.debug("Registry provided uninstall string for #{new_resource} is '#{uninstall_string}'")
74
+ shell_out!(uninstall_command(uninstall_string), timeout: new_resource.timeout, returns: new_resource.returns)
75
+ end
76
76
  end
77
77
 
78
78
  private
@@ -85,13 +85,13 @@ class Chef
85
85
  " ",
86
86
  unattended_flags,
87
87
  ].join
88
- %Q{start "" /wait #{uninstall_string} & exit %%%%ERRORLEVEL%%%%}
88
+ %{start "" /wait #{uninstall_string} & exit %%%%ERRORLEVEL%%%%}
89
89
  end
90
90
 
91
91
  def current_installed_version
92
92
  @current_installed_version ||=
93
93
  if uninstall_entries.count != 0
94
- uninstall_entries.map { |entry| entry.display_version }.uniq
94
+ uninstall_entries.map(&:display_version).uniq
95
95
  end
96
96
  end
97
97
 
@@ -16,7 +16,7 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- # TODO: Allow @new_resource.source to be a Product Code as a GUID for uninstall / network install
19
+ # TODO: Allow new_resource.source to be a Product Code as a GUID for uninstall / network install
20
20
 
21
21
  require "chef/win32/api/installer" if (RUBY_PLATFORM =~ /mswin|mingw32|windows/) && Chef::Platform.supports_msi?
22
22
  require "chef/mixin/shell_out"
@@ -51,7 +51,7 @@ class Chef
51
51
  get_installed_version(product_code)
52
52
  else
53
53
  if uninstall_entries.count != 0
54
- uninstall_entries.map { |entry| entry.display_version }.uniq
54
+ uninstall_entries.map(&:display_version).uniq
55
55
  end
56
56
  end
57
57
  end
@@ -67,23 +67,23 @@ class Chef
67
67
  def install_package
68
68
  # We could use MsiConfigureProduct here, but we'll start off with msiexec
69
69
  Chef::Log.debug("#{new_resource} installing MSI package '#{new_resource.source}'")
70
- shell_out!("msiexec /qn /i \"#{new_resource.source}\" #{expand_options(new_resource.options)}", { :timeout => new_resource.timeout, :returns => new_resource.returns })
70
+ shell_out!("msiexec /qn /i \"#{new_resource.source}\" #{expand_options(new_resource.options)}", timeout: new_resource.timeout, returns: new_resource.returns)
71
71
  end
72
72
 
73
73
  def remove_package
74
74
  # We could use MsiConfigureProduct here, but we'll start off with msiexec
75
75
  if !new_resource.source.nil? && ::File.exist?(new_resource.source)
76
76
  Chef::Log.debug("#{new_resource} removing MSI package '#{new_resource.source}'")
77
- shell_out!("msiexec /qn /x \"#{new_resource.source}\" #{expand_options(new_resource.options)}", { :timeout => new_resource.timeout, :returns => new_resource.returns })
77
+ shell_out!("msiexec /qn /x \"#{new_resource.source}\" #{expand_options(new_resource.options)}", timeout: new_resource.timeout, returns: new_resource.returns)
78
78
  else
79
79
  uninstall_version = new_resource.version || installed_version
80
80
  uninstall_entries.select { |entry| [uninstall_version].flatten.include?(entry.display_version) }
81
- .map { |version| version.uninstall_string }.uniq.each do |uninstall_string|
81
+ .map(&:uninstall_string).uniq.each do |uninstall_string|
82
82
  uninstall_string = "msiexec /x #{uninstall_string.match(/{.*}/)}"
83
83
  uninstall_string += expand_options(new_resource.options)
84
84
  uninstall_string += " /q" unless uninstall_string.downcase =~ / \/q/
85
85
  Chef::Log.debug("#{new_resource} removing MSI package version using '#{uninstall_string}'")
86
- shell_out!(uninstall_string, { :timeout => new_resource.timeout, :returns => new_resource.returns })
86
+ shell_out!(uninstall_string, timeout: new_resource.timeout, returns: new_resource.returns)
87
87
  end
88
88
  end
89
89
  end
@@ -1,6 +1,6 @@
1
1
 
2
2
  # Author:: Adam Jacob (<adam@chef.io>)
3
- # Copyright:: Copyright 2008-2016, Chef Software, Inc.
3
+ # Copyright:: Copyright 2008-2017, Chef Software, Inc.
4
4
  # License:: Apache License, Version 2.0
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,12 +27,17 @@ class Chef
27
27
  class Provider
28
28
  class Package
29
29
  class Yum < Chef::Provider::Package
30
+ include Chef::Mixin::GetSourceFromPackage
30
31
 
31
32
  provides :package, platform_family: %w{rhel fedora}
32
33
  provides :yum_package, os: "linux"
33
34
 
34
- include Chef::Mixin::GetSourceFromPackage
35
+ # Multipackage API
36
+ allow_nils
37
+ use_multipackage_api
38
+ use_package_name_for_source
35
39
 
40
+ # Overload the Package provider to keep track of the YumCache
36
41
  def initialize(new_resource, run_context)
37
42
  super
38
43
 
@@ -40,89 +45,60 @@ class Chef
40
45
  @yum.yum_binary = yum_binary
41
46
  end
42
47
 
43
- def yum_binary
44
- @yum_binary ||=
45
- begin
46
- yum_binary = new_resource.yum_binary if new_resource.is_a?(Chef::Resource::YumPackage)
47
- yum_binary ||= ::File.exist?("/usr/bin/yum-deprecated") ? "yum-deprecated" : "yum"
48
- end
49
- end
50
-
51
- # Extra attributes
52
- #
48
+ # @see Chef::Provider::Package#check_resource_semantics!
49
+ def check_resource_semantics!
50
+ super
53
51
 
54
- def arch_for_name(n)
55
- if @new_resource.respond_to?("arch")
56
- @new_resource.arch
57
- elsif @arch
58
- idx = package_name_array.index(n)
59
- as_array(@arch)[idx]
60
- else
61
- nil
52
+ if !new_resource.version.nil? && package_name_array.length != new_version_array.length
53
+ raise Chef::Exceptions::InvalidResourceSpecification, "Please provide a version for each package. Use `nil` for default version."
62
54
  end
63
- end
64
55
 
65
- def arch
66
- if @new_resource.respond_to?("arch")
67
- @new_resource.arch
68
- else
69
- nil
56
+ if !new_resource.arch.nil? && package_name_array.length != safe_arch_array.length
57
+ raise Chef::Exceptions::InvalidResourceSpecification, "Please provide an architecture for each package. Use `nil` for default architecture."
70
58
  end
71
59
  end
72
60
 
73
- def set_arch(arch)
74
- if @new_resource.respond_to?("arch")
75
- @new_resource.arch(arch)
76
- end
77
- end
61
+ # @see Chef::Provider#define_resource_requirements
62
+ def define_resource_requirements
63
+ super
78
64
 
79
- def flush_cache
80
- if @new_resource.respond_to?("flush_cache")
81
- @new_resource.flush_cache
82
- else
83
- { :before => false, :after => false }
65
+ # Ensure that the source file (if specified) is present on the file system
66
+ requirements.assert(:install, :upgrade, :remove, :purge) do |a|
67
+ a.assertion { !new_resource.source || ::File.exist?(new_resource.source) }
68
+ a.failure_message Chef::Exceptions::Package, "Package #{new_resource.package_name} not found: #{new_resource.source}"
69
+ a.whyrun "assuming #{new_resource.source} would have previously been created"
84
70
  end
85
71
  end
86
72
 
87
- # Helpers
88
- #
89
-
90
- def yum_arch(arch)
91
- arch ? ".#{arch}" : nil
92
- end
73
+ # @see Chef::Provider#load_current_resource
74
+ def load_current_resource
75
+ @yum.reload if flush_cache[:before]
76
+ manage_extra_repo_control
93
77
 
94
- def yum_command(command)
95
- command = "#{yum_binary} #{command}"
96
- Chef::Log.debug("#{@new_resource}: yum command: \"#{command}\"")
97
- status = shell_out_with_timeout(command, { :timeout => Chef::Config[:yum_timeout] })
78
+ if new_resource.source
79
+ query_source_file
80
+ else
81
+ # At this point package_name could be:
82
+ #
83
+ # 1) a package name, eg: "foo"
84
+ # 2) a package name.arch, eg: "foo.i386"
85
+ # 3) or a dependency, eg: "foo >= 1.1"
86
+ #
87
+ # In the third case, we want to convert those dependency strings into
88
+ # packages that we can actually install
89
+ convert_dependency_strings_into_packages
98
90
 
99
- # This is fun: rpm can encounter errors in the %post/%postun scripts which aren't
100
- # considered fatal - meaning the rpm is still successfully installed. These issue
101
- # cause yum to emit a non fatal warning but still exit(1). As there's currently no
102
- # way to suppress this behavior and an exit(1) will break a Chef run we make an
103
- # effort to trap these and re-run the same install command - it will either fail a
104
- # second time or succeed.
105
- #
106
- # A cleaner solution would have to be done in python and better hook into
107
- # yum/rpm to handle exceptions as we see fit.
108
- if status.exitstatus == 1
109
- status.stdout.each_line do |l|
110
- # rpm-4.4.2.3 lib/psm.c line 2182
111
- if l =~ %r{^error: %(post|postun)\(.*\) scriptlet failed, exit status \d+$}
112
- Chef::Log.warn("#{@new_resource} caught non-fatal scriptlet issue: \"#{l}\". Can't trust yum exit status " +
113
- "so running install again to verify.")
114
- status = shell_out_with_timeout(command, { :timeout => Chef::Config[:yum_timeout] })
115
- break
116
- end
117
- end
91
+ # Fill out the rest of the details by querying the Yum Cache
92
+ query_yum_cache
118
93
  end
119
94
 
120
- if status.exitstatus > 0
121
- command_output = "STDOUT: #{status.stdout}\nSTDERR: #{status.stderr}"
122
- raise Chef::Exceptions::Exec, "#{command} returned #{status.exitstatus}:\n#{command_output}"
123
- end
95
+ @current_resource = Chef::Resource::YumPackage.new(new_resource.name)
96
+ current_resource.package_name(new_resource.package_name)
97
+ current_resource.version(@installed_version)
98
+ current_resource
124
99
  end
125
100
 
101
+ # @see Chef::Provider::Package#package_locked
126
102
  def package_locked(name, version)
127
103
  islocked = false
128
104
  locked = shell_out_with_timeout!("yum versionlock")
@@ -132,26 +108,97 @@ class Chef
132
108
  islocked = true
133
109
  end
134
110
  end
135
- return islocked
111
+ islocked
136
112
  end
137
113
 
138
- # Standard Provider methods for Parent
114
+ #
115
+ # Package Action Classes
139
116
  #
140
117
 
141
- def load_current_resource
142
- if flush_cache[:before]
143
- @yum.reload
118
+ # @see Chef::Provider::Package#install_package
119
+ def install_package(name, version)
120
+ if new_resource.source
121
+ yum_command("-d0 -e0 -y#{expand_options(new_resource.options)} localinstall #{new_resource.source}")
122
+ else
123
+ install_remote_package(name, version)
124
+ end
125
+
126
+ flush_cache[:after] ? @yum.reload : @yum.reload_installed
127
+ end
128
+
129
+ # @see Chef::Provider::Package#upgrade_package
130
+ def upgrade_package(name, version)
131
+ install_package(name, version)
132
+ end
133
+
134
+ # @see Chef::Provider::Package#remove_package
135
+ def remove_package(name, version)
136
+ remove_str = full_package_name(name, version).join(" ")
137
+ yum_command("-d0 -e0 -y#{expand_options(new_resource.options)} remove #{remove_str}")
138
+
139
+ flush_cache[:after] ? @yum.reload : @yum.reload_installed
140
+ end
141
+
142
+ # @see Chef::Provider::Package#purge_package
143
+ def purge_package(name, version)
144
+ remove_package(name, version)
145
+ end
146
+
147
+ # @see Chef::Provider::Package#lock_package
148
+ def lock_package(name, version)
149
+ lock_str = full_package_name(name, as_array(name).map { nil }).join(" ")
150
+ yum_command("-d0 -e0 -y#{expand_options(new_resource.options)} versionlock add #{lock_str}")
151
+ end
152
+
153
+ # @see Chef::Provider::Package#unlock_package
154
+ def unlock_package(name, version)
155
+ unlock_str = full_package_name(name, as_array(name).map { nil }).join(" ")
156
+ yum_command("-d0 -e0 -y#{expand_options(new_resource.options)} versionlock delete #{unlock_str}")
157
+ end
158
+
159
+ # Keep upgrades from trying to install an older candidate version. Can happen when a new
160
+ # version is installed then removed from a repository, now the older available version
161
+ # shows up as a viable install candidate.
162
+ #
163
+ # Can be done in upgrade_package but an upgraded from->to log message slips out
164
+ #
165
+ # Hacky - better overall solution? Custom compare in Package provider?
166
+ def action_upgrade
167
+ # Could be uninstalled or have no candidate
168
+ if current_resource.version.nil? || !candidate_version_array.any?
169
+ super
170
+ elsif candidate_version_array.zip(current_version_array).any? do |c, i|
171
+ RPMVersion.parse(c) > RPMVersion.parse(i)
172
+ end
173
+ super
174
+ else
175
+ Chef::Log.debug("#{new_resource} is at the latest version - nothing to do")
144
176
  end
177
+ end
145
178
 
146
- if @new_resource.options
179
+ private
180
+
181
+ #
182
+ # System Level Yum Operations
183
+ #
184
+
185
+ def yum_binary
186
+ @yum_binary ||=
187
+ begin
188
+ yum_binary = new_resource.yum_binary if new_resource.is_a?(Chef::Resource::YumPackage)
189
+ yum_binary ||= ::File.exist?("/usr/bin/yum-deprecated") ? "yum-deprecated" : "yum"
190
+ end
191
+ end
192
+
193
+ # Enable or disable YumCache extra_repo_control
194
+ def manage_extra_repo_control
195
+ if new_resource.options
147
196
  repo_control = []
148
- @new_resource.options.split.each do |opt|
149
- if opt =~ %r{--(enable|disable)repo=.+}
150
- repo_control << opt
151
- end
197
+ new_resource.options.split.each do |opt|
198
+ repo_control << opt if opt =~ /--(enable|disable)repo=.+/
152
199
  end
153
200
 
154
- if repo_control.size > 0
201
+ if !repo_control.empty?
155
202
  @yum.enable_extra_repo_control(repo_control.join(" "))
156
203
  else
157
204
  @yum.disable_extra_repo_control
@@ -159,105 +206,100 @@ class Chef
159
206
  else
160
207
  @yum.disable_extra_repo_control
161
208
  end
209
+ end
162
210
 
163
- # At this point package_name could be:
164
- #
165
- # 1) a package name, eg: "foo"
166
- # 2) a package name.arch, eg: "foo.i386"
167
- # 3) or a dependency, eg: "foo >= 1.1"
211
+ # Query the Yum cache for information about potential packages
212
+ def query_yum_cache
213
+ installed_versions = []
214
+ candidate_versions = []
168
215
 
169
- # Check if we have name or name+arch which has a priority over a dependency
170
- package_name_array.each_with_index do |n, index|
171
- unless @yum.package_available?(n)
172
- # If they aren't in the installed packages they could be a dependency
173
- dep = parse_dependency(n, new_version_array[index])
174
- if dep
175
- if @new_resource.package_name.is_a?(Array)
176
- @new_resource.package_name(package_name_array - [n] + [dep.first])
177
- @new_resource.version(new_version_array - [new_version_array[index]] + [dep.last]) if dep.last
178
- else
179
- @new_resource.package_name(dep.first)
180
- @new_resource.version(dep.last) if dep.last
181
- end
182
- end
183
- end
184
- end
216
+ package_name_array.each_with_index do |n, idx|
217
+ pkg_name, eval_pkg_arch = parse_arch(n)
185
218
 
186
- @current_resource = Chef::Resource::YumPackage.new(@new_resource.name)
187
- @current_resource.package_name(@new_resource.package_name)
219
+ # Defer to the arch property for the desired package architecture
220
+ pkg_arch = safe_arch_array[idx] || eval_pkg_arch
221
+ set_package_name(idx, pkg_name)
222
+ set_package_arch(idx, pkg_arch)
188
223
 
189
- installed_version = []
190
- @candidate_version = []
191
- @arch = []
192
- if @new_resource.source
193
- unless ::File.exists?(@new_resource.source)
194
- raise Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}"
195
- end
224
+ Chef::Log.debug("#{new_resource} checking yum info for #{yum_syntax(n, nil, pkg_arch)}")
225
+ installed_versions << iv = @yum.installed_version(pkg_name, pkg_arch)
226
+ candidate_versions << cv = @yum.candidate_version(pkg_name, pkg_arch)
196
227
 
197
- Chef::Log.debug("#{@new_resource} checking rpm status")
198
- shell_out_with_timeout!("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@new_resource.source}", :timeout => Chef::Config[:yum_timeout]).stdout.each_line do |line|
199
- case line
200
- when /^(\S+)\s(\S+)$/
201
- @current_resource.package_name($1)
202
- @new_resource.version($2)
228
+ Chef::Log.debug("Found Yum package: #{pkg_name} installed version: #{iv || '(none)'} candidate version: #{cv || '(none)'}")
229
+ end
230
+
231
+ @installed_version = installed_versions.length > 1 ? installed_versions : installed_versions[0]
232
+ @candidate_version = candidate_versions.length > 1 ? candidate_versions : candidate_versions[0]
233
+ end
234
+
235
+ # Query the provided source file for the package name and version
236
+ def query_source_file
237
+ Chef::Log.debug("#{new_resource} checking rpm status")
238
+ shell_out_with_timeout!("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE} %{ARCH}\n' #{new_resource.source}", timeout: Chef::Config[:yum_timeout]).stdout.each_line do |line|
239
+ case line
240
+ when /^(\S+)\s(\S+)\s(\S+)$/
241
+ n = $1
242
+ v = $2
243
+ a = $3
244
+
245
+ unless new_resource.package_name == n
246
+ Chef::Log.debug("#{new_resource} updating package_name from #{new_resource.package_name} to #{n} (per #{new_resource.source})")
247
+ new_resource.package_name(n)
203
248
  end
204
- end
205
- @candidate_version << @new_resource.version
206
- installed_version << @yum.installed_version(@current_resource.package_name, arch)
207
- else
208
249
 
209
- package_name_array.each_with_index do |pkg, idx|
210
- # Don't overwrite an existing arch
211
- if arch
212
- name, parch = pkg, arch
213
- else
214
- name, parch = parse_arch(pkg)
215
- # if we parsed an arch from the name, update the name
216
- # to be just the package name.
217
- if parch
218
- if @new_resource.package_name.is_a?(Array)
219
- @new_resource.package_name[idx] = name
220
- else
221
- @new_resource.package_name(name)
222
- # only set the arch if it's a single package
223
- set_arch(parch)
224
- end
225
- end
250
+ unless new_resource.version == v
251
+ Chef::Log.debug("#{new_resource} updating version from #{new_resource.version} to #{v} (per #{new_resource.source})")
252
+ new_resource.version(v)
226
253
  end
227
254
 
228
- if @new_resource.version
229
- new_resource =
230
- "#{@new_resource.package_name}-#{@new_resource.version}#{yum_arch(parch)}"
231
- else
232
- new_resource = "#{@new_resource.package_name}#{yum_arch(parch)}"
255
+ unless new_resource.arch == a
256
+ Chef::Log.debug("#{new_resource} updating architecture from #{new_resource.arch} to #{a} (per #{new_resource.source})")
257
+ new_resource.arch(a)
233
258
  end
234
- Chef::Log.debug("#{@new_resource} checking yum info for #{new_resource}")
235
- installed_version << @yum.installed_version(name, parch)
236
- @candidate_version << @yum.candidate_version(name, parch)
237
- @arch << parch
238
259
  end
239
260
  end
240
261
 
241
- if installed_version.size == 1
242
- @current_resource.version(installed_version[0])
243
- @candidate_version = @candidate_version[0]
244
- @arch = @arch[0]
245
- else
246
- @current_resource.version(installed_version)
247
- end
262
+ @installed_version = @yum.installed_version(new_resource.package_name, new_resource.arch)
263
+ @candidate_version = new_resource.version
264
+ end
248
265
 
249
- Chef::Log.debug("#{@new_resource} installed version: #{installed_version || "(none)"} candidate version: " +
250
- "#{@candidate_version || "(none)"}")
266
+ def yum_command(command)
267
+ command = "#{yum_binary} #{command}"
268
+ Chef::Log.debug("#{new_resource}: yum command: \"#{command}\"")
269
+ status = shell_out_with_timeout(command, timeout: Chef::Config[:yum_timeout])
270
+
271
+ # This is fun: rpm can encounter errors in the %post/%postun scripts which aren't
272
+ # considered fatal - meaning the rpm is still successfully installed. These issue
273
+ # cause yum to emit a non fatal warning but still exit(1). As there's currently no
274
+ # way to suppress this behavior and an exit(1) will break a Chef run we make an
275
+ # effort to trap these and re-run the same install command - it will either fail a
276
+ # second time or succeed.
277
+ #
278
+ # A cleaner solution would have to be done in python and better hook into
279
+ # yum/rpm to handle exceptions as we see fit.
280
+ if status.exitstatus == 1
281
+ status.stdout.each_line do |l|
282
+ # rpm-4.4.2.3 lib/psm.c line 2182
283
+ next unless l =~ /^error: %(post|postun)\(.*\) scriptlet failed, exit status \d+$/
284
+ Chef::Log.warn("#{new_resource} caught non-fatal scriptlet issue: \"#{l}\". Can't trust yum exit status " \
285
+ "so running install again to verify.")
286
+ status = shell_out_with_timeout(command, timeout: Chef::Config[:yum_timeout])
287
+ break
288
+ end
289
+ end
251
290
 
252
- @current_resource
291
+ if status.exitstatus > 0
292
+ command_output = "STDOUT: #{status.stdout}\nSTDERR: #{status.stderr}"
293
+ raise Chef::Exceptions::Exec, "#{command} returned #{status.exitstatus}:\n#{command_output}"
294
+ end
253
295
  end
254
296
 
255
297
  def install_remote_package(name, version)
256
- # Work around yum not exiting with an error if a package doesn't exist
257
- # for CHEF-2062
258
- all_avail = as_array(name).zip(as_array(version)).any? do |n, v|
259
- @yum.version_available?(n, v, arch_for_name(n))
298
+ # Work around yum not exiting with an error if a package doesn't exist for CHEF-2062.
299
+ all_avail = as_array(name).zip(as_array(version), safe_arch_array).any? do |n, v, a|
300
+ @yum.version_available?(n, v, a)
260
301
  end
302
+
261
303
  method = log_method = nil
262
304
  methods = []
263
305
  if all_avail
@@ -267,12 +309,14 @@ class Chef
267
309
  # yum install of an old name+version+arch will exit(0) for some reason
268
310
  #
269
311
  # Some packages can be installed multiple times like the kernel
270
- as_array(name).zip(as_array(version)).each do |n, v|
312
+ as_array(name).zip(current_version_array, as_array(version), safe_arch_array).each do |n, cv, v, a|
313
+ next if n.nil?
314
+
271
315
  method = "install"
272
316
  log_method = "installing"
273
- idx = package_name_array.index(n)
317
+
274
318
  unless @yum.allow_multi_install.include?(n)
275
- if RPMVersion.parse(current_version_array[idx]) > RPMVersion.parse(v)
319
+ if RPMVersion.parse(cv) > RPMVersion.parse(v)
276
320
  # We allow downgrading only in the evenit of single-package
277
321
  # rules where the user explicitly allowed it
278
322
  if allow_downgrade
@@ -280,13 +324,13 @@ class Chef
280
324
  log_method = "downgrading"
281
325
  else
282
326
  # we bail like yum when the package is older
283
- raise Chef::Exceptions::Package, "Installed package #{n}-#{current_version_array[idx]} is newer " +
284
- "than candidate package #{n}-#{v}"
327
+ raise Chef::Exceptions::Package, "Installed package #{yum_syntax(n, cv, a)} is newer " \
328
+ "than candidate package #{yum_syntax(n, v, a)}"
285
329
  end
286
330
  end
287
331
  end
288
332
  # methods don't count for packages we won't be touching
289
- next if RPMVersion.parse(current_version_array[idx]) == RPMVersion.parse(v)
333
+ next if RPMVersion.parse(cv) == RPMVersion.parse(v)
290
334
  methods << method
291
335
  end
292
336
 
@@ -298,103 +342,26 @@ class Chef
298
342
 
299
343
  repos = []
300
344
  pkg_string_bits = []
301
- as_array(name).zip(as_array(version)).each do |n, v|
302
- idx = package_name_array.index(n)
303
- a = arch_for_name(n)
304
- s = ""
305
- unless v == current_version_array[idx]
306
- s = "#{n}-#{v}#{yum_arch(a)}"
307
- repo = @yum.package_repository(n, v, a)
308
- repos << "#{s} from #{repo} repository"
309
- pkg_string_bits << s
310
- end
345
+ as_array(name).zip(current_version_array, as_array(version), safe_arch_array).each do |n, cv, v, a|
346
+ next if n.nil?
347
+ next if v == cv
348
+ s = yum_syntax(n, v, a)
349
+ repo = @yum.package_repository(n, v, a)
350
+ repos << "#{s} from #{repo} repository"
351
+ pkg_string_bits << s
311
352
  end
312
353
  pkg_string = pkg_string_bits.join(" ")
313
- Chef::Log.info("#{@new_resource} #{log_method} #{repos.join(' ')}")
314
- yum_command("-d0 -e0 -y#{expand_options(@new_resource.options)} #{method} #{pkg_string}")
354
+ Chef::Log.info("#{new_resource} #{log_method} #{repos.join(' ')}")
355
+ yum_command("-d0 -e0 -y#{expand_options(new_resource.options)} #{method} #{pkg_string}")
315
356
  else
316
- raise Chef::Exceptions::Package, "Version #{version} of #{name} not found. Did you specify both version " +
357
+ raise Chef::Exceptions::Package, "Version #{version} of #{name} not found. Did you specify both version " \
317
358
  "and release? (version-release, e.g. 1.84-10.fc6)"
318
359
  end
319
360
  end
320
361
 
321
- def install_package(name, version)
322
- if @new_resource.source
323
- yum_command("-d0 -e0 -y#{expand_options(@new_resource.options)} localinstall #{@new_resource.source}")
324
- else
325
- install_remote_package(name, version)
326
- end
327
-
328
- if flush_cache[:after]
329
- @yum.reload
330
- else
331
- @yum.reload_installed
332
- end
333
- end
334
-
335
- # Keep upgrades from trying to install an older candidate version. Can happen when a new
336
- # version is installed then removed from a repository, now the older available version
337
- # shows up as a viable install candidate.
338
- #
339
- # Can be done in upgrade_package but an upgraded from->to log message slips out
340
- #
341
- # Hacky - better overall solution? Custom compare in Package provider?
342
- def action_upgrade
343
- # Could be uninstalled or have no candidate
344
- if @current_resource.version.nil? || !candidate_version_array.any?
345
- super
346
- elsif candidate_version_array.zip(current_version_array).any? do |c, i|
347
- RPMVersion.parse(c) > RPMVersion.parse(i)
348
- end
349
- super
350
- else
351
- Chef::Log.debug("#{@new_resource} is at the latest version - nothing to do")
352
- end
353
- end
354
-
355
- def upgrade_package(name, version)
356
- install_package(name, version)
357
- end
358
-
359
- def remove_package(name, version)
360
- if version
361
- remove_str = as_array(name).zip(as_array(version)).map do |n, v|
362
- a = arch_for_name(n)
363
- "#{[n, v].join('-')}#{yum_arch(a)}"
364
- end.join(" ")
365
- else
366
- remove_str = as_array(name).map do |n|
367
- a = arch_for_name(n)
368
- "#{n}#{yum_arch(a)}"
369
- end.join(" ")
370
- end
371
- yum_command("-d0 -e0 -y#{expand_options(@new_resource.options)} remove #{remove_str}")
372
-
373
- if flush_cache[:after]
374
- @yum.reload
375
- else
376
- @yum.reload_installed
377
- end
378
- end
379
-
380
- def purge_package(name, version)
381
- remove_package(name, version)
382
- end
383
-
384
- def lock_package(name, version)
385
- yum_command("-d0 -e0 -y#{expand_options(@new_resource.options)} versionlock add #{name}")
386
- end
387
-
388
- def unlock_package(name, version)
389
- yum_command("-d0 -e0 -y#{expand_options(@new_resource.options)} versionlock delete #{name}")
390
- end
391
-
392
- private
393
-
362
+ # Allow for foo.x86_64 style package_name like yum uses in it's output
394
363
  def parse_arch(package_name)
395
- # Allow for foo.x86_64 style package_name like yum uses in it's output
396
- #
397
- if package_name =~ %r{^(.*)\.(.*)$}
364
+ if package_name =~ /^(.*)\.(.*)$/
398
365
  new_package_name = $1
399
366
  new_arch = $2
400
367
  # foo.i386 and foo.beta1 are both valid package names or expressions of an arch.
@@ -410,7 +377,31 @@ class Chef
410
377
  return new_package_name, new_arch
411
378
  end
412
379
  end
413
- return package_name, nil
380
+ [package_name, nil]
381
+ end
382
+
383
+ #
384
+ # Dependency String Handling
385
+ #
386
+
387
+ # Iterate through the list of package_names given to us by the user and
388
+ # see if any of them are in the depenency format ("foo >= 1.1"). Modify
389
+ # the list of packages and versions to incorporate those values.
390
+ def convert_dependency_strings_into_packages
391
+ package_name_array.each_with_index do |n, index|
392
+ next if @yum.package_available?(n)
393
+ # If they aren't in the installed packages they could be a dependency.
394
+ dep = parse_dependency(n, new_version_array[index])
395
+ if dep
396
+ if new_resource.package_name.is_a?(Array)
397
+ new_resource.package_name(package_name_array - [n] + [dep.first])
398
+ new_resource.version(new_version_array - [new_version_array[index]] + [dep.last]) if dep.last
399
+ else
400
+ new_resource.package_name(dep.first)
401
+ new_resource.version(dep.last) if dep.last
402
+ end
403
+ end
404
+ end
414
405
  end
415
406
 
416
407
  # If we don't have the package we could have been passed a 'whatprovides' feature
@@ -423,18 +414,20 @@ class Chef
423
414
  # matching them up with an actual package so the standard resource handling can apply.
424
415
  #
425
416
  # There is currently no support for filename matching.
417
+ #
418
+ # Note: This was largely left alone during the multipackage refactor
426
419
  def parse_dependency(name, version)
427
420
  # Transform the package_name into a requirement
428
421
 
429
422
  # If we are passed a version or a version constraint we have to assume it's a requirement first. If it can't be
430
- # parsed only yum_require.name will be set and @new_resource.version will be left intact
431
- if version
432
- require_string = "#{name} #{version}"
433
- else
434
- # Transform the package_name into a requirement, might contain a version, could just be
435
- # a match for virtual provides
436
- require_string = name
437
- end
423
+ # parsed only yum_require.name will be set and new_resource.version will be left intact
424
+ require_string = if version
425
+ "#{name} #{version}"
426
+ else
427
+ # Transform the package_name into a requirement, might contain a version, could just be
428
+ # a match for virtual provides
429
+ name
430
+ end
438
431
  yum_require = RPMRequire.parse(require_string)
439
432
  # and gather all the packages that have a Provides feature satisfying the requirement.
440
433
  # It could be multiple be we can only manage one
@@ -442,9 +435,9 @@ class Chef
442
435
 
443
436
  if packages.empty?
444
437
  # Don't bother if we are just ensuring a package is removed - we don't need Provides data
445
- actions = Array(@new_resource.action)
438
+ actions = Array(new_resource.action)
446
439
  unless actions.size == 1 && (actions[0] == :remove || actions[0] == :purge)
447
- Chef::Log.debug("#{@new_resource} couldn't match #{@new_resource.package_name} in " +
440
+ Chef::Log.debug("#{new_resource} couldn't match #{new_resource.package_name} in " \
448
441
  "installed Provides, loading available Provides - this may take a moment")
449
442
  @yum.reload_provides
450
443
  packages = @yum.packages_from_require(yum_require)
@@ -467,8 +460,8 @@ class Chef
467
460
  unique_names.uniq!
468
461
 
469
462
  if unique_names.size > 1
470
- Chef::Log.warn("#{@new_resource} matched multiple Provides for #{@new_resource.package_name} " +
471
- "but we can only use the first match: #{new_package_name}. Please use a more " +
463
+ Chef::Log.warn("#{new_resource} matched multiple Provides for #{new_resource.package_name} " \
464
+ "but we can only use the first match: #{new_package_name}. Please use a more " \
472
465
  "specific version.")
473
466
  end
474
467
 
@@ -480,6 +473,63 @@ class Chef
480
473
  end
481
474
  end
482
475
 
476
+ #
477
+ # Misc Helpers
478
+ #
479
+
480
+ # Given an list of names and versions, generate the full yum syntax package name
481
+ def full_package_name(name, version)
482
+ as_array(name).zip(as_array(version), safe_arch_array).map do |n, v, a|
483
+ yum_syntax(n, v, a)
484
+ end
485
+ end
486
+
487
+ # Generate the yum syntax for the package
488
+ def yum_syntax(name, version, arch)
489
+ s = name
490
+ s += "-#{version}" if version
491
+ s += ".#{arch}" if arch
492
+ s
493
+ end
494
+
495
+ # Set the package name correctly based on whether it is a String or Array
496
+ def set_package_name(idx, name)
497
+ if new_resource.package_name.is_a?(String)
498
+ new_resource.package_name(name)
499
+ else
500
+ new_resource.package_name[idx] = name
501
+ end
502
+ end
503
+
504
+ # Set the architecture correcly based on whether it is a String or Array
505
+ def set_package_arch(idx, arch)
506
+ if new_resource.package_name.is_a?(String)
507
+ new_resource.arch(arch) unless arch.nil?
508
+ else
509
+ new_resource.arch ||= []
510
+ new_resource.arch[idx] = arch
511
+ end
512
+ end
513
+
514
+ # A cousin of package_name_array, return a list of the architectures
515
+ # defined in the resource.
516
+ def safe_arch_array
517
+ if new_resource.arch.is_a?(Array)
518
+ new_resource.arch
519
+ elsif new_resource.arch.nil?
520
+ package_name_array.map { nil }
521
+ else
522
+ [ new_resource.arch ]
523
+ end
524
+ end
525
+
526
+ def flush_cache
527
+ if new_resource.respond_to?("flush_cache")
528
+ new_resource.flush_cache
529
+ else
530
+ { before: false, after: false }
531
+ end
532
+ end
483
533
  end
484
534
  end
485
535
  end