chef 17.9.52 → 18.0.169

Sign up to get free protection for your applications and to get access to all the features.
Files changed (311) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +16 -8
  3. data/README.md +7 -7
  4. data/Rakefile +5 -24
  5. data/{chef-universal-mingw32.gemspec → chef-universal-mingw-ucrt.gemspec} +7 -5
  6. data/chef.gemspec +14 -7
  7. data/lib/chef/api_client.rb +1 -1
  8. data/lib/chef/api_client_v1.rb +9 -1
  9. data/lib/chef/application/exit_code.rb +3 -3
  10. data/lib/chef/client.rb +167 -0
  11. data/lib/chef/compliance/input.rb +1 -1
  12. data/lib/chef/compliance/input_collection.rb +1 -1
  13. data/lib/chef/compliance/profile.rb +1 -1
  14. data/lib/chef/compliance/profile_collection.rb +1 -2
  15. data/lib/chef/compliance/waiver.rb +1 -1
  16. data/lib/chef/compliance/waiver_collection.rb +1 -1
  17. data/lib/chef/cookbook/syntax_check.rb +2 -2
  18. data/lib/chef/dsl/reader_helpers.rb +1 -1
  19. data/lib/chef/dsl/rest_resource.rb +77 -0
  20. data/lib/chef/dsl/secret.rb +113 -5
  21. data/lib/chef/event_dispatch/base.rb +3 -0
  22. data/lib/chef/exceptions.rb +8 -0
  23. data/lib/chef/http/authenticator.rb +170 -3
  24. data/lib/chef/http/ssl_policies.rb +3 -3
  25. data/lib/chef/mixin/powershell_exec.rb +5 -28
  26. data/lib/chef/mixin/properties.rb +6 -0
  27. data/lib/chef/node/attribute.rb +20 -3
  28. data/lib/chef/node/mixin/deep_merge_cache.rb +4 -4
  29. data/lib/chef/node/mixin/immutablize_array.rb +1 -0
  30. data/lib/chef/policy_builder/expand_node_object.rb +1 -2
  31. data/lib/chef/policy_builder/policyfile.rb +1 -1
  32. data/lib/chef/property.rb +5 -3
  33. data/lib/chef/provider/group/windows.rb +1 -1
  34. data/lib/chef/provider/http_request.rb +11 -9
  35. data/lib/chef/provider/mount/linux.rb +5 -0
  36. data/lib/chef/provider/mount/mount.rb +8 -0
  37. data/lib/chef/provider/mount/windows.rb +1 -1
  38. data/lib/chef/provider/package/powershell.rb +1 -1
  39. data/lib/chef/provider/package/rubygems.rb +7 -7
  40. data/lib/chef/provider/package/windows/msi.rb +2 -2
  41. data/lib/chef/provider/package/windows/registry_uninstall_entry.rb +1 -1
  42. data/lib/chef/provider/package/yum/python_helper.rb +14 -1
  43. data/lib/chef/provider/package/zypper/version.rb +60 -0
  44. data/lib/chef/provider/package/zypper.rb +47 -3
  45. data/lib/chef/provider/service/windows.rb +5 -5
  46. data/lib/chef/provider/user/aix.rb +5 -0
  47. data/lib/chef/provider/user/linux.rb +29 -0
  48. data/lib/chef/provider/user/mac.rb +1 -1
  49. data/lib/chef/provider/user/windows.rb +2 -2
  50. data/lib/chef/provider/user.rb +45 -9
  51. data/lib/chef/provider.rb +1 -1
  52. data/lib/chef/recipe.rb +1 -1
  53. data/lib/chef/resource/_rest_resource.rb +389 -0
  54. data/lib/chef/resource/alternatives.rb +0 -1
  55. data/lib/chef/resource/apt_package.rb +0 -1
  56. data/lib/chef/resource/apt_preference.rb +0 -1
  57. data/lib/chef/resource/apt_repository.rb +0 -1
  58. data/lib/chef/resource/apt_update.rb +0 -1
  59. data/lib/chef/resource/archive_file.rb +0 -1
  60. data/lib/chef/resource/bash.rb +0 -1
  61. data/lib/chef/resource/batch.rb +0 -1
  62. data/lib/chef/resource/bff_package.rb +0 -1
  63. data/lib/chef/resource/breakpoint.rb +0 -1
  64. data/lib/chef/resource/build_essential.rb +0 -1
  65. data/lib/chef/resource/cab_package.rb +0 -1
  66. data/lib/chef/resource/chef_client_config.rb +17 -14
  67. data/lib/chef/resource/chef_client_cron.rb +1 -2
  68. data/lib/chef/resource/chef_client_launchd.rb +2 -2
  69. data/lib/chef/resource/chef_client_scheduled_task.rb +3 -3
  70. data/lib/chef/resource/chef_client_systemd_timer.rb +0 -1
  71. data/lib/chef/resource/chef_client_trusted_certificate.rb +0 -1
  72. data/lib/chef/resource/chef_gem.rb +0 -1
  73. data/lib/chef/resource/chef_handler.rb +0 -1
  74. data/lib/chef/resource/chef_sleep.rb +1 -3
  75. data/lib/chef/resource/chef_vault_secret.rb +0 -1
  76. data/lib/chef/resource/chocolatey_config.rb +0 -1
  77. data/lib/chef/resource/chocolatey_feature.rb +0 -1
  78. data/lib/chef/resource/chocolatey_package.rb +0 -1
  79. data/lib/chef/resource/chocolatey_source.rb +0 -1
  80. data/lib/chef/resource/cookbook_file.rb +0 -1
  81. data/lib/chef/resource/cron/_cron_shared.rb +0 -1
  82. data/lib/chef/resource/cron/cron.rb +0 -1
  83. data/lib/chef/resource/cron/cron_d.rb +15 -1
  84. data/lib/chef/resource/cron_access.rb +0 -1
  85. data/lib/chef/resource/csh.rb +0 -1
  86. data/lib/chef/resource/directory.rb +0 -1
  87. data/lib/chef/resource/dmg_package.rb +0 -1
  88. data/lib/chef/resource/dnf_package.rb +0 -1
  89. data/lib/chef/resource/dpkg_package.rb +0 -1
  90. data/lib/chef/resource/dsc_resource.rb +0 -1
  91. data/lib/chef/resource/dsc_script.rb +0 -1
  92. data/lib/chef/resource/execute.rb +0 -1
  93. data/lib/chef/resource/file.rb +0 -1
  94. data/lib/chef/resource/freebsd_package.rb +0 -1
  95. data/lib/chef/resource/gem_package.rb +0 -1
  96. data/lib/chef/resource/group.rb +25 -2
  97. data/lib/chef/resource/habitat/habitat_package.rb +0 -1
  98. data/lib/chef/resource/habitat/habitat_sup.rb +6 -7
  99. data/lib/chef/resource/habitat/habitat_sup_windows.rb +1 -1
  100. data/lib/chef/resource/habitat_config.rb +0 -1
  101. data/lib/chef/resource/habitat_install.rb +0 -1
  102. data/lib/chef/resource/habitat_service.rb +0 -1
  103. data/lib/chef/resource/habitat_user_toml.rb +0 -1
  104. data/lib/chef/resource/homebrew_cask.rb +0 -1
  105. data/lib/chef/resource/homebrew_package.rb +0 -1
  106. data/lib/chef/resource/homebrew_tap.rb +0 -1
  107. data/lib/chef/resource/homebrew_update.rb +0 -2
  108. data/lib/chef/resource/hostname.rb +0 -1
  109. data/lib/chef/resource/http_request.rb +0 -1
  110. data/lib/chef/resource/ifconfig.rb +0 -1
  111. data/lib/chef/resource/inspec_input.rb +0 -1
  112. data/lib/chef/resource/inspec_waiver.rb +0 -1
  113. data/lib/chef/resource/inspec_waiver_file_entry.rb +2 -3
  114. data/lib/chef/resource/ips_package.rb +0 -1
  115. data/lib/chef/resource/kernel_module.rb +0 -1
  116. data/lib/chef/resource/ksh.rb +0 -1
  117. data/lib/chef/resource/launchd.rb +0 -1
  118. data/lib/chef/resource/link.rb +0 -1
  119. data/lib/chef/resource/locale.rb +1 -2
  120. data/lib/chef/resource/log.rb +0 -1
  121. data/lib/chef/resource/lwrp_base.rb +0 -4
  122. data/lib/chef/resource/macos_userdefaults.rb +0 -1
  123. data/lib/chef/resource/macosx_service.rb +0 -1
  124. data/lib/chef/resource/macports_package.rb +0 -1
  125. data/lib/chef/resource/mdadm.rb +0 -1
  126. data/lib/chef/resource/mount.rb +0 -1
  127. data/lib/chef/resource/msu_package.rb +0 -1
  128. data/lib/chef/resource/notify_group.rb +0 -2
  129. data/lib/chef/resource/ohai.rb +0 -1
  130. data/lib/chef/resource/ohai_hint.rb +0 -1
  131. data/lib/chef/resource/openbsd_package.rb +0 -1
  132. data/lib/chef/resource/openssl_dhparam.rb +0 -2
  133. data/lib/chef/resource/openssl_ec_private_key.rb +0 -2
  134. data/lib/chef/resource/openssl_ec_public_key.rb +0 -2
  135. data/lib/chef/resource/openssl_rsa_private_key.rb +0 -2
  136. data/lib/chef/resource/openssl_rsa_public_key.rb +0 -2
  137. data/lib/chef/resource/openssl_x509_certificate.rb +0 -2
  138. data/lib/chef/resource/openssl_x509_crl.rb +0 -2
  139. data/lib/chef/resource/openssl_x509_request.rb +0 -2
  140. data/lib/chef/resource/osx_profile.rb +0 -1
  141. data/lib/chef/resource/package.rb +0 -1
  142. data/lib/chef/resource/pacman_package.rb +0 -1
  143. data/lib/chef/resource/paludis_package.rb +0 -1
  144. data/lib/chef/resource/perl.rb +0 -1
  145. data/lib/chef/resource/plist.rb +7 -3
  146. data/lib/chef/resource/portage_package.rb +0 -1
  147. data/lib/chef/resource/powershell_package.rb +0 -1
  148. data/lib/chef/resource/powershell_package_source.rb +0 -1
  149. data/lib/chef/resource/powershell_script.rb +0 -1
  150. data/lib/chef/resource/python.rb +0 -1
  151. data/lib/chef/resource/reboot.rb +0 -1
  152. data/lib/chef/resource/registry_key.rb +0 -1
  153. data/lib/chef/resource/remote_directory.rb +0 -1
  154. data/lib/chef/resource/remote_file.rb +0 -1
  155. data/lib/chef/resource/rhsm_errata.rb +0 -1
  156. data/lib/chef/resource/rhsm_errata_level.rb +0 -1
  157. data/lib/chef/resource/rhsm_register.rb +17 -1
  158. data/lib/chef/resource/rhsm_repo.rb +0 -1
  159. data/lib/chef/resource/rhsm_subscription.rb +0 -1
  160. data/lib/chef/resource/route.rb +0 -1
  161. data/lib/chef/resource/rpm_package.rb +0 -1
  162. data/lib/chef/resource/ruby.rb +0 -1
  163. data/lib/chef/resource/ruby_block.rb +0 -1
  164. data/lib/chef/resource/scm/_scm.rb +0 -2
  165. data/lib/chef/resource/scm/git.rb +0 -2
  166. data/lib/chef/resource/scm/subversion.rb +0 -2
  167. data/lib/chef/resource/script.rb +0 -1
  168. data/lib/chef/resource/selinux/common_helpers.rb +47 -0
  169. data/lib/chef/resource/selinux/selinux_debian.erb +18 -0
  170. data/lib/chef/resource/selinux/selinux_default.erb +15 -0
  171. data/lib/chef/resource/selinux_boolean.rb +101 -0
  172. data/lib/chef/resource/selinux_fcontext.rb +160 -0
  173. data/lib/chef/resource/selinux_install.rb +107 -0
  174. data/lib/chef/resource/selinux_module.rb +143 -0
  175. data/lib/chef/resource/selinux_permissive.rb +64 -0
  176. data/lib/chef/resource/selinux_port.rb +118 -0
  177. data/lib/chef/resource/selinux_state.rb +166 -0
  178. data/lib/chef/resource/service.rb +0 -1
  179. data/lib/chef/resource/smartos_package.rb +0 -1
  180. data/lib/chef/resource/snap_package.rb +0 -1
  181. data/lib/chef/resource/solaris_package.rb +0 -1
  182. data/lib/chef/resource/ssh_known_hosts_entry.rb +0 -1
  183. data/lib/chef/resource/sudo.rb +0 -1
  184. data/lib/chef/resource/support/client.erb +3 -4
  185. data/lib/chef/resource/swap_file.rb +0 -1
  186. data/lib/chef/resource/sysctl.rb +1 -2
  187. data/lib/chef/resource/systemd_unit.rb +0 -1
  188. data/lib/chef/resource/template.rb +0 -1
  189. data/lib/chef/resource/timezone.rb +0 -1
  190. data/lib/chef/resource/user/aix_user.rb +0 -1
  191. data/lib/chef/resource/user/linux_user.rb +0 -1
  192. data/lib/chef/resource/user/mac_user.rb +0 -1
  193. data/lib/chef/resource/user/pw_user.rb +0 -1
  194. data/lib/chef/resource/user/solaris_user.rb +0 -1
  195. data/lib/chef/resource/user/windows_user.rb +0 -1
  196. data/lib/chef/resource/user.rb +10 -1
  197. data/lib/chef/resource/user_ulimit.rb +0 -1
  198. data/lib/chef/resource/whyrun_safe_ruby_block.rb +0 -1
  199. data/lib/chef/resource/windows_ad_join.rb +0 -2
  200. data/lib/chef/resource/windows_audit_policy.rb +0 -2
  201. data/lib/chef/resource/windows_auto_run.rb +0 -1
  202. data/lib/chef/resource/windows_certificate.rb +54 -43
  203. data/lib/chef/resource/windows_defender.rb +0 -1
  204. data/lib/chef/resource/windows_defender_exclusion.rb +0 -1
  205. data/lib/chef/resource/windows_dfs_folder.rb +0 -1
  206. data/lib/chef/resource/windows_dfs_namespace.rb +0 -1
  207. data/lib/chef/resource/windows_dfs_server.rb +0 -1
  208. data/lib/chef/resource/windows_dns_record.rb +0 -1
  209. data/lib/chef/resource/windows_dns_zone.rb +0 -1
  210. data/lib/chef/resource/windows_env.rb +0 -1
  211. data/lib/chef/resource/windows_feature.rb +0 -1
  212. data/lib/chef/resource/windows_feature_dism.rb +0 -1
  213. data/lib/chef/resource/windows_feature_powershell.rb +0 -1
  214. data/lib/chef/resource/windows_firewall_profile.rb +0 -2
  215. data/lib/chef/resource/windows_firewall_rule.rb +0 -1
  216. data/lib/chef/resource/windows_font.rb +2 -3
  217. data/lib/chef/resource/windows_package.rb +0 -1
  218. data/lib/chef/resource/windows_pagefile.rb +27 -22
  219. data/lib/chef/resource/windows_path.rb +0 -1
  220. data/lib/chef/resource/windows_printer.rb +0 -1
  221. data/lib/chef/resource/windows_printer_port.rb +0 -1
  222. data/lib/chef/resource/windows_script.rb +0 -2
  223. data/lib/chef/resource/windows_security_policy.rb +0 -1
  224. data/lib/chef/resource/windows_service.rb +0 -1
  225. data/lib/chef/resource/windows_share.rb +0 -1
  226. data/lib/chef/resource/windows_shortcut.rb +1 -2
  227. data/lib/chef/resource/windows_task.rb +0 -1
  228. data/lib/chef/resource/windows_uac.rb +0 -1
  229. data/lib/chef/resource/windows_update_settings.rb +0 -1
  230. data/lib/chef/resource/windows_user_privilege.rb +36 -27
  231. data/lib/chef/resource/windows_workgroup.rb +0 -1
  232. data/lib/chef/resource/yum_package.rb +0 -1
  233. data/lib/chef/resource/yum_repository.rb +0 -1
  234. data/lib/chef/resource/zypper_package.rb +0 -1
  235. data/lib/chef/resource/zypper_repository.rb +0 -1
  236. data/lib/chef/resource.rb +13 -5
  237. data/lib/chef/resources.rb +7 -0
  238. data/lib/chef/run_context.rb +19 -3
  239. data/lib/chef/secret_fetcher/azure_key_vault.rb +3 -3
  240. data/lib/chef/secret_fetcher/hashi_vault.rb +1 -1
  241. data/lib/chef/version.rb +1 -1
  242. data/lib/chef/win32/handle.rb +6 -7
  243. data/lib/chef/win32/registry.rb +7 -3
  244. data/lib/chef/win32/version.rb +2 -1
  245. data/spec/data/rubygems.org/sexp_processor-info +2 -1
  246. data/spec/functional/resource/dnf_package_spec.rb +15 -0
  247. data/spec/functional/resource/dsc_script_spec.rb +1 -1
  248. data/spec/functional/resource/group_spec.rb +10 -6
  249. data/spec/functional/resource/link_spec.rb +8 -8
  250. data/spec/functional/resource/plist_spec.rb +25 -0
  251. data/spec/functional/resource/user/linux_user_spec.rb +127 -0
  252. data/spec/functional/resource/windows_certificate_spec.rb +15 -12
  253. data/spec/functional/resource/windows_font_spec.rb +11 -8
  254. data/spec/functional/resource/windows_pagefile_spec.rb +31 -4
  255. data/spec/functional/resource/yum_package_spec.rb +15 -0
  256. data/spec/functional/resource/zypper_package_spec.rb +12 -0
  257. data/spec/functional/shell_spec.rb +7 -2
  258. data/spec/functional/version_spec.rb +1 -1
  259. data/spec/integration/client/client_spec.rb +82 -3
  260. data/spec/integration/client/exit_code_spec.rb +1 -1
  261. data/spec/integration/client/ipv6_spec.rb +1 -1
  262. data/spec/integration/compliance/compliance_spec.rb +1 -1
  263. data/spec/integration/recipes/accumulator_spec.rb +1 -1
  264. data/spec/integration/recipes/lwrp_inline_resources_spec.rb +1 -1
  265. data/spec/integration/recipes/lwrp_spec.rb +1 -1
  266. data/spec/integration/recipes/notifies_spec.rb +1 -1
  267. data/spec/integration/recipes/notifying_block_spec.rb +1 -1
  268. data/spec/integration/recipes/remote_directory.rb +1 -1
  269. data/spec/integration/recipes/unified_mode_spec.rb +1 -1
  270. data/spec/integration/recipes/use_partial_spec.rb +2 -1
  271. data/spec/integration/solo/solo_spec.rb +2 -2
  272. data/spec/spec_helper.rb +1 -0
  273. data/spec/support/platform_helpers.rb +4 -0
  274. data/spec/support/ruby_installer.rb +1 -1
  275. data/spec/support/shared/functional/windows_script.rb +2 -2
  276. data/spec/unit/application/client_spec.rb +0 -10
  277. data/spec/unit/client_spec.rb +54 -2
  278. data/spec/unit/cookbook/syntax_check_spec.rb +3 -0
  279. data/spec/unit/daemon_spec.rb +1 -5
  280. data/spec/unit/dsl/secret_spec.rb +127 -23
  281. data/spec/unit/http/authenticator_spec.rb +68 -0
  282. data/spec/unit/mixin/powershell_exec_spec.rb +5 -5
  283. data/spec/unit/platform/query_helpers_spec.rb +2 -17
  284. data/spec/unit/provider/http_request_spec.rb +60 -72
  285. data/spec/unit/provider/mount/linux_spec.rb +10 -0
  286. data/spec/unit/provider/package/rubygems_spec.rb +2 -2
  287. data/spec/unit/provider/package/zypper_spec.rb +32 -0
  288. data/spec/unit/provider/user/linux_spec.rb +96 -1
  289. data/spec/unit/provider/user_spec.rb +24 -6
  290. data/spec/unit/resource/archive_file_spec.rb +1 -1
  291. data/spec/unit/resource/chef_client_config_spec.rb +8 -0
  292. data/spec/unit/resource/chef_client_cron_spec.rb +5 -0
  293. data/spec/unit/resource/chef_client_launchd_spec.rb +5 -0
  294. data/spec/unit/resource/chef_client_scheduled_task_spec.rb +5 -0
  295. data/spec/unit/resource/chef_client_systemd_timer_spec.rb +1 -1
  296. data/spec/unit/resource/cron_d_spec.rb +37 -1
  297. data/spec/unit/resource/rest_resource_spec.rb +381 -0
  298. data/spec/unit/resource/selinux_boolean_spec.rb +92 -0
  299. data/spec/unit/resource/selinux_fcontext_spec.rb +65 -0
  300. data/spec/unit/resource/selinux_install_spec.rb +60 -0
  301. data/spec/unit/resource/selinux_module_spec.rb +55 -0
  302. data/spec/unit/resource/selinux_permissive_spec.rb +39 -0
  303. data/spec/unit/resource/selinux_port_spec.rb +42 -0
  304. data/spec/unit/resource/selinux_state_spec.rb +46 -0
  305. data/spec/unit/resource/sysctl_spec.rb +2 -2
  306. data/spec/unit/resource/user/linux_user_spec.rb +42 -0
  307. data/spec/unit/resource_spec.rb +21 -1
  308. data/spec/unit/run_context_spec.rb +16 -0
  309. data/spec/unit/util/dsc/local_configuration_manager_spec.rb +1 -1
  310. data/tasks/rspec.rb +1 -1
  311. metadata +93 -21
