chef 12.4.3 → 12.5.0.alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +1 -2
- data/lib/chef.rb +1 -1
- data/lib/chef/application/solo.rb +1 -1
- data/lib/chef/application/windows_service_manager.rb +17 -12
- data/lib/chef/chef_class.rb +7 -0
- data/lib/chef/chef_fs/config.rb +22 -24
- data/lib/chef/chef_fs/file_pattern.rb +4 -15
- data/lib/chef/chef_fs/file_system/cookbook_dir.rb +1 -0
- data/lib/chef/chef_fs/knife.rb +35 -7
- data/lib/chef/chef_fs/path_utils.rb +65 -34
- data/lib/chef/constants.rb +27 -0
- data/lib/chef/delayed_evaluator.rb +21 -0
- data/lib/chef/dsl/recipe.rb +20 -2
- data/lib/chef/event_dispatch/base.rb +40 -16
- data/lib/chef/event_dispatch/dsl.rb +64 -0
- data/lib/chef/exceptions.rb +6 -1
- data/lib/chef/formatters/doc.rb +3 -1
- data/lib/chef/guard_interpreter/resource_guard_interpreter.rb +3 -1
- data/lib/chef/http/http_request.rb +1 -1
- data/lib/chef/knife/bootstrap/templates/chef-full.erb +1 -1
- data/lib/chef/knife/ssl_check.rb +3 -2
- data/lib/chef/knife/user_edit.rb +1 -2
- data/lib/chef/mixin/params_validate.rb +362 -135
- data/lib/chef/node.rb +19 -0
- data/lib/chef/platform/handler_map.rb +0 -5
- data/lib/chef/platform/rebooter.rb +1 -1
- data/lib/chef/property.rb +539 -0
- data/lib/chef/provider.rb +129 -12
- data/lib/chef/provider/deploy.rb +3 -5
- data/lib/chef/provider/lwrp_base.rb +1 -75
- data/lib/chef/provider/package.rb +1 -1
- data/lib/chef/provider/powershell_script.rb +32 -19
- data/lib/chef/provider/registry_key.rb +5 -5
- data/lib/chef/provider/service/macosx.rb +5 -1
- data/lib/chef/recipe.rb +1 -8
- data/lib/chef/resource.rb +499 -84
- data/lib/chef/resource/file/verification.rb +7 -1
- data/lib/chef/resource/lwrp_base.rb +1 -7
- data/lib/chef/run_context.rb +404 -83
- data/lib/chef/version.rb +1 -1
- data/lib/chef/win32/registry.rb +10 -2
- data/lib/chef/workstation_config_loader.rb +3 -158
- data/spec/data/run_context/cookbooks/include/recipes/default.rb +24 -0
- data/spec/data/run_context/cookbooks/include/recipes/includee.rb +3 -0
- data/spec/functional/rebooter_spec.rb +1 -1
- data/spec/functional/resource/{powershell_spec.rb → powershell_script_spec.rb} +3 -3
- data/spec/functional/win32/registry_helper_spec.rb +12 -0
- data/spec/functional/win32/service_manager_spec.rb +2 -2
- data/spec/integration/knife/chef_repo_path_spec.rb +13 -11
- data/spec/integration/recipes/recipe_dsl_spec.rb +0 -15
- data/spec/integration/recipes/resource_action_spec.rb +343 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/support/shared/functional/win32_service.rb +2 -1
- data/spec/unit/application/solo_spec.rb +4 -3
- data/spec/unit/chef_class_spec.rb +23 -0
- data/spec/unit/chef_fs/path_util_spec.rb +108 -0
- data/spec/unit/event_dispatch/dsl_spec.rb +87 -0
- data/spec/unit/json_compat_spec.rb +4 -3
- data/spec/unit/knife/ssl_check_spec.rb +4 -0
- data/spec/unit/mixin/params_validate_spec.rb +4 -2
- data/spec/unit/node_spec.rb +7 -0
- data/spec/unit/property/state_spec.rb +506 -0
- data/spec/unit/property/validation_spec.rb +658 -0
- data/spec/unit/property_spec.rb +968 -0
- data/spec/unit/provider/{powershell_spec.rb → powershell_script_spec.rb} +0 -0
- data/spec/unit/provider/registry_key_spec.rb +12 -0
- data/spec/unit/provider/service/macosx_spec.rb +4 -4
- data/spec/unit/provider_spec.rb +1 -3
- data/spec/unit/recipe_spec.rb +0 -4
- data/spec/unit/registry_helper_spec.rb +15 -1
- data/spec/unit/resource/file/verification_spec.rb +33 -5
- data/spec/unit/resource/{powershell_spec.rb → powershell_script_spec.rb} +0 -0
- data/spec/unit/resource_spec.rb +2 -2
- data/spec/unit/run_context/child_run_context_spec.rb +133 -0
- data/spec/unit/run_context_spec.rb +7 -0
- metadata +25 -25
- data/spec/unit/workstation_config_loader_spec.rb +0 -283
data/lib/chef/provider.rb
CHANGED
@@ -26,6 +26,7 @@ require 'chef/mixin/powershell_out'
|
|
26
26
|
require 'chef/mixin/provides'
|
27
27
|
require 'chef/platform/service_helpers'
|
28
28
|
require 'chef/node_map'
|
29
|
+
require 'forwardable'
|
29
30
|
|
30
31
|
class Chef
|
31
32
|
class Provider
|
@@ -65,6 +66,7 @@ class Chef
|
|
65
66
|
|
66
67
|
@recipe_name = nil
|
67
68
|
@cookbook_name = nil
|
69
|
+
self.class.include_resource_dsl_module(new_resource)
|
68
70
|
end
|
69
71
|
|
70
72
|
def whyrun_mode?
|
@@ -119,11 +121,11 @@ class Chef
|
|
119
121
|
check_resource_semantics!
|
120
122
|
|
121
123
|
# user-defined LWRPs may include unsafe load_current_resource methods that cannot be run in whyrun mode
|
122
|
-
if
|
124
|
+
if whyrun_mode? && !whyrun_supported?
|
125
|
+
events.resource_current_state_load_bypassed(@new_resource, @action, @current_resource)
|
126
|
+
else
|
123
127
|
load_current_resource
|
124
128
|
events.resource_current_state_loaded(@new_resource, @action, @current_resource)
|
125
|
-
elsif whyrun_mode? && !whyrun_supported?
|
126
|
-
events.resource_current_state_load_bypassed(@new_resource, @action, @current_resource)
|
127
129
|
end
|
128
130
|
|
129
131
|
define_resource_requirements
|
@@ -136,9 +138,7 @@ class Chef
|
|
136
138
|
# we can't execute the action.
|
137
139
|
# in non-whyrun mode, this will still cause the action to be
|
138
140
|
# executed normally.
|
139
|
-
if
|
140
|
-
send("action_#{@action}")
|
141
|
-
elsif whyrun_mode?
|
141
|
+
if whyrun_mode? && (!whyrun_supported? || requirements.action_blocked?(@action))
|
142
142
|
events.resource_bypassed(@new_resource, @action, self)
|
143
143
|
else
|
144
144
|
send("action_#{@action}")
|
@@ -183,6 +183,121 @@ class Chef
|
|
183
183
|
Chef::ProviderResolver.new(node, resource, :nothing).provided_by?(self)
|
184
184
|
end
|
185
185
|
|
186
|
+
#
|
187
|
+
# Include attributes, public and protected methods from this Resource in
|
188
|
+
# the provider.
|
189
|
+
#
|
190
|
+
# If this is set to true, delegate methods are included in the provider so
|
191
|
+
# that you can call (for example) `attrname` and it will call
|
192
|
+
# `new_resource.attrname`.
|
193
|
+
#
|
194
|
+
# The actual include does not happen until the first time the Provider
|
195
|
+
# is instantiated (so that we don't have to worry about load order issues).
|
196
|
+
#
|
197
|
+
# @param include_resource_dsl [Boolean] Whether to include resource DSL or
|
198
|
+
# not (defaults to `false`).
|
199
|
+
#
|
200
|
+
def self.include_resource_dsl(include_resource_dsl)
|
201
|
+
@include_resource_dsl = include_resource_dsl
|
202
|
+
end
|
203
|
+
|
204
|
+
# Create the resource DSL module that forwards resource methods to new_resource
|
205
|
+
#
|
206
|
+
# @api private
|
207
|
+
def self.include_resource_dsl_module(resource)
|
208
|
+
if @include_resource_dsl && !defined?(@included_resource_dsl_module)
|
209
|
+
provider_class = self
|
210
|
+
@included_resource_dsl_module = Module.new do
|
211
|
+
extend Forwardable
|
212
|
+
define_singleton_method(:to_s) { "#{resource_class} forwarder module" }
|
213
|
+
define_singleton_method(:inspect) { to_s }
|
214
|
+
dsl_methods =
|
215
|
+
resource.class.public_instance_methods +
|
216
|
+
resource.class.protected_instance_methods -
|
217
|
+
provider_class.instance_methods
|
218
|
+
def_delegators(:new_resource, *dsl_methods)
|
219
|
+
end
|
220
|
+
include @included_resource_dsl_module
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
# Enables inline evaluation of resources in provider actions.
|
225
|
+
#
|
226
|
+
# Without this option, any resources declared inside the Provider are added
|
227
|
+
# to the resource collection after the current position at the time the
|
228
|
+
# action is executed. Because they are added to the primary resource
|
229
|
+
# collection for the chef run, they can notify other resources outside
|
230
|
+
# the Provider, and potentially be notified by resources outside the Provider
|
231
|
+
# (but this is complicated by the fact that they don't exist until the
|
232
|
+
# provider executes). In this mode, it is impossible to correctly set the
|
233
|
+
# updated_by_last_action flag on the parent Provider resource, since it
|
234
|
+
# executes and returns before its component resources are run.
|
235
|
+
#
|
236
|
+
# With this option enabled, each action creates a temporary run_context
|
237
|
+
# with its own resource collection, evaluates the action's code in that
|
238
|
+
# context, and then converges the resources created. If any resources
|
239
|
+
# were updated, then this provider's new_resource will be marked updated.
|
240
|
+
#
|
241
|
+
# In this mode, resources created within the Provider cannot interact with
|
242
|
+
# external resources via notifies, though notifications to other
|
243
|
+
# resources within the Provider will work. Delayed notifications are executed
|
244
|
+
# at the conclusion of the provider's action, *not* at the end of the
|
245
|
+
# main chef run.
|
246
|
+
#
|
247
|
+
# This mode of evaluation is experimental, but is believed to be a better
|
248
|
+
# set of tradeoffs than the append-after mode, so it will likely become
|
249
|
+
# the default in a future major release of Chef.
|
250
|
+
#
|
251
|
+
def self.use_inline_resources
|
252
|
+
extend InlineResources::ClassMethods
|
253
|
+
include InlineResources
|
254
|
+
end
|
255
|
+
|
256
|
+
# Chef::Provider::InlineResources
|
257
|
+
# Implementation of inline resource convergence for providers. See
|
258
|
+
# Provider.use_inline_resources for a longer explanation.
|
259
|
+
#
|
260
|
+
# This code is restricted to a module so that it can be selectively
|
261
|
+
# applied to providers on an opt-in basis.
|
262
|
+
#
|
263
|
+
# @api private
|
264
|
+
module InlineResources
|
265
|
+
|
266
|
+
# Our run context is a child of the main run context; that gives us a
|
267
|
+
# whole new resource collection and notification set.
|
268
|
+
def initialize(resource, run_context)
|
269
|
+
super(resource, run_context.create_child)
|
270
|
+
end
|
271
|
+
|
272
|
+
# Class methods for InlineResources. Overrides the `action` DSL method
|
273
|
+
# with one that enables inline resource convergence.
|
274
|
+
#
|
275
|
+
# @api private
|
276
|
+
module ClassMethods
|
277
|
+
# Defines an action method on the provider, running the block to
|
278
|
+
# compile the resources, converging them, and then checking if any
|
279
|
+
# were updated (and updating new-resource if so)
|
280
|
+
def action(name, &block)
|
281
|
+
class_eval <<-EOM, __FILE__, __LINE__+1
|
282
|
+
def action_#{name}
|
283
|
+
return_value = compile_action_#{name}
|
284
|
+
Chef::Runner.new(run_context).converge
|
285
|
+
return_value
|
286
|
+
ensure
|
287
|
+
if run_context.resource_collection.any? {|r| r.updated? }
|
288
|
+
new_resource.updated_by_last_action(true)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
EOM
|
292
|
+
# We put the action in its own method so that super() works.
|
293
|
+
define_method("compile_action_#{name}", &block)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
require 'chef/dsl/recipe'
|
298
|
+
include Chef::DSL::Recipe::FullDSL
|
299
|
+
end
|
300
|
+
|
186
301
|
protected
|
187
302
|
|
188
303
|
def converge_actions
|
@@ -200,12 +315,14 @@ class Chef
|
|
200
315
|
# manipulating notifies.
|
201
316
|
|
202
317
|
converge_by ("evaluate block and run any associated actions") do
|
203
|
-
saved_run_context =
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
318
|
+
saved_run_context = run_context
|
319
|
+
begin
|
320
|
+
@run_context = run_context.create_child
|
321
|
+
instance_eval(&block)
|
322
|
+
Chef::Runner.new(run_context).converge
|
323
|
+
ensure
|
324
|
+
@run_context = saved_run_context
|
325
|
+
end
|
209
326
|
end
|
210
327
|
end
|
211
328
|
|
data/lib/chef/provider/deploy.rb
CHANGED
@@ -373,11 +373,9 @@ class Chef
|
|
373
373
|
end
|
374
374
|
|
375
375
|
def gem_resource_collection_runner
|
376
|
-
|
377
|
-
gem_packages.each { |rbgem|
|
378
|
-
|
379
|
-
gems_run_context.resource_collection = gems_collection
|
380
|
-
Chef::Runner.new(gems_run_context)
|
376
|
+
child_context = run_context.create_child
|
377
|
+
gem_packages.each { |rbgem| child_context.resource_collection.insert(rbgem) }
|
378
|
+
Chef::Runner.new(child_context)
|
381
379
|
end
|
382
380
|
|
383
381
|
def gem_packages
|
@@ -28,52 +28,10 @@ class Chef
|
|
28
28
|
# Base class from which LWRP providers inherit.
|
29
29
|
class LWRPBase < Provider
|
30
30
|
|
31
|
-
# Chef::Provider::LWRPBase::InlineResources
|
32
|
-
# Implementation of inline resource convergence for LWRP providers. See
|
33
|
-
# Provider::LWRPBase.use_inline_resources for a longer explanation.
|
34
|
-
#
|
35
|
-
# This code is restricted to a module so that it can be selectively
|
36
|
-
# applied to providers on an opt-in basis.
|
37
|
-
module InlineResources
|
38
|
-
|
39
|
-
# Class methods for InlineResources. Overrides the `action` DSL method
|
40
|
-
# with one that enables inline resource convergence.
|
41
|
-
module ClassMethods
|
42
|
-
# Defines an action method on the provider, using
|
43
|
-
# recipe_eval_with_update_check to execute the given block.
|
44
|
-
def action(name, &block)
|
45
|
-
define_method("action_#{name}") do
|
46
|
-
recipe_eval_with_update_check(&block)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
# Executes the given block in a temporary run_context with its own
|
52
|
-
# resource collection. After the block is executed, any resources
|
53
|
-
# declared inside are converged, and if any are updated, the
|
54
|
-
# new_resource will be marked updated.
|
55
|
-
def recipe_eval_with_update_check(&block)
|
56
|
-
saved_run_context = @run_context
|
57
|
-
temp_run_context = @run_context.dup
|
58
|
-
@run_context = temp_run_context
|
59
|
-
@run_context.resource_collection = Chef::ResourceCollection.new
|
60
|
-
|
61
|
-
return_value = instance_eval(&block)
|
62
|
-
Chef::Runner.new(@run_context).converge
|
63
|
-
return_value
|
64
|
-
ensure
|
65
|
-
@run_context = saved_run_context
|
66
|
-
if temp_run_context.resource_collection.any? {|r| r.updated? }
|
67
|
-
new_resource.updated_by_last_action(true)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
end
|
72
|
-
|
73
31
|
include Chef::DSL::Recipe
|
74
32
|
|
75
33
|
# These were previously provided by Chef::Mixin::RecipeDefinitionDSLCore.
|
76
|
-
# They are not included by its
|
34
|
+
# They are not included by its replacement, Chef::DSL::Recipe, but
|
77
35
|
# they may be used in existing LWRPs.
|
78
36
|
include Chef::DSL::PlatformIntrospection
|
79
37
|
include Chef::DSL::DataQuery
|
@@ -122,38 +80,6 @@ class Chef
|
|
122
80
|
provider_class
|
123
81
|
end
|
124
82
|
|
125
|
-
# Enables inline evaluation of resources in provider actions.
|
126
|
-
#
|
127
|
-
# Without this option, any resources declared inside the LWRP are added
|
128
|
-
# to the resource collection after the current position at the time the
|
129
|
-
# action is executed. Because they are added to the primary resource
|
130
|
-
# collection for the chef run, they can notify other resources outside
|
131
|
-
# the LWRP, and potentially be notified by resources outside the LWRP
|
132
|
-
# (but this is complicated by the fact that they don't exist until the
|
133
|
-
# provider executes). In this mode, it is impossible to correctly set the
|
134
|
-
# updated_by_last_action flag on the parent LWRP resource, since it
|
135
|
-
# executes and returns before its component resources are run.
|
136
|
-
#
|
137
|
-
# With this option enabled, each action creates a temporary run_context
|
138
|
-
# with its own resource collection, evaluates the action's code in that
|
139
|
-
# context, and then converges the resources created. If any resources
|
140
|
-
# were updated, then this provider's new_resource will be marked updated.
|
141
|
-
#
|
142
|
-
# In this mode, resources created within the LWRP cannot interact with
|
143
|
-
# external resources via notifies, though notifications to other
|
144
|
-
# resources within the LWRP will work. Delayed notifications are executed
|
145
|
-
# at the conclusion of the provider's action, *not* at the end of the
|
146
|
-
# main chef run.
|
147
|
-
#
|
148
|
-
# This mode of evaluation is experimental, but is believed to be a better
|
149
|
-
# set of tradeoffs than the append-after mode, so it will likely become
|
150
|
-
# the default in a future major release of Chef.
|
151
|
-
#
|
152
|
-
def use_inline_resources
|
153
|
-
extend InlineResources::ClassMethods
|
154
|
-
include InlineResources
|
155
|
-
end
|
156
|
-
|
157
83
|
# DSL for defining a provider's actions.
|
158
84
|
def action(name, &block)
|
159
85
|
define_method("action_#{name}") do
|
@@ -142,7 +142,7 @@ class Chef
|
|
142
142
|
def action_remove
|
143
143
|
if removing_package?
|
144
144
|
description = @new_resource.version ? "version #{@new_resource.version} of " : ""
|
145
|
-
converge_by("remove #{description}
|
145
|
+
converge_by("remove #{description}package #{@current_resource.package_name}") do
|
146
146
|
remove_package(@current_resource.package_name, @new_resource.version)
|
147
147
|
Chef::Log.info("#{@new_resource} removed")
|
148
148
|
end
|
@@ -30,8 +30,8 @@ class Chef
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def action_run
|
33
|
-
|
34
|
-
super
|
33
|
+
validate_script_syntax!
|
34
|
+
super
|
35
35
|
end
|
36
36
|
|
37
37
|
def flags
|
@@ -62,30 +62,43 @@ class Chef
|
|
62
62
|
def validate_script_syntax!
|
63
63
|
interpreter_arguments = default_interpreter_flags.join(' ')
|
64
64
|
Tempfile.open(['chef_powershell_script-user-code', '.ps1']) do | user_script_file |
|
65
|
-
|
66
|
-
|
65
|
+
# Wrap the user's code in a PowerShell script block so that
|
66
|
+
# it isn't executed. However, syntactically invalid script
|
67
|
+
# in that block will still trigger a syntax error which is
|
68
|
+
# exactly what we want here -- verify the syntax without
|
69
|
+
# actually running the script.
|
70
|
+
user_code_wrapped_in_powershell_script_block = <<-EOH
|
71
|
+
{
|
72
|
+
#{@new_resource.code}
|
73
|
+
}
|
74
|
+
EOH
|
75
|
+
user_script_file.puts user_code_wrapped_in_powershell_script_block
|
67
76
|
|
77
|
+
# A .close or explicit .flush required to ensure the file is
|
78
|
+
# written to the file system at this point, which is required since
|
79
|
+
# the intent is to execute the code just written to it.
|
80
|
+
user_script_file.close
|
68
81
|
validation_command = "\"#{interpreter}\" #{interpreter_arguments} -Command #{user_script_file.path}"
|
69
82
|
|
70
|
-
#
|
71
|
-
# to be suppressed
|
72
|
-
#
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
83
|
+
# Note that other script providers like bash allow syntax errors
|
84
|
+
# to be suppressed by setting 'returns' to a value that the
|
85
|
+
# interpreter would return as a status code in the syntax
|
86
|
+
# error case. We explicitly don't do this here -- syntax
|
87
|
+
# errors will not be suppressed, since doing so could make
|
88
|
+
# it harder for users to detect / debug invalid scripts.
|
89
|
+
|
90
|
+
# Therefore, the only return value for a syntactically valid
|
91
|
+
# script is 0. If an exception is raised by shellout, this
|
92
|
+
# means a non-zero return and thus a syntactically invalid script.
|
93
|
+
shell_out!(validation_command, {returns: [0]})
|
81
94
|
end
|
82
95
|
end
|
83
96
|
|
84
97
|
def default_interpreter_flags
|
85
|
-
# 'Bypass' is preferable since it doesn't require
|
86
|
-
# for files such as PowerShell modules
|
87
|
-
# Internet. However, 'Bypass' is not supported
|
88
|
-
# PowerShell 3.0, so the fallback is 'Unrestricted'
|
98
|
+
# Execution policy 'Bypass' is preferable since it doesn't require
|
99
|
+
# user input confirmation for files such as PowerShell modules
|
100
|
+
# downloaded from the Internet. However, 'Bypass' is not supported
|
101
|
+
# prior to PowerShell 3.0, so the fallback is 'Unrestricted'
|
89
102
|
execution_policy = Chef::Platform.supports_powershell_execution_bypass?(run_context.node) ? 'Bypass' : 'Unrestricted'
|
90
103
|
|
91
104
|
[
|
@@ -64,7 +64,7 @@ class Chef
|
|
64
64
|
|
65
65
|
def values_to_hash(values)
|
66
66
|
if values
|
67
|
-
@name_hash = Hash[values.map { |val| [val[:name], val] }]
|
67
|
+
@name_hash = Hash[values.map { |val| [val[:name].downcase, val] }]
|
68
68
|
else
|
69
69
|
@name_hash = {}
|
70
70
|
end
|
@@ -100,8 +100,8 @@ class Chef
|
|
100
100
|
end
|
101
101
|
end
|
102
102
|
@new_resource.unscrubbed_values.each do |value|
|
103
|
-
if @name_hash.has_key?(value[:name])
|
104
|
-
current_value = @name_hash[value[:name]]
|
103
|
+
if @name_hash.has_key?(value[:name].downcase)
|
104
|
+
current_value = @name_hash[value[:name].downcase]
|
105
105
|
unless current_value[:type] == value[:type] && current_value[:data] == value[:data]
|
106
106
|
converge_by("set value #{value}") do
|
107
107
|
registry.set_value(@new_resource.key, value)
|
@@ -122,7 +122,7 @@ class Chef
|
|
122
122
|
end
|
123
123
|
end
|
124
124
|
@new_resource.unscrubbed_values.each do |value|
|
125
|
-
unless @name_hash.has_key?(value[:name])
|
125
|
+
unless @name_hash.has_key?(value[:name].downcase)
|
126
126
|
converge_by("create value #{value}") do
|
127
127
|
registry.set_value(@new_resource.key, value)
|
128
128
|
end
|
@@ -133,7 +133,7 @@ class Chef
|
|
133
133
|
def action_delete
|
134
134
|
if registry.key_exists?(@new_resource.key)
|
135
135
|
@new_resource.unscrubbed_values.each do |value|
|
136
|
-
if @name_hash.has_key?(value[:name])
|
136
|
+
if @name_hash.has_key?(value[:name].downcase)
|
137
137
|
converge_by("delete value #{value}") do
|
138
138
|
registry.delete_value(@new_resource.key, value)
|
139
139
|
end
|
@@ -42,6 +42,10 @@ class Chef
|
|
42
42
|
|
43
43
|
PLIST_DIRS = gather_plist_dirs
|
44
44
|
|
45
|
+
def this_version_or_newer?(this_version)
|
46
|
+
Gem::Version.new(node['platform_version']) >= Gem::Version.new(this_version)
|
47
|
+
end
|
48
|
+
|
45
49
|
def load_current_resource
|
46
50
|
@current_resource = Chef::Resource::MacosxService.new(@new_resource.name)
|
47
51
|
@current_resource.service_name(@new_resource.service_name)
|
@@ -56,7 +60,7 @@ class Chef
|
|
56
60
|
@console_user = Etc.getlogin
|
57
61
|
Chef::Log.debug("#{new_resource} console_user: '#{@console_user}'")
|
58
62
|
cmd = "su "
|
59
|
-
param =
|
63
|
+
param = this_version_or_newer?('10.10') ? '' : '-l '
|
60
64
|
@base_user_cmd = cmd + param + "#{@console_user} -c"
|
61
65
|
# Default LauchAgent session should be Aqua
|
62
66
|
@session_type = 'Aqua' if @session_type.nil?
|
data/lib/chef/recipe.rb
CHANGED
@@ -36,14 +36,7 @@ class Chef
|
|
36
36
|
# A Recipe object is the context in which Chef recipes are evaluated.
|
37
37
|
class Recipe
|
38
38
|
|
39
|
-
include Chef::DSL::
|
40
|
-
include Chef::DSL::PlatformIntrospection
|
41
|
-
include Chef::DSL::IncludeRecipe
|
42
|
-
include Chef::DSL::Recipe
|
43
|
-
include Chef::DSL::RegistryHelper
|
44
|
-
include Chef::DSL::RebootPending
|
45
|
-
include Chef::DSL::Audit
|
46
|
-
include Chef::DSL::Powershell
|
39
|
+
include Chef::DSL::Recipe::FullDSL
|
47
40
|
|
48
41
|
include Chef::Mixin::FromFile
|
49
42
|
include Chef::Mixin::Deprecation
|
data/lib/chef/resource.rb
CHANGED
@@ -58,8 +58,6 @@ class Chef
|
|
58
58
|
include Chef::Mixin::ShellOut
|
59
59
|
include Chef::Mixin::PowershellOut
|
60
60
|
|
61
|
-
NULL_ARG = Object.new
|
62
|
-
|
63
61
|
#
|
64
62
|
# The node the current Chef run is using.
|
65
63
|
#
|
@@ -103,7 +101,7 @@ class Chef
|
|
103
101
|
# @param run_context The context of the Chef run. Corresponds to #run_context.
|
104
102
|
#
|
105
103
|
def initialize(name, run_context=nil)
|
106
|
-
name(name)
|
104
|
+
name(name) unless name.nil?
|
107
105
|
@run_context = run_context
|
108
106
|
@noop = nil
|
109
107
|
@before = nil
|
@@ -132,37 +130,27 @@ class Chef
|
|
132
130
|
end
|
133
131
|
|
134
132
|
#
|
135
|
-
# The
|
136
|
-
#
|
137
|
-
# This special resource attribute is set automatically from the declaration
|
138
|
-
# of the resource, e.g.
|
139
|
-
#
|
140
|
-
# execute 'Vitruvius' do
|
141
|
-
# command 'ls'
|
142
|
-
# end
|
143
|
-
#
|
144
|
-
# Will set the name to "Vitruvius".
|
145
|
-
#
|
146
|
-
# This is also used in to_s to show the resource name, e.g. `execute[Vitruvius]`.
|
133
|
+
# The list of properties defined on this resource.
|
147
134
|
#
|
148
|
-
#
|
135
|
+
# Everything defined with `property` is in this list.
|
149
136
|
#
|
150
|
-
#
|
151
|
-
#
|
152
|
-
#
|
137
|
+
# @param include_superclass [Boolean] `true` to include properties defined
|
138
|
+
# on superclasses; `false` or `nil` to return the list of properties
|
139
|
+
# directly on this class.
|
153
140
|
#
|
154
|
-
# @
|
155
|
-
# @return [String] The name of this Resource.
|
141
|
+
# @return [Hash<Symbol,Property>] The list of property names and types.
|
156
142
|
#
|
157
|
-
def
|
158
|
-
|
159
|
-
|
160
|
-
|
143
|
+
def self.properties(include_superclass=true)
|
144
|
+
@properties ||= {}
|
145
|
+
if include_superclass
|
146
|
+
if superclass.respond_to?(:properties)
|
147
|
+
superclass.properties.merge(@properties)
|
161
148
|
else
|
162
|
-
@
|
149
|
+
@properties.dup
|
163
150
|
end
|
151
|
+
else
|
152
|
+
@properties
|
164
153
|
end
|
165
|
-
@name
|
166
154
|
end
|
167
155
|
|
168
156
|
#
|
@@ -182,8 +170,7 @@ class Chef
|
|
182
170
|
end
|
183
171
|
@action = arg
|
184
172
|
else
|
185
|
-
|
186
|
-
@action || self.class.default_action
|
173
|
+
@action
|
187
174
|
end
|
188
175
|
end
|
189
176
|
|
@@ -478,13 +465,21 @@ class Chef
|
|
478
465
|
#
|
479
466
|
# Get the value of the state attributes in this resource as a hash.
|
480
467
|
#
|
468
|
+
# Does not include properties that are not set (unless they are identity
|
469
|
+
# properties).
|
470
|
+
#
|
481
471
|
# @return [Hash{Symbol => Object}] A Hash of attribute => value for the
|
482
472
|
# Resource class's `state_attrs`.
|
473
|
+
#
|
483
474
|
def state_for_resource_reporter
|
484
|
-
|
485
|
-
|
486
|
-
|
475
|
+
state = {}
|
476
|
+
state_properties = self.class.state_properties
|
477
|
+
state_properties.each do |property|
|
478
|
+
if property.identity? || property.is_set?(self)
|
479
|
+
state[property.name] = send(property.name)
|
480
|
+
end
|
487
481
|
end
|
482
|
+
state
|
488
483
|
end
|
489
484
|
|
490
485
|
#
|
@@ -497,17 +492,22 @@ class Chef
|
|
497
492
|
alias_method :state, :state_for_resource_reporter
|
498
493
|
|
499
494
|
#
|
500
|
-
# The value of the identity
|
501
|
-
#
|
495
|
+
# The value of the identity of this resource.
|
496
|
+
#
|
497
|
+
# - If there are no identity properties on the resource, `name` is returned.
|
498
|
+
# - If there is exactly one identity property on the resource, it is returned.
|
499
|
+
# - If there are more than one, they are returned in a hash.
|
502
500
|
#
|
503
|
-
# @return The
|
501
|
+
# @return [Object,Hash<Symbol,Object>] The identity of this resource.
|
504
502
|
#
|
505
503
|
def identity
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
name
|
504
|
+
result = {}
|
505
|
+
identity_properties = self.class.identity_properties
|
506
|
+
identity_properties.each do |property|
|
507
|
+
result[property.name] = send(property.name)
|
510
508
|
end
|
509
|
+
return result.values.first if identity_properties.size == 1
|
510
|
+
result
|
511
511
|
end
|
512
512
|
|
513
513
|
#
|
@@ -529,9 +529,7 @@ class Chef
|
|
529
529
|
#
|
530
530
|
# Equivalent to #ignore_failure.
|
531
531
|
#
|
532
|
-
|
533
|
-
ignore_failure(arg)
|
534
|
-
end
|
532
|
+
alias :epic_fail :ignore_failure
|
535
533
|
|
536
534
|
#
|
537
535
|
# Make this resource into an exact (shallow) copy of the other resource.
|
@@ -686,66 +684,389 @@ class Chef
|
|
686
684
|
#
|
687
685
|
# The provider class for this resource.
|
688
686
|
#
|
687
|
+
# If `action :x do ... end` has been declared on this resource or its
|
688
|
+
# superclasses, this will return the `action_provider_class`.
|
689
|
+
#
|
689
690
|
# If this is not set, `provider_for_action` will dynamically determine the
|
690
691
|
# provider.
|
691
692
|
#
|
692
693
|
# @param arg [String, Symbol, Class] Sets the provider class for this resource.
|
693
694
|
# If passed a String or Symbol, e.g. `:file` or `"file"`, looks up the
|
694
695
|
# provider based on the name.
|
696
|
+
#
|
695
697
|
# @return The provider class for this resource.
|
696
698
|
#
|
699
|
+
# @see Chef::Resource.action_provider_class
|
700
|
+
#
|
697
701
|
def provider(arg=nil)
|
698
702
|
klass = if arg.kind_of?(String) || arg.kind_of?(Symbol)
|
699
703
|
lookup_provider_constant(arg)
|
700
704
|
else
|
701
705
|
arg
|
702
706
|
end
|
703
|
-
set_or_return(:provider, klass, kind_of: [ Class ])
|
707
|
+
set_or_return(:provider, klass, kind_of: [ Class ]) ||
|
708
|
+
self.class.action_provider_class
|
704
709
|
end
|
705
710
|
def provider=(arg)
|
706
711
|
provider(arg)
|
707
712
|
end
|
708
713
|
|
709
|
-
#
|
710
|
-
#
|
711
|
-
#
|
712
|
-
#
|
713
|
-
#
|
714
|
-
#
|
715
|
-
#
|
716
|
-
#
|
717
|
-
#
|
714
|
+
#
|
715
|
+
# Create a property on this resource class.
|
716
|
+
#
|
717
|
+
# If a superclass has this property, or if this property has already been
|
718
|
+
# defined by this resource, this will *override* the previous value.
|
719
|
+
#
|
720
|
+
# @param name [Symbol] The name of the property.
|
721
|
+
# @param type [Object,Array<Object>] The type(s) of this property.
|
722
|
+
# If present, this is prepended to the `is` validation option.
|
723
|
+
# @param options [Hash<Symbol,Object>] Validation options.
|
724
|
+
# @option options [Object,Array] :is An object, or list of
|
725
|
+
# objects, that must match the value using Ruby's `===` operator
|
726
|
+
# (`options[:is].any? { |v| v === value }`).
|
727
|
+
# @option options [Object,Array] :equal_to An object, or list
|
728
|
+
# of objects, that must be equal to the value using Ruby's `==`
|
729
|
+
# operator (`options[:is].any? { |v| v == value }`)
|
730
|
+
# @option options [Regexp,Array<Regexp>] :regex An object, or
|
731
|
+
# list of objects, that must match the value with `regex.match(value)`.
|
732
|
+
# @option options [Class,Array<Class>] :kind_of A class, or
|
733
|
+
# list of classes, that the value must be an instance of.
|
734
|
+
# @option options [Hash<String,Proc>] :callbacks A hash of
|
735
|
+
# messages -> procs, all of which match the value. The proc must
|
736
|
+
# return a truthy or falsey value (true means it matches).
|
737
|
+
# @option options [Symbol,Array<Symbol>] :respond_to A method
|
738
|
+
# name, or list of method names, the value must respond to.
|
739
|
+
# @option options [Symbol,Array<Symbol>] :cannot_be A property,
|
740
|
+
# or a list of properties, that the value cannot have (such as `:nil` or
|
741
|
+
# `:empty`). The method with a questionmark at the end is called on the
|
742
|
+
# value (e.g. `value.empty?`). If the value does not have this method,
|
743
|
+
# it is considered valid (i.e. if you don't respond to `empty?` we
|
744
|
+
# assume you are not empty).
|
745
|
+
# @option options [Proc] :coerce A proc which will be called to
|
746
|
+
# transform the user input to canonical form. The value is passed in,
|
747
|
+
# and the transformed value returned as output. Lazy values will *not*
|
748
|
+
# be passed to this method until after they are evaluated. Called in the
|
749
|
+
# context of the resource (meaning you can access other properties).
|
750
|
+
# @option options [Boolean] :required `true` if this property
|
751
|
+
# must be present; `false` otherwise. This is checked after the resource
|
752
|
+
# is fully initialized.
|
753
|
+
# @option options [Boolean] :name_property `true` if this
|
754
|
+
# property defaults to the same value as `name`. Equivalent to
|
755
|
+
# `default: lazy { name }`, except that #property_is_set? will
|
756
|
+
# return `true` if the property is set *or* if `name` is set.
|
757
|
+
# @option options [Boolean] :name_attribute Same as `name_property`.
|
758
|
+
# @option options [Object] :default The value this property
|
759
|
+
# will return if the user does not set one. If this is `lazy`, it will
|
760
|
+
# be run in the context of the instance (and able to access other
|
761
|
+
# properties).
|
762
|
+
# @option options [Boolean] :desired_state `true` if this property is
|
763
|
+
# part of desired state. Defaults to `true`.
|
764
|
+
# @option options [Boolean] :identity `true` if this property
|
765
|
+
# is part of object identity. Defaults to `false`.
|
766
|
+
#
|
767
|
+
# @example Bare property
|
768
|
+
# property :x
|
769
|
+
#
|
770
|
+
# @example With just a type
|
771
|
+
# property :x, String
|
772
|
+
#
|
773
|
+
# @example With just options
|
774
|
+
# property :x, default: 'hi'
|
775
|
+
#
|
776
|
+
# @example With type and options
|
777
|
+
# property :x, String, default: 'hi'
|
778
|
+
#
|
779
|
+
def self.property(name, type=NOT_PASSED, **options)
|
780
|
+
name = name.to_sym
|
781
|
+
|
782
|
+
options[:instance_variable_name] = :"@#{name}" if !options.has_key?(:instance_variable_name)
|
783
|
+
options.merge!(name: name, declared_in: self)
|
784
|
+
|
785
|
+
if type == NOT_PASSED
|
786
|
+
# If a type is not passed, the property derives from the
|
787
|
+
# superclass property (if any)
|
788
|
+
if properties.has_key?(name)
|
789
|
+
property = properties[name].derive(**options)
|
790
|
+
else
|
791
|
+
property = property_type(**options)
|
792
|
+
end
|
793
|
+
|
794
|
+
# If a Property is specified, derive a new one from that.
|
795
|
+
elsif type.is_a?(Property) || (type.is_a?(Class) && type <= Property)
|
796
|
+
property = type.derive(**options)
|
797
|
+
|
798
|
+
# If a primitive type was passed, combine it with "is"
|
799
|
+
else
|
800
|
+
if options[:is]
|
801
|
+
options[:is] = ([ type ] + [ options[:is] ]).flatten(1)
|
802
|
+
else
|
803
|
+
options[:is] = type
|
804
|
+
end
|
805
|
+
property = property_type(**options)
|
806
|
+
end
|
807
|
+
|
808
|
+
local_properties = properties(false)
|
809
|
+
local_properties[name] = property
|
810
|
+
|
811
|
+
property.emit_dsl
|
812
|
+
end
|
813
|
+
|
814
|
+
#
|
815
|
+
# Create a reusable property type that can be used in multiple properties
|
816
|
+
# in different resources.
|
817
|
+
#
|
818
|
+
# @param options [Hash<Symbol,Object>] Validation options. see #property for
|
819
|
+
# the list of options.
|
820
|
+
#
|
821
|
+
# @example
|
822
|
+
# property_type(default: 'hi')
|
823
|
+
#
|
824
|
+
def self.property_type(**options)
|
825
|
+
Property.derive(**options)
|
826
|
+
end
|
827
|
+
|
828
|
+
#
|
829
|
+
# The name of this particular resource.
|
830
|
+
#
|
831
|
+
# This special resource attribute is set automatically from the declaration
|
832
|
+
# of the resource, e.g.
|
833
|
+
#
|
834
|
+
# execute 'Vitruvius' do
|
835
|
+
# command 'ls'
|
836
|
+
# end
|
837
|
+
#
|
838
|
+
# Will set the name to "Vitruvius".
|
839
|
+
#
|
840
|
+
# This is also used in to_s to show the resource name, e.g. `execute[Vitruvius]`.
|
841
|
+
#
|
842
|
+
# This is also used for resource notifications and subscribes in the same manner.
|
843
|
+
#
|
844
|
+
# This will coerce any object into a string via #to_s. Arrays are a special case
|
845
|
+
# so that `package ["foo", "bar"]` becomes package[foo, bar] instead of the more
|
846
|
+
# awkward `package[["foo", "bar"]]` that #to_s would produce.
|
847
|
+
#
|
848
|
+
# @param name [Object] The name to set, typically a String or Array
|
849
|
+
# @return [String] The name of this Resource.
|
850
|
+
#
|
851
|
+
property :name, String, coerce: proc { |v| v.is_a?(Array) ? v.join(', ') : v.to_s }, desired_state: false
|
852
|
+
|
853
|
+
#
|
854
|
+
# Whether this property has been set (or whether it has a default that has
|
855
|
+
# been retrieved).
|
856
|
+
#
|
857
|
+
# @param name [Symbol] The name of the property.
|
858
|
+
# @return [Boolean] `true` if the property has been set.
|
859
|
+
#
|
860
|
+
def property_is_set?(name)
|
861
|
+
property = self.class.properties[name.to_sym]
|
862
|
+
raise ArgumentError, "Property #{name} is not defined in class #{self}" if !property
|
863
|
+
property.is_set?(self)
|
864
|
+
end
|
865
|
+
|
866
|
+
#
|
867
|
+
# Clear this property as if it had never been set. It will thereafter return
|
868
|
+
# the default.
|
869
|
+
# been retrieved).
|
870
|
+
#
|
871
|
+
# @param name [Symbol] The name of the property.
|
872
|
+
#
|
873
|
+
def reset_property(name)
|
874
|
+
property = self.class.properties[name.to_sym]
|
875
|
+
raise ArgumentError, "Property #{name} is not defined in class #{self}" if !property
|
876
|
+
property.reset(self)
|
877
|
+
end
|
878
|
+
|
879
|
+
#
|
880
|
+
# Create a lazy value for assignment to a default value.
|
881
|
+
#
|
882
|
+
# @param block The block to run when the value is retrieved.
|
883
|
+
#
|
884
|
+
# @return [Chef::DelayedEvaluator] The lazy value
|
885
|
+
#
|
886
|
+
def self.lazy(&block)
|
887
|
+
DelayedEvaluator.new(&block)
|
888
|
+
end
|
889
|
+
|
890
|
+
#
|
891
|
+
# Get or set the list of desired state properties for this resource.
|
892
|
+
#
|
893
|
+
# State properties are properties that describe the desired state
|
894
|
+
# of the system, such as file permissions or ownership.
|
895
|
+
# In general, state properties are properties that could be populated by
|
896
|
+
# examining the state of the system (e.g., File.stat can tell you the
|
897
|
+
# permissions on an existing file). Contrarily, properties that are not
|
898
|
+
# "state properties" usually modify the way Chef itself behaves, for example
|
899
|
+
# by providing additional options for a package manager to use when
|
900
|
+
# installing a package.
|
718
901
|
#
|
719
902
|
# This list is used by the Chef client auditing system to extract
|
720
903
|
# information from resources to describe changes made to the system.
|
721
|
-
|
722
|
-
|
723
|
-
|
904
|
+
#
|
905
|
+
# This method is unnecessary when declaring properties with `property`;
|
906
|
+
# properties are added to state_properties by default, and can be turned off
|
907
|
+
# with `desired_state: false`.
|
908
|
+
#
|
909
|
+
# ```ruby
|
910
|
+
# property :x # part of desired state
|
911
|
+
# property :y, desired_state: false # not part of desired state
|
912
|
+
# ```
|
913
|
+
#
|
914
|
+
# @param names [Array<Symbol>] A list of property names to set as desired
|
915
|
+
# state.
|
916
|
+
#
|
917
|
+
# @return [Array<Property>] All properties in desired state.
|
918
|
+
#
|
919
|
+
def self.state_properties(*names)
|
920
|
+
if !names.empty?
|
921
|
+
names = names.map { |name| name.to_sym }.uniq
|
724
922
|
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
923
|
+
local_properties = properties(false)
|
924
|
+
# Add new properties to the list.
|
925
|
+
names.each do |name|
|
926
|
+
property = properties[name]
|
927
|
+
if !property
|
928
|
+
self.property name, instance_variable_name: false, desired_state: true
|
929
|
+
elsif !property.desired_state?
|
930
|
+
self.property name, desired_state: true
|
931
|
+
end
|
932
|
+
end
|
933
|
+
|
934
|
+
# If state_attrs *excludes* something which is currently desired state,
|
935
|
+
# mark it as desired_state: false.
|
936
|
+
local_properties.each do |name,property|
|
937
|
+
if property.desired_state? && !names.include?(name)
|
938
|
+
self.property name, desired_state: false
|
939
|
+
end
|
940
|
+
end
|
730
941
|
end
|
942
|
+
|
943
|
+
properties.values.select { |property| property.desired_state? }
|
731
944
|
end
|
732
945
|
|
733
|
-
#
|
734
|
-
#
|
735
|
-
#
|
736
|
-
#
|
737
|
-
#
|
738
|
-
#
|
739
|
-
|
740
|
-
|
741
|
-
|
946
|
+
#
|
947
|
+
# Set or return the list of "state properties" implemented by the Resource
|
948
|
+
# subclass.
|
949
|
+
#
|
950
|
+
# Equivalent to calling #state_properties and getting `state_properties.keys`.
|
951
|
+
#
|
952
|
+
# @deprecated Use state_properties.keys instead. Note that when you declare
|
953
|
+
# properties with `property`: properties are added to state_properties by
|
954
|
+
# default, and can be turned off with `desired_state: false`
|
955
|
+
#
|
956
|
+
# ```ruby
|
957
|
+
# property :x # part of desired state
|
958
|
+
# property :y, desired_state: false # not part of desired state
|
959
|
+
# ```
|
960
|
+
#
|
961
|
+
# @param names [Array<Symbol>] A list of property names to set as desired
|
962
|
+
# state.
|
963
|
+
#
|
964
|
+
# @return [Array<Symbol>] All property names with desired state.
|
965
|
+
#
|
966
|
+
def self.state_attrs(*names)
|
967
|
+
state_properties(*names).map { |property| property.name }
|
968
|
+
end
|
742
969
|
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
970
|
+
#
|
971
|
+
# Set the identity of this resource to a particular set of properties.
|
972
|
+
#
|
973
|
+
# This drives #identity, which returns data that uniquely refers to a given
|
974
|
+
# resource on the given node (in such a way that it can be correlated
|
975
|
+
# across Chef runs).
|
976
|
+
#
|
977
|
+
# This method is unnecessary when declaring properties with `property`;
|
978
|
+
# properties can be added to identity during declaration with
|
979
|
+
# `identity: true`.
|
980
|
+
#
|
981
|
+
# ```ruby
|
982
|
+
# property :x, identity: true # part of identity
|
983
|
+
# property :y # not part of identity
|
984
|
+
# ```
|
985
|
+
#
|
986
|
+
# If no properties are marked as identity, "name" is considered the identity.
|
987
|
+
#
|
988
|
+
# @param names [Array<Symbol>] A list of property names to set as the identity.
|
989
|
+
#
|
990
|
+
# @return [Array<Property>] All identity properties.
|
991
|
+
#
|
992
|
+
def self.identity_properties(*names)
|
993
|
+
if !names.empty?
|
994
|
+
names = names.map { |name| name.to_sym }
|
995
|
+
|
996
|
+
# Add or change properties that are not part of the identity.
|
997
|
+
names.each do |name|
|
998
|
+
property = properties[name]
|
999
|
+
if !property
|
1000
|
+
self.property name, instance_variable_name: false, identity: true
|
1001
|
+
elsif !property.identity?
|
1002
|
+
self.property name, identity: true
|
1003
|
+
end
|
1004
|
+
end
|
1005
|
+
|
1006
|
+
# If identity_properties *excludes* something which is currently part of
|
1007
|
+
# the identity, mark it as identity: false.
|
1008
|
+
properties.each do |name,property|
|
1009
|
+
if property.identity? && !names.include?(name)
|
1010
|
+
self.property name, identity: false
|
1011
|
+
end
|
1012
|
+
end
|
748
1013
|
end
|
1014
|
+
|
1015
|
+
result = properties.values.select { |property| property.identity? }
|
1016
|
+
result = [ properties[:name] ] if result.empty?
|
1017
|
+
result
|
1018
|
+
end
|
1019
|
+
|
1020
|
+
#
|
1021
|
+
# Set the identity of this resource to a particular property.
|
1022
|
+
#
|
1023
|
+
# This drives #identity, which returns data that uniquely refers to a given
|
1024
|
+
# resource on the given node (in such a way that it can be correlated
|
1025
|
+
# across Chef runs).
|
1026
|
+
#
|
1027
|
+
# This method is unnecessary when declaring properties with `property`;
|
1028
|
+
# properties can be added to identity during declaration with
|
1029
|
+
# `identity: true`.
|
1030
|
+
#
|
1031
|
+
# ```ruby
|
1032
|
+
# property :x, identity: true # part of identity
|
1033
|
+
# property :y # not part of identity
|
1034
|
+
# ```
|
1035
|
+
#
|
1036
|
+
# @param name [Symbol] A list of property names to set as the identity.
|
1037
|
+
#
|
1038
|
+
# @return [Symbol] The identity property if there is only one; or `nil` if
|
1039
|
+
# there are more than one.
|
1040
|
+
#
|
1041
|
+
# @raise [ArgumentError] If no arguments are passed and the resource has
|
1042
|
+
# more than one identity property.
|
1043
|
+
#
|
1044
|
+
def self.identity_property(name=nil)
|
1045
|
+
result = identity_properties(*Array(name))
|
1046
|
+
if result.size > 1
|
1047
|
+
raise Chef::Exceptions::MultipleIdentityError, "identity_property cannot be called on an object with more than one identity property (#{result.map { |r| r.name }.join(", ")})."
|
1048
|
+
end
|
1049
|
+
result.first
|
1050
|
+
end
|
1051
|
+
|
1052
|
+
#
|
1053
|
+
# Set a property as the "identity attribute" for this resource.
|
1054
|
+
#
|
1055
|
+
# Identical to calling #identity_property.first.key.
|
1056
|
+
#
|
1057
|
+
# @param name [Symbol] The name of the property to set.
|
1058
|
+
#
|
1059
|
+
# @return [Symbol]
|
1060
|
+
#
|
1061
|
+
# @deprecated `identity_property` should be used instead.
|
1062
|
+
#
|
1063
|
+
# @raise [ArgumentError] If no arguments are passed and the resource has
|
1064
|
+
# more than one identity property.
|
1065
|
+
#
|
1066
|
+
def self.identity_attr(name=nil)
|
1067
|
+
property = identity_property(name)
|
1068
|
+
return nil if !property
|
1069
|
+
property.name
|
749
1070
|
end
|
750
1071
|
|
751
1072
|
#
|
@@ -771,8 +1092,8 @@ class Chef
|
|
771
1092
|
# have.
|
772
1093
|
#
|
773
1094
|
attr_accessor :allowed_actions
|
774
|
-
def allowed_actions(value=
|
775
|
-
if value !=
|
1095
|
+
def allowed_actions(value=NOT_PASSED)
|
1096
|
+
if value != NOT_PASSED
|
776
1097
|
self.allowed_actions = value
|
777
1098
|
end
|
778
1099
|
@allowed_actions
|
@@ -906,9 +1227,9 @@ class Chef
|
|
906
1227
|
#
|
907
1228
|
# @return [Symbol] The name of this resource type (e.g. `:execute`).
|
908
1229
|
#
|
909
|
-
def self.resource_name(name=
|
1230
|
+
def self.resource_name(name=NOT_PASSED)
|
910
1231
|
# Setter
|
911
|
-
if name !=
|
1232
|
+
if name != NOT_PASSED
|
912
1233
|
remove_canonical_dsl
|
913
1234
|
|
914
1235
|
# Set the resource_name and call provides
|
@@ -923,13 +1244,25 @@ class Chef
|
|
923
1244
|
@resource_name = nil
|
924
1245
|
end
|
925
1246
|
end
|
926
|
-
|
927
1247
|
@resource_name
|
928
1248
|
end
|
929
1249
|
def self.resource_name=(name)
|
930
1250
|
resource_name(name)
|
931
1251
|
end
|
932
1252
|
|
1253
|
+
#
|
1254
|
+
# Use the class name as the resource name.
|
1255
|
+
#
|
1256
|
+
# Munges the last part of the class name from camel case to snake case,
|
1257
|
+
# and sets the resource_name to that:
|
1258
|
+
#
|
1259
|
+
# A::B::BlahDBlah -> blah_d_blah
|
1260
|
+
#
|
1261
|
+
def self.use_automatic_resource_name
|
1262
|
+
automatic_name = convert_to_snake_case(self.name.split('::')[-1])
|
1263
|
+
resource_name automatic_name
|
1264
|
+
end
|
1265
|
+
|
933
1266
|
#
|
934
1267
|
# The module where Chef should look for providers for this resource.
|
935
1268
|
# The provider for `MyResource` will be looked up using
|
@@ -986,8 +1319,8 @@ class Chef
|
|
986
1319
|
#
|
987
1320
|
# @return [Array<Symbol>] The default actions for the resource.
|
988
1321
|
#
|
989
|
-
def self.default_action(action_name=
|
990
|
-
unless action_name.equal?(
|
1322
|
+
def self.default_action(action_name=NOT_PASSED)
|
1323
|
+
unless action_name.equal?(NOT_PASSED)
|
991
1324
|
@default_action = Array(action_name).map(&:to_sym)
|
992
1325
|
self.allowed_actions |= @default_action
|
993
1326
|
end
|
@@ -1001,9 +1334,90 @@ class Chef
|
|
1001
1334
|
end
|
1002
1335
|
end
|
1003
1336
|
def self.default_action=(action_name)
|
1004
|
-
default_action
|
1337
|
+
default_action action_name
|
1338
|
+
end
|
1339
|
+
|
1340
|
+
#
|
1341
|
+
# Define an action on this resource.
|
1342
|
+
#
|
1343
|
+
# The action is defined as a *recipe* block that will be compiled and then
|
1344
|
+
# converged when the action is taken (when Resource is converged). The recipe
|
1345
|
+
# has access to the resource's attributes and methods, as well as the Chef
|
1346
|
+
# recipe DSL.
|
1347
|
+
#
|
1348
|
+
# Resources in the action recipe may notify and subscribe to other resources
|
1349
|
+
# within the action recipe, but cannot notify or subscribe to resources
|
1350
|
+
# in the main Chef run.
|
1351
|
+
#
|
1352
|
+
# Resource actions are *inheritable*: if resource A defines `action :create`
|
1353
|
+
# and B is a subclass of A, B gets all of A's actions. Additionally,
|
1354
|
+
# resource B can define `action :create` and call `super()` to invoke A's
|
1355
|
+
# action code.
|
1356
|
+
#
|
1357
|
+
# The first action defined (besides `:nothing`) will become the default
|
1358
|
+
# action for the resource.
|
1359
|
+
#
|
1360
|
+
# @param name [Symbol] The action name to define.
|
1361
|
+
# @param recipe_block The recipe to run when the action is taken. This block
|
1362
|
+
# takes no parameters, and will be evaluated in a new context containing:
|
1363
|
+
#
|
1364
|
+
# - The resource's public and protected methods (including attributes)
|
1365
|
+
# - The Chef Recipe DSL (file, etc.)
|
1366
|
+
# - super() referring to the parent version of the action (if any)
|
1367
|
+
#
|
1368
|
+
# @return The Action class implementing the action
|
1369
|
+
#
|
1370
|
+
def self.action(action, &recipe_block)
|
1371
|
+
action = action.to_sym
|
1372
|
+
new_action_provider_class.action(action, &recipe_block)
|
1373
|
+
self.allowed_actions += [ action ]
|
1374
|
+
default_action action if Array(default_action) == [:nothing]
|
1005
1375
|
end
|
1006
1376
|
|
1377
|
+
#
|
1378
|
+
# The action provider class is an automatic `Provider` created to handle
|
1379
|
+
# actions declared by `action :x do ... end`.
|
1380
|
+
#
|
1381
|
+
# This class will be returned by `resource.provider` if `resource.provider`
|
1382
|
+
# is not set. `provider_for_action` will also use this instead of calling
|
1383
|
+
# out to `Chef::ProviderResolver`.
|
1384
|
+
#
|
1385
|
+
# If the user has not declared actions on this class or its superclasses
|
1386
|
+
# using `action :x do ... end`, then there is no need for this class and
|
1387
|
+
# `action_provider_class` will be `nil`.
|
1388
|
+
#
|
1389
|
+
# @api private
|
1390
|
+
#
|
1391
|
+
def self.action_provider_class
|
1392
|
+
@action_provider_class ||
|
1393
|
+
# If the superclass needed one, then we need one as well.
|
1394
|
+
if superclass.respond_to?(:action_provider_class) && superclass.action_provider_class
|
1395
|
+
new_action_provider_class
|
1396
|
+
end
|
1397
|
+
end
|
1398
|
+
|
1399
|
+
#
|
1400
|
+
# Ensure the action provider class actually gets created. This is called
|
1401
|
+
# when the user does `action :x do ... end`.
|
1402
|
+
#
|
1403
|
+
# @api private
|
1404
|
+
def self.new_action_provider_class
|
1405
|
+
return @action_provider_class if @action_provider_class
|
1406
|
+
|
1407
|
+
if superclass.respond_to?(:action_provider_class)
|
1408
|
+
base_provider = superclass.action_provider_class
|
1409
|
+
end
|
1410
|
+
base_provider ||= Chef::Provider
|
1411
|
+
|
1412
|
+
resource_class = self
|
1413
|
+
@action_provider_class = Class.new(base_provider) do
|
1414
|
+
use_inline_resources
|
1415
|
+
include_resource_dsl true
|
1416
|
+
define_singleton_method(:to_s) { "#{resource_class} action provider" }
|
1417
|
+
define_singleton_method(:inspect) { to_s }
|
1418
|
+
define_method(:load_current_resource) {}
|
1419
|
+
end
|
1420
|
+
end
|
1007
1421
|
|
1008
1422
|
#
|
1009
1423
|
# Internal Resource Interface (for Chef)
|
@@ -1076,7 +1490,7 @@ class Chef
|
|
1076
1490
|
|
1077
1491
|
class << self
|
1078
1492
|
# back-compat
|
1079
|
-
# NOTE: that we do not support unregistering classes as
|
1493
|
+
# NOTE: that we do not support unregistering classes as descendants like
|
1080
1494
|
# we used to for LWRP unloading because that was horrible and removed in
|
1081
1495
|
# Chef-12.
|
1082
1496
|
# @deprecated
|
@@ -1202,7 +1616,8 @@ class Chef
|
|
1202
1616
|
end
|
1203
1617
|
|
1204
1618
|
def provider_for_action(action)
|
1205
|
-
|
1619
|
+
provider_class = Chef::ProviderResolver.new(node, self, action).resolve
|
1620
|
+
provider = provider_class.new(self, run_context)
|
1206
1621
|
provider.action = action
|
1207
1622
|
provider
|
1208
1623
|
end
|