chef 12.16.42-universal-mingw32 → 12.17.44-universal-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -1
  3. data/README.md +20 -5
  4. data/Rakefile +17 -0
  5. data/VERSION +1 -1
  6. data/acceptance/Gemfile.lock +32 -23
  7. data/distro/common/markdown/man1/knife-configure.mkd +3 -2
  8. data/lib-backcompat/chef/chef_fs/file_system/already_exists_error.rb +1 -1
  9. data/lib-backcompat/chef/chef_fs/file_system/cookbook_frozen_error.rb +1 -1
  10. data/lib-backcompat/chef/chef_fs/file_system/default_environment_cannot_be_modified_error.rb +1 -1
  11. data/lib-backcompat/chef/chef_fs/file_system/file_system_error.rb +1 -1
  12. data/lib-backcompat/chef/chef_fs/file_system/must_delete_recursively_error.rb +1 -1
  13. data/lib-backcompat/chef/chef_fs/file_system/not_found_error.rb +1 -1
  14. data/lib-backcompat/chef/chef_fs/file_system/operation_failed_error.rb +1 -1
  15. data/lib-backcompat/chef/chef_fs/file_system/operation_not_allowed_error.rb +1 -1
  16. data/lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_entry.rb +1 -1
  17. data/lib-backcompat/chef/chef_fs/file_system/repository/file_system_root_dir.rb +1 -1
  18. data/lib/chef/api_client.rb +1 -1
  19. data/lib/chef/application.rb +1 -1
  20. data/lib/chef/application/exit_code.rb +3 -3
  21. data/lib/chef/chef_class.rb +15 -5
  22. data/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir.rb +12 -1
  23. data/lib/chef/chef_fs/file_system/repository/nodes_dir.rb +19 -0
  24. data/lib/chef/client.rb +1 -0
  25. data/lib/chef/cookbook/metadata.rb +2 -2
  26. data/lib/chef/cookbook_version.rb +4 -4
  27. data/lib/chef/data_bag.rb +1 -1
  28. data/lib/chef/data_bag_item.rb +1 -1
  29. data/lib/chef/data_collector.rb +20 -13
  30. data/lib/chef/data_collector/messages.rb +0 -1
  31. data/lib/chef/data_collector/messages/helpers.rb +2 -2
  32. data/lib/chef/decorator/unchain.rb +2 -2
  33. data/lib/chef/deprecated.rb +190 -0
  34. data/lib/chef/deprecation/provider/remote_directory.rb +1 -1
  35. data/lib/chef/deprecation/warnings.rb +3 -4
  36. data/lib/chef/dsl/method_missing.rb +2 -2
  37. data/lib/chef/dsl/resources.rb +2 -2
  38. data/lib/chef/environment.rb +1 -1
  39. data/lib/chef/exceptions.rb +1 -1
  40. data/lib/chef/formatters/base.rb +11 -1
  41. data/lib/chef/formatters/doc.rb +13 -4
  42. data/lib/chef/key.rb +1 -1
  43. data/lib/chef/knife/client_delete.rb +12 -9
  44. data/lib/chef/knife/configure.rb +1 -1
  45. data/lib/chef/knife/core/bootstrap_context.rb +25 -1
  46. data/lib/chef/knife/core/subcommand_loader.rb +3 -3
  47. data/lib/chef/knife/core/ui.rb +1 -1
  48. data/lib/chef/knife/node_delete.rb +6 -6
  49. data/lib/chef/log.rb +1 -1
  50. data/lib/chef/mixin/deprecation.rb +4 -10
  51. data/lib/chef/mixin/powershell_type_coercions.rb +19 -19
  52. data/lib/chef/mixin/shell_out.rb +1 -1
  53. data/lib/chef/node.rb +2 -2
  54. data/lib/chef/node/attribute.rb +3 -4
  55. data/lib/chef/node/common_api.rb +1 -1
  56. data/lib/chef/node/mixin/state_tracking.rb +5 -2
  57. data/lib/chef/node_map.rb +2 -2
  58. data/lib/chef/org.rb +1 -1
  59. data/lib/chef/platform/rebooter.rb +3 -1
  60. data/lib/chef/policy_builder/expand_node_object.rb +1 -1
  61. data/lib/chef/property.rb +5 -5
  62. data/lib/chef/provider.rb +4 -4
  63. data/lib/chef/provider/launchd.rb +1 -1
  64. data/lib/chef/provider/link.rb +6 -0
  65. data/lib/chef/provider/mount.rb +2 -0
  66. data/lib/chef/provider/mount/mount.rb +1 -1
  67. data/lib/chef/provider/ohai.rb +5 -3
  68. data/lib/chef/provider/package/cab.rb +1 -1
  69. data/lib/chef/provider/package/chocolatey.rb +2 -2
  70. data/lib/chef/provider/package/easy_install.rb +2 -2
  71. data/lib/chef/provider/package/msu.rb +162 -0
  72. data/lib/chef/provider/package/powershell.rb +114 -0
  73. data/lib/chef/provider/package/yum.rb +1 -1
  74. data/lib/chef/provider/yum_repository.rb +6 -7
  75. data/lib/chef/provider_resolver.rb +2 -2
  76. data/lib/chef/providers.rb +2 -0
  77. data/lib/chef/resource.rb +3 -5
  78. data/lib/chef/resource/apt_update.rb +1 -1
  79. data/lib/chef/resource/chef_gem.rb +2 -3
  80. data/lib/chef/resource/file/verification.rb +1 -1
  81. data/lib/chef/resource/launchd.rb +48 -8
  82. data/lib/chef/resource/mount.rb +1 -1
  83. data/lib/chef/resource/msu_package.rb +47 -0
  84. data/lib/chef/resource/ohai.rb +5 -25
  85. data/lib/chef/resource/powershell_package.rb +41 -0
  86. data/lib/chef/resource/reboot.rb +1 -1
  87. data/lib/chef/resource/user.rb +2 -2
  88. data/lib/chef/resource_builder.rb +4 -4
  89. data/lib/chef/resource_resolver.rb +2 -3
  90. data/lib/chef/resources.rb +2 -0
  91. data/lib/chef/rest.rb +1 -1
  92. data/lib/chef/role.rb +1 -1
  93. data/lib/chef/run_context.rb +3 -3
  94. data/lib/chef/shell/ext.rb +2 -2
  95. data/lib/chef/user.rb +3 -3
  96. data/lib/chef/user_v1.rb +1 -1
  97. data/lib/chef/version.rb +1 -1
  98. data/lib/chef/win32/api/security.rb +12 -12
  99. data/spec/data/sample_msu1.xml +10 -0
  100. data/spec/data/sample_msu2.xml +14 -0
  101. data/spec/data/sample_msu3.xml +16 -0
  102. data/spec/functional/rebooter_spec.rb +3 -3
  103. data/spec/functional/resource/link_spec.rb +62 -1
  104. data/spec/functional/resource/msu_package_spec.rb +84 -0
  105. data/spec/functional/resource/registry_spec.rb +3 -3
  106. data/spec/functional/resource/rpm_spec.rb +7 -10
  107. data/spec/integration/solo/solo_spec.rb +50 -0
  108. data/spec/spec_helper.rb +3 -0
  109. data/spec/support/platform_helpers.rb +16 -8
  110. data/spec/unit/application/exit_code_spec.rb +3 -15
  111. data/spec/unit/data_collector_spec.rb +6 -16
  112. data/spec/unit/deprecated_spec.rb +59 -0
  113. data/spec/unit/deprecation_spec.rb +1 -8
  114. data/spec/unit/handler_spec.rb +2 -2
  115. data/spec/unit/knife/client_delete_spec.rb +16 -0
  116. data/spec/unit/knife/configure_spec.rb +1 -1
  117. data/spec/unit/knife/cookbook_metadata_spec.rb +116 -113
  118. data/spec/unit/knife/core/bootstrap_context_spec.rb +55 -5
  119. data/spec/unit/knife/node_delete_spec.rb +19 -10
  120. data/spec/unit/mixin/shell_out_spec.rb +0 -1
  121. data/spec/unit/node/immutable_collections_spec.rb +5 -0
  122. data/spec/unit/node/vivid_mash_spec.rb +11 -0
  123. data/spec/unit/node_spec.rb +2 -2
  124. data/spec/unit/provider/launchd_spec.rb +81 -3
  125. data/spec/unit/provider/mount/mount_spec.rb +1 -1
  126. data/spec/unit/provider/mount_spec.rb +7 -0
  127. data/spec/unit/provider/package/chocolatey_spec.rb +5 -5
  128. data/spec/unit/provider/package/easy_install_spec.rb +6 -6
  129. data/spec/unit/provider/package/msu_spec.rb +283 -0
  130. data/spec/unit/provider/package/powershell_spec.rb +337 -0
  131. data/spec/unit/provider/service/macosx_spec.rb +1 -1
  132. data/spec/unit/provider/subversion_spec.rb +9 -0
  133. data/spec/unit/provider/user/linux_spec.rb +7 -1
  134. data/spec/unit/recipe_spec.rb +43 -11
  135. data/spec/unit/resource/apt_update_spec.rb +17 -25
  136. data/spec/unit/resource/file/verification_spec.rb +1 -1
  137. data/spec/unit/resource/mount_spec.rb +2 -1
  138. data/spec/unit/resource/msu_package_spec.rb +49 -0
  139. data/spec/unit/resource/ohai_spec.rb +1 -1
  140. data/spec/unit/resource/powershell_package_spec.rb +68 -0
  141. data/spec/unit/resource_reporter_spec.rb +4 -4
  142. data/spec/unit/run_status_spec.rb +1 -1
  143. data/tasks/announce.rb +58 -0
  144. data/tasks/changelog.rb +26 -6
  145. data/tasks/templates/prerelease.md.erb +35 -0
  146. data/tasks/templates/release.md.erb +34 -0
  147. metadata +21 -4