@@ -0,0 +1,389 @@
1
+ #
2
+ # Copyright:: Copyright 2008-2016, Chef, Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require "addressable/template" unless defined?(Addressable::Template)
19
+ require "rest-client" unless defined?(RestClient)
20
+ require "jmespath" unless defined?(JMESPath)
21
+ require "chef/dsl/rest_resource" unless defined?(Chef::DSL::RestResource)
22
+
23
+ extend Chef::DSL::RestResource
24
+
25
+ action_class do
26
+ def load_current_resource
27
+ @current_resource = new_resource.class.new(new_resource.name)
28
+
29
+ required_properties.each do |name|
30
+ requested = new_resource.send(name)
31
+ current_resource.send(name, requested)
32
+ end
33
+
34
+ return @current_resource if rest_get_all.data.empty?
35
+
36
+ resource_data = rest_get.data rescue nil
37
+ return @current_resource if resource_data.nil? || resource_data.empty?
38
+
39
+ @resource_exists = true
40
+
41
+ # Map JSON contents to defined properties
42
+ current_resource.class.rest_property_map.each do |property, match_instruction|
43
+ property_value = json_to_property(match_instruction, property, resource_data)
44
+ current_resource.send(property, property_value) unless property_value.nil?
45
+ end
46
+
47
+ current_resource
48
+ end
49
+ end
50
+
51
+ action :configure do
52
+ if resource_exists?
53
+ converge_if_changed do
54
+ data = {}
55
+
56
+ new_resource.class.rest_property_map.each do |property, match_instruction|
57
+ # Skip "creation-only" properties on modifications
58
+ next if new_resource.class.rest_post_only_properties.include?(property)
59
+
60
+ deep_merge! data, property_to_json(property, match_instruction)
61
+ end
62
+
63
+ deep_compact!(data)
64
+
65
+ rest_patch(data)
66
+ end
67
+ else
68
+ converge_by "creating resource" do
69
+ data = {}
70
+
71
+ new_resource.class.rest_property_map.each do |property, match_instruction|
72
+ deep_merge! data, property_to_json(property, match_instruction)
73
+ end
74
+
75
+ deep_compact!(data)
76
+
77
+ rest_post(data)
78
+ end
79
+ end
80
+ end
81
+
82
+ action :delete do
83
+ if resource_exists?
84
+ converge_by "deleting resource" do
85
+ rest_delete
86
+ end
87
+ else
88
+ logger.debug format("REST resource %<name>s of type %<type>s does not exist. Skipping.",
89
+ type: new_resource.name, name: id_property)
90
+ end
91
+ end
92
+
93
+ action_class do
94
+ # Override this for postprocessing device-specifics (paging, data conversion)
95
+ def rest_postprocess(response)
96
+ response
97
+ end
98
+
99
+ # Override this for error handling of device-specifics (readable error messages)
100
+ def rest_errorhandler(error_obj)
101
+ error_obj
102
+ end
103
+
104
+ private
105
+
106
+ def resource_exists?
107
+ @resource_exists
108
+ end
109
+
110
+ def required_properties
111
+ current_resource.class.properties.select { |_, v| v.required? }.except(:name).keys
112
+ end
113
+
114
+ # Return changed value or nil for delta current->new
115
+ def changed_value(property)
116
+ new_value = new_resource.send(property)
117
+ return new_value if current_resource.nil?
118
+
119
+ current_value = current_resource.send(property)
120
+
121
+ return current_value if required_properties.include? property
122
+
123
+ new_value == current_value ? nil : new_value
124
+ end
125
+
126
+ def id_property
127
+ current_resource.class.identity_attr
128
+ end
129
+
130
+ # Map properties to their current values
131
+ def property_map
132
+ map = {}
133
+
134
+ current_resource.class.state_properties.each do |property|
135
+ name = property.options[:name]
136
+
137
+ map[name] = current_resource.send(name)
138
+ end
139
+
140
+ map[id_property] = current_resource.send(id_property)
141
+
142
+ map
143
+ end
144
+
145
+ # Map part of a JSON (Hash) to resource property via JMESPath or user-supplied function
146
+ def json_to_property(match_instruction, property, resource_data)
147
+ case match_instruction
148
+ when String
149
+ JMESPath.search(match_instruction, resource_data)
150
+ when Symbol
151
+ function = "#{property}_from_json".to_sym
152
+ raise "#{new_resource.name} missing #{function} method" unless self.class.protected_method_defined?(function)
153
+
154
+ send(function, resource_data) || {}
155
+ else
156
+ raise TypeError, "Did not expect match type #{match_instruction.class}"
157
+ end
158
+ end
159
+
160
+ # Map resource contents into a JSON (Hash) via JMESPath-like syntax or user-supplied function
161
+ def property_to_json(property, match_instruction)
162
+ case match_instruction
163
+ when String
164
+ bury(match_instruction, changed_value(property))
165
+ when Symbol
166
+ function = "#{property}_to_json".to_sym
167
+ raise "#{new_resource.name} missing #{function} method" unless self.class.protected_method_defined?(function)
168
+
169
+ value = new_resource.send(property)
170
+ changed_value(property).nil? ? {} : send(function, value)
171
+ else
172
+ raise TypeError, "Did not expect match type #{match_instruction.class}"
173
+ end
174
+ end
175
+
176
+ def rest_url_collection
177
+ current_resource.class.rest_api_collection
178
+ end
179
+
180
+ # Resource document URL after RFC 6570 template evaluation via properties substitution
181
+ def rest_url_document
182
+ template = ::Addressable::Template.new(current_resource.class.rest_api_document)
183
+ template.expand(property_map).to_s
184
+ end
185
+
186
+ # Convenience method for conditional requires
187
+ def conditionally_require_on_setting(property, dependent_properties)
188
+ dependent_properties = Array(dependent_properties)
189
+
190
+ requirements.assert(:configure) do |a|
191
+ a.assertion do
192
+ # Needs to be set and truthy to require dependent properties
193
+ if new_resource.send(property)
194
+ dependent_properties.all? { |dep_prop| new_resource.property_is_set?(dep_prop) }
195
+ else
196
+ true
197
+ end
198
+ end
199
+
200
+ message = format("Setting property :%<property>s requires properties :%<properties>s to be set as well on resource %<resource_name>s",
201
+ property: property,
202
+ properties: dependent_properties.join(", :"),
203
+ resource_name: current_resource.to_s)
204
+
205
+ a.failure_message message
206
+ end
207
+ end
208
+
209
+ # Generic REST helpers
210
+
211
+ def rest_get_all
212
+ response = api_connection.get(rest_url_collection)
213
+
214
+ rest_postprocess(response)
215
+ rescue RestClient::Exception => e
216
+ rest_errorhandler(e)
217
+ end
218
+
219
+ def rest_get
220
+ response = api_connection.get(rest_url_document)
221
+
222
+ response = rest_postprocess(response)
223
+
224
+ first_only = current_resource.class.rest_api_document_first_element_only
225
+ response.data = response.data.first if first_only && response.data.is_a?(Array)
226
+
227
+ response
228
+ rescue RestClient::Exception => e
229
+ rest_errorhandler(e)
230
+ end
231
+
232
+ def rest_post(data)
233
+ data.merge! rest_identity_values
234
+
235
+ response = api_connection.post(rest_url_collection, data: data)
236
+
237
+ rest_postprocess(response)
238
+ rescue RestClient::Exception => e
239
+ rest_errorhandler(e)
240
+ end
241
+
242
+ def rest_put(data)
243
+ data.merge! rest_identity_values
244
+
245
+ response = api_connection.put(rest_url_collection, data: data)
246
+
247
+ rest_postprocess(response)
248
+ rescue RestClient::Exception => e
249
+ rest_errorhandler(e)
250
+ end
251
+
252
+ def rest_patch(data)
253
+ response = api_connection.patch(rest_url_document, data: data)
254
+
255
+ rest_postprocess(response)
256
+ rescue RestClient::Exception => e
257
+ rest_errorhandler(e)
258
+ end
259
+
260
+ def rest_delete
261
+ response = api_connection.delete(rest_url_document)
262
+
263
+ rest_postprocess(response)
264
+ rescue RestClient::Exception => e
265
+ rest_errorhandler(e)
266
+ end
267
+
268
+ # REST parameter mapping
269
+
270
+ # Return number of parameters needed to identify a resource (pre- and post-creation)
271
+ def rest_arity
272
+ rest_identity_map.keys.count
273
+ end
274
+
275
+ # Return mapping of template placeholders to property value of identity parameters
276
+ def rest_identity_values
277
+ data = {}
278
+
279
+ rest_identity_map.each do |rfc_template, property|
280
+ property_value = new_resource.send(property)
281
+ data.merge! bury(rfc_template, property_value)
282
+ end
283
+
284
+ data
285
+ end
286
+
287
+ def rest_identity_map
288
+ rest_identity_explicit || rest_identity_implicit
289
+ end
290
+
291
+ # Accept direct mapping like { "svm.name" => :name } for specifying the x-ary identity of a resource
292
+ def rest_identity_explicit
293
+ current_resource.class.rest_identity_map
294
+ end
295
+
296
+ # Parse document URL for RFC 6570 templates and map them to resource properties.
297
+ #
298
+ # Examples:
299
+ # Query based: "/api/protocols/san/igroups?name={name}&svm.name={svm}": { "name" => :name, "svm.name" => :svm }
300
+ # Path based: "/api/v1/{address}": { "address" => :address }
301
+ #
302
+ def rest_identity_implicit
303
+ template_url = current_resource.class.rest_api_document
304
+
305
+ rfc_template = ::Addressable::Template.new(template_url)
306
+ rfc_template_vars = rfc_template.variables
307
+
308
+ # Shortcut for 0-ary resources
309
+ return {} if rfc_template_vars.empty?
310
+
311
+ if query_based_selection?
312
+ uri_query = URI.parse(template_url).query
313
+
314
+ if CGI.parse(uri_query).values.any?(&:empty?)
315
+ raise "Need explicit identity mapping, as URL does not contain query parameters for all templates"
316
+ end
317
+
318
+ path_variables = CGI.parse(uri_query).keys
319
+ elsif path_based_selection?
320
+ path_variables = rfc_template_vars
321
+ else
322
+ # There is also
323
+ raise "Unknown type of resource selection. Document URL does not seem to be path- or query-based?"
324
+ end
325
+
326
+ identity_map = {}
327
+ path_variables.each_with_index do |v, i|
328
+ next if rfc_template_vars[i].nil? # Not mapped to property, assume metaparameter
329
+
330
+ identity_map[v] = rfc_template_vars[i].to_sym
331
+ end
332
+
333
+ identity_map
334
+ end
335
+
336
+ def query_based_selection?
337
+ template_url = current_resource.class.rest_api_document
338
+
339
+ # Will throw exception on presence of RFC 6570 templates
340
+ URI.parse(template_url)
341
+ true
342
+ rescue URI::InvalidURIError => _e
343
+ false
344
+ end
345
+
346
+ def path_based_selection?
347
+ !query_based_selection?
348
+ end
349
+
350
+ def api_connection
351
+ Chef.run_context.transport.connection
352
+ end
353
+
354
+ # Remove all empty keys (recusively) from Hash.
355
+ # @see https://stackoverflow.com/questions/56457020/#answer-56458673
356
+ def deep_compact!(hsh)
357
+ raise TypeError unless hsh.is_a? Hash
358
+
359
+ hsh.each do |_, v|
360
+ deep_compact!(v) if v.is_a? Hash
361
+ end.reject! { |_, v| v.nil? || (v.respond_to?(:empty?) && v.empty?) }
362
+ end
363
+
364
+ # Deep merge two hashes
365
+ # @see https://stackoverflow.com/questions/41109599#answer-41109737
366
+ def deep_merge!(hsh1, hsh2)
367
+ raise TypeError unless hsh1.is_a?(Hash) && hsh2.is_a?(Hash)
368
+
369
+ hsh1.merge!(hsh2) { |_, v1, v2| deep_merge!(v1, v2) }
370
+ end
371
+
372
+ # Create nested hashes from JMESPath syntax.
373
+ def bury(path, value)
374
+ raise TypeError unless path.is_a?(String)
375
+
376
+ arr = path.split(".")
377
+ ret = {}
378
+
379
+ if arr.count == 1
380
+ ret[arr.first] = value
381
+
382
+ ret
383
+ else
384
+ partial_path = arr[0..-2].join(".")
385
+
386
+ bury(partial_path, bury(arr.last, value))
387
+ end
388
+ end
389
+ end
@@ -22,7 +22,6 @@ require_relative "../resource"
22
22
  class Chef
