chef 12.16.42 → 12.17.44
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -1
- data/README.md +20 -5
- data/Rakefile +17 -0
- data/VERSION +1 -1
- data/acceptance/Gemfile.lock +32 -23
- data/distro/common/markdown/man1/knife-configure.mkd +3 -2
- data/lib-backcompat/chef/chef_fs/file_system/already_exists_error.rb +1 -1
- data/lib-backcompat/chef/chef_fs/file_system/cookbook_frozen_error.rb +1 -1
- data/lib-backcompat/chef/chef_fs/file_system/default_environment_cannot_be_modified_error.rb +1 -1
- data/lib-backcompat/chef/chef_fs/file_system/file_system_error.rb +1 -1
- data/lib-backcompat/chef/chef_fs/file_system/must_delete_recursively_error.rb +1 -1
- data/lib-backcompat/chef/chef_fs/file_system/not_found_error.rb +1 -1
- data/lib-backcompat/chef/chef_fs/file_system/operation_failed_error.rb +1 -1
- data/lib-backcompat/chef/chef_fs/file_system/operation_not_allowed_error.rb +1 -1
- data/lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_entry.rb +1 -1
- data/lib-backcompat/chef/chef_fs/file_system/repository/file_system_root_dir.rb +1 -1
- data/lib/chef/api_client.rb +1 -1
- data/lib/chef/application.rb +1 -1
- data/lib/chef/application/exit_code.rb +3 -3
- data/lib/chef/chef_class.rb +15 -5
- data/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir.rb +12 -1
- data/lib/chef/chef_fs/file_system/repository/nodes_dir.rb +19 -0
- data/lib/chef/client.rb +1 -0
- data/lib/chef/cookbook/metadata.rb +2 -2
- data/lib/chef/cookbook_version.rb +4 -4
- data/lib/chef/data_bag.rb +1 -1
- data/lib/chef/data_bag_item.rb +1 -1
- data/lib/chef/data_collector.rb +20 -13
- data/lib/chef/data_collector/messages.rb +0 -1
- data/lib/chef/data_collector/messages/helpers.rb +2 -2
- data/lib/chef/decorator/unchain.rb +2 -2
- data/lib/chef/deprecated.rb +190 -0
- data/lib/chef/deprecation/provider/remote_directory.rb +1 -1
- data/lib/chef/deprecation/warnings.rb +3 -4
- data/lib/chef/dsl/method_missing.rb +2 -2
- data/lib/chef/dsl/resources.rb +2 -2
- data/lib/chef/environment.rb +1 -1
- data/lib/chef/exceptions.rb +1 -1
- data/lib/chef/formatters/base.rb +11 -1
- data/lib/chef/formatters/doc.rb +13 -4
- data/lib/chef/key.rb +1 -1
- data/lib/chef/knife/client_delete.rb +12 -9
- data/lib/chef/knife/configure.rb +1 -1
- data/lib/chef/knife/core/bootstrap_context.rb +25 -1
- data/lib/chef/knife/core/subcommand_loader.rb +3 -3
- data/lib/chef/knife/core/ui.rb +1 -1
- data/lib/chef/knife/node_delete.rb +6 -6
- data/lib/chef/log.rb +1 -1
- data/lib/chef/mixin/deprecation.rb +4 -10
- data/lib/chef/mixin/powershell_type_coercions.rb +19 -19
- data/lib/chef/mixin/shell_out.rb +1 -1
- data/lib/chef/node.rb +2 -2
- data/lib/chef/node/attribute.rb +3 -4
- data/lib/chef/node/common_api.rb +1 -1
- data/lib/chef/node/mixin/state_tracking.rb +5 -2
- data/lib/chef/node_map.rb +2 -2
- data/lib/chef/org.rb +1 -1
- data/lib/chef/platform/rebooter.rb +3 -1
- data/lib/chef/policy_builder/expand_node_object.rb +1 -1
- data/lib/chef/property.rb +5 -5
- data/lib/chef/provider.rb +4 -4
- data/lib/chef/provider/launchd.rb +1 -1
- data/lib/chef/provider/link.rb +6 -0
- data/lib/chef/provider/mount.rb +2 -0
- data/lib/chef/provider/mount/mount.rb +1 -1
- data/lib/chef/provider/ohai.rb +5 -3
- data/lib/chef/provider/package/cab.rb +1 -1
- data/lib/chef/provider/package/chocolatey.rb +2 -2
- data/lib/chef/provider/package/easy_install.rb +2 -2
- data/lib/chef/provider/package/msu.rb +162 -0
- data/lib/chef/provider/package/powershell.rb +114 -0
- data/lib/chef/provider/package/yum.rb +1 -1
- data/lib/chef/provider/yum_repository.rb +6 -7
- data/lib/chef/provider_resolver.rb +2 -2
- data/lib/chef/providers.rb +2 -0
- data/lib/chef/resource.rb +3 -5
- data/lib/chef/resource/apt_update.rb +1 -1
- data/lib/chef/resource/chef_gem.rb +2 -3
- data/lib/chef/resource/file/verification.rb +1 -1
- data/lib/chef/resource/launchd.rb +48 -8
- data/lib/chef/resource/mount.rb +1 -1
- data/lib/chef/resource/msu_package.rb +47 -0
- data/lib/chef/resource/ohai.rb +5 -25
- data/lib/chef/resource/powershell_package.rb +41 -0
- data/lib/chef/resource/reboot.rb +1 -1
- data/lib/chef/resource/user.rb +2 -2
- data/lib/chef/resource_builder.rb +4 -4
- data/lib/chef/resource_resolver.rb +2 -3
- data/lib/chef/resources.rb +2 -0
- data/lib/chef/rest.rb +1 -1
- data/lib/chef/role.rb +1 -1
- data/lib/chef/run_context.rb +3 -3
- data/lib/chef/shell/ext.rb +2 -2
- data/lib/chef/user.rb +3 -3
- data/lib/chef/user_v1.rb +1 -1
- data/lib/chef/version.rb +1 -1
- data/lib/chef/win32/api/security.rb +12 -12
- data/spec/data/sample_msu1.xml +10 -0
- data/spec/data/sample_msu2.xml +14 -0
- data/spec/data/sample_msu3.xml +16 -0
- data/spec/functional/rebooter_spec.rb +3 -3
- data/spec/functional/resource/link_spec.rb +62 -1
- data/spec/functional/resource/msu_package_spec.rb +84 -0
- data/spec/functional/resource/registry_spec.rb +3 -3
- data/spec/functional/resource/rpm_spec.rb +7 -10
- data/spec/integration/solo/solo_spec.rb +50 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/platform_helpers.rb +16 -8
- data/spec/unit/application/exit_code_spec.rb +3 -15
- data/spec/unit/data_collector_spec.rb +6 -16
- data/spec/unit/deprecated_spec.rb +59 -0
- data/spec/unit/deprecation_spec.rb +1 -8
- data/spec/unit/handler_spec.rb +2 -2
- data/spec/unit/knife/client_delete_spec.rb +16 -0
- data/spec/unit/knife/configure_spec.rb +1 -1
- data/spec/unit/knife/cookbook_metadata_spec.rb +116 -113
- data/spec/unit/knife/core/bootstrap_context_spec.rb +55 -5
- data/spec/unit/knife/node_delete_spec.rb +19 -10
- data/spec/unit/mixin/shell_out_spec.rb +0 -1
- data/spec/unit/node/immutable_collections_spec.rb +5 -0
- data/spec/unit/node/vivid_mash_spec.rb +11 -0
- data/spec/unit/node_spec.rb +2 -2
- data/spec/unit/provider/launchd_spec.rb +81 -3
- data/spec/unit/provider/mount/mount_spec.rb +1 -1
- data/spec/unit/provider/mount_spec.rb +7 -0
- data/spec/unit/provider/package/chocolatey_spec.rb +5 -5
- data/spec/unit/provider/package/easy_install_spec.rb +6 -6
- data/spec/unit/provider/package/msu_spec.rb +283 -0
- data/spec/unit/provider/package/powershell_spec.rb +337 -0
- data/spec/unit/provider/service/macosx_spec.rb +1 -1
- data/spec/unit/provider/subversion_spec.rb +9 -0
- data/spec/unit/provider/user/linux_spec.rb +7 -1
- data/spec/unit/recipe_spec.rb +43 -11
- data/spec/unit/resource/apt_update_spec.rb +17 -25
- data/spec/unit/resource/file/verification_spec.rb +1 -1
- data/spec/unit/resource/mount_spec.rb +2 -1
- data/spec/unit/resource/msu_package_spec.rb +49 -0
- data/spec/unit/resource/ohai_spec.rb +1 -1
- data/spec/unit/resource/powershell_package_spec.rb +68 -0
- data/spec/unit/resource_reporter_spec.rb +4 -4
- data/spec/unit/run_status_spec.rb +1 -1
- data/tasks/announce.rb +58 -0
- data/tasks/changelog.rb +26 -6
- data/tasks/templates/prerelease.md.erb +35 -0
- data/tasks/templates/release.md.erb +34 -0
- metadata +21 -4
data/lib/chef/node_map.rb
CHANGED
@@ -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.
|
36
|
-
Chef.
|
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
|
data/lib/chef/org.rb
CHANGED
@@ -125,7 +125,7 @@ class Chef
|
|
125
125
|
end
|
126
126
|
|
127
127
|
def self.json_create(json)
|
128
|
-
Chef.
|
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
|
-
|
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.
|
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}")
|
data/lib/chef/property.rb
CHANGED
@@ -116,7 +116,7 @@ class Chef
|
|
116
116
|
options.delete(:name_property)
|
117
117
|
preferred_default = :default
|
118
118
|
end
|
119
|
-
Chef.
|
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.
|
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.
|
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.
|
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.
|
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
|
data/lib/chef/provider.rb
CHANGED
@@ -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.
|
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
|
data/lib/chef/provider/link.rb
CHANGED
@@ -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
|
data/lib/chef/provider/mount.rb
CHANGED
@@ -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
|
data/lib/chef/provider/ohai.rb
CHANGED
@@ -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
|
-
|
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
|
44
|
+
ohai.all_plugins new_resource.plugin
|
43
45
|
node.automatic_attrs.merge! ohai.data
|
44
|
-
Chef::Log.info("#{
|
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
|
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
|
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.
|
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.
|
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
|