@@ -32,8 +32,8 @@ class Chef
32
32
  # @return [NodeMap] Returns self for possible chaining
33
33
  #
34
34
  def set(key, value, platform: nil, platform_version: nil, platform_family: nil, os: nil, on_platform: nil, on_platforms: nil, canonical: nil, override: nil, &block)
35
- Chef.log_deprecation("The on_platform option to node_map has been deprecated") if on_platform
36
- Chef.log_deprecation("The on_platforms option to node_map has been deprecated") if on_platforms
35
+ Chef.deprecated(:internal_api, "The on_platform option to node_map has been deprecated") if on_platform
36
+ Chef.deprecated(:internal_api, "The on_platforms option to node_map has been deprecated") if on_platforms
37
37
  platform ||= on_platform || on_platforms
38
38
  filters = {}
39
39
  filters[:platform] = platform if platform
@@ -125,7 +125,7 @@ class Chef
125
125
  end
126
126
 
127
127
  def self.json_create(json)
128
- Chef.log_deprecation("Auto inflation of JSON data is deprecated. Please use Chef::Org#from_json or Chef::Org#load.")
128
+ Chef.deprecated(:json_auto_inflate, "Auto inflation of JSON data is deprecated. Please use Chef::Org#from_json or Chef::Org#load.")
129
129
  Chef::Org.from_json(json)