23
23
  class Resource
24
24
  class Alternatives < Chef::Resource
25
- unified_mode true
26
25
 
27
26
  provides(:alternatives) { true }
28
27
 
@@ -21,7 +21,6 @@ require_relative "package"
21
21
  class Chef
22
22
  class Resource
23
23
  class AptPackage < Chef::Resource::Package
24
- unified_mode true
25
24
 
26
25
  provides :apt_package, target_mode: true
27
26
  provides :package, platform_family: "debian", target_mode: true
@@ -21,7 +21,6 @@ require_relative "../resource"
21
21
  class Chef
22
22
  class Resource
23
23
  class AptPreference < Chef::Resource
24
- unified_mode true
25
24
 
26
25
  provides(:apt_preference) { true }
27
26
 
@@ -26,7 +26,6 @@ end
26
26
  class Chef
27
27
  class Resource
28
28
  class AptRepository < Chef::Resource
29
- unified_mode true
30
29
 
31
30
  provides(:apt_repository) { true }
32
31
 
@@ -22,7 +22,6 @@ require "chef-utils/dist" unless defined?(ChefUtils::Dist)
22
22
  class Chef
23
23
  class Resource
24
24
  class AptUpdate < Chef::Resource
25
- unified_mode true
26
25
 
27
26
  provides(:apt_update) { true }
