1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
#
# Author:: Lamont Granquist (<lamont@chef.io>)
# Copyright:: Copyright (c) 2015 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/exceptions'
require 'chef/platform/resource_priority_map'
class Chef
class ResourceResolver
include Chef::Mixin::ConvertToClassName
attr_reader :node
attr_reader :resource
attr_reader :action
def initialize(node, resource)
@node = node
@resource = resource.to_sym
end
def resolve
maybe_dynamic_resource_resolution ||
maybe_chef_platform_lookup
end
def provided_by?(resource_class)
!prioritized_handlers.include?(resource_class)
end
#
# Resolve a resource by name.
#
# @param resource_name [Symbol] The resource DSL name (e.g. `:file`)
# @param node [Chef::Node] The node on which the resource will run.
#
def self.resolve(resource_name, node: Chef.node)
new(node, resource_name).resolve
end
protected
# try dynamically finding a resource based on querying the resources to see what they support
def maybe_dynamic_resource_resolution
# log this so we know what resources will work for the generic resource on the node (early cut)
Chef::Log.debug "Resources for generic #{resource} resource enabled on node include: #{enabled_handlers}"
handler = prioritized_handlers.first
if handler
Chef::Log.debug "Resource for #{resource} is #{handler}"
else
Chef::Log.debug "Dynamic resource resolver FAILED to resolve a resource for #{resource}"
end
handler
end
# try the old static lookup of resources by mangling name to resource klass
def maybe_chef_platform_lookup
Chef::Resource.resource_matching_short_name(resource)
end
def priority_map
Chef::Platform::ResourcePriorityMap.instance
end
def prioritized_handlers
@prioritized_handlers ||= priority_map.list_handlers(node, resource)
end
module Deprecated
# return a deterministically sorted list of Chef::Resource subclasses
# @deprecated Now prioritized_handlers does its own work (more efficiently)
def resources
Chef::Resource.sorted_descendants
end
# A list of all handlers
# @deprecated Now prioritized_handlers does its own work
def enabled_handlers
resources.select { |klass| klass.provides?(node, resource) }
end
protected
# If there are no providers for a DSL, we search through the
def prioritized_handlers
@prioritized_handlers ||= super ||
resources.select do |klass|
# Don't bother calling provides? unless it's overriden. We already
# know prioritized_handlers
if klass.method(:provides?).owner != Chef::Resource && klass.provides?(node, resource)
Chef::Log.deprecation("Resources #{provided.join(", ")} are marked as providing DSL #{resource}, but provides #{resource.inspect} was never called!")
Chef::Log.deprecation("In Chef 13, this will break: you must call provides to mark the names you provide, even if you also override provides? yourself.")
true
end
end
end
end
prepend Deprecated
end
end
|