File Manager
Viewing File: resource_resolver.rb
#
# Author:: Lamont Granquist (<lamont@chef.io>)
# Copyright:: Copyright (c) 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_relative "exceptions"
require_relative "platform/resource_priority_map"
require_relative "mixin/convert_to_class_name"
class Chef
class ResourceResolver
#
# Resolve a resource by name.
#
# @param resource_name [Symbol] The resource DSL name (e.g. `:file`).
# @param node [Chef::Node] The node against which to resolve. `nil` causes
# platform filters to be ignored.
#
def self.resolve(resource_name, node: nil)
new(node, resource_name).resolve
end
#
# Resolve a list of all resources that implement the given DSL (in order of
# preference).
#
# @param resource_name [Symbol] The resource DSL name (e.g. `:file`).
# @param node [Chef::Node] The node against which to resolve. `nil` causes
# platform filters to be ignored.
#
def self.list(resource_name, node: nil)
new(node, resource_name).list
end
include Chef::Mixin::ConvertToClassName
# @api private
attr_reader :node
# @api private
attr_reader :resource_name
# @api private
attr_reader :action
#
# Create a resolver.
#
# @param node [Chef::Node] The node against which to resolve. `nil` causes
# platform filters to be ignored.
# @param resource_name [Symbol] The resource DSL name (e.g. `:file`).
#
# @api private use Chef::ResourceResolver.resolve or .list instead.
def initialize(node, resource_name)
@node = node
@resource_name = resource_name.to_sym
end
# @api private use Chef::ResourceResolver.resolve instead.
def resolve
# log this so we know what resources will work for the generic resource on the node (early cut)
Chef::Log.trace "Resources for generic #{resource_name} resource enabled on node include: #{prioritized_handlers}"
handler = prioritized_handlers.first
if handler
Chef::Log.trace "Resource for #{resource_name} is #{handler}"
else
Chef::Log.trace "Dynamic resource resolver FAILED to resolve a resource for #{resource_name}"
end
handler
end
# @api private
def list
Chef::Log.trace "Resources for generic #{resource_name} resource enabled on node include: #{prioritized_handlers}"
prioritized_handlers
end
#
# Whether this DSL is provided by the given resource_class.
#
# Does NOT call provides? on the resource (it is assumed this is being
# called *from* provides?).
#
# @api private
def provided_by?(resource_class)
potential_handlers.include?(resource_class)
end
#
# Whether the given handler attempts to provide the resource class at all.
#
# @api private
def self.includes_handler?(resource_name, resource_class)
handler_map.list(nil, resource_name).include?(resource_class)
end
protected
def self.priority_map
Chef.resource_priority_map
end
def self.handler_map
Chef.resource_handler_map
end
def priority_map
Chef.resource_priority_map
end
def handler_map
Chef.resource_handler_map
end
# @api private
def potential_handlers
handler_map.list(node, resource_name).uniq
end
def enabled_handlers
potential_handlers.select { |handler| !overrode_provides?(handler) || handler.provides?(node, resource_name) }
end
def prioritized_handlers
@prioritized_handlers ||= begin
enabled_handlers = self.enabled_handlers
prioritized = priority_map.list(node, resource_name).flatten(1)
prioritized &= enabled_handlers # Filter the priority map by the actual enabled handlers
prioritized |= enabled_handlers # Bring back any handlers that aren't in the priority map, at the *end* (ordered set)
prioritized
end
end
def overrode_provides?(handler)
handler.method(:provides?).owner != Chef::Resource.method(:provides?).owner
end
end
end