28
27
 
@@ -30,7 +30,6 @@ end
30
30
  class Chef
31
31
  class Resource
32
32
  class ArchiveFile < Chef::Resource
33
- unified_mode true
34
33
 
35
34
  provides :archive_file
36
35
  provides :libarchive_file # legacy cookbook name
@@ -21,7 +21,6 @@ require_relative "script"
21
21
  class Chef
22
22
  class Resource
23
23
  class Bash < Chef::Resource::Script
24
- unified_mode true
25
24
 
26
25
  provides :bash
27
26
 
@@ -21,7 +21,6 @@ require_relative "windows_script"
21
21
  class Chef
22
22
  class Resource
23
23
  class Batch < Chef::Resource::WindowsScript
24
- unified_mode true
25
24
 
26
25
  provides :batch
27
26
 
@@ -22,7 +22,6 @@ require "chef-utils/dist" unless defined?(ChefUtils::Dist)
22
22
  class Chef
23
23
  class Resource
24
24
  class BffPackage < Chef::Resource::Package
25
- unified_mode true
26
25
 
27
26
  provides :bff_package
28
27
 
@@ -22,7 +22,6 @@ require "chef-utils/dist" unless defined?(ChefUtils::Dist)
22
22
  class Chef
23
23
  class Resource
24
24
  class Breakpoint < Chef::Resource
