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
@@ -0,0 +1,27 @@
|
|
1
|
+
#
|
2
|
+
# Author:: John Keiser <jkeiser@chef.io>
|
3
|
+
# Copyright:: Copyright (c) 2015 Opscode, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
class Chef
|
19
|
+
NOT_PASSED = Object.new
|
20
|
+
def NOT_PASSED.to_s
|
21
|
+
"NOT_PASSED"
|
22
|
+
end
|
23
|
+
def NOT_PASSED.inspect
|
24
|
+
to_s
|
25
|
+
end
|
26
|
+
NOT_PASSED.freeze
|
27
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#
|
2
|
+
# Author:: John Keiser <jkeiser@chef.io>
|
3
|
+
# Copyright:: Copyright (c) 2015 Opscode, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
class Chef
|
19
|
+
class DelayedEvaluator < Proc
|
20
|
+
end
|
21
|
+
end
|
data/lib/chef/dsl/recipe.rb
CHANGED
@@ -122,9 +122,9 @@ class Chef
|
|
122
122
|
|
123
123
|
def describe_self_for_error
|
124
124
|
if respond_to?(:name)
|
125
|
-
%Q[`#{self.class
|
125
|
+
%Q[`#{self.class} "#{name}"']
|
126
126
|
elsif respond_to?(:recipe_name)
|
127
|
-
%Q[`#{self.class
|
127
|
+
%Q[`#{self.class} "#{recipe_name}"']
|
128
128
|
else
|
129
129
|
to_s
|
130
130
|
end
|
@@ -176,6 +176,24 @@ class Chef
|
|
176
176
|
raise NameError, "No resource, method, or local variable named `#{method_symbol}' for #{describe_self_for_error}"
|
177
177
|
end
|
178
178
|
end
|
179
|
+
|
180
|
+
module FullDSL
|
181
|
+
require 'chef/dsl/data_query'
|
182
|
+
require 'chef/dsl/platform_introspection'
|
183
|
+
require 'chef/dsl/include_recipe'
|
184
|
+
require 'chef/dsl/registry_helper'
|
185
|
+
require 'chef/dsl/reboot_pending'
|
186
|
+
require 'chef/dsl/audit'
|
187
|
+
require 'chef/dsl/powershell'
|
188
|
+
include Chef::DSL::DataQuery
|
189
|
+
include Chef::DSL::PlatformIntrospection
|
190
|
+
include Chef::DSL::IncludeRecipe
|
191
|
+
include Chef::DSL::Recipe
|
192
|
+
include Chef::DSL::RegistryHelper
|
193
|
+
include Chef::DSL::RebootPending
|
194
|
+
include Chef::DSL::Audit
|
195
|
+
include Chef::DSL::Powershell
|
196
|
+
end
|
179
197
|
end
|
180
198
|
end
|
181
199
|
end
|
@@ -269,26 +269,37 @@ class Chef
|
|
269
269
|
# def notifications_resolved
|
270
270
|
# end
|
271
271
|
|
272
|
+
#
|
273
|
+
# Resource events and ordering:
|
274
|
+
#
|
275
|
+
# 1. Start the action
|
276
|
+
# - resource_action_start
|
277
|
+
# 2. Check the guard
|
278
|
+
# - resource_skipped: (goto 7) if only_if/not_if say to skip
|
279
|
+
# 3. Load the current resource
|
280
|
+
# - resource_current_state_loaded
|
281
|
+
# - resource_current_state_load_bypassed (if not why-run safe)
|
282
|
+
# 4. Check if why-run safe
|
283
|
+
# - resource_bypassed: (goto 7) if not why-run safe
|
284
|
+
# 5. During processing:
|
285
|
+
# - resource_update_applied: For each actual change (many per action)
|
286
|
+
# 6. Processing complete status:
|
287
|
+
# - resource_failed if the resource threw an exception while running
|
288
|
+
# - resource_failed_retriable: (goto 3) if resource failed and will be retried
|
289
|
+
# - resource_updated if the resource was updated (resource_update_applied will have been called)
|
290
|
+
# - resource_up_to_date if the resource was up to date (no resource_update_applied)
|
291
|
+
# 7. Processing complete:
|
292
|
+
# - resource_completed
|
293
|
+
#
|
294
|
+
|
272
295
|
# Called before action is executed on a resource.
|
273
296
|
def resource_action_start(resource, action, notification_type=nil, notifier=nil)
|
274
297
|
end
|
275
298
|
|
276
|
-
# Called when a resource fails, but will retry.
|
277
|
-
def resource_failed_retriable(resource, action, retry_count, exception)
|
278
|
-
end
|
279
|
-
|
280
|
-
# Called when a resource fails and will not be retried.
|
281
|
-
def resource_failed(resource, action, exception)
|
282
|
-
end
|
283
|
-
|
284
299
|
# Called when a resource action has been skipped b/c of a conditional
|
285
300
|
def resource_skipped(resource, action, conditional)
|
286
301
|
end
|
287
302
|
|
288
|
-
# Called when a resource action has been completed
|
289
|
-
def resource_completed(resource)
|
290
|
-
end
|
291
|
-
|
292
303
|
# Called after #load_current_resource has run.
|
293
304
|
def resource_current_state_loaded(resource, action, current_resource)
|
294
305
|
end
|
@@ -302,21 +313,34 @@ class Chef
|
|
302
313
|
def resource_bypassed(resource, action, current_resource)
|
303
314
|
end
|
304
315
|
|
305
|
-
# Called when a resource has no converge actions, e.g., it was already correct.
|
306
|
-
def resource_up_to_date(resource, action)
|
307
|
-
end
|
308
|
-
|
309
316
|
# Called when a change has been made to a resource. May be called multiple
|
310
317
|
# times per resource, e.g., a file may have its content updated, and then
|
311
318
|
# its permissions updated.
|
312
319
|
def resource_update_applied(resource, action, update)
|
313
320
|
end
|
314
321
|
|
322
|
+
# Called when a resource fails, but will retry.
|
323
|
+
def resource_failed_retriable(resource, action, retry_count, exception)
|
324
|
+
end
|
325
|
+
|
326
|
+
# Called when a resource fails and will not be retried.
|
327
|
+
def resource_failed(resource, action, exception)
|
328
|
+
end
|
329
|
+
|
315
330
|
# Called after a resource has been completely converged, but only if
|
316
331
|
# modifications were made.
|
317
332
|
def resource_updated(resource, action)
|
318
333
|
end
|
319
334
|
|
335
|
+
# Called when a resource has no converge actions, e.g., it was already correct.
|
336
|
+
def resource_up_to_date(resource, action)
|
337
|
+
end
|
338
|
+
|
339
|
+
# Called when a resource action has been completed
|
340
|
+
def resource_completed(resource)
|
341
|
+
end
|
342
|
+
|
343
|
+
|
320
344
|
# A stream has opened.
|
321
345
|
def stream_opened(stream, options = {})
|
322
346
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Ranjib Dey (<ranjib@linux.com>)
|
3
|
+
# Copyright:: Copyright (c) 2015 Ranjib Dey
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
require 'chef/event_dispatch/base'
|
19
|
+
require 'chef/exceptions'
|
20
|
+
require 'chef/config'
|
21
|
+
|
22
|
+
class Chef
|
23
|
+
module EventDispatch
|
24
|
+
class DSL
|
25
|
+
attr_reader :handler
|
26
|
+
|
27
|
+
def initialize(name)
|
28
|
+
klass = Class.new(Chef::EventDispatch::Base) do
|
29
|
+
attr_reader :name
|
30
|
+
end
|
31
|
+
@handler = klass.new
|
32
|
+
@handler.instance_variable_set(:@name, name)
|
33
|
+
|
34
|
+
# Use event.register API to add anonymous handler if Chef.run_context
|
35
|
+
# and associated event dispatcher is set, else fallback to
|
36
|
+
# Chef::Config[:hanlder]
|
37
|
+
if Chef.run_context && Chef.run_context.events
|
38
|
+
Chef::Log.debug("Registering handler '#{name}' using events api")
|
39
|
+
Chef.run_context.events.register(handler)
|
40
|
+
else
|
41
|
+
Chef::Log.debug("Registering handler '#{name}' using global config")
|
42
|
+
Chef::Config[:event_handlers] << handler
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Adds a new event handler derived from base handler
|
47
|
+
# with user defined block against a chef event
|
48
|
+
#
|
49
|
+
# @return [Chef::EventDispatch::Base] a base handler object
|
50
|
+
def on(event_type, &block)
|
51
|
+
validate!(event_type)
|
52
|
+
handler.define_singleton_method(event_type) do |*args|
|
53
|
+
instance_exec(*args, &block)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def validate!(event_type)
|
59
|
+
all_event_types = (Chef::EventDispatch::Base.instance_methods - Object.instance_methods)
|
60
|
+
raise Chef::Exceptions::InvalidEventType, "Invalid event type: #{event_type}" unless all_event_types.include?(event_type)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/chef/exceptions.rb
CHANGED
@@ -17,12 +17,16 @@
|
|
17
17
|
# See the License for the specific language governing permissions and
|
18
18
|
# limitations under the License.
|
19
19
|
|
20
|
+
require 'chef-config/exceptions'
|
21
|
+
|
20
22
|
class Chef
|
21
23
|
# == Chef::Exceptions
|
22
24
|
# Chef's custom exceptions are all contained within the Chef::Exceptions
|
23
25
|
# namespace.
|
24
26
|
class Exceptions
|
25
27
|
|
28
|
+
ConfigurationError = ChefConfig::ConfigurationError
|
29
|
+
|
26
30
|
# Backcompat with Chef::ShellOut code:
|
27
31
|
require 'mixlib/shellout/exceptions'
|
28
32
|
|
@@ -68,7 +72,6 @@ class Chef
|
|
68
72
|
class DuplicateRole < RuntimeError; end
|
69
73
|
class ValidationFailed < ArgumentError; end
|
70
74
|
class InvalidPrivateKey < ArgumentError; end
|
71
|
-
class ConfigurationError < ArgumentError; end
|
72
75
|
class MissingKeyAttribute < ArgumentError; end
|
73
76
|
class KeyCommandInputError < ArgumentError; end
|
74
77
|
class InvalidKeyArgument < ArgumentError; end
|
@@ -100,6 +103,8 @@ class Chef
|
|
100
103
|
class ProviderNotFound < RuntimeError; end
|
101
104
|
NoProviderAvailable = ProviderNotFound
|
102
105
|
class VerificationNotFound < RuntimeError; end
|
106
|
+
class InvalidEventType < ArgumentError; end
|
107
|
+
class MultipleIdentityError < RuntimeError; end
|
103
108
|
|
104
109
|
# Can't find a Resource of this type that is valid on this platform.
|
105
110
|
class NoSuchResourceType < NameError
|
data/lib/chef/formatters/doc.rb
CHANGED
@@ -22,6 +22,7 @@ class Chef
|
|
22
22
|
@failed_audits = 0
|
23
23
|
@start_time = Time.now
|
24
24
|
@end_time = @start_time
|
25
|
+
@skipped_resources = 0
|
25
26
|
end
|
26
27
|
|
27
28
|
def elapsed_time
|
@@ -33,7 +34,7 @@ class Chef
|
|
33
34
|
end
|
34
35
|
|
35
36
|
def total_resources
|
36
|
-
@up_to_date_resources + @updated_resources
|
37
|
+
@up_to_date_resources + @updated_resources + @skipped_resources
|
37
38
|
end
|
38
39
|
|
39
40
|
def total_audits
|
@@ -236,6 +237,7 @@ class Chef
|
|
236
237
|
|
237
238
|
# Called when a resource action has been skipped b/c of a conditional
|
238
239
|
def resource_skipped(resource, action, conditional)
|
240
|
+
@skipped_resources += 1
|
239
241
|
# TODO: more info about conditional
|
240
242
|
puts " (skipped due to #{conditional.short_description})", :stream => resource
|
241
243
|
unindent
|
@@ -68,7 +68,9 @@ class Chef
|
|
68
68
|
run_action = action || @resource.action
|
69
69
|
|
70
70
|
begin
|
71
|
-
# Coerce to an array to be safe.
|
71
|
+
# Coerce to an array to be safe. This could happen with a legacy
|
72
|
+
# resource or something overriding the default_action code in a
|
73
|
+
# subclass.
|
72
74
|
Array(run_action).each {|action_to_run| @resource.run_action(action_to_run) }
|
73
75
|
resource_updated = @resource.updated
|
74
76
|
rescue Mixlib::ShellOut::ShellCommandFailed
|
@@ -40,7 +40,7 @@ class Chef
|
|
40
40
|
|
41
41
|
engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : "ruby"
|
42
42
|
|
43
|
-
UA_COMMON = "/#{::Chef::VERSION} (#{engine}-#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}; ohai-#{Ohai::VERSION}; #{RUBY_PLATFORM}; +
|
43
|
+
UA_COMMON = "/#{::Chef::VERSION} (#{engine}-#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}; ohai-#{Ohai::VERSION}; #{RUBY_PLATFORM}; +https://chef.io)"
|
44
44
|
DEFAULT_UA = "Chef Client" << UA_COMMON
|
45
45
|
|
46
46
|
USER_AGENT = "User-Agent".freeze
|
data/lib/chef/knife/ssl_check.rb
CHANGED
@@ -73,11 +73,12 @@ class Chef
|
|
73
73
|
exit 1
|
74
74
|
end
|
75
75
|
|
76
|
-
|
77
76
|
def verify_peer_socket
|
78
77
|
@verify_peer_socket ||= begin
|
79
78
|
tcp_connection = TCPSocket.new(host, port)
|
80
|
-
OpenSSL::SSL::SSLSocket.new(tcp_connection, verify_peer_ssl_context)
|
79
|
+
ssl_client = OpenSSL::SSL::SSLSocket.new(tcp_connection, verify_peer_ssl_context)
|
80
|
+
ssl_client.hostname = host
|
81
|
+
ssl_client
|
81
82
|
end
|
82
83
|
end
|
83
84
|
|
data/lib/chef/knife/user_edit.rb
CHANGED
@@ -57,7 +57,6 @@ EOF
|
|
57
57
|
end
|
58
58
|
|
59
59
|
original_user = Chef::UserV1.load(@user_name).to_hash
|
60
|
-
|
61
60
|
# DEPRECATION NOTE
|
62
61
|
# Remove this if statement and corrosponding code post OSC 11 support.
|
63
62
|
#
|
@@ -73,7 +72,7 @@ EOF
|
|
73
72
|
user.update
|
74
73
|
ui.msg("Saved #{user}.")
|
75
74
|
else
|
76
|
-
ui.msg("User
|
75
|
+
ui.msg("User unchanged, not saving.")
|
77
76
|
end
|
78
77
|
end
|
79
78
|
|
@@ -15,9 +15,11 @@
|
|
15
15
|
# See the License for the specific language governing permissions and
|
16
16
|
# limitations under the License.
|
17
17
|
|
18
|
+
require 'chef/constants'
|
19
|
+
require 'chef/property'
|
20
|
+
require 'chef/delayed_evaluator'
|
21
|
+
|
18
22
|
class Chef
|
19
|
-
class DelayedEvaluator < Proc
|
20
|
-
end
|
21
23
|
module Mixin
|
22
24
|
module ParamsValidate
|
23
25
|
|
@@ -32,20 +34,55 @@ class Chef
|
|
32
34
|
# Would raise an exception if the value of :one above is not a kind_of? string. Valid
|
33
35
|
# map options are:
|
34
36
|
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
# :
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
37
|
+
# @param opts [Hash<Symbol,Object>] Validation opts.
|
38
|
+
# @option opts [Object,Array] :is An object, or list of
|
39
|
+
# objects, that must match the value using Ruby's `===` operator
|
40
|
+
# (`opts[:is].any? { |v| v === value }`). (See #_pv_is.)
|
41
|
+
# @option opts [Object,Array] :equal_to An object, or list
|
42
|
+
# of objects, that must be equal to the value using Ruby's `==`
|
43
|
+
# operator (`opts[:is].any? { |v| v == value }`) (See #_pv_equal_to.)
|
44
|
+
# @option opts [Regexp,Array<Regexp>] :regex An object, or
|
45
|
+
# list of objects, that must match the value with `regex.match(value)`.
|
46
|
+
# (See #_pv_regex)
|
47
|
+
# @option opts [Class,Array<Class>] :kind_of A class, or
|
48
|
+
# list of classes, that the value must be an instance of. (See
|
49
|
+
# #_pv_kind_of.)
|
50
|
+
# @option opts [Hash<String,Proc>] :callbacks A hash of
|
51
|
+
# messages -> procs, all of which match the value. The proc must
|
52
|
+
# return a truthy or falsey value (true means it matches). (See
|
53
|
+
# #_pv_callbacks.)
|
54
|
+
# @option opts [Symbol,Array<Symbol>] :respond_to A method
|
55
|
+
# name, or list of method names, the value must respond to. (See
|
56
|
+
# #_pv_respond_to.)
|
57
|
+
# @option opts [Symbol,Array<Symbol>] :cannot_be A property,
|
58
|
+
# or a list of properties, that the value cannot have (such as `:nil` or
|
59
|
+
# `:empty`). The method with a questionmark at the end is called on the
|
60
|
+
# value (e.g. `value.empty?`). If the value does not have this method,
|
61
|
+
# it is considered valid (i.e. if you don't respond to `empty?` we
|
62
|
+
# assume you are not empty). (See #_pv_cannot_be.)
|
63
|
+
# @option opts [Proc] :coerce A proc which will be called to
|
64
|
+
# transform the user input to canonical form. The value is passed in,
|
65
|
+
# and the transformed value returned as output. Lazy values will *not*
|
66
|
+
# be passed to this method until after they are evaluated. Called in the
|
67
|
+
# context of the resource (meaning you can access other properties).
|
68
|
+
# (See #_pv_coerce.) (See #_pv_coerce.)
|
69
|
+
# @option opts [Boolean] :required `true` if this property
|
70
|
+
# must be present and not `nil`; `false` otherwise. This is checked
|
71
|
+
# after the resource is fully initialized. (See #_pv_required.)
|
72
|
+
# @option opts [Boolean] :name_property `true` if this
|
73
|
+
# property defaults to the same value as `name`. Equivalent to
|
74
|
+
# `default: lazy { name }`, except that #property_is_set? will
|
75
|
+
# return `true` if the property is set *or* if `name` is set. (See
|
76
|
+
# #_pv_name_property.)
|
77
|
+
# @option opts [Boolean] :name_attribute Same as `name_property`.
|
78
|
+
# @option opts [Object] :default The value this property
|
79
|
+
# will return if the user does not set one. If this is `lazy`, it will
|
80
|
+
# be run in the context of the instance (and able to access other
|
81
|
+
# properties). (See #_pv_default.)
|
82
|
+
#
|
48
83
|
def validate(opts, map)
|
84
|
+
map = map.validation_options if map.is_a?(Property)
|
85
|
+
|
49
86
|
#--
|
50
87
|
# validate works by taking the keys in the validation map, assuming it's a hash, and
|
51
88
|
# looking for _pv_:symbol as methods. Assuming it find them, it calls the right
|
@@ -65,7 +102,7 @@ class Chef
|
|
65
102
|
true
|
66
103
|
when Hash
|
67
104
|
validation.each do |check, carg|
|
68
|
-
check_method = "_pv_#{check
|
105
|
+
check_method = "_pv_#{check}"
|
69
106
|
if self.respond_to?(check_method, true)
|
70
107
|
self.send(check_method, opts, key, carg)
|
71
108
|
else
|
@@ -81,162 +118,352 @@ class Chef
|
|
81
118
|
DelayedEvaluator.new(&block)
|
82
119
|
end
|
83
120
|
|
84
|
-
def set_or_return(symbol,
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
if(ivar.is_a?(DelayedEvaluator))
|
89
|
-
validate({ symbol => ivar.call }, { symbol => validation })[symbol]
|
90
|
-
else
|
91
|
-
ivar
|
92
|
-
end
|
93
|
-
else
|
94
|
-
if(arg.is_a?(DelayedEvaluator))
|
95
|
-
val = arg
|
96
|
-
else
|
97
|
-
val = validate({ symbol => arg }, { symbol => validation })[symbol]
|
121
|
+
def set_or_return(symbol, value, validation)
|
122
|
+
property = SetOrReturnProperty.new(name: symbol, **validation)
|
123
|
+
property.call(self, value)
|
124
|
+
end
|
98
125
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
126
|
+
private
|
127
|
+
|
128
|
+
def explicitly_allows_nil?(key, validation)
|
129
|
+
validation.has_key?(:is) && _pv_is({ key => nil }, key, validation[:is], raise_error: false)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Return the value of a parameter, or nil if it doesn't exist.
|
133
|
+
def _pv_opts_lookup(opts, key)
|
134
|
+
if opts.has_key?(key.to_s)
|
135
|
+
opts[key.to_s]
|
136
|
+
elsif opts.has_key?(key.to_sym)
|
137
|
+
opts[key.to_sym]
|
138
|
+
else
|
139
|
+
nil
|
107
140
|
end
|
108
141
|
end
|
109
142
|
|
110
|
-
|
143
|
+
# Raise an exception if the parameter is not found.
|
144
|
+
def _pv_required(opts, key, is_required=true, explicitly_allows_nil=false)
|
145
|
+
if is_required
|
146
|
+
return true if opts.has_key?(key.to_s) && (explicitly_allows_nil || !opts[key.to_s].nil?)
|
147
|
+
return true if opts.has_key?(key.to_sym) && (explicitly_allows_nil || !opts[key.to_sym].nil?)
|
148
|
+
raise Exceptions::ValidationFailed, "Required argument #{key.inspect} is missing!"
|
149
|
+
end
|
150
|
+
true
|
151
|
+
end
|
111
152
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
153
|
+
#
|
154
|
+
# List of things values must be equal to.
|
155
|
+
#
|
156
|
+
# Uses Ruby's `==` to evaluate (equal_to == value). At least one must
|
157
|
+
# match for the value to be valid.
|
158
|
+
#
|
159
|
+
# `nil` passes this validation automatically.
|
160
|
+
#
|
161
|
+
# @return [Array,nil] List of things values must be equal to, or nil if
|
162
|
+
# equal_to is unspecified.
|
163
|
+
#
|
164
|
+
def _pv_equal_to(opts, key, to_be)
|
165
|
+
value = _pv_opts_lookup(opts, key)
|
166
|
+
unless value.nil?
|
167
|
+
to_be = Array(to_be)
|
168
|
+
to_be.each do |tb|
|
169
|
+
return true if value == tb
|
120
170
|
end
|
171
|
+
raise Exceptions::ValidationFailed, "Option #{key} must be equal to one of: #{to_be.join(", ")}! You passed #{value.inspect}."
|
121
172
|
end
|
173
|
+
end
|
122
174
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
175
|
+
#
|
176
|
+
# List of things values must be instances of.
|
177
|
+
#
|
178
|
+
# Uses value.kind_of?(kind_of) to evaluate. At least one must match for
|
179
|
+
# the value to be valid.
|
180
|
+
#
|
181
|
+
# `nil` automatically passes this validation.
|
182
|
+
#
|
183
|
+
def _pv_kind_of(opts, key, to_be)
|
184
|
+
value = _pv_opts_lookup(opts, key)
|
185
|
+
unless value.nil?
|
186
|
+
to_be = Array(to_be)
|
187
|
+
to_be.each do |tb|
|
188
|
+
return true if value.kind_of?(tb)
|
132
189
|
end
|
190
|
+
raise Exceptions::ValidationFailed, "Option #{key} must be a kind of #{to_be}! You passed #{value.inspect}."
|
133
191
|
end
|
192
|
+
end
|
134
193
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
194
|
+
#
|
195
|
+
# List of method names values must respond to.
|
196
|
+
#
|
197
|
+
# Uses value.respond_to?(respond_to) to evaluate. At least one must match
|
198
|
+
# for the value to be valid.
|
199
|
+
#
|
200
|
+
def _pv_respond_to(opts, key, method_name_list)
|
201
|
+
value = _pv_opts_lookup(opts, key)
|
202
|
+
unless value.nil?
|
203
|
+
Array(method_name_list).each do |method_name|
|
204
|
+
unless value.respond_to?(method_name)
|
205
|
+
raise Exceptions::ValidationFailed, "Option #{key} must have a #{method_name} method!"
|
144
206
|
end
|
145
207
|
end
|
146
208
|
end
|
209
|
+
end
|
147
210
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
211
|
+
#
|
212
|
+
# List of things that must not be true about the value.
|
213
|
+
#
|
214
|
+
# Calls `value.<thing>?` All responses must be false for the value to be
|
215
|
+
# valid.
|
216
|
+
# Values which do not respond to <thing>? are considered valid (because if
|
217
|
+
# a value doesn't respond to `:readable?`, then it probably isn't
|
218
|
+
# readable.)
|
219
|
+
#
|
220
|
+
# @example
|
221
|
+
# ```ruby
|
222
|
+
# property :x, cannot_be: [ :nil, :empty ]
|
223
|
+
# x [ 1, 2 ] #=> valid
|
224
|
+
# x 1 #=> valid
|
225
|
+
# x [] #=> invalid
|
226
|
+
# x nil #=> invalid
|
227
|
+
# ```
|
228
|
+
#
|
229
|
+
def _pv_cannot_be(opts, key, predicate_method_base_name)
|
230
|
+
value = _pv_opts_lookup(opts, key)
|
231
|
+
if !value.nil?
|
232
|
+
Array(predicate_method_base_name).each do |method_name|
|
233
|
+
predicate_method = :"#{method_name}?"
|
234
|
+
|
235
|
+
if value.respond_to?(predicate_method)
|
236
|
+
if value.send(predicate_method)
|
237
|
+
raise Exceptions::ValidationFailed, "Option #{key} cannot be #{predicate_method_base_name}"
|
238
|
+
end
|
158
239
|
end
|
159
240
|
end
|
160
241
|
end
|
242
|
+
end
|
161
243
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
244
|
+
#
|
245
|
+
# The default value for a property.
|
246
|
+
#
|
247
|
+
# When the property is not assigned, this will be used.
|
248
|
+
#
|
249
|
+
# If this is a lazy value, it will either be passed the resource as a value,
|
250
|
+
# or if the lazy proc does not take parameters, it will be run in the
|
251
|
+
# context of the instance with instance_eval.
|
252
|
+
#
|
253
|
+
# @example
|
254
|
+
# ```ruby
|
255
|
+
# property :x, default: 10
|
256
|
+
# ```
|
257
|
+
#
|
258
|
+
# @example
|
259
|
+
# ```ruby
|
260
|
+
# property :x
|
261
|
+
# property :y, default: lazy { x+2 }
|
262
|
+
# ```
|
263
|
+
#
|
264
|
+
# @example
|
265
|
+
# ```ruby
|
266
|
+
# property :x
|
267
|
+
# property :y, default: lazy { |r| r.x+2 }
|
268
|
+
# ```
|
269
|
+
#
|
270
|
+
def _pv_default(opts, key, default_value)
|
271
|
+
value = _pv_opts_lookup(opts, key)
|
272
|
+
if value.nil?
|
273
|
+
default_value = default_value.freeze if !default_value.is_a?(DelayedEvaluator)
|
274
|
+
opts[key] = default_value
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
#
|
279
|
+
# List of regexes values that must match.
|
280
|
+
#
|
281
|
+
# Uses regex.match() to evaluate. At least one must match for the value to
|
282
|
+
# be valid.
|
283
|
+
#
|
284
|
+
# `nil` passes regex validation automatically.
|
285
|
+
#
|
286
|
+
# @example
|
287
|
+
# ```ruby
|
288
|
+
# property :x, regex: [ /abc/, /xyz/ ]
|
289
|
+
# ```
|
290
|
+
#
|
291
|
+
def _pv_regex(opts, key, regex)
|
292
|
+
value = _pv_opts_lookup(opts, key)
|
293
|
+
if !value.nil?
|
294
|
+
Array(regex).each do |r|
|
295
|
+
return true if r.match(value.to_s)
|
171
296
|
end
|
297
|
+
raise Exceptions::ValidationFailed, "Option #{key}'s value #{value} does not match regular expression #{regex.inspect}"
|
172
298
|
end
|
299
|
+
end
|
173
300
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
301
|
+
#
|
302
|
+
# List of procs we pass the value to.
|
303
|
+
#
|
304
|
+
# All procs must return true for the value to be valid. If any procs do
|
305
|
+
# not return true, the key will be used for the message: `"Property x's
|
306
|
+
# value :y <message>"`.
|
307
|
+
#
|
308
|
+
# @example
|
309
|
+
# ```ruby
|
310
|
+
# property :x, callbacks: { "is bigger than 10" => proc { |v| v <= 10 }, "is not awesome" => proc { |v| !v.awesome }}
|
311
|
+
# ```
|
312
|
+
#
|
313
|
+
def _pv_callbacks(opts, key, callbacks)
|
314
|
+
raise ArgumentError, "Callback list must be a hash!" unless callbacks.kind_of?(Hash)
|
315
|
+
value = _pv_opts_lookup(opts, key)
|
316
|
+
if !value.nil?
|
317
|
+
callbacks.each do |message, zeproc|
|
318
|
+
if zeproc.call(value) != true
|
319
|
+
raise Exceptions::ValidationFailed, "Option #{key}'s value #{value} #{message}!"
|
188
320
|
end
|
189
321
|
end
|
190
322
|
end
|
323
|
+
end
|
191
324
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
325
|
+
#
|
326
|
+
# Allows a parameter to default to the value of the resource name.
|
327
|
+
#
|
328
|
+
# @example
|
329
|
+
# ```ruby
|
330
|
+
# property :x, name_property: true
|
331
|
+
# ```
|
332
|
+
#
|
333
|
+
def _pv_name_property(opts, key, is_name_property=true)
|
334
|
+
if is_name_property
|
335
|
+
if opts[key].nil?
|
336
|
+
opts[key] = self.instance_variable_get(:"@name")
|
197
337
|
end
|
198
338
|
end
|
339
|
+
end
|
340
|
+
alias :_pv_name_attribute :_pv_name_property
|
199
341
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
342
|
+
#
|
343
|
+
# List of valid things values can be.
|
344
|
+
#
|
345
|
+
# Uses Ruby's `===` to evaluate (is === value). At least one must match
|
346
|
+
# for the value to be valid.
|
347
|
+
#
|
348
|
+
# If a proc is passed, it is instance_eval'd in the resource, passed the
|
349
|
+
# value, and must return a truthy or falsey value.
|
350
|
+
#
|
351
|
+
# @example Class
|
352
|
+
# ```ruby
|
353
|
+
# property :x, String
|
354
|
+
# x 'valid' #=> valid
|
355
|
+
# x 1 #=> invalid
|
356
|
+
# x nil #=> invalid
|
357
|
+
#
|
358
|
+
# @example Value
|
359
|
+
# ```ruby
|
360
|
+
# property :x, [ :a, :b, :c, nil ]
|
361
|
+
# x :a #=> valid
|
362
|
+
# x nil #=> valid
|
363
|
+
# ```
|
364
|
+
#
|
365
|
+
# @example Regex
|
366
|
+
# ```ruby
|
367
|
+
# property :x, /bar/
|
368
|
+
# x 'foobar' #=> valid
|
369
|
+
# x 'foo' #=> invalid
|
370
|
+
# x nil #=> invalid
|
371
|
+
# ```
|
372
|
+
#
|
373
|
+
# @example Proc
|
374
|
+
# ```ruby
|
375
|
+
# property :x, proc { |x| x > y }
|
376
|
+
# property :y, default: 2
|
377
|
+
# x 3 #=> valid
|
378
|
+
# x 1 #=> invalid
|
379
|
+
# ```
|
380
|
+
#
|
381
|
+
# @example Property
|
382
|
+
# ```ruby
|
383
|
+
# type = Property.new(is: String)
|
384
|
+
# property :x, type
|
385
|
+
# x 'foo' #=> valid
|
386
|
+
# x 1 #=> invalid
|
387
|
+
# x nil #=> invalid
|
388
|
+
# ```
|
389
|
+
#
|
390
|
+
# @example RSpec Matcher
|
391
|
+
# ```ruby
|
392
|
+
# include RSpec::Matchers
|
393
|
+
# property :x, a_string_matching /bar/
|
394
|
+
# x 'foobar' #=> valid
|
395
|
+
# x 'foo' #=> invalid
|
396
|
+
# x nil #=> invalid
|
397
|
+
# ```
|
398
|
+
#
|
399
|
+
def _pv_is(opts, key, to_be, raise_error: true)
|
400
|
+
return true if !opts.has_key?(key.to_s) && !opts.has_key?(key.to_sym)
|
401
|
+
value = _pv_opts_lookup(opts, key)
|
402
|
+
to_be = [ to_be ].flatten(1)
|
403
|
+
to_be.each do |tb|
|
404
|
+
case tb
|
405
|
+
when Proc
|
406
|
+
return true if instance_exec(value, &tb)
|
407
|
+
when Property
|
408
|
+
validate(opts, { key => tb.validation_options })
|
409
|
+
return true
|
410
|
+
else
|
411
|
+
return true if tb === value
|
215
412
|
end
|
216
413
|
end
|
217
414
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
415
|
+
if raise_error
|
416
|
+
raise Exceptions::ValidationFailed, "Option #{key} must be one of: #{to_be.join(", ")}! You passed #{value.inspect}."
|
417
|
+
else
|
418
|
+
false
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
#
|
423
|
+
# Method to mess with a value before it is validated and stored.
|
424
|
+
#
|
425
|
+
# Allows you to transform values into a canonical form that is easy to
|
426
|
+
# work with.
|
427
|
+
#
|
428
|
+
# This is passed the value to transform, and is run in the context of the
|
429
|
+
# instance (so it has access to other resource properties). It must return
|
430
|
+
# the value that will be stored in the instance.
|
431
|
+
#
|
432
|
+
# @example
|
433
|
+
# ```ruby
|
434
|
+
# property :x, Integer, coerce: { |v| v.to_i }
|
435
|
+
# ```
|
436
|
+
#
|
437
|
+
def _pv_coerce(opts, key, coercer)
|
438
|
+
if opts.has_key?(key.to_s)
|
439
|
+
opts[key.to_s] = instance_exec(opts[key], &coercer)
|
440
|
+
elsif opts.has_key?(key.to_sym)
|
441
|
+
opts[key.to_sym] = instance_exec(opts[key], &coercer)
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
# Used by #set_or_return to avoid emitting a deprecation warning for
|
446
|
+
# "value nil" and to keep default stickiness working exactly the same
|
447
|
+
# @api private
|
448
|
+
class SetOrReturnProperty < Chef::Property
|
449
|
+
def get(resource)
|
450
|
+
value = super
|
451
|
+
# All values are sticky, frozen or not
|
452
|
+
if !is_set?(resource)
|
453
|
+
set_value(resource, value)
|
228
454
|
end
|
455
|
+
value
|
229
456
|
end
|
230
457
|
|
231
|
-
|
232
|
-
|
233
|
-
if
|
234
|
-
|
235
|
-
|
236
|
-
|
458
|
+
def call(resource, value=NOT_PASSED)
|
459
|
+
# setting to nil does a get
|
460
|
+
if value.nil? && !explicitly_accepts_nil?(resource)
|
461
|
+
get(resource)
|
462
|
+
else
|
463
|
+
super
|
237
464
|
end
|
238
465
|
end
|
466
|
+
end
|
239
467
|
end
|
240
468
|
end
|
241
469
|
end
|
242
|
-
|