chef 12.5.1 → 12.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (221) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +6 -1
  3. data/README.md +6 -4
  4. data/Rakefile +1 -4
  5. data/chef-windows.gemspec +21 -0
  6. data/chef.gemspec +58 -0
  7. data/lib/chef/api_client/registration.rb +9 -4
  8. data/lib/chef/application.rb +3 -84
  9. data/lib/chef/application/apply.rb +9 -2
  10. data/lib/chef/application/client.rb +8 -3
  11. data/lib/chef/application/solo.rb +7 -1
  12. data/lib/chef/application/windows_service.rb +21 -6
  13. data/lib/chef/application/windows_service_manager.rb +2 -3
  14. data/lib/chef/audit/runner.rb +1 -0
  15. data/lib/chef/chef_class.rb +1 -11
  16. data/lib/chef/chef_fs/chef_fs_data_store.rb +181 -2
  17. data/lib/chef/chef_fs/file_system/cookbook_subdir.rb +5 -0
  18. data/lib/chef/chef_fs/file_system/file_system_entry.rb +11 -7
  19. data/lib/chef/client.rb +28 -1
  20. data/lib/chef/cookbook/cookbook_collection.rb +14 -1
  21. data/lib/chef/cookbook/cookbook_version_loader.rb +1 -1
  22. data/lib/chef/cookbook/metadata.rb +115 -9
  23. data/lib/chef/cookbook/remote_file_vendor.rb +1 -1
  24. data/lib/chef/cookbook_version.rb +6 -2
  25. data/lib/chef/data_bag.rb +1 -1
  26. data/lib/chef/data_bag_item.rb +1 -1
  27. data/lib/chef/digester.rb +5 -1
  28. data/lib/chef/dsl/chef_provisioning.rb +57 -0
  29. data/lib/chef/dsl/cheffish.rb +64 -0
  30. data/lib/chef/dsl/declare_resource.rb +108 -0
  31. data/lib/chef/dsl/platform_introspection.rb +3 -3
  32. data/lib/chef/dsl/recipe.rb +3 -73
  33. data/lib/chef/dsl/resources.rb +27 -1
  34. data/lib/chef/event_dispatch/base.rb +3 -0
  35. data/lib/chef/event_dispatch/dispatcher.rb +5 -0
  36. data/lib/chef/event_dispatch/events_output_stream.rb +8 -0
  37. data/lib/chef/exceptions.rb +21 -1
  38. data/lib/chef/file_access_control/unix.rb +12 -12
  39. data/lib/chef/file_content_management/deploy/cp.rb +2 -2
  40. data/lib/chef/file_content_management/deploy/mv_unix.rb +4 -4
  41. data/lib/chef/file_content_management/deploy/mv_windows.rb +1 -1
  42. data/lib/chef/formatters/base.rb +7 -0
  43. data/lib/chef/formatters/error_inspectors/compile_error_inspector.rb +2 -2
  44. data/lib/chef/formatters/indentable_output_stream.rb +5 -0
  45. data/lib/chef/http.rb +19 -3
  46. data/lib/chef/http/decompressor.rb +2 -2
  47. data/lib/chef/json_compat.rb +1 -0
  48. data/lib/chef/knife.rb +16 -2
  49. data/lib/chef/knife/bootstrap.rb +55 -10
  50. data/lib/chef/knife/cookbook_site_install.rb +5 -1
  51. data/lib/chef/knife/core/bootstrap_context.rb +2 -1
  52. data/lib/chef/knife/core/node_presenter.rb +1 -1
  53. data/lib/chef/knife/ssh.rb +30 -16
  54. data/lib/chef/knife/ssl_check.rb +4 -2
  55. data/lib/chef/knife/ssl_fetch.rb +3 -2
  56. data/lib/chef/knife/status.rb +14 -1
  57. data/lib/chef/log.rb +14 -0
  58. data/lib/chef/mixin/get_source_from_package.rb +7 -2
  59. data/lib/chef/mixin/properties.rb +302 -0
  60. data/lib/chef/mixin/proxified_socket.rb +38 -0
  61. data/lib/chef/mixin/subclass_directive.rb +37 -0
  62. data/lib/chef/node.rb +13 -5
  63. data/lib/chef/platform/query_helpers.rb +14 -3
  64. data/lib/chef/platform/service_helpers.rb +20 -38
  65. data/lib/chef/policy_builder/expand_node_object.rb +3 -0
  66. data/lib/chef/policy_builder/policyfile.rb +1 -0
  67. data/lib/chef/property.rb +51 -12
  68. data/lib/chef/provider.rb +40 -35
  69. data/lib/chef/provider/deploy.rb +1 -1
  70. data/lib/chef/provider/dsc_resource.rb +54 -20
  71. data/lib/chef/provider/execute.rb +25 -4
  72. data/lib/chef/provider/group.rb +1 -1
  73. data/lib/chef/provider/lwrp_base.rb +1 -0
  74. data/lib/chef/provider/package.rb +76 -30
  75. data/lib/chef/provider/package/dpkg.rb +152 -69
  76. data/lib/chef/provider/package/openbsd.rb +6 -8
  77. data/lib/chef/provider/package/solaris.rb +2 -0
  78. data/lib/chef/provider/package/windows.rb +95 -14
  79. data/lib/chef/provider/package/windows/exe.rb +129 -0
  80. data/lib/chef/provider/package/windows/msi.rb +37 -13
  81. data/lib/chef/provider/package/windows/registry_uninstall_entry.rb +89 -0
  82. data/lib/chef/provider/package/yum.rb +13 -3
  83. data/lib/chef/provider/powershell_script.rb +3 -0
  84. data/lib/chef/provider/remote_file/cache_control_data.rb +37 -4
  85. data/lib/chef/provider/remote_file/http.rb +1 -1
  86. data/lib/chef/provider/script.rb +1 -0
  87. data/lib/chef/provider/service.rb +13 -10
  88. data/lib/chef/provider/service/solaris.rb +43 -17
  89. data/lib/chef/provider/service/upstart.rb +3 -3
  90. data/lib/chef/provider/user.rb +1 -1
  91. data/lib/chef/provider/user/dscl.rb +111 -100
  92. data/lib/chef/provider/user/windows.rb +5 -3
  93. data/lib/chef/recipe.rb +3 -5
  94. data/lib/chef/resource.rb +77 -320
  95. data/lib/chef/resource/action_class.rb +4 -0
  96. data/lib/chef/resource/dpkg_package.rb +4 -3
  97. data/lib/chef/resource/dsc_resource.rb +40 -2
  98. data/lib/chef/resource/execute.rb +9 -1
  99. data/lib/chef/resource/ksh.rb +32 -0
  100. data/lib/chef/resource/lwrp_base.rb +6 -10
  101. data/lib/chef/resource/package.rb +8 -9
  102. data/lib/chef/resource/registry_key.rb +1 -1
  103. data/lib/chef/resource/resource_notification.rb +14 -1
  104. data/lib/chef/resource/script.rb +1 -1
  105. data/lib/chef/resource/windows_package.rb +1 -1
  106. data/lib/chef/resource_builder.rb +14 -7
  107. data/lib/chef/resource_reporter.rb +6 -0
  108. data/lib/chef/resources.rb +1 -7
  109. data/lib/chef/rest.rb +1 -1
  110. data/lib/chef/run_context.rb +45 -2
  111. data/lib/chef/run_list/run_list_expansion.rb +47 -0
  112. data/lib/chef/runner.rb +25 -0
  113. data/lib/chef/search/query.rb +16 -2
  114. data/lib/chef/util/diff.rb +2 -2
  115. data/lib/chef/util/powershell/ps_credential.rb +2 -3
  116. data/lib/chef/version.rb +1 -1
  117. data/lib/chef/win32/api/file.rb +51 -1
  118. data/lib/chef/win32/file.rb +5 -0
  119. data/lib/chef/win32/file/version_info.rb +93 -0
  120. data/lib/chef/win32/mutex.rb +1 -1
  121. data/spec/data/apt/chef-integration-test2-1.0/debian/changelog +5 -0
  122. data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.debhelper.log +45 -0
  123. data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.substvars +1 -0
  124. data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/conffiles +1 -0
  125. data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/control +10 -0
  126. data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/md5sums +1 -0
  127. data/spec/data/apt/chef-integration-test2-1.0/debian/compat +1 -0
  128. data/spec/data/apt/chef-integration-test2-1.0/debian/conffiles +1 -0
  129. data/spec/data/apt/chef-integration-test2-1.0/debian/control +13 -0
  130. data/spec/data/apt/chef-integration-test2-1.0/debian/copyright +34 -0
  131. data/spec/data/apt/chef-integration-test2-1.0/debian/files +1 -0
  132. data/spec/data/apt/chef-integration-test2-1.0/debian/rules +13 -0
  133. data/spec/data/apt/chef-integration-test2-1.0/debian/source/format +1 -0
  134. data/spec/data/apt/chef-integration-test2_1.0-1.debian.tar.gz +0 -0
  135. data/spec/data/apt/chef-integration-test2_1.0-1.dsc +18 -0
  136. data/spec/data/apt/chef-integration-test2_1.0-1_amd64.build +91 -0
  137. data/spec/data/apt/chef-integration-test2_1.0-1_amd64.changes +31 -0
  138. data/spec/data/apt/chef-integration-test2_1.0-1_amd64.deb +0 -0
  139. data/spec/data/apt/chef-integration-test2_1.0.orig.tar.gz +0 -0
  140. data/spec/functional/application_spec.rb +1 -1
  141. data/spec/functional/audit/runner_spec.rb +4 -0
  142. data/spec/functional/knife/ssh_spec.rb +5 -5
  143. data/spec/functional/notifications_spec.rb +74 -4
  144. data/spec/functional/resource/aix_service_spec.rb +2 -2
  145. data/spec/functional/resource/dpkg_package_spec.rb +339 -0
  146. data/spec/functional/resource/ifconfig_spec.rb +3 -1
  147. data/spec/functional/resource/mount_spec.rb +5 -2
  148. data/spec/functional/resource/package_spec.rb +1 -1
  149. data/spec/functional/resource/user/windows_spec.rb +8 -0
  150. data/spec/functional/resource/windows_package_spec.rb +177 -0
  151. data/spec/functional/win32/version_info_spec.rb +50 -0
  152. data/spec/integration/client/client_spec.rb +80 -0
  153. data/spec/integration/knife/download_spec.rb +9 -0
  154. data/spec/integration/knife/upload_spec.rb +28 -1
  155. data/spec/integration/recipes/lwrp_inline_resources_spec.rb +93 -23
  156. data/spec/integration/recipes/resource_action_spec.rb +211 -116
  157. data/spec/integration/recipes/resource_converge_if_changed_spec.rb +72 -0
  158. data/spec/integration/solo/solo_spec.rb +34 -0
  159. data/spec/spec_helper.rb +11 -1
  160. data/spec/support/platform_helpers.rb +8 -0
  161. data/spec/support/shared/integration/integration_helper.rb +6 -0
  162. data/spec/support/shared/unit/execute_resource.rb +5 -0
  163. data/spec/support/shared/unit/platform_introspector.rb +7 -0
  164. data/spec/tiny_server.rb +6 -2
  165. data/spec/unit/api_client/registration_spec.rb +5 -4
  166. data/spec/unit/application_spec.rb +1 -181
  167. data/spec/unit/chef_fs/file_system/cookbook_subdir_spec.rb +34 -0
  168. data/spec/unit/cookbook/metadata_spec.rb +122 -2
  169. data/spec/unit/http_spec.rb +102 -0
  170. data/spec/unit/knife/bootstrap_spec.rb +55 -13
  171. data/spec/unit/knife/core/bootstrap_context_spec.rb +10 -3
  172. data/spec/unit/knife/ssl_check_spec.rb +7 -3
  173. data/spec/unit/knife/ssl_fetch_spec.rb +2 -2
  174. data/spec/unit/knife/status_spec.rb +13 -13
  175. data/spec/unit/knife_spec.rb +26 -2
  176. data/spec/unit/lwrp_spec.rb +1 -1
  177. data/spec/unit/mixin/properties_spec.rb +97 -0
  178. data/spec/unit/mixin/proxified_socket_spec.rb +94 -0
  179. data/spec/unit/mixin/subclass_directive_spec.rb +45 -0
  180. data/spec/unit/node_spec.rb +9 -1
  181. data/spec/unit/policy_builder/policyfile_spec.rb +2 -0
  182. data/spec/unit/property/validation_spec.rb +14 -12
  183. data/spec/unit/property_spec.rb +56 -0
  184. data/spec/unit/provider/deploy_spec.rb +1 -1
  185. data/spec/unit/provider/dsc_resource_spec.rb +63 -24
  186. data/spec/unit/provider/execute_spec.rb +95 -28
  187. data/spec/unit/provider/package/dpkg_spec.rb +185 -96
  188. data/spec/unit/provider/package/windows/exe_spec.rb +251 -0
  189. data/spec/unit/provider/package/windows/msi_spec.rb +94 -10
  190. data/spec/unit/provider/package/windows_spec.rb +227 -26
  191. data/spec/unit/provider/package/yum_spec.rb +6 -0
  192. data/spec/unit/provider/package_spec.rb +495 -366
  193. data/spec/unit/provider/remote_file/cache_control_data_spec.rb +62 -36
  194. data/spec/unit/provider/script_spec.rb +2 -2
  195. data/spec/unit/provider/service/solaris_smf_service_spec.rb +110 -39
  196. data/spec/unit/provider/service/upstart_service_spec.rb +19 -0
  197. data/spec/unit/provider/user/dscl_spec.rb +14 -0
  198. data/spec/unit/provider/user/windows_spec.rb +2 -2
  199. data/spec/unit/provider/user_spec.rb +9 -0
  200. data/spec/unit/provider_resolver_spec.rb +6 -30
  201. data/spec/unit/recipe_spec.rb +46 -20
  202. data/spec/unit/resource/chef_gem_spec.rb +1 -1
  203. data/spec/unit/resource/dsc_resource_spec.rb +14 -3
  204. data/spec/unit/resource/ksh_spec.rb +40 -0
  205. data/spec/unit/resource/registry_key_spec.rb +2 -2
  206. data/spec/unit/resource/resource_notification_spec.rb +44 -45
  207. data/spec/unit/resource_reporter_spec.rb +7 -0
  208. data/spec/unit/resource_spec.rb +268 -253
  209. data/spec/unit/rest_spec.rb +2 -2
  210. data/spec/unit/run_list/run_list_expansion_spec.rb +18 -3
  211. data/spec/unit/search/query_spec.rb +19 -1
  212. data/spec/unit/util/powershell/ps_credential_spec.rb +8 -1
  213. data/spec/unit/windows_service_spec.rb +83 -38
  214. data/tasks/external_tests.rb +19 -9
  215. data/tasks/rspec.rb +1 -1
  216. metadata +64 -15
  217. data/spec/support/pedant/Gemfile +0 -3
  218. data/spec/support/pedant/pedant_config.rb +0 -129
  219. data/spec/support/pedant/run_pedant.rb +0 -63
  220. data/spec/support/pedant/stickywicket.pem +0 -27
  221. data/spec/unit/provider/package_spec.rbe +0 -0