25
- unified_mode true
26
25
 
27
26
  provides :breakpoint, target_mode: true
28
27
 
@@ -19,7 +19,6 @@ require_relative "../resource"
19
19
  class Chef
20
20
  class Resource
21
21
  class BuildEssential < Chef::Resource
22
- unified_mode true
23
22
 
24
23
  provides(:build_essential) { true }
25
24
 
@@ -23,7 +23,6 @@ class Chef
23
23
  class Resource
24
24
  class CabPackage < Chef::Resource::Package
25
25
  include Chef::Mixin::Uris
26
- unified_mode true
27
26
 
28
27
  provides :cab_package
29
28
 
@@ -20,7 +20,6 @@ require "chef-utils/dist" unless defined?(ChefUtils::Dist)
20
20
  class Chef
21
21
  class Resource
22
22
  class ChefClientConfig < Chef::Resource
23
- unified_mode true
24
23
 
25
24
  provides :chef_client_config
26
25
 
@@ -209,6 +208,10 @@ class Chef
209
208
  description: %q(An array of hashes that contain a report handler class and the arguments to pass to that class on initialization. The hash should include `class` and `argument` keys where `class` is a String and `argument` is an array of quoted String values. For example: `[{'class' => 'MyHandler', %w('"argument1"', '"argument2"')}]`),
