chef 12.4.3 → 12.5.0.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|