class Chef::ProviderResolver
Provider Resolution
¶ ↑
Provider resolution is the process of taking a Resource object and an action, and determining the Provider class that should be instantiated to handle the action.
If the resource has its `provider` set, that is used.
Otherwise, we take the lists of Providers that have registered as providing the DSL through `provides :dsl_name, <filters>` or `Chef.set_resource_priority_array :dsl_name, <filters>`. We filter each list of Providers through:
-
The filters it was registered with (such as `os: 'linux'` or `platform_family: 'debian'`)
-
`provides?(node, resource)`
-
`supports?(resource, action)`
Anything that passes the filter and returns `true` to provides and supports, is considered a match. The first matching Provider in the *most recently registered list* is selected and returned.
Attributes
Public Class Methods
# File lib/chef/provider_resolver.rb, line 53 def initialize(node, resource, action) @node = node @resource = resource @action = action end
Public Instance Methods
# File lib/chef/provider_resolver.rb, line 72 def enabled_handlers @enabled_handlers ||= potential_handlers.select { |handler| !overrode_provides?(handler) || handler.provides?(node, resource) } end
Does NOT call provides? on the resource (it is assumed this is being called from provides?).
# File lib/chef/provider_resolver.rb, line 68 def provided_by?(provider_class) potential_handlers.include?(provider_class) end
# File lib/chef/provider_resolver.rb, line 59 def resolve maybe_explicit_provider(resource) || maybe_custom_resource(resource) || maybe_dynamic_provider_resolution(resource, action) || raise(Chef::Exceptions::ProviderNotFound, "Cannot find a provider for #{resource} on #{node["platform"]} version #{node["platform_version"]}") end
TODO deprecate this and allow actions to be passed as a filter to `provides` so we don't have to have two separate things. @api private
# File lib/chef/provider_resolver.rb, line 79 def supported_handlers enabled_handlers.select { |handler| handler.supports?(resource, action) } end
Private Instance Methods
# File lib/chef/provider_resolver.rb, line 138 def handler_map Chef.provider_handler_map end
if its a custom resource, just grab the action class
# File lib/chef/provider_resolver.rb, line 110 def maybe_custom_resource(resource) resource.class.action_class if resource.class.custom_resource? end
try dynamically finding a provider based on querying the providers to see what they support
# File lib/chef/provider_resolver.rb, line 120 def maybe_dynamic_provider_resolution(resource, action) Chef::Log.trace "Providers for generic #{resource.resource_name} resource enabled on node include: #{enabled_handlers}" handler = prioritized_handlers.first if handler Chef::Log.trace "Provider for action #{action} on resource #{resource} is #{handler}" else Chef::Log.trace "Dynamic provider resolver FAILED to resolve a provider for action #{action} on resource #{resource}" end handler end
if resource.provider is set, just return one of those objects
# File lib/chef/provider_resolver.rb, line 115 def maybe_explicit_provider(resource) resource.provider if resource.provider end
# File lib/chef/provider_resolver.rb, line 142 def overrode_provides?(handler) handler.method(:provides?).owner != Chef::Provider.method(:provides?).owner end
# File lib/chef/provider_resolver.rb, line 85 def potential_handlers handler_map.list(node, resource.resource_name).uniq end
The list of handlers, with any in the #priority_map moved to the front
# File lib/chef/provider_resolver.rb, line 90 def prioritized_handlers @prioritized_handlers ||= begin supported_handlers = self.supported_handlers if supported_handlers.empty? # We always require a provider to be able to call define_resource_requirements on. In the why-run case we need # a provider to say "assuming /etc/init.d/whatever would have been installed" and in the non-why-run case we # need to make a best guess at "cannot find /etc/init.d/whatever". We are essentially defining a "default" provider # for the platform, which is the best we can do, but which might give misleading errors, but we cannot read minds. Chef::Log.trace "No providers responded true to `supports?` for action #{action} on resource #{resource}, falling back to enabled handlers so we can return something anyway." supported_handlers = enabled_handlers end prioritized = priority_map.list(node, resource.resource_name).flatten(1) prioritized &= supported_handlers # Filter the priority map by the actual enabled handlers prioritized |= supported_handlers # Bring back any handlers that aren't in the priority map, at the *end* (ordered set) prioritized end end
# File lib/chef/provider_resolver.rb, line 134 def priority_map Chef.provider_priority_map end