210
209
  default: []
211
210
 
211
+ property :rubygems_url, [String, Array],
212
+ description: "The location to source rubygems. It can be set to a string or array of strings for URIs to set as rubygems sources. This allows individuals to setup an internal mirror of rubygems for “airgapped” environments.",
213
+ introduced: "17.11"
214
+
212
215
  property :exception_handlers, Array,
213
216
  description: %q(An array of hashes that contain a exception handler class and the arguments to pass to that class on initialization. The hash should include `class` and `argument` keys where `class` is a String and `argument` is an array of quoted String values. For example: `[{'class' => 'MyHandler', %w('"argument1"', '"argument2"')}]`),
214
217
  default: []
@@ -249,21 +252,20 @@ class Chef
249
252
  description: "The data collector token to interact with the data collector server URL (Automate). Note: If possible, use Chef Infra Server to do all data collection reporting, as this removes the need to distribute tokens to individual nodes.",
250
253
  introduced: "17.8"
251
254
 
252
- action :create, description: "Create a client.rb config file for configuring #{ChefUtils::Dist::Infra::PRODUCT}." do
253
- unless ::Dir.exist?(new_resource.config_directory)
254
- directory new_resource.config_directory do
255
- user new_resource.user unless new_resource.user.nil?
256
- group new_resource.group unless new_resource.group.nil?
257
- mode "0750"
258
- recursive true
259
- end
260
- end
261
-
262
- unless ::Dir.exist?(::File.join(new_resource.config_directory, "client.d"))
263
- directory ::File.join(new_resource.config_directory, "client.d") do
255
+ action :create, description: "Create a client.rb config file and folders for configuring #{ChefUtils::Dist::Infra::PRODUCT}." do
256
+ [
257
+ new_resource.config_directory,
258
+ (::File.dirname(new_resource.log_location) unless new_resource.log_location.nil?),
259
+ new_resource.file_backup_path,
260
+ new_resource.file_cache_path,
261
+ ::File.join(new_resource.config_directory, "client.d"),
262
+ (::File.dirname(new_resource.pid_file) unless new_resource.pid_file.nil?),
263
+ ].compact.each do |dir_path|
264
+
265
+ directory dir_path do
264
266
  user new_resource.user unless new_resource.user.nil?