@@ -276,7 +276,7 @@ class Chef
276
276
 
277
277
  def enforce_ownership
278
278
  converge_by("force ownership of #{@new_resource.deploy_to} to #{@new_resource.group}:#{@new_resource.user}") do
279
- FileUtils.chown_R(@new_resource.user, @new_resource.group, @new_resource.deploy_to)
279
+ FileUtils.chown_R(@new_resource.user, @new_resource.group, @new_resource.deploy_to, :force => true)
280
280
  Chef::Log.info("#{@new_resource} set user to #{@new_resource.user}") if @new_resource.user
281
281
  Chef::Log.info("#{@new_resource} set group to #{@new_resource.group}") if @new_resource.group
282
282
  end
@@ -15,7 +15,6 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
  #
18
-
19
18
  require 'chef/util/powershell/cmdlet'
20
19
  require 'chef/util/dsc/local_configuration_manager'
21
20
  require 'chef/mixin/powershell_type_coercions'
@@ -25,19 +24,19 @@ class Chef
25
24
  class Provider
26
25
  class DscResource < Chef::Provider
27
26
  include Chef::Mixin::PowershellTypeCoercions
28
-
29
27
  provides :dsc_resource, os: "windows"
30
-
31
28
  def initialize(new_resource, run_context)
32
29
  super
