chef 12.0.1 → 12.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb +1 -1
- data/lib/chef/digester.rb +1 -0
- data/lib/chef/dsl/recipe.rb +2 -1
- data/lib/chef/exceptions.rb +5 -0
- data/lib/chef/knife.rb +7 -0
- data/lib/chef/knife/cookbook_site_install.rb +34 -10
- data/lib/chef/provider/link.rb +1 -1
- data/lib/chef/provider/package/apt.rb +2 -2
- data/lib/chef/provider/package/homebrew.rb +11 -2
- data/lib/chef/provider/package/windows/msi.rb +2 -0
- data/lib/chef/provider/subversion.rb +3 -3
- data/lib/chef/resource.rb +23 -91
- data/lib/chef/resource/homebrew_package.rb +2 -1
- data/lib/chef/resource/resource_notification.rb +109 -0
- data/lib/chef/resource_collection/resource_set.rb +8 -8
- data/lib/chef/run_context.rb +4 -4
- data/lib/chef/version.rb +1 -1
- data/lib/chef/whitelist.rb +3 -1
- data/lib/chef/win32/api/file.rb +17 -3
- data/spec/functional/notifications_spec.rb +169 -0
- data/spec/functional/resource/link_spec.rb +31 -32
- data/spec/support/platform_helpers.rb +5 -2
- data/spec/unit/knife/cookbook_site_install_spec.rb +157 -116
- data/spec/unit/knife_spec.rb +108 -78
- data/spec/unit/mixin/shell_out_spec.rb +39 -40
- data/spec/unit/node_spec.rb +34 -0
- data/spec/unit/provider/link_spec.rb +5 -5
- data/spec/unit/provider/package/apt_spec.rb +264 -257
- data/spec/unit/provider/package/homebrew_spec.rb +26 -0
- data/spec/unit/provider/package/windows/msi_spec.rb +18 -3
- data/spec/unit/provider/subversion_spec.rb +5 -5
- data/spec/unit/provider_resolver_spec.rb +2 -2
- data/spec/unit/recipe_spec.rb +1 -0
- data/spec/unit/resource/apt_package_spec.rb +3 -5
- data/spec/unit/resource/resource_notification_spec.rb +170 -0
- data/spec/unit/resource_spec.rb +0 -151
- data/spec/unit/run_context_spec.rb +94 -55
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e516e23b8f432618bba6ae817b113bef6f1fd7e6
|
4
|
+
data.tar.gz: 0130eaec499c6059291f3d395b1fb282a203d9d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dad78645f06fa14308a32787553f371b741d3195df67b027afddb3f6e3e3a44b291a47bda4fddb7a623358c3677c95b145203e5657e133116cc0ee255c168b90
|
7
|
+
data.tar.gz: 4aa354a66a468b4100723a4027b1ff9265cfcf8c8377d3698f279c6852494c9f01bc246868c29dea3d8b49251a0c287920671bb9fbeb913bbbf0682e6a4a6ad9
|
@@ -64,7 +64,7 @@ class Chef
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def minimize(file_contents, entry)
|
67
|
-
object = Chef::JSONCompat.
|
67
|
+
object = Chef::JSONCompat.parse(file_contents)
|
68
68
|
object = data_handler.normalize(object, entry)
|
69
69
|
object = data_handler.minimize(object, entry)
|
70
70
|
Chef::JSONCompat.to_json_pretty(object)
|
data/lib/chef/digester.rb
CHANGED
data/lib/chef/dsl/recipe.rb
CHANGED
@@ -81,7 +81,7 @@ class Chef
|
|
81
81
|
|
82
82
|
resource = build_resource(type, name, created_at, &resource_attrs_block)
|
83
83
|
|
84
|
-
run_context.resource_collection.insert(resource, resource_type:type, instance_name:name)
|
84
|
+
run_context.resource_collection.insert(resource, resource_type: type, instance_name: name)
|
85
85
|
resource
|
86
86
|
end
|
87
87
|
|
@@ -101,6 +101,7 @@ class Chef
|
|
101
101
|
|
102
102
|
resource = resource_class.new(name, run_context)
|
103
103
|
resource.source_line = created_at
|
104
|
+
resource.declared_type = type
|
104
105
|
# If we have a resource like this one, we want to steal its state
|
105
106
|
# This behavior is very counter-intuitive and should be removed.
|
106
107
|
# See CHEF-3694, https://tickets.opscode.com/browse/CHEF-3694
|
data/lib/chef/exceptions.rb
CHANGED
@@ -149,6 +149,11 @@ class Chef
|
|
149
149
|
class IllegalVersionConstraint < NotImplementedError; end
|
150
150
|
|
151
151
|
class MetadataNotValid < StandardError; end
|
152
|
+
class MetadataNotFound < StandardError
|
153
|
+
def initialize
|
154
|
+
super "No metadata.rb or metadata.json!"
|
155
|
+
end
|
156
|
+
end
|
152
157
|
|
153
158
|
# File operation attempted but no permissions to perform it
|
154
159
|
class InsufficientPermissions < RuntimeError; end
|
data/lib/chef/knife.rb
CHANGED
@@ -428,6 +428,13 @@ class Chef
|
|
428
428
|
raise # make sure exit passes through.
|
429
429
|
when Net::HTTPServerException, Net::HTTPFatalError
|
430
430
|
humanize_http_exception(e)
|
431
|
+
when OpenSSL::SSL::SSLError
|
432
|
+
ui.error "Could not establish a secure connection to the server."
|
433
|
+
ui.info "Use `knife ssl check` to troubleshoot your SSL configuration."
|
434
|
+
ui.info "If your Chef Server uses a self-signed certificate, you can use"
|
435
|
+
ui.info "`knife ssl fetch` to make knife trust the server's certificates."
|
436
|
+
ui.info ""
|
437
|
+
ui.info "Original Exception: #{e.class.name}: #{e.message}"
|
431
438
|
when Errno::ECONNREFUSED, Timeout::Error, Errno::ETIMEDOUT, SocketError
|
432
439
|
ui.error "Network Error: #{e.message}"
|
433
440
|
ui.info "Check your knife configuration and network settings"
|
@@ -17,11 +17,11 @@
|
|
17
17
|
#
|
18
18
|
|
19
19
|
require 'chef/knife'
|
20
|
+
require 'chef/exceptions'
|
20
21
|
require 'shellwords'
|
21
22
|
|
22
23
|
class Chef
|
23
24
|
class Knife
|
24
|
-
|
25
25
|
class CookbookSiteInstall < Knife
|
26
26
|
|
27
27
|
deps do
|
@@ -107,11 +107,8 @@ class Chef
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
110
|
-
|
111
110
|
unless config[:no_deps]
|
112
|
-
|
113
|
-
md.from_file(File.join(@install_path, @cookbook_name, "metadata.rb"))
|
114
|
-
md.dependencies.each do |cookbook, version_list|
|
111
|
+
preferred_metadata.dependencies.each do |cookbook, version_list|
|
115
112
|
# Doesn't do versions.. yet
|
116
113
|
nv = self.class.new
|
117
114
|
nv.config = config
|
@@ -144,6 +141,7 @@ class Chef
|
|
144
141
|
|
145
142
|
def extract_cookbook(upstream_file, version)
|
146
143
|
ui.info("Uncompressing #{@cookbook_name} version #{version}.")
|
144
|
+
# FIXME: Detect if we have the bad tar from git on Windows: https://github.com/opscode/chef/issues/1753
|
147
145
|
shell_out!("tar zxvf #{convert_path upstream_file}", :cwd => @install_path)
|
148
146
|
end
|
149
147
|
|
@@ -153,11 +151,37 @@ class Chef
|
|
153
151
|
end
|
154
152
|
|
155
153
|
def convert_path(upstream_file)
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
154
|
+
# converts a Windows path (C:\foo) to a mingw path (/c/foo)
|
155
|
+
if ENV['MSYSTEM'] == 'MINGW32'
|
156
|
+
return upstream_file.sub(/^([[:alpha:]]):/, '/\1')
|
157
|
+
else
|
158
|
+
return Shellwords.escape upstream_file
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Get the preferred metadata path on disk. Chef prefers the metadata.rb
|
163
|
+
# over the metadata.json.
|
164
|
+
#
|
165
|
+
# @raise if there is no metadata in the cookbook
|
166
|
+
#
|
167
|
+
# @return [Chef::Cookbook::Metadata]
|
168
|
+
def preferred_metadata
|
169
|
+
md = Chef::Cookbook::Metadata.new
|
170
|
+
|
171
|
+
rb = File.join(@install_path, @cookbook_name, "metadata.rb")
|
172
|
+
if File.exist?(rb)
|
173
|
+
md.from_file(rb)
|
174
|
+
return md
|
175
|
+
end
|
176
|
+
|
177
|
+
json = File.join(@install_path, @cookbook_name, "metadata.json")
|
178
|
+
if File.exist?(json)
|
179
|
+
json = IO.read(json)
|
180
|
+
md.from_json(json)
|
181
|
+
return md
|
182
|
+
end
|
183
|
+
|
184
|
+
raise Chef::Exceptions::MetadataNotFound
|
161
185
|
end
|
162
186
|
end
|
163
187
|
end
|
data/lib/chef/provider/link.rb
CHANGED
@@ -46,8 +46,8 @@ class Chef
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def default_release_options
|
49
|
-
# Use apt::Default-Release option only if provider
|
50
|
-
"-o APT::Default-Release=#{@new_resource.default_release}" if @new_resource.
|
49
|
+
# Use apt::Default-Release option only if provider supports it
|
50
|
+
"-o APT::Default-Release=#{@new_resource.default_release}" if @new_resource.respond_to?(:default_release) && @new_resource.default_release
|
51
51
|
end
|
52
52
|
|
53
53
|
def check_package_state(package)
|
@@ -26,7 +26,8 @@ class Chef
|
|
26
26
|
class Package
|
27
27
|
class Homebrew < Chef::Provider::Package
|
28
28
|
|
29
|
-
provides :homebrew_package
|
29
|
+
provides :homebrew_package
|
30
|
+
provides :package, os: ["mac_os_x", "darwin"]
|
30
31
|
|
31
32
|
include Chef::Mixin::HomebrewUser
|
32
33
|
|
@@ -94,7 +95,15 @@ class Chef
|
|
94
95
|
# that brew thinks is linked as the current version.
|
95
96
|
#
|
96
97
|
def current_installed_version
|
97
|
-
brew_info['keg_only']
|
98
|
+
if brew_info['keg_only']
|
99
|
+
if brew_info['installed'].empty?
|
100
|
+
nil
|
101
|
+
else
|
102
|
+
brew_info['installed'].last['version']
|
103
|
+
end
|
104
|
+
else
|
105
|
+
brew_info['linked_keg']
|
106
|
+
end
|
98
107
|
end
|
99
108
|
|
100
109
|
# Packages (formula) available to install should have a
|
@@ -19,6 +19,7 @@
|
|
19
19
|
# TODO: Allow @new_resource.source to be a Product Code as a GUID for uninstall / network install
|
20
20
|
|
21
21
|
require 'chef/win32/api/installer' if RUBY_PLATFORM =~ /mswin|mingw32|windows/
|
22
|
+
require 'chef/mixin/shell_out'
|
22
23
|
|
23
24
|
class Chef
|
24
25
|
class Provider
|
@@ -26,6 +27,7 @@ class Chef
|
|
26
27
|
class Windows
|
27
28
|
class MSI
|
28
29
|
include Chef::ReservedNames::Win32::API::Installer if RUBY_PLATFORM =~ /mswin|mingw32|windows/
|
30
|
+
include Chef::Mixin::ShellOut
|
29
31
|
|
30
32
|
def initialize(resource)
|
31
33
|
@new_resource = resource
|
@@ -62,7 +62,7 @@ class Chef
|
|
62
62
|
def action_checkout
|
63
63
|
if target_dir_non_existent_or_empty?
|
64
64
|
converge_by("perform checkout of #{@new_resource.repository} into #{@new_resource.destination}") do
|
65
|
-
shell_out!(run_options
|
65
|
+
shell_out!(checkout_command, run_options)
|
66
66
|
end
|
67
67
|
else
|
68
68
|
Chef::Log.debug "#{@new_resource} checkout destination #{@new_resource.destination} already exists or is a non-empty directory - nothing to do"
|
@@ -79,7 +79,7 @@ class Chef
|
|
79
79
|
|
80
80
|
def action_force_export
|
81
81
|
converge_by("export #{@new_resource.repository} into #{@new_resource.destination}") do
|
82
|
-
shell_out!(run_options
|
82
|
+
shell_out!(export_command, run_options)
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
@@ -90,7 +90,7 @@ class Chef
|
|
90
90
|
Chef::Log.debug "#{@new_resource} current revision: #{current_rev} target revision: #{revision_int}"
|
91
91
|
unless current_revision_matches_target_revision?
|
92
92
|
converge_by("sync #{@new_resource.destination} from #{@new_resource.repository}") do
|
93
|
-
shell_out!(run_options
|
93
|
+
shell_out!(sync_command, run_options)
|
94
94
|
Chef::Log.info "#{@new_resource} updated to revision: #{revision_int}"
|
95
95
|
end
|
96
96
|
end
|
data/lib/chef/resource.rb
CHANGED
@@ -29,99 +29,14 @@ require 'chef/resource/conditional_action_not_nothing'
|
|
29
29
|
require 'chef/resource_collection'
|
30
30
|
require 'chef/node_map'
|
31
31
|
require 'chef/node'
|
32
|
-
require 'chef/provider_resolver'
|
33
32
|
require 'chef/platform'
|
33
|
+
require 'chef/resource/resource_notification'
|
34
34
|
|
35
35
|
require 'chef/mixin/deprecation'
|
36
36
|
require 'chef/mixin/descendants_tracker'
|
37
37
|
|
38
38
|
class Chef
|
39
39
|
class Resource
|
40
|
-
class Notification < Struct.new(:resource, :action, :notifying_resource)
|
41
|
-
|
42
|
-
def duplicates?(other_notification)
|
43
|
-
unless other_notification.respond_to?(:resource) && other_notification.respond_to?(:action)
|
44
|
-
msg = "only duck-types of Chef::Resource::Notification can be checked for duplication "\
|
45
|
-
"you gave #{other_notification.inspect}"
|
46
|
-
raise ArgumentError, msg
|
47
|
-
end
|
48
|
-
other_notification.resource == resource && other_notification.action == action
|
49
|
-
end
|
50
|
-
|
51
|
-
# If resource and/or notifying_resource is not a resource object, this will look them up in the resource collection
|
52
|
-
# and fix the references from strings to actual Resource objects.
|
53
|
-
def resolve_resource_reference(resource_collection)
|
54
|
-
return resource if resource.kind_of?(Chef::Resource) && notifying_resource.kind_of?(Chef::Resource)
|
55
|
-
|
56
|
-
if not(resource.kind_of?(Chef::Resource))
|
57
|
-
fix_resource_reference(resource_collection)
|
58
|
-
end
|
59
|
-
|
60
|
-
if not(notifying_resource.kind_of?(Chef::Resource))
|
61
|
-
fix_notifier_reference(resource_collection)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
# This will look up the resource if it is not a Resource Object. It will complain if it finds multiple
|
66
|
-
# resources, can't find a resource, or gets invalid syntax.
|
67
|
-
def fix_resource_reference(resource_collection)
|
68
|
-
matching_resource = resource_collection.find(resource)
|
69
|
-
if Array(matching_resource).size > 1
|
70
|
-
msg = "Notification #{self} from #{notifying_resource} was created with a reference to multiple resources, "\
|
71
|
-
"but can only notify one resource. Notifying resource was defined on #{notifying_resource.source_line}"
|
72
|
-
raise Chef::Exceptions::InvalidResourceReference, msg
|
73
|
-
end
|
74
|
-
self.resource = matching_resource
|
75
|
-
|
76
|
-
rescue Chef::Exceptions::ResourceNotFound => e
|
77
|
-
err = Chef::Exceptions::ResourceNotFound.new(<<-FAIL)
|
78
|
-
resource #{notifying_resource} is configured to notify resource #{resource} with action #{action}, \
|
79
|
-
but #{resource} cannot be found in the resource collection. #{notifying_resource} is defined in \
|
80
|
-
#{notifying_resource.source_line}
|
81
|
-
FAIL
|
82
|
-
err.set_backtrace(e.backtrace)
|
83
|
-
raise err
|
84
|
-
rescue Chef::Exceptions::InvalidResourceSpecification => e
|
85
|
-
err = Chef::Exceptions::InvalidResourceSpecification.new(<<-F)
|
86
|
-
Resource #{notifying_resource} is configured to notify resource #{resource} with action #{action}, \
|
87
|
-
but #{resource.inspect} is not valid syntax to look up a resource in the resource collection. Notification \
|
88
|
-
is defined near #{notifying_resource.source_line}
|
89
|
-
F
|
90
|
-
err.set_backtrace(e.backtrace)
|
91
|
-
raise err
|
92
|
-
end
|
93
|
-
|
94
|
-
# This will look up the notifying_resource if it is not a Resource Object. It will complain if it finds multiple
|
95
|
-
# resources, can't find a resource, or gets invalid syntax.
|
96
|
-
def fix_notifier_reference(resource_collection)
|
97
|
-
matching_notifier = resource_collection.find(notifying_resource)
|
98
|
-
if Array(matching_notifier).size > 1
|
99
|
-
msg = "Notification #{self} from #{notifying_resource} was created with a reference to multiple notifying "\
|
100
|
-
"resources, but can only originate from one resource. Destination resource was defined "\
|
101
|
-
"on #{resource.source_line}"
|
102
|
-
raise Chef::Exceptions::InvalidResourceReference, msg
|
103
|
-
end
|
104
|
-
self.notifying_resource = matching_notifier
|
105
|
-
|
106
|
-
rescue Chef::Exceptions::ResourceNotFound => e
|
107
|
-
err = Chef::Exceptions::ResourceNotFound.new(<<-FAIL)
|
108
|
-
Resource #{resource} is configured to receive notifications from #{notifying_resource} with action #{action}, \
|
109
|
-
but #{notifying_resource} cannot be found in the resource collection. #{resource} is defined in \
|
110
|
-
#{resource.source_line}
|
111
|
-
FAIL
|
112
|
-
err.set_backtrace(e.backtrace)
|
113
|
-
raise err
|
114
|
-
rescue Chef::Exceptions::InvalidResourceSpecification => e
|
115
|
-
err = Chef::Exceptions::InvalidResourceSpecification.new(<<-F)
|
116
|
-
Resource #{resource} is configured to receive notifications from #{notifying_resource} with action #{action}, \
|
117
|
-
but #{notifying_resource.inspect} is not valid syntax to look up a resource in the resource collection. Notification \
|
118
|
-
is defined near #{resource.source_line}
|
119
|
-
F
|
120
|
-
err.set_backtrace(e.backtrace)
|
121
|
-
raise err
|
122
|
-
end
|
123
|
-
|
124
|
-
end
|
125
40
|
|
126
41
|
FORBIDDEN_IVARS = [:@run_context, :@not_if, :@only_if, :@enclosing_provider]
|
127
42
|
HIDDEN_IVARS = [:@allowed_actions, :@resource_name, :@source_line, :@run_context, :@name, :@not_if, :@only_if, :@elapsed_time, :@enclosing_provider]
|
@@ -212,6 +127,7 @@ F
|
|
212
127
|
attr_accessor :source_line
|
213
128
|
attr_accessor :retries
|
214
129
|
attr_accessor :retry_delay
|
130
|
+
attr_accessor :declared_type
|
215
131
|
|
216
132
|
attr_reader :updated
|
217
133
|
|
@@ -299,7 +215,7 @@ F
|
|
299
215
|
|
300
216
|
def load_prior_resource(resource_type, instance_name)
|
301
217
|
begin
|
302
|
-
key =
|
218
|
+
key = "#{resource_type}[#{instance_name}]"
|
303
219
|
prior_resource = run_context.resource_collection.lookup(key)
|
304
220
|
# if we get here, there is a prior resource (otherwise we'd have jumped
|
305
221
|
# to the rescue clause).
|
@@ -426,11 +342,11 @@ F
|
|
426
342
|
def notifies(action, resource_spec, timing=:delayed)
|
427
343
|
# when using old-style resources(:template => "/foo.txt") style, you
|
428
344
|
# could end up with multiple resources.
|
345
|
+
validate_resource_spec!(resource_spec)
|
346
|
+
|
429
347
|
resources = [ resource_spec ].flatten
|
430
348
|
resources.each do |resource|
|
431
349
|
|
432
|
-
validate_resource_spec!(resource_spec)
|
433
|
-
|
434
350
|
case timing.to_s
|
435
351
|
when 'delayed'
|
436
352
|
notifies_delayed(action, resource)
|
@@ -449,8 +365,12 @@ F
|
|
449
365
|
# resolve_resource_reference on each in turn, causing them to
|
450
366
|
# resolve lazy/forward references.
|
451
367
|
def resolve_notification_references
|
452
|
-
run_context.immediate_notifications(self).each { |n|
|
453
|
-
|
368
|
+
run_context.immediate_notifications(self).each { |n|
|
369
|
+
n.resolve_resource_reference(run_context.resource_collection)
|
370
|
+
}
|
371
|
+
run_context.delayed_notifications(self).each {|n|
|
372
|
+
n.resolve_resource_reference(run_context.resource_collection)
|
373
|
+
}
|
454
374
|
end
|
455
375
|
|
456
376
|
def notifies_immediately(action, resource_spec)
|
@@ -499,6 +419,14 @@ F
|
|
499
419
|
end
|
500
420
|
end
|
501
421
|
|
422
|
+
# We usually want to store and reference resources by their declared type and not the actual type that
|
423
|
+
# was looked up by the Resolver (IE, "package" becomes YumPackage class). If we have not been provided
|
424
|
+
# the declared key we want to fall back on the old to_s key.
|
425
|
+
def declared_key
|
426
|
+
return to_s if declared_type.nil?
|
427
|
+
"#{declared_type}[#{@name}]"
|
428
|
+
end
|
429
|
+
|
502
430
|
def to_s
|
503
431
|
"#{@resource_name}[#{@name}]"
|
504
432
|
end
|
@@ -833,3 +761,7 @@ F
|
|
833
761
|
end
|
834
762
|
end
|
835
763
|
end
|
764
|
+
|
765
|
+
# We require this at the BOTTOM of this file to avoid circular requires (it is used
|
766
|
+
# at runtime but not load time)
|
767
|
+
require 'chef/provider_resolver'
|
@@ -25,7 +25,8 @@ class Chef
|
|
25
25
|
class Resource
|
26
26
|
class HomebrewPackage < Chef::Resource::Package
|
27
27
|
|
28
|
-
provides :homebrew_package
|
28
|
+
provides :homebrew_package
|
29
|
+
provides :package, os: ["mac_os_x", "darwin"]
|
29
30
|
|
30
31
|
def initialize(name, run_context=nil)
|
31
32
|
super
|
@@ -0,0 +1,109 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Tyler Ball (<tball@chef.io>)
|
3
|
+
# Copyright:: Copyright (c) 2014 Chef Software, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'chef/resource'
|
20
|
+
|
21
|
+
class Chef
|
22
|
+
class Resource
|
23
|
+
class Notification < Struct.new(:resource, :action, :notifying_resource)
|
24
|
+
|
25
|
+
def duplicates?(other_notification)
|
26
|
+
unless other_notification.respond_to?(:resource) && other_notification.respond_to?(:action)
|
27
|
+
msg = "only duck-types of Chef::Resource::Notification can be checked for duplication "\
|
28
|
+
"you gave #{other_notification.inspect}"
|
29
|
+
raise ArgumentError, msg
|
30
|
+
end
|
31
|
+
other_notification.resource == resource && other_notification.action == action
|
32
|
+
end
|
33
|
+
|
34
|
+
# If resource and/or notifying_resource is not a resource object, this will look them up in the resource collection
|
35
|
+
# and fix the references from strings to actual Resource objects.
|
36
|
+
def resolve_resource_reference(resource_collection)
|
37
|
+
return resource if resource.kind_of?(Chef::Resource) && notifying_resource.kind_of?(Chef::Resource)
|
38
|
+
|
39
|
+
if not(resource.kind_of?(Chef::Resource))
|
40
|
+
fix_resource_reference(resource_collection)
|
41
|
+
end
|
42
|
+
|
43
|
+
if not(notifying_resource.kind_of?(Chef::Resource))
|
44
|
+
fix_notifier_reference(resource_collection)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# This will look up the resource if it is not a Resource Object. It will complain if it finds multiple
|
49
|
+
# resources, can't find a resource, or gets invalid syntax.
|
50
|
+
def fix_resource_reference(resource_collection)
|
51
|
+
matching_resource = resource_collection.find(resource)
|
52
|
+
if Array(matching_resource).size > 1
|
53
|
+
msg = "Notification #{self} from #{notifying_resource} was created with a reference to multiple resources, "\
|
54
|
+
"but can only notify one resource. Notifying resource was defined on #{notifying_resource.source_line}"
|
55
|
+
raise Chef::Exceptions::InvalidResourceReference, msg
|
56
|
+
end
|
57
|
+
self.resource = matching_resource
|
58
|
+
|
59
|
+
rescue Chef::Exceptions::ResourceNotFound => e
|
60
|
+
err = Chef::Exceptions::ResourceNotFound.new(<<-FAIL)
|
61
|
+
resource #{notifying_resource} is configured to notify resource #{resource} with action #{action}, \
|
62
|
+
but #{resource} cannot be found in the resource collection. #{notifying_resource} is defined in \
|
63
|
+
#{notifying_resource.source_line}
|
64
|
+
FAIL
|
65
|
+
err.set_backtrace(e.backtrace)
|
66
|
+
raise err
|
67
|
+
rescue Chef::Exceptions::InvalidResourceSpecification => e
|
68
|
+
err = Chef::Exceptions::InvalidResourceSpecification.new(<<-F)
|
69
|
+
Resource #{notifying_resource} is configured to notify resource #{resource} with action #{action}, \
|
70
|
+
but #{resource.inspect} is not valid syntax to look up a resource in the resource collection. Notification \
|
71
|
+
is defined near #{notifying_resource.source_line}
|
72
|
+
F
|
73
|
+
err.set_backtrace(e.backtrace)
|
74
|
+
raise err
|
75
|
+
end
|
76
|
+
|
77
|
+
# This will look up the notifying_resource if it is not a Resource Object. It will complain if it finds multiple
|
78
|
+
# resources, can't find a resource, or gets invalid syntax.
|
79
|
+
def fix_notifier_reference(resource_collection)
|
80
|
+
matching_notifier = resource_collection.find(notifying_resource)
|
81
|
+
if Array(matching_notifier).size > 1
|
82
|
+
msg = "Notification #{self} from #{notifying_resource} was created with a reference to multiple notifying "\
|
83
|
+
"resources, but can only originate from one resource. Destination resource was defined "\
|
84
|
+
"on #{resource.source_line}"
|
85
|
+
raise Chef::Exceptions::InvalidResourceReference, msg
|
86
|
+
end
|
87
|
+
self.notifying_resource = matching_notifier
|
88
|
+
|
89
|
+
rescue Chef::Exceptions::ResourceNotFound => e
|
90
|
+
err = Chef::Exceptions::ResourceNotFound.new(<<-FAIL)
|
91
|
+
Resource #{resource} is configured to receive notifications from #{notifying_resource} with action #{action}, \
|
92
|
+
but #{notifying_resource} cannot be found in the resource collection. #{resource} is defined in \
|
93
|
+
#{resource.source_line}
|
94
|
+
FAIL
|
95
|
+
err.set_backtrace(e.backtrace)
|
96
|
+
raise err
|
97
|
+
rescue Chef::Exceptions::InvalidResourceSpecification => e
|
98
|
+
err = Chef::Exceptions::InvalidResourceSpecification.new(<<-F)
|
99
|
+
Resource #{resource} is configured to receive notifications from #{notifying_resource} with action #{action}, \
|
100
|
+
but #{notifying_resource.inspect} is not valid syntax to look up a resource in the resource collection. Notification \
|
101
|
+
is defined near #{resource.source_line}
|
102
|
+
F
|
103
|
+
err.set_backtrace(e.backtrace)
|
104
|
+
raise err
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|