265
267
  group new_resource.group unless new_resource.group.nil?
266
- mode "0750"
268
+ mode dir_path == ::File.dirname(new_resource.log_location) ? "0755" : "0750"
267
269
  recursive true
268
270
  end
269
271
  end
@@ -297,6 +299,7 @@ class Chef
297
299
  policy_group: new_resource.policy_group,
298
300
  policy_name: new_resource.policy_name,
299
301
  report_handlers: format_handler(new_resource.report_handlers),
302
+ rubygems_url: new_resource.rubygems_url,
300
303
  ssl_verify_mode: new_resource.ssl_verify_mode,
301
304
  start_handlers: format_handler(new_resource.start_handlers),
302
305
  additional_config: new_resource.additional_config,
@@ -22,7 +22,6 @@ require "digest/md5" unless defined?(Digest::MD5)
22
22
  class Chef
23
23
  class Resource
24
24
  class ChefClientCron < Chef::Resource
25
- unified_mode true
26
25
 
27
26
  provides :chef_client_cron
28
27
 
@@ -99,7 +98,7 @@ class Chef
99
98
  property :splay, [Integer, String],
100
99
  default: 300,
101
100
  coerce: proc { |x| Integer(x) },
102
- callbacks: { "should be a positive number" => proc { |v| v > 0 } },
101
+ callbacks: { "should be a positive number" => proc { |v| v >= 0 } },
103
102
  description: "A random number of seconds between 0 and X to add to interval so that all #{ChefUtils::Dist::Infra::CLIENT} commands don't execute at the same time."