130
130
  end
131
131
 
@@ -35,7 +35,9 @@ class Chef
35
35
 
36
36
  cmd = if Chef::Platform.windows?
37
37
  # should this do /f as well? do we then need a minimum delay to let apps quit?
38
- "shutdown /r /t #{reboot_info[:delay_mins] * 60} /c \"#{reboot_info[:reason]}\""
38
+ # Use explicit path to shutdown.exe, to protect against https://github.com/chef/chef/issues/5594
39
+ windows_shutdown_path = "#{ENV['SYSTEMROOT']}/System32/shutdown.exe"
40
+ "#{windows_shutdown_path} /r /t #{reboot_info[:delay_mins] * 60} /c \"#{reboot_info[:reason]}\""
39
41
  else
40
42
  # probably Linux-only.
41
43
  "shutdown -r +#{reboot_info[:delay_mins]} \"#{reboot_info[:reason]}\""
@@ -112,7 +112,7 @@ class Chef
112
112
  # to create a PolicyBuilder::Dynamc policy builder and allow it to select
113
113
  # the proper implementation.
114
114
  def load_node
115
- Chef.log_deprecation("ExpandNodeObject#load_node is deprecated. Please use Chef::PolicyBuilder::Dynamic instead of using ExpandNodeObject directly")
115
+ Chef.deprecated(:internal_api, "ExpandNodeObject#load_node is deprecated. Please use Chef::PolicyBuilder::Dynamic instead of using ExpandNodeObject directly")
116
116
 
