diff options
author | John Keiser <john@johnkeiser.com> | 2015-06-02 10:06:40 -0700 |
---|---|---|
committer | John Keiser <john@johnkeiser.com> | 2015-06-02 10:06:40 -0700 |
commit | d838d8310d30d85e8eab6244f90abbfd59747eca (patch) | |
tree | 98327c777bcdeba2933bbff11e945685840d400e | |
parent | 93f7b74349362d0c698a1080177b94e64248dac6 (diff) | |
parent | 871848fe20769ca8ebf54632f278cc508b5c26aa (diff) | |
download | chef-d838d8310d30d85e8eab6244f90abbfd59747eca.tar.gz |
Merge branch 'jk/one_map_to_rule_them_all'
50 files changed, 951 insertions, 1123 deletions
diff --git a/lib/chef/chef_class.rb b/lib/chef/chef_class.rb index d3f7ee55c7..7c0a2bf944 100644 --- a/lib/chef/chef_class.rb +++ b/lib/chef/chef_class.rb @@ -26,6 +26,9 @@ # injected" into this class by other objects and do not reference the class symbols in those files # directly and we do not need to require those files here. +require 'chef/platform/provider_priority_map' +require 'chef/platform/resource_priority_map' + class Chef class << self @@ -48,7 +51,7 @@ class Chef # @param resource_name [Symbol] name of the resource as a symbol # @return [Array<Class>] Priority Array of Provider Classes to use for the resource_name on the node def get_provider_priority_array(resource_name) - @provider_priority_map.get_priority_array(node, resource_name).dup + provider_priority_map.get_priority_array(node, resource_name).dup end # Get the array of resources associated with a resource_name for the current node @@ -56,27 +59,27 @@ class Chef # @param resource_name [Symbol] name of the resource as a symbol # @return [Array<Class>] Priority Array of Resource Classes to use for the resource_name on the node def get_resource_priority_array(resource_name) - @resource_priority_map.get_priority_array(node, resource_name).dup + resource_priority_map.get_priority_array(node, resource_name).dup end # Set the array of providers associated with a resource_name for the current node # # @param resource_name [Symbol] name of the resource as a symbol - # @param priority_array [Array<Class>] Array of Classes to set as the priority for resource_name on the node + # @param priority_array [Class, Array<Class>] Class or Array of Classes to set as the priority for resource_name on the node # @param filter [Hash] Chef::Nodearray-style filter # @return [Array<Class>] Modified Priority Array of Provider Classes to use for the resource_name on the node - def set_provider_priority_array(resource_name, priority_array, *filter) - @provider_priority_map.set_priority_array(resource_name, priority_array, *filter).dup + def set_provider_priority_array(resource_name, priority_array, *filter, &block) + provider_priority_map.set_priority_array(resource_name, priority_array, *filter, &block).dup end # Get the array of resources associated with a resource_name for the current node # # @param resource_name [Symbol] name of the resource as a symbol - # @param priority_array [Array<Class>] Array of Classes to set as the priority for resource_name on the node + # @param priority_array [Class, Array<Class>] Class or Array of Classes to set as the priority for resource_name on the node # @param filter [Hash] Chef::Nodearray-style filter # @return [Array<Class>] Modified Priority Array of Resource Classes to use for the resource_name on the node - def set_resource_priority_array(resource_name, priority_array, *filter) - @resource_priority_map.set_priority_array(resource_name, priority_array, *filter).dup + def set_resource_priority_array(resource_name, priority_array, *filter, &block) + resource_priority_map.set_priority_array(resource_name, priority_array, *filter, &block).dup end # @@ -126,5 +129,21 @@ class Chef @provider_priority_map = nil @resource_priority_map = nil end + + private + + def provider_priority_map + @provider_priority_map ||= begin + # these slurp in the resource+provider world, so be exceedingly lazy about requiring them + Chef::Platform::ProviderPriorityMap.instance + end + end + def resource_priority_map + @resource_priority_map ||= begin + Chef::Platform::ResourcePriorityMap.instance + end + end end + + reset! end diff --git a/lib/chef/client.rb b/lib/chef/client.rb index 141827e65b..86e92585e3 100644 --- a/lib/chef/client.rb +++ b/lib/chef/client.rb @@ -159,13 +159,6 @@ class Chef if new_runlist = args.delete(:runlist) @json_attribs["run_list"] = new_runlist end - - # these slurp in the resource+provider world, so be exceedingly lazy about requiring them - require 'chef/platform/provider_priority_map' unless defined? Chef::Platform::ProviderPriorityMap - require 'chef/platform/resource_priority_map' unless defined? Chef::Platform::ResourcePriorityMap - - Chef.set_provider_priority_map(Chef::Platform::ProviderPriorityMap.instance) - Chef.set_resource_priority_map(Chef::Platform::ResourcePriorityMap.instance) end # diff --git a/lib/chef/dsl/recipe.rb b/lib/chef/dsl/recipe.rb index 77646376ba..ff398bc9e6 100644 --- a/lib/chef/dsl/recipe.rb +++ b/lib/chef/dsl/recipe.rb @@ -24,6 +24,7 @@ require 'chef/mixin/shell_out' require 'chef/mixin/powershell_out' require 'chef/dsl/resources' require 'chef/dsl/definitions' +require 'chef/resource' class Chef module DSL @@ -36,58 +37,6 @@ class Chef include Chef::Mixin::ShellOut include Chef::Mixin::PowershellOut - # method_missing must live for backcompat purposes until Chef 13. - def method_missing(method_symbol, *args, &block) - # - # If there is already DSL for this, someone must have called - # method_missing manually. Not a fan. Not. A. Fan. - # - if respond_to?(method_symbol) - Chef::Log.deprecation("Calling method_missing(#{method_symbol.inspect}) directly is deprecated in Chef 12 and will be removed in Chef 13.") - Chef::Log.deprecation("Use public_send() or send() instead.") - return send(method_symbol, *args, &block) - end - - # - # If a definition exists, then Chef::DSL::Definitions.add_definition was - # never called. DEPRECATED. - # - if run_context.definitions.has_key?(method_symbol.to_sym) - Chef::Log.deprecation("Definition #{method_symbol} (#{run_context.definitions[method_symbol.to_sym]}) was added to the run_context without calling Chef::DSL::Definitions.add_definition(#{method_symbol.to_sym.inspect}). This will become required in Chef 13.") - Chef::DSL::Definitions.add_definition(method_symbol) - return send(method_symbol, *args, &block) - end - - # - # See if the resource exists anyway. If the user had set - # Chef::Resource::Blah = <resource>, a deprecation warning will be - # emitted and the DSL method 'blah' will be added to the DSL. - # - resource_class = Chef::ResourceResolver.new(run_context ? run_context.node : nil, method_symbol).resolve - if resource_class - # - # If the DSL method was *not* added, this is the case where the - # matching class implements 'provides?' and matches resources that it - # never declared "provides" for (which means we would never have - # created DSL). Anything where we don't create DSL is deprecated. - # - if !respond_to?(method_symbol) - Chef::Log.deprecation("#{resource_class} is marked as providing DSL #{method_symbol}, but provides #{method_symbol.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.") - Chef::DSL::Resources.add_resource_dsl(method_symbol) - end - return send(method_symbol, *args, &block) - end - - begin - super - rescue NoMethodError - raise NoMethodError, "No resource or method named `#{method_symbol}' for #{describe_self_for_error}" - rescue NameError - raise NameError, "No resource, method, or local variable named `#{method_symbol}' for #{describe_self_for_error}" - end - end - include Chef::DSL::Resources include Chef::DSL::Definitions @@ -185,14 +134,52 @@ class Chef raise Chef::Exceptions::ResourceNotFound, "exec was called, but you probably meant to use an execute resource. If not, please call Kernel#exec explicitly. The exec block called was \"#{args}\"" end + # DEPRECATED: + # method_missing must live for backcompat purposes until Chef 13. + def method_missing(method_symbol, *args, &block) + # + # If there is already DSL for this, someone must have called + # method_missing manually. Not a fan. Not. A. Fan. + # + if respond_to?(method_symbol) + Chef::Log.deprecation("Calling method_missing(#{method_symbol.inspect}) directly is deprecated in Chef 12 and will be removed in Chef 13.") + Chef::Log.deprecation("Use public_send() or send() instead.") + return send(method_symbol, *args, &block) + end + + # + # If a definition exists, then Chef::DSL::Definitions.add_definition was + # never called. DEPRECATED. + # + if run_context.definitions.has_key?(method_symbol.to_sym) + Chef::Log.deprecation("Definition #{method_symbol} (#{run_context.definitions[method_symbol.to_sym]}) was added to the run_context without calling Chef::DSL::Definitions.add_definition(#{method_symbol.to_sym.inspect}). This will become required in Chef 13.") + Chef::DSL::Definitions.add_definition(method_symbol) + return send(method_symbol, *args, &block) + end + + # + # See if the resource exists anyway. If the user had set + # Chef::Resource::Blah = <resource>, a deprecation warning will be + # emitted and the DSL method 'blah' will be added to the DSL. + # + resource_class = Chef::ResourceResolver.new(run_context ? run_context.node : nil, method_symbol).resolve + if resource_class + Chef::DSL::Resources.add_resource_dsl(method_symbol) + return send(method_symbol, *args, &block) + end + + begin + super + rescue NoMethodError + raise NoMethodError, "No resource or method named `#{method_symbol}' for #{describe_self_for_error}" + rescue NameError + raise NameError, "No resource, method, or local variable named `#{method_symbol}' for #{describe_self_for_error}" + end + end end end end -# We require this at the BOTTOM of this file to avoid circular requires (it is used -# at runtime but not load time) -require 'chef/resource' - # **DEPRECATED** # This used to be part of chef/mixin/recipe_definition_dsl_core. Load the file to activate the deprecation code. require 'chef/mixin/recipe_definition_dsl_core' diff --git a/lib/chef/mixin/provides.rb b/lib/chef/mixin/provides.rb index c39c53a190..095e273dab 100644 --- a/lib/chef/mixin/provides.rb +++ b/lib/chef/mixin/provides.rb @@ -4,30 +4,17 @@ require 'chef/mixin/descendants_tracker' class Chef module Mixin module Provides + # TODO no longer needed, remove or deprecate? include Chef::Mixin::DescendantsTracker - def node_map - @node_map ||= Chef::NodeMap.new - end - def provides(short_name, opts={}, &block) - if !short_name.kind_of?(Symbol) - # YAGNI: this is probably completely unnecessary and can be removed? - Chef::Log.deprecation "Passing a non-Symbol to Chef::Resource#provides will be removed" - if short_name.kind_of?(String) - short_name.downcase! - short_name.gsub!(/\s/, "_") - end - short_name = short_name.to_sym - end - node_map.set(short_name, true, opts, &block) + raise NotImplementedError, :provides end # Check whether this resource provides the resource_name DSL for the given - # node - def provides?(node, resource_name) - resource_name = resource_name.resource_name if resource_name.is_a?(Chef::Resource) - node_map.get(node, resource_name) + # node. TODO remove this when we stop checking unregistered things. + def provides?(node, resource) + raise NotImplementedError, :provides? end # Get the list of recipe DSL this resource is responsible for on the given diff --git a/lib/chef/node_map.rb b/lib/chef/node_map.rb index 2ca6d9ba17..34f19d18b4 100644 --- a/lib/chef/node_map.rb +++ b/lib/chef/node_map.rb @@ -19,19 +19,6 @@ class Chef class NodeMap - VALID_OPTS = [ - :on_platform, - :on_platforms, - :platform, - :os, - :platform_family, - ] - - DEPRECATED_OPTS = [ - :on_platform, - :on_platforms, - ] - # Create a new NodeMap # def initialize @@ -47,14 +34,29 @@ class Chef # @yield [node] Arbitrary node filter as a block which takes a node argument # @return [NodeMap] Returns self for possible chaining # - def set(key, value, filters = {}, &block) - validate_filter!(filters) - deprecate_filter!(filters) + def set(key, value, platform: nil, platform_version: nil, platform_family: nil, os: nil, on_platform: nil, on_platforms: nil, &block) + Chef::Log.deprecation "The on_platform option to node_map has been deprecated" if on_platform + Chef::Log.deprecation "The on_platforms option to node_map has been deprecated" if on_platforms + platform ||= on_platform || on_platforms + filters = { platform: platform, platform_version: platform_version, platform_family: platform_family, os: os } + new_matcher = { filters: filters, block: block, value: value } @map[key] ||= [] - # we match on the first value we find, so we want to unshift so that the - # last setter wins - # FIXME: need a test for this behavior - @map[key].unshift({ filters: filters, block: block, value: value }) + # Decide where to insert the matcher; the new value is preferred over + # anything more specific (see `priority_of`) and is preferred over older + # values of the same specificity. (So all other things being equal, + # newest wins.) + insert_at = nil + @map[key].each_with_index do |matcher, index| + if specificity(new_matcher) >= specificity(matcher) + insert_at = index + break + end + end + if insert_at + @map[key].insert(insert_at, new_matcher) + else + @map[key] << new_matcher + end self end @@ -68,74 +70,90 @@ class Chef def get(node, key) # FIXME: real exception raise "first argument must be a Chef::Node" unless node.is_a?(Chef::Node) - return nil unless @map.has_key?(key) - @map[key].each do |matcher| - if filters_match?(node, matcher[:filters]) && - block_matches?(node, matcher[:block]) - return matcher[:value] - end - end - nil + list(node, key).first + end + + # List all matches for the given node and key from the NodeMap, from + # most-recently added to oldest. + # + # @param node [Chef::Node] The Chef::Node object for the run + # @param key [Object] Key to look up + # @return [Object] Value + # + def list(node, key) + # FIXME: real exception + raise "first argument must be a Chef::Node" unless node.is_a?(Chef::Node) + return [] unless @map.has_key?(key) + @map[key].select do |matcher| + filters_match?(node, matcher[:filters]) && block_matches?(node, matcher[:block]) + end.map { |matcher| matcher[:value] } end private - # only allow valid filter options - def validate_filter!(filters) - filters.each_key do |key| - # FIXME: real exception - raise "Bad key #{key} in Chef::NodeMap filter expression" unless VALID_OPTS.include?(key) + # + # Gives a value for "how specific" the matcher is. + # Things which specify more specific filters get a higher number + # (platform_version > platform > platform_family > os); things + # with a block have higher specificity than similar things without + # a block. + # + def specificity(matcher) + if matcher[:filters][:platform_version] + specificity = 8 + elsif matcher[:filters][:platform] + specificity = 6 + elsif matcher[:filters][:platform_family] + specificity = 4 + elsif matcher[:filters][:os] + specificity = 2 + else + specificity = 0 end + specificity += 1 if matcher[:block] + specificity end - # warn on deprecated filter options - def deprecate_filter!(filters) - filters.each_key do |key| - Chef::Log.warn "The #{key} option to node_map has been deprecated" if DEPRECATED_OPTS.include?(key) - end - end + # + # Succeeds if: + # - no negative matches (!value) + # - at least one positive match (value or :all), or no positive filters + # + def matches_black_white_list?(node, filters, attribute) + # It's super common for the filter to be nil. Catch that so we don't + # spend any time here. + return true if !filters[attribute] + filter_values = Array(filters[attribute]) + value = node[attribute] - # @todo: this works fine, but is probably hard to understand - def negative_match(filter, param) - # We support strings prefaced by '!' to mean 'not'. In particular, this is most useful - # for os matching on '!windows'. - negative_matches = filter.select { |f| f[0] == '!' } - return true if !negative_matches.empty? && negative_matches.include?('!' + param) + # Split the blacklist and whitelist + blacklist, whitelist = filter_values.partition { |v| v.is_a?(String) && v.start_with?('!') } - # We support the symbol :all to match everything, for backcompat, but this can and should - # simply be ommitted. - positive_matches = filter.reject { |f| f[0] == '!' || f == :all } - return true if !positive_matches.empty? && !positive_matches.include?(param) + # If any blacklist value matches, we don't match + return false if blacklist.any? { |v| v[1..-1] == value } - # sorry double-negative: this means we pass this filter. - false + # If the whitelist is empty, or anything matches, we match. + whitelist.empty? || whitelist.any? { |v| v == :all || v == value } end - def filters_match?(node, filters) - return true if filters.empty? + def matches_version_list?(node, filters, attribute) + # It's super common for the filter to be nil. Catch that so we don't + # spend any time here. + return true if !filters[attribute] + filter_values = Array(filters[attribute]) + value = node[attribute] - # each filter is applied in turn. if any fail, then it shortcuts and returns false. - # if it passes or does not exist it succeeds and continues on. so multiple filters are - # effectively joined by 'and'. all filters can be single strings, or arrays which are - # effectively joined by 'or'. - - os_filter = [ filters[:os] ].flatten.compact - unless os_filter.empty? - return false if negative_match(os_filter, node[:os]) - end - - platform_family_filter = [ filters[:platform_family] ].flatten.compact - unless platform_family_filter.empty? - return false if negative_match(platform_family_filter, node[:platform_family]) - end - - # :on_platform and :on_platforms here are synonyms which are deprecated - platform_filter = [ filters[:platform] || filters[:on_platform] || filters[:on_platforms] ].flatten.compact - unless platform_filter.empty? - return false if negative_match(platform_filter, node[:platform]) + filter_values.empty? || + Array(filter_values).any? do |v| + Chef::VersionConstraint::Platform.new(v).include?(value) end + end - return true + def filters_match?(node, filters) + matches_black_white_list?(node, filters, :os) && + matches_black_white_list?(node, filters, :platform_family) && + matches_black_white_list?(node, filters, :platform) && + matches_version_list?(node, filters, :platform_version) end def block_matches?(node, block) diff --git a/lib/chef/platform/provider_mapping.rb b/lib/chef/platform/provider_mapping.rb index 00458b6485..0440ff8601 100644 --- a/lib/chef/platform/provider_mapping.rb +++ b/lib/chef/platform/provider_mapping.rb @@ -20,13 +20,8 @@ require 'chef/log' require 'chef/exceptions' require 'chef/mixin/params_validate' require 'chef/version_constraint/platform' - -# This file depends on nearly every provider in chef, but requiring them -# directly causes circular requires resulting in uninitialized constant errors. -# Therefore, we do the includes inline rather than up top. require 'chef/provider' - class Chef class Platform @@ -34,267 +29,7 @@ class Chef attr_writer :platforms def platforms - @platforms ||= begin - require 'chef/providers' - - { - :freebsd => { - :default => { - :group => Chef::Provider::Group::Pw, - :user => Chef::Provider::User::Pw, - } - }, - :ubuntu => { - :default => { - :package => Chef::Provider::Package::Apt, - :service => Chef::Provider::Service::Debian, - }, - ">= 11.10" => { - :ifconfig => Chef::Provider::Ifconfig::Debian - } - # Chef::Provider::Service::Upstart is a candidate to be used in - # ubuntu versions >= 13.10 but it currently requires all the - # services to have an entry under /etc/init. We need to update it - # to use the service ctl apis in order to migrate to using it on - # ubuntu >= 13.10. - }, - :gcel => { - :default => { - :package => Chef::Provider::Package::Apt, - :service => Chef::Provider::Service::Debian, - } - }, - :linaro => { - :default => { - :package => Chef::Provider::Package::Apt, - :service => Chef::Provider::Service::Debian, - } - }, - :raspbian => { - :default => { - :package => Chef::Provider::Package::Apt, - :service => Chef::Provider::Service::Debian, - } - }, - :linuxmint => { - :default => { - :package => Chef::Provider::Package::Apt, - :service => Chef::Provider::Service::Upstart, - } - }, - :debian => { - :default => { - :package => Chef::Provider::Package::Apt, - :service => Chef::Provider::Service::Debian, - }, - ">= 6.0" => { - :service => Chef::Provider::Service::Insserv - }, - ">= 7.0" => { - :ifconfig => Chef::Provider::Ifconfig::Debian - } - }, - :xenserver => { - :default => { - :service => Chef::Provider::Service::Redhat, - :package => Chef::Provider::Package::Yum, - } - }, - :xcp => { - :default => { - :service => Chef::Provider::Service::Redhat, - :package => Chef::Provider::Package::Yum, - } - }, - :centos => { - :default => { - :service => Chef::Provider::Service::Systemd, - :package => Chef::Provider::Package::Yum, - :ifconfig => Chef::Provider::Ifconfig::Redhat - }, - "< 7" => { - :service => Chef::Provider::Service::Redhat - } - }, - :amazon => { - :default => { - :service => Chef::Provider::Service::Redhat, - :package => Chef::Provider::Package::Yum, - } - }, - :scientific => { - :default => { - :service => Chef::Provider::Service::Systemd, - :package => Chef::Provider::Package::Yum, - }, - "< 7" => { - :service => Chef::Provider::Service::Redhat - } - }, - :fedora => { - :default => { - :service => Chef::Provider::Service::Systemd, - :package => Chef::Provider::Package::Yum, - :ifconfig => Chef::Provider::Ifconfig::Redhat - }, - "< 15" => { - :service => Chef::Provider::Service::Redhat - } - }, - :opensuse => { - :default => { - :service => Chef::Provider::Service::Redhat, - :package => Chef::Provider::Package::Zypper, - :group => Chef::Provider::Group::Suse - }, - # Only OpenSuSE 12.3+ should use the Usermod group provider: - ">= 12.3" => { - :group => Chef::Provider::Group::Usermod - } - }, - :suse => { - :default => { - :service => Chef::Provider::Service::Systemd, - :package => Chef::Provider::Package::Zypper, - :group => Chef::Provider::Group::Gpasswd - }, - "< 12.0" => { - :group => Chef::Provider::Group::Suse, - :service => Chef::Provider::Service::Redhat - } - }, - :oracle => { - :default => { - :service => Chef::Provider::Service::Systemd, - :package => Chef::Provider::Package::Yum, - }, - "< 7" => { - :service => Chef::Provider::Service::Redhat - } - }, - :redhat => { - :default => { - :service => Chef::Provider::Service::Systemd, - :package => Chef::Provider::Package::Yum, - :ifconfig => Chef::Provider::Ifconfig::Redhat - }, - "< 7" => { - :service => Chef::Provider::Service::Redhat - } - }, - :ibm_powerkvm => { - :default => { - :service => Chef::Provider::Service::Redhat, - :package => Chef::Provider::Package::Yum, - :ifconfig => Chef::Provider::Ifconfig::Redhat - } - }, - :cloudlinux => { - :default => { - :service => Chef::Provider::Service::Redhat, - :package => Chef::Provider::Package::Yum, - :ifconfig => Chef::Provider::Ifconfig::Redhat - } - }, - :parallels => { - :default => { - :service => Chef::Provider::Service::Redhat, - :package => Chef::Provider::Package::Yum, - :ifconfig => Chef::Provider::Ifconfig::Redhat - } - }, - :gentoo => { - :default => { - :package => Chef::Provider::Package::Portage, - :service => Chef::Provider::Service::Gentoo, - } - }, - :arch => { - :default => { - :package => Chef::Provider::Package::Pacman, - :service => Chef::Provider::Service::Systemd, - } - }, - :solaris => {}, - :openindiana => { - :default => { - :mount => Chef::Provider::Mount::Solaris, - :package => Chef::Provider::Package::Ips, - :group => Chef::Provider::Group::Usermod - } - }, - :opensolaris => { - :default => { - :mount => Chef::Provider::Mount::Solaris, - :package => Chef::Provider::Package::Ips, - :group => Chef::Provider::Group::Usermod - } - }, - :nexentacore => { - :default => { - :mount => Chef::Provider::Mount::Solaris, - :package => Chef::Provider::Package::Solaris, - :group => Chef::Provider::Group::Usermod - } - }, - :omnios => { - :default => { - :mount => Chef::Provider::Mount::Solaris, - :package => Chef::Provider::Package::Ips, - :group => Chef::Provider::Group::Usermod, - :user => Chef::Provider::User::Solaris, - } - }, - :solaris2 => { - :default => { - :mount => Chef::Provider::Mount::Solaris, - :package => Chef::Provider::Package::Ips, - :group => Chef::Provider::Group::Usermod, - :user => Chef::Provider::User::Solaris, - }, - "< 5.11" => { - :mount => Chef::Provider::Mount::Solaris, - :package => Chef::Provider::Package::Solaris, - :group => Chef::Provider::Group::Usermod, - :user => Chef::Provider::User::Solaris, - } - }, - :smartos => { - :default => { - :mount => Chef::Provider::Mount::Solaris, - :package => Chef::Provider::Package::SmartOS, - :group => Chef::Provider::Group::Usermod - } - }, - :hpux => { - :default => { - :group => Chef::Provider::Group::Usermod - } - }, - :aix => { - :default => { - :group => Chef::Provider::Group::Aix, - :mount => Chef::Provider::Mount::Aix, - :ifconfig => Chef::Provider::Ifconfig::Aix, - :package => Chef::Provider::Package::Aix, - :user => Chef::Provider::User::Aix, - :service => Chef::Provider::Service::Aix - } - }, - :exherbo => { - :default => { - :package => Chef::Provider::Package::Paludis, - :service => Chef::Provider::Service::Systemd, - } - }, - :default => { - :mount => Chef::Provider::Mount::Mount, - :user => Chef::Provider::User::Useradd, - :group => Chef::Provider::Group::Gpasswd, - :ifconfig => Chef::Provider::Ifconfig, - } - } - end + @platforms ||= { default: {} } end include Chef::Mixin::ParamsValidate @@ -304,7 +39,7 @@ class Chef name_sym = name if name.kind_of?(String) - name.downcase! + name = name.downcase name.gsub!(/\s/, "_") name_sym = name.to_sym end diff --git a/lib/chef/platform/provider_priority_map.rb b/lib/chef/platform/provider_priority_map.rb index 1539f61900..9d703c9178 100644 --- a/lib/chef/platform/provider_priority_map.rb +++ b/lib/chef/platform/provider_priority_map.rb @@ -1,88 +1,25 @@ +require 'singleton' class Chef class Platform class ProviderPriorityMap include Singleton - def initialize - load_default_map - end - def get_priority_array(node, resource_name) priority_map.get(node, resource_name.to_sym) end - def set_priority_array(resource_name, priority_array, *filter) - priority(resource_name.to_sym, priority_array.to_a, *filter) + def set_priority_array(resource_name, priority_array, *filter, &block) + priority_map.set(resource_name.to_sym, Array(priority_array), *filter, &block) end - def priority(*args) - priority_map.set(*args) + # @api private + def list_handlers(node, resource_name) + priority_map.list(node, resource_name.to_sym).flatten(1).uniq end private - def load_default_map - require 'chef/providers' - - # - # Linux - # - - # default block for linux O/Sen must come before platform_family exceptions - priority :service, [ - Chef::Provider::Service::Systemd, - Chef::Provider::Service::Insserv, - Chef::Provider::Service::Redhat, - ], os: "linux" - - priority :service, [ - Chef::Provider::Service::Systemd, - Chef::Provider::Service::Arch, - ], platform_family: "arch" - - priority :service, [ - Chef::Provider::Service::Systemd, - Chef::Provider::Service::Gentoo, - ], platform_family: "gentoo" - - priority :service, [ - # we can determine what systemd supports accurately - Chef::Provider::Service::Systemd, - # on debian-ish system if an upstart script exists that must win over sysv types - Chef::Provider::Service::Upstart, - Chef::Provider::Service::Insserv, - Chef::Provider::Service::Debian, - Chef::Provider::Service::Invokercd, - ], platform_family: "debian" - - priority :service, [ - Chef::Provider::Service::Systemd, - Chef::Provider::Service::Insserv, - Chef::Provider::Service::Redhat, - ], platform_family: [ "rhel", "fedora", "suse" ] - - # - # BSDen - # - - priority :service, Chef::Provider::Service::Freebsd, os: [ "freebsd", "netbsd" ] - priority :service, Chef::Provider::Service::Openbsd, os: [ "openbsd" ] - - # - # Solaris-en - # - - priority :service, Chef::Provider::Service::Solaris, os: "solaris2" - - # - # Mac - # - - priority :service, Chef::Provider::Service::Macosx, os: "darwin" - priority :package, Chef::Provider::Package::Homebrew, os: "darwin" - end - def priority_map require 'chef/node_map' @priority_map ||= Chef::NodeMap.new diff --git a/lib/chef/platform/resource_priority_map.rb b/lib/chef/platform/resource_priority_map.rb index fc43b3e7db..e98fc12413 100644 --- a/lib/chef/platform/resource_priority_map.rb +++ b/lib/chef/platform/resource_priority_map.rb @@ -1,33 +1,25 @@ +require 'singleton' + class Chef class Platform class ResourcePriorityMap include Singleton - def initialize - load_default_map - end - def get_priority_array(node, resource_name) priority_map.get(node, resource_name.to_sym) end - def set_priority_array(resource_name, priority_array, *filter) - priority resource_name.to_sym, priority_array.to_a, *filter + def set_priority_array(resource_name, priority_array, *filter, &block) + priority_map.set(resource_name.to_sym, Array(priority_array), *filter, &block) end - def priority(*args) - priority_map.set(*args) + # @api private + def list_handlers(*args) + priority_map.list(*args).flatten(1).uniq end private - def load_default_map - require 'chef/resources' - - # MacOSX - priority :package, Chef::Resource::HomebrewPackage, os: "darwin" - end - def priority_map require 'chef/node_map' @priority_map ||= Chef::NodeMap.new diff --git a/lib/chef/provider.rb b/lib/chef/provider.rb index 42347a230e..e50e374804 100644 --- a/lib/chef/provider.rb +++ b/lib/chef/provider.rb @@ -29,6 +29,9 @@ require 'chef/node_map' class Chef class Provider + require 'chef/mixin/why_run' + require 'chef/mixin/shell_out' + require 'chef/mixin/provides' include Chef::Mixin::WhyRun include Chef::Mixin::ShellOut include Chef::Mixin::PowershellOut @@ -172,6 +175,14 @@ class Chef converge_actions.add_action(descriptions, &block) end + def self.provides(short_name, opts={}, &block) + Chef.set_provider_priority_array(short_name, self, opts, &block) + end + + def self.provides?(node, resource) + Chef::ProviderResolver.new(node, resource, :nothing).provided_by?(self) + end + protected def converge_actions @@ -228,3 +239,9 @@ class Chef extend DeprecatedLWRPClass end end + +# Requiring things at the bottom breaks cycles +require 'chef/chef_class' +require 'chef/mixin/why_run' +require 'chef/resource_collection' +require 'chef/runner' diff --git a/lib/chef/provider/file.rb b/lib/chef/provider/file.rb index 4ce2c040a4..5ed7c6ac5b 100644 --- a/lib/chef/provider/file.rb +++ b/lib/chef/provider/file.rb @@ -26,6 +26,7 @@ require 'fileutils' require 'chef/scan_access_control' require 'chef/mixin/checksum' require 'chef/mixin/file_class' +require 'chef/mixin/enforce_ownership_and_permissions' require 'chef/util/backup' require 'chef/util/diff' require 'chef/util/selinux' diff --git a/lib/chef/provider/group/aix.rb b/lib/chef/provider/group/aix.rb index 6ac9d03357..92bb8cb225 100644 --- a/lib/chef/provider/group/aix.rb +++ b/lib/chef/provider/group/aix.rb @@ -23,6 +23,7 @@ class Chef class Provider class Group class Aix < Chef::Provider::Group::Groupadd + provides :group, platform: 'aix' def required_binaries [ "/usr/bin/mkgroup", diff --git a/lib/chef/provider/group/dscl.rb b/lib/chef/provider/group/dscl.rb index d7e8f2e827..9775ac8270 100644 --- a/lib/chef/provider/group/dscl.rb +++ b/lib/chef/provider/group/dscl.rb @@ -21,7 +21,7 @@ class Chef class Group class Dscl < Chef::Provider::Group - provides :group, os: "darwin" + provides :group, os: 'darwin' def dscl(*args) host = "." diff --git a/lib/chef/provider/group/gpasswd.rb b/lib/chef/provider/group/gpasswd.rb index 521affac11..432c524acd 100644 --- a/lib/chef/provider/group/gpasswd.rb +++ b/lib/chef/provider/group/gpasswd.rb @@ -22,6 +22,7 @@ class Chef class Provider class Group class Gpasswd < Chef::Provider::Group::Groupadd + provides :group def load_current_resource super diff --git a/lib/chef/provider/group/groupmod.rb b/lib/chef/provider/group/groupmod.rb index f9299546c8..82b68b8672 100644 --- a/lib/chef/provider/group/groupmod.rb +++ b/lib/chef/provider/group/groupmod.rb @@ -21,7 +21,7 @@ class Chef class Group class Groupmod < Chef::Provider::Group - provides :group, os: "netbsd" + provides :group, os: 'netbsd' def load_current_resource super diff --git a/lib/chef/provider/group/pw.rb b/lib/chef/provider/group/pw.rb index 7a66ab4d69..f877ed2424 100644 --- a/lib/chef/provider/group/pw.rb +++ b/lib/chef/provider/group/pw.rb @@ -20,6 +20,7 @@ class Chef class Provider class Group class Pw < Chef::Provider::Group + provides :group, platform: 'freebsd' def load_current_resource super diff --git a/lib/chef/provider/group/suse.rb b/lib/chef/provider/group/suse.rb index 7ac2831d02..b47ea33e80 100644 --- a/lib/chef/provider/group/suse.rb +++ b/lib/chef/provider/group/suse.rb @@ -22,6 +22,8 @@ class Chef class Provider class Group class Suse < Chef::Provider::Group::Groupadd + provides :group, platform: 'opensuse', platform_version: '< 12.3' + provides :group, platform: 'suse', platform_version: '< 12.0' def load_current_resource super diff --git a/lib/chef/provider/group/usermod.rb b/lib/chef/provider/group/usermod.rb index e50e13c443..d78d42d6e1 100644 --- a/lib/chef/provider/group/usermod.rb +++ b/lib/chef/provider/group/usermod.rb @@ -23,7 +23,8 @@ class Chef class Group class Usermod < Chef::Provider::Group::Groupadd - provides :group, os: "openbsd" + provides :group, os: %w(openbsd solaris2 hpux) + provides :group, platform: "opensuse" def load_current_resource super diff --git a/lib/chef/provider/group/windows.rb b/lib/chef/provider/group/windows.rb index 54e49b0e06..46d8afc7f6 100644 --- a/lib/chef/provider/group/windows.rb +++ b/lib/chef/provider/group/windows.rb @@ -26,7 +26,7 @@ class Chef class Group class Windows < Chef::Provider::Group - provides :group, os: "windows" + provides :group, os: 'windows' def initialize(new_resource,run_context) super diff --git a/lib/chef/provider/ifconfig.rb b/lib/chef/provider/ifconfig.rb index 06080c90c3..468e1ec639 100644 --- a/lib/chef/provider/ifconfig.rb +++ b/lib/chef/provider/ifconfig.rb @@ -39,6 +39,8 @@ require 'erb' class Chef class Provider class Ifconfig < Chef::Provider + provides :ifconfig + include Chef::Mixin::ShellOut include Chef::Mixin::Command diff --git a/lib/chef/provider/ifconfig/aix.rb b/lib/chef/provider/ifconfig/aix.rb index 8fead44bc6..25c3de3040 100644 --- a/lib/chef/provider/ifconfig/aix.rb +++ b/lib/chef/provider/ifconfig/aix.rb @@ -22,6 +22,7 @@ class Chef class Provider class Ifconfig class Aix < Chef::Provider::Ifconfig + provides :ifconfig, platform: %w(aix) def load_current_resource @current_resource = Chef::Resource::Ifconfig.new(@new_resource.name) diff --git a/lib/chef/provider/ifconfig/debian.rb b/lib/chef/provider/ifconfig/debian.rb index 7589971143..1e6863c8b5 100644 --- a/lib/chef/provider/ifconfig/debian.rb +++ b/lib/chef/provider/ifconfig/debian.rb @@ -23,6 +23,8 @@ class Chef class Provider class Ifconfig class Debian < Chef::Provider::Ifconfig + provides :ifconfig, platform: %w(ubuntu), platform_version: '>= 11.10' + provides :ifconfig, platform: %w(debian), platform_version: '>= 7.0' INTERFACES_FILE = "/etc/network/interfaces" INTERFACES_DOT_D_DIR = "/etc/network/interfaces.d" diff --git a/lib/chef/provider/ifconfig/redhat.rb b/lib/chef/provider/ifconfig/redhat.rb index ef35b0e012..ee053d1e52 100644 --- a/lib/chef/provider/ifconfig/redhat.rb +++ b/lib/chef/provider/ifconfig/redhat.rb @@ -22,6 +22,7 @@ class Chef class Provider class Ifconfig class Redhat < Chef::Provider::Ifconfig + provides :ifconfig, platform_family: %w(fedora rhel) def initialize(new_resource, run_context) super(new_resource, run_context) diff --git a/lib/chef/provider/mount.rb b/lib/chef/provider/mount.rb index 1631d87033..2039e9ae51 100644 --- a/lib/chef/provider/mount.rb +++ b/lib/chef/provider/mount.rb @@ -24,7 +24,6 @@ require 'chef/provider' class Chef class Provider class Mount < Chef::Provider - include Chef::Mixin::ShellOut attr_accessor :unmount_retries diff --git a/lib/chef/provider/mount/aix.rb b/lib/chef/provider/mount/aix.rb index 0d7e11a1b8..4ad7b24c15 100644 --- a/lib/chef/provider/mount/aix.rb +++ b/lib/chef/provider/mount/aix.rb @@ -22,6 +22,7 @@ class Chef class Provider class Mount class Aix < Chef::Provider::Mount::Mount + provides :mount, platform: %w(aix) # Override for aix specific handling def initialize(new_resource, run_context) diff --git a/lib/chef/provider/mount/mount.rb b/lib/chef/provider/mount/mount.rb index 0a6e269d2d..ef074166a9 100644 --- a/lib/chef/provider/mount/mount.rb +++ b/lib/chef/provider/mount/mount.rb @@ -24,6 +24,8 @@ class Chef class Mount class Mount < Chef::Provider::Mount + provides :mount + def initialize(new_resource, run_context) super @real_device = nil diff --git a/lib/chef/provider/mount/solaris.rb b/lib/chef/provider/mount/solaris.rb index d8cec24138..deb04d4d7b 100644 --- a/lib/chef/provider/mount/solaris.rb +++ b/lib/chef/provider/mount/solaris.rb @@ -27,6 +27,8 @@ class Chef class Mount # Mount Solaris File systems class Solaris < Chef::Provider::Mount + provides :mount, platform: %w(openindiana opensolaris nexentacore omnios solaris2 smartos) + extend Forwardable VFSTAB = '/etc/vfstab'.freeze diff --git a/lib/chef/provider/package.rb b/lib/chef/provider/package.rb index bdc96cd070..291ff882f6 100644 --- a/lib/chef/provider/package.rb +++ b/lib/chef/provider/package.rb @@ -490,6 +490,37 @@ class Chef false end end + + # Set provider priority + require 'chef/chef_class' + require 'chef/provider/package/dpkg' + require 'chef/provider/package/homebrew' + require 'chef/provider/package/macports' + require 'chef/provider/package/apt' + require 'chef/provider/package/yum' + require 'chef/provider/package/zypper' + require 'chef/provider/package/portage' + require 'chef/provider/package/pacman' + require 'chef/provider/package/ips' + require 'chef/provider/package/solaris' + require 'chef/provider/package/smartos' + require 'chef/provider/package/aix' + require 'chef/provider/package/paludis' + + Chef.set_provider_priority_array :package, [ Homebrew, Macports ], os: "darwin" + + Chef.set_provider_priority_array :package, Apt, platform_family: "debian" + Chef.set_provider_priority_array :package, Yum, platform_family: %w(rhel fedora) + Chef.set_provider_priority_array :package, Zypper, platform_family: "suse" + Chef.set_provider_priority_array :package, Portage, platform: "gentoo" + Chef.set_provider_priority_array :package, Pacman, platform: "arch" + Chef.set_provider_priority_array :package, Ips, platform: %w(openindiana opensolaris omnios solaris2) + Chef.set_provider_priority_array :package, Solaris, platform: "nexentacore" + Chef.set_provider_priority_array :package, Solaris, platform: "solaris2", platform_version: '< 5.11' + + Chef.set_provider_priority_array :package, SmartOS, platform: "smartos" + Chef.set_provider_priority_array :package, Aix, platform: "aix" + Chef.set_provider_priority_array :package, Paludis, platform: "exherbo" end end end diff --git a/lib/chef/provider/package/homebrew.rb b/lib/chef/provider/package/homebrew.rb index 603899646f..e2bc24d1ec 100644 --- a/lib/chef/provider/package/homebrew.rb +++ b/lib/chef/provider/package/homebrew.rb @@ -27,7 +27,6 @@ class Chef class Homebrew < Chef::Provider::Package provides :homebrew_package - provides :package, os: "darwin" include Chef::Mixin::HomebrewUser diff --git a/lib/chef/provider/package/macports.rb b/lib/chef/provider/package/macports.rb index b252344c99..97c13fec73 100644 --- a/lib/chef/provider/package/macports.rb +++ b/lib/chef/provider/package/macports.rb @@ -4,7 +4,6 @@ class Chef class Macports < Chef::Provider::Package provides :macports_package - provides :package, os: "darwin" def load_current_resource @current_resource = Chef::Resource::Package.new(@new_resource.name) diff --git a/lib/chef/provider/package/portage.rb b/lib/chef/provider/package/portage.rb index bb047ad2fa..4ba0160bb0 100644 --- a/lib/chef/provider/package/portage.rb +++ b/lib/chef/provider/package/portage.rb @@ -25,6 +25,8 @@ class Chef class Provider class Package class Portage < Chef::Provider::Package + provides :portage_package + PACKAGE_NAME_PATTERN = %r{(?:([^/]+)/)?([^/]+)} def load_current_resource diff --git a/lib/chef/provider/service.rb b/lib/chef/provider/service.rb index 75da2ddb31..9c523b5e66 100644 --- a/lib/chef/provider/service.rb +++ b/lib/chef/provider/service.rb @@ -168,6 +168,50 @@ class Chef @new_resource.respond_to?(method_name) && !!@new_resource.send(method_name) end + + module ServicePriorityInit + + # + # Platform-specific versions + # + + # + # Linux + # + + require 'chef/chef_class' + require 'chef/provider/service/systemd' + require 'chef/provider/service/insserv' + require 'chef/provider/service/redhat' + require 'chef/provider/service/arch' + require 'chef/provider/service/gentoo' + require 'chef/provider/service/upstart' + require 'chef/provider/service/debian' + require 'chef/provider/service/invokercd' + require 'chef/provider/service/freebsd' + require 'chef/provider/service/openbsd' + require 'chef/provider/service/solaris' + require 'chef/provider/service/macosx' + + def self.os(os, *providers) + Chef.set_provider_priority_array(:service, providers, os: os) + end + def self.platform_family(platform_family, *providers) + Chef.set_provider_priority_array(:service, providers, platform_family: platform_family) + end + + os %w(freebsd netbsd), Freebsd + os %w(openbsd), Openbsd + os %w(solaris2), Solaris + os %w(darwin), Macosx + os %w(linux), Systemd, Insserv, Redhat + + platform_family %w(arch), Systemd, Arch + platform_family %w(gentoo), Systemd, Gentoo + platform_family %w(debian), Systemd, Upstart, Insserv, Debian, Invokercd + platform_family %w(rhel fedora suse), Systemd, Insserv, Redhat + + end end end end diff --git a/lib/chef/provider/service/init.rb b/lib/chef/provider/service/init.rb index 0a219a69e1..355e98a0eb 100644 --- a/lib/chef/provider/service/init.rb +++ b/lib/chef/provider/service/init.rb @@ -18,6 +18,7 @@ require 'chef/provider/service/simple' require 'chef/mixin/command' +require 'chef/platform/service_helpers' class Chef class Provider diff --git a/lib/chef/provider/service/windows.rb b/lib/chef/provider/service/windows.rb index ba53f0a3c3..355ffafc2a 100644 --- a/lib/chef/provider/service/windows.rb +++ b/lib/chef/provider/service/windows.rb @@ -25,7 +25,6 @@ if RUBY_PLATFORM =~ /mswin|mingw32|windows/ end class Chef::Provider::Service::Windows < Chef::Provider::Service - provides :service, os: "windows" provides :windows_service, os: "windows" diff --git a/lib/chef/provider/user.rb b/lib/chef/provider/user.rb index f6ac72448e..ad92a72a0a 100644 --- a/lib/chef/provider/user.rb +++ b/lib/chef/provider/user.rb @@ -23,6 +23,7 @@ require 'etc' class Chef class Provider class User < Chef::Provider + provides :user include Chef::Mixin::Command @@ -208,7 +209,6 @@ class Chef def unlock_user raise NotImplementedError end - end end end diff --git a/lib/chef/provider/user/aix.rb b/lib/chef/provider/user/aix.rb index af08ab4364..a575a41e54 100644 --- a/lib/chef/provider/user/aix.rb +++ b/lib/chef/provider/user/aix.rb @@ -18,9 +18,10 @@ class Chef class Provider class User class Aix < Chef::Provider::User::Useradd + provides :user, platform: %w(aix) UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:shell, "-s"], [:uid, "-u"]] - + def create_user super add_password @@ -88,7 +89,7 @@ class Chef end end end - + end end end diff --git a/lib/chef/provider/user/pw.rb b/lib/chef/provider/user/pw.rb index fe71e93561..810ffb9a8d 100644 --- a/lib/chef/provider/user/pw.rb +++ b/lib/chef/provider/user/pw.rb @@ -22,6 +22,7 @@ class Chef class Provider class User class Pw < Chef::Provider::User + provides :user, platform: %w(freebsd) def load_current_resource super diff --git a/lib/chef/provider/user/solaris.rb b/lib/chef/provider/user/solaris.rb index d480acaced..b242095f0c 100644 --- a/lib/chef/provider/user/solaris.rb +++ b/lib/chef/provider/user/solaris.rb @@ -22,6 +22,8 @@ class Chef class Provider class User class Solaris < Chef::Provider::User::Useradd + provides :user, platform: %w(omnios solaris2) + UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:shell, "-s"], [:uid, "-u"]] attr_writer :password_file diff --git a/lib/chef/provider/user/useradd.rb b/lib/chef/provider/user/useradd.rb index cc770c0be2..a1b5b3459c 100644 --- a/lib/chef/provider/user/useradd.rb +++ b/lib/chef/provider/user/useradd.rb @@ -23,6 +23,7 @@ class Chef class Provider class User class Useradd < Chef::Provider::User + provides :user UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:password, "-p"], [:shell, "-s"], [:uid, "-u"]] diff --git a/lib/chef/provider_resolver.rb b/lib/chef/provider_resolver.rb index 7c7bac0443..5bfee343d1 100644 --- a/lib/chef/provider_resolver.rb +++ b/lib/chef/provider_resolver.rb @@ -24,88 +24,25 @@ class Chef # Provider Resolution # =================== # - # When you type `service 'myservice' { action :restart }` in a recipe, a whole - # string of events happens eventually leading to convergence. The overview of - # that process is described in `Chef::DSL::Recipe`. 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. + # 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. # - # The process happens in three steps: - # - # Explicit Provider on the Resource - # --------------------------------- # If the resource has its `provider` set, that is used. # - # Dynamic Provider Matches - # ------------------------ - # In this stage, we call `provides?` to see if the Provider supports the - # resource on this platform, and then we call `supports?` to determine if it - # can handle the action. It's a little more complicated than that, though: - # - # ### Provider.provides? - # - # First, we go through all known provider classes (all descendants of - # `Chef::Provider`), and call `provides?(node, resource)` to determine if it - # supports this action for this resource on this OS. We get a list of all - # matches. - # - # #### Defining provides - # - # The typical way of getting `provides?` is for the Provider class to call - # `provides :name`. - # - # The Provider may pass the OS, platform family, platform, and platform version - # to `provides`, and they will be matched against the values in the `node` - # object. The Provider may also pass a block, which allows for custom logic - # to decide whether it provides the resource or not. - # - # Some Providers also override `provides?` with custom logic. - # - # ### Provider.supports? - # - # Once we have the list of willing providers, we filter it by calling their - # `supports?(resource, action)` method to see if they support the specific - # action (`:create`, `:delete`) or not. - # - # If no provider supports the specific action, we fall back to the full list - # of matches from step 1. (TODO The comment says it's for why run. I'm not - # sure what that means specifically yet.) - # - # ### Priority lists: Chef.get_provider_priority_array + # 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: # - # Once we have the list of matches, we look at `Chef.get_provider_priority_array(node, resource)` - # to see if anyone has set a *priority list*. This method takes - # the the first matching priority list for this OS (which is the last list - # that was registered). + # 1. The filters it was registered with (such as `os: 'linux'` or + # `platform_family: 'debian'`) + # 2. `provides?(node, resource)` + # 3. `supports?(resource, action)` # - # If any of our matches are on the priority list, we take the first one. - # - # If there is no priority list or no matches on it, we take the first result - # alphabetically by class name. - # - # Chef::Platform Provider Map - # --------------------------- - # If we still have no matches, we try `Chef::Platform.find_provider_for_node(node, resource)`. - # This does two new things: - # - # ### System Provider Map - # - # The system provider map is a large Hash loaded during `require` time, - # which shows system-specific providers by os/platform, and platform_version. - # It keys off of `node[:platform] || node[:os]`, and `node[:platform_version] - # || node[:os_version] || node[:os_release]`. The version uses typical gem - # constraints like > and <=. - # - # The first platform+version match wins over the first platform-only match, - # which wins over the default. - # - # ### Chef::Provider::FooBar - # - # As a last resort, if there are *still* no classes, the system transforms the - # DSL name `foo_bar` into `Chef::Provider::FooBar`, and returns the class if - # it is there and descends from `Chef::Provider`. - # - # NOTE: this behavior is now deprecated. + # 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. # class ProviderResolver @@ -119,33 +56,14 @@ class Chef @action = action end - # return a deterministically sorted list of Chef::Provider subclasses - def providers - @providers ||= Chef::Provider.descendants - end - def resolve maybe_explicit_provider(resource) || maybe_dynamic_provider_resolution(resource, action) || maybe_chef_platform_lookup(resource) 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 + def provided_by?(provider_class) + prioritized_handlers.include?(provider_class) end private @@ -158,40 +76,37 @@ class Chef # try dynamically finding a provider based on querying the providers to see what they support def maybe_dynamic_provider_resolution(resource, action) - # 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}" - - # 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}" - - # 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. - handlers = supported_handlers.empty? ? enabled_handlers : supported_handlers - Chef::Log.debug "no providers supported the resource, falling back to enabled handlers" if supported_handlers.empty? - - if handlers.count >= 2 - # this magic stack ranks the providers by where they appear in the provider_priority_map, it is mostly used - # to pick amongst N different ways to start init scripts on different debian/ubuntu systems. - priority_list = [ get_priority_array(node, resource.resource_name) ].flatten.compact - handlers = handlers.sort_by { |x| i = priority_list.index x; i.nil? ? Float::INFINITY : i } - if priority_list.index(handlers.first).nil? - # if we had more than one and we picked one with a precidence of infinity that means that the resource_priority_map - # entry for this resource is missing -- we should probably raise here and force resolution of the ambiguity. - Chef::Log.warn "Ambiguous provider precedence: #{handlers}, please use Chef.set_provider_priority_array to provide determinism" - end - handlers = [ handlers.first ] + 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? + # 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 end - Chef::Log.debug "providers that survived replacement include: #{handlers}" - - raise Chef::Exceptions::AmbiguousProviderResolution.new(resource, handlers) if handlers.count >= 2 - - Chef::Log.debug "dynamic provider resolver FAILED to resolve a provider" if handlers.empty? - - return nil if handlers.empty? + if handler + Chef::Log.debug "Provider for action #{action} on resource #{resource} is #{handler}" + else + Chef::Log.debug "Dynamic provider resolver FAILED to resolve a provider for action #{action} on resource #{resource}" + end - handlers[0] + handler end # try the old static lookup of providers by platform @@ -199,13 +114,51 @@ class Chef Chef::Platform.find_provider_for_node(node, resource) end - # dep injection hooks - def get_priority_array(node, resource_name) - provider_priority_map.get_priority_array(node, resource_name) - end - def provider_priority_map Chef::Platform::ProviderPriorityMap.instance end + + def prioritized_handlers + @prioritized_handlers ||= + provider_priority_map.list_handlers(node, resource.resource_name).flatten(1).uniq + end + + module Deprecated + # return a deterministically sorted list of Chef::Provider subclasses + def providers + @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.") + end + result + end + end + end + prepend Deprecated end end diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb index 070793a7a2..b8bf53d6ec 100644 --- a/lib/chef/resource.rb +++ b/lib/chef/resource.rb @@ -1103,12 +1103,16 @@ class Chef end end - def self.provides(name, *args, &block) - result = super + def self.provides(name, opts={}, &block) + result = Chef.set_resource_priority_array(name, self, opts, &block) Chef::DSL::Resources.add_resource_dsl(name) result end + def self.provides?(node, resource) + Chef::ResourceResolver.new(node, resource).provided_by?(self) + end + # Helper for #notifies def validate_resource_spec!(resource_spec) run_context.resource_collection.validate_lookup_spec!(resource_spec) @@ -1290,8 +1294,6 @@ class Chef end end - private - def deprecated_constants @deprecated_constants ||= {} end @@ -1312,3 +1314,6 @@ class Chef end end end + +# Requiring things at the bottom breaks cycles +require 'chef/chef_class' diff --git a/lib/chef/resource/package.rb b/lib/chef/resource/package.rb index 4148144816..0944b5e9d8 100644 --- a/lib/chef/resource/package.rb +++ b/lib/chef/resource/package.rb @@ -102,3 +102,8 @@ class Chef end end end + +require 'chef/chef_class' +require 'chef/resource/homebrew_package' + +Chef.set_resource_priority_array :package, Chef::Resource::HomebrewPackage, os: "darwin" diff --git a/lib/chef/resource_resolver.rb b/lib/chef/resource_resolver.rb index a987b236c2..1bd8892239 100644 --- a/lib/chef/resource_resolver.rb +++ b/lib/chef/resource_resolver.rb @@ -18,7 +18,6 @@ require 'chef/exceptions' require 'chef/platform/resource_priority_map' -require 'chef/mixin/convert_to_class_name' class Chef class ResourceResolver @@ -33,22 +32,13 @@ class Chef @resource = resource.to_sym end - # return a deterministically sorted list of Chef::Resource subclasses - def resources - @resources ||= Chef::Resource.descendants - end - def resolve maybe_dynamic_resource_resolution || maybe_chef_platform_lookup end - # this cut looks at if the resource can handle the resource type on the node - def enabled_handlers - @enabled_handlers ||= - resources.select do |klass| - klass.provides?(node, resource) - end.sort {|a,b| a.to_s <=> b.to_s } + def provided_by?(resource_class) + !prioritized_handlers.include?(resource_class) end # @@ -61,37 +51,22 @@ class Chef new(node, resource_name).resolve end - private + 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}" - - # if none of the resources specifically support the resource, we still need to pick one of the resources that are - # enabled on the node to handle the why-run use case. - handlers = enabled_handlers - - if handlers.size >= 2 - # this magic stack ranks the resources by where they appear in the resource_priority_map - priority_list = [ get_priority_array(node, resource) ].flatten.compact - handlers = handlers.sort_by { |x| i = priority_list.index x; i.nil? ? Float::INFINITY : i } - if priority_list.index(handlers.first).nil? - # if we had more than one and we picked one with a precidence of infinity that means that the resource_priority_map - # entry for this resource is missing -- we should probably raise here and force resolution of the ambiguity. - Chef::Log.warn "Ambiguous resource precedence: #{handlers}, please use Chef.set_resource_priority_array to provide determinism" - end - handlers = handlers[0..0] - end - - Chef::Log.debug "resources that survived replacement include: #{handlers}" + 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}" - raise Chef::Exceptions::AmbiguousResourceResolution.new(resource, handlers) if handlers.count >= 2 + handler = prioritized_handlers.first - Chef::Log.debug "dynamic resource resolver FAILED to resolve a resource" if handlers.empty? - - return nil if handlers.empty? + 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 - handlers[0] + handler end # try the old static lookup of resources by mangling name to resource klass @@ -99,13 +74,42 @@ class Chef Chef::Resource.resource_matching_short_name(resource) end - # dep injection hooks - def get_priority_array(node, resource_name) - resource_priority_map.get_priority_array(node, resource_name) + def priority_map + Chef::Platform::ResourcePriorityMap.instance end - def resource_priority_map - Chef::Platform::ResourcePriorityMap.instance + def prioritized_handlers + @prioritized_handlers ||= + priority_map.list_handlers(node, resource) + end + + module Deprecated + # return a deterministically sorted list of Chef::Resource subclasses + def resources + @resources ||= Chef::Resource.descendants + end + + # this cut looks at if the resource can handle the resource type on the node + def enabled_handlers + @enabled_handlers ||= + resources.select do |klass| + klass.provides?(node, resource) + end.sort {|a,b| a.to_s <=> b.to_s } + end + + protected + + # If there are no providers for a DSL, we search through the + def prioritized_handlers + @prioritized_handlers ||= super || begin + if !enabled_handlers.empty? + Chef::Log.deprecation("#{resource} is 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.") + end + enabled_handlers + end + end end + prepend Deprecated end end diff --git a/lib/chef/util/path_helper.rb b/lib/chef/util/path_helper.rb index 10527f8906..9ebc9319b8 100644 --- a/lib/chef/util/path_helper.rb +++ b/lib/chef/util/path_helper.rb @@ -23,4 +23,3 @@ class Chef PathHelper = ChefConfig::PathHelper end end - diff --git a/spec/integration/recipes/recipe_dsl_spec.rb b/spec/integration/recipes/recipe_dsl_spec.rb index c79c20cd7d..93270a9a19 100644 --- a/spec/integration/recipes/recipe_dsl_spec.rb +++ b/spec/integration/recipes/recipe_dsl_spec.rb @@ -157,18 +157,17 @@ describe "Recipe DSL methods" do context "And Thingy4 provides :thingy3" do before(:context) { - class RecipeDSLSpecNamespace::Thingy4 < Chef::Resource + class RecipeDSLSpecNamespace::Thingy4 < BaseThingy resource_name :thingy3 end } - it "thingy3 works in a recipe and yields " do + it "thingy3 works in a recipe and yields Foo::Thingy4 (the explicit one)" do recipe = converge { thingy3 'blah' do; end } - expect(recipe.logged_warnings).to match(/ambiguous resource precedence/i) - expect(BaseThingy.created_resource).not_to be_nil + expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy4 end it "thingy4 does not work in a recipe" do diff --git a/spec/unit/node_map_spec.rb b/spec/unit/node_map_spec.rb index fe7372961b..9b5ff5e8c6 100644 --- a/spec/unit/node_map_spec.rb +++ b/spec/unit/node_map_spec.rb @@ -134,6 +134,10 @@ describe Chef::NodeMap do end describe "resource back-compat testing" do + before :each do + Chef::Config[:treat_deprecation_warnings_as_errors] = false + end + it "should handle :on_platforms => :all" do node_map.set(:chef_gem, :foo, :on_platforms => :all) allow(node).to receive(:[]).with(:platform).and_return("windows") @@ -152,4 +156,3 @@ describe Chef::NodeMap do end end - diff --git a/spec/unit/platform_spec.rb b/spec/unit/platform_spec.rb index e0115bc42a..36325d5411 100644 --- a/spec/unit/platform_spec.rb +++ b/spec/unit/platform_spec.rb @@ -18,29 +18,6 @@ require 'spec_helper' -describe "Chef::Platform supports" do - [ - :freebsd, - :ubuntu, - :debian, - :centos, - :fedora, - :suse, - :opensuse, - :redhat, - :oracle, - :gentoo, - :arch, - :solaris, - :gcel, - :ibm_powerkvm - ].each do |platform| - it "#{platform}" do - expect(Chef::Platform.platforms).to have_key(platform) - end - end -end - describe Chef::Platform do context "while testing with fake data" do @@ -261,41 +238,4 @@ describe Chef::Platform do end - context "while testing the configured platform data" do - - it "should use the solaris package provider on Solaris <11" do - pmap = Chef::Platform.find("Solaris2", "5.9") - expect(pmap[:package]).to eql(Chef::Provider::Package::Solaris) - end - - it "should use the IPS package provider on Solaris 11" do - pmap = Chef::Platform.find("Solaris2", "5.11") - expect(pmap[:package]).to eql(Chef::Provider::Package::Ips) - end - - it "should use the Redhat service provider on SLES11" do - 1.upto(3) do |sp| - pmap = Chef::Platform.find("SUSE", "11.#{sp}") - expect(pmap[:service]).to eql(Chef::Provider::Service::Redhat) - end - end - - it "should use the Systemd service provider on SLES12" do - pmap = Chef::Platform.find("SUSE", "12.0") - expect(pmap[:service]).to eql(Chef::Provider::Service::Systemd) - end - - it "should use the SUSE group provider on SLES11" do - 1.upto(3) do |sp| - pmap = Chef::Platform.find("SUSE", "11.#{sp}") - expect(pmap[:group]).to eql(Chef::Provider::Group::Suse) - end - end - - it "should use the Gpasswd group provider on SLES12" do - pmap = Chef::Platform.find("SUSE", "12.0") - expect(pmap[:group]).to eql(Chef::Provider::Group::Gpasswd) - end - end - end diff --git a/spec/unit/provider_resolver_spec.rb b/spec/unit/provider_resolver_spec.rb index bdf6d06e09..a27074e0bc 100644 --- a/spec/unit/provider_resolver_spec.rb +++ b/spec/unit/provider_resolver_spec.rb @@ -19,9 +19,13 @@ require 'spec_helper' require 'chef/mixin/convert_to_class_name' require 'chef/provider_resolver' +require 'chef/platform/service_helpers' include Chef::Mixin::ConvertToClassName +# Open up Provider so we can write things down easier in here +#module Chef::Provider + describe Chef::ProviderResolver do let(:node) do @@ -50,6 +54,51 @@ describe Chef::ProviderResolver do allow(resource).to receive(:is_a?).with(Chef::Resource).and_return(true) end + def self.on_platform(platform, *tags, + platform_version: '11.0.1', + platform_family: nil, + os: nil, + &block) + Array(platform).each do |platform| + Array(platform_version).each do |platform_version| + on_one_platform(platform, platform_version, platform_family || platform, os || platform_family || platform, *tags, &block) + end + end + end + + def self.on_one_platform(platform, platform_version, platform_family, os, *tags, &block) + describe "on #{platform} #{platform_version}, platform_family: #{platform_family}, os: #{os}", *tags do + let(:os) { os } + let(:platform) { platform } + let(:platform_family) { platform_family } + let(:platform_version) { platform_version } + + define_singleton_method(:os) { os } + define_singleton_method(:platform) { platform } + define_singleton_method(:platform_family) { platform_family } + define_singleton_method(:platform_version) { platform_version } + + instance_eval(&block) + end + end + + def self.expect_providers(**providers) + providers.each do |name, provider| + describe name.to_s do + let(:resource_name) { name } + if provider + it "resolves to a #{provider}" do + expect(resolved_provider).to eql(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/ + end + end + end + end + end + describe "resolving service resource" do def stub_service_providers(*services) services ||= [] @@ -301,389 +350,477 @@ describe Chef::ProviderResolver do end end - describe "on Ubuntu 14.10" do - let(:os) { "linux" } - let(:platform) { "ubuntu" } - let(:platform_family) { "debian" } - let(:platform_version) { "14.04" } - + on_platform "ubuntu", platform_version: "14.10", platform_family: "debian", os: "linux" do it_behaves_like "an ubuntu platform with upstart, update-rc.d and systemd" end - describe "on Ubuntu 14.04" do - let(:os) { "linux" } - let(:platform) { "ubuntu" } - let(:platform_family) { "debian" } - let(:platform_version) { "14.04" } - + on_platform "ubuntu", platform_version: "14.04", platform_family: "debian", os: "linux" do it_behaves_like "an ubuntu platform with upstart and update-rc.d" end - describe "on Ubuntu 10.04" do - let(:os) { "linux" } - let(:platform) { "ubuntu" } - let(:platform_family) { "debian" } - let(:platform_version) { "10.04" } - + on_platform "ubuntu", platform_version: "10.04", platform_family: "debian", os: "linux" do it_behaves_like "an ubuntu platform with upstart and update-rc.d" end # old debian uses the Debian provider (does not have insserv or upstart, or update-rc.d???) - describe "on Debian 4.0" do - let(:os) { "linux" } - let(:platform) { "debian" } - let(:platform_family) { "debian" } - let(:platform_version) { "4.0" } - + on_platform "debian", platform_version: "4.0", os: "linux" do #it_behaves_like "a debian platform using the debian provider" end # Debian replaced the debian provider with insserv in the FIXME:VERSION distro - describe "on Debian 7.0" do - let(:os) { "linux" } - let(:platform) { "debian" } - let(:platform_family) { "debian" } - let(:platform_version) { "7.0" } - + on_platform "debian", platform_version: "7.0", os: "linux" do it_behaves_like "a debian platform using the insserv provider" end - %w{solaris2 openindiana opensolaris nexentacore omnios smartos}.each do |platform| - describe "on #{platform}" do - let(:os) { "solaris2" } - let(:platform) { platform } - let(:platform_family) { platform } - let(:platform_version) { "5.11" } - - it "returns a Solaris provider" do - stub_service_providers - stub_service_configs - expect(resolved_provider).to eql(Chef::Provider::Service::Solaris) - end + on_platform %w{solaris2 openindiana opensolaris nexentacore omnios smartos}, os: "solaris2", platform_version: "5.11" do + it "returns a Solaris provider" do + stub_service_providers + stub_service_configs + expect(resolved_provider).to eql(Chef::Provider::Service::Solaris) + end - it "always returns a Solaris provider" do - # no matter what we stub on the next two lines we should get a Solaris provider - stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd) - stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd) - expect(resolved_provider).to eql(Chef::Provider::Service::Solaris) - end + it "always returns a Solaris provider" do + # no matter what we stub on the next two lines we should get a Solaris provider + stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd) + stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd) + expect(resolved_provider).to eql(Chef::Provider::Service::Solaris) end end - %w{mswin mingw32 windows}.each do |platform| - describe "on #{platform}" do - let(:os) { "windows" } - let(:platform) { platform } - let(:platform_family) { "windows" } - let(:platform_version) { "5.11" } - - it "returns a Windows provider" do - stub_service_providers - stub_service_configs - expect(resolved_provider).to eql(Chef::Provider::Service::Windows) - end + on_platform %w{mswin mingw32 windows}, platform_family: "windows", platform_version: "5.11" do + it "returns a Windows provider" do + stub_service_providers + stub_service_configs + expect(resolved_provider).to eql(Chef::Provider::Service::Windows) + end - it "always returns a Windows provider" do - # no matter what we stub on the next two lines we should get a Windows provider - stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd) - stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd) - expect(resolved_provider).to eql(Chef::Provider::Service::Windows) - end + it "always returns a Windows provider" do + # no matter what we stub on the next two lines we should get a Windows provider + stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd) + stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd) + expect(resolved_provider).to eql(Chef::Provider::Service::Windows) end end - %w{mac_os_x mac_os_x_server}.each do |platform| - describe "on #{platform}" do - let(:os) { "darwin" } - let(:platform) { platform } - let(:platform_family) { "mac_os_x" } - let(:platform_version) { "10.9.2" } - - it "returns a Macosx provider" do - stub_service_providers - stub_service_configs - expect(resolved_provider).to eql(Chef::Provider::Service::Macosx) - end + on_platform %w{mac_os_x mac_os_x_server}, os: "darwin", platform_family: "mac_os_x", platform_version: "10.9.2" do + it "returns a Macosx provider" do + stub_service_providers + stub_service_configs + expect(resolved_provider).to eql(Chef::Provider::Service::Macosx) + end - it "always returns a Macosx provider" do - # no matter what we stub on the next two lines we should get a Macosx provider - stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd) - stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd) - expect(resolved_provider).to eql(Chef::Provider::Service::Macosx) - end + it "always returns a Macosx provider" do + # no matter what we stub on the next two lines we should get a Macosx provider + stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd) + stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd) + expect(resolved_provider).to eql(Chef::Provider::Service::Macosx) end end - %w{freebsd netbsd}.each do |platform| - describe "on #{platform}" do - let(:os) { platform } - let(:platform) { platform } - let(:platform_family) { platform } - let(:platform_version) { "10.0-RELEASE" } - - it "returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do - stub_service_providers - stub_service_configs(:usr_local_etc_rcd) - expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd) - end + on_platform %w(freebsd netbsd), platform_version: '3.1.4' do + it "returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do + stub_service_providers + stub_service_configs(:usr_local_etc_rcd) + expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd) + end - it "returns a Freebsd provider if it finds the /etc/rc.d initscript" do - stub_service_providers - stub_service_configs(:etc_rcd) - expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd) - end + it "returns a Freebsd provider if it finds the /etc/rc.d initscript" do + stub_service_providers + stub_service_configs(:etc_rcd) + expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd) + end - it "always returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do - # should only care about :usr_local_etc_rcd stub in the service configs - stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd) - stub_service_configs(:usr_local_etc_rcd, :initd, :upstart, :xinetd, :systemd) - expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd) - end + it "always returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do + # should only care about :usr_local_etc_rcd stub in the service configs + stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd) + stub_service_configs(:usr_local_etc_rcd, :initd, :upstart, :xinetd, :systemd) + expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd) + end - it "always returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do - # should only care about :etc_rcd stub in the service configs - stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd) - stub_service_configs(:etc_rcd, :initd, :upstart, :xinetd, :systemd) - expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd) - end + it "always returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do + # should only care about :etc_rcd stub in the service configs + stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd) + stub_service_configs(:etc_rcd, :initd, :upstart, :xinetd, :systemd) + expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd) + end - it "foo" do - stub_service_providers - stub_service_configs - expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd) - end + it "foo" do + stub_service_providers + stub_service_configs + expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd) end end end - describe "for the package provider" do - let(:resource_name) { :package } - - before do - expect(provider_resolver).not_to receive(:maybe_chef_platform_lookup) - end - - %w{mac_os_x mac_os_x_server}.each do |platform| - describe "on #{platform}" do - let(:os) { "darwin" } - let(:platform) { platform } - let(:platform_family) { "mac_os_x" } - let(:platform_version) { "10.9.2" } - - - it "returns a Chef::Provider::Package::Homebrew provider" do - expect(resolved_provider).to eql(Chef::Provider::Package::Homebrew) - end - end - end - end + 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, + rpm_package: Chef::Provider::Package::Rpm, + 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, + + # We want to check that these are unsupported: + apt_package: nil, + bff_package: nil, + dsc_script: nil, + dpkg_package: nil, + ips_package: nil, + pacman_package: nil, + paludis_package: nil, + rpm_package: nil, + smartos_package: nil, + solaris_package: nil, + yum_package: nil, + windows_package: nil, + 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, + + "debian" => { + ifconfig: Chef::Provider::Ifconfig::Debian, + package: Chef::Provider::Package::Apt, +# service: Chef::Provider::Service::Debian, + + "debian" => { + "7.0" => { + }, + "6.0" => { + ifconfig: Chef::Provider::Ifconfig, +# service: Chef::Provider::Service::Insserv, + }, + "5.0" => { + ifconfig: Chef::Provider::Ifconfig, + }, + }, + "gcel" => { + "3.1.4" => { + ifconfig: Chef::Provider::Ifconfig, + }, + }, + "linaro" => { + "3.1.4" => { + ifconfig: Chef::Provider::Ifconfig, + }, + }, + "linuxmint" => { + "3.1.4" => { + ifconfig: Chef::Provider::Ifconfig, +# service: Chef::Provider::Service::Upstart, + }, + }, + "raspbian" => { + "3.1.4" => { + ifconfig: Chef::Provider::Ifconfig, + }, + }, + "ubuntu" => { + "11.10" => { + }, + "10.04" => { + ifconfig: Chef::Provider::Ifconfig, + }, + }, + }, + + "arch" => { + package: Chef::Provider::Package::Pacman, + + "arch" => { + "3.1.4" => { + } + }, + }, + + "freebsd" => { + group: Chef::Provider::Group::Pw, + user: Chef::Provider::User::Pw, + + "freebsd" => { + "3.1.4" => { + }, + }, + }, + "suse" => { + group: Chef::Provider::Group::Gpasswd, + "suse" => { + "12.0" => { + }, + %w(11.1 11.2 11.3) => { + group: Chef::Provider::Group::Suse, + }, + }, + "opensuse" => { +# service: Chef::Provider::Service::Redhat, + package: Chef::Provider::Package::Zypper, + group: Chef::Provider::Group::Usermod, + "12.3" => { + }, + "12.2" => { + group: Chef::Provider::Group::Suse, + }, + }, + }, + + "gentoo" => { + package: Chef::Provider::Package::Portage, + portage_package: Chef::Provider::Package::Portage, +# service: Chef::Provider::Service::Gentoo, + + "gentoo" => { + "3.1.4" => { + }, + }, + }, + + "rhel" => { +# service: Chef::Provider::Service::Systemd, + package: Chef::Provider::Package::Yum, + ifconfig: Chef::Provider::Ifconfig::Redhat, + + %w(amazon xcp xenserver ibm_powerkvm cloudlinux parallels) => { + "3.1.4" => { +# service: Chef::Provider::Service::Redhat, + }, + }, + %w(redhat centos scientific oracle) => { + "7.0" => { + }, + "6.0" => { +# service: Chef::Provider::Service::Redhat, + }, + }, + "fedora" => { + "15.0" => { + }, + "14.0" => { +# service: Chef::Provider::Service::Redhat, + }, + }, + }, - provider_mapping = { - "mac_os_x" => { - :package => Chef::Provider::Package::Homebrew, - :user => Chef::Provider::User::Dscl, - :group => Chef::Provider::Group::Dscl, }, - "mac_os_x_server" => { - :package => Chef::Provider::Package::Homebrew, - :user => Chef::Provider::User::Dscl, - :group => Chef::Provider::Group::Dscl, - }, - "mswin" => { - :env => Chef::Provider::Env::Windows, - :user => Chef::Provider::User::Windows, - :group => Chef::Provider::Group::Windows, - :mount => Chef::Provider::Mount::Windows, - :batch => Chef::Provider::Batch, - :powershell_script => Chef::Provider::PowershellScript, - }, - "mingw32" => { - :env => Chef::Provider::Env::Windows, - :user => Chef::Provider::User::Windows, - :group => Chef::Provider::Group::Windows, - :mount => Chef::Provider::Mount::Windows, - :batch => Chef::Provider::Batch, - :powershell_script => Chef::Provider::PowershellScript, + + "darwin" => { + %w(mac_os_x mac_os_x_server) => { + group: Chef::Provider::Group::Dscl, + package: Chef::Provider::Package::Homebrew, + user: Chef::Provider::User::Dscl, + + "mac_os_x" => { + "10.9.2" => { + }, + }, + }, }, + "windows" => { - :env => Chef::Provider::Env::Windows, - :user => Chef::Provider::User::Windows, - :group => Chef::Provider::Group::Windows, - :mount => Chef::Provider::Mount::Windows, - :batch => Chef::Provider::Batch, - :powershell_script => Chef::Provider::PowershellScript, + 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, + + "windows" => { + %w(mswin mingw32 windows) => { + "10.9.2" => { + }, + }, + }, }, + "aix" => { - :cron => Chef::Provider::Cron::Aix, - }, - "netbsd"=> { - :group => Chef::Provider::Group::Groupmod, + 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, + + "aix" => { + "aix" => { + "5.6" => { + }, + }, + }, }, - "openbsd" => { - :group => Chef::Provider::Group::Usermod, - :package => Chef::Provider::Package::Openbsd, - }, - } - - def self.do_platform(platform_hash) - platform_hash.each do |resource, provider| - describe "for #{resource}" do - let(:resource_name) { resource } - - it "resolves to a #{provider}" do - expect(resolved_provider).to eql(provider) - end - end - end - end - - describe "individual platform mappings" do - let(:resource_name) { :user } - - before do - expect(provider_resolver).not_to receive(:maybe_chef_platform_lookup) - end - - %w{mac_os_x mac_os_x_server}.each do |platform| - describe "on #{platform}" do - let(:os) { "darwin" } - let(:platform) { platform } - let(:platform_family) { "mac_os_x" } - let(:platform_version) { "10.9.2" } - do_platform(provider_mapping[platform]) - end - end - - %w{mswin mingw32 windows}.each do |platform| - describe "on #{platform}" do - let(:os) { "windows" } - let(:platform) { platform } - let(:platform_family) { "windows" } - let(:platform_version) { "10.9.2" } + "hpux" => { + "hpux" => { + "hpux" => { + "3.1.4" => { + group: Chef::Provider::Group::Usermod + } + } + } + }, - do_platform(provider_mapping[platform]) - end - end + "netbsd" => { + "netbsd" => { + "netbsd" => { + "3.1.4" => { + group: Chef::Provider::Group::Groupmod, + }, + }, + }, + }, - describe "on AIX" do - let(:os) { "aix" } - let(:platform) { "aix" } - let(:platform_family) { "aix" } - let(:platform_version) { "6.2" } + "openbsd" => { + group: Chef::Provider::Group::Usermod, + package: Chef::Provider::Package::Openbsd, + + "openbsd" => { + "openbsd" => { + "3.1.4" => { + }, + }, + }, + }, - do_platform(provider_mapping['aix']) - end + "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, + + "smartos" => { + smartos_package: Chef::Provider::Package::SmartOS, + package: Chef::Provider::Package::SmartOS, + + "smartos" => { + "3.1.4" => { + }, + }, + }, + + "solaris2" => { + "nexentacore" => { + "3.1.4" => { + package: Chef::Provider::Package::Solaris, + }, + }, + "omnios" => { + "3.1.4" => { + user: Chef::Provider::User::Solaris, + } + }, + "openindiana" => { + "3.1.4" => { + }, + }, + "opensolaris" => { + "3.1.4" => { + }, + }, + "solaris2" => { + user: Chef::Provider::User::Solaris, + "5.11" => { + }, + "5.9" => { + package: Chef::Provider::Package::Solaris, + }, + }, + }, - %w{netbsd openbsd}.each do |platform| - describe "on #{platform}" do - let(:os) { platform } - let(:platform) { platform } - let(:platform_family) { platform } - let(:platform_version) { "10.0-RELEASE" } + }, - do_platform(provider_mapping[platform]) - end - end - end + "solaris" => { + "solaris" => { + "solaris" => { + "3.1.4" => { + }, + }, + }, + }, - describe "resolving static providers" do - def resource_class(resource) - Chef::Resource.const_get(convert_to_class_name(resource.to_s)) - end - static_mapping = { - apt_package: Chef::Provider::Package::Apt, - bash: Chef::Provider::Script, - bff_package: Chef::Provider::Package::Aix, - 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, - dpkg_package: Chef::Provider::Package::Dpkg, - dsc_script: Chef::Provider::DscScript, - 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, - homebrew_package: Chef::Provider::Package::Homebrew, - http_request: Chef::Provider::HttpRequest, - ips_package: Chef::Provider::Package::Ips, - link: Chef::Provider::Link, - log: Chef::Provider::Log::ChefLog, - macports_package: Chef::Provider::Package::Macports, - mdadm: Chef::Provider::Mdadm, - pacman_package: Chef::Provider::Package::Pacman, - paludis_package: Chef::Provider::Package::Paludis, - perl: Chef::Provider::Script, - portage_package: Chef::Provider::Package::Portage, - python: Chef::Provider::Script, - remote_directory: Chef::Provider::RemoteDirectory, - route: Chef::Provider::Route, - rpm_package: Chef::Provider::Package::Rpm, - ruby: Chef::Provider::Script, - ruby_block: Chef::Provider::RubyBlock, - script: Chef::Provider::Script, - smartos_package: Chef::Provider::Package::SmartOS, - solaris_package: Chef::Provider::Package::Solaris, - subversion: Chef::Provider::Subversion, - template: Chef::Provider::Template, - timestamped_deploy: Chef::Provider::Deploy::Timestamped, - whyrun_safe_ruby_block: Chef::Provider::WhyrunSafeRubyBlock, - windows_package: Chef::Provider::Package::Windows, - windows_service: Chef::Provider::Service::Windows, - yum_package: Chef::Provider::Package::Yum, + "exherbo" => { + "exherbo" => { + "exherbo" => { + "3.1.4" => { + package: Chef::Provider::Package::Paludis + } + } } + } + } - describe "on Ubuntu 14.04" do - let(:os) { "linux" } - let(:platform) { "ubuntu" } - let(:platform_family) { "debian" } - let(:platform_version) { "14.04" } - - supported_providers = [ - :apt_package, :bash, :breakpoint, :chef_gem, :cookbook_file, :csh, :deploy, - :deploy_revision, :directory, :dpkg_package, :easy_install_package, :erl_call, - :execute, :file, :gem_package, :git, :homebrew_package, :http_request, :link, - :log, :macports_package, :pacman_package, :paludis_package, :perl, :python, - :remote_directory, :route, :rpm_package, :ruby, :ruby_block, :script, :subversion, - :template, :timestamped_deploy, :whyrun_safe_ruby_block, :yum_package, - ] - - supported_providers.each do |static_resource| - static_provider = static_mapping[static_resource] - context "when the resource is a #{static_resource}" do - let(:resource) { double(Chef::Resource, provider: nil, resource_name: static_resource) } - let(:action) { :start } # in reality this doesn't matter much - it "should resolve to a #{static_provider} provider" do - expect(provider_resolver).not_to receive(:maybe_chef_platform_lookup) - expect(resolved_provider).to eql(static_provider) + def self.create_provider_tests(providers, test, expected, filter) + expected = expected.merge(providers.select { |key, value| key.is_a?(Symbol) }) + providers.each do |key, value| + if !key.is_a?(Symbol) + next_test = test.merge({ filter => key }) + next_filter = + case filter + when :os + :platform_family + when :platform_family + :platform + when :platform + :platform_version + when :platform_version + nil + else + raise "Hash too deep; only os, platform_family, platform and platform_version supported" end - end + create_provider_tests(value, next_test, expected, next_filter) end - - unsupported_providers = [ - :bff_package, :dsc_script, :ips_package, :smartos_package, - :solaris_package, :windows_package, :windows_service, - ] - - unsupported_providers.each do |static_resource| - static_provider = static_mapping[static_resource] - context "when the resource is a #{static_resource}" do - let(:resource) { double(Chef::Resource, provider: nil, resource_name: static_resource) } - let(:action) { :start } # in reality this doesn't matter much - it "should fall back into the old provider mapper code and hooks" do - retval = Object.new - expect(provider_resolver).to receive(:maybe_chef_platform_lookup).and_return(retval) - expect(resolved_provider).to equal(retval) - end - end + end + # If there is no filter, we're as deep as we need to go + if !filter + on_platform test.delete(:platform), test do + expect_providers(expected) end end end + + create_provider_tests(PROVIDERS, {}, {}, :os) end diff --git a/spec/unit/recipe_spec.rb b/spec/unit/recipe_spec.rb index 86f9a2d1d7..618c742998 100644 --- a/spec/unit/recipe_spec.rb +++ b/spec/unit/recipe_spec.rb @@ -122,7 +122,7 @@ describe Chef::Recipe do it "locate resource for particular platform" do ShaunTheSheep = Class.new(Chef::Resource) ShaunTheSheep.use_automatic_resource_name - ShaunTheSheep.provides :laughter, :on_platforms => ["television"] + ShaunTheSheep.provides :laughter, :platform => ["television"] node.automatic[:platform] = "television" node.automatic[:platform_version] = "123" res = recipe.laughter "timmy" @@ -144,10 +144,8 @@ describe Chef::Recipe do node.automatic[:platform] = "nbc_sports" Sounders = Class.new(Chef::Resource) Sounders.use_automatic_resource_name - Sounders.provides :football, platform: "nbc_sports" TottenhamHotspur = Class.new(Chef::Resource) TottenhamHotspur.use_automatic_resource_name - TottenhamHotspur.provides :football, platform: "nbc_sports" end after do @@ -155,16 +153,12 @@ describe Chef::Recipe do Object.send(:remove_const, :TottenhamHotspur) end - it "warns if resolution of the two resources is ambiguous" do - expect(Chef::Log).to receive(:warn).at_least(:once).with(/Ambiguous resource precedence/) - res1 = recipe.football "club world cup" - expect(res1.name).to eql("club world cup") - # the class of res1 is not defined. - end - - it "selects one if it is given priority" do + it "selects one if it is the last declared" do expect(Chef::Log).not_to receive(:warn) - Chef::Platform::ResourcePriorityMap.instance.send(:priority, :football, TottenhamHotspur, platform: "nbc_sports") + + Sounders.provides :football, platform: "nbc_sports" + TottenhamHotspur.provides :football, platform: "nbc_sports" + res1 = recipe.football "club world cup" expect(res1.name).to eql("club world cup") expect(res1).to be_a_kind_of(TottenhamHotspur) @@ -172,7 +166,10 @@ describe Chef::Recipe do it "selects the other one if it is given priority" do expect(Chef::Log).not_to receive(:warn) - Chef::Platform::ResourcePriorityMap.instance.send(:priority, :football, Sounders, platform: "nbc_sports") + + TottenhamHotspur.provides :football, platform: "nbc_sports" + Sounders.provides :football, platform: "nbc_sports" + res1 = recipe.football "club world cup" expect(res1.name).to eql("club world cup") expect(res1).to be_a_kind_of(Sounders) diff --git a/spec/unit/resource/ifconfig_spec.rb b/spec/unit/resource/ifconfig_spec.rb index ea5282acd5..e3e1f6daa2 100644 --- a/spec/unit/resource/ifconfig_spec.rb +++ b/spec/unit/resource/ifconfig_spec.rb @@ -47,21 +47,23 @@ describe Chef::Resource::Ifconfig do end end - shared_examples "being a platform using the default ifconfig provider" do |platform, version| + shared_examples "being a platform based on an old Debian" do |platform, version| before do + @node.automatic_attrs[:os] = 'linux' + @node.automatic_attrs[:platform_family] = 'debian' @node.automatic_attrs[:platform] = platform @node.automatic_attrs[:platform_version] = version end it "should use an ordinary Provider::Ifconfig as a provider for #{platform} #{version}" do - expect(@resource.provider_for_action(:add)).to be_a_kind_of(Chef::Provider::Ifconfig) - expect(@resource.provider_for_action(:add)).not_to be_a_kind_of(Chef::Provider::Ifconfig::Debian) - expect(@resource.provider_for_action(:add)).not_to be_a_kind_of(Chef::Provider::Ifconfig::Redhat) + expect(@resource.provider_for_action(:add).class).to eq(Chef::Provider::Ifconfig) end end shared_examples "being a platform based on RedHat" do |platform, version| before do + @node.automatic_attrs[:os] = 'linux' + @node.automatic_attrs[:platform_family] = 'rhel' @node.automatic_attrs[:platform] = platform @node.automatic_attrs[:platform_version] = version end @@ -73,6 +75,8 @@ describe Chef::Resource::Ifconfig do shared_examples "being a platform based on a recent Debian" do |platform, version| before do + @node.automatic_attrs[:os] = 'linux' + @node.automatic_attrs[:platform_family] = 'debian' @node.automatic_attrs[:platform] = platform @node.automatic_attrs[:platform_version] = version end @@ -87,7 +91,7 @@ describe Chef::Resource::Ifconfig do end describe "when it is an old Debian platform" do - it_should_behave_like "being a platform using the default ifconfig provider", "debian", "6.0" + it_should_behave_like "being a platform based on an old Debian", "debian", "6.0" end describe "when it is a new Debian platform" do @@ -95,7 +99,7 @@ describe Chef::Resource::Ifconfig do end describe "when it is an old Ubuntu platform" do - it_should_behave_like "being a platform using the default ifconfig provider", "ubuntu", "11.04" + it_should_behave_like "being a platform based on an old Debian", "ubuntu", "11.04" end describe "when it is a new Ubuntu platform" do diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb index fefe78fbda..1d20fcf604 100644 --- a/spec/unit/resource_spec.rb +++ b/spec/unit/resource_spec.rb @@ -809,22 +809,22 @@ describe Chef::Resource do end it 'adds mappings for a single platform' do - expect(Chef::Resource::Klz.node_map).to receive(:set).with( - :dinobot, true, { platform: ['autobots'] } + expect(Chef).to receive(:set_resource_priority_array).with( + :dinobot, Chef::Resource::Klz, { platform: ['autobots'] } ) klz.provides :dinobot, platform: ['autobots'] end it 'adds mappings for multiple platforms' do - expect(Chef::Resource::Klz.node_map).to receive(:set).with( - :energy, true, { platform: ['autobots', 'decepticons']} + expect(Chef).to receive(:set_resource_priority_array).with( + :energy, Chef::Resource::Klz, { platform: ['autobots', 'decepticons']} ) klz.provides :energy, platform: ['autobots', 'decepticons'] end it 'adds mappings for all platforms' do - expect(Chef::Resource::Klz.node_map).to receive(:set).with( - :tape_deck, true, {} + expect(Chef).to receive(:set_resource_priority_array).with( + :tape_deck, Chef::Resource::Klz, {} ) klz.provides :tape_deck end @@ -864,7 +864,7 @@ describe Chef::Resource do @node.name("bumblebee") @node.automatic[:platform] = "autobots" @node.automatic[:platform_version] = "6.1" - klz2.provides :dinobot, :on_platforms => ['autobots'] + klz2.provides :dinobot, :platform => ['autobots'] Object.const_set('Grimlock', klz2) klz2.provides :grimlock end |