104
103
 
105
104
  property :mailto, String,
@@ -19,7 +19,6 @@ require "chef-utils/dist" unless defined?(ChefUtils::Dist)
19
19
  class Chef
20
20
  class Resource
21
21
  class ChefClientLaunchd < Chef::Resource
22
- unified_mode true
23
22
 
24
23
  provides :chef_client_launchd
25
24
 
@@ -61,7 +60,7 @@ class Chef
61
60
  property :splay, [Integer, String],
62
61
  default: 300,
63
62
  coerce: proc { |x| Integer(x) },
64
- callbacks: { "should be a positive number" => proc { |v| v > 0 } },
63
+ callbacks: { "should be a positive number" => proc { |v| v >= 0 } },
65
64
  description: "A random number of seconds between 0 and X to add to interval so that all #{ChefUtils::Dist::Infra::CLIENT} commands don't execute at the same time."
66
65
 
67
66
  property :accept_chef_license, [true, false],
@@ -135,6 +134,7 @@ class Chef
135
134
  program_arguments ["/bin/bash",
136
135
  "-c",
137
136
  "echo; echo #{ChefUtils::Dist::Infra::PRODUCT} launchd daemon config has been updated. Manually unloading and reloading the daemon; echo Now unloading the daemon; sudo /bin/launchctl unload /Library/LaunchDaemons/com.#{ChefUtils::Dist::Infra::SHORT}.#{ChefUtils::Dist::Infra::CLIENT}.plist; sleep 2; echo Now loading the daemon; sudo /bin/launchctl load /Library/LaunchDaemons/com.#{ChefUtils::Dist::Infra::SHORT}.#{ChefUtils::Dist::Infra::CLIENT}.plist"]
137
+ run_at_load true
138
138
  action :enable # enable creates the plist & triggers service restarts on change
139
139
  end
140
140
 
@@ -20,7 +20,6 @@ require "chef-utils/dist" unless defined?(ChefUtils::Dist)
20
20
  class Chef
21
21
  class Resource
22
22
  class ChefClientScheduledTask < Chef::Resource
23
- unified_mode true
24
23
 
25
24
  provides :chef_client_scheduled_task
26
25
 
@@ -108,7 +107,7 @@ class Chef
108
107
 
109
108
  property :splay, [Integer, String],
110
109
  coerce: proc { |x| Integer(x) },
111
- callbacks: { "should be a positive number" => proc { |v| v > 0 } },
110
+ callbacks: { "should be a positive number" => proc { |v| v >= 0 } },
112
111
  description: "A random number of seconds between 0 and X to add to interval so that all #{ChefUtils::Dist::Infra::CLIENT} commands don't execute at the same time.",
113
112
  default: 300
114
113
 
@@ -123,7 +122,8 @@ class Chef
123
122
 
124
123
  property :config_directory, String,
125
124
  description: "The path of the config directory.",
126
- default: ChefConfig::Config.etc_chef_dir
125
+ default: ChefConfig::Config.etc_chef_dir,
126
+ default_description: ChefConfig::Config.c_chef_dir
127
127
 
128
128
  property :log_directory, String,
129
129
  description: "The path of the directory to create the log file in.",
@@ -20,7 +20,6 @@ require "chef-utils/dist" unless defined?(ChefUtils::Dist)
20
20
  class Chef
21
21
  class Resource
22
22
  class ChefClientSystemdTimer < Chef::Resource
23
- unified_mode true
24
23
 
25
24
  provides :chef_client_systemd_timer
26
25
 
@@ -20,7 +20,6 @@ require "chef-utils/dist" unless defined?(ChefUtils::Dist)
20
20
  class Chef
21
21
  class Resource
22
22
  class ChefClientTrustedCertificate < Chef::Resource
23
- unified_mode true
24
23
 
25
24
  provides :chef_client_trusted_certificate
26
25
 
@@ -23,7 +23,6 @@ require "chef-utils/dist" unless defined?(ChefUtils::Dist)
23
23
  class Chef
24
24
  class Resource
25
25
  class ChefGem < Chef::Resource::Package::GemPackage
26
- unified_mode true
27
26
  provides :chef_gem
28
27
 
29
28
  description <<~DESC
@@ -21,7 +21,6 @@ require "chef-utils/dist" unless defined?(ChefUtils::Dist)
21
21
  class Chef
22
22
  class Resource
23
23
  class ChefHandler < Chef::Resource
24
- unified_mode true
25
24
 
26
25
  provides(:chef_handler) { true }
27
26
 
@@ -22,8 +22,6 @@ class Chef
22
22
  class ChefSleep < Chef::Resource
23
23
  provides :chef_sleep
24
24
 
25
- unified_mode true
26
-
27
25
  description "Use the **chef_sleep** resource to pause (sleep) for a number of seconds during a #{ChefUtils::Dist::Infra::PRODUCT} run. Only use this resource when a command or service exits successfully but is not ready for the next step in a recipe."
28
26
  introduced "15.5"
29
27
  examples <<~DOC
@@ -47,7 +45,7 @@ class Chef
47
45
  service 'Service that is slow to start and reports as started' do
48
46
  service_name 'my_database'
49
47
  action :start
50
- notifies :sleep, chef_sleep['wait for service start']
48
+ notifies :sleep, 'chef_sleep[wait for service start]'
51
49
  end
52
50
 
53
51
  chef_sleep 'wait for service start' do