33
30
  @new_resource = new_resource
34
31
  @module_name = new_resource.module_name
32
+ @reboot_resource = nil
35
33
  end
36
34
 
37
35
  def action_run
38
36
  if ! test_resource
39
37
  converge_by(generate_description) do
40
38
  result = set_resource
39
+ reboot_if_required
41
40
  end
42
41
  end
43
42
  end
@@ -59,8 +58,9 @@ class Chef
59
58
  a.block_action!
60
59
  end
61
60
  requirements.assert(:run) do |a|
62
- a.assertion { dsc_refresh_mode_disabled? }
63
- err = ["The LCM must have its RefreshMode set to Disabled. "]
61
+ a.assertion { supports_refresh_mode_enabled? || dsc_refresh_mode_disabled? }
62
+ err = ["The LCM must have its RefreshMode set to Disabled for" \
63
+ " PowerShell versions before 5.0.10586.0."]
64
64
  a.failure_message Chef::Exceptions::ProviderNotFound, err.join(' ')
65
65
  a.whyrun err + ["Assuming a previous resource sets the RefreshMode."]
66
66
  a.block_action!
@@ -83,11 +83,15 @@ class Chef
83
83
  def supports_dsc_invoke_resource?
84
84
  run_context && Chef::Platform.supports_dsc_invoke_resource?(node)
