chef 12.0.0.rc.0 → 12.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +1 -1
- data/lib/chef/api_client/registration.rb +3 -1
- data/lib/chef/chef_fs/data_handler/group_data_handler.rb +4 -0
- data/lib/chef/config.rb +46 -38
- data/lib/chef/event_loggers/windows_eventlog.rb +5 -6
- data/lib/chef/exceptions.rb +13 -1
- data/lib/chef/file_content_management/tempfile.rb +33 -5
- data/lib/chef/knife.rb +11 -3
- data/lib/chef/knife/bootstrap.rb +8 -7
- data/lib/chef/mixin/deep_merge.rb +15 -54
- data/lib/chef/mixin/which.rb +37 -0
- data/lib/chef/node.rb +14 -25
- data/lib/chef/node/attribute.rb +227 -41
- data/lib/chef/node/attribute_collections.rb +117 -3
- data/lib/chef/node/immutable_collections.rb +6 -6
- data/lib/chef/platform/provider_priority_map.rb +3 -2
- data/lib/chef/platform/service_helpers.rb +37 -8
- data/lib/chef/provider/service/aixinit.rb +1 -1
- data/lib/chef/provider/service/arch.rb +1 -1
- data/lib/chef/provider/service/debian.rb +5 -1
- data/lib/chef/provider/service/init.rb +4 -0
- data/lib/chef/provider/service/insserv.rb +5 -1
- data/lib/chef/provider/service/invokercd.rb +5 -1
- data/lib/chef/provider/service/redhat.rb +5 -1
- data/lib/chef/provider/service/systemd.rb +50 -32
- data/lib/chef/provider/service/upstart.rb +5 -2
- data/lib/chef/provider_resolver.rb +30 -16
- data/lib/chef/resource.rb +2 -1
- data/lib/chef/resources.rb +7 -0
- data/lib/chef/run_context.rb +0 -5
- data/lib/chef/run_list/run_list_expansion.rb +2 -2
- data/lib/chef/shell.rb +2 -2
- data/lib/chef/util/selinux.rb +2 -10
- data/lib/chef/version.rb +1 -1
- data/lib/chef/workstation_config_loader.rb +1 -1
- data/spec/support/shared/unit/resource/static_provider_resolution.rb +1 -6
- data/spec/unit/api_client/registration_spec.rb +22 -0
- data/spec/unit/application/knife_spec.rb +6 -2
- data/spec/unit/chef_fs/data_handler/group_handler_spec.rb +63 -0
- data/spec/unit/config_spec.rb +5 -5
- data/spec/unit/knife/bootstrap_spec.rb +27 -1
- data/spec/unit/knife_spec.rb +5 -0
- data/spec/unit/mixin/deep_merge_spec.rb +0 -40
- data/spec/unit/node/attribute_spec.rb +37 -50
- data/spec/unit/node_spec.rb +321 -13
- data/spec/unit/provider/file/content_spec.rb +23 -2
- data/spec/unit/provider/service/systemd_service_spec.rb +173 -158
- data/spec/unit/provider_resolver_spec.rb +175 -10
- data/spec/unit/resource/timestamped_deploy_spec.rb +8 -29
- data/spec/unit/runner_spec.rb +3 -1
- metadata +141 -191
- data/spec/.DS_Store +0 -0
- data/spec/data/.DS_Store +0 -0
- data/spec/data/lwrp/.DS_Store +0 -0
- data/spec/data/lwrp/providers/.DS_Store +0 -0
- data/spec/data/lwrp/resources/.DS_Store +0 -0
- data/spec/data/lwrp_override/.DS_Store +0 -0
- data/spec/data/lwrp_override/providers/.DS_Store +0 -0
- data/spec/data/lwrp_override/resources/.DS_Store +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1bef47bedec10e78a63b563578b47919c68066b9
|
4
|
+
data.tar.gz: 2073eef92ea6cc252afa09d2c047de4798d6c997
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: efd4822d4ef0e0b4c01666d8093faf3a238cab14b3e421d802be7e19b666d51b2ba39e1c710cbd1e0dee6e8210ba4539a77e9a71aa2a889d317eb191f3f15897
|
7
|
+
data.tar.gz: 4a7d25fc7c1592c5484e7c47b8bfa38c5db25fed17c6d08c76a8e2d226ab173db93d3f7063c74462e148e8f865c29b5b59fc9bfb4179a1fbe73e019e0e3ab957
|
data/README.md
CHANGED
@@ -153,7 +153,9 @@ class Chef
|
|
153
153
|
def file_flags
|
154
154
|
base_flags = File::CREAT|File::TRUNC|File::RDWR
|
155
155
|
# Windows doesn't have symlinks, so it doesn't have NOFOLLOW
|
156
|
-
|
156
|
+
if defined?(File::NOFOLLOW) && !Chef::Config[:follow_client_key_symlink]
|
157
|
+
base_flags |= File::NOFOLLOW
|
158
|
+
end
|
157
159
|
base_flags
|
158
160
|
end
|
159
161
|
end
|
data/lib/chef/config.rb
CHANGED
@@ -396,6 +396,12 @@ class Chef
|
|
396
396
|
# If chef-zero is enabled, this defaults to nil (no authentication).
|
397
397
|
default(:client_key) { chef_zero.enabled ? nil : platform_specific_path("/etc/chef/client.pem") }
|
398
398
|
|
399
|
+
# When registering the client, should we allow the client key location to
|
400
|
+
# be a symlink? eg: /etc/chef/client.pem -> /etc/chef/prod-client.pem
|
401
|
+
# If the path of the key goes through a directory like /tmp this should
|
402
|
+
# never be set to true or its possibly an easily exploitable security hole.
|
403
|
+
default :follow_client_key_symlink, false
|
404
|
+
|
399
405
|
# This secret is used to decrypt encrypted data bag items.
|
400
406
|
default(:encrypted_data_bag_secret) do
|
401
407
|
if File.exist?(platform_specific_path("/etc/chef/encrypted_data_bag_secret"))
|
@@ -491,7 +497,7 @@ class Chef
|
|
491
497
|
default :ssh_gateway, nil
|
492
498
|
default :bootstrap_version, nil
|
493
499
|
default :bootstrap_proxy, nil
|
494
|
-
default :bootstrap_template,
|
500
|
+
default :bootstrap_template, nil
|
495
501
|
default :secret, nil
|
496
502
|
default :secret_file, nil
|
497
503
|
default :identity_file, nil
|
@@ -554,10 +560,12 @@ class Chef
|
|
554
560
|
# used to update files.
|
555
561
|
default :file_atomic_update, true
|
556
562
|
|
557
|
-
#
|
558
|
-
#
|
559
|
-
#
|
560
|
-
|
563
|
+
# There are 3 possible values for this configuration setting.
|
564
|
+
# true => file staging is done in the destination directory
|
565
|
+
# false => file staging is done via tempfiles under ENV['TMP']
|
566
|
+
# :auto => file staging will try using destination directory if possible and
|
567
|
+
# will fall back to ENV['TMP'] if destination directory is not usable.
|
568
|
+
default :file_staging_uses_destdir, :auto
|
561
569
|
|
562
570
|
# Exit if another run is in progress and the chef-client is unable to
|
563
571
|
# get the lock before time expires. If nil, no timeout is enforced. (Exits
|
@@ -617,44 +625,44 @@ class Chef
|
|
617
625
|
#
|
618
626
|
# If there is no 'locale -a' then we return 'en_US.UTF-8' since that is the most commonly
|
619
627
|
# available English UTF-8 locale. However, all modern POSIXen should support 'locale -a'.
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
guessed_locale.gsub(/UTF-?8$/i, "UTF-8")
|
643
|
-
else
|
644
|
-
Chef::Log.warn "Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support."
|
645
|
-
'C'
|
646
|
-
end
|
647
|
-
end
|
648
|
-
rescue
|
649
|
-
if Chef::Platform.windows?
|
650
|
-
Chef::Log.debug "Defaulting to locale en_US.UTF-8 on Windows, until it matters that we do something else."
|
628
|
+
def self.guess_internal_locale
|
629
|
+
# https://github.com/opscode/chef/issues/2181
|
630
|
+
# Some systems have the `locale -a` command, but the result has
|
631
|
+
# invalid characters for the default encoding.
|
632
|
+
#
|
633
|
+
# For example, on CentOS 6 with ENV['LANG'] = "en_US.UTF-8",
|
634
|
+
# `locale -a`.split fails with ArgumentError invalid UTF-8 encoding.
|
635
|
+
locales = shell_out_with_systems_locale!("locale -a").stdout.split
|
636
|
+
case
|
637
|
+
when locales.include?('C.UTF-8')
|
638
|
+
'C.UTF-8'
|
639
|
+
when locales.include?('en_US.UTF-8'), locales.include?('en_US.utf8')
|
640
|
+
'en_US.UTF-8'
|
641
|
+
when locales.include?('en.UTF-8')
|
642
|
+
'en.UTF-8'
|
643
|
+
else
|
644
|
+
# Will match en_ZZ.UTF-8, en_ZZ.utf-8, en_ZZ.UTF8, en_ZZ.utf8
|
645
|
+
guesses = locales.select { |l| l =~ /^en_.*UTF-?8$/i }
|
646
|
+
unless guesses.empty?
|
647
|
+
guessed_locale = guesses.first
|
648
|
+
# Transform into the form en_ZZ.UTF-8
|
649
|
+
guessed_locale.gsub(/UTF-?8$/i, "UTF-8")
|
651
650
|
else
|
652
|
-
Chef::Log.
|
651
|
+
Chef::Log.warn "Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support."
|
652
|
+
'C'
|
653
653
|
end
|
654
|
-
'en_US.UTF-8'
|
655
654
|
end
|
655
|
+
rescue
|
656
|
+
if Chef::Platform.windows?
|
657
|
+
Chef::Log.debug "Defaulting to locale en_US.UTF-8 on Windows, until it matters that we do something else."
|
658
|
+
else
|
659
|
+
Chef::Log.debug "No usable locale -a command found, assuming you have en_US.UTF-8 installed."
|
660
|
+
end
|
661
|
+
'en_US.UTF-8'
|
656
662
|
end
|
657
663
|
|
664
|
+
default :internal_locale, guess_internal_locale
|
665
|
+
|
658
666
|
# Force UTF-8 Encoding, for when we fire up in the 'C' locale or other strange locales (e.g.
|
659
667
|
# japanese windows encodings). If we do not do this, then knife upload will fail when a cookbook's
|
660
668
|
# README.md has UTF-8 characters that do not encode in whatever surrounding encoding we have been
|
@@ -26,7 +26,6 @@ if Chef::Platform::windows? and not Chef::Platform::windows_server_2003?
|
|
26
26
|
end
|
27
27
|
|
28
28
|
require 'win32/eventlog'
|
29
|
-
include Win32
|
30
29
|
end
|
31
30
|
|
32
31
|
class Chef
|
@@ -51,12 +50,12 @@ class Chef
|
|
51
50
|
end
|
52
51
|
|
53
52
|
def initialize
|
54
|
-
@eventlog = EventLog::open('Application')
|
53
|
+
@eventlog = ::Win32::EventLog::open('Application')
|
55
54
|
end
|
56
55
|
|
57
56
|
def run_start(version)
|
58
57
|
@eventlog.report_event(
|
59
|
-
:event_type => EventLog::INFO_TYPE,
|
58
|
+
:event_type => ::Win32::EventLog::INFO_TYPE,
|
60
59
|
:source => SOURCE,
|
61
60
|
:event_id => RUN_START_EVENT_ID,
|
62
61
|
:data => [version]
|
@@ -66,7 +65,7 @@ class Chef
|
|
66
65
|
def run_started(run_status)
|
67
66
|
@run_status = run_status
|
68
67
|
@eventlog.report_event(
|
69
|
-
:event_type => EventLog::INFO_TYPE,
|
68
|
+
:event_type => ::Win32::EventLog::INFO_TYPE,
|
70
69
|
:source => SOURCE,
|
71
70
|
:event_id => RUN_STARTED_EVENT_ID,
|
72
71
|
:data => [run_status.run_id]
|
@@ -75,7 +74,7 @@ class Chef
|
|
75
74
|
|
76
75
|
def run_completed(node)
|
77
76
|
@eventlog.report_event(
|
78
|
-
:event_type => EventLog::INFO_TYPE,
|
77
|
+
:event_type => ::Win32::EventLog::INFO_TYPE,
|
79
78
|
:source => SOURCE,
|
80
79
|
:event_id => RUN_COMPLETED_EVENT_ID,
|
81
80
|
:data => [@run_status.run_id, @run_status.elapsed_time.to_s]
|
@@ -88,7 +87,7 @@ class Chef
|
|
88
87
|
#Exception backtrace: %5
|
89
88
|
def run_failed(e)
|
90
89
|
@eventlog.report_event(
|
91
|
-
:event_type => EventLog::ERROR_TYPE,
|
90
|
+
:event_type => ::Win32::EventLog::ERROR_TYPE,
|
92
91
|
:source => SOURCE,
|
93
92
|
:event_id => RUN_FAILED_EVENT_ID,
|
94
93
|
:data => [@run_status.run_id,
|
data/lib/chef/exceptions.rb
CHANGED
@@ -126,6 +126,13 @@ class Chef
|
|
126
126
|
|
127
127
|
class CannotDetermineHomebrewOwner < Package; end
|
128
128
|
|
129
|
+
# Can not create staging file during file deployment
|
130
|
+
class FileContentStagingError < RuntimeError
|
131
|
+
def initialize(errors)
|
132
|
+
super "Staging tempfile can not be created during file deployment.\n Errors: #{errors.join('\n')}!"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
129
136
|
# A different version of a cookbook was added to a
|
130
137
|
# VersionedRecipeList than the one already there.
|
131
138
|
class CookbookVersionConflict < ArgumentError ; end
|
@@ -155,7 +162,12 @@ class Chef
|
|
155
162
|
# Node::Attribute computes the merged version of of attributes
|
156
163
|
# and makes it read-only. Attempting to modify a read-only
|
157
164
|
# attribute will cause this error.
|
158
|
-
class ImmutableAttributeModification < NoMethodError
|
165
|
+
class ImmutableAttributeModification < NoMethodError
|
166
|
+
def initialize
|
167
|
+
super "Node attributes are read-only when you do not specify which precedence level to set. " +
|
168
|
+
%Q(To set an attribute use code like `node.default["key"] = "value"')
|
169
|
+
end
|
170
|
+
end
|
159
171
|
|
160
172
|
# Merged node attributes are invalidated when the component
|
161
173
|
# attributes are updated. Attempting to read from a stale copy
|
@@ -35,7 +35,22 @@ class Chef
|
|
35
35
|
private
|
36
36
|
|
37
37
|
def tempfile_open
|
38
|
-
tf =
|
38
|
+
tf = nil
|
39
|
+
errors = [ ]
|
40
|
+
|
41
|
+
tempfile_dirnames.each do |tempfile_dirname|
|
42
|
+
begin
|
43
|
+
tf = ::Tempfile.open(tempfile_basename, tempfile_dirname)
|
44
|
+
break
|
45
|
+
rescue SystemCallError => e
|
46
|
+
message = "Creating temp file under '#{tempfile_dirname}' failed with: '#{e.message}'"
|
47
|
+
Chef::Log.debug(message)
|
48
|
+
errors << message
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
raise Chef::Exceptions::FileContentStagingError(errors) if tf.nil?
|
53
|
+
|
39
54
|
# We always process the tempfile in binmode so that we
|
40
55
|
# preserve the line endings of the content.
|
41
56
|
tf.binmode
|
@@ -53,16 +68,29 @@ class Chef
|
|
53
68
|
basename
|
54
69
|
end
|
55
70
|
|
56
|
-
|
71
|
+
# Returns the possible directories for the tempfile to be created in.
|
72
|
+
def tempfile_dirnames
|
57
73
|
# in why-run mode we need to create a Tempfile to compare against, which we will never
|
58
74
|
# wind up deploying, but our enclosing directory for the destdir may not exist yet, so
|
59
75
|
# instead we can reliably always create a Tempfile to compare against in Dir::tmpdir
|
60
|
-
if Chef::Config[:
|
61
|
-
|
76
|
+
if Chef::Config[:why_run]
|
77
|
+
[ Dir.tmpdir ]
|
62
78
|
else
|
63
|
-
|
79
|
+
case Chef::Config[:file_staging_uses_destdir]
|
80
|
+
when :auto
|
81
|
+
# In auto mode we try the destination directory first and fallback to ENV['TMP'] if
|
82
|
+
# that doesn't work.
|
83
|
+
[ ::File.dirname(@new_resource.path), Dir.tmpdir ]
|
84
|
+
when true
|
85
|
+
[ ::File.dirname(@new_resource.path) ]
|
86
|
+
when false
|
87
|
+
[ Dir.tmpdir ]
|
88
|
+
else
|
89
|
+
raise Chef::Exceptions::ConfigurationError, "Unknown setting '#{Chef::Config[:file_staging_uses_destdir]}' for Chef::Config[:file_staging_uses_destdir]. Possible values are :auto, true or false."
|
90
|
+
end
|
64
91
|
end
|
65
92
|
end
|
93
|
+
|
66
94
|
end
|
67
95
|
end
|
68
96
|
end
|
data/lib/chef/knife.rb
CHANGED
@@ -72,6 +72,11 @@ class Chef
|
|
72
72
|
ui.msg(msg)
|
73
73
|
end
|
74
74
|
|
75
|
+
def self.reset_config_loader!
|
76
|
+
@@chef_config_dir = nil
|
77
|
+
@config_loader = nil
|
78
|
+
end
|
79
|
+
|
75
80
|
def self.reset_subcommands!
|
76
81
|
@@subcommands = {}
|
77
82
|
@subcommands_by_category = nil
|
@@ -162,12 +167,15 @@ class Chef
|
|
162
167
|
# Shared with subclasses
|
163
168
|
@@chef_config_dir = nil
|
164
169
|
|
170
|
+
def self.config_loader
|
171
|
+
@config_loader ||= WorkstationConfigLoader.new(nil, Chef::Log)
|
172
|
+
end
|
173
|
+
|
165
174
|
def self.load_config(explicit_config_file)
|
166
|
-
config_loader =
|
175
|
+
config_loader.explicit_config_file = explicit_config_file
|
167
176
|
config_loader.load
|
168
177
|
|
169
178
|
ui.warn("No knife configuration file found") if config_loader.no_config_found?
|
170
|
-
@@chef_config_dir = config_loader.chef_config_dir
|
171
179
|
|
172
180
|
config_loader
|
173
181
|
rescue Exceptions::ConfigurationError => e
|
@@ -176,7 +184,7 @@ class Chef
|
|
176
184
|
end
|
177
185
|
|
178
186
|
def self.chef_config_dir
|
179
|
-
@@chef_config_dir
|
187
|
+
@@chef_config_dir ||= config_loader.chef_config_dir
|
180
188
|
end
|
181
189
|
|
182
190
|
# Run knife for the given +args+ (ARGV), adding +options+ to the list of
|
data/lib/chef/knife/bootstrap.rb
CHANGED
@@ -194,13 +194,15 @@ class Chef
|
|
194
194
|
:description => "Verify the SSL cert for HTTPS requests to the Chef server API.",
|
195
195
|
:boolean => true
|
196
196
|
|
197
|
+
def default_bootstrap_template
|
198
|
+
"chef-full"
|
199
|
+
end
|
200
|
+
|
197
201
|
def bootstrap_template
|
198
|
-
#
|
199
|
-
#
|
200
|
-
#
|
201
|
-
|
202
|
-
# if no option is specified.
|
203
|
-
config[:bootstrap_template] || config[:distro] || config[:template_file] || Chef::Config[:knife][:bootstrap_template]
|
202
|
+
# The order here is important. We want to check if we have the new Chef 12 option is set first.
|
203
|
+
# Knife cloud plugins unfortunately all set a default option for the :distro so it should be at
|
204
|
+
# the end.
|
205
|
+
config[:bootstrap_template] || config[:template_file] || config[:distro] || default_bootstrap_template
|
204
206
|
end
|
205
207
|
|
206
208
|
def find_template
|
@@ -210,7 +212,6 @@ class Chef
|
|
210
212
|
if File.exists?(template)
|
211
213
|
Chef::Log.debug("Using the specified bootstrap template: #{File.dirname(template)}")
|
212
214
|
return template
|
213
|
-
|
214
215
|
end
|
215
216
|
|
216
217
|
# Otherwise search the template directories until we find the right one
|
@@ -27,16 +27,6 @@ class Chef
|
|
27
27
|
# http://trac.misuse.org/science/wiki/DeepMerge
|
28
28
|
module DeepMerge
|
29
29
|
|
30
|
-
class InvalidSubtractiveMerge < ArgumentError; end
|
31
|
-
|
32
|
-
OLD_KNOCKOUT_PREFIX = "!merge:".freeze
|
33
|
-
|
34
|
-
# Regex to match the "knockout prefix" that was used to indicate
|
35
|
-
# subtractive merging in Chef 10.x and previous. Subtractive merging is
|
36
|
-
# removed as of Chef 11, but we detect attempted use of it and raise an
|
37
|
-
# error (see: raise_if_knockout_used!)
|
38
|
-
OLD_KNOCKOUT_MATCH = %r[!merge].freeze
|
39
|
-
|
40
30
|
extend self
|
41
31
|
|
42
32
|
def merge(first, second)
|
@@ -46,15 +36,6 @@ class Chef
|
|
46
36
|
DeepMerge.deep_merge(second, first)
|
47
37
|
end
|
48
38
|
|
49
|
-
# Inherited roles use the knockout_prefix array subtraction functionality
|
50
|
-
# This is likely to go away in Chef >= 0.11
|
51
|
-
def role_merge(first, second)
|
52
|
-
first = Mash.new(first) unless first.kind_of?(Mash)
|
53
|
-
second = Mash.new(second) unless second.kind_of?(Mash)
|
54
|
-
|
55
|
-
DeepMerge.deep_merge(second, first)
|
56
|
-
end
|
57
|
-
|
58
39
|
class InvalidParameter < StandardError; end
|
59
40
|
|
60
41
|
# Deep Merge core documentation.
|
@@ -77,22 +58,15 @@ class Chef
|
|
77
58
|
dest = source; return dest
|
78
59
|
end
|
79
60
|
|
80
|
-
raise_if_knockout_used!(source)
|
81
|
-
raise_if_knockout_used!(dest)
|
82
61
|
case source
|
83
62
|
when nil
|
84
63
|
dest
|
85
64
|
when Hash
|
86
65
|
if dest.kind_of?(Hash)
|
87
66
|
source.each do |src_key, src_value|
|
88
|
-
if dest
|
89
|
-
|
90
|
-
dest[src_key] = nil
|
91
|
-
else
|
92
|
-
dest[src_key] = deep_merge!(src_value, dest[src_key])
|
93
|
-
end
|
67
|
+
if dest[src_key]
|
68
|
+
dest[src_key] = deep_merge!(src_value, dest[src_key])
|
94
69
|
else # dest[src_key] doesn't exist so we take whatever source has
|
95
|
-
raise_if_knockout_used!(src_value)
|
96
70
|
dest[src_key] = src_value
|
97
71
|
end
|
98
72
|
end
|
@@ -131,11 +105,19 @@ class Chef
|
|
131
105
|
# If there are two Hashes, recursively merge.
|
132
106
|
if merge_onto.kind_of?(Hash) && merge_with.kind_of?(Hash)
|
133
107
|
merge_with.each do |key, merge_with_value|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
108
|
+
value =
|
109
|
+
if merge_onto.has_key?(key)
|
110
|
+
hash_only_merge(merge_onto[key], merge_with_value)
|
111
|
+
else
|
112
|
+
merge_with_value
|
113
|
+
end
|
114
|
+
|
115
|
+
if merge_onto.respond_to?(:public_method_that_only_deep_merge_should_use)
|
116
|
+
# we can't call ImmutableMash#[]= because its immutable, but we need to mutate it to build it in-place
|
117
|
+
merge_onto.public_method_that_only_deep_merge_should_use(key, value)
|
118
|
+
else
|
119
|
+
merge_onto[key] = value
|
120
|
+
end
|
139
121
|
end
|
140
122
|
merge_onto
|
141
123
|
|
@@ -149,27 +131,6 @@ class Chef
|
|
149
131
|
end
|
150
132
|
end
|
151
133
|
|
152
|
-
# Checks for attempted use of subtractive merge, which was removed for
|
153
|
-
# Chef 11.0. If subtractive merge use is detected, will raise an
|
154
|
-
# InvalidSubtractiveMerge exception.
|
155
|
-
def raise_if_knockout_used!(obj)
|
156
|
-
if uses_knockout?(obj)
|
157
|
-
raise InvalidSubtractiveMerge, "subtractive merge with !merge is no longer supported"
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
# Checks for attempted use of subtractive merge in +obj+.
|
162
|
-
def uses_knockout?(obj)
|
163
|
-
case obj
|
164
|
-
when String
|
165
|
-
obj =~ OLD_KNOCKOUT_MATCH
|
166
|
-
when Array
|
167
|
-
obj.any? {|element| element.respond_to?(:gsub) && element =~ OLD_KNOCKOUT_MATCH }
|
168
|
-
else
|
169
|
-
false
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
134
|
def deep_merge(source, dest)
|
174
135
|
deep_merge!(safe_dup(source), safe_dup(dest))
|
175
136
|
end
|