summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Keiser <john@johnkeiser.com>2015-06-02 10:06:40 -0700
committerJohn Keiser <john@johnkeiser.com>2015-06-02 10:06:40 -0700
commitd838d8310d30d85e8eab6244f90abbfd59747eca (patch)
tree98327c777bcdeba2933bbff11e945685840d400e
parent93f7b74349362d0c698a1080177b94e64248dac6 (diff)
parent871848fe20769ca8ebf54632f278cc508b5c26aa (diff)
downloadchef-d838d8310d30d85e8eab6244f90abbfd59747eca.tar.gz
Merge branch 'jk/one_map_to_rule_them_all'
-rw-r--r--lib/chef/chef_class.rb35
-rw-r--r--lib/chef/client.rb7
-rw-r--r--lib/chef/dsl/recipe.rb99
-rw-r--r--lib/chef/mixin/provides.rb23
-rw-r--r--lib/chef/node_map.rb164
-rw-r--r--lib/chef/platform/provider_mapping.rb269
-rw-r--r--lib/chef/platform/provider_priority_map.rb75
-rw-r--r--lib/chef/platform/resource_priority_map.rb22
-rw-r--r--lib/chef/provider.rb17
-rw-r--r--lib/chef/provider/file.rb1
-rw-r--r--lib/chef/provider/group/aix.rb1
-rw-r--r--lib/chef/provider/group/dscl.rb2
-rw-r--r--lib/chef/provider/group/gpasswd.rb1
-rw-r--r--lib/chef/provider/group/groupmod.rb2
-rw-r--r--lib/chef/provider/group/pw.rb1
-rw-r--r--lib/chef/provider/group/suse.rb2
-rw-r--r--lib/chef/provider/group/usermod.rb3
-rw-r--r--lib/chef/provider/group/windows.rb2
-rw-r--r--lib/chef/provider/ifconfig.rb2
-rw-r--r--lib/chef/provider/ifconfig/aix.rb1
-rw-r--r--lib/chef/provider/ifconfig/debian.rb2
-rw-r--r--lib/chef/provider/ifconfig/redhat.rb1
-rw-r--r--lib/chef/provider/mount.rb1
-rw-r--r--lib/chef/provider/mount/aix.rb1
-rw-r--r--lib/chef/provider/mount/mount.rb2
-rw-r--r--lib/chef/provider/mount/solaris.rb2
-rw-r--r--lib/chef/provider/package.rb31
-rw-r--r--lib/chef/provider/package/homebrew.rb1
-rw-r--r--lib/chef/provider/package/macports.rb1
-rw-r--r--lib/chef/provider/package/portage.rb2
-rw-r--r--lib/chef/provider/service.rb44
-rw-r--r--lib/chef/provider/service/init.rb1
-rw-r--r--lib/chef/provider/service/windows.rb1
-rw-r--r--lib/chef/provider/user.rb2
-rw-r--r--lib/chef/provider/user/aix.rb5
-rw-r--r--lib/chef/provider/user/pw.rb1
-rw-r--r--lib/chef/provider/user/solaris.rb2
-rw-r--r--lib/chef/provider/user/useradd.rb1
-rw-r--r--lib/chef/provider_resolver.rb221
-rw-r--r--lib/chef/resource.rb13
-rw-r--r--lib/chef/resource/package.rb5
-rw-r--r--lib/chef/resource_resolver.rb90
-rw-r--r--lib/chef/util/path_helper.rb1
-rw-r--r--spec/integration/recipes/recipe_dsl_spec.rb7
-rw-r--r--spec/unit/node_map_spec.rb5
-rw-r--r--spec/unit/platform_spec.rb60
-rw-r--r--spec/unit/provider_resolver_spec.rb789
-rw-r--r--spec/unit/recipe_spec.rb23
-rw-r--r--spec/unit/resource/ifconfig_spec.rb16
-rw-r--r--spec/unit/resource_spec.rb14
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