85
85
  end
86
-
86
+
87
87
  def dsc_refresh_mode_disabled?
88
88
  Chef::Platform.dsc_refresh_mode_disabled?(node)
89
89
  end
90
90
 
91
+ def supports_refresh_mode_enabled?
92
+ Chef::Platform.supports_refresh_mode_enabled?(node)
93
+ end
94
+
91
95
  def generate_description
92
96
  @converge_description
93
97
  end
@@ -99,7 +103,6 @@ class Chef
99
103
  def module_name
100
104
  @module_name ||= begin
101
105
  found = resource_store.find(dsc_resource_name)
102
-
103
106
  r = case found.length
104
107
  when 0
105
108
  raise Chef::Exceptions::ResourceNotFound,
@@ -119,22 +122,23 @@ class Chef
119
122
 
120
123
  def test_resource
121
124
  result = invoke_resource(:test)
122
- # We really want this information from the verbose stream,
123
- # however Invoke-DscResource is not correctly writing to that
124
- # stream and instead just dumping to stdout
125
- @converge_description = result.stdout
125
+ @converge_description = result.stream(:verbose)
126
126
 
127
- if result.return_value.is_a?(Array)
128
- # WMF Feb 2015 Preview
129
- result.return_value[0]["InDesiredState"]
130
- else
131
- # WMF April 2015 Preview
132
- result.return_value["InDesiredState"]
127
+ # We really want this information from the verbose stream,
128
+ # however in some versions of WMF, Invoke-DscResource is not correctly
129
+ # writing to that stream and instead just dumping to stdout
130
+ if @converge_description.empty?
131
+ @converge_description = result.stdout
133
132
  end