117
117
  events.node_load_start(node_name, config)
118
118
  Chef::Log.debug("Building node object for #{node_name}")
@@ -116,7 +116,7 @@ class Chef
116
116
  options.delete(:name_property)
117
117
  preferred_default = :default
118
118
  end
119
- Chef.log_deprecation("Cannot specify both default and name_property together on property #{self}. Only one (#{preferred_default}) will be obeyed. In Chef 13, this will become an error. Please remove one or the other from the property.")
119
+ Chef.deprecated(:custom_resource, "Cannot specify both default and name_property together on property #{self}. Only one (#{preferred_default}) will be obeyed. In Chef 13, this will become an error. Please remove one or the other from the property.")
120
120
  end
121
121
 
122
122
  # Validate the default early, so the user gets a good error message, and
@@ -287,13 +287,13 @@ class Chef
287
287
  input_to_stored_value(resource, value)
288
288
  # If nil is valid, and it would change the value, warn that this will change to a set.
289
289
  if !result.nil?
290
- Chef.log_deprecation("An attempt was made to change #{name} from #{result.inspect} to nil by calling #{name}(nil). In Chef 12, this does a get rather than a set. In Chef 13, this will change to set the value to nil.")
290
+ Chef.deprecated(:custom_resource, "An attempt was made to change #{name} from #{result.inspect} to nil by calling #{name}(nil). In Chef 12, this does a get rather than a set. In Chef 13, this will change to set the value to nil.")
291
291
  end
292
292
  rescue Chef::Exceptions::DeprecatedFeatureError
293
293
  raise
294
294
  rescue
295
295
  # If nil is invalid, warn that this will become an error.
296
- Chef.log_deprecation("nil is an invalid value for #{self}. In Chef 13, this warning will change to an error. Error: #{$!}")
296
+ Chef.deprecated(:custom_resource, "nil is an invalid value for #{self}. In Chef 13, this warning will change to an error. Error: #{$!}")
297
297
  end
298
298
 
299
299
  result
@@ -677,9 +677,9 @@ class Chef
677
677
  # warn and return the (possibly coerced) value to the user.
678
678
  if is_default
679
679
  if value.nil?
680
- Chef.log_deprecation("Default value nil is invalid for property #{self}. Possible fixes: 1. Remove 'default: nil' if nil means 'undefined'. 2. Set a valid default value if there is a reasonable one. 3. Allow nil as a valid value of your property (for example, 'property #{name.inspect}, [ String, nil ], default: nil'). Error: #{$!}")
680
+ Chef.deprecated(:custom_resource, "Default value nil is invalid for property #{self}. Possible fixes: 1. Remove 'default: nil' if nil means 'undefined'. 2. Set a valid default value if there is a reasonable one. 3. Allow nil as a valid value of your property (for example, 'property #{name.inspect}, [ String, nil ], default: nil'). Error: #{$!}")
681
681
  else
682
- Chef.log_deprecation("Default value #{value.inspect} is invalid for property #{self}. In Chef 13 this will become an error: #{$!}.")
682
+ Chef.deprecated(:custom_resource, "Default value #{value.inspect} is invalid for property #{self}. In Chef 13 this will become an error: #{$!}.")
683
683
  end
684
684
  else
685
685
  raise
@@ -205,7 +205,7 @@ class Chef
205
205
  specified_properties = properties.select { |property| new_resource.property_is_set?(property) }
206
206
  modified = specified_properties.select { |p| new_resource.send(p) != current_resource.send(p) }
207
207
  if modified.empty?
208
- properties_str = if sensitive
208
+ properties_str = if new_resource.sensitive
209
209
  specified_properties.join(", ")
210
210
  else
211
211
  specified_properties.map { |p| "#{p}=#{new_resource.send(p).inspect}" }.join(", ")
@@ -217,7 +217,7 @@ class Chef
217
217
  # Print the pretty green text and run the block
218
218
  property_size = modified.map { |p| p.size }.max
219
219
  modified.map! do |p|
