diff options
author | Lamont Granquist <lamont@scriptkiddie.org> | 2014-10-24 10:45:43 -0700 |
---|---|---|
committer | Lamont Granquist <lamont@scriptkiddie.org> | 2014-10-24 10:45:43 -0700 |
commit | 97aaf5bbcdfd0810722b123bdc67e883a7ca8077 (patch) | |
tree | 25663bf1d4f53664b96844251091b51273ad84c7 /lib/chef/provider_resolver.rb | |
parent | cb1bcb1f08816f551f96e713624718f58da3c9b3 (diff) | |
download | chef-97aaf5bbcdfd0810722b123bdc67e883a7ca8077.tar.gz |
Chef-12 RC Provider Resolver
makes resource and provider class resolution more dynamic.
begins deprecation of Chef::Platform static mapping.
Diffstat (limited to 'lib/chef/provider_resolver.rb')
-rw-r--r-- | lib/chef/provider_resolver.rb | 82 |
1 files changed, 64 insertions, 18 deletions
diff --git a/lib/chef/provider_resolver.rb b/lib/chef/provider_resolver.rb index 91b85e3aa0..c819b0c87f 100644 --- a/lib/chef/provider_resolver.rb +++ b/lib/chef/provider_resolver.rb @@ -16,42 +16,88 @@ # limitations under the License. # +require 'chef/exceptions' +require 'chef/platform/provider_priority_map' + class Chef class ProviderResolver attr_reader :node - attr_reader :providers def initialize(node) @node = node - @providers = [] - @loaded = false end - def load(reload = false) - return if loaded? && !reload + # return a deterministically sorted list of Chef::Provider subclasses + def providers + Chef::Provider.descendants.sort {|a,b| a.to_s <=> b.to_s } + end - @providers = [] if reload + def resolve(resource, action) + maybe_explicit_provider(resource) || + maybe_dynamic_provider_resolution(resource, action) || + maybe_chef_platform_lookup(resource) + end - Chef::Provider.each do |provider| - @providers << provider if provider.supports_platform?(@node[:platform]) - end + private - @loaded = true + # if resource.provider is set, just return one of those objects + def maybe_explicit_provider(resource) + return nil unless resource.provider + resource.provider end - def loaded? - !!@loaded - end + # try dynamically finding a provider based on querying the providers to see what they support + def maybe_dynamic_provider_resolution(resource, action) + # this cut only depends on the node value and is going to be static for all nodes + # will contain all providers that could possibly support a resource on a node + enabled_handlers = providers.select do |klass| + klass.provides?(node, resource) + end - def resolve(resource) - self.load if !loaded? + # log this so we know what providers will work for the generic resource on the node (early cut) + Chef::Log.debug "providers for generic #{resource.resource_name} resource enabled on node include: #{enabled_handlers}" - providers = @providers.find_all do |provider| - provider.enabled?(node) && provider.implements?(resource) + # ask all the enabled providers if they can actually support the resource + supported_handlers = enabled_handlers.select do |klass| + klass.supports?(resource, action) end - resource.evaluate_providers(providers) + # what providers were excluded by machine state (late cut) + Chef::Log.debug "providers that refused resource #{resource} were: #{enabled_handlers - supported_handlers}" + Chef::Log.debug "providers that support resource #{resource} include: #{supported_handlers}" + + handlers = supported_handlers.empty? ? enabled_handlers : supported_handlers + + if handlers.count >= 2 + priority_list = [ get_provider_priority_map(resource.resource_name, node) ].flatten.compact + + handlers = handlers.sort_by { |x| i = priority_list.index x; i.nil? ? Float::INFINITY : i } + + handlers = [ handlers.first ] + end + + Chef::Log.debug "providers that survived replacement include: #{handlers}" + + raise Chef::Exceptions::AmbiguousProviderResolution.new(resource, handlers) if handlers.count >= 2 + + return nil if handlers.empty? + + handlers[0] + end + + # try the old static lookup of providers by platform + def maybe_chef_platform_lookup(resource) + Chef::Platform.find_provider_for_node(node, resource) + end + + # dep injection hooks + def get_provider_priority_map(resource_name, node) + provider_priority_map.get(node, resource_name) + end + + def provider_priority_map + Chef::Platform::ProviderPriorityMap.instance.priority_map end end end |