133
+
134
+ return_dsc_resource_result(result, "InDesiredState")
134
135
  end
135
136
 
136
137
  def set_resource
137
138
  result = invoke_resource(:set)
139
+ if return_dsc_resource_result(result, 'RebootRequired')
140
+ create_reboot_resource
141
+ end
138
142
  result.return_value
139
143
  end
140
144
 
@@ -142,19 +146,49 @@ class Chef
142
146
  properties = translate_type(@new_resource.properties)
143
147
  switches = "-Method #{method.to_s} -Name #{@new_resource.resource}"\
144
148
  " -Property #{properties} -Verbose"
145
-
146
149
  if module_name != :none
147
150
  switches += " -Module #{module_name}"
148
151
  end
149
-
150
152
  cmdlet = Chef::Util::Powershell::Cmdlet.new(
151
153
  node,
152
154
  "Invoke-DscResource #{switches}",
153
155
  output_format
154
156
  )
155
- cmdlet.run!
157
+ cmdlet.run!({}, {:timeout => new_resource.timeout})
156
158
  end
157
159
 
160
+ def return_dsc_resource_result(result, property_name)
161
+ if result.return_value.is_a?(Array)
162
+ # WMF Feb 2015 Preview
163
+ result.return_value[0][property_name]
164
+ else
165
+ # WMF April 2015 Preview
166
+ result.return_value[property_name]
167
+ end
168
+ end
169
+
170
+ def create_reboot_resource
171
+ @reboot_resource = Chef::Resource::Reboot.new(
172
+ "Reboot for #{@new_resource.name}",
173
+ run_context
174
+ ).tap do |r|
175
+ r.reason("Reboot for #{@new_resource.resource}.")
176
+ end
177
+ end
178
+
179
+ def reboot_if_required
180
+ reboot_action = @new_resource.reboot_action
181
+ unless @reboot_resource.nil?
182
+ case reboot_action
183
+ when :nothing
184
+ Chef::Log.debug("A reboot was requested by the DSC resource, but reboot_action is :nothing.")
185
+ Chef::Log.debug("This dsc_resource will not reboot the node.")
186
+ else
187
+ Chef::Log.debug("Requesting node reboot with #{reboot_action}.")
188
+ @reboot_resource.run_action(reboot_action)
189
+ end
190
+ end
191
+ end
158
192
  end