220
- properties_str = if sensitive
220
+ properties_str = if new_resource.sensitive
221
221
  "(suppressed sensitive property)"
222
222
  else
223
223
  "#{new_resource.send(p).inspect} (was #{current_resource.send(p).inspect})"
@@ -232,7 +232,7 @@ class Chef
232
232
  property_size = properties.map { |p| p.size }.max
233
233
  created = properties.map do |property|
234
234
  default = " (default value)" unless new_resource.property_is_set?(property)
235
- properties_str = if sensitive
235
+ properties_str = if new_resource.sensitive
236
236
  "(suppressed sensitive property)"
237
237
  else
238
238
  new_resource.send(property).inspect
@@ -424,7 +424,7 @@ class Chef
424
424
  module DeprecatedLWRPClass
425
425
  def const_missing(class_name)
426
426
  if Chef::Provider.deprecated_constants[class_name.to_sym]
427
- Chef.log_deprecation("Using an LWRP provider by its name (#{class_name}) directly is no longer supported in Chef 12 and will be removed. Use Chef::ProviderResolver.new(node, resource, action) instead.")
427
+ Chef.deprecated(:custom_resource, "Using an LWRP provider by its name (#{class_name}) directly is no longer supported in Chef 12 and will be removed. Use Chef::ProviderResolver.new(node, resource, action) instead.")
428
428
  Chef::Provider.deprecated_constants[class_name.to_sym]
429
429
  else
430
430
  raise NameError, "uninitialized constant Chef::Provider::#{class_name}"
@@ -115,7 +115,7 @@ class Chef
115
115
  res = Chef::Resource::File.new(@path, run_context)
116
116
  res.name(@path) if @path
117
117
  res.backup(backup) if backup
118
- res.content(content) if content
118
+ res.content(content) if content?
119
119
  res.group(group) if group
120
120
  res.mode(mode) if mode
121
121
  res.owner(owner) if owner
@@ -121,6 +121,12 @@ class Chef
121
121
  file_class.symlink(canonicalize(@new_resource.to), @new_resource.target_file)
122
122
  Chef::Log.debug("#{@new_resource} created #{@new_resource.link_type} link from #{@new_resource.target_file} -> #{@new_resource.to}")
123
123
  Chef::Log.info("#{@new_resource} created")
124
+ # file_class.symlink will create the link with default access controls.
125
+ # This means that the access controls of the file could be different
126
+ # than those captured during the initial evaluation of current_resource.
127
+ # We need to re-evaluate the current_resource to ensure that the desired
128
+ # access controls are applied.
129
+ ScanAccessControl.new(@new_resource, @current_resource).set_all!
124
130
  end
125
131
  elsif @new_resource.link_type == :hard
126
132
  converge_by("create hard link at #{@new_resource.target_file} to #{@new_resource.to}") do
@@ -108,6 +108,8 @@ class Chef
108
108
  end
109
109
  end
110
110
 
111
+ alias :action_unmount :action_umount
112
+
111
113
  #
112
114
  # Abstract Methods to be implemented by subclasses
113
115
  #
@@ -193,7 +193,7 @@ class Chef
193
193
  def device_should_exist?
194
194
  ( @new_resource.device != "none" ) &&
195
195
  ( not network_device? ) &&
196
- ( not %w{ cgroup tmpfs fuse vboxsf }.include? @new_resource.fstype )
196
+ ( not %w{ cgroup tmpfs fuse vboxsf zfs }.include? @new_resource.fstype )
197
197
  end
198
198
 
199
199
  private
@@ -21,6 +21,8 @@ require "ohai"
21
21
  class Chef
22
22
  class Provider
23
23
  class Ohai < Chef::Provider
24
+ use_inline_resources
25
+
24
26
  provides :ohai
25
27
 
26
28
  def whyrun_supported?
@@ -31,7 +33,7 @@ class Chef
31
33
  true
32
34
  end
33
35
 
34
- def action_reload
36
+ action :reload do
35
37
  converge_by("re-run ohai and merge results into node attributes") do
36
38
  ohai = ::Ohai::System.new
37
39
 
@@ -39,9 +41,9 @@ class Chef
39
41
  # Otherwise it will only reload the specified plugin
40
42
  # Note that any changes to plugins, or new plugins placed on
