diff options
author | John Keiser <john@johnkeiser.com> | 2015-06-30 11:35:33 -0600 |
---|---|---|
committer | John Keiser <john@johnkeiser.com> | 2015-06-30 11:35:33 -0600 |
commit | 480d18f26f17c289889ed65d3f8a50e5b336053f (patch) | |
tree | 4aa5d541a6a2f06c84ac6be9f742e8d1e8477687 | |
parent | f0e9b2ffe7ec0904456b50ee26913cb42c0ca258 (diff) | |
parent | e1e1e1331a4e87c662dae72acdeff00230e74a3c (diff) | |
download | chef-480d18f26f17c289889ed65d3f8a50e5b336053f.tar.gz |
Merge branch 'jk/call_provides_when_resolving'
24 files changed, 676 insertions, 372 deletions
diff --git a/lib/chef/exceptions.rb b/lib/chef/exceptions.rb index dd0bac3cf9..1b726d654c 100644 --- a/lib/chef/exceptions.rb +++ b/lib/chef/exceptions.rb @@ -97,6 +97,8 @@ class Chef class ConflictingMembersInGroup < ArgumentError; end class InvalidResourceReference < RuntimeError; end class ResourceNotFound < RuntimeError; end + class ProviderNotFound < RuntimeError; end + NoProviderAvailable = ProviderNotFound class VerificationNotFound < RuntimeError; end # Can't find a Resource of this type that is valid on this platform. @@ -218,8 +220,6 @@ class Chef class ChildConvergeError < RuntimeError; end - class NoProviderAvailable < RuntimeError; end - class DeprecatedFeatureError < RuntimeError; def initalize(message) super("#{message} (raising error due to treat_deprecation_warnings_as_errors being set)") diff --git a/lib/chef/node_map.rb b/lib/chef/node_map.rb index edf0fd689a..d905c8779e 100644 --- a/lib/chef/node_map.rb +++ b/lib/chef/node_map.rb @@ -20,13 +20,6 @@ class Chef class NodeMap # - # Create a new NodeMap - # - def initialize - @map = {} - end - - # # Set a key/value pair on the map with a filter. The filter must be true # when applied to the node in order to retrieve the value. # @@ -55,18 +48,17 @@ class Chef # The map is sorted in order of preference already; we just need to find # our place in it (just before the first value with the same preference level). insert_at = nil - @map[key] ||= [] - @map[key].each_with_index do |matcher,index| + map[key] ||= [] + map[key].each_with_index do |matcher,index| cmp = compare_matchers(key, new_matcher, matcher) insert_at ||= index if cmp && cmp <= 0 end if insert_at - @map[key].insert(insert_at, new_matcher) + map[key].insert(insert_at, new_matcher) else - @map[key] << new_matcher + map[key] << new_matcher end - insert_at ||= @map[key].size - 1 - @map + map end # @@ -100,8 +92,8 @@ class Chef # def list(node, key, canonical: nil) raise ArgumentError, "first argument must be a Chef::Node" unless node.is_a?(Chef::Node) || node.nil? - return [] unless @map.has_key?(key) - @map[key].select do |matcher| + return [] unless map.has_key?(key) + map[key].select do |matcher| node_matches?(node, matcher) && canonical_matches?(canonical, matcher) end.map { |matcher| matcher[:value] } end @@ -110,11 +102,11 @@ class Chef # @return remaining # @api private def delete_canonical(key, value) - remaining = @map[key] + remaining = map[key] if remaining remaining.delete_if { |matcher| matcher[:canonical] && Array(matcher[:value]) == Array(value) } if remaining.empty? - @map.delete(key) + map.delete(key) remaining = nil end end @@ -222,5 +214,9 @@ class Chef end cmp end + + def map + @map ||= {} + end end end diff --git a/lib/chef/platform/priority_map.rb b/lib/chef/platform/priority_map.rb index d559eece78..73554eafe1 100644 --- a/lib/chef/platform/priority_map.rb +++ b/lib/chef/platform/priority_map.rb @@ -6,7 +6,7 @@ class Chef def priority(resource_name, priority_array, *filter) set_priority_array(resource_name.to_sym, priority_array, *filter) end - + # @api private def get_priority_array(node, key) get(node, key) @@ -24,6 +24,12 @@ class Chef list(node, key, **filters).flatten(1).uniq end + # @api private + def includes_handler?(key, handler) + return false if !map.has_key?(key) + map[key].any? { |m| h = m[:value]; h.is_a?(Array) ? h.include?(handler) : h == handler } + end + # # Priority maps have one extra precedence: priority arrays override "provides," # and "provides" lines with identical filters sort by class name (ascending). diff --git a/lib/chef/platform/provider_mapping.rb b/lib/chef/platform/provider_mapping.rb index 4278b8d24f..38dd0e38af 100644 --- a/lib/chef/platform/provider_mapping.rb +++ b/lib/chef/platform/provider_mapping.rb @@ -176,7 +176,7 @@ class Chef platform_provider(platform, version, resource_type) || resource_matching_provider(platform, version, resource_type) - raise ArgumentError, "Cannot find a provider for #{resource_type} on #{platform} version #{version}" if provider_klass.nil? + raise Chef::Exceptions::ProviderNotFound, "Cannot find a provider for #{resource_type} on #{platform} version #{version}" if provider_klass.nil? provider_klass end @@ -197,7 +197,7 @@ class Chef def resource_matching_provider(platform, version, resource_type) if resource_type.kind_of?(Chef::Resource) - class_name = resource_type.class.name ? resource_type.class.name.split('::').last : + class_name = resource_type.class.name ? resource_type.class.name.split('::').last : convert_to_class_name(resource_type.resource_name.to_s) begin diff --git a/lib/chef/provider/dsc_resource.rb b/lib/chef/provider/dsc_resource.rb index 5fa84a21e9..379369ba6e 100644 --- a/lib/chef/provider/dsc_resource.rb +++ b/lib/chef/provider/dsc_resource.rb @@ -53,7 +53,7 @@ class Chef requirements.assert(:run) do |a| a.assertion { supports_dsc_invoke_resource? } err = ["You must have Powershell version >= 5.0.10018.0 to use dsc_resource."] - a.failure_message Chef::Exceptions::NoProviderAvailable, + a.failure_message Chef::Exceptions::ProviderNotFound, err a.whyrun err + ["Assuming a previous resource installs Powershell 5.0.10018.0 or higher."] a.block_action! @@ -63,7 +63,7 @@ class Chef meta_configuration['RefreshMode'] == 'Disabled' } err = ["The LCM must have its RefreshMode set to Disabled. "] - a.failure_message Chef::Exceptions::NoProviderAvailable, err.join(' ') + a.failure_message Chef::Exceptions::ProviderNotFound, err.join(' ') a.whyrun err + ["Assuming a previous resource sets the RefreshMode."] a.block_action! end diff --git a/lib/chef/provider/dsc_script.rb b/lib/chef/provider/dsc_script.rb index a75e68a475..b2432132b7 100644 --- a/lib/chef/provider/dsc_script.rb +++ b/lib/chef/provider/dsc_script.rb @@ -70,7 +70,7 @@ class Chef "Powershell 4.0 or higher was not detected on your system and is required to use the dsc_script resource.", ] a.assertion { supports_dsc? } - a.failure_message Chef::Exceptions::NoProviderAvailable, err.join(' ') + a.failure_message Chef::Exceptions::ProviderNotFound, err.join(' ') a.whyrun err + ["Assuming a previous resource installs Powershell 4.0 or higher."] a.block_action! end diff --git a/lib/chef/provider/mount/aix.rb b/lib/chef/provider/mount/aix.rb index 4ad7b24c15..510dfde46d 100644 --- a/lib/chef/provider/mount/aix.rb +++ b/lib/chef/provider/mount/aix.rb @@ -32,7 +32,7 @@ class Chef @new_resource.options.clear end if @new_resource.fstype == "auto" - @new_resource.fstype = nil + @new_resource.send(:clear_fstype) end end diff --git a/lib/chef/provider/package/openbsd.rb b/lib/chef/provider/package/openbsd.rb index f231101390..83fc09c8ae 100644 --- a/lib/chef/provider/package/openbsd.rb +++ b/lib/chef/provider/package/openbsd.rb @@ -31,6 +31,7 @@ class Chef class Openbsd < Chef::Provider::Package provides :package, os: "openbsd" + provides :openbsd_package include Chef::Mixin::ShellOut include Chef::Mixin::GetSourceFromPackage diff --git a/lib/chef/provider_resolver.rb b/lib/chef/provider_resolver.rb index 5bfee343d1..8e731ff96a 100644 --- a/lib/chef/provider_resolver.rb +++ b/lib/chef/provider_resolver.rb @@ -17,7 +17,7 @@ # require 'chef/exceptions' -require 'chef/platform/provider_priority_map' +require 'chef/platform/priority_map' class Chef # @@ -62,12 +62,35 @@ class Chef maybe_chef_platform_lookup(resource) end + # Does NOT call provides? on the resource (it is assumed this is being + # called *from* provides?). def provided_by?(provider_class) - prioritized_handlers.include?(provider_class) + potential_handlers.include?(provider_class) + end + + def self.includes_handler?(resource_name, provider_class) + priority_map.includes_handler?(resource_name, provider_class) + end + + def enabled_handlers + @enabled_handlers ||= + potential_handlers.select { |handler| !overrode_provides?(handler) || handler.provides?(node, resource) } + 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 + def supported_handlers + @supported_handlers ||= + enabled_handlers.select { |handler| handler.supports?(resource, action) } end private + def potential_handlers + priority_map.list_handlers(node, resource.resource_name) + end + # if resource.provider is set, just return one of those objects def maybe_explicit_provider(resource) return nil unless resource.provider @@ -78,28 +101,16 @@ class Chef def maybe_dynamic_provider_resolution(resource, action) Chef::Log.debug "Providers for generic #{resource.resource_name} resource enabled on node include: #{enabled_handlers}" - # Get all the handlers in the priority bucket - handlers = prioritized_handlers - - # Narrow it down to handlers that return `true` to `provides?` - # TODO deprecate this and don't bother calling--the fact that they said - # `provides` should be enough. But we need to do it right now because - # some classes implement additional handling. - enabled_handlers = prioritized_handlers.select { |handler| handler.provides?(node, resource) } - - # Narrow it down to handlers that return `true` to `supports?` - # TODO deprecate this and allow actions to be passed as a filter to - # `provides` so we don't have to have two separate things. - supported_handlers = enabled_handlers.select { |handler| handler.supports?(resource, action) } - if supported_handlers.empty? + handlers = supported_handlers + if handlers.empty? # if none of the providers specifically support the resource, we still need to pick one of the providers that are # enabled on the node to handle the why-run use case. FIXME we should only do this in why-run mode then. Chef::Log.debug "No providers responded true to `supports?` for action #{action} on resource #{resource}, falling back to enabled handlers so we can return something anyway." - handler = enabled_handlers.first - else - handler = supported_handlers.first + handlers = enabled_handlers end + handler = handlers.first + if handler Chef::Log.debug "Provider for action #{action} on resource #{resource} is #{handler}" else @@ -114,13 +125,16 @@ class Chef Chef::Platform.find_provider_for_node(node, resource) end - def provider_priority_map - Chef::Platform::ProviderPriorityMap.instance + def self.priority_map + Chef.provider_priority_map end - def prioritized_handlers - @prioritized_handlers ||= - provider_priority_map.list_handlers(node, resource.resource_name).flatten(1).uniq + def priority_map + Chef.provider_priority_map + end + + def overrode_provides?(handler) + handler.method(:provides?).owner != Chef::Provider.method(:provides?).owner end module Deprecated @@ -129,33 +143,21 @@ class Chef @providers ||= Chef::Provider.descendants end - # this cut looks at if the provider can handle the resource type on the node def enabled_handlers - @enabled_handlers ||= - providers.select do |klass| - # NB: this is different from resource_resolver which must pass a resource_name - # FIXME: deprecate this and normalize on passing resource_name here - klass.provides?(node, resource) - end.sort {|a,b| a.to_s <=> b.to_s } - end - - # this cut looks at if the provider can handle the specific resource and action - def supported_handlers - @supported_handlers ||= - enabled_handlers.select do |klass| - klass.supports?(resource, action) - end - end - - # If there are no providers for a DSL, we search through the - def prioritized_handlers - @prioritized_handlers ||= super || begin - result = providers.select { |handler| handler.provides?(node, resource) }.sort_by(:name) - if !result.empty? - Chef::Log.deprecation("#{resource.resource_name.to_sym} is marked as providing DSL #{method_symbol}, but provides #{resource.resource_name.to_sym.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.") + @enabled_handlers ||= begin + handlers = super + if handlers.empty? + # Look through all providers, and find ones that return true to provides. + # Don't bother with ones that don't override provides?, since they + # would have been in enabled_handlers already if that were so. (It's a + # perf concern otherwise.) + handlers = providers.select { |handler| overrode_provides?(handler) && handler.provides?(node, resource) } + handlers.each do |handler| + Chef::Log.deprecation("#{handler}.provides? returned true when asked if it provides DSL #{resource.resource_name}, but provides #{resource.resource_name.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.") + end end - result + handlers end end end diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb index 704490e748..7965068037 100644 --- a/lib/chef/resource.rb +++ b/lib/chef/resource.rb @@ -1017,7 +1017,7 @@ class Chef if name name = name.to_sym # If our class is not already providing this name, provide it. - if !Chef::ResourceResolver.list(name).include?(self) + if !Chef::ResourceResolver.includes_handler?(name, self) provides name, canonical: true end @resource_name = name @@ -1297,7 +1297,7 @@ class Chef end def self.inherited(child) super - @sorted_descendants = nil + @@sorted_descendants = nil # set resource_name automatically if it's not set if child.name && !child.resource_name if child.name =~ /^Chef::Resource::(\w+)$/ @@ -1340,8 +1340,8 @@ class Chef result end - def self.provides?(node, resource) - Chef::ResourceResolver.resolve(resource, node: node).provided_by?(self) + def self.provides?(node, resource_name) + Chef::ResourceResolver.new(node, resource_name).provided_by?(self) end # Helper for #notifies diff --git a/lib/chef/resource/dsc_script.rb b/lib/chef/resource/dsc_script.rb index 2fcf183375..2877f61eb4 100644 --- a/lib/chef/resource/dsc_script.rb +++ b/lib/chef/resource/dsc_script.rb @@ -22,7 +22,7 @@ class Chef class Resource class DscScript < Chef::Resource - provides :dsc_script, platform: "windows" + provides :dsc_script, os: "windows" default_action :run diff --git a/lib/chef/resource/ips_package.rb b/lib/chef/resource/ips_package.rb index 8d720dd411..2bf8e1dba8 100644 --- a/lib/chef/resource/ips_package.rb +++ b/lib/chef/resource/ips_package.rb @@ -23,6 +23,7 @@ class Chef class Resource class IpsPackage < ::Chef::Resource::Package + provides :package, os: "solaris2" provides :ips_package, os: "solaris2" allowed_actions :install, :remove, :upgrade diff --git a/lib/chef/resource/mount.rb b/lib/chef/resource/mount.rb index 79986d127f..a5da0ba329 100644 --- a/lib/chef/resource/mount.rb +++ b/lib/chef/resource/mount.rb @@ -174,6 +174,14 @@ class Chef ) end + private + + # Used by the AIX provider to set fstype to nil. + # TODO use property to make nil a valid value for fstype + def clear_fstype + @fstype = nil + end + end end end diff --git a/lib/chef/resource/openbsd_package.rb b/lib/chef/resource/openbsd_package.rb index f91fdb37e0..9ae8813d69 100644 --- a/lib/chef/resource/openbsd_package.rb +++ b/lib/chef/resource/openbsd_package.rb @@ -29,17 +29,6 @@ class Chef include Chef::Mixin::ShellOut provides :package, os: "openbsd" - - def after_created - assign_provider - end - - private - - def assign_provider - @provider = Chef::Provider::Package::Openbsd - end - end end end diff --git a/lib/chef/resource/solaris_package.rb b/lib/chef/resource/solaris_package.rb index 2dc72d5c47..a98fb8b4fa 100644 --- a/lib/chef/resource/solaris_package.rb +++ b/lib/chef/resource/solaris_package.rb @@ -24,10 +24,7 @@ class Chef class Resource class SolarisPackage < Chef::Resource::Package provides :package, os: "solaris2", platform_family: "nexentacore" - provides :package, os: "solaris2", platform_family: "solaris2" do |node| - # on >= Solaris 11 we default to IPS packages instead - node[:platform_version].to_f <= 5.10 - end + provides :package, os: "solaris2", platform_family: "solaris2", platform_version: "<= 5.10" end end end diff --git a/lib/chef/resource_resolver.rb b/lib/chef/resource_resolver.rb index 9df627beb2..2f27e93a3b 100644 --- a/lib/chef/resource_resolver.rb +++ b/lib/chef/resource_resolver.rb @@ -83,9 +83,9 @@ class Chef # @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.debug "Resources for generic #{resource_name} resource enabled on node include: #{prioritized_handlers}" + Chef::Log.debug "Resources for generic #{resource_name} resource enabled on node include: #{enabled_handlers}" - handler = prioritized_handlers.first + handler = enabled_handlers.first if handler Chef::Log.debug "Resource for #{resource_name} is #{handler}" @@ -98,59 +98,70 @@ class Chef # @api private def list - Chef::Log.debug "Resources for generic #{resource_name} resource enabled on node include: #{prioritized_handlers}" - prioritized_handlers + Chef::Log.debug "Resources for generic #{resource_name} resource enabled on node include: #{enabled_handlers}" + enabled_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) - !prioritized_handlers.include?(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) + priority_map.includes_handler?(resource_name, resource_class) end protected + def self.priority_map + Chef.resource_priority_map + end + def priority_map - Chef::Platform::ResourcePriorityMap.instance + Chef.resource_priority_map end - def prioritized_handlers - @prioritized_handlers ||= - priority_map.list_handlers(node, resource_name, canonical: canonical) + # @api private + def potential_handlers + priority_map.list_handlers(node, resource_name, canonical: canonical) + end + + def enabled_handlers + potential_handlers.select { |handler| !overrode_provides?(handler) || handler.provides?(node, resource_name) } + end + + def overrode_provides?(handler) + handler.method(:provides?).owner != Chef::Resource.method(:provides?).owner 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 - Chef::Log.deprecation("enabled_handlers is deprecated. If you are implementing a ResourceResolver, use provided_handlers. If you are not, use Chef::ResourceResolver.list(#{resource_name.inspect}, node: <node>)") - resources.select { |klass| klass.provides?(node, resource_name) } - end - - protected - - # A list of all handlers for the given DSL. If there are no handlers in - # the map, we still check all descendants of Chef::Resource for backwards - # compatibility purposes. - def prioritized_handlers - @prioritized_handlers ||= super || - resources.select do |klass| - # Don't bother calling provides? unless it's overridden. We already - # know prioritized_handlers - if klass.method(:provides?).owner != Chef::Resource && klass.provides?(node, resource_name) - Chef::Log.deprecation("Resources #{provided.join(", ")} are marked as providing DSL #{resource_name}, but provides #{resource_name.inspect} was never called!") + @enabled_handlers ||= begin + handlers = super + if handlers.empty? + handlers = resources.select { |handler| overrode_provides?(handler) && handler.provides?(node, resource_name) } + handlers.each do |handler| + Chef::Log.deprecation("#{handler}.provides? returned true when asked if it provides DSL #{resource_name}, but provides #{resource_name.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 + handlers + end end end prepend Deprecated diff --git a/spec/functional/resource/package_spec.rb b/spec/functional/resource/package_spec.rb index 5c17ca0107..8d37b072e8 100644 --- a/spec/functional/resource/package_spec.rb +++ b/spec/functional/resource/package_spec.rb @@ -386,5 +386,3 @@ describe Chef::Resource::Package, metadata do end end - - diff --git a/spec/integration/recipes/recipe_dsl_spec.rb b/spec/integration/recipes/recipe_dsl_spec.rb index 5426dce080..fa38808e3e 100644 --- a/spec/integration/recipes/recipe_dsl_spec.rb +++ b/spec/integration/recipes/recipe_dsl_spec.rb @@ -11,7 +11,7 @@ describe "Recipe DSL methods" do before(:all) { Namer.current_index = 1 } before { Namer.current_index += 1 } - context "With resource 'base_thingy' declared as BaseThingy" do + context "with resource 'base_thingy' declared as BaseThingy" do before(:context) { class BaseThingy < Chef::Resource @@ -52,7 +52,7 @@ describe "Recipe DSL methods" do Chef::Config[:treat_deprecation_warnings_as_errors] = false end - context "With a resource 'backcompat_thingy' declared in Chef::Resource and Chef::Provider" do + context "with a resource 'backcompat_thingy' declared in Chef::Resource and Chef::Provider" do before(:context) { class Chef::Resource::BackcompatThingy < Chef::Resource @@ -97,7 +97,7 @@ describe "Recipe DSL methods" do end end - context "With a resource named RecipeDSLSpecNamespace::Bar::BarThingy" do + context "with a resource named RecipeDSLSpecNamespace::Bar::BarThingy" do before(:context) { class RecipeDSLSpecNamespace::Bar::BarThingy < BaseThingy @@ -112,7 +112,7 @@ describe "Recipe DSL methods" do end end - context "With a resource named Chef::Resource::NoNameThingy with resource_name nil" do + context "with a resource named Chef::Resource::NoNameThingy with resource_name nil" do before(:context) { class Chef::Resource::NoNameThingy < BaseThingy @@ -128,7 +128,7 @@ describe "Recipe DSL methods" do end end - context "With a resource named AnotherNoNameThingy with resource_name :another_thingy_name" do + context "with a resource named AnotherNoNameThingy with resource_name :another_thingy_name" do before(:context) { class AnotherNoNameThingy < BaseThingy @@ -152,7 +152,7 @@ describe "Recipe DSL methods" do end end - context "With a resource named AnotherNoNameThingy2 with resource_name :another_thingy_name2; resource_name :another_thingy_name3" do + context "with a resource named AnotherNoNameThingy2 with resource_name :another_thingy_name2; resource_name :another_thingy_name3" do before(:context) { class AnotherNoNameThingy2 < BaseThingy @@ -184,7 +184,7 @@ describe "Recipe DSL methods" do end context "provides overriding resource_name" do - context "With a resource named AnotherNoNameThingy3 with provides :another_no_name_thingy3, os: 'blarghle'" do + context "with a resource named AnotherNoNameThingy3 with provides :another_no_name_thingy3, os: 'blarghle'" do before(:context) { class AnotherNoNameThingy3 < BaseThingy @@ -213,7 +213,7 @@ describe "Recipe DSL methods" do end end - context "With a resource named AnotherNoNameThingy4 with two provides" do + context "with a resource named AnotherNoNameThingy4 with two provides" do before(:context) { class AnotherNoNameThingy4 < BaseThingy @@ -253,7 +253,7 @@ describe "Recipe DSL methods" do end end - context "With a resource named AnotherNoNameThingy5, a different resource_name, and a provides with the original resource_name" do + context "with a resource named AnotherNoNameThingy5, a different resource_name, and a provides with the original resource_name" do before(:context) { class AnotherNoNameThingy5 < BaseThingy @@ -290,7 +290,7 @@ describe "Recipe DSL methods" do end end - context "With a resource named AnotherNoNameThingy6, a provides with the original resource name, and a different resource_name" do + context "with a resource named AnotherNoNameThingy6, a provides with the original resource name, and a different resource_name" do before(:context) { class AnotherNoNameThingy6 < BaseThingy @@ -327,7 +327,7 @@ describe "Recipe DSL methods" do end end - context "With a resource named AnotherNoNameThingy7, a new resource_name, and provides with that new resource name" do + context "with a resource named AnotherNoNameThingy7, a new resource_name, and provides with that new resource name" do before(:context) { class AnotherNoNameThingy7 < BaseThingy @@ -365,7 +365,7 @@ describe "Recipe DSL methods" do end # opposite order from the previous test (provides, then resource_name) - context "With a resource named AnotherNoNameThingy8, a provides with a new resource name, and resource_name with that new resource name" do + context "with a resource named AnotherNoNameThingy8, a provides with a new resource name, and resource_name with that new resource name" do before(:context) { class AnotherNoNameThingy8 < BaseThingy @@ -402,118 +402,369 @@ describe "Recipe DSL methods" do end end - context "With a resource TwoClassesOneDsl" do - let(:class_name) { "TwoClassesOneDsl#{Namer.current_index}" } - let(:dsl_method) { :"two_classes_one_dsl#{Namer.current_index}" } - - before { - eval <<-EOM, nil, __FILE__, __LINE__+1 - class #{class_name} < BaseThingy - resource_name #{dsl_method.inspect} + context "with a resource named 'B' with resource name :two_classes_one_dsl" do + let(:two_classes_one_dsl) { :"two_classes_one_dsl#{Namer.current_index}" } + let(:resource_class) { + result = Class.new(BaseThingy) do + def self.name + "B" end - EOM - } - context "and resource BlahModule::TwoClassesOneDsl" do - before { - eval <<-EOM, nil, __FILE__, __LINE__+1 - module BlahModule - class #{class_name} < BaseThingy - resource_name #{dsl_method.inspect} - end - end - EOM - } - it "two_classes_one_dsl resolves to BlahModule::TwoClassesOneDsl (alphabetical)" do - dsl_method = self.dsl_method - recipe = converge { - instance_eval("#{dsl_method} 'blah' do; end") - } - expect(recipe.logged_warnings).to eq '' - expect(BaseThingy.created_resource).to eq eval("BlahModule::#{class_name}") + def self.to_s; name; end + def self.inspect; name.inspect; end end - it "resource_matching_short_name returns BlahModule::TwoClassesOneDsl" do - expect(Chef::Resource.resource_matching_short_name(dsl_method)).to eq eval("BlahModule::#{class_name}") - end - end - context "and resource BlahModule::TwoClassesOneDsl with resource_name nil" do - before { - eval <<-EOM, nil, __FILE__, __LINE__+1 - module BlahModule - class BlahModule::#{class_name} < BaseThingy - resource_name nil - end + result.resource_name two_classes_one_dsl + result + } + before { resource_class } # pull on it so it gets defined before the recipe runs + + context "and another resource named 'A' with resource_name :two_classes_one_dsl" do + let(:resource_class_a) { + result = Class.new(BaseThingy) do + def self.name + "A" end - EOM + def self.to_s; name; end + def self.inspect; name.inspect; end + end + result.resource_name two_classes_one_dsl + result } - it "two_classes_one_dsl resolves to ::TwoClassesOneDsl" do - dsl_method = self.dsl_method + before { resource_class_a } # pull on it so it gets defined before the recipe runs + + it "two_classes_one_dsl resolves to A (alphabetically earliest)" do + two_classes_one_dsl = self.two_classes_one_dsl recipe = converge { - instance_eval("#{dsl_method} 'blah' do; end") + instance_eval("#{two_classes_one_dsl} 'blah'") } expect(recipe.logged_warnings).to eq '' - expect(BaseThingy.created_resource).to eq eval("::#{class_name}") + expect(BaseThingy.created_resource).to eq resource_class_a end - it "resource_matching_short_name returns ::TwoClassesOneDsl" do - expect(Chef::Resource.resource_matching_short_name(dsl_method)).to eq eval("::#{class_name}") + + it "resource_matching_short_name returns B" do + expect(Chef::Resource.resource_matching_short_name(two_classes_one_dsl)).to eq resource_class_a end end - context "and resource BlahModule::TwoClassesOneDsl with resource_name :argh" do - before { - eval <<-EOM, nil, __FILE__, __LINE__+1 - module BlahModule - class BlahModule::#{class_name} < BaseThingy - resource_name :argh - end + + context "and another resource named 'Z' with resource_name :two_classes_one_dsl" do + let(:resource_class_z) { + result = Class.new(BaseThingy) do + def self.name + "Z" end - EOM + def self.to_s; name; end + def self.inspect; name.inspect; end + end + result.resource_name two_classes_one_dsl + result } - it "two_classes_one_dsl resolves to ::TwoClassesOneDsl" do - dsl_method = self.dsl_method + before { resource_class_z } # pull on it so it gets defined before the recipe runs + + it "two_classes_one_dsl resolves to B (alphabetically earliest)" do + two_classes_one_dsl = self.two_classes_one_dsl recipe = converge { - instance_eval("#{dsl_method} 'blah' do; end") + instance_eval("#{two_classes_one_dsl} 'blah'") } expect(recipe.logged_warnings).to eq '' - expect(BaseThingy.created_resource).to eq eval("::#{class_name}") + expect(BaseThingy.created_resource).to eq resource_class end - it "resource_matching_short_name returns ::TwoClassesOneDsl" do - expect(Chef::Resource.resource_matching_short_name(dsl_method)).to eq eval("::#{class_name}") + + it "resource_matching_short_name returns B" do + expect(Chef::Resource.resource_matching_short_name(two_classes_one_dsl)).to eq resource_class end end - context "and resource BlahModule::TwoClassesOneDsl with provides :two_classes_one_dsl, os: 'blarghle'" do - before { - eval <<-EOM, nil, __FILE__, __LINE__+1 - module BlahModule - class BlahModule::#{class_name} < BaseThingy - resource_name #{dsl_method.inspect} - provides #{dsl_method.inspect}, os: 'blarghle' - end + + context "and another resource Blarghle with provides :two_classes_one_dsl, os: 'blarghle'" do + let(:resource_class_blarghle) { + result = Class.new(BaseThingy) do + def self.name + "Blarghle" end - EOM + def self.to_s; name; end + def self.inspect; name.inspect; end + end + result.resource_name two_classes_one_dsl + result.provides two_classes_one_dsl, os: 'blarghle' + result } + before { resource_class_blarghle } # pull on it so it gets defined before the recipe runs - it "and os = blarghle, two_classes_one_dsl resolves to BlahModule::TwoClassesOneDsl" do - dsl_method = self.dsl_method + it "on os = blarghle, two_classes_one_dsl resolves to Blarghle" do + two_classes_one_dsl = self.two_classes_one_dsl recipe = converge { # this is an ugly way to test, make Cheffish expose node attrs run_context.node.automatic[:os] = 'blarghle' - instance_eval("#{dsl_method} 'blah' do; end") + instance_eval("#{two_classes_one_dsl} 'blah' do; end") } expect(recipe.logged_warnings).to eq '' - expect(BaseThingy.created_resource).to eq eval("BlahModule::#{class_name}") + expect(BaseThingy.created_resource).to eq resource_class_blarghle end - it "and os = linux, two_classes_one_dsl resolves to ::TwoClassesOneDsl" do - dsl_method = self.dsl_method + it "on os = linux, two_classes_one_dsl resolves to B" do + two_classes_one_dsl = self.two_classes_one_dsl recipe = converge { # this is an ugly way to test, make Cheffish expose node attrs run_context.node.automatic[:os] = 'linux' - instance_eval("#{dsl_method} 'blah' do; end") + instance_eval("#{two_classes_one_dsl} 'blah' do; end") } expect(recipe.logged_warnings).to eq '' - expect(BaseThingy.created_resource).to eq eval("::#{class_name}") + expect(BaseThingy.created_resource).to eq resource_class + end + end + end + + context "with a resource MyResource" do + let(:resource_class) { Class.new(BaseThingy) do + def self.called_provides + @called_provides + end + def to_s + "MyResource" + end + end } + let(:my_resource) { :"my_resource#{Namer.current_index}" } + let(:blarghle_blarghle_little_star) { :"blarghle_blarghle_little_star#{Namer.current_index}" } + + context "with resource_name :my_resource" do + before { + resource_class.resource_name my_resource + } + + context "with provides? returning true to my_resource" do + before { + my_resource = self.my_resource + resource_class.define_singleton_method(:provides?) do |node, resource_name| + @called_provides = true + resource_name == my_resource + end + } + + it "my_resource returns the resource and calls provides?, but does not emit a warning" do + dsl_name = self.my_resource + recipe = converge { + instance_eval("#{dsl_name} 'foo'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_resource).to eq resource_class + expect(resource_class.called_provides).to be_truthy + end + end + + context "with provides? returning true to blarghle_blarghle_little_star and not resource_name" do + before do + blarghle_blarghle_little_star = self.blarghle_blarghle_little_star + resource_class.define_singleton_method(:provides?) do |node, resource_name| + @called_provides = true + resource_name == blarghle_blarghle_little_star + end + end + + it "my_resource does not return the resource" do + dsl_name = self.my_resource + expect_converge { + instance_eval("#{dsl_name} 'foo'") + }.to raise_error(Chef::Exceptions::NoSuchResourceType) + expect(resource_class.called_provides).to be_truthy + end + + it "blarghle_blarghle_little_star 'foo' returns the resource and emits a warning" do + dsl_name = self.blarghle_blarghle_little_star + recipe = converge { + instance_eval("#{dsl_name} 'foo'") + } + expect(recipe.logged_warnings).to include "WARN: #{resource_class}.provides? returned true when asked if it provides DSL #{dsl_name}, but provides :#{dsl_name} was never called!" + expect(BaseThingy.created_resource).to eq resource_class + expect(resource_class.called_provides).to be_truthy + end + end + + context "and a provider" do + let(:provider_class) do + Class.new(BaseThingy::Provider) do + def self.name + "MyProvider" + end + def self.to_s; name; end + def self.inspect; name.inspect; end + def self.called_provides + @called_provides + end + end + end + + before do + resource_class.send(:define_method, :provider) { nil } + end + + context "that provides :my_resource" do + before do + provider_class.provides my_resource + end + + context "with supports? returning true" do + before do + provider_class.define_singleton_method(:supports?) { |resource,action| true } + end + + it "my_resource runs the provider and does not emit a warning" do + my_resource = self.my_resource + recipe = converge { + instance_eval("#{my_resource} 'foo'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_provider).to eq provider_class + end + + context "and another provider supporting :my_resource with supports? false" do + let(:provider_class2) do + Class.new(BaseThingy::Provider) do + def self.name + "MyProvider2" + end + def self.to_s; name; end + def self.inspect; name.inspect; end + def self.called_provides + @called_provides + end + provides my_resource + def self.supports?(resource, action) + false + end + end + end + + it "my_resource runs the first provider" do + my_resource = self.my_resource + recipe = converge { + instance_eval("#{my_resource} 'foo'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_provider).to eq provider_class + end + end + end + + context "with supports? returning false" do + before do + provider_class.define_singleton_method(:supports?) { |resource,action| false } + end + + # TODO no warning? ick + it "my_resource runs the provider anyway" do + my_resource = self.my_resource + recipe = converge { + instance_eval("#{my_resource} 'foo'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_provider).to eq provider_class + end + + context "and another provider supporting :my_resource with supports? true" do + let(:provider_class2) do + my_resource = self.my_resource + Class.new(BaseThingy::Provider) do + def self.name + "MyProvider2" + end + def self.to_s; name; end + def self.inspect; name.inspect; end + def self.called_provides + @called_provides + end + provides my_resource + def self.supports?(resource, action) + true + end + end + end + before { provider_class2 } # make sure the provider class shows up + + it "my_resource runs the other provider" do + my_resource = self.my_resource + recipe = converge { + instance_eval("#{my_resource} 'foo'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_provider).to eq provider_class2 + end + end + end + end + + context "with provides? returning true" do + before { + my_resource = self.my_resource + provider_class.define_singleton_method(:provides?) do |node, resource| + @called_provides = true + resource.declared_type == my_resource + end + } + + context "that provides :my_resource" do + before { + provider_class.provides my_resource + } + + it "my_resource calls the provider (and calls provides?), but does not emit a warning" do + my_resource = self.my_resource + recipe = converge { + instance_eval("#{my_resource} 'foo'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_provider).to eq provider_class + expect(provider_class.called_provides).to be_truthy + end + end + + context "that does not call provides :my_resource" do + it "my_resource calls the provider (and calls provides?), and emits a warning" do + my_resource = self.my_resource + recipe = converge { + instance_eval("#{my_resource} 'foo'") + } + expect(recipe.logged_warnings).to include("WARN: #{provider_class}.provides? returned true when asked if it provides DSL #{my_resource}, but provides :#{my_resource} was never called!") + expect(BaseThingy.created_provider).to eq provider_class + expect(provider_class.called_provides).to be_truthy + end + end + end + + context "with provides? returning false to my_resource" do + before { + my_resource = self.my_resource + provider_class.define_singleton_method(:provides?) do |node, resource| + @called_provides = true + false + end + } + + context "that provides :my_resource" do + before { + provider_class.provides my_resource + } + + it "my_resource fails to find a provider (and calls provides)" do + my_resource = self.my_resource + expect_converge { + instance_eval("#{my_resource} 'foo'") + }.to raise_error(Chef::Exceptions::ProviderNotFound) + expect(provider_class.called_provides).to be_truthy + end + end + + context "that does not provide :my_resource" do + it "my_resource fails to find a provider (and calls provides)" do + my_resource = self.my_resource + expect_converge { + instance_eval("#{my_resource} 'foo'") + }.to raise_error(Chef::Exceptions::ProviderNotFound) + expect(provider_class.called_provides).to be_truthy + end + end + end end end end + end end @@ -833,7 +1084,7 @@ describe "Recipe DSL methods" do end end - context "With platform-specific resources 'my_super_thingy_foo' and 'my_super_thingy_bar'" do + context "with platform-specific resources 'my_super_thingy_foo' and 'my_super_thingy_bar'" do before(:context) { class MySuperThingyFoo < BaseThingy resource_name :my_super_thingy_foo diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index dcf244c3cc..8e24e03e9f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -87,12 +87,14 @@ Dir["spec/support/**/*.rb"]. OHAI_SYSTEM = Ohai::System.new OHAI_SYSTEM.all_plugins("platform") -TEST_PLATFORM = - (OHAI_SYSTEM['platform'] || - 'unknown_test_platform').dup.freeze -TEST_PLATFORM_VERSION = - (OHAI_SYSTEM['platform_version'] || - 'unknown_platform_version').dup.freeze +test_node = Chef::Node.new +test_node.automatic['os'] = (OHAI_SYSTEM['os'] || 'unknown_os').dup.freeze +test_node.automatic['platform_family'] = (OHAI_SYSTEM['platform_family'] || 'unknown_platform_family').dup.freeze +test_node.automatic['platform'] = (OHAI_SYSTEM['platform'] || 'unknown_platform').dup.freeze +test_node.automatic['platform_version'] = (OHAI_SYSTEM['platform_version'] || 'unknown_platform_version').dup.freeze +TEST_NODE = test_node.freeze +TEST_PLATFORM = TEST_NODE['platform'] +TEST_PLATFORM_VERSION = TEST_NODE['platform_version'] RSpec.configure do |config| config.include(Matchers) @@ -162,13 +164,17 @@ RSpec.configure do |config| config.filter_run_excluding :provider => lambda {|criteria| type, target_provider = criteria.first - platform = TEST_PLATFORM.dup - platform_version = TEST_PLATFORM_VERSION.dup - - begin - provider_for_running_platform = Chef::Platform.find_provider(platform, platform_version, type) - provider_for_running_platform != target_provider - rescue ArgumentError # no provider for platform + node = TEST_NODE.dup + resource_class = Chef::ResourceResolver.resolve(type, node: node) + if resource_class + resource = resource_class.new('test', Chef::RunContext.new(node, nil, nil)) + begin + provider = resource.provider_for_action(Array(resource_class.default_action).first) + provider.class != target_provider + rescue Chef::Exceptions::ProviderNotFound # no provider for platform + true + end + else true end } diff --git a/spec/unit/platform_spec.rb b/spec/unit/platform_spec.rb index 36325d5411..34b46f657f 100644 --- a/spec/unit/platform_spec.rb +++ b/spec/unit/platform_spec.rb @@ -103,7 +103,7 @@ describe Chef::Platform do end it "should raise an exception if a provider cannot be found for a resource type" do - expect { Chef::Platform.find_provider("Darwin", "9.2.2", :coffee) }.to raise_error(ArgumentError) + expect { Chef::Platform.find_provider("Darwin", "9.2.2", :coffee) }.to raise_error(Chef::Exceptions::ProviderNotFound) end it "should look up a provider for a resource with a Chef::Resource object" do diff --git a/spec/unit/provider/dsc_resource_spec.rb b/spec/unit/provider/dsc_resource_spec.rb index 0a6c22bdcf..65c1c019f0 100644 --- a/spec/unit/provider/dsc_resource_spec.rb +++ b/spec/unit/provider/dsc_resource_spec.rb @@ -35,10 +35,10 @@ describe Chef::Provider::DscResource do node } - it 'raises a NoProviderAvailable exception' do + it 'raises a ProviderNotFound exception' do expect(provider).not_to receive(:meta_configuration) expect{provider.run_action(:run)}.to raise_error( - Chef::Exceptions::NoProviderAvailable, /5\.0\.10018\.0/) + Chef::Exceptions::ProviderNotFound, /5\.0\.10018\.0/) end end @@ -56,7 +56,7 @@ describe Chef::Provider::DscResource do expect(provider).to receive(:meta_configuration).and_return( meta_configuration) expect { provider.run_action(:run) }.to raise_error( - Chef::Exceptions::NoProviderAvailable, /Disabled/) + Chef::Exceptions::ProviderNotFound, /Disabled/) end end diff --git a/spec/unit/provider/dsc_script_spec.rb b/spec/unit/provider/dsc_script_spec.rb index d4b2eb3b22..76589e71c1 100644 --- a/spec/unit/provider/dsc_script_spec.rb +++ b/spec/unit/provider/dsc_script_spec.rb @@ -158,14 +158,14 @@ describe Chef::Provider::DscScript do expect { provider.run_action(:run) - }.to raise_error(Chef::Exceptions::NoProviderAvailable) + }.to raise_error(Chef::Exceptions::ProviderNotFound) end end it 'raises an exception if Powershell is not present' do expect { provider.run_action(:run) - }.to raise_error(Chef::Exceptions::NoProviderAvailable) + }.to raise_error(Chef::Exceptions::ProviderNotFound) end end diff --git a/spec/unit/provider_resolver_spec.rb b/spec/unit/provider_resolver_spec.rb index cd3d7713a7..e09b12a20a 100644 --- a/spec/unit/provider_resolver_spec.rb +++ b/spec/unit/provider_resolver_spec.rb @@ -28,30 +28,37 @@ include Chef::Mixin::ConvertToClassName describe Chef::ProviderResolver do + let(:resource_name) { :service } + let(:provider) { nil } + let(:action) { :start } + let(:node) do node = Chef::Node.new - allow(node).to receive(:[]).with(:os).and_return(os) - allow(node).to receive(:[]).with(:platform_family).and_return(platform_family) - allow(node).to receive(:[]).with(:platform).and_return(platform) - allow(node).to receive(:[]).with(:platform_version).and_return(platform_version) - allow(node).to receive(:is_a?).and_return(Chef::Node) + node.automatic[:os] = os + node.automatic[:platform_family] = platform_family + node.automatic[:platform] = platform + node.automatic[:platform_version] = platform_version + node.automatic[:kernel] = { machine: 'i386' } node end + let(:run_context) { Chef::RunContext.new(node, nil, nil) } let(:provider_resolver) { Chef::ProviderResolver.new(node, resource, action) } + let(:resolved_provider) do + begin + resource ? resource.provider_for_action(action).class : nil + rescue Chef::Exceptions::ProviderNotFound + nil + end + end - let(:action) { :start } - - let(:resolved_provider) { provider_resolver.resolve } - - let(:provider) { nil } - - let(:resource_name) { :service } - - let(:resource) { double(Chef::Resource, provider: provider, resource_name: resource_name) } - - before do - allow(resource).to receive(:is_a?).with(Chef::Resource).and_return(true) + let(:resource) do + resource_class = Chef::ResourceResolver.resolve(resource_name, node: node) + if resource_class + resource = resource_class.new('test', run_context) + resource.provider = provider if provider + end + resource end def self.on_platform(platform, *tags, @@ -83,16 +90,40 @@ describe Chef::ProviderResolver do end def self.expect_providers(**providers) - providers.each do |name, provider| + providers.each do |name, expected_provider| describe name.to_s do let(:resource_name) { name } - if provider - it "resolves to a #{provider}" do - expect(resolved_provider).to eql(provider) + + tags = [] + expected_resource = nil + Array(expected_provider).each do |p| + if p.is_a?(Class) && p <= Chef::Provider + expected_provider = p + elsif p.is_a?(Class) && p <= Chef::Resource + expected_resource = p + else + tags << p + end + end + + if expected_resource && expected_provider + it "'#{name}' resolves to resource #{expected_resource} and provider #{expected_provider}", *tags do + expect(resource.class).to eql(expected_resource) + provider = double(expected_provider, class: expected_provider) + expect(provider).to receive(:action=).with(action) + expect(expected_provider).to receive(:new).with(resource, run_context).and_return(provider) + expect(resolved_provider).to eql(expected_provider) + end + elsif expected_provider + it "'#{name}' resolves to provider #{expected_provider}", *tags do + provider = double(expected_provider) + expect(provider).to receive(:action=).with(action) + expect(expected_provider).to receive(:new).with(resource, run_context).and_return(provider) + expect(resolved_provider).to eql(expected_provider) end else - it "Fails to resolve (since #{name.inspect} is unsupported on #{platform} #{platform_version})" do - expect { resolved_provider }.to raise_error /Cannot find a provider/ + it "'#{name}' fails to resolve (since #{name.inspect} is unsupported on #{platform} #{platform_version})", *tags do + expect(resolved_provider).to be_nil end end end @@ -454,42 +485,42 @@ describe Chef::ProviderResolver do PROVIDERS = { - bash: Chef::Provider::Script, - breakpoint: Chef::Provider::Breakpoint, - chef_gem: Chef::Provider::Package::Rubygems, - cookbook_file: Chef::Provider::CookbookFile, - csh: Chef::Provider::Script, - deploy: Chef::Provider::Deploy::Timestamped, - deploy_revision: Chef::Provider::Deploy::Revision, - directory: Chef::Provider::Directory, - easy_install_package: Chef::Provider::Package::EasyInstall, - erl_call: Chef::Provider::ErlCall, - execute: Chef::Provider::Execute, - file: Chef::Provider::File, - gem_package: Chef::Provider::Package::Rubygems, - git: Chef::Provider::Git, - group: Chef::Provider::Group::Gpasswd, - homebrew_package: Chef::Provider::Package::Homebrew, - http_request: Chef::Provider::HttpRequest, - ifconfig: Chef::Provider::Ifconfig, - link: Chef::Provider::Link, - log: Chef::Provider::Log::ChefLog, - macports_package: Chef::Provider::Package::Macports, - mdadm: Chef::Provider::Mdadm, - mount: Chef::Provider::Mount::Mount, - perl: Chef::Provider::Script, - portage_package: Chef::Provider::Package::Portage, - python: Chef::Provider::Script, - remote_directory: Chef::Provider::RemoteDirectory, - route: Chef::Provider::Route, - ruby: Chef::Provider::Script, - ruby_block: Chef::Provider::RubyBlock, - script: Chef::Provider::Script, - subversion: Chef::Provider::Subversion, - template: Chef::Provider::Template, - timestamped_deploy: Chef::Provider::Deploy::Timestamped, - user: Chef::Provider::User::Useradd, - whyrun_safe_ruby_block: Chef::Provider::WhyrunSafeRubyBlock, + bash: [ Chef::Resource::Bash, Chef::Provider::Script ], + breakpoint: [ Chef::Resource::Breakpoint, Chef::Provider::Breakpoint ], + chef_gem: [ Chef::Resource::ChefGem, Chef::Provider::Package::Rubygems ], + cookbook_file: [ Chef::Resource::CookbookFile, Chef::Provider::CookbookFile ], + csh: [ Chef::Resource::Csh, Chef::Provider::Script ], + deploy: [ Chef::Resource::Deploy, Chef::Provider::Deploy::Timestamped ], + deploy_revision: [ Chef::Resource::DeployRevision, Chef::Provider::Deploy::Revision ], + directory: [ Chef::Resource::Directory, Chef::Provider::Directory ], + easy_install_package: [ Chef::Resource::EasyInstallPackage, Chef::Provider::Package::EasyInstall ], + erl_call: [ Chef::Resource::ErlCall, Chef::Provider::ErlCall ], + execute: [ Chef::Resource::Execute, Chef::Provider::Execute ], + file: [ Chef::Resource::File, Chef::Provider::File ], + gem_package: [ Chef::Resource::GemPackage, Chef::Provider::Package::Rubygems ], + git: [ Chef::Resource::Git, Chef::Provider::Git ], + group: [ Chef::Resource::Group, Chef::Provider::Group::Gpasswd ], + homebrew_package: [ Chef::Resource::HomebrewPackage, Chef::Provider::Package::Homebrew ], + http_request: [ Chef::Resource::HttpRequest, Chef::Provider::HttpRequest ], + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ], + link: [ Chef::Resource::Link, Chef::Provider::Link ], + log: [ Chef::Resource::Log, Chef::Provider::Log::ChefLog ], + macports_package: [ Chef::Resource::MacportsPackage, Chef::Provider::Package::Macports ], + mdadm: [ Chef::Resource::Mdadm, Chef::Provider::Mdadm ], + mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Mount ], + perl: [ Chef::Resource::Perl, Chef::Provider::Script ], + portage_package: [ Chef::Resource::PortagePackage, Chef::Provider::Package::Portage ], + python: [ Chef::Resource::Python, Chef::Provider::Script ], + remote_directory: [ Chef::Resource::RemoteDirectory, Chef::Provider::RemoteDirectory ], + route: [ Chef::Resource::Route, Chef::Provider::Route ], + ruby: [ Chef::Resource::Ruby, Chef::Provider::Script ], + ruby_block: [ Chef::Resource::RubyBlock, Chef::Provider::RubyBlock ], + script: [ Chef::Resource::Script, Chef::Provider::Script ], + subversion: [ Chef::Resource::Subversion, Chef::Provider::Subversion ], + template: [ Chef::Resource::Template, Chef::Provider::Template ], + timestamped_deploy: [ Chef::Resource::TimestampedDeploy, Chef::Provider::Deploy::Timestamped ], + user: [ Chef::Resource::User, Chef::Provider::User::Useradd ], + whyrun_safe_ruby_block: [ Chef::Resource::WhyrunSafeRubyBlock, Chef::Provider::WhyrunSafeRubyBlock ], # We want to check that these are unsupported: apt_package: nil, @@ -507,61 +538,62 @@ describe Chef::ProviderResolver do windows_service: nil, "linux" => { - apt_package: Chef::Provider::Package::Apt, - dpkg_package: Chef::Provider::Package::Dpkg, - pacman_package: Chef::Provider::Package::Pacman, - paludis_package: Chef::Provider::Package::Paludis, - rpm_package: Chef::Provider::Package::Rpm, - yum_package: Chef::Provider::Package::Yum, + apt_package: [ Chef::Resource::AptPackage, Chef::Provider::Package::Apt ], + dpkg_package: [ Chef::Resource::DpkgPackage, Chef::Provider::Package::Dpkg ], + pacman_package: [ Chef::Resource::PacmanPackage, Chef::Provider::Package::Pacman ], + paludis_package: [ Chef::Resource::PaludisPackage, Chef::Provider::Package::Paludis ], + rpm_package: [ Chef::Resource::RpmPackage, Chef::Provider::Package::Rpm ], + yum_package: [ Chef::Resource::YumPackage, Chef::Provider::Package::Yum ], "debian" => { - ifconfig: Chef::Provider::Ifconfig::Debian, - package: Chef::Provider::Package::Apt, -# service: Chef::Provider::Service::Debian, + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig::Debian ], + package: [ Chef::Resource::AptPackage, Chef::Provider::Package::Apt ], +# service: [ Chef::Resource::DebianService, Chef::Provider::Service::Debian ], "debian" => { "7.0" => { }, "6.0" => { - ifconfig: Chef::Provider::Ifconfig, -# service: Chef::Provider::Service::Insserv, + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ], +# service: [ Chef::Resource::InsservService, Chef::Provider::Service::Insserv ], }, "5.0" => { - ifconfig: Chef::Provider::Ifconfig, + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ], }, }, "gcel" => { "3.1.4" => { - ifconfig: Chef::Provider::Ifconfig, + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ], }, }, "linaro" => { "3.1.4" => { - ifconfig: Chef::Provider::Ifconfig, + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ], }, }, "linuxmint" => { "3.1.4" => { - ifconfig: Chef::Provider::Ifconfig, -# service: Chef::Provider::Service::Upstart, + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ], +# service: [ Chef::Resource::UpstartService, Chef::Provider::Service::Upstart ], }, }, "raspbian" => { "3.1.4" => { - ifconfig: Chef::Provider::Ifconfig, + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ], }, }, "ubuntu" => { "11.10" => { }, "10.04" => { - ifconfig: Chef::Provider::Ifconfig, + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ], }, }, }, "arch" => { - package: Chef::Provider::Package::Pacman, + # TODO should be Chef::Resource::PacmanPackage + package: [ Chef::Resource::Package, Chef::Provider::Package::Pacman ], "arch" => { "3.1.4" => { @@ -570,8 +602,8 @@ describe Chef::ProviderResolver do }, "freebsd" => { - group: Chef::Provider::Group::Pw, - user: Chef::Provider::User::Pw, + group: [ Chef::Resource::Group, Chef::Provider::Group::Pw ], + user: [ Chef::Resource::User, Chef::Provider::User::Pw ], "freebsd" => { "3.1.4" => { @@ -579,30 +611,31 @@ describe Chef::ProviderResolver do }, }, "suse" => { - group: Chef::Provider::Group::Gpasswd, + group: [ Chef::Resource::Group, Chef::Provider::Group::Gpasswd ], "suse" => { "12.0" => { }, %w(11.1 11.2 11.3) => { - group: Chef::Provider::Group::Suse, + group: [ Chef::Resource::Group, Chef::Provider::Group::Suse ], }, }, "opensuse" => { -# service: Chef::Provider::Service::Redhat, - package: Chef::Provider::Package::Zypper, - group: Chef::Provider::Group::Usermod, +# service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ], + package: [ Chef::Resource::ZypperPackage, Chef::Provider::Package::Zypper ], + group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ], "12.3" => { }, "12.2" => { - group: Chef::Provider::Group::Suse, + group: [ Chef::Resource::Group, Chef::Provider::Group::Suse ], }, }, }, "gentoo" => { - package: Chef::Provider::Package::Portage, - portage_package: Chef::Provider::Package::Portage, -# service: Chef::Provider::Service::Gentoo, + # TODO should be Chef::Resource::PortagePackage + package: [ Chef::Resource::Package, Chef::Provider::Package::Portage ], + portage_package: [ Chef::Resource::PortagePackage, Chef::Provider::Package::Portage ], +# service: [ Chef::Resource::GentooService, Chef::Provider::Service::Gentoo ], "gentoo" => { "3.1.4" => { @@ -611,27 +644,27 @@ describe Chef::ProviderResolver do }, "rhel" => { -# service: Chef::Provider::Service::Systemd, - package: Chef::Provider::Package::Yum, - ifconfig: Chef::Provider::Ifconfig::Redhat, +# service: [ Chef::Resource::SystemdService, Chef::Provider::Service::Systemd ], + package: [ Chef::Resource::YumPackage, Chef::Provider::Package::Yum ], + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig::Redhat ], %w(amazon xcp xenserver ibm_powerkvm cloudlinux parallels) => { "3.1.4" => { -# service: Chef::Provider::Service::Redhat, +# service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ], }, }, %w(redhat centos scientific oracle) => { "7.0" => { }, "6.0" => { -# service: Chef::Provider::Service::Redhat, +# service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ], }, }, "fedora" => { "15.0" => { }, "14.0" => { -# service: Chef::Provider::Service::Redhat, +# service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ], }, }, }, @@ -640,9 +673,9 @@ describe Chef::ProviderResolver do "darwin" => { %w(mac_os_x mac_os_x_server) => { - group: Chef::Provider::Group::Dscl, - package: Chef::Provider::Package::Homebrew, - user: Chef::Provider::User::Dscl, + group: [ Chef::Resource::Group, Chef::Provider::Group::Dscl ], + package: [ Chef::Resource::HomebrewPackage, Chef::Provider::Package::Homebrew ], + user: [ Chef::Resource::User, Chef::Provider::User::Dscl ], "mac_os_x" => { "10.9.2" => { @@ -652,17 +685,17 @@ describe Chef::ProviderResolver do }, "windows" => { - batch: Chef::Provider::Batch, - dsc_script: Chef::Provider::DscScript, - env: Chef::Provider::Env::Windows, - group: Chef::Provider::Group::Windows, - mount: Chef::Provider::Mount::Windows, - package: Chef::Provider::Package::Windows, - powershell_script: Chef::Provider::PowershellScript, - service: Chef::Provider::Service::Windows, - user: Chef::Provider::User::Windows, - windows_package: Chef::Provider::Package::Windows, - windows_service: Chef::Provider::Service::Windows, + batch: [ Chef::Resource::Batch, Chef::Provider::Batch ], + dsc_script: [ Chef::Resource::DscScript, Chef::Provider::DscScript ], + env: [ Chef::Resource::Env, Chef::Provider::Env::Windows ], + group: [ Chef::Resource::Group, Chef::Provider::Group::Windows ], + mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Windows ], + package: [ Chef::Resource::WindowsPackage, Chef::Provider::Package::Windows ], + powershell_script: [ Chef::Resource::PowershellScript, Chef::Provider::PowershellScript ], + service: [ Chef::Resource::WindowsService, Chef::Provider::Service::Windows ], + user: [ Chef::Resource::User, Chef::Provider::User::Windows ], + windows_package: [ Chef::Resource::WindowsPackage, Chef::Provider::Package::Windows ], + windows_service: [ Chef::Resource::WindowsService, Chef::Provider::Service::Windows ], "windows" => { %w(mswin mingw32 windows) => { @@ -673,15 +706,16 @@ describe Chef::ProviderResolver do }, "aix" => { - bff_package: Chef::Provider::Package::Aix, - cron: Chef::Provider::Cron::Aix, - group: Chef::Provider::Group::Aix, - ifconfig: Chef::Provider::Ifconfig::Aix, - mount: Chef::Provider::Mount::Aix, - package: Chef::Provider::Package::Aix, - rpm_package: Chef::Provider::Package::Rpm, - user: Chef::Provider::User::Aix, -# service: Chef::Provider::Service::Aix, + bff_package: [ Chef::Resource::BffPackage, Chef::Provider::Package::Aix ], + cron: [ Chef::Resource::Cron, Chef::Provider::Cron::Aix ], + group: [ Chef::Resource::Group, Chef::Provider::Group::Aix ], + ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig::Aix ], + mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Aix ], + # TODO should be Chef::Resource::BffPackage + package: [ Chef::Resource::Package, Chef::Provider::Package::Aix ], + rpm_package: [ Chef::Resource::RpmPackage, Chef::Provider::Package::Rpm ], + user: [ Chef::Resource::User, Chef::Provider::User::Aix ], +# service: [ Chef::Resource::AixService, Chef::Provider::Service::Aix ], "aix" => { "aix" => { @@ -695,7 +729,7 @@ describe Chef::ProviderResolver do "hpux" => { "hpux" => { "3.1.4" => { - group: Chef::Provider::Group::Usermod + group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ] } } } @@ -705,15 +739,15 @@ describe Chef::ProviderResolver do "netbsd" => { "netbsd" => { "3.1.4" => { - group: Chef::Provider::Group::Groupmod, + group: [ Chef::Resource::Group, Chef::Provider::Group::Groupmod ], }, }, }, }, "openbsd" => { - group: Chef::Provider::Group::Usermod, - package: Chef::Provider::Package::Openbsd, + group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ], + package: [ Chef::Resource::OpenbsdPackage, Chef::Provider::Package::Openbsd ], "openbsd" => { "openbsd" => { @@ -724,15 +758,15 @@ describe Chef::ProviderResolver do }, "solaris2" => { - group: Chef::Provider::Group::Usermod, - ips_package: Chef::Provider::Package::Ips, - package: Chef::Provider::Package::Ips, - mount: Chef::Provider::Mount::Solaris, - solaris_package: Chef::Provider::Package::Solaris, + group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ], + ips_package: [ Chef::Resource::IpsPackage, Chef::Provider::Package::Ips ], + package: [ Chef::Resource::SolarisPackage, Chef::Provider::Package::Solaris ], + mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Solaris ], + solaris_package: [ Chef::Resource::SolarisPackage, Chef::Provider::Package::Solaris ], "smartos" => { - smartos_package: Chef::Provider::Package::SmartOS, - package: Chef::Provider::Package::SmartOS, + smartos_package: [ Chef::Resource::SmartosPackage, Chef::Provider::Package::SmartOS ], + package: [ Chef::Resource::SmartosPackage, Chef::Provider::Package::SmartOS ], "smartos" => { "3.1.4" => { @@ -743,12 +777,11 @@ describe Chef::ProviderResolver do "solaris2" => { "nexentacore" => { "3.1.4" => { - package: Chef::Provider::Package::Solaris, }, }, "omnios" => { "3.1.4" => { - user: Chef::Provider::User::Solaris, + user: [ Chef::Resource::User, Chef::Provider::User::Solaris ], } }, "openindiana" => { @@ -760,11 +793,11 @@ describe Chef::ProviderResolver do }, }, "solaris2" => { - user: Chef::Provider::User::Solaris, + user: [ Chef::Resource::User, Chef::Provider::User::Solaris ], "5.11" => { + package: [ Chef::Resource::IpsPackage, Chef::Provider::Package::Ips ], }, "5.9" => { - package: Chef::Provider::Package::Solaris, }, }, }, @@ -784,7 +817,8 @@ describe Chef::ProviderResolver do "exherbo" => { "exherbo" => { "3.1.4" => { - package: Chef::Provider::Package::Paludis + # TODO should be Chef::Resource::PaludisPackage + package: [ Chef::Resource::Package, Chef::Provider::Package::Paludis ] } } } diff --git a/spec/unit/resource_resolver_spec.rb b/spec/unit/resource_resolver_spec.rb index 09ff026575..b3bda9d945 100644 --- a/spec/unit/resource_resolver_spec.rb +++ b/spec/unit/resource_resolver_spec.rb @@ -31,19 +31,23 @@ describe Chef::ResourceResolver do context 'instance methods' do let(:resolver) do - described_class.new(Chef::Node.new, 'execute[echo]') + described_class.new(Chef::Node.new, 'execute') end it '#resolve' do - expect(resolver.resolve).to be_nil + expect(resolver.resolve).to eq Chef::Resource::Execute end it '#list' do - expect(resolver.list).to be_empty + expect(resolver.list).to eq [ Chef::Resource::Execute ] end - it '#provided_by?' do + it '#provided_by? returns true when resource class is in the list' do expect(resolver.provided_by?(Chef::Resource::Execute)).to be_truthy end + + it '#provided_by? returns false when resource class is not in the list' do + expect(resolver.provided_by?(Chef::Resource::File)).to be_falsey + end end end |