159
193
  end
160
194
  end
@@ -41,7 +41,7 @@ class Chef
41
41
  def define_resource_requirements
42
42
  # @todo: this should change to raise in some appropriate major version bump.
43
43
  if creates && creates_relative? && !cwd
44
- Chef::Log.warn "Providing a relative path for the creates attribute without the cwd is deprecated and will be changed to fail (CHEF-3819)"
44
+ Chef::Log.warn "Providing a relative path for the creates attribute without the cwd is deprecated and will be changed to fail in the future (CHEF-3819)"
45
45
  end
46
46
  end
47
47
 
@@ -58,7 +58,16 @@ class Chef
58
58
  end
59
59
 
60
60
  converge_by("execute #{description}") do
61
- result = shell_out!(command, opts)
61
+ begin
62
+ shell_out!(command, opts)
63
+ rescue Mixlib::ShellOut::ShellCommandFailed
64
+ if sensitive?
65
+ raise Mixlib::ShellOut::ShellCommandFailed,
66
+ "Command execution failed. STDOUT/STDERR suppressed for sensitive resource"
67
+ else
68
+ raise
69
+ end
70
+ end
62
71
  Chef::Log.info("#{new_resource} ran successfully")
63
72
  end
64
73
  end
@@ -69,6 +78,14 @@ class Chef
69
78
  !!new_resource.sensitive
70
79
  end
71
80
 
81
+ def live_stream?
82
+ Chef::Config[:stream_execute_output] || !!new_resource.live_stream
83
+ end
84
+
85
+ def stream_to_stdout?
86
+ STDOUT.tty? && !Chef::Config[:daemon]
87
+ end
88
+
72
89
  def opts
73
90
  opts = {}
74
91
  opts[:timeout] = timeout
@@ -80,8 +97,12 @@ class Chef
80
97
  opts[:umask] = umask if umask
81
98
  opts[:log_level] = :info
82
99
  opts[:log_tag] = new_resource.to_s
83
- if STDOUT.tty? && !Chef::Config[:daemon] && Chef::Log.info? && !sensitive?
84
- opts[:live_stream] = STDOUT
100
+ if (Chef::Log.info? || live_stream?) && !sensitive?
101
+ if run_context.events.formatter?
102
+ opts[:live_stream] = Chef::EventDispatch::EventsOutputStream.new(run_context.events, :name => :execute)
103
+ elsif stream_to_stdout?
104
+ opts[:live_stream] = STDOUT
105
+ end
85
106
  end
86
107
  opts
87
108
  end
@@ -125,7 +125,7 @@ class Chef
125
125
  def action_create
126
126
  case @group_exists
127
127
  when false
128
- converge_by("create #{@new_resource.group_name}") do
128
+ converge_by("create group #{@new_resource.group_name}") do
129
129
  create_group
130
130
  Chef::Log.info("#{@new_resource} created")
131
131
  end
@@ -19,6 +19,7 @@
19
19
  #
20
20
 
21
21
  require 'chef/provider'
22
+ require 'chef/dsl/recipe'
22
23
  require 'chef/dsl/include_recipe'
23
24
 
24
25
  class Chef
@@ -1,6 +1,6 @@
1
1
  #
2
2
  # Author:: Adam Jacob (<adam@opscode.com>)
3
- # Copyright:: Copyright (c) 2008 Opscode, Inc.
3
+ # Copyright:: Copyright (c) 2008-2015 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");
@@ -18,6 +18,7 @@
18
18
 
19
19
  require 'chef/mixin/shell_out'
20
20
  require 'chef/mixin/command'
21
+ require 'chef/mixin/subclass_directive'
21
22
  require 'chef/log'
22
23
  require 'chef/file_cache'
23
24
  require 'chef/platform'
@@ -27,6 +28,12 @@ class Chef
27
28
  class Package < Chef::Provider
28
29
  include Chef::Mixin::Command
29
30
  include Chef::Mixin::ShellOut