41
43
  # the path are picked up by ohai.
42
- ohai.all_plugins @new_resource.plugin
44
+ ohai.all_plugins new_resource.plugin
43
45
  node.automatic_attrs.merge! ohai.data
44
- Chef::Log.info("#{@new_resource} reloaded")
46
+ Chef::Log.info("#{new_resource} reloaded")
45
47
  end
46
48
  end
47
49
  end
@@ -45,7 +45,7 @@ class Chef
45
45
  end
46
46
 
47
47
  def dism_command(command)
48
- shellout = Mixlib::ShellOut.new("dism.exe /Online #{command} /NoRestart", { :timeout => @new_resource.timeout })
48
+ shellout = Mixlib::ShellOut.new("dism.exe /Online /English #{command} /NoRestart", { :timeout => @new_resource.timeout })
49
49
  with_os_architecture(nil) do
50
50
  shellout.run_command
51
51
  end
@@ -84,7 +84,7 @@ EOS
84
84
 
85
85
  # choco does not support installing multiple packages with version pins
86
86
  name_has_versions.each do |name, version|
87
- choco_command("install -y -version", version, cmd_args, name)
87
+ choco_command("install -y --version", version, cmd_args, name)
88
88
  end
89
89
 
90
90
  # but we can do all the ones without version pins at once
@@ -106,7 +106,7 @@ EOS
106
106
 
107
107
  # choco does not support installing multiple packages with version pins
108
108
  name_has_versions.each do |name, version|
109
- choco_command("upgrade -y -version", version, cmd_args, name)
109
+ choco_command("upgrade -y --version", version, cmd_args, name)
110
110
  end
111
111
 
112
112
  # but we can do all the ones without version pins at once
@@ -112,7 +112,7 @@ class Chef
112
112
  end
113
113
 
114
114
  def install_package(name, version)
115
- Chef.log_deprecation("The easy_install package provider is deprecated and will be removed in Chef 13.")
115
+ Chef.deprecated(:easy_install, "The easy_install package provider is deprecated and will be removed in Chef 13.")
116
116
  run_command(:command => "#{easy_install_binary_path}#{expand_options(@new_resource.options)} \"#{name}==#{version}\"")
117
117
  end
118
118
 
@@ -121,7 +121,7 @@ class Chef
121
121
  end
122
122
 
123
123
  def remove_package(name, version)
124
- Chef.log_deprecation("The easy_install package provider is deprecated and will be removed in Chef 13.")
124
+ Chef.deprecated(:easy_install, "The easy_install package provider is deprecated and will be removed in Chef 13.")
125
125
  run_command(:command => "#{easy_install_binary_path }#{expand_options(@new_resource.options)} -m #{name}")
126
126
  end
127
127
 