31
+ extend Chef::Mixin::SubclassDirective
32
+
33
+ # subclasses declare this if they want all their arguments as arrays of packages and names
34
+ subclass_directive :use_multipackage_api
35
+ # subclasses declare this if they want sources (filenames) pulled from their package names
36
+ subclass_directive :use_package_name_for_source
30
37
 
31
38
  #
32
39
  # Hook that subclasses use to populate the candidate_version(s)
@@ -44,6 +51,8 @@ class Chef
44
51
  end
45
52
 
46
53
  def check_resource_semantics!
54
+ # FIXME: this is not universally true and subclasses are needing to override this and no-ops it. It should be turned into
55
+ # another "subclass_directive" and the apt and yum providers should declare that they need this behavior.
47
56
  if new_resource.package_name.is_a?(Array) && new_resource.source != nil
48
57
  raise Chef::Exceptions::InvalidResourceSpecification, "You may not specify both multipackage and source"
49
58
  end
@@ -86,11 +95,10 @@ class Chef
86
95
  end
87
96
  end
88
97
 
89
- # XXX: mutating the new resource is generally bad
90
- @new_resource.version(versions_for_new_resource)
91
-
92
98
  converge_by(install_description) do
93
- install_package(package_names_for_targets, versions_for_targets)
99
+ multipackage_api_adapter(package_names_for_targets, versions_for_targets) do |name, version|
100
+ install_package(name, version)
101
+ end
94
102
  Chef::Log.info("#{@new_resource} installed #{package_names_for_targets} at #{versions_for_targets}")
95
103
  end
96
104
  end
@@ -113,11 +121,10 @@ class Chef
113
121
  return
114
122
  end
115
123
 
116
- # XXX: mutating the new resource is generally bad
117
- @new_resource.version(versions_for_new_resource)
118
-
119
124
  converge_by(upgrade_description) do
120
- upgrade_package(package_names_for_targets, versions_for_targets)
125
+ multipackage_api_adapter(package_names_for_targets, versions_for_targets) do |name, version|
126
+ upgrade_package(name, version)
127
+ end
121
128
  log_allow_downgrade = allow_downgrade ? '(allow_downgrade)' : ''
122
129
  Chef::Log.info("#{@new_resource} upgraded#{log_allow_downgrade} #{package_names_for_targets} to #{versions_for_targets}")
123
130
  end
@@ -138,12 +145,13 @@ class Chef
138
145
 
139
146
  private :upgrade_description
140
147
 
141
- # @todo: ability to remove an array of packages
142
148
  def action_remove
143
149
  if removing_package?
144
150
  description = @new_resource.version ? "version #{@new_resource.version} of " : ""
145
151
  converge_by("remove #{description}package #{@current_resource.package_name}") do
146
- remove_package(@current_resource.package_name, @new_resource.version)
152
+ multipackage_api_adapter(@current_resource.package_name, @new_resource.version) do |name, version|
153
+ remove_package(name, version)
154
+ end
147
155
  Chef::Log.info("#{@new_resource} removed")
148
156
  end
149
157
  else
@@ -172,18 +180,18 @@ class Chef
172
180
  end
173
181
  end
174
182
 
175
- # @todo: ability to purge an array of packages
176
183
  def action_purge
177
184
  if removing_package?
178
185
  description = @new_resource.version ? "version #{@new_resource.version} of" : ""
179
186
  converge_by("purge #{description} package #{@current_resource.package_name}") do
180
- purge_package(@current_resource.package_name, @new_resource.version)
187
+ multipackage_api_adapter(@current_resource.package_name, @new_resource.version) do |name, version|
188
+ purge_package(name, version)
189
+ end
181
190
  Chef::Log.info("#{@new_resource} purged")
182
191
  end
183
192
  end
184
193
  end
185
194
 
186
- # @todo: ability to reconfigure an array of packages
187
195
  def action_reconfig
188
196
  if @current_resource.version == nil then
189
197
  Chef::Log.debug("#{@new_resource} is NOT installed - nothing to do")
@@ -198,7 +206,10 @@ class Chef
198
206
  if preseed_file = get_preseed_file(@new_resource.package_name, @current_resource.version)
199
207
  converge_by("reconfigure package #{@new_resource.package_name}") do
200
208
  preseed_package(preseed_file)
201
- reconfig_package(@new_resource.package_name, @current_resource.version)
209
+ multipackage_api_adapter(@new_resource.package_name, @current_resource.version) do |name, version|
210
+ reconfig_package(name, version)
211
+
212
+ end
202
213
  Chef::Log.info("#{@new_resource} reconfigured")
203
214
  end
204
215
  else
@@ -207,6 +218,15 @@ class Chef
207
218
  end
208
219
 
209
220
  # @todo use composition rather than inheritance
221
+
222
+ def multipackage_api_adapter(name, version)
223
+ if use_multipackage_api?
224
+ yield [name].flatten, [version].flatten
225
+ else
226
+ yield name, version
227
+ end
228
+ end
229
+
210
230
  def install_package(name, version)
211
231
  raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :install"
212
232
  end
@@ -231,7 +251,7 @@ class Chef
231
251
  raise( Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :reconfig" )
232
252
  end
233
253
 
234
- # this is heavily used by subclasses
254
+ # used by subclasses. deprecated. use #a_to_s instead.
235
255
  def expand_options(options)
236
256
  options ? " #{options}" : ""
237
257
  end
@@ -322,18 +342,6 @@ class Chef
322
342
  multipackage? ? versions_for_targets : versions_for_targets[0]
323
343
  end
324
344
 
325
- # We need to mutate @new_resource.version() for some reason and this is a helper so that we inject the right
326
- # class (String or Array) into that attribute based on if we're handling an array of package names or not.
327
- #
328
- # @return [String, Array<String>] target_versions coerced into the correct type for back-compat
329
- def versions_for_new_resource
330
- if multipackage?
331
- target_version_array
332
- else
333
- target_version_array[0]
334
- end
335
- end
336
-
337
345
  # Return an array indexed the same as *_version_array which contains either the target version to install/upgrade to
338
346
  # or else nil if the package is not being modified.
339
347
  #
@@ -473,6 +481,37 @@ class Chef
473
481
  [ new_resource.version ].flatten.map { |v| v.to_s.empty? ? nil : v }
474
482
  end
475
483
 
484
+ # TIP: less error prone to simply always call resolved_source_array, even if you
485
+ # don't think that you need to.
486
+ #
487
+ # @return [Array] new_resource.source as an array
488
+ def source_array
489
+ if new_resource.source.nil?
490
+ package_name_array.map { nil }
491
+ else
492
+ [ new_resource.source ].flatten
493
+ end
494
+ end
495
+
496
+ # Helper to handle use_package_name_for_source to convert names into local packages to install.
497
+ #
498
+ # @return [Array] Array of sources with package_names converted to sources
499
+ def resolved_source_array
500
+ @resolved_source_array ||=
501
+ begin
502
+ source_array.each_with_index.map do |source, i|
503
+ package_name = package_name_array[i]
504
+ # we require at least one '/' in the package_name to avoid [XXX_]package 'foo' breaking due to a random 'foo' file in cwd
505
+ if use_package_name_for_source? && source.nil? && package_name.match(/#{::File::SEPARATOR}/) && ::File.exist?(package_name)
506
+ Chef::Log.debug("No package source specified, but #{package_name} exists on filesystem, using #{package_name} as source.")
507
+ package_name
508
+ else
509
+ source
510
+ end
511
+ end
512
+ end
513
+ end
514
+
476
515
  # @todo: extract apt/dpkg specific preseeding to a helper class
477
516
  def template_available?(path)
478
517
  run_context.has_template_in_cookbook?(new_resource.cookbook_name, path)
@@ -491,8 +530,6 @@ class Chef
491
530
  end
492
531
  end
493
532
 
494
- private
495
-
496
533
  def shell_out_with_timeout(*command_args)
497
534
  shell_out(*add_timeout_option(command_args))
498
535
  end
@@ -514,6 +551,15 @@ class Chef
514
551
  args
515
552
  end
516
553
 
554
+ # Helper for sublcasses to convert an array of string args into a string. It
555
+ # will compact nil or empty strings in the array and will join the array elements
556
+ # with spaces, without introducing any double spaces for nil/empty elements.
557
+ #
558
+ # @param args [String] variable number of string arguments
559
+ # @return [String] nicely concatenated string or empty string
560
+ def a_to_s(*args)
561
+ args.reject {|i| i.nil? || i == "" }.join(" ")
562
+ end
517
563
  end
518
564
  end
519
565
  end