@@ -0,0 +1,162 @@
1
+ #
2
+ # Author:: Nimisha Sharad (<nimisha.sharad@msystechnologies.com>)
3
+ # Copyright:: Copyright 2015-2016, Chef Software, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ # msu_package leverages cab_package
20
+ # The contents of msu file are extracted, which contains one or more cab files.
21
+ # The extracted cab files are installed using Chef::Resource::Package::CabPackage
22
+ # Reference: https://support.microsoft.com/en-in/kb/934307
23
+ require "chef/provider/package"
24
+ require "chef/resource/msu_package"
25
+ require "chef/mixin/shell_out"
26
+ require "chef/provider/package/cab"
27
+ require "chef/util/path_helper"
28
+ require "chef/mixin/uris"
29
+ require "chef/mixin/checksum"
30
+
31
+ class Chef
32
+ class Provider
33
+ class Package
34
+ class Msu < Chef::Provider::Package
35
+ use_inline_resources
36
+ include Chef::Mixin::ShellOut
37
+ include Chef::Mixin::Uris
38
+ include Chef::Mixin::Checksum
39
+
40
+ provides :msu_package, os: "windows"
41
+
42
+ def load_current_resource
43
+ @current_resource = Chef::Resource::MsuPackage.new(new_resource.name)
44
+
45
+ # download file if source is a url
46
+ msu_file = uri_scheme?(new_resource.source) ? download_source_file : @new_resource.source
47
+
48
+ # temp directory where the contents of msu file get extracted
49
+ @temp_directory = Dir.mktmpdir("chef")
50
+ extract_msu_contents(msu_file, @temp_directory)
51
+ @cab_files = read_cab_files_from_xml(@temp_directory)
52
+
53
+ unless @cab_files.empty?
54
+ current_resource.version(get_current_versions)
55
+ else
56
+ raise Chef::Exceptions::Package, "Corrupt MSU package: MSU package XML does not contain any cab file"
57
+ end
58
+ current_resource
59
+ end
60
+
61
+ def get_current_versions
62
+ @cab_files.map do |cabfile|
63
+ cab_pkg = get_cab_package(cabfile)
64
+ cab_pkg.installed_version
65
+ end
66
+ end
67
+
68
+ def get_candidate_versions
69
+ @cab_files.map do |cabfile|
70
+ cab_pkg = get_cab_package(cabfile)
71
+ cab_pkg.package_version
72
+ end
73
+ end
74
+
75
+ def candidate_version
76
+ @candidate_version ||= get_candidate_versions
77
+ end
78
+
79
+ def get_cab_package(cab_file)
80
+ cab_resource = @new_resource
81
+ cab_resource.source = cab_file
82
+ cab_pkg = Chef::Provider::Package::Cab.new(cab_resource, nil)
83
+ end
84
+
85
+ def download_source_file
86
+ source_resource.run_action(:create)
87
+ Chef::Log.debug("#{new_resource} fetched source file to #{source_resource.path}")
88
+ source_resource.path
89
+ end
90
+
91
+ def source_resource
92
+ @source_resource ||= declare_resource(:remote_file, new_resource.name) do
93
+ path default_download_cache_path
94
+ source new_resource.source
95
+ checksum new_resource.checksum
96
+ backup false
97
+ end
98
+ end
99
+
100
+ def default_download_cache_path
101
+ uri = ::URI.parse(new_resource.source)
102
+ filename = ::File.basename(::URI.unescape(uri.path))
103
+ file_cache_dir = Chef::FileCache.create_cache_path("package/")
104
+ Chef::Util::PathHelper.cleanpath("#{file_cache_dir}/#{filename}")
105
+ end
106
+
107
+ def install_package(name, version)
108
+ #use cab_package resource to install the extracted cab packages
109
+ @cab_files.each do |cab_file|
110
+ declare_resource(:cab_package, @new_resource.name) do
111
+ source cab_file
112
+ action :install
113
+ end
114
+ end
115
+ end
116
+
117
+ def remove_package(name, version)
118
+ #use cab_package provider to remove the extracted cab packages
119
+ @cab_files.each do |cab_file|
120
+ declare_resource(:cab_package, @new_resource.name) do
121
+ source cab_file
122
+ action :remove
123
+ end
124
+ end
125
+ end
126
+
127
+ def extract_msu_contents(msu_file, destination)
128
+ with_os_architecture(nil) do
129
+ shell_out_with_timeout!("#{ENV['SYSTEMROOT']}\\system32\\expand.exe -f:* #{msu_file} #{destination}")
130
+ end
131
+ end
132
+
133
+ # msu package can contain multiple cab files
134
+ # Reading cab files from xml to ensure the order of installation in case of multiple cab files
135
+ def read_cab_files_from_xml(msu_dir)
136
+ # get the file with .xml extension
137
+ xml_files = Dir.glob("#{msu_dir}/*.xml")
138
+ cab_files = []
139
+
140
+ if xml_files.empty?
141
+ raise Chef::Exceptions::Package, "Corrupt MSU package: MSU package doesn't contain any xml file"
142
+ else
143
+ # msu package contains only single xml file. So using xml_files.first is sufficient
144
+ doc = ::File.open("#{xml_files.first}") { |f| REXML::Document.new f }
145
+ locations = doc.elements.each("unattend/servicing/package/source") { |element| puts element.attributes["location"] }
146
+ locations.each do |loc|
147
+ cab_files << msu_dir + "/" + loc.attribute("location").value.split("\\")[1]
148
+ end
149
+
150
+ cab_files
151
+ end
152
+ cab_files
153
+ end
154
+
155
+ def cleanup_after_converge
156
+ # delete the temp directory where the contents of msu file are extracted
157
+ FileUtils.rm_rf(@temp_directory) if Dir.exists?(@temp_directory)
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,114 @@
1
+ # Author:: Dheeraj Dubey(dheeraj.dubey@msystechnologies.com)
2
+ # Copyright:: Copyright 2015-2016, Chef Software, 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 "chef/provider/package"
19
+ require "chef/resource/powershell_package"
20
+ require "chef/mixin/powershell_out"
21
+
22
+ class Chef
23
+ class Provider
24
+ class Package
25
+ class Powershell < Chef::Provider::Package
26
+ include Chef::Mixin::PowershellOut
27
+
28
+ provides :powershell_package, os: "windows"
29
+
30
+ def load_current_resource
31
+ @current_resource = Chef::Resource::PowershellPackage.new(new_resource.name)
32
+ current_resource.package_name(new_resource.package_name)
33
+ current_resource.version(build_current_versions)
34
+ current_resource
35
+ end
36
+
37
+ def define_resource_requirements
38
+ super
39
+ if powershell_out("$PSVersionTable.PSVersion.Major").stdout.strip().to_i < 5
40
+ raise "Minimum installed Powershell Version required is 5"
41
+ end
42
+ requirements.assert(:install) do |a|
43
+ a.assertion { candidates_exist_for_all_uninstalled? }
44
+ a.failure_message(Chef::Exceptions::Package, "No candidate version available for #{packages_missing_candidates.join(", ")}")
45
+ a.whyrun("Assuming a repository that offers #{packages_missing_candidates.join(", ")} would have been configured")
46
+ end
47
+ end
48
+
49
+ def candidate_version
50
+ @candidate_version ||= build_candidate_versions
51
+ end
52
+
53
+ # Installs the package specified with the version passed else latest version will be installed
54
+ def install_package(names, versions)
55
+ names.each_with_index do |name, index|
56
+ powershell_out("Install-Package '#{name}' -Force -ForceBootstrap -RequiredVersion #{versions[index]}", { :timeout => @new_resource.timeout })
57
+ end
58
+ end
59
+
60
+ # Removes the package for the version passed and if no version is passed, then all installed versions of the package are removed
61
+ def remove_package(names, versions)
62
+ names.each_with_index do |name, index|
63
+ if versions && versions[index] != nil
64
+ powershell_out( "Uninstall-Package '#{name}' -Force -ForceBootstrap -RequiredVersion #{versions[index]}", { :timeout => @new_resource.timeout })
65
+ else
66
+ version = "0"
67
+ until version.empty?
68
+ version = powershell_out( "(Uninstall-Package '#{name}' -Force -ForceBootstrap | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => @new_resource.timeout }).stdout.strip()
69
+ if !version.empty?
70
+ Chef::Log.info("Removed package '#{name}' with version #{version}")
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ # Returns array of available available online
78
+ def build_candidate_versions
79
+ versions = []
80
+ new_resource.package_name.each_with_index do |name, index|
81
+ if new_resource.version && new_resource.version[index] != nil
82
+ version = powershell_out("(Find-Package '#{name}' -RequiredVersion #{new_resource.version[index]} -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => @new_resource.timeout }).stdout.strip()
83
+ else
84
+ version = powershell_out("(Find-Package '#{name}' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => @new_resource.timeout }).stdout.strip()
85
+ end
86
+ if version.empty?
87
+ version = nil
88
+ end
89
+ versions.push(version)
90
+ end
91
+ versions
92
+ end
93
+
94
+ # Returns version array of installed version on the system
95
+ def build_current_versions
96
+ version_list = []
97
+ new_resource.package_name.each_with_index do |name, index|
98
+ if new_resource.version && new_resource.version[index] != nil
99
+ version = powershell_out("(Get-Package -Name '#{name}' -RequiredVersion #{new_resource.version[index]} -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => @new_resource.timeout }).stdout.strip()
100
+ else
101
+ version = powershell_out("(Get-Package -Name '#{name}' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => @new_resource.timeout }).stdout.strip()
102
+ end
103
+ if version.empty?
104
+ version = nil
105
+ end
106
+ version_list.push(version)
107
+ end
108
+ version_list
109
+ end
110
+
111
+ end
112
+ end
113
+ end
114
+ end