summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLamont Granquist <lamont@scriptkiddie.org>2014-10-24 10:46:31 -0700
committerLamont Granquist <lamont@scriptkiddie.org>2014-10-24 10:46:31 -0700
commit59236f77e5ce61dea27bb99ac259e59ef9436705 (patch)
tree89f61115a2332193ed4099f2cc5f7e24ad62937d
parente2b9b28ec4ab89991c758588cbed4e80743e47ae (diff)
parent97aaf5bbcdfd0810722b123bdc67e883a7ca8077 (diff)
downloadchef-59236f77e5ce61dea27bb99ac259e59ef9436705.tar.gz
Merge pull request #1596 from opscode/lcg/provider-resovler
CHEF-3404: Provider Resolver
-rw-r--r--lib/chef/dsl/recipe.rb1
-rw-r--r--lib/chef/exceptions.rb13
-rw-r--r--lib/chef/json_compat.rb2
-rw-r--r--lib/chef/mixin/convert_to_class_name.rb54
-rw-r--r--lib/chef/mixin/descendants_tracker.rb82
-rw-r--r--lib/chef/node_map.rb146
-rw-r--r--lib/chef/platform/provider_mapping.rb35
-rw-r--r--lib/chef/platform/provider_priority_map.rb80
-rw-r--r--lib/chef/platform/service_helpers.rb113
-rw-r--r--lib/chef/provider.rb24
-rw-r--r--lib/chef/provider/breakpoint.rb2
-rw-r--r--lib/chef/provider/cookbook_file.rb2
-rw-r--r--lib/chef/provider/cron.rb2
-rw-r--r--lib/chef/provider/deploy/revision.rb2
-rw-r--r--lib/chef/provider/deploy/timestamped.rb2
-rw-r--r--lib/chef/provider/directory.rb2
-rw-r--r--lib/chef/provider/dsc_script.rb3
-rw-r--r--lib/chef/provider/erl_call.rb2
-rw-r--r--lib/chef/provider/execute.rb2
-rw-r--r--lib/chef/provider/file.rb2
-rw-r--r--lib/chef/provider/git.rb2
-rw-r--r--lib/chef/provider/http_request.rb2
-rw-r--r--lib/chef/provider/link.rb2
-rw-r--r--lib/chef/provider/log.rb2
-rw-r--r--lib/chef/provider/package/aix.rb2
-rw-r--r--lib/chef/provider/package/apt.rb2
-rw-r--r--lib/chef/provider/package/dpkg.rb2
-rw-r--r--lib/chef/provider/package/easy_install.rb2
-rw-r--r--lib/chef/provider/package/homebrew.rb4
-rw-r--r--lib/chef/provider/package/ips.rb2
-rw-r--r--lib/chef/provider/package/macports.rb3
-rw-r--r--lib/chef/provider/package/pacman.rb2
-rw-r--r--lib/chef/provider/package/paludis.rb4
-rw-r--r--lib/chef/provider/package/rpm.rb2
-rw-r--r--lib/chef/provider/package/rubygems.rb3
-rw-r--r--lib/chef/provider/package/smartos.rb2
-rw-r--r--lib/chef/provider/package/solaris.rb2
-rw-r--r--lib/chef/provider/package/yum.rb2
-rw-r--r--lib/chef/provider/remote_directory.rb4
-rw-r--r--lib/chef/provider/route.rb2
-rw-r--r--lib/chef/provider/ruby_block.rb2
-rw-r--r--lib/chef/provider/script.rb6
-rw-r--r--lib/chef/provider/service/arch.rb6
-rw-r--r--lib/chef/provider/service/debian.rb64
-rw-r--r--lib/chef/provider/service/freebsd.rb4
-rw-r--r--lib/chef/provider/service/gentoo.rb3
-rw-r--r--lib/chef/provider/service/init.rb2
-rw-r--r--lib/chef/provider/service/insserv.rb22
-rw-r--r--lib/chef/provider/service/invokercd.rb6
-rw-r--r--lib/chef/provider/service/macosx.rb2
-rw-r--r--lib/chef/provider/service/redhat.rb12
-rw-r--r--lib/chef/provider/service/simple.rb2
-rw-r--r--lib/chef/provider/service/solaris.rb2
-rw-r--r--lib/chef/provider/service/systemd.rb7
-rw-r--r--lib/chef/provider/service/upstart.rb7
-rw-r--r--lib/chef/provider/service/windows.rb4
-rw-r--r--lib/chef/provider/subversion.rb2
-rw-r--r--lib/chef/provider/template.rb1
-rw-r--r--lib/chef/provider/whyrun_safe_ruby_block.rb2
-rw-r--r--lib/chef/provider_resolver.rb103
-rw-r--r--lib/chef/providers.rb4
-rw-r--r--lib/chef/resource.rb103
-rw-r--r--lib/chef/resource/apt_package.rb4
-rw-r--r--lib/chef/resource/bash.rb1
-rw-r--r--lib/chef/resource/bff_package.rb1
-rw-r--r--lib/chef/resource/breakpoint.rb2
-rw-r--r--lib/chef/resource/chef_gem.rb3
-rw-r--r--lib/chef/resource/cookbook_file.rb3
-rw-r--r--lib/chef/resource/csh.rb1
-rw-r--r--lib/chef/resource/deploy.rb1
-rw-r--r--lib/chef/resource/deploy_revision.rb7
-rw-r--r--lib/chef/resource/directory.rb3
-rw-r--r--lib/chef/resource/dpkg_package.rb3
-rw-r--r--lib/chef/resource/dsc_script.rb3
-rw-r--r--lib/chef/resource/easy_install_package.rb3
-rw-r--r--lib/chef/resource/erl_call.rb1
-rw-r--r--lib/chef/resource/execute.rb1
-rw-r--r--lib/chef/resource/file.rb4
-rw-r--r--lib/chef/resource/freebsd_package.rb2
-rw-r--r--lib/chef/resource/gem_package.rb3
-rw-r--r--lib/chef/resource/git.rb3
-rw-r--r--lib/chef/resource/homebrew_package.rb3
-rw-r--r--lib/chef/resource/http_request.rb1
-rw-r--r--lib/chef/resource/ips_package.rb4
-rw-r--r--lib/chef/resource/link.rb3
-rw-r--r--lib/chef/resource/log.rb4
-rw-r--r--lib/chef/resource/macports_package.rb4
-rw-r--r--lib/chef/resource/pacman_package.rb3
-rw-r--r--lib/chef/resource/paludis_package.rb4
-rw-r--r--lib/chef/resource/perl.rb1
-rw-r--r--lib/chef/resource/python.rb2
-rw-r--r--lib/chef/resource/remote_directory.rb3
-rw-r--r--lib/chef/resource/remote_file.rb2
-rw-r--r--lib/chef/resource/rpm_package.rb3
-rw-r--r--lib/chef/resource/ruby.rb1
-rw-r--r--lib/chef/resource/ruby_block.rb3
-rw-r--r--lib/chef/resource/script.rb1
-rw-r--r--lib/chef/resource/service.rb4
-rw-r--r--lib/chef/resource/smartos_package.rb7
-rw-r--r--lib/chef/resource/solaris_package.rb8
-rw-r--r--lib/chef/resource/subversion.rb1
-rw-r--r--lib/chef/resource/template.rb3
-rw-r--r--lib/chef/resource/timestamped_deploy.rb3
-rw-r--r--lib/chef/resource/whyrun_safe_ruby_block.rb1
-rw-r--r--lib/chef/resource/windows_package.rb4
-rw-r--r--lib/chef/resource/windows_service.rb3
-rw-r--r--lib/chef/resource/yum_package.rb4
-rw-r--r--lib/chef/resource_platform_map.rb151
-rw-r--r--lib/chef/run_context.rb6
-rw-r--r--spec/support/lib/chef/provider/snakeoil.rb1
-rw-r--r--spec/support/lib/chef/resource/zen_follower.rb2
-rw-r--r--spec/support/shared/unit/resource/static_provider_resolution.rb71
-rw-r--r--spec/unit/node_map_spec.rb155
-rw-r--r--spec/unit/provider/log_spec.rb4
-rw-r--r--spec/unit/provider/package/apt_spec.rb2
-rw-r--r--spec/unit/provider_resolver_spec.rb387
-rw-r--r--spec/unit/recipe_spec.rb17
-rw-r--r--spec/unit/resource/apt_package_spec.rb21
-rw-r--r--spec/unit/resource/breakpoint_spec.rb12
-rw-r--r--spec/unit/resource/chef_gem_spec.rb21
-rw-r--r--spec/unit/resource/deploy_revision_spec.rb31
-rw-r--r--spec/unit/resource/deploy_spec.rb13
-rw-r--r--spec/unit/resource/dpkg_package_spec.rb22
-rw-r--r--spec/unit/resource/easy_install_package_spec.rb25
-rw-r--r--spec/unit/resource/gem_package_spec.rb21
-rw-r--r--spec/unit/resource/git_spec.rb12
-rw-r--r--spec/unit/resource/homebrew_package_spec.rb25
-rw-r--r--spec/unit/resource/ips_package_spec.rb21
-rw-r--r--spec/unit/resource/macports_package_spec.rb21
-rw-r--r--spec/unit/resource/pacman_package_spec.rb22
-rw-r--r--spec/unit/resource/rpm_package_spec.rb22
-rw-r--r--spec/unit/resource/service_spec.rb12
-rw-r--r--spec/unit/resource/smartos_package_spec.rb25
-rw-r--r--spec/unit/resource/solaris_package_spec.rb39
-rw-r--r--spec/unit/resource/subversion_spec.rb12
-rw-r--r--spec/unit/resource/timestamped_deploy_spec.rb34
-rw-r--r--spec/unit/resource/yum_package_spec.rb23
-rw-r--r--spec/unit/resource_platform_map_spec.rb164
-rw-r--r--spec/unit/resource_spec.rb49
-rw-r--r--spec/unit/runner_spec.rb483
140 files changed, 2002 insertions, 1038 deletions
diff --git a/lib/chef/dsl/recipe.rb b/lib/chef/dsl/recipe.rb
index 94b0d2d18b..120497d56e 100644
--- a/lib/chef/dsl/recipe.rb
+++ b/lib/chef/dsl/recipe.rb
@@ -17,7 +17,6 @@
# limitations under the License.
#
-require 'chef/resource_platform_map'
require 'chef/mixin/convert_to_class_name'
require 'chef/exceptions'
diff --git a/lib/chef/exceptions.rb b/lib/chef/exceptions.rb
index 67429ac5a2..25f08455fc 100644
--- a/lib/chef/exceptions.rb
+++ b/lib/chef/exceptions.rb
@@ -91,7 +91,11 @@ class Chef
class ResourceNotFound < RuntimeError; end
# Can't find a Resource of this type that is valid on this platform.
- class NoSuchResourceType < NameError; end
+ class NoSuchResourceType < NameError
+ def initialize(short_name, node)
+ super "Cannot find a resource for #{short_name} on #{node[:platform]} version #{node[:platform_version]}"
+ end
+ end
class InvalidResourceSpecification < ArgumentError; end
class SolrConnectionError < RuntimeError; end
@@ -355,5 +359,12 @@ class Chef
end
class InvalidSearchQuery < ArgumentError; end
+
+ # Raised by Chef::ProviderResolver
+ class AmbiguousProviderResolution < RuntimeError
+ def initialize(resource, classes)
+ super "Found more than one provider for #{resource.resource_name} resource: #{classes}"
+ end
+ end
end
end
diff --git a/lib/chef/json_compat.rb b/lib/chef/json_compat.rb
index 0796984ab2..d0b3b4c7f8 100644
--- a/lib/chef/json_compat.rb
+++ b/lib/chef/json_compat.rb
@@ -152,7 +152,7 @@ class Chef
when CHEF_RESOURCELIST
Chef::ResourceCollection::ResourceList
when /^Chef::Resource/
- Chef::Resource.find_subclass_by_name(json_class)
+ Chef::Resource.find_descendants_by_name(json_class)
else
raise Chef::Exceptions::JSON::ParseError, "Unsupported `json_class` type '#{json_class}'"
end
diff --git a/lib/chef/mixin/convert_to_class_name.rb b/lib/chef/mixin/convert_to_class_name.rb
index f849b8de6a..19f229fdd3 100644
--- a/lib/chef/mixin/convert_to_class_name.rb
+++ b/lib/chef/mixin/convert_to_class_name.rb
@@ -61,6 +61,60 @@ class Chef
base.to_s + (file_base == 'default' ? '' : "_#{file_base}")
end
+ # Copied from rails activesupport. In ruby >= 2.0 const_get will just do this, so this can
+ # be deprecated and removed.
+ #
+ # MIT LICENSE is here: https://github.com/rails/rails/blob/master/activesupport/MIT-LICENSE
+
+ # Tries to find a constant with the name specified in the argument string.
+ #
+ # 'Module'.constantize # => Module
+ # 'Test::Unit'.constantize # => Test::Unit
+ #
+ # The name is assumed to be the one of a top-level constant, no matter
+ # whether it starts with "::" or not. No lexical context is taken into
+ # account:
+ #
+ # C = 'outside'
+ # module M
+ # C = 'inside'
+ # C # => 'inside'
+ # 'C'.constantize # => 'outside', same as ::C
+ # end
+ #
+ # NameError is raised when the name is not in CamelCase or the constant is
+ # unknown.
+ def constantize(camel_cased_word)
+ names = camel_cased_word.split('::')
+
+ # Trigger a built-in NameError exception including the ill-formed constant in the message.
+ Object.const_get(camel_cased_word) if names.empty?
+
+ # Remove the first blank element in case of '::ClassName' notation.
+ names.shift if names.size > 1 && names.first.empty?
+
+ names.inject(Object) do |constant, name|
+ if constant == Object
+ constant.const_get(name)
+ else
+ candidate = constant.const_get(name)
+ next candidate if constant.const_defined?(name, false)
+ next candidate unless Object.const_defined?(name)
+
+ # Go down the ancestors to check if it is owned directly. The check
+ # stops when we reach Object or the end of ancestors tree.
+ constant = constant.ancestors.inject do |const, ancestor|
+ break const if ancestor == Object
+ break ancestor if ancestor.const_defined?(name, false)
+ const
+ end
+
+ # owner is in Object, so raise
+ constant.const_get(name, false)
+ end
+ end
+ end
+
end
end
end
diff --git a/lib/chef/mixin/descendants_tracker.rb b/lib/chef/mixin/descendants_tracker.rb
new file mode 100644
index 0000000000..75d1f620d4
--- /dev/null
+++ b/lib/chef/mixin/descendants_tracker.rb
@@ -0,0 +1,82 @@
+#
+# Copyright (c) 2005-2012 David Heinemeier Hansson
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+
+# This is lifted from rails activesupport (note the copyright above):
+# https://github.com/rails/rails/blob/9f84e60ac9d7bf07d6ae1bc94f3941f5b8f1a228/activesupport/lib/active_support/descendants_tracker.rb
+
+class Chef
+ module Mixin
+ module DescendantsTracker
+ @@direct_descendants = {}
+
+ class << self
+ def direct_descendants(klass)
+ @@direct_descendants[klass] || []
+ end
+
+ def descendants(klass)
+ arr = []
+ accumulate_descendants(klass, arr)
+ arr
+ end
+
+ def find_descendants_by_name(klass, name)
+ descendants(klass).first {|c| c.name == name }
+ end
+
+ # This is the only method that is not thread safe, but is only ever called
+ # during the eager loading phase.
+ def store_inherited(klass, descendant)
+ (@@direct_descendants[klass] ||= []) << descendant
+ end
+
+ private
+
+ def accumulate_descendants(klass, acc)
+ if direct_descendants = @@direct_descendants[klass]
+ acc.concat(direct_descendants)
+ direct_descendants.each { |direct_descendant| accumulate_descendants(direct_descendant, acc) }
+ end
+ end
+ end
+
+ def inherited(base)
+ DescendantsTracker.store_inherited(self, base)
+ super
+ end
+
+ def direct_descendants
+ DescendantsTracker.direct_descendants(self)
+ end
+
+ def find_descendants_by_name(name)
+ DescendantsTracker.find_descendants_by_name(self, name)
+ end
+
+ def descendants
+ DescendantsTracker.descendants(self)
+ end
+ end
+ end
+end
diff --git a/lib/chef/node_map.rb b/lib/chef/node_map.rb
new file mode 100644
index 0000000000..2ca6d9ba17
--- /dev/null
+++ b/lib/chef/node_map.rb
@@ -0,0 +1,146 @@
+#
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+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
+ @map = {}
+ end
+
+ # Set a key/value pair on the map with a filter. The filter must be true
+ # when applied to the node in order to retrieve the value.
+ #
+ # @param key [Object] Key to store
+ # @param value [Object] Value associated with the key
+ # @param filters [Hash] Node filter options to apply to key retrieval
+ # @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)
+ @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 })
+ self
+ end
+
+ # Get a value from the NodeMap via applying the node to the filters that
+ # were set on the key.
+ #
+ # @param node [Chef::Node] The Chef::Node object for the run
+ # @param key [Object] Key to look up
+ # @return [Object] Value
+ #
+ 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
+ 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)
+ end
+ 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
+
+ # @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)
+
+ # 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)
+
+ # sorry double-negative: this means we pass this filter.
+ false
+ end
+
+ def filters_match?(node, filters)
+ return true if filters.empty?
+
+ # 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])
+ end
+
+ return true
+ end
+
+ def block_matches?(node, block)
+ return true if block.nil?
+ block.call node
+ end
+ end
+end
diff --git a/lib/chef/platform/provider_mapping.rb b/lib/chef/platform/provider_mapping.rb
index e6d948276c..382df342f5 100644
--- a/lib/chef/platform/provider_mapping.rb
+++ b/lib/chef/platform/provider_mapping.rb
@@ -41,7 +41,6 @@ class Chef
:mac_os_x => {
:default => {
:package => Chef::Provider::Package::Homebrew,
- :service => Chef::Provider::Service::Macosx,
:user => Chef::Provider::User::Dscl,
:group => Chef::Provider::Group::Dscl
}
@@ -49,7 +48,6 @@ class Chef
:mac_os_x_server => {
:default => {
:package => Chef::Provider::Package::Homebrew,
- :service => Chef::Provider::Service::Macosx,
:user => Chef::Provider::User::Dscl,
:group => Chef::Provider::Group::Dscl
}
@@ -57,7 +55,6 @@ class Chef
:freebsd => {
:default => {
:group => Chef::Provider::Group::Pw,
- :service => Chef::Provider::Service::Freebsd,
:user => Chef::Provider::User::Pw,
:cron => Chef::Provider::Cron
}
@@ -203,7 +200,7 @@ class Chef
:group => Chef::Provider::Group::Gpasswd
},
"< 12.0" => {
- :group => Chef::Provider::Group::Suse,
+ :group => Chef::Provider::Group::Suse,
:service => Chef::Provider::Service::Redhat
}
},
@@ -276,7 +273,6 @@ class Chef
:mswin => {
:default => {
:env => Chef::Provider::Env::Windows,
- :service => Chef::Provider::Service::Windows,
:user => Chef::Provider::User::Windows,
:group => Chef::Provider::Group::Windows,
:mount => Chef::Provider::Mount::Windows,
@@ -287,7 +283,6 @@ class Chef
:mingw32 => {
:default => {
:env => Chef::Provider::Env::Windows,
- :service => Chef::Provider::Service::Windows,
:user => Chef::Provider::User::Windows,
:group => Chef::Provider::Group::Windows,
:mount => Chef::Provider::Mount::Windows,
@@ -298,7 +293,6 @@ class Chef
:windows => {
:default => {
:env => Chef::Provider::Env::Windows,
- :service => Chef::Provider::Service::Windows,
:user => Chef::Provider::User::Windows,
:group => Chef::Provider::Group::Windows,
:mount => Chef::Provider::Mount::Windows,
@@ -310,7 +304,6 @@ class Chef
:openindiana => {
:default => {
:mount => Chef::Provider::Mount::Solaris,
- :service => Chef::Provider::Service::Solaris,
:package => Chef::Provider::Package::Ips,
:cron => Chef::Provider::Cron::Solaris,
:group => Chef::Provider::Group::Usermod
@@ -319,7 +312,6 @@ class Chef
:opensolaris => {
:default => {
:mount => Chef::Provider::Mount::Solaris,
- :service => Chef::Provider::Service::Solaris,
:package => Chef::Provider::Package::Ips,
:cron => Chef::Provider::Cron::Solaris,
:group => Chef::Provider::Group::Usermod
@@ -328,7 +320,6 @@ class Chef
:nexentacore => {
:default => {
:mount => Chef::Provider::Mount::Solaris,
- :service => Chef::Provider::Service::Solaris,
:package => Chef::Provider::Package::Solaris,
:cron => Chef::Provider::Cron::Solaris,
:group => Chef::Provider::Group::Usermod
@@ -337,7 +328,6 @@ class Chef
:omnios => {
:default => {
:mount => Chef::Provider::Mount::Solaris,
- :service => Chef::Provider::Service::Solaris,
:package => Chef::Provider::Package::Ips,
:cron => Chef::Provider::Cron::Solaris,
:group => Chef::Provider::Group::Usermod,
@@ -347,7 +337,6 @@ class Chef
:solaris2 => {
:default => {
:mount => Chef::Provider::Mount::Solaris,
- :service => Chef::Provider::Service::Solaris,
:package => Chef::Provider::Package::Ips,
:cron => Chef::Provider::Cron::Solaris,
:group => Chef::Provider::Group::Usermod,
@@ -355,7 +344,6 @@ class Chef
},
"< 5.11" => {
:mount => Chef::Provider::Mount::Solaris,
- :service => Chef::Provider::Service::Solaris,
:package => Chef::Provider::Package::Solaris,
:cron => Chef::Provider::Cron::Solaris,
:group => Chef::Provider::Group::Usermod,
@@ -365,7 +353,6 @@ class Chef
:smartos => {
:default => {
:mount => Chef::Provider::Mount::Solaris,
- :service => Chef::Provider::Service::Solaris,
:package => Chef::Provider::Package::SmartOS,
:cron => Chef::Provider::Cron::Solaris,
:group => Chef::Provider::Group::Usermod
@@ -373,7 +360,6 @@ class Chef
},
:netbsd => {
:default => {
- :service => Chef::Provider::Service::Freebsd,
:group => Chef::Provider::Group::Groupmod
}
},
@@ -407,29 +393,10 @@ class Chef
}
},
:default => {
- :file => Chef::Provider::File,
- :directory => Chef::Provider::Directory,
- :link => Chef::Provider::Link,
- :template => Chef::Provider::Template,
- :remote_directory => Chef::Provider::RemoteDirectory,
- :execute => Chef::Provider::Execute,
:mount => Chef::Provider::Mount::Mount,
- :script => Chef::Provider::Script,
- :service => Chef::Provider::Service::Init,
- :perl => Chef::Provider::Script,
- :python => Chef::Provider::Script,
- :ruby => Chef::Provider::Script,
- :bash => Chef::Provider::Script,
- :csh => Chef::Provider::Script,
:user => Chef::Provider::User::Useradd,
:group => Chef::Provider::Group::Gpasswd,
- :http_request => Chef::Provider::HttpRequest,
- :route => Chef::Provider::Route,
:ifconfig => Chef::Provider::Ifconfig,
- :ruby_block => Chef::Provider::RubyBlock,
- :whyrun_safe_ruby_block => Chef::Provider::WhyrunSafeRubyBlock,
- :erl_call => Chef::Provider::ErlCall,
- :log => Chef::Provider::Log::ChefLog
}
}
end
diff --git a/lib/chef/platform/provider_priority_map.rb b/lib/chef/platform/provider_priority_map.rb
new file mode 100644
index 0000000000..ccf6ef0bbe
--- /dev/null
+++ b/lib/chef/platform/provider_priority_map.rb
@@ -0,0 +1,80 @@
+
+require 'chef/providers'
+
+class Chef
+ class Platform
+ class ProviderPriorityMap
+ include Singleton
+
+ def initialize
+ load_default_map
+ end
+
+ def load_default_map
+
+ #
+ # 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, [
+ # on debian-ish system if an upstart script exists that always wins
+ Chef::Provider::Service::Upstart,
+ Chef::Provider::Service::Systemd,
+ 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" ]
+
+ #
+ # Solaris-en
+ #
+
+ priority :service, Chef::Provider::Service::Solaris, os: "solaris2"
+
+ #
+ # Mac
+ #
+
+ priority :service, Chef::Provider::Service::Macosx, os: "darwin"
+ end
+
+ def priority_map
+ @priority_map ||= Chef::NodeMap.new
+ end
+
+ def priority(*args)
+ priority_map.set(*args)
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/platform/service_helpers.rb b/lib/chef/platform/service_helpers.rb
new file mode 100644
index 0000000000..440391843e
--- /dev/null
+++ b/lib/chef/platform/service_helpers.rb
@@ -0,0 +1,113 @@
+#
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# XXX: mixing shellout into a mixin into classes has to be code smell
+require 'chef/mixin/shell_out'
+
+class Chef
+ class Platform
+ class ServiceHelpers
+ class << self
+
+ include Chef::Mixin::ShellOut
+
+ # This helper is mostly used to sort out the mess of different
+ # linux mechanisms that can be used to start services. It does
+ # not necessarily need to linux-specific, but currently all our
+ # other service providers are narrowly platform-specific with no
+ # alternatives.
+ def service_resource_providers
+ service_resource_providers = []
+
+ if ::File.exist?("/usr/sbin/update-rc.d")
+ service_resource_providers << :debian
+ end
+
+ if ::File.exist?("/usr/sbin/invoke-rc.d")
+ service_resource_providers << :invokercd
+ end
+
+ if ::File.exist?("/sbin/insserv")
+ service_resource_providers << :insserv
+ end
+
+ # debian >= 6.0 has /etc/init but does not have upstart
+ if ::File.exist?("/etc/init") && ::File.exist?("/sbin/start")
+ service_resource_providers << :upstart
+ end
+
+ if ::File.exist?("/sbin/chkconfig")
+ service_resource_providers << :redhat
+ end
+
+ if ::File.exist?("/bin/systemctl")
+ # FIXME: look for systemd as init provider
+ service_resource_providers << :systemd
+ end
+
+ service_resource_providers
+ end
+
+ def config_for_service(service_name)
+ configs = []
+
+ if ::File.exist?("/etc/init.d/#{service_name}")
+ configs << :initd
+ end
+
+ if ::File.exist?("/etc/init/#{service_name}.conf")
+ configs << :upstart
+ end
+
+ if ::File.exist?("/etc/xinetd.d/#{service_name}")
+ configs << :xinetd
+ end
+
+ if ::File.exist?("/etc/rc.d/#{service_name}")
+ configs << :etc_rcd
+ end
+
+ if ::File.exist?("/usr/local/etc/rc.d/#{service_name}")
+ configs << :usr_local_etc_rcd
+ end
+
+ if ::File.exist?("/bin/systemctl") && platform_has_systemd_unit?(service_name)
+ configs << :systemd
+ end
+
+ configs
+ end
+
+ private
+
+ def extract_systemd_services(output)
+ # first line finds e.g. "sshd.service"
+ services = output.lines.split.map { |l| l.split[0] }
+ # this splits off the suffix after the last dot to return "sshd"
+ services += services.map { |s| s.sub(/(.*)\..*/, '\1') }
+ end
+
+ def platform_has_systemd_unit?(service_name)
+ services = extract_systemd_services(shell_out!("systemctl --all").stdout) +
+ extract_systemd_services(shell_out!("systemctl --list-unit-files").stdout)
+ services.include?(service_name)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider.rb b/lib/chef/provider.rb
index bdfe826944..680fe9782f 100644
--- a/lib/chef/provider.rb
+++ b/lib/chef/provider.rb
@@ -22,11 +22,35 @@ require 'chef/mixin/convert_to_class_name'
require 'chef/mixin/enforce_ownership_and_permissions'
require 'chef/mixin/why_run'
require 'chef/mixin/shell_out'
+require 'chef/mixin/descendants_tracker'
+require 'chef/platform/service_helpers'
+require 'chef/node_map'
class Chef
class Provider
include Chef::Mixin::WhyRun
include Chef::Mixin::ShellOut
+ extend Chef::Mixin::DescendantsTracker
+
+ class << self
+ def node_map
+ @node_map ||= Chef::NodeMap.new
+ end
+
+ def provides(resource_name, opts={}, &block)
+ node_map.set(resource_name.to_sym, true, opts, &block)
+ end
+
+ # provides a node on the resource (early binding)
+ def provides?(node, resource)
+ node_map.get(node, resource.resource_name)
+ end
+
+ # supports the given resource and action (late binding)
+ def supports?(resource, action)
+ true
+ end
+ end
attr_accessor :new_resource
attr_accessor :current_resource
diff --git a/lib/chef/provider/breakpoint.rb b/lib/chef/provider/breakpoint.rb
index 224e2758eb..663d558f66 100644
--- a/lib/chef/provider/breakpoint.rb
+++ b/lib/chef/provider/breakpoint.rb
@@ -20,6 +20,8 @@ class Chef
class Provider
class Breakpoint < Chef::Provider
+ provides :breakpoint
+
def load_current_resource
end
diff --git a/lib/chef/provider/cookbook_file.rb b/lib/chef/provider/cookbook_file.rb
index 26d6ebf1d9..b501a9b41d 100644
--- a/lib/chef/provider/cookbook_file.rb
+++ b/lib/chef/provider/cookbook_file.rb
@@ -24,6 +24,8 @@ class Chef
class Provider
class CookbookFile < Chef::Provider::File
+ provides :cookbook_file
+
extend Chef::Deprecation::Warnings
include Chef::Deprecation::Provider::CookbookFile
add_deprecation_warnings_for(Chef::Deprecation::Provider::CookbookFile.instance_methods)
diff --git a/lib/chef/provider/cron.rb b/lib/chef/provider/cron.rb
index c3be9746df..1590c624f6 100644
--- a/lib/chef/provider/cron.rb
+++ b/lib/chef/provider/cron.rb
@@ -28,7 +28,7 @@ class Chef
SPECIAL_TIME_VALUES = [:reboot, :yearly, :annually, :monthly, :weekly, :daily, :midnight, :hourly]
CRON_ATTRIBUTES = [:minute, :hour, :day, :month, :weekday, :time, :command, :mailto, :path, :shell, :home, :environment]
WEEKDAY_SYMBOLS = [:sunday, :monday, :tuesday, :wednesday, :thursday, :friday, :saturday]
-
+
CRON_PATTERN = /\A([-0-9*,\/]+)\s([-0-9*,\/]+)\s([-0-9*,\/]+)\s([-0-9*,\/]+|[a-zA-Z]{3})\s([-0-9*,\/]+|[a-zA-Z]{3})\s(.*)/
SPECIAL_PATTERN = /\A(@(#{SPECIAL_TIME_VALUES.join('|')}))\s(.*)/
ENV_PATTERN = /\A(\S+)=(\S*)/
diff --git a/lib/chef/provider/deploy/revision.rb b/lib/chef/provider/deploy/revision.rb
index c98c1e5c75..62aa0e87f6 100644
--- a/lib/chef/provider/deploy/revision.rb
+++ b/lib/chef/provider/deploy/revision.rb
@@ -27,6 +27,8 @@ class Chef
class Provider
class Deploy
class Revision < Chef::Provider::Deploy
+ provides :deploy_revision
+ provides :deploy_branch
def all_releases
sorted_releases
diff --git a/lib/chef/provider/deploy/timestamped.rb b/lib/chef/provider/deploy/timestamped.rb
index ce921161e0..ba3f6683f0 100644
--- a/lib/chef/provider/deploy/timestamped.rb
+++ b/lib/chef/provider/deploy/timestamped.rb
@@ -20,6 +20,8 @@ class Chef
class Provider
class Deploy
class Timestamped < Chef::Provider::Deploy
+ provides :timestamped_deploy
+ provides :deploy
protected
diff --git a/lib/chef/provider/directory.rb b/lib/chef/provider/directory.rb
index 067737b9d4..c9c3d466b9 100644
--- a/lib/chef/provider/directory.rb
+++ b/lib/chef/provider/directory.rb
@@ -27,6 +27,8 @@ class Chef
class Provider
class Directory < Chef::Provider::File
+ provides :directory
+
def whyrun_supported?
true
end
diff --git a/lib/chef/provider/dsc_script.rb b/lib/chef/provider/dsc_script.rb
index a70f4b5048..5db50e74b3 100644
--- a/lib/chef/provider/dsc_script.rb
+++ b/lib/chef/provider/dsc_script.rb
@@ -24,6 +24,9 @@ require 'chef/util/path_helper'
class Chef
class Provider
class DscScript < Chef::Provider
+
+ provides :dsc_script, os: "windows"
+
def initialize(dsc_resource, run_context)
super(dsc_resource, run_context)
@dsc_resource = dsc_resource
diff --git a/lib/chef/provider/erl_call.rb b/lib/chef/provider/erl_call.rb
index cdd494a243..f5855bcce6 100644
--- a/lib/chef/provider/erl_call.rb
+++ b/lib/chef/provider/erl_call.rb
@@ -25,6 +25,8 @@ class Chef
class ErlCall < Chef::Provider
include Chef::Mixin::Command
+ provides :erl_call
+
def initialize(node, new_resource)
super(node, new_resource)
end
diff --git a/lib/chef/provider/execute.rb b/lib/chef/provider/execute.rb
index 54632c0684..48b2a344d1 100644
--- a/lib/chef/provider/execute.rb
+++ b/lib/chef/provider/execute.rb
@@ -23,6 +23,8 @@ class Chef
class Provider
class Execute < Chef::Provider
+ provides :execute
+
def load_current_resource
true
end
diff --git a/lib/chef/provider/file.rb b/lib/chef/provider/file.rb
index 256248f240..a9390cc45c 100644
--- a/lib/chef/provider/file.rb
+++ b/lib/chef/provider/file.rb
@@ -54,6 +54,8 @@ class Chef
include Chef::Deprecation::Provider::File
add_deprecation_warnings_for(Chef::Deprecation::Provider::File.instance_methods)
+ provides :file
+
attr_reader :deployment_strategy
attr_accessor :needs_creating
diff --git a/lib/chef/provider/git.rb b/lib/chef/provider/git.rb
index 2ef119e839..8418f22933 100644
--- a/lib/chef/provider/git.rb
+++ b/lib/chef/provider/git.rb
@@ -25,6 +25,8 @@ class Chef
class Provider
class Git < Chef::Provider
+ provides :git
+
def whyrun_supported?
true
end
diff --git a/lib/chef/provider/http_request.rb b/lib/chef/provider/http_request.rb
index ba54b10195..61aff434ed 100644
--- a/lib/chef/provider/http_request.rb
+++ b/lib/chef/provider/http_request.rb
@@ -23,6 +23,8 @@ class Chef
class Provider
class HttpRequest < Chef::Provider
+ provides :http_request
+
attr_accessor :http
def whyrun_supported?
diff --git a/lib/chef/provider/link.rb b/lib/chef/provider/link.rb
index 639dc4f3ff..417d6a21b0 100644
--- a/lib/chef/provider/link.rb
+++ b/lib/chef/provider/link.rb
@@ -28,6 +28,8 @@ class Chef
class Provider
class Link < Chef::Provider
+ provides :link
+
include Chef::Mixin::EnforceOwnershipAndPermissions
include Chef::Mixin::FileClass
diff --git a/lib/chef/provider/log.rb b/lib/chef/provider/log.rb
index 9379ceeefa..40eaf0aa28 100644
--- a/lib/chef/provider/log.rb
+++ b/lib/chef/provider/log.rb
@@ -25,6 +25,8 @@ class Chef
# Chef log provider, allows logging to chef's logs from recipes
class ChefLog < Chef::Provider
+ provides :log
+
def whyrun_supported?
true
end
diff --git a/lib/chef/provider/package/aix.rb b/lib/chef/provider/package/aix.rb
index da3e6d1684..88de4679ba 100644
--- a/lib/chef/provider/package/aix.rb
+++ b/lib/chef/provider/package/aix.rb
@@ -26,6 +26,8 @@ class Chef
class Package
class Aix < Chef::Provider::Package
+ provides :bff_package, os: "aix"
+
include Chef::Mixin::GetSourceFromPackage
def define_resource_requirements
diff --git a/lib/chef/provider/package/apt.rb b/lib/chef/provider/package/apt.rb
index 0d91d0d1f0..eb2c038eaa 100644
--- a/lib/chef/provider/package/apt.rb
+++ b/lib/chef/provider/package/apt.rb
@@ -25,6 +25,8 @@ class Chef
class Package
class Apt < Chef::Provider::Package
+ provides :apt_package, os: "linux"
+
attr_accessor :is_virtual_package
def load_current_resource
diff --git a/lib/chef/provider/package/dpkg.rb b/lib/chef/provider/package/dpkg.rb
index a1f1c797b1..3a9cecc660 100644
--- a/lib/chef/provider/package/dpkg.rb
+++ b/lib/chef/provider/package/dpkg.rb
@@ -30,6 +30,8 @@ class Chef
DPKG_INSTALLED = /^Status: install ok installed/
DPKG_VERSION = /^Version: (.+)$/
+ provides :dpkg_package, os: "linux"
+
include Chef::Mixin::GetSourceFromPackage
def define_resource_requirements
diff --git a/lib/chef/provider/package/easy_install.rb b/lib/chef/provider/package/easy_install.rb
index 2af8a72e61..90727b738d 100644
--- a/lib/chef/provider/package/easy_install.rb
+++ b/lib/chef/provider/package/easy_install.rb
@@ -25,6 +25,8 @@ class Chef
class Package
class EasyInstall < Chef::Provider::Package
+ provides :easy_install_package
+
def install_check(name)
check = false
diff --git a/lib/chef/provider/package/homebrew.rb b/lib/chef/provider/package/homebrew.rb
index a9aeea1415..822f4c8a42 100644
--- a/lib/chef/provider/package/homebrew.rb
+++ b/lib/chef/provider/package/homebrew.rb
@@ -25,7 +25,11 @@ class Chef
class Provider
class Package
class Homebrew < Chef::Provider::Package
+
+ provides :homebrew_package, os: "mac_os_x"
+
include Chef::Mixin::HomebrewUser
+
def load_current_resource
self.current_resource = Chef::Resource::Package.new(new_resource.name)
current_resource.package_name(new_resource.package_name)
diff --git a/lib/chef/provider/package/ips.rb b/lib/chef/provider/package/ips.rb
index 4090507303..87022d770a 100644
--- a/lib/chef/provider/package/ips.rb
+++ b/lib/chef/provider/package/ips.rb
@@ -27,6 +27,8 @@ class Chef
class Package
class Ips < Chef::Provider::Package
+ provides :ips_package, os: "solaris2"
+
attr_accessor :virtual
def define_resource_requirements
diff --git a/lib/chef/provider/package/macports.rb b/lib/chef/provider/package/macports.rb
index 05247e6d31..cd142eca42 100644
--- a/lib/chef/provider/package/macports.rb
+++ b/lib/chef/provider/package/macports.rb
@@ -2,6 +2,9 @@ class Chef
class Provider
class Package
class Macports < Chef::Provider::Package
+
+ provides :macports_package, os: "mac_os_x"
+
def load_current_resource
@current_resource = Chef::Resource::Package.new(@new_resource.name)
@current_resource.package_name(@new_resource.package_name)
diff --git a/lib/chef/provider/package/pacman.rb b/lib/chef/provider/package/pacman.rb
index a9ff0edf7f..85c0208d76 100644
--- a/lib/chef/provider/package/pacman.rb
+++ b/lib/chef/provider/package/pacman.rb
@@ -25,6 +25,8 @@ class Chef
class Package
class Pacman < Chef::Provider::Package
+ provides :pacman_package, os: "linux"
+
def load_current_resource
@current_resource = Chef::Resource::Package.new(@new_resource.name)
@current_resource.package_name(@new_resource.package_name)
diff --git a/lib/chef/provider/package/paludis.rb b/lib/chef/provider/package/paludis.rb
index f363b38e50..407e0d0110 100644
--- a/lib/chef/provider/package/paludis.rb
+++ b/lib/chef/provider/package/paludis.rb
@@ -24,6 +24,8 @@ class Chef
class Package
class Paludis < Chef::Provider::Package
+ provides :paludis_package, os: "linux"
+
def load_current_resource
@current_resource = Chef::Resource::Package.new(@new_resource.package_name)
@current_resource.package_name(@new_resource.package_name)
@@ -45,7 +47,7 @@ class Chef
@current_resource.version(res[2])
else
@candidate_version = res[2]
- @current_resource.version(nil)
+ @current_resource.version(nil)
end
end
end
diff --git a/lib/chef/provider/package/rpm.rb b/lib/chef/provider/package/rpm.rb
index c0a6444252..131587e066 100644
--- a/lib/chef/provider/package/rpm.rb
+++ b/lib/chef/provider/package/rpm.rb
@@ -25,6 +25,8 @@ class Chef
class Package
class Rpm < Chef::Provider::Package
+ provides :rpm_package, os: [ "linux", "aix" ]
+
include Chef::Mixin::GetSourceFromPackage
def define_resource_requirements
diff --git a/lib/chef/provider/package/rubygems.rb b/lib/chef/provider/package/rubygems.rb
index 6c7e1c066e..3c0ca40693 100644
--- a/lib/chef/provider/package/rubygems.rb
+++ b/lib/chef/provider/package/rubygems.rb
@@ -359,6 +359,9 @@ class Chef
Chef::Log.logger
end
+ provides :chef_gem
+ provides :gem_package
+
include Chef::Mixin::GetSourceFromPackage
def initialize(new_resource, run_context=nil)
diff --git a/lib/chef/provider/package/smartos.rb b/lib/chef/provider/package/smartos.rb
index 19a6b9efef..7cef91953a 100644
--- a/lib/chef/provider/package/smartos.rb
+++ b/lib/chef/provider/package/smartos.rb
@@ -29,6 +29,8 @@ class Chef
class SmartOS < Chef::Provider::Package
attr_accessor :is_virtual_package
+ provides :smartos_package, os: "solaris2", platform_family: "smartos"
+
def load_current_resource
Chef::Log.debug("#{@new_resource} loading current resource")
@current_resource = Chef::Resource::Package.new(@new_resource.name)
diff --git a/lib/chef/provider/package/solaris.rb b/lib/chef/provider/package/solaris.rb
index 19f844b66a..53dd00dd07 100644
--- a/lib/chef/provider/package/solaris.rb
+++ b/lib/chef/provider/package/solaris.rb
@@ -27,6 +27,8 @@ class Chef
include Chef::Mixin::GetSourceFromPackage
+ provides :solaris_package, os: "solaris2"
+
# def initialize(*args)
# super
# @current_resource = Chef::Resource::Package.new(@new_resource.name)
diff --git a/lib/chef/provider/package/yum.rb b/lib/chef/provider/package/yum.rb
index e77319c254..505f5fd6a3 100644
--- a/lib/chef/provider/package/yum.rb
+++ b/lib/chef/provider/package/yum.rb
@@ -29,6 +29,8 @@ class Chef
class Package
class Yum < Chef::Provider::Package
+ provides :yum_package, os: "linux"
+
class RPMUtils
class << self
diff --git a/lib/chef/provider/remote_directory.rb b/lib/chef/provider/remote_directory.rb
index 5bd1cb5493..9a7416e318 100644
--- a/lib/chef/provider/remote_directory.rb
+++ b/lib/chef/provider/remote_directory.rb
@@ -32,6 +32,8 @@ class Chef
class Provider
class RemoteDirectory < Chef::Provider::Directory
+ provides :remote_directory
+
include Chef::Mixin::FileClass
def action_create
@@ -63,7 +65,7 @@ class Chef
def ls(path)
files = Dir.glob(::File.join(Chef::Util::PathHelper.escape_glob(path), '**', '*'),
::File::FNM_DOTMATCH)
-
+
# Remove current directory and previous directory
files.reject! do |name|
basename = Pathname.new(name).basename().to_s
diff --git a/lib/chef/provider/route.rb b/lib/chef/provider/route.rb
index 208a4f4139..72a5029a94 100644
--- a/lib/chef/provider/route.rb
+++ b/lib/chef/provider/route.rb
@@ -24,6 +24,8 @@ require 'ipaddr'
class Chef::Provider::Route < Chef::Provider
include Chef::Mixin::Command
+ provides :route
+
attr_accessor :is_running
MASK = {'0.0.0.0' => '0',
diff --git a/lib/chef/provider/ruby_block.rb b/lib/chef/provider/ruby_block.rb
index b0d94a3f8d..eb93fd5708 100644
--- a/lib/chef/provider/ruby_block.rb
+++ b/lib/chef/provider/ruby_block.rb
@@ -20,6 +20,8 @@
class Chef
class Provider
class RubyBlock < Chef::Provider
+ provides :ruby_block
+
def whyrun_supported?
true
end
diff --git a/lib/chef/provider/script.rb b/lib/chef/provider/script.rb
index 4aacf4f524..1615517553 100644
--- a/lib/chef/provider/script.rb
+++ b/lib/chef/provider/script.rb
@@ -22,6 +22,12 @@ require 'chef/provider/execute'
class Chef
class Provider
class Script < Chef::Provider::Execute
+ provides :bash
+ provides :csh
+ provides :perl
+ provides :python
+ provides :ruby
+ provides :script
def initialize(new_resource, run_context)
super
diff --git a/lib/chef/provider/service/arch.rb b/lib/chef/provider/service/arch.rb
index 9be5fb6fe3..888fb3fdf5 100644
--- a/lib/chef/provider/service/arch.rb
+++ b/lib/chef/provider/service/arch.rb
@@ -20,6 +20,12 @@ require 'chef/provider/service/init'
class Chef::Provider::Service::Arch < Chef::Provider::Service::Init
+ provides :service, platform_family: "arch"
+
+ def self.supports?(resource, action)
+ ::File.exist?("/etc/rc.d/#{resource.service_name}")
+ end
+
def initialize(new_resource, run_context)
super
@init_command = "/etc/rc.d/#{@new_resource.service_name}"
diff --git a/lib/chef/provider/service/debian.rb b/lib/chef/provider/service/debian.rb
index 1ebef90349..25b1960b26 100644
--- a/lib/chef/provider/service/debian.rb
+++ b/lib/chef/provider/service/debian.rb
@@ -25,13 +25,19 @@ class Chef
UPDATE_RC_D_ENABLED_MATCHES = /\/rc[\dS].d\/S|not installed/i
UPDATE_RC_D_PRIORITIES = /\/rc([\dS]).d\/([SK])(\d\d)/i
+ provides :service, platform_family: "debian"
+
+ def self.supports?(resource, action)
+ Chef::Platform::ServiceHelpers.service_resource_providers.include?(:debian)
+ end
+
def load_current_resource
super
@priority_success = true
@rcd_status = nil
- @current_resource.priority(get_priority)
- @current_resource.enabled(service_currently_enabled?(@current_resource.priority))
- @current_resource
+ current_resource.priority(get_priority)
+ current_resource.enabled(service_currently_enabled?(current_resource.priority))
+ current_resource
end
def define_resource_requirements
@@ -47,7 +53,7 @@ class Chef
requirements.assert(:all_actions) do |a|
a.assertion { @priority_success }
- a.failure_message Chef::Exceptions::Service, "/usr/sbin/update-rc.d -n -f #{@current_resource.service_name} failed - #{@rcd_status.inspect}"
+ a.failure_message Chef::Exceptions::Service, "/usr/sbin/update-rc.d -n -f #{current_resource.service_name} failed - #{@rcd_status.inspect}"
# This can happen if the service is not yet installed,so we'll fake it.
a.whyrun ["Unable to determine priority of service, assuming service would have been correctly installed earlier in the run.",
"Assigning temporary priorities to continue.",
@@ -59,7 +65,7 @@ class Chef
"3"=>[:start, "20"],
"4"=>[:start, "20"],
"5"=>[:start, "20"]}
- @current_resource.priority(temp_priorities)
+ current_resource.priority(temp_priorities)
end
end
end
@@ -67,7 +73,7 @@ class Chef
def get_priority
priority = {}
- @rcd_status = popen4("/usr/sbin/update-rc.d -n -f #{@current_resource.service_name} remove") do |pid, stdin, stdout, stderr|
+ @rcd_status = popen4("/usr/sbin/update-rc.d -n -f #{current_resource.service_name} remove") do |pid, stdin, stdout, stderr|
[stdout, stderr].each do |iop|
iop.each_line do |line|
@@ -99,7 +105,7 @@ class Chef
def service_currently_enabled?(priority)
enabled = false
priority.each { |runlevel, arguments|
- Chef::Log.debug("#{@new_resource} runlevel #{runlevel}, action #{arguments[0]}, priority #{arguments[1]}")
+ Chef::Log.debug("#{new_resource} runlevel #{runlevel}, action #{arguments[0]}, priority #{arguments[1]}")
# if we are in a update-rc.d default startup runlevel && we start in this runlevel
if %w[ 1 2 3 4 5 S ].include?(runlevel) && arguments[0] == :start
enabled = true
@@ -111,63 +117,63 @@ class Chef
# Override method from parent to ensure priority is up-to-date
def action_enable
- if @new_resource.priority.nil?
+ if new_resource.priority.nil?
priority_ok = true
else
- priority_ok = @current_resource.priority == @new_resource.priority
+ priority_ok = @current_resource.priority == new_resource.priority
end
- if @current_resource.enabled and priority_ok
- Chef::Log.debug("#{@new_resource} already enabled - nothing to do")
+ if current_resource.enabled and priority_ok
+ Chef::Log.debug("#{new_resource} already enabled - nothing to do")
else
- converge_by("enable service #{@new_resource}") do
+ converge_by("enable service #{new_resource}") do
enable_service
- Chef::Log.info("#{@new_resource} enabled")
+ Chef::Log.info("#{new_resource} enabled")
end
end
load_new_resource_state
- @new_resource.enabled(true)
+ new_resource.enabled(true)
end
def enable_service
- if @new_resource.priority.is_a? Integer
- shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
- shell_out!("/usr/sbin/update-rc.d #{@new_resource.service_name} defaults #{@new_resource.priority} #{100 - @new_resource.priority}")
- elsif @new_resource.priority.is_a? Hash
+ if new_resource.priority.is_a? Integer
+ shell_out!("/usr/sbin/update-rc.d -f #{new_resource.service_name} remove")
+ shell_out!("/usr/sbin/update-rc.d #{new_resource.service_name} defaults #{new_resource.priority} #{100 - new_resource.priority}")
+ elsif new_resource.priority.is_a? Hash
# we call the same command regardless of we're enabling or disabling
# users passing a Hash are responsible for setting their own start priorities
set_priority
else # No priority, go with update-rc.d defaults
- shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
- shell_out!("/usr/sbin/update-rc.d #{@new_resource.service_name} defaults")
+ shell_out!("/usr/sbin/update-rc.d -f #{new_resource.service_name} remove")
+ shell_out!("/usr/sbin/update-rc.d #{new_resource.service_name} defaults")
end
end
def disable_service
- if @new_resource.priority.is_a? Integer
+ if new_resource.priority.is_a? Integer
# Stop processes in reverse order of start using '100 - start_priority'
- shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
- shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} stop #{100 - @new_resource.priority} 2 3 4 5 .")
- elsif @new_resource.priority.is_a? Hash
+ shell_out!("/usr/sbin/update-rc.d -f #{new_resource.service_name} remove")
+ shell_out!("/usr/sbin/update-rc.d -f #{new_resource.service_name} stop #{100 - new_resource.priority} 2 3 4 5 .")
+ elsif new_resource.priority.is_a? Hash
# we call the same command regardless of we're enabling or disabling
# users passing a Hash are responsible for setting their own stop priorities
set_priority
else
# no priority, using '100 - 20 (update-rc.d default)' to stop in reverse order of start
- shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
- shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} stop 80 2 3 4 5 .")
+ shell_out!("/usr/sbin/update-rc.d -f #{new_resource.service_name} remove")
+ shell_out!("/usr/sbin/update-rc.d -f #{new_resource.service_name} stop 80 2 3 4 5 .")
end
end
def set_priority
args = ""
- @new_resource.priority.each do |level, o|
+ new_resource.priority.each do |level, o|
action = o[0]
priority = o[1]
args += "#{action} #{priority} #{level} . "
end
- shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
- shell_out!("/usr/sbin/update-rc.d #{@new_resource.service_name} #{args}")
+ shell_out!("/usr/sbin/update-rc.d -f #{new_resource.service_name} remove")
+ shell_out!("/usr/sbin/update-rc.d #{new_resource.service_name} #{args}")
end
end
end
diff --git a/lib/chef/provider/service/freebsd.rb b/lib/chef/provider/service/freebsd.rb
index 08d58232e1..e4a456ac25 100644
--- a/lib/chef/provider/service/freebsd.rb
+++ b/lib/chef/provider/service/freebsd.rb
@@ -27,6 +27,10 @@ class Chef
attr_reader :enabled_state_found
+ provides :service, os: [ "freebsd", "netbsd" ]
+
+ include Chef::Mixin::ShellOut
+
def initialize(new_resource, run_context)
super
@enabled_state_found = false
diff --git a/lib/chef/provider/service/gentoo.rb b/lib/chef/provider/service/gentoo.rb
index e2dff10994..3dab920f06 100644
--- a/lib/chef/provider/service/gentoo.rb
+++ b/lib/chef/provider/service/gentoo.rb
@@ -22,6 +22,9 @@ require 'chef/mixin/command'
require 'chef/util/path_helper'
class Chef::Provider::Service::Gentoo < Chef::Provider::Service::Init
+
+ provides :service, platform_family: "gentoo"
+
def load_current_resource
@new_resource.supports[:status] = true
diff --git a/lib/chef/provider/service/init.rb b/lib/chef/provider/service/init.rb
index 5d8bb5bb38..ab40a720f6 100644
--- a/lib/chef/provider/service/init.rb
+++ b/lib/chef/provider/service/init.rb
@@ -26,6 +26,8 @@ class Chef
attr_accessor :init_command
+ provides :service, os: "!windows"
+
def initialize(new_resource, run_context)
super
@init_command = "/etc/init.d/#{@new_resource.service_name}"
diff --git a/lib/chef/provider/service/insserv.rb b/lib/chef/provider/service/insserv.rb
index 1ee817707a..df5a162a45 100644
--- a/lib/chef/provider/service/insserv.rb
+++ b/lib/chef/provider/service/insserv.rb
@@ -24,26 +24,32 @@ class Chef
class Service
class Insserv < Chef::Provider::Service::Init
+ provides :service, os: "linux"
+
+ def self.supports?(resource, action)
+ Chef::Platform::ServiceHelpers.service_resource_providers.include?(:insserv)
+ end
+
def load_current_resource
super
- # Look for a /etc/rc.*/SnnSERVICE link to signifiy that the service would be started in a runlevel
- if Dir.glob("/etc/rc**/S*#{Chef::Util::PathHelper.escape_glob(@current_resource.service_name)}").empty?
- @current_resource.enabled false
+ # Look for a /etc/rc.*/SnnSERVICE link to signify that the service would be started in a runlevel
+ if Dir.glob("/etc/rc**/S*#{Chef::Util::PathHelper.escape_glob(current_resource.service_name)}").empty?
+ current_resource.enabled false
else
- @current_resource.enabled true
+ current_resource.enabled true
end
- @current_resource
+ current_resource
end
def enable_service()
- shell_out!("/sbin/insserv -r -f #{@new_resource.service_name}")
- shell_out!("/sbin/insserv -d -f #{@new_resource.service_name}")
+ shell_out!("/sbin/insserv -r -f #{new_resource.service_name}")
+ shell_out!("/sbin/insserv -d -f #{new_resource.service_name}")
end
def disable_service()
- shell_out!("/sbin/insserv -r -f #{@new_resource.service_name}")
+ shell_out!("/sbin/insserv -r -f #{new_resource.service_name}")
end
end
end
diff --git a/lib/chef/provider/service/invokercd.rb b/lib/chef/provider/service/invokercd.rb
index e6afa7272a..c7472211bc 100644
--- a/lib/chef/provider/service/invokercd.rb
+++ b/lib/chef/provider/service/invokercd.rb
@@ -23,6 +23,12 @@ class Chef
class Service
class Invokercd < Chef::Provider::Service::Init
+ provides :service, platform_family: "debian"
+
+ def self.supports?(resource, action)
+ Chef::Platform::ServiceHelpers.service_resource_providers.include?(:invokerc)
+ end
+
def initialize(new_resource, run_context)
super
@init_command = "/usr/sbin/invoke-rc.d #{@new_resource.service_name}"
diff --git a/lib/chef/provider/service/macosx.rb b/lib/chef/provider/service/macosx.rb
index ad1535327b..10ad1aa29d 100644
--- a/lib/chef/provider/service/macosx.rb
+++ b/lib/chef/provider/service/macosx.rb
@@ -26,6 +26,8 @@ class Chef
class Service
class Macosx < Chef::Provider::Service::Simple
+ provides :service, os: "darwin"
+
def self.gather_plist_dirs
locations = %w{/Library/LaunchAgents
/Library/LaunchDaemons
diff --git a/lib/chef/provider/service/redhat.rb b/lib/chef/provider/service/redhat.rb
index 7a7b2a1c40..90744ae268 100644
--- a/lib/chef/provider/service/redhat.rb
+++ b/lib/chef/provider/service/redhat.rb
@@ -26,11 +26,17 @@ class Chef
CHKCONFIG_ON = /\d:on/
CHKCONFIG_MISSING = /No such/
+ provides :service, platform_family: [ "rhel", "fedora", "suse" ]
+
+ def self.supports?(resource, action)
+ Chef::Platform::ServiceHelpers.service_resource_providers.include?(:redhat)
+ end
+
def initialize(new_resource, run_context)
super
- @init_command = "/sbin/service #{@new_resource.service_name}"
- @new_resource.supports[:status] = true
- @service_missing = false
+ @init_command = "/sbin/service #{@new_resource.service_name}"
+ @new_resource.supports[:status] = true
+ @service_missing = false
end
def define_resource_requirements
diff --git a/lib/chef/provider/service/simple.rb b/lib/chef/provider/service/simple.rb
index bd51d15f84..ee403ee163 100644
--- a/lib/chef/provider/service/simple.rb
+++ b/lib/chef/provider/service/simple.rb
@@ -25,6 +25,8 @@ class Chef
class Service
class Simple < Chef::Provider::Service
+ # this must be subclassed to be useful so does not directly implement :service
+
attr_reader :status_load_success
def load_current_resource
diff --git a/lib/chef/provider/service/solaris.rb b/lib/chef/provider/service/solaris.rb
index f0584dcf6d..eaea6bb1ab 100644
--- a/lib/chef/provider/service/solaris.rb
+++ b/lib/chef/provider/service/solaris.rb
@@ -26,6 +26,8 @@ class Chef
class Solaris < Chef::Provider::Service
attr_reader :maintenance
+ provides :service, os: "solaris2"
+
def initialize(new_resource, run_context=nil)
super
@init_command = "/usr/sbin/svcadm"
diff --git a/lib/chef/provider/service/systemd.rb b/lib/chef/provider/service/systemd.rb
index 31feee65d4..311751ab9a 100644
--- a/lib/chef/provider/service/systemd.rb
+++ b/lib/chef/provider/service/systemd.rb
@@ -20,6 +20,13 @@ require 'chef/resource/service'
require 'chef/provider/service/simple'
class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
+
+ provides :service, os: "linux"
+
+ def self.supports?(resource, action)
+ Chef::Platform::ServiceHelpers.service_resource_providers.include?(:systemd)
+ end
+
def load_current_resource
@current_resource = Chef::Resource::Service.new(@new_resource.name)
@current_resource.service_name(@new_resource.service_name)
diff --git a/lib/chef/provider/service/upstart.rb b/lib/chef/provider/service/upstart.rb
index 670bf9e5f8..41bd850d6a 100644
--- a/lib/chef/provider/service/upstart.rb
+++ b/lib/chef/provider/service/upstart.rb
@@ -27,6 +27,13 @@ class Chef
class Upstart < Chef::Provider::Service::Simple
UPSTART_STATE_FORMAT = /\w+ \(?(\w+)\)?[\/ ](\w+)/
+ provides :service, os: "linux"
+
+ def self.supports?(resource, action)
+ Chef::Platform::ServiceHelpers.service_resource_providers.include?(:upstart) &&
+ Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:upstart)
+ end
+
# Upstart does more than start or stop a service, creating multiple 'states' [1] that a service can be in.
# In chef, when we ask a service to start, we expect it to have started before performing the next step
# since we have top down dependencies. Which is to say we may follow witha resource next that requires
diff --git a/lib/chef/provider/service/windows.rb b/lib/chef/provider/service/windows.rb
index d31aad4c9d..4b1d2079ec 100644
--- a/lib/chef/provider/service/windows.rb
+++ b/lib/chef/provider/service/windows.rb
@@ -25,6 +25,10 @@ end
class Chef::Provider::Service::Windows < Chef::Provider::Service
+ provides :service, os: "windows"
+
+ include Chef::Mixin::ShellOut
+
#Win32::Service.get_start_type
AUTO_START = 'auto start'
MANUAL = 'demand start'
diff --git a/lib/chef/provider/subversion.rb b/lib/chef/provider/subversion.rb
index 6cf31c8ec8..f4a0e6fc13 100644
--- a/lib/chef/provider/subversion.rb
+++ b/lib/chef/provider/subversion.rb
@@ -27,6 +27,8 @@ class Chef
class Provider
class Subversion < Chef::Provider
+ provides :subversion
+
SVN_INFO_PATTERN = /^([\w\s]+): (.+)$/
include Chef::Mixin::Command
diff --git a/lib/chef/provider/template.rb b/lib/chef/provider/template.rb
index 48cc45f3a8..1e759074b9 100644
--- a/lib/chef/provider/template.rb
+++ b/lib/chef/provider/template.rb
@@ -25,6 +25,7 @@ require 'chef/deprecation/warnings'
class Chef
class Provider
class Template < Chef::Provider::File
+ provides :template
extend Chef::Deprecation::Warnings
include Chef::Deprecation::Provider::Template
diff --git a/lib/chef/provider/whyrun_safe_ruby_block.rb b/lib/chef/provider/whyrun_safe_ruby_block.rb
index e5f35debd7..3b95752cc4 100644
--- a/lib/chef/provider/whyrun_safe_ruby_block.rb
+++ b/lib/chef/provider/whyrun_safe_ruby_block.rb
@@ -19,6 +19,8 @@
class Chef
class Provider
class WhyrunSafeRubyBlock < Chef::Provider::RubyBlock
+ provides :whyrun_safe_ruby_block
+
def action_run
@new_resource.block.call
@new_resource.updated_by_last_action(true)
diff --git a/lib/chef/provider_resolver.rb b/lib/chef/provider_resolver.rb
new file mode 100644
index 0000000000..c819b0c87f
--- /dev/null
+++ b/lib/chef/provider_resolver.rb
@@ -0,0 +1,103 @@
+#
+# Author:: Richard Manyanza (<liseki@nyikacraftsmen.com>)
+# Copyright:: Copyright (c) 2014 Richard Manyanza.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/exceptions'
+require 'chef/platform/provider_priority_map'
+
+class Chef
+ class ProviderResolver
+
+ attr_reader :node
+
+ def initialize(node)
+ @node = node
+ end
+
+ # return a deterministically sorted list of Chef::Provider subclasses
+ def providers
+ Chef::Provider.descendants.sort {|a,b| a.to_s <=> b.to_s }
+ end
+
+ def resolve(resource, action)
+ maybe_explicit_provider(resource) ||
+ maybe_dynamic_provider_resolution(resource, action) ||
+ maybe_chef_platform_lookup(resource)
+ end
+
+ private
+
+ # if resource.provider is set, just return one of those objects
+ def maybe_explicit_provider(resource)
+ return nil unless resource.provider
+ resource.provider
+ end
+
+ # try dynamically finding a provider based on querying the providers to see what they support
+ def maybe_dynamic_provider_resolution(resource, action)
+ # this cut only depends on the node value and is going to be static for all nodes
+ # will contain all providers that could possibly support a resource on a node
+ enabled_handlers = providers.select do |klass|
+ klass.provides?(node, resource)
+ end
+
+ # 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}"
+
+ # ask all the enabled providers if they can actually support the resource
+ supported_handlers = enabled_handlers.select do |klass|
+ klass.supports?(resource, action)
+ end
+
+ # what providers were excluded by machine state (late cut)
+ Chef::Log.debug "providers that refused resource #{resource} were: #{enabled_handlers - supported_handlers}"
+ Chef::Log.debug "providers that support resource #{resource} include: #{supported_handlers}"
+
+ handlers = supported_handlers.empty? ? enabled_handlers : supported_handlers
+
+ if handlers.count >= 2
+ priority_list = [ get_provider_priority_map(resource.resource_name, node) ].flatten.compact
+
+ handlers = handlers.sort_by { |x| i = priority_list.index x; i.nil? ? Float::INFINITY : i }
+
+ handlers = [ handlers.first ]
+ end
+
+ Chef::Log.debug "providers that survived replacement include: #{handlers}"
+
+ raise Chef::Exceptions::AmbiguousProviderResolution.new(resource, handlers) if handlers.count >= 2
+
+ return nil if handlers.empty?
+
+ handlers[0]
+ end
+
+ # try the old static lookup of providers by platform
+ def maybe_chef_platform_lookup(resource)
+ Chef::Platform.find_provider_for_node(node, resource)
+ end
+
+ # dep injection hooks
+ def get_provider_priority_map(resource_name, node)
+ provider_priority_map.get(node, resource_name)
+ end
+
+ def provider_priority_map
+ Chef::Platform::ProviderPriorityMap.instance.priority_map
+ end
+ end
+end
diff --git a/lib/chef/providers.rb b/lib/chef/providers.rb
index bceb1f7106..c4f1ce769d 100644
--- a/lib/chef/providers.rb
+++ b/lib/chef/providers.rb
@@ -75,13 +75,13 @@ require 'chef/provider/package/smartos'
require 'chef/provider/package/aix'
require 'chef/provider/service/arch'
-require 'chef/provider/service/debian'
require 'chef/provider/service/freebsd'
require 'chef/provider/service/gentoo'
require 'chef/provider/service/init'
-require 'chef/provider/service/insserv'
require 'chef/provider/service/invokercd'
+require 'chef/provider/service/debian'
require 'chef/provider/service/redhat'
+require 'chef/provider/service/insserv'
require 'chef/provider/service/simple'
require 'chef/provider/service/systemd'
require 'chef/provider/service/upstart'
diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb
index e92ea28c69..c38f36aa72 100644
--- a/lib/chef/resource.rb
+++ b/lib/chef/resource.rb
@@ -27,11 +27,12 @@ require 'chef/guard_interpreter/resource_guard_interpreter'
require 'chef/resource/conditional'
require 'chef/resource/conditional_action_not_nothing'
require 'chef/resource_collection'
-require 'chef/resource_platform_map'
+require 'chef/node_map'
require 'chef/node'
require 'chef/platform'
require 'chef/mixin/deprecation'
+require 'chef/mixin/descendants_tracker'
class Chef
class Resource
@@ -133,6 +134,7 @@ F
include Chef::Mixin::Deprecation
extend Chef::Mixin::ConvertToClassName
+ extend Chef::Mixin::DescendantsTracker
if Module.method(:const_defined?).arity == 1
def self.strict_const_defined?(const)
@@ -144,24 +146,13 @@ F
end
end
- # Track all subclasses of Resource. This is used so names can be looked up
- # when attempting to deserialize from JSON. (See: json_compat)
- def self.resource_classes
- # Using a class variable here ensures we have one variable to track
- # subclasses shared by the entire class hierarchy; without this, each
- # subclass would have its own list of subclasses.
- @@resource_classes ||= []
- end
-
- # Callback when subclass is defined. Adds subclass to list of subclasses.
- def self.inherited(subclass)
- resource_classes << subclass
- end
-
- # Look up a subclass by +class_name+ which should be a string that matches
- # `Subclass.name`
- def self.find_subclass_by_name(class_name)
- resource_classes.first {|c| c.name == class_name }
+ class << self
+ # back-compat
+ # NOTE: that we do not support unregistering classes as descendents like
+ # we used to for LWRP unloading because that was horrible and removed in
+ # Chef-12.
+ alias :resource_classes :descendants
+ alias :find_subclass_by_name :find_descendants_by_name
end
# Set or return the list of "state attributes" implemented by the Resource
@@ -688,16 +679,9 @@ F
end
def provider_for_action(action)
- # leverage new platform => short_name => resource
- # which requires explicitly setting provider in
- # resource class
- if self.provider
- provider = self.provider.new(self, self.run_context)
- provider.action = action
- provider
- else # fall back to old provider resolution
- Chef::Platform.provider_for_resource(self, action)
- end
+ provider = run_context.provider_resolver.resolve(self, action).new(self, run_context)
+ provider.action = action
+ provider
end
def custom_exception_message(e)
@@ -772,8 +756,8 @@ F
@provider_base ||= Chef::Provider
end
- def self.platform_map
- @@platform_map ||= PlatformMap.new
+ def self.node_map
+ @@node_map ||= NodeMap.new
end
# Maps a short_name (and optionally a platform and version) to a
@@ -782,66 +766,55 @@ F
# (I'm looking at you Chef::Resource::Package)
# Ex:
# class WindowsFile < Chef::Resource
- # provides :file, :on_platforms => ["windows"]
+ # provides :file, os: "linux", platform_family: "rhel", platform: "redhat"
+ # provides :file, os: "!windows
+ # provides :file, os: [ "linux", "aix" ]
+ # provides :file, os: "solaris2" do |node|
+ # node['platform_version'].to_f <= 5.11
+ # end
# # ...other stuff
# end
#
- # TODO: 2011-11-02 schisamo - platform_version support
- def self.provides(short_name, opts={})
+ def self.provides(short_name, opts={}, &block)
short_name_sym = short_name
if short_name.kind_of?(String)
+ # YAGNI: this is probably completely unnecessary and can be removed?
+ Chef::Log.warn "[DEPRECATION] Passing a String to Chef::Resource#provides will be removed"
short_name.downcase!
short_name.gsub!(/\s/, "_")
short_name_sym = short_name.to_sym
end
- if opts.has_key?(:on_platforms)
- platforms = [opts[:on_platforms]].flatten
- platforms.each do |p|
- p = :default if :all == p.to_sym
- platform_map.set(
- :platform => p.to_sym,
- :short_name => short_name_sym,
- :resource => self
- )
- end
- else
- platform_map.set(
- :short_name => short_name_sym,
- :resource => self
- )
- end
+ node_map.set(short_name_sym, constantize(self.name), opts, &block)
end
- # Returns a resource based on a short_name anda platform and version.
- #
+ # Returns a resource based on a short_name and node
#
# ==== Parameters
# short_name<Symbol>:: short_name of the resource (ie :directory)
- # platform<Symbol,String>:: platform name
- # version<String>:: platform version
+ # node<Chef::Node>:: Node object to look up platform and version in
#
# === Returns
# <Chef::Resource>:: returns the proper Chef::Resource class
- def self.resource_for_platform(short_name, platform=nil, version=nil)
- platform_map.get(short_name, platform, version)
+ def self.resource_for_node(short_name, node)
+ klass = node_map.get(node, short_name) ||
+ resource_matching_short_name(short_name)
+ raise Chef::Exceptions::NoSuchResourceType.new(short_name, node) if klass.nil?
+ klass
end
- # Returns a resource based on a short_name and a node's
- # platform and version.
- #
+ # Returns the class of a Chef::Resource based on the short name
# ==== Parameters
# short_name<Symbol>:: short_name of the resource (ie :directory)
- # node<Chef::Node>:: Node object to look up platform and version in
#
# === Returns
# <Chef::Resource>:: returns the proper Chef::Resource class
- def self.resource_for_node(short_name, node)
+ def self.resource_matching_short_name(short_name)
begin
- platform, version = Chef::Platform.find_platform_and_version(node)
- rescue ArgumentError
+ rname = convert_to_class_name(short_name.to_s)
+ Chef::Resource.const_get(rname)
+ rescue NameError
+ nil
end
- resource = resource_for_platform(short_name, platform, version)
- resource
end
private
diff --git a/lib/chef/resource/apt_package.rb b/lib/chef/resource/apt_package.rb
index 050cf838ae..f944825ac3 100644
--- a/lib/chef/resource/apt_package.rb
+++ b/lib/chef/resource/apt_package.rb
@@ -23,10 +23,12 @@ class Chef
class Resource
class AptPackage < Chef::Resource::Package
+ provides :apt_package
+ provides :package, os: "linux", platform_family: [ "debian" ]
+
def initialize(name, run_context=nil)
super
@resource_name = :apt_package
- @provider = Chef::Provider::Package::Apt
@default_release = nil
end
diff --git a/lib/chef/resource/bash.rb b/lib/chef/resource/bash.rb
index c56de5fe20..0add0ce501 100644
--- a/lib/chef/resource/bash.rb
+++ b/lib/chef/resource/bash.rb
@@ -17,6 +17,7 @@
#
require 'chef/resource/script'
+require 'chef/provider/script'
class Chef
class Resource
diff --git a/lib/chef/resource/bff_package.rb b/lib/chef/resource/bff_package.rb
index 2d78483e4b..917f0d1d50 100644
--- a/lib/chef/resource/bff_package.rb
+++ b/lib/chef/resource/bff_package.rb
@@ -26,7 +26,6 @@ class Chef
def initialize(name, run_context=nil)
super
@resource_name = :bff_package
- @provider = Chef::Provider::Package::Aix
end
end
diff --git a/lib/chef/resource/breakpoint.rb b/lib/chef/resource/breakpoint.rb
index 83c397bd5b..b2210262d2 100644
--- a/lib/chef/resource/breakpoint.rb
+++ b/lib/chef/resource/breakpoint.rb
@@ -28,7 +28,7 @@ class Chef
super(@name, *args)
@action = "break"
@allowed_actions << :break
- @provider = Chef::Provider::Breakpoint
+ @resource_name = :breakpoint
end
end
end
diff --git a/lib/chef/resource/chef_gem.rb b/lib/chef/resource/chef_gem.rb
index af45cb93e6..b4ead11f1d 100644
--- a/lib/chef/resource/chef_gem.rb
+++ b/lib/chef/resource/chef_gem.rb
@@ -23,13 +23,12 @@ class Chef
class Resource
class ChefGem < Chef::Resource::Package::GemPackage
- provides :chef_gem, :on_platforms => :all
+ provides :chef_gem
def initialize(name, run_context=nil)
super
@resource_name = :chef_gem
@gem_binary = RbConfig::CONFIG['bindir'] + "/gem"
- @provider = Chef::Provider::Package::Rubygems
end
# The chef_gem resources is for installing gems to the current gem environment only for use by Chef cookbooks.
diff --git a/lib/chef/resource/cookbook_file.rb b/lib/chef/resource/cookbook_file.rb
index 2709cf64f4..7be353b648 100644
--- a/lib/chef/resource/cookbook_file.rb
+++ b/lib/chef/resource/cookbook_file.rb
@@ -27,7 +27,7 @@ class Chef
class CookbookFile < Chef::Resource::File
include Chef::Mixin::Securable
- provides :cookbook_file, :on_platforms => :all
+ provides :cookbook_file
def initialize(name, run_context=nil)
super
@@ -36,7 +36,6 @@ class Chef
@action = "create"
@source = ::File.basename(name)
@cookbook = nil
- @provider = Chef::Provider::CookbookFile
end
def source(source_filename=nil)
diff --git a/lib/chef/resource/csh.rb b/lib/chef/resource/csh.rb
index 95aa8afd7a..36659c349b 100644
--- a/lib/chef/resource/csh.rb
+++ b/lib/chef/resource/csh.rb
@@ -17,6 +17,7 @@
#
require 'chef/resource/script'
+require 'chef/provider/script'
class Chef
class Resource
diff --git a/lib/chef/resource/deploy.rb b/lib/chef/resource/deploy.rb
index a08e8aeeea..4252aa230f 100644
--- a/lib/chef/resource/deploy.rb
+++ b/lib/chef/resource/deploy.rb
@@ -77,7 +77,6 @@ class Chef
@shallow_clone = false
@scm_provider = Chef::Provider::Git
@svn_force_export = false
- @provider = Chef::Provider::Deploy::Timestamped
@allowed_actions.push(:force_deploy, :deploy, :rollback)
@additional_remotes = Hash[]
@keep_releases = 5
diff --git a/lib/chef/resource/deploy_revision.rb b/lib/chef/resource/deploy_revision.rb
index ceac26e91a..e144ce2162 100644
--- a/lib/chef/resource/deploy_revision.rb
+++ b/lib/chef/resource/deploy_revision.rb
@@ -22,14 +22,19 @@ class Chef
# Convenience class for using the deploy resource with the revision
# deployment strategy (provider)
class DeployRevision < Chef::Resource::Deploy
+
+ provides :deploy_revision
+
def initialize(*args, &block)
super
@resource_name = :deploy_revision
- @provider = Chef::Provider::Deploy::Revision
end
end
class DeployBranch < Chef::Resource::DeployRevision
+
+ provides :deploy_branch
+
def initialize(*args, &block)
super
@resource_name = :deploy_branch
diff --git a/lib/chef/resource/directory.rb b/lib/chef/resource/directory.rb
index 423c0bbe27..1ab7f0d16d 100644
--- a/lib/chef/resource/directory.rb
+++ b/lib/chef/resource/directory.rb
@@ -32,7 +32,7 @@ class Chef
include Chef::Mixin::Securable
- provides :directory, :on_platforms => :all
+ provides :directory
def initialize(name, run_context=nil)
super
@@ -41,7 +41,6 @@ class Chef
@action = :create
@recursive = false
@allowed_actions.push(:create, :delete)
- @provider = Chef::Provider::Directory
end
def recursive(arg=nil)
diff --git a/lib/chef/resource/dpkg_package.rb b/lib/chef/resource/dpkg_package.rb
index 2fb5b5c249..35a47e8a82 100644
--- a/lib/chef/resource/dpkg_package.rb
+++ b/lib/chef/resource/dpkg_package.rb
@@ -23,10 +23,11 @@ class Chef
class Resource
class DpkgPackage < Chef::Resource::Package
+ provides :dpkg_package, os: "linux"
+
def initialize(name, run_context=nil)
super
@resource_name = :dpkg_package
- @provider = Chef::Provider::Package::Dpkg
end
end
diff --git a/lib/chef/resource/dsc_script.rb b/lib/chef/resource/dsc_script.rb
index 76ac6659d6..82907c25db 100644
--- a/lib/chef/resource/dsc_script.rb
+++ b/lib/chef/resource/dsc_script.rb
@@ -22,13 +22,12 @@ class Chef
class Resource
class DscScript < Chef::Resource
- provides :dsc_script, :on_platforms => ["windows"]
+ provides :dsc_script, platform: "windows"
def initialize(name, run_context=nil)
super
@allowed_actions.push(:run)
@action = :run
- @provider = Chef::Provider::DscScript
@resource_name = :dsc_script
end
diff --git a/lib/chef/resource/easy_install_package.rb b/lib/chef/resource/easy_install_package.rb
index f25e1ac22f..5286e9a289 100644
--- a/lib/chef/resource/easy_install_package.rb
+++ b/lib/chef/resource/easy_install_package.rb
@@ -22,10 +22,11 @@ class Chef
class Resource
class EasyInstallPackage < Chef::Resource::Package
+ provides :easy_install_package
+
def initialize(name, run_context=nil)
super
@resource_name = :easy_install_package
- @provider = Chef::Provider::Package::EasyInstall
end
def easy_install_binary(arg=nil)
diff --git a/lib/chef/resource/erl_call.rb b/lib/chef/resource/erl_call.rb
index 959856af66..24009d51c7 100644
--- a/lib/chef/resource/erl_call.rb
+++ b/lib/chef/resource/erl_call.rb
@@ -18,6 +18,7 @@
#
require 'chef/resource'
+require 'chef/provider/erl_call'
class Chef
class Resource
diff --git a/lib/chef/resource/execute.rb b/lib/chef/resource/execute.rb
index ae118b1c9e..980035b079 100644
--- a/lib/chef/resource/execute.rb
+++ b/lib/chef/resource/execute.rb
@@ -18,6 +18,7 @@
#
require 'chef/resource'
+require 'chef/provider/execute'
class Chef
class Resource
diff --git a/lib/chef/resource/file.rb b/lib/chef/resource/file.rb
index 3c1f4785ef..16491f9bc8 100644
--- a/lib/chef/resource/file.rb
+++ b/lib/chef/resource/file.rb
@@ -19,7 +19,6 @@
require 'chef/resource'
require 'chef/platform/query_helpers'
-require 'chef/provider/file'
require 'chef/mixin/securable'
class Chef
@@ -38,7 +37,7 @@ class Chef
attr_writer :checksum
- provides :file, :on_platforms => :all
+ provides :file
def initialize(name, run_context=nil)
super
@@ -47,7 +46,6 @@ class Chef
@backup = 5
@action = "create"
@allowed_actions.push(:create, :delete, :touch, :create_if_missing)
- @provider = Chef::Provider::File
@atomic_update = Chef::Config[:file_atomic_update]
@force_unlink = false
@manage_symlink_source = nil
diff --git a/lib/chef/resource/freebsd_package.rb b/lib/chef/resource/freebsd_package.rb
index 957c25caf1..9c8db506f8 100644
--- a/lib/chef/resource/freebsd_package.rb
+++ b/lib/chef/resource/freebsd_package.rb
@@ -29,7 +29,7 @@ class Chef
class FreebsdPackage < Chef::Resource::Package
include Chef::Mixin::ShellOut
- provides :package, :on_platforms => ["freebsd"]
+ provides :package, platform: "freebsd"
def initialize(name, run_context=nil)
super
diff --git a/lib/chef/resource/gem_package.rb b/lib/chef/resource/gem_package.rb
index 6def7b6653..631aa13f56 100644
--- a/lib/chef/resource/gem_package.rb
+++ b/lib/chef/resource/gem_package.rb
@@ -22,10 +22,11 @@ class Chef
class Resource
class GemPackage < Chef::Resource::Package
+ provides :gem_package
+
def initialize(name, run_context=nil)
super
@resource_name = :gem_package
- @provider = Chef::Provider::Package::Rubygems
end
def source(arg=nil)
diff --git a/lib/chef/resource/git.rb b/lib/chef/resource/git.rb
index 774bb24f24..7156873315 100644
--- a/lib/chef/resource/git.rb
+++ b/lib/chef/resource/git.rb
@@ -22,10 +22,11 @@ class Chef
class Resource
class Git < Chef::Resource::Scm
+ provides :git
+
def initialize(name, run_context=nil)
super
@resource_name = :git
- @provider = Chef::Provider::Git
@additional_remotes = Hash[]
end
diff --git a/lib/chef/resource/homebrew_package.rb b/lib/chef/resource/homebrew_package.rb
index e1d50c1739..952552e3a8 100644
--- a/lib/chef/resource/homebrew_package.rb
+++ b/lib/chef/resource/homebrew_package.rb
@@ -25,10 +25,11 @@ class Chef
class Resource
class HomebrewPackage < Chef::Resource::Package
+ provides :homebrew_package, os: "mac_os_x"
+
def initialize(name, run_context=nil)
super
@resource_name = :homebrew_package
- @provider = Chef::Provider::Package::Homebrew
@homebrew_user = nil
end
diff --git a/lib/chef/resource/http_request.rb b/lib/chef/resource/http_request.rb
index 47f6286fb4..ccb0a26629 100644
--- a/lib/chef/resource/http_request.rb
+++ b/lib/chef/resource/http_request.rb
@@ -18,6 +18,7 @@
#
require 'chef/resource'
+require 'chef/provider/http_request'
class Chef
class Resource
diff --git a/lib/chef/resource/ips_package.rb b/lib/chef/resource/ips_package.rb
index 88c6e9a538..77b3387946 100644
--- a/lib/chef/resource/ips_package.rb
+++ b/lib/chef/resource/ips_package.rb
@@ -22,10 +22,12 @@ require 'chef/provider/package/ips'
class Chef
class Resource
class IpsPackage < ::Chef::Resource::Package
+
+ provides :ips_package, os: "solaris2"
+
def initialize(name, run_context = nil)
super(name, run_context)
@resource_name = :ips_package
- @provider = Chef::Provider::Package::Ips
@allowed_actions = [ :install, :remove, :upgrade ]
@accept_license = false
end
diff --git a/lib/chef/resource/link.rb b/lib/chef/resource/link.rb
index e53b386a74..8726eded1d 100644
--- a/lib/chef/resource/link.rb
+++ b/lib/chef/resource/link.rb
@@ -25,7 +25,7 @@ class Chef
class Link < Chef::Resource
include Chef::Mixin::Securable
- provides :link, :on_platform => :all
+ provides :link
identity_attr :target_file
@@ -40,7 +40,6 @@ class Chef
@link_type = :symbolic
@target_file = name
@allowed_actions.push(:create, :delete)
- @provider = Chef::Provider::Link
end
def to(arg=nil)
diff --git a/lib/chef/resource/log.rb b/lib/chef/resource/log.rb
index 391c3b5393..7f970a87a4 100644
--- a/lib/chef/resource/log.rb
+++ b/lib/chef/resource/log.rb
@@ -16,6 +16,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+
+require 'chef/resource'
+require 'chef/provider/log'
+
class Chef
class Resource
class Log < Chef::Resource
diff --git a/lib/chef/resource/macports_package.rb b/lib/chef/resource/macports_package.rb
index c9434c9e69..bdc8698155 100644
--- a/lib/chef/resource/macports_package.rb
+++ b/lib/chef/resource/macports_package.rb
@@ -19,10 +19,12 @@
class Chef
class Resource
class MacportsPackage < Chef::Resource::Package
+
+ provides :macports_package, os: "mac_os_x"
+
def initialize(name, run_context=nil)
super
@resource_name = :macports_package
- @provider = Chef::Provider::Package::Macports
end
end
end
diff --git a/lib/chef/resource/pacman_package.rb b/lib/chef/resource/pacman_package.rb
index 2894e415ac..4c45dd004f 100644
--- a/lib/chef/resource/pacman_package.rb
+++ b/lib/chef/resource/pacman_package.rb
@@ -22,10 +22,11 @@ class Chef
class Resource
class PacmanPackage < Chef::Resource::Package
+ provides :pacman_package, os: "linux"
+
def initialize(name, run_context=nil)
super
@resource_name = :pacman_package
- @provider = Chef::Provider::Package::Pacman
end
end
diff --git a/lib/chef/resource/paludis_package.rb b/lib/chef/resource/paludis_package.rb
index fde25e69b3..7eddf8690b 100644
--- a/lib/chef/resource/paludis_package.rb
+++ b/lib/chef/resource/paludis_package.rb
@@ -22,10 +22,12 @@ require 'chef/provider/package/paludis'
class Chef
class Resource
class PaludisPackage < Chef::Resource::Package
+
+ provides :paludis_package, os: "linux"
+
def initialize(name, run_context=nil)
super(name, run_context)
@resource_name = :paludis_package
- @provider = Chef::Provider::Package::Paludis
@allowed_actions = [ :install, :remove, :upgrade ]
@timeout = 3600
end
diff --git a/lib/chef/resource/perl.rb b/lib/chef/resource/perl.rb
index 546f639e1f..c4bdb6e130 100644
--- a/lib/chef/resource/perl.rb
+++ b/lib/chef/resource/perl.rb
@@ -17,6 +17,7 @@
#
require 'chef/resource/script'
+require 'chef/provider/script'
class Chef
class Resource
diff --git a/lib/chef/resource/python.rb b/lib/chef/resource/python.rb
index f340afdb39..b1f23d13ce 100644
--- a/lib/chef/resource/python.rb
+++ b/lib/chef/resource/python.rb
@@ -1,4 +1,3 @@
-#
# Author:: Adam Jacob (<adam@opscode.com>)
# Copyright:: Copyright (c) 2008 Opscode, Inc.
# License:: Apache License, Version 2.0
@@ -17,6 +16,7 @@
#
require 'chef/resource/script'
+require 'chef/provider/script'
class Chef
class Resource
diff --git a/lib/chef/resource/remote_directory.rb b/lib/chef/resource/remote_directory.rb
index 0f7e0eb5de..d4108da47a 100644
--- a/lib/chef/resource/remote_directory.rb
+++ b/lib/chef/resource/remote_directory.rb
@@ -26,7 +26,7 @@ class Chef
class RemoteDirectory < Chef::Resource::Directory
include Chef::Mixin::Securable
- provides :remote_directory, :on_platforms => :all
+ provides :remote_directory
identity_attr :path
@@ -48,7 +48,6 @@ class Chef
@overwrite = true
@allowed_actions.push(:create, :create_if_missing, :delete)
@cookbook = nil
- @provider = Chef::Provider::RemoteDirectory
end
if Chef::Platform.windows?
diff --git a/lib/chef/resource/remote_file.rb b/lib/chef/resource/remote_file.rb
index 6334b1bf44..46516fd3fb 100644
--- a/lib/chef/resource/remote_file.rb
+++ b/lib/chef/resource/remote_file.rb
@@ -26,7 +26,7 @@ class Chef
class RemoteFile < Chef::Resource::File
include Chef::Mixin::Securable
- provides :remote_file, :on_platforms => :all
+ provides :remote_file
def initialize(name, run_context=nil)
super
diff --git a/lib/chef/resource/rpm_package.rb b/lib/chef/resource/rpm_package.rb
index 200a9633ce..8634f1e25d 100644
--- a/lib/chef/resource/rpm_package.rb
+++ b/lib/chef/resource/rpm_package.rb
@@ -23,10 +23,11 @@ class Chef
class Resource
class RpmPackage < Chef::Resource::Package
+ provides :rpm_package, os: [ "linux", "aix" ]
+
def initialize(name, run_context=nil)
super
@resource_name = :rpm_package
- @provider = Chef::Provider::Package::Rpm
end
end
diff --git a/lib/chef/resource/ruby.rb b/lib/chef/resource/ruby.rb
index 605d27b00d..2b2aa0249d 100644
--- a/lib/chef/resource/ruby.rb
+++ b/lib/chef/resource/ruby.rb
@@ -17,6 +17,7 @@
#
require 'chef/resource/script'
+require 'chef/provider/script'
class Chef
class Resource
diff --git a/lib/chef/resource/ruby_block.rb b/lib/chef/resource/ruby_block.rb
index d9b8954a90..a9cbf234cf 100644
--- a/lib/chef/resource/ruby_block.rb
+++ b/lib/chef/resource/ruby_block.rb
@@ -17,6 +17,9 @@
# limitations under the License.
#
+require 'chef/resource'
+require 'chef/provider/ruby_block'
+
class Chef
class Resource
class RubyBlock < Chef::Resource
diff --git a/lib/chef/resource/script.rb b/lib/chef/resource/script.rb
index ff7d23f075..479295922c 100644
--- a/lib/chef/resource/script.rb
+++ b/lib/chef/resource/script.rb
@@ -18,6 +18,7 @@
#
require 'chef/resource/execute'
+require 'chef/provider/script'
class Chef
class Resource
diff --git a/lib/chef/resource/service.rb b/lib/chef/resource/service.rb
index 4d64c3e3f4..36df7c859a 100644
--- a/lib/chef/resource/service.rb
+++ b/lib/chef/resource/service.rb
@@ -46,10 +46,6 @@ class Chef
@action = "nothing"
@supports = { :restart => false, :reload => false, :status => false }
@allowed_actions.push(:enable, :disable, :start, :stop, :restart, :reload)
-
- if(run_context && run_context.node[:init_package] == "systemd")
- @provider = Chef::Provider::Service::Systemd
- end
end
def service_name(arg=nil)
diff --git a/lib/chef/resource/smartos_package.rb b/lib/chef/resource/smartos_package.rb
index 0f4f6d8b0a..99b3b953b0 100644
--- a/lib/chef/resource/smartos_package.rb
+++ b/lib/chef/resource/smartos_package.rb
@@ -23,16 +23,15 @@ class Chef
class Resource
class SmartosPackage < Chef::Resource::Package
+ provides :smartos_package
+ provides :package, os: "solaris2", platform_family: "smartos"
+
def initialize(name, run_context=nil)
super
@resource_name = :smartos_package
- @provider = Chef::Provider::Package::SmartOS
end
end
end
end
-# Backwards compatability
-# @todo remove in Chef 12
-Chef::Resource::SmartOSPackage = Chef::Resource::SmartosPackage
diff --git a/lib/chef/resource/solaris_package.rb b/lib/chef/resource/solaris_package.rb
index 3513703076..94be4693b6 100644
--- a/lib/chef/resource/solaris_package.rb
+++ b/lib/chef/resource/solaris_package.rb
@@ -24,10 +24,16 @@ class Chef
class Resource
class SolarisPackage < Chef::Resource::Package
+ provides :solaris_package
+ provides :package, os: "solaris2", platform_family: "nexentacore"
+ provides :package, os: "solaris2", platform_family: "solaris2" do |node|
+ # on >= Solaris 11 we default to IPS packages instead
+ node[:platform_version].to_f <= 5.10
+ end
+
def initialize(name, run_context=nil)
super
@resource_name = :solaris_package
- @provider = Chef::Provider::Package::Solaris
end
end
diff --git a/lib/chef/resource/subversion.rb b/lib/chef/resource/subversion.rb
index 44158cb080..3afbe0baaf 100644
--- a/lib/chef/resource/subversion.rb
+++ b/lib/chef/resource/subversion.rb
@@ -28,7 +28,6 @@ class Chef
@svn_arguments = '--no-auth-cache'
@svn_info_args = '--no-auth-cache'
@resource_name = :subversion
- @provider = Chef::Provider::Subversion
allowed_actions << :force_export
end
diff --git a/lib/chef/resource/template.rb b/lib/chef/resource/template.rb
index 8473f5b677..8c9607ee07 100644
--- a/lib/chef/resource/template.rb
+++ b/lib/chef/resource/template.rb
@@ -27,7 +27,7 @@ class Chef
class Template < Chef::Resource::File
include Chef::Mixin::Securable
- provides :template, :on_platforms => :all
+ provides :template
attr_reader :inline_helper_blocks
attr_reader :inline_helper_modules
@@ -40,7 +40,6 @@ class Chef
@cookbook = nil
@local = false
@variables = Hash.new
- @provider = Chef::Provider::Template
@inline_helper_blocks = {}
@inline_helper_modules = []
@helper_modules = []
diff --git a/lib/chef/resource/timestamped_deploy.rb b/lib/chef/resource/timestamped_deploy.rb
index 4032ae9854..b2109db85c 100644
--- a/lib/chef/resource/timestamped_deploy.rb
+++ b/lib/chef/resource/timestamped_deploy.rb
@@ -18,13 +18,12 @@
class Chef
class Resource
-
# Convenience class for using the deploy resource with the timestamped
# deployment strategy (provider)
class TimestampedDeploy < Chef::Resource::Deploy
+ provides :timestamped_deploy
def initialize(*args, &block)
super(*args, &block)
- @provider = Chef::Provider::Deploy::Timestamped
end
end
end
diff --git a/lib/chef/resource/whyrun_safe_ruby_block.rb b/lib/chef/resource/whyrun_safe_ruby_block.rb
index ddb9d91dc3..6fa5383f5d 100644
--- a/lib/chef/resource/whyrun_safe_ruby_block.rb
+++ b/lib/chef/resource/whyrun_safe_ruby_block.rb
@@ -23,7 +23,6 @@ class Chef
def initialize(name, run_context=nil)
super
@resource_name = :whyrun_safe_ruby_block
- @provider = Chef::Provider::WhyrunSafeRubyBlock
end
end
diff --git a/lib/chef/resource/windows_package.rb b/lib/chef/resource/windows_package.rb
index 8bd41e0cb7..c563ba5fdc 100644
--- a/lib/chef/resource/windows_package.rb
+++ b/lib/chef/resource/windows_package.rb
@@ -24,12 +24,11 @@ class Chef
class Resource
class WindowsPackage < Chef::Resource::Package
- provides :package, :on_platforms => ["windows"]
+ provides :package, platform: "windows"
def initialize(name, run_context=nil)
super
@allowed_actions = [ :install, :remove ]
- @provider = Chef::Provider::Package::Windows
@resource_name = :windows_package
@source ||= source(@package_name)
@@ -76,4 +75,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/resource/windows_service.rb b/lib/chef/resource/windows_service.rb
index 5ed8e76cbd..49495117ee 100644
--- a/lib/chef/resource/windows_service.rb
+++ b/lib/chef/resource/windows_service.rb
@@ -25,7 +25,7 @@ class Chef
# Until #1773 is resolved, you need to manually specify the windows_service resource
# to use action :configure_startup and attribute startup_type
- # provides :service, :on_platforms => ["windows"]
+ provides :service, platform: "windows"
identity_attr :service_name
@@ -34,7 +34,6 @@ class Chef
def initialize(name, run_context=nil)
super
@resource_name = :windows_service
- @provider = Chef::Provider::Service::Windows
@allowed_actions.push(:configure_startup)
@startup_type = :automatic
end
diff --git a/lib/chef/resource/yum_package.rb b/lib/chef/resource/yum_package.rb
index dff70bcf62..8fbca9b097 100644
--- a/lib/chef/resource/yum_package.rb
+++ b/lib/chef/resource/yum_package.rb
@@ -23,10 +23,12 @@ class Chef
class Resource
class YumPackage < Chef::Resource::Package
+ provides :yum_package
+ provides :package, os: "linux", platform_family: [ "rhel", "fedora" ]
+
def initialize(name, run_context=nil)
super
@resource_name = :yum_package
- @provider = Chef::Provider::Package::Yum
@flush_cache = { :before => false, :after => false }
@allow_downgrade = false
end
diff --git a/lib/chef/resource_platform_map.rb b/lib/chef/resource_platform_map.rb
deleted file mode 100644
index a678f5be4b..0000000000
--- a/lib/chef/resource_platform_map.rb
+++ /dev/null
@@ -1,151 +0,0 @@
-#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/mixin/params_validate'
-require 'chef/mixin/convert_to_class_name'
-
-class Chef
- class Resource
- class PlatformMap
-
- include Chef::Mixin::ParamsValidate
- include Chef::Mixin::ConvertToClassName
-
- attr_reader :map
-
- def initialize(map={:default => {}})
- @map = map
- end
-
- def filter(platform, version)
- resource_map = map[:default].clone
- platform_sym = platform
- if platform.kind_of?(String)
- platform.downcase!
- platform.gsub!(/\s/, "_")
- platform_sym = platform.to_sym
- end
-
- if map.has_key?(platform_sym)
- if map[platform_sym].has_key?(version)
- if map[platform_sym].has_key?(:default)
- resource_map.merge!(map[platform_sym][:default])
- end
- resource_map.merge!(map[platform_sym][version])
- elsif map[platform_sym].has_key?(:default)
- resource_map.merge!(map[platform_sym][:default])
- end
- end
- resource_map
- end
-
- def set(args)
- validate(
- args,
- {
- :platform => {
- :kind_of => Symbol,
- :required => false
- },
- :version => {
- :kind_of => String,
- :required => false
- },
- :short_name => {
- :kind_of => Symbol,
- :required => true
- },
- :resource => {
- :kind_of => [ String, Symbol, Class ],
- :required => true
- }
- }
- )
- if args.has_key?(:platform)
- if args.has_key?(:version)
- if map.has_key?(args[:platform])
- if map[args[:platform]].has_key?(args[:version])
- map[args[:platform]][args[:version]][args[:short_name].to_sym] = args[:resource]
- else
- map[args[:platform]][args[:version]] = {
- args[:short_name].to_sym => args[:resource]
- }
- end
- else
- map[args[:platform]] = {
- args[:version] => {
- args[:short_name].to_sym => args[:resource]
- }
- }
- end
- else
- if map.has_key?(args[:platform])
- if map[args[:platform]].has_key?(:default)
- map[args[:platform]][:default][args[:short_name].to_sym] = args[:resource]
- else
- map[args[:platform]] = { :default => { args[:short_name].to_sym => args[:resource] } }
- end
- else
- map[args[:platform]] = {
- :default => {
- args[:short_name].to_sym => args[:resource]
- }
- }
- end
- end
- else
- if map.has_key?(:default)
- map[:default][args[:short_name].to_sym] = args[:resource]
- else
- map[:default] = {
- args[:short_name].to_sym => args[:resource]
- }
- end
- end
- end
-
- def get(short_name, platform=nil, version=nil)
- resource_klass = platform_resource(short_name, platform, version) ||
- resource_matching_short_name(short_name)
-
- raise Exceptions::NoSuchResourceType, "Cannot find a resource for #{short_name} on #{platform} version #{version}" if resource_klass.nil?
-
- resource_klass
- end
-
- private
-
- def platform_resource(short_name, platform, version)
- pmap = filter(platform, version)
- rtkey = short_name.kind_of?(Chef::Resource) ? short_name.resource_name.to_sym : short_name
-
- pmap.has_key?(rtkey) ? pmap[rtkey] : nil
- end
-
- def resource_matching_short_name(short_name)
- begin
- rname = convert_to_class_name(short_name.to_s)
- Chef::Resource.const_get(rname)
- rescue NameError
- nil
- end
- end
-
- end
- end
-end
diff --git a/lib/chef/run_context.rb b/lib/chef/run_context.rb
index bbe2f9eba0..18d353ac61 100644
--- a/lib/chef/run_context.rb
+++ b/lib/chef/run_context.rb
@@ -18,6 +18,7 @@
# limitations under the License.
require 'chef/resource_collection'
+require 'chef/provider_resolver'
require 'chef/cookbook_version'
require 'chef/node'
require 'chef/role'
@@ -50,6 +51,9 @@ class Chef
# recipes, which is triggered by #load. (See also: CookbookCompiler)
attr_accessor :resource_collection
+ # Chef::ProviderResolver for this run
+ attr_accessor :provider_resolver
+
# A Hash containing the immediate notifications triggered by resources
# during the converge phase of the chef run.
attr_accessor :immediate_notification_collection
@@ -82,8 +86,8 @@ class Chef
@reboot_info = {}
@node.run_context = self
-
@cookbook_compiler = nil
+ @provider_resolver = Chef::ProviderResolver.new(@node)
end
# Triggers the compile phase of the chef run. Implemented by
diff --git a/spec/support/lib/chef/provider/snakeoil.rb b/spec/support/lib/chef/provider/snakeoil.rb
index e9d01f654f..485d37329f 100644
--- a/spec/support/lib/chef/provider/snakeoil.rb
+++ b/spec/support/lib/chef/provider/snakeoil.rb
@@ -19,6 +19,7 @@
class Chef
class Provider
class SnakeOil < Chef::Provider
+
def load_current_resource
true
end
diff --git a/spec/support/lib/chef/resource/zen_follower.rb b/spec/support/lib/chef/resource/zen_follower.rb
index 713f122f06..ddc289e48d 100644
--- a/spec/support/lib/chef/resource/zen_follower.rb
+++ b/spec/support/lib/chef/resource/zen_follower.rb
@@ -22,7 +22,7 @@ class Chef
class Resource
class ZenFollower < Chef::Resource
- provides :follower, :on_platforms => ["zen"]
+ provides :follower, platform: "zen"
def initialize(name, run_context=nil)
@resource_name = :zen_follower
diff --git a/spec/support/shared/unit/resource/static_provider_resolution.rb b/spec/support/shared/unit/resource/static_provider_resolution.rb
new file mode 100644
index 0000000000..147852598a
--- /dev/null
+++ b/spec/support/shared/unit/resource/static_provider_resolution.rb
@@ -0,0 +1,71 @@
+#
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+
+
+#
+# This is for typical "static" provider resolution which maps resources onto
+# providers based only on the node data. Its not really 'static' because it
+# all goes through the Chef::ProviderResolver, but the effective result is
+# a static mapping for the node (unlike the service resource which is
+# complicated).
+#
+def static_provider_resolution(opts={})
+ action = opts[:action]
+ provider_class = opts[:provider]
+ resource_class = opts[:resource]
+ name = opts[:name]
+ os = opts[:os]
+ platform_family = opts[:platform_family]
+ platform_version = opts[:platform_version]
+
+ describe resource_class, "static provider initialization" do
+ let(:node) {
+ node = Chef::Node.new
+ node.automatic_attrs[:os] = os
+ node.automatic_attrs[:platform_family] = platform_family
+ node.automatic_attrs[:platform_version] = platform_version
+ node
+ }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:provider_resolver) { Chef::ProviderResolver.new(node) }
+ let(:run_context) {
+ run_context = Chef::RunContext.new(node, {}, events)
+ run_context.provider_resolver = provider_resolver
+ run_context
+ }
+ let(:resource) { resource_class.new("foo", run_context) }
+
+ it "should return a #{resource_class}" do
+ expect(resource).to be_a_kind_of(resource_class)
+ end
+
+ it "should set the resource_name to #{name}" do
+ expect(resource.resource_name).to eql(name)
+ end
+
+ it "should leave the provider nil" do
+ expect(resource.provider).to eql(nil)
+ end
+
+ it "should resolve to a #{provider_class}" do
+ expect(resource.provider_for_action(action)).to be_a(provider_class)
+ end
+ end
+end
+
diff --git a/spec/unit/node_map_spec.rb b/spec/unit/node_map_spec.rb
new file mode 100644
index 0000000000..fe7372961b
--- /dev/null
+++ b/spec/unit/node_map_spec.rb
@@ -0,0 +1,155 @@
+#
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+require 'chef/node_map'
+
+describe Chef::NodeMap do
+
+ let(:node_map) { Chef::NodeMap.new }
+
+ let(:node) { Chef::Node.new }
+
+ describe "with a bad filter name" do
+ it "should raise an error" do
+ expect{ node_map.set(node, :thing, on_platform_family: 'rhel') }.to raise_error
+ end
+ end
+
+ describe "when no matchers are set at all" do
+ before do
+ node_map.set(:thing, :foo)
+ end
+
+ it "returns the value" do
+ expect(node_map.get(node, :thing)).to eql(:foo)
+ end
+
+ it "returns nil for keys that do not exist" do
+ expect(node_map.get(node, :other_thing)).to eql(nil)
+ end
+ end
+
+ describe "filtering by os" do
+ before do
+ node_map.set(:thing, :foo, os: ["windows"])
+ node_map.set(:thing, :bar, os: "linux")
+ end
+ it "returns the correct value for windows" do
+ allow(node).to receive(:[]).with(:os).and_return("windows")
+ expect(node_map.get(node, :thing)).to eql(:foo)
+ end
+ it "returns the correct value for linux" do
+ allow(node).to receive(:[]).with(:os).and_return("linux")
+ expect(node_map.get(node, :thing)).to eql(:bar)
+ end
+ it "returns nil for a non-matching os" do
+ allow(node).to receive(:[]).with(:os).and_return("freebsd")
+ expect(node_map.get(node, :thing)).to eql(nil)
+ end
+ end
+
+ describe "rejecting an os" do
+ before do
+ node_map.set(:thing, :foo, os: "!windows")
+ end
+ it "returns nil for windows" do
+ allow(node).to receive(:[]).with(:os).and_return("windows")
+ expect(node_map.get(node, :thing)).to eql(nil)
+ end
+ it "returns the correct value for linux" do
+ allow(node).to receive(:[]).with(:os).and_return("linux")
+ expect(node_map.get(node, :thing)).to eql(:foo)
+ end
+ end
+
+ describe "filtering by os and platform_family" do
+ before do
+ node_map.set(:thing, :bar, os: "linux", platform_family: "rhel")
+ end
+
+ it "returns the correct value when both match" do
+ allow(node).to receive(:[]).with(:os).and_return("linux")
+ allow(node).to receive(:[]).with(:platform_family).and_return("rhel")
+ expect(node_map.get(node, :thing)).to eql(:bar)
+ end
+
+ it "returns nil for a non-matching os" do
+ allow(node).to receive(:[]).with(:os).and_return("freebsd")
+ expect(node_map.get(node, :thing)).to eql(nil)
+ end
+
+ it "returns nil when the platform_family does not match" do
+ allow(node).to receive(:[]).with(:os).and_return("linux")
+ allow(node).to receive(:[]).with(:platform_family).and_return("debian")
+ expect(node_map.get(node, :thing)).to eql(nil)
+ end
+ end
+
+ describe "with a block doing platform_version checks" do
+ before do
+ node_map.set(:thing, :foo, platform_family: "rhel") do |node|
+ node[:platform_version].to_i >= 7
+ end
+ end
+
+ it "returns the value when the node matches" do
+ allow(node).to receive(:[]).with(:platform_family).and_return("rhel")
+ allow(node).to receive(:[]).with(:platform_version).and_return("7.0")
+ expect(node_map.get(node, :thing)).to eql(:foo)
+ end
+
+ it "returns nil when the block does not match" do
+ allow(node).to receive(:[]).with(:platform_family).and_return("rhel")
+ allow(node).to receive(:[]).with(:platform_version).and_return("6.4")
+ expect(node_map.get(node, :thing)).to eql(nil)
+ end
+
+ it "returns nil when the platform_family filter does not match" do
+ allow(node).to receive(:[]).with(:platform_family).and_return("debian")
+ allow(node).to receive(:[]).with(:platform_version).and_return("7.0")
+ expect(node_map.get(node, :thing)).to eql(nil)
+ end
+
+ it "returns nil when both do not match" do
+ allow(node).to receive(:[]).with(:platform_family).and_return("debian")
+ allow(node).to receive(:[]).with(:platform_version).and_return("6.0")
+ expect(node_map.get(node, :thing)).to eql(nil)
+ end
+ end
+
+ describe "resource back-compat testing" do
+ 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")
+ expect(node_map.get(node, :chef_gem)).to eql(:foo)
+ end
+ it "should handle :on_platforms => [ 'windows' ]" do
+ node_map.set(:dsc_script, :foo, :on_platforms => [ 'windows' ])
+ allow(node).to receive(:[]).with(:platform).and_return("windows")
+ expect(node_map.get(node, :dsc_script)).to eql(:foo)
+ end
+ it "should handle :on_platform => :all" do
+ node_map.set(:link, :foo, :on_platform => :all)
+ allow(node).to receive(:[]).with(:platform).and_return("windows")
+ expect(node_map.get(node, :link)).to eql(:foo)
+ end
+ end
+
+end
+
diff --git a/spec/unit/provider/log_spec.rb b/spec/unit/provider/log_spec.rb
index a270ee4822..1ecc633ce1 100644
--- a/spec/unit/provider/log_spec.rb
+++ b/spec/unit/provider/log_spec.rb
@@ -32,10 +32,6 @@ describe Chef::Provider::Log::ChefLog do
let(:provider) { Chef::Provider::Log::ChefLog.new(new_resource, run_context) }
- it "should be registered with the default platform hash" do
- expect(Chef::Platform.platforms[:default][:log]).not_to be_nil
- end
-
it "should write the string to the Chef::Log object at default level (info)" do
expect(Chef::Log).to receive(:info).with(log_str).and_return(true)
provider.run_action(:write)
diff --git a/spec/unit/provider/package/apt_spec.rb b/spec/unit/provider/package/apt_spec.rb
index a94b248418..90e9dd6d3f 100644
--- a/spec/unit/provider/package/apt_spec.rb
+++ b/spec/unit/provider/package/apt_spec.rb
@@ -229,7 +229,7 @@ SHOWPKG_STDOUT
@new_resource = nil
@new_resource = Chef::Resource::AptPackage.new("irssi", @run_context)
@new_resource.default_release("lenny-backports")
-
+ @new_resource.provider = @provider
@provider.new_resource = @new_resource
@provider.should_receive(:shell_out!).with(
diff --git a/spec/unit/provider_resolver_spec.rb b/spec/unit/provider_resolver_spec.rb
new file mode 100644
index 0000000000..927cca4f58
--- /dev/null
+++ b/spec/unit/provider_resolver_spec.rb
@@ -0,0 +1,387 @@
+#
+# Author:: Lamont Granquist (<lamont@getchef.com>)
+# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+require 'chef/mixin/convert_to_class_name'
+
+include Chef::Mixin::ConvertToClassName
+
+describe Chef::ProviderResolver do
+
+ let(:node) do
+ node = Chef::Node.new
+ allow(node).to receive(:[]).with(:os).and_return(os)
+ allow(node).to receive(:[]).with(:platform_family).and_return(platform_family)
+ allow(node).to receive(:[]).with(:platform).and_return(platform)
+ allow(node).to receive(:[]).with(:platform_version).and_return(platform_version)
+ allow(node).to receive(:is_a?).and_return(Chef::Node)
+ node
+ end
+
+ let(:provider_resolver) { Chef::ProviderResolver.new(node) }
+
+ let(:action) { :start }
+
+ let(:resolved_provider) { provider_resolver.resolve(resource, action) }
+
+ let(:provider) { nil }
+
+ let(:resource_name) { :service }
+
+ let(:resource) { double(Chef::Resource, provider: provider, resource_name: resource_name) }
+
+ describe "resolving service resource" do
+ def stub_service_providers(*services)
+ services ||= []
+ allow(Chef::Platform::ServiceHelpers).to receive(:service_resource_providers)
+ .and_return(services)
+ end
+
+ def stub_service_configs(*configs)
+ configs ||= []
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return(configs)
+ end
+
+ before do
+ expect(provider_resolver).not_to receive(:maybe_chef_platform_lookup)
+ allow(resource).to receive(:service_name).and_return("ntp")
+ end
+
+ shared_examples_for "a debian platform with upstart and update-rc.d" do
+ before do
+ stub_service_providers(:debian, :invokercd, :upstart)
+ end
+
+ it "when only the SysV init script exists, it returns a Service::Debian provider" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :initd ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Debian)
+ end
+
+ it "when both SysV and Upstart scripts exist, it returns a Service::Upstart provider" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :initd, :upstart ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
+ end
+
+ it "when only the Upstart script exists, it returns a Service::Upstart provider" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :upstart ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
+ end
+
+ it "when both do not exist, it calls the old style provider resolver and returns a Debian Provider" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Debian)
+ end
+ end
+
+ shared_examples_for "a debian platform using the insserv provider" do
+ context "with a default install" do
+ before do
+ stub_service_providers(:debian, :invokercd, :insserv)
+ end
+
+ it "uses the Service::Insserv Provider to manage sysv init scripts" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :initd ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Insserv)
+ end
+ end
+
+ context "when the user has installed upstart" do
+ before do
+ stub_service_providers(:debian, :invokercd, :insserv, :upstart)
+ end
+
+ it "when only the SysV init script exists, it returns a Service::Debian provider" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :initd ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Insserv)
+ end
+
+ it "when both SysV and Upstart scripts exist, it returns a Service::Upstart provider" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :initd, :upstart ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
+ end
+
+ it "when only the Upstart script exists, it returns a Service::Upstart provider" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :upstart ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
+ end
+
+ it "when both do not exist, it calls the old style provider resolver and returns a Debian Provider" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Insserv)
+ end
+ end
+ end
+
+ describe "on Linux" do
+ end
+
+ describe "on Ubuntu 14.04" do
+ let(:os) { "linux" }
+ let(:platform) { "ubuntu" }
+ let(:platform_family) { "debian" }
+ let(:platform_version) { "14.04" }
+
+ it_behaves_like "a debian 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" }
+
+ it_behaves_like "a debian 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" }
+
+ #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" }
+
+ 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
+
+ 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
+ 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
+
+ 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
+ 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
+
+ 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
+ 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
+
+ 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 :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
+ end
+ end
+
+ end
+
+ 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,
+ 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,
+ }
+
+ 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, :http_request, :link, :log, :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)
+ end
+ end
+ end
+
+ unsupported_providers = [
+ :bff_package, :dsc_script, :homebrew_package, :ips_package, :macports_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
+ end
+ end
+end
diff --git a/spec/unit/recipe_spec.rb b/spec/unit/recipe_spec.rb
index cb7581b5fb..0e660dc0cc 100644
--- a/spec/unit/recipe_spec.rb
+++ b/spec/unit/recipe_spec.rb
@@ -119,7 +119,8 @@ describe Chef::Recipe do
describe "should locate platform mapped resources" do
it "locate resource for particular platform" do
- Object.const_set('ShaunTheSheep', Class.new(Chef::Resource){ provides :laughter, :on_platforms => ["television"] })
+ ShaunTheSheep = Class.new(Chef::Resource)
+ ShaunTheSheep.provides :laughter, :on_platforms => ["television"]
node.automatic[:platform] = "television"
node.automatic[:platform_version] = "123"
res = recipe.laughter "timmy"
@@ -128,7 +129,8 @@ describe Chef::Recipe do
end
it "locate a resource for all platforms" do
- Object.const_set("YourMom", Class.new(Chef::Resource){ provides :love_and_caring })
+ YourMom = Class.new(Chef::Resource)
+ YourMom.provides :love_and_caring
res = recipe.love_and_caring "mommy"
res.name.should eql("mommy")
res.kind_of?(YourMom)
@@ -188,16 +190,7 @@ describe Chef::Recipe do
# zen_follower resource has this:
# provides :follower, :on_platforms => ["zen"]
before do
- node.stub(:[]) do |key|
- case key
- when :platform
- :zen
- when :platform_version
- "1.0.0"
- else
- nil
- end
- end
+ node.automatic_attrs[:platform] = "zen"
end
let(:resource_follower) do
diff --git a/spec/unit/resource/apt_package_spec.rb b/spec/unit/resource/apt_package_spec.rb
index 58b007c327..9503e0cbe1 100644
--- a/spec/unit/resource/apt_package_spec.rb
+++ b/spec/unit/resource/apt_package_spec.rb
@@ -17,25 +17,22 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::AptPackage, "initialize" do
+ static_provider_resolution(
+ resource: Chef::Resource::AptPackage,
+ provider: Chef::Provider::Package::Apt,
+ name: :apt_package,
+ action: :install,
+ os: "linux",
+ )
+
before(:each) do
@resource = Chef::Resource::AptPackage.new("foo")
end
- it "should return a Chef::Resource::AptPackage" do
- @resource.should be_a_kind_of(Chef::Resource::AptPackage)
- end
-
- it "should set the resource_name to :apt_package" do
- @resource.resource_name.should eql(:apt_package)
- end
-
- it "should set the provider to Chef::Provider::Package::Apt" do
- @resource.provider.should eql(Chef::Provider::Package::Apt)
- end
-
it "should support default_release" do
@resource.default_release("lenny-backports")
@resource.default_release.should eql("lenny-backports")
diff --git a/spec/unit/resource/breakpoint_spec.rb b/spec/unit/resource/breakpoint_spec.rb
index 412211a038..ed655b84a6 100644
--- a/spec/unit/resource/breakpoint_spec.rb
+++ b/spec/unit/resource/breakpoint_spec.rb
@@ -17,9 +17,17 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::Breakpoint do
+ static_provider_resolution(
+ resource: Chef::Resource::Breakpoint,
+ provider: Chef::Provider::Breakpoint,
+ name: :breakpoint,
+ action: :break,
+ )
+
before do
@breakpoint = Chef::Resource::Breakpoint.new
end
@@ -36,8 +44,4 @@ describe Chef::Resource::Breakpoint do
@breakpoint.name.should match(/breakpoint_spec\.rb\:[\d]{2}\:in \`new\'$/)
end
- it "uses the breakpoint provider" do
- @breakpoint.provider.should == Chef::Provider::Breakpoint
- end
-
end
diff --git a/spec/unit/resource/chef_gem_spec.rb b/spec/unit/resource/chef_gem_spec.rb
index dda65f8741..6a419b3f3b 100644
--- a/spec/unit/resource/chef_gem_spec.rb
+++ b/spec/unit/resource/chef_gem_spec.rb
@@ -18,24 +18,17 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::ChefGem, "initialize" do
- before(:each) do
- @resource = Chef::Resource::ChefGem.new("foo")
- end
-
- it "should return a Chef::Resource::ChefGem" do
- @resource.should be_a_kind_of(Chef::Resource::ChefGem)
- end
-
- it "should set the resource_name to :chef_gem" do
- @resource.resource_name.should eql(:chef_gem)
- end
+ static_provider_resolution(
+ resource: Chef::Resource::ChefGem,
+ provider: Chef::Provider::Package::Rubygems,
+ name: :chef_gem,
+ action: :install,
+ )
- it "should set the provider to Chef::Provider::Package::Rubygems" do
- @resource.provider.should eql(Chef::Provider::Package::Rubygems)
- end
end
describe Chef::Resource::ChefGem, "gem_binary" do
diff --git a/spec/unit/resource/deploy_revision_spec.rb b/spec/unit/resource/deploy_revision_spec.rb
index 1f509992aa..d136aa251e 100644
--- a/spec/unit/resource/deploy_revision_spec.rb
+++ b/spec/unit/resource/deploy_revision_spec.rb
@@ -17,31 +17,26 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::DeployRevision do
- it "defaults to the revision deploy provider" do
- @resource = Chef::Resource::DeployRevision.new("deploy _this_!")
- @resource.provider.should == Chef::Provider::Deploy::Revision
- end
-
- it "has a name of deploy_revision" do
- @resource = Chef::Resource::DeployRevision.new("deploy _this_!")
- @resource.resource_name.should == :deploy_revision
- end
+ static_provider_resolution(
+ resource: Chef::Resource::DeployRevision,
+ provider: Chef::Provider::Deploy::Revision,
+ name: :deploy_revision,
+ action: :deploy,
+ )
end
describe Chef::Resource::DeployBranch do
- it "defaults to the revision deploy provider" do
- @resource = Chef::Resource::DeployBranch.new("deploy _this_!")
- @resource.provider.should == Chef::Provider::Deploy::Revision
- end
-
- it "has a name of deploy_branch" do
- @resource = Chef::Resource::DeployBranch.new("deploy _this_!")
- @resource.resource_name.should == :deploy_branch
- end
+ static_provider_resolution(
+ resource: Chef::Resource::DeployBranch,
+ provider: Chef::Provider::Deploy::Revision,
+ name: :deploy_branch,
+ action: :deploy,
+ )
end
diff --git a/spec/unit/resource/deploy_spec.rb b/spec/unit/resource/deploy_spec.rb
index 7cc25ed41c..914ea19030 100644
--- a/spec/unit/resource/deploy_spec.rb
+++ b/spec/unit/resource/deploy_spec.rb
@@ -17,9 +17,18 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::Deploy do
+ static_provider_resolution(
+ resource: Chef::Resource::Deploy,
+ provider: Chef::Provider::Deploy::Timestamped,
+ name: :deploy,
+ action: :deploy,
+ )
+
+
class << self
def resource_has_a_string_attribute(attr_name)
it "has a String attribute for #{attr_name.to_s}" do
@@ -196,10 +205,6 @@ describe Chef::Resource::Deploy do
@resource.restart.should == restart_like_this
end
- it "defaults to using the Deploy::Timestamped provider" do
- @resource.provider.should == Chef::Provider::Deploy::Timestamped
- end
-
it "allows providers to be set with a full class name" do
@resource.provider Chef::Provider::Deploy::Timestamped
@resource.provider.should == Chef::Provider::Deploy::Timestamped
diff --git a/spec/unit/resource/dpkg_package_spec.rb b/spec/unit/resource/dpkg_package_spec.rb
index 9ef498a577..931e6763bd 100644
--- a/spec/unit/resource/dpkg_package_spec.rb
+++ b/spec/unit/resource/dpkg_package_spec.rb
@@ -17,22 +17,16 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::DpkgPackage, "initialize" do
- before(:each) do
- @resource = Chef::Resource::DpkgPackage.new("foo")
- end
+ static_provider_resolution(
+ resource: Chef::Resource::DpkgPackage,
+ provider: Chef::Provider::Package::Dpkg,
+ name: :dpkg_package,
+ action: :install,
+ os: 'linux',
+ )
- it "should return a Chef::Resource::DpkgPackage" do
- @resource.should be_a_kind_of(Chef::Resource::DpkgPackage)
- end
-
- it "should set the resource_name to :dpkg_package" do
- @resource.resource_name.should eql(:dpkg_package)
- end
-
- it "should set the provider to Chef::Provider::Package::Dpkg" do
- @resource.provider.should eql(Chef::Provider::Package::Dpkg)
- end
end
diff --git a/spec/unit/resource/easy_install_package_spec.rb b/spec/unit/resource/easy_install_package_spec.rb
index 9682c8177b..d3a5f4a0fe 100644
--- a/spec/unit/resource/easy_install_package_spec.rb
+++ b/spec/unit/resource/easy_install_package_spec.rb
@@ -17,30 +17,21 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::EasyInstallPackage, "initialize" do
+ static_provider_resolution(
+ resource: Chef::Resource::EasyInstallPackage,
+ provider: Chef::Provider::Package::EasyInstall,
+ name: :easy_install_package,
+ action: :install,
+ )
+
before(:each) do
@resource = Chef::Resource::EasyInstallPackage.new("foo")
end
- it "should create a new Chef::Resource::EasyInstallPackage" do
- @resource.should be_a_kind_of(Chef::Resource)
- @resource.should be_a_kind_of(Chef::Resource::EasyInstallPackage)
- end
-
- it "should return a Chef::Resource::EasyInstallPackage" do
- @resource.should be_a_kind_of(Chef::Resource::EasyInstallPackage)
- end
-
- it "should set the resource_name to :easy_install_package" do
- @resource.resource_name.should eql(:easy_install_package)
- end
-
- it "should set the provider to Chef::Provider::Package::EasyInstall" do
- @resource.provider.should eql(Chef::Provider::Package::EasyInstall)
- end
-
it "should allow you to set the easy_install_binary attribute" do
@resource.easy_install_binary "/opt/local/bin/easy_install"
@resource.easy_install_binary.should eql("/opt/local/bin/easy_install")
diff --git a/spec/unit/resource/gem_package_spec.rb b/spec/unit/resource/gem_package_spec.rb
index 98703455de..01c4fb6106 100644
--- a/spec/unit/resource/gem_package_spec.rb
+++ b/spec/unit/resource/gem_package_spec.rb
@@ -17,24 +17,17 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::GemPackage, "initialize" do
- before(:each) do
- @resource = Chef::Resource::GemPackage.new("foo")
- end
-
- it "should return a Chef::Resource::GemPackage" do
- @resource.should be_a_kind_of(Chef::Resource::GemPackage)
- end
-
- it "should set the resource_name to :gem_package" do
- @resource.resource_name.should eql(:gem_package)
- end
+ static_provider_resolution(
+ resource: Chef::Resource::GemPackage,
+ provider: Chef::Provider::Package::Rubygems,
+ name: :gem_package,
+ action: :install,
+ )
- it "should set the provider to Chef::Provider::Package::Rubygems" do
- @resource.provider.should eql(Chef::Provider::Package::Rubygems)
- end
end
describe Chef::Resource::GemPackage, "gem_binary" do
diff --git a/spec/unit/resource/git_spec.rb b/spec/unit/resource/git_spec.rb
index 95a30c28a4..da7aee1014 100644
--- a/spec/unit/resource/git_spec.rb
+++ b/spec/unit/resource/git_spec.rb
@@ -17,9 +17,17 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::Git do
+ static_provider_resolution(
+ resource: Chef::Resource::Git,
+ provider: Chef::Provider::Git,
+ name: :git,
+ action: :sync,
+ )
+
before(:each) do
@git = Chef::Resource::Git.new("my awesome webapp")
end
@@ -29,10 +37,6 @@ describe Chef::Resource::Git do
@git.should be_an_instance_of(Chef::Resource::Git)
end
- it "uses the git provider" do
- @git.provider.should eql(Chef::Provider::Git)
- end
-
it "uses aliases revision as branch" do
@git.branch "HEAD"
@git.revision.should eql("HEAD")
diff --git a/spec/unit/resource/homebrew_package_spec.rb b/spec/unit/resource/homebrew_package_spec.rb
index bb657607b7..bb248d1189 100644
--- a/spec/unit/resource/homebrew_package_spec.rb
+++ b/spec/unit/resource/homebrew_package_spec.rb
@@ -16,26 +16,19 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::HomebrewPackage, 'initialize' do
- let(:resource) { Chef::Resource::HomebrewPackage.new('emacs') }
-
- it 'returns a Chef::Resource::HomebrewPackage' do
- expect(resource).to be_a_kind_of(Chef::Resource::HomebrewPackage)
- end
-
- it 'sets the resource_name to :homebrew_package' do
- expect(resource.resource_name).to eql(:homebrew_package)
- end
+ static_provider_resolution(
+ resource: Chef::Resource::HomebrewPackage,
+ provider: Chef::Provider::Package::Homebrew,
+ name: :homebrew_package,
+ action: :install,
+ os: "mac_os_x",
+ )
- it 'sets the provider to Chef::Provider::Package::Homebrew' do
- expect(resource.provider).to eql(Chef::Provider::Package::Homebrew)
- end
-
- it 'sets the homebrew_user to nil' do
- expect(resource.homebrew_user).to eql(nil)
- end
+ let(:resource) { Chef::Resource::HomebrewPackage.new('emacs') }
shared_examples 'home_brew user set and returned' do
it 'returns the configured homebrew_user' do
diff --git a/spec/unit/resource/ips_package_spec.rb b/spec/unit/resource/ips_package_spec.rb
index 61661922fa..8718c5c093 100644
--- a/spec/unit/resource/ips_package_spec.rb
+++ b/spec/unit/resource/ips_package_spec.rb
@@ -17,25 +17,22 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::IpsPackage, "initialize" do
+ static_provider_resolution(
+ resource: Chef::Resource::IpsPackage,
+ provider: Chef::Provider::Package::Ips,
+ name: :ips_package,
+ action: :install,
+ os: "solaris2",
+ )
+
before(:each) do
@resource = Chef::Resource::IpsPackage.new("crypto/gnupg")
end
- it "should return a Chef::Resource::IpsPackage" do
- @resource.should be_a_kind_of(Chef::Resource::IpsPackage)
- end
-
- it "should set the resource_name to :ips_package" do
- @resource.resource_name.should eql(:ips_package)
- end
-
- it "should set the provider to Chef::Provider::Package::Ips" do
- @resource.provider.should eql(Chef::Provider::Package::Ips)
- end
-
it "should support accept_license" do
@resource.accept_license(true)
@resource.accept_license.should eql(true)
diff --git a/spec/unit/resource/macports_package_spec.rb b/spec/unit/resource/macports_package_spec.rb
index 7e2e200487..0a203b2e97 100644
--- a/spec/unit/resource/macports_package_spec.rb
+++ b/spec/unit/resource/macports_package_spec.rb
@@ -17,21 +17,16 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::MacportsPackage, "initialize" do
- before(:each) do
- @resource = Chef::Resource::MacportsPackage.new("foo")
- end
- it "should return a Chef::Resource::MacportsPackage" do
- @resource.should be_a_kind_of(Chef::Resource::MacportsPackage)
- end
+ static_provider_resolution(
+ resource: Chef::Resource::MacportsPackage,
+ provider: Chef::Provider::Package::Macports,
+ name: :macports_package,
+ action: :install,
+ os: "mac_os_x",
+ )
- it "should set the resource_name to :macports_package" do
- @resource.resource_name.should eql(:macports_package)
- end
-
- it "should set the provider to Chef::Provider::Package::Macports" do
- @resource.provider.should eql(Chef::Provider::Package::Macports)
- end
end
diff --git a/spec/unit/resource/pacman_package_spec.rb b/spec/unit/resource/pacman_package_spec.rb
index ec5feeb82c..975863d04f 100644
--- a/spec/unit/resource/pacman_package_spec.rb
+++ b/spec/unit/resource/pacman_package_spec.rb
@@ -17,22 +17,16 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::PacmanPackage, "initialize" do
- before(:each) do
- @resource = Chef::Resource::PacmanPackage.new("foo")
- end
+ static_provider_resolution(
+ resource: Chef::Resource::PacmanPackage,
+ provider: Chef::Provider::Package::Pacman,
+ name: :pacman_package,
+ action: :install,
+ os: "linux",
+ )
- it "should return a Chef::Resource::PacmanPackage" do
- @resource.should be_a_kind_of(Chef::Resource::PacmanPackage)
- end
-
- it "should set the resource_name to :pacman_package" do
- @resource.resource_name.should eql(:pacman_package)
- end
-
- it "should set the provider to Chef::Provider::Package::Pacman" do
- @resource.provider.should eql(Chef::Provider::Package::Pacman)
- end
end
diff --git a/spec/unit/resource/rpm_package_spec.rb b/spec/unit/resource/rpm_package_spec.rb
index 25930a5484..d209c6a5a2 100644
--- a/spec/unit/resource/rpm_package_spec.rb
+++ b/spec/unit/resource/rpm_package_spec.rb
@@ -17,22 +17,18 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::RpmPackage, "initialize" do
- before(:each) do
- @resource = Chef::Resource::RpmPackage.new("foo")
+ %w{linux aix}.each do |os|
+ static_provider_resolution(
+ resource: Chef::Resource::RpmPackage,
+ provider: Chef::Provider::Package::Rpm,
+ name: :rpm_package,
+ action: :install,
+ os: os
+ )
end
- it "should return a Chef::Resource::RpmPackage" do
- @resource.should be_a_kind_of(Chef::Resource::RpmPackage)
- end
-
- it "should set the resource_name to :rpm_package" do
- @resource.resource_name.should eql(:rpm_package)
- end
-
- it "should set the provider to Chef::Provider::Package::Rpm" do
- @resource.provider.should eql(Chef::Provider::Package::Rpm)
- end
end
diff --git a/spec/unit/resource/service_spec.rb b/spec/unit/resource/service_spec.rb
index ec62d012bb..9b779e5830 100644
--- a/spec/unit/resource/service_spec.rb
+++ b/spec/unit/resource/service_spec.rb
@@ -29,20 +29,10 @@ describe Chef::Resource::Service do
@resource.should be_a_kind_of(Chef::Resource)
@resource.should be_a_kind_of(Chef::Resource::Service)
end
-
+
it "should not set a provider unless node[:init_package] is defined as systemd" do
@resource.provider.should == nil
end
-
- it "should set the provider to Chef::Provider::Service::Systemd if node[:init_package] is systemd" do
- node = Chef::Node.new
- node.set[:init_package] = "systemd"
- cookbook_collection = Chef::CookbookCollection.new([])
- events = Chef::EventDispatch::Dispatcher.new
- run_context = Chef::RunContext.new(node, cookbook_collection, events)
- @resource = Chef::Resource::Service.new("chef", run_context)
- @resource.provider.should == Chef::Provider::Service::Systemd
- end
it "should set the service_name to the first argument to new" do
@resource.service_name.should eql("chef")
diff --git a/spec/unit/resource/smartos_package_spec.rb b/spec/unit/resource/smartos_package_spec.rb
index 391713c8ff..c2cf546dd5 100644
--- a/spec/unit/resource/smartos_package_spec.rb
+++ b/spec/unit/resource/smartos_package_spec.rb
@@ -16,23 +16,18 @@
# limitations under the License.
#
-require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
+require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::SmartosPackage, "initialize" do
- before(:each) do
- @resource = Chef::Resource::SmartosPackage.new("foo")
- end
+ static_provider_resolution(
+ resource: Chef::Resource::SmartosPackage,
+ provider: Chef::Provider::Package::SmartOS,
+ name: :smartos_package,
+ action: :install,
+ os: "solaris2",
+ platform_family: "smartos",
+ )
- it "should return a Chef::Resource::SmartosPackage" do
- @resource.should be_a_kind_of(Chef::Resource::SmartosPackage)
- end
-
- it "should set the resource_name to :smartos_package" do
- @resource.resource_name.should eql(:smartos_package)
- end
-
- it "should set the provider to Chef::Provider::Package::SmartOS" do
- @resource.provider.should eql(Chef::Provider::Package::SmartOS)
- end
end
diff --git a/spec/unit/resource/solaris_package_spec.rb b/spec/unit/resource/solaris_package_spec.rb
index 6d0260ab5a..ab4e03807d 100644
--- a/spec/unit/resource/solaris_package_spec.rb
+++ b/spec/unit/resource/solaris_package_spec.rb
@@ -17,41 +17,26 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::SolarisPackage, "initialize" do
- before(:each) do
- @resource = Chef::Resource::SolarisPackage.new("foo")
- end
-
- it "should return a Chef::Resource::SolarisPackage object" do
- @resource.should be_a_kind_of(Chef::Resource::SolarisPackage)
+ %w{solaris2 nexentacore}.each do |platform_family|
+ static_provider_resolution(
+ resource: Chef::Resource::SolarisPackage,
+ provider: Chef::Provider::Package::Solaris,
+ name: :solaris_package,
+ action: :install,
+ os: "solaris2",
+ platform_family: platform_family,
+ )
end
- it "should not raise any Error when valid number of arguments are provided" do
- expect { Chef::Resource::SolarisPackage.new("foo") }.to_not raise_error
- end
-
- it "should raise ArgumentError when incorrect number of arguments are provided" do
- expect { Chef::Resource::SolarisPackage.new }.to raise_error(ArgumentError)
+ before(:each) do
+ @resource = Chef::Resource::SolarisPackage.new("foo")
end
it "should set the package_name to the name provided" do
@resource.package_name.should eql("foo")
end
-
- it "should set the resource_name to :solaris_package" do
- @resource.resource_name.should eql(:solaris_package)
- end
-
- it "should set the run_context to the run_context provided" do
- @run_context = double()
- @run_context.stub(:node)
- resource = Chef::Resource::SolarisPackage.new("foo", @run_context)
- resource.run_context.should eql(@run_context)
- end
-
- it "should set the provider to Chef::Provider::Package::Solaris" do
- @resource.provider.should eql(Chef::Provider::Package::Solaris)
- end
end
diff --git a/spec/unit/resource/subversion_spec.rb b/spec/unit/resource/subversion_spec.rb
index ae06ce665a..a52d8421c6 100644
--- a/spec/unit/resource/subversion_spec.rb
+++ b/spec/unit/resource/subversion_spec.rb
@@ -17,9 +17,17 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::Subversion do
+ static_provider_resolution(
+ resource: Chef::Resource::Subversion,
+ provider: Chef::Provider::Subversion,
+ name: :subversion,
+ action: :install,
+ )
+
before do
@svn = Chef::Resource::Subversion.new("ohai, svn project!")
end
@@ -29,10 +37,6 @@ describe Chef::Resource::Subversion do
@svn.should be_a_kind_of(Chef::Resource::Scm)
end
- it "uses the subversion provider" do
- @svn.provider.should eql(Chef::Provider::Subversion)
- end
-
it "allows the force_export action" do
@svn.allowed_actions.should include(:force_export)
end
diff --git a/spec/unit/resource/timestamped_deploy_spec.rb b/spec/unit/resource/timestamped_deploy_spec.rb
index f380ffca87..2af9d8bb0f 100644
--- a/spec/unit/resource/timestamped_deploy_spec.rb
+++ b/spec/unit/resource/timestamped_deploy_spec.rb
@@ -18,11 +18,37 @@
require 'spec_helper'
-describe Chef::Resource::TimestampedDeploy do
+describe Chef::Resource::TimestampedDeploy, "initialize" do
- it "defaults to the TimestampedDeploy provider" do
- @resource = Chef::Resource::TimestampedDeploy.new("stuff")
- @resource.provider.should == Chef::Provider::Deploy::Timestamped
+ let(:node) {
+ node = Chef::Node.new
+ node.automatic_attrs[:os] = 'linux'
+ node.automatic_attrs[:platform_family] = 'rhel'
+ node
+ }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:provider_resolver) { Chef::ProviderResolver.new(node) }
+ let(:run_context) {
+ run_context = Chef::RunContext.new(node, {}, events)
+ run_context.provider_resolver = provider_resolver
+ run_context
+ }
+ let(:resource) { Chef::Resource::TimestampedDeploy.new("stuff", run_context) }
+
+ it "should return a Chef::Resource::TimestampedDeploy" do
+ expect(resource).to be_a_kind_of(Chef::Resource::TimestampedDeploy)
+ end
+
+ it "should set the resource_name to :timestamped_deploy" do
+ expect(resource.resource_name).to eql(:deploy)
end
+ it "should leave the provider nil" do
+ expect(resource.provider).to eql(nil)
+ end
+
+ it "should resolve to a Chef::Provider::Deploy::Timestamped" do
+ expect(resource.provider_for_action(:install)).to be_a(Chef::Provider::Deploy::Timestamped)
+ end
end
+
diff --git a/spec/unit/resource/yum_package_spec.rb b/spec/unit/resource/yum_package_spec.rb
index 57ab4dfcd9..7e1979fdfd 100644
--- a/spec/unit/resource/yum_package_spec.rb
+++ b/spec/unit/resource/yum_package_spec.rb
@@ -17,24 +17,19 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::YumPackage, "initialize" do
- before(:each) do
- @resource = Chef::Resource::YumPackage.new("foo")
- end
-
- it "should return a Chef::Resource::YumPackage" do
- @resource.should be_a_kind_of(Chef::Resource::YumPackage)
- end
-
- it "should set the resource_name to :yum_package" do
- @resource.resource_name.should eql(:yum_package)
- end
+ static_provider_resolution(
+ resource: Chef::Resource::YumPackage,
+ provider: Chef::Provider::Package::Yum,
+ name: :yum_package,
+ action: :install,
+ os: 'linux',
+ platform_family: 'rhel',
+ )
- it "should set the provider to Chef::Provider::Package::Yum" do
- @resource.provider.should eql(Chef::Provider::Package::Yum)
- end
end
describe Chef::Resource::YumPackage, "arch" do
diff --git a/spec/unit/resource_platform_map_spec.rb b/spec/unit/resource_platform_map_spec.rb
deleted file mode 100644
index 99673d868f..0000000000
--- a/spec/unit/resource_platform_map_spec.rb
+++ /dev/null
@@ -1,164 +0,0 @@
-#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'spec_helper'
-
-describe Chef::Resource::PlatformMap do
-
- before(:each) do
- @platform_map = Chef::Resource::PlatformMap.new({
- :windows => {
- "6.1" => {
- :file => "softiefile",
- :else => "thing"
- },
- :default => {
- :file => Chef::Resource::File,
- :ping => "pong",
- :cat => "nice"
- }
- },
- :pop_tron => {
- },
- :default => {
- :soundwave => "lazerbeak",
- :directory => Chef::Resource::Directory,
- }
- })
- end
-
- describe 'filtering the map' do
- it "returns resources for platform and version" do
- pmap = @platform_map.filter("Windows", "6.1")
- pmap.should be_a_kind_of(Hash)
- pmap[:file].should eql("softiefile")
- end
-
- it "returns platform default resources if version does not exist" do
- pmap = @platform_map.filter("windows", "1")
- pmap.should be_a_kind_of(Hash)
- pmap[:file].should eql(Chef::Resource::File)
- end
-
- it "returns global default resources if none exist for plaform" do
- pmap = @platform_map.filter("pop_tron", "1")
- pmap.should be_a_kind_of(Hash)
- pmap[:directory].should eql(Chef::Resource::Directory)
- end
-
- it "returns global default resources if platform does not exist" do
- pmap = @platform_map.filter("BeOS", "1")
- pmap.should be_a_kind_of(Hash)
- pmap[:soundwave].should eql("lazerbeak")
- end
-
- it "returns a merged map of platform version and plaform default resources" do
- pmap = @platform_map.filter("Windows", "6.1")
- pmap[:file].should eql("softiefile")
- pmap[:ping].should eql("pong")
- end
-
- it "returns a merged map of platform specific version and global defaults" do
- pmap = @platform_map.filter("Windows", "6.1")
- pmap[:file].should eql("softiefile")
- pmap[:soundwave].should eql("lazerbeak")
- end
- end
-
- describe 'finding a resource' do
- it "returns a resource for a platform directly by short name" do
- @platform_map.get(:file, "windows", "6.1").should eql("softiefile")
- end
-
- it "returns a default resource if platform and version don't exist" do
- @platform_map.get(:remote_file).should eql(Chef::Resource::RemoteFile)
- end
-
- it "raises an exception if a resource cannot be found" do
- lambda { @platform_map.get(:coffee, "windows", "6.1")}.should raise_error(NameError)
- end
-
- it "returns a resource with a Chef::Resource object" do
- kitty = Chef::Resource::Cat.new("loulou")
- @platform_map.get(kitty, "windows", "6.1").should eql("nice")
- end
- end
-
- describe 'building the map' do
- it "allows passing of a resource map at creation time" do
- @new_map = Chef::Resource::PlatformMap.new({:the_dude => {:default => 'abides'}})
- @new_map.map[:the_dude][:default].should eql("abides")
- end
-
- it "defaults to a resource map with :default key" do
- @new_map = Chef::Resource::PlatformMap.new
- @new_map.map.has_key?(:default)
- end
-
- it "updates the resource map with a map" do
- @platform_map.set(
- :platform => :darwin,
- :version => "9.2.2",
- :short_name => :file,
- :resource => "masterful"
- )
- @platform_map.map[:darwin]["9.2.2"][:file].should eql("masterful")
-
- @platform_map.set(
- :platform => :darwin,
- :short_name => :file,
- :resource => "masterful"
- )
- @platform_map.map[:darwin][:default][:file].should eql("masterful")
-
- @platform_map.set(
- :short_name => :file,
- :resource => "masterful"
- )
- @platform_map.map[:default][:file].should eql("masterful")
-
- @platform_map.set(
- :platform => :hero,
- :version => "9.2.2",
- :short_name => :file,
- :resource => "masterful"
- )
- @platform_map.map[:hero]["9.2.2"][:file].should eql("masterful")
-
- @platform_map.set(
- :short_name => :file,
- :resource => "masterful"
- )
- @platform_map.map[:default][:file].should eql("masterful")
-
- @platform_map.set(
- :short_name => :file,
- :resource => "masterful"
- )
- @platform_map.map[:default][:file].should eql("masterful")
-
- @platform_map.set(
- :platform => :neurosis,
- :short_name => :package,
- :resource => "masterful"
- )
- @platform_map.map[:neurosis][:default][:package].should eql("masterful")
- end
- end
-
-end
diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb
index 584ec8175c..2163cf181e 100644
--- a/spec/unit/resource_spec.rb
+++ b/spec/unit/resource_spec.rb
@@ -692,24 +692,33 @@ describe Chef::Resource do
describe "building the platform map" do
+ let(:klz) { Class.new(Chef::Resource) }
+
+ before do
+ Chef::Resource::Klz = klz
+ end
+
+ after do
+ Chef::Resource.send(:remove_const, :Klz)
+ end
+
it 'adds mappings for a single platform' do
- klz = Class.new(Chef::Resource)
- Chef::Resource.platform_map.should_receive(:set).with(
- :platform => :autobots, :short_name => :dinobot, :resource => klz
+ expect(Chef::Resource.node_map).to receive(:set).with(
+ :dinobot, Chef::Resource::Klz, { platform: ['autobots'] }
)
- klz.provides :dinobot, :on_platforms => ['autobots']
+ klz.provides :dinobot, platform: ['autobots']
end
it 'adds mappings for multiple platforms' do
- klz = Class.new(Chef::Resource)
- Chef::Resource.platform_map.should_receive(:set).twice
- klz.provides :energy, :on_platforms => ['autobots','decepticons']
+ expect(Chef::Resource.node_map).to receive(:set).with(
+ :energy, Chef::Resource::Klz, { platform: ['autobots', 'decepticons']}
+ )
+ klz.provides :energy, platform: ['autobots', 'decepticons']
end
it 'adds mappings for all platforms' do
- klz = Class.new(Chef::Resource)
- Chef::Resource.platform_map.should_receive(:set).with(
- :short_name => :tape_deck, :resource => klz
+ expect(Chef::Resource.node_map).to receive(:set).with(
+ :tape_deck, Chef::Resource::Klz, {}
)
klz.provides :tape_deck
end
@@ -717,28 +726,26 @@ describe Chef::Resource do
end
describe "lookups from the platform map" do
+ let(:klz1) { Class.new(Chef::Resource) }
+ let(:klz2) { Class.new(Chef::Resource) }
before(:each) do
+ Chef::Resource::Klz1 = klz1
+ Chef::Resource::Klz2 = klz2
@node = Chef::Node.new
@node.name("bumblebee")
@node.automatic[:platform] = "autobots"
@node.automatic[:platform_version] = "6.1"
- Object.const_set('Soundwave', Class.new(Chef::Resource))
- Object.const_set('Grimlock', Class.new(Chef::Resource){ provides :dinobot, :on_platforms => ['autobots'] })
+ Object.const_set('Soundwave', klz1)
+ klz2.provides :dinobot, :on_platforms => ['autobots']
+ Object.const_set('Grimlock', klz2)
end
after(:each) do
Object.send(:remove_const, :Soundwave)
Object.send(:remove_const, :Grimlock)
- end
-
- describe "resource_for_platform" do
- it 'return a resource by short_name and platform' do
- Chef::Resource.resource_for_platform(:dinobot,'autobots','6.1').should eql(Grimlock)
- end
- it "returns a resource by short_name if nothing else matches" do
- Chef::Resource.resource_for_node(:soundwave, @node).should eql(Soundwave)
- end
+ Chef::Resource.send(:remove_const, :Klz1)
+ Chef::Resource.send(:remove_const, :Klz2)
end
describe "resource_for_node" do
diff --git a/spec/unit/runner_spec.rb b/spec/unit/runner_spec.rb
index 68d8b0e011..9bd4199418 100644
--- a/spec/unit/runner_spec.rb
+++ b/spec/unit/runner_spec.rb
@@ -81,322 +81,329 @@ end
describe Chef::Runner do
- before(:each) do
- @node = Chef::Node.new
- @node.name "latte"
- @node.automatic[:platform] = "mac_os_x"
- @node.automatic[:platform_version] = "10.5.1"
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, Chef::CookbookCollection.new({}), @events)
- @first_resource = Chef::Resource::Cat.new("loulou1", @run_context)
- @run_context.resource_collection << @first_resource
- Chef::Platform.set(
- :resource => :cat,
- :provider => Chef::Provider::SnakeOil
- )
- @runner = Chef::Runner.new(@run_context)
+ let(:node) do
+ node = Chef::Node.new
+ node.name "latte"
+ node.automatic[:platform] = "mac_os_x"
+ node.automatic[:platform_version] = "10.5.1"
+ node
end
- it "should pass each resource in the collection to a provider" do
- @run_context.resource_collection.should_receive(:execute_each_resource).once
- @runner.converge
- end
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, Chef::CookbookCollection.new({}), events) }
+ let(:first_resource) { Chef::Resource::Cat.new("loulou1", run_context) }
+ let(:runner) { Chef::Runner.new(run_context) }
- it "should use the provider specified by the resource (if it has one)" do
- provider = Chef::Provider::Easy.new(@run_context.resource_collection[0], @run_context)
- # Expect provider to be called twice, because will fall back to old provider lookup
- @run_context.resource_collection[0].should_receive(:provider).twice.and_return(Chef::Provider::Easy)
- Chef::Provider::Easy.should_receive(:new).once.and_return(provider)
- @runner.converge
+ before do
+ run_context.resource_collection << first_resource
end
- it "should use the platform provider if it has one" do
- Chef::Platform.should_receive(:find_provider_for_node).once.and_return(Chef::Provider::SnakeOil)
- @runner.converge
- end
+ context "when we fall through to old Chef::Platform resolution" do
+ before do
+ # set up old Chef::Platform resolution instead of provider_resolver
+ Chef::Platform.set(
+ :resource => :cat,
+ :provider => Chef::Provider::SnakeOil
+ )
+ allow(run_context.provider_resolver).to receive(:maybe_dynamic_provider_resolution).with(first_resource, anything()).and_return(nil)
+ end
- it "should run the action for each resource" do
- Chef::Platform.should_receive(:find_provider_for_node).once.and_return(Chef::Provider::SnakeOil)
- provider = Chef::Provider::SnakeOil.new(@run_context.resource_collection[0], @run_context)
- provider.should_receive(:action_sell).once.and_return(true)
- Chef::Provider::SnakeOil.should_receive(:new).once.and_return(provider)
- @runner.converge
+ it "should use the platform provider if it has one" do
+ expect(Chef::Platform).to receive(:find_provider_for_node).with(node, first_resource).and_call_original
+ runner.converge
+ end
end
- it "should raise exceptions as thrown by a provider" do
- provider = Chef::Provider::SnakeOil.new(@run_context.resource_collection[0], @run_context)
- Chef::Provider::SnakeOil.stub(:new).once.and_return(provider)
- provider.stub(:action_sell).once.and_raise(ArgumentError)
- lambda { @runner.converge }.should raise_error(ArgumentError)
- end
+ context "when we are doing dynamic provider resolution" do
- it "should not raise exceptions thrown by providers if the resource has ignore_failure set to true" do
- @run_context.resource_collection[0].stub(:ignore_failure).and_return(true)
- provider = Chef::Provider::SnakeOil.new(@run_context.resource_collection[0], @run_context)
- Chef::Provider::SnakeOil.stub(:new).once.and_return(provider)
- provider.stub(:action_sell).once.and_raise(ArgumentError)
- lambda { @runner.converge }.should_not raise_error
- end
+ it "should pass each resource in the collection to a provider" do
+ expect(run_context.resource_collection).to receive(:execute_each_resource).once
+ runner.converge
+ end
- it "should retry with the specified delay if retries are specified" do
- @first_resource.retries 3
- provider = Chef::Provider::SnakeOil.new(@run_context.resource_collection[0], @run_context)
- Chef::Provider::SnakeOil.stub(:new).once.and_return(provider)
- provider.stub(:action_sell).and_raise(ArgumentError)
- @first_resource.should_receive(:sleep).with(2).exactly(3).times
- lambda { @runner.converge }.should raise_error(ArgumentError)
- end
+ it "should use the provider specified by the resource (if it has one)" do
+ provider = Chef::Provider::Easy.new(run_context.resource_collection[0], run_context)
+ # Expect provider to be called twice, because will fall back to old provider lookup
+ expect(run_context.resource_collection[0]).to receive(:provider).twice.and_return(Chef::Provider::Easy)
+ expect(Chef::Provider::Easy).to receive(:new).once.and_return(provider)
+ runner.converge
+ end
- it "should execute immediate actions on changed resources" do
- notifying_resource = Chef::Resource::Cat.new("peanut", @run_context)
- notifying_resource.action = :purr # only action that will set updated on the resource
+ it "should run the action for each resource" do
+ provider = Chef::Provider::SnakeOil.new(run_context.resource_collection[0], run_context)
+ expect(provider).to receive(:action_sell).once.and_return(true)
+ expect(Chef::Provider::SnakeOil).to receive(:new).once.and_return(provider)
+ runner.converge
+ end
- @run_context.resource_collection << notifying_resource
- @first_resource.action = :nothing # won't be updated unless notified by other resource
+ it "should raise exceptions as thrown by a provider" do
+ provider = Chef::Provider::SnakeOil.new(run_context.resource_collection[0], run_context)
+ allow(Chef::Provider::SnakeOil).to receive(:new).once.and_return(provider)
+ allow(provider).to receive(:action_sell).once.and_raise(ArgumentError)
+ expect { runner.converge }.to raise_error(ArgumentError)
+ end
- notifying_resource.notifies(:purr, @first_resource, :immediately)
+ it "should not raise exceptions thrown by providers if the resource has ignore_failure set to true" do
+ allow(run_context.resource_collection[0]).to receive(:ignore_failure).and_return(true)
+ provider = Chef::Provider::SnakeOil.new(run_context.resource_collection[0], run_context)
+ allow(Chef::Provider::SnakeOil).to receive(:new).once.and_return(provider)
+ allow(provider).to receive(:action_sell).once.and_raise(ArgumentError)
+ expect { runner.converge }.not_to raise_error
+ end
- @runner.converge
+ it "should retry with the specified delay if retries are specified" do
+ first_resource.retries 3
+ provider = Chef::Provider::SnakeOil.new(run_context.resource_collection[0], run_context)
+ allow(Chef::Provider::SnakeOil).to receive(:new).once.and_return(provider)
+ allow(provider).to receive(:action_sell).and_raise(ArgumentError)
+ expect(first_resource).to receive(:sleep).with(2).exactly(3).times
+ expect { runner.converge }.to raise_error(ArgumentError)
+ end
- @first_resource.should be_updated
- end
+ it "should execute immediate actions on changed resources" do
+ notifying_resource = Chef::Resource::Cat.new("peanut", run_context)
+ notifying_resource.action = :purr # only action that will set updated on the resource
- it "should follow a chain of actions" do
- @first_resource.action = :nothing
+ run_context.resource_collection << notifying_resource
+ first_resource.action = :nothing # won't be updated unless notified by other resource
- middle_resource = Chef::Resource::Cat.new("peanut", @run_context)
- middle_resource.action = :nothing
- @run_context.resource_collection << middle_resource
- middle_resource.notifies(:purr, @first_resource, :immediately)
+ notifying_resource.notifies(:purr, first_resource, :immediately)
- last_resource = Chef::Resource::Cat.new("snuffles", @run_context)
- last_resource.action = :purr
- @run_context.resource_collection << last_resource
- last_resource.notifies(:purr, middle_resource, :immediately)
+ runner.converge
- @runner.converge
+ expect(first_resource).to be_updated
+ end
- last_resource.should be_updated # by action(:purr)
- middle_resource.should be_updated # by notification from last_resource
- @first_resource.should be_updated # by notification from middle_resource
- end
+ it "should follow a chain of actions" do
+ first_resource.action = :nothing
- it "should execute delayed actions on changed resources" do
- @first_resource.action = :nothing
- second_resource = Chef::Resource::Cat.new("peanut", @run_context)
- second_resource.action = :purr
+ middle_resource = Chef::Resource::Cat.new("peanut", run_context)
+ middle_resource.action = :nothing
+ run_context.resource_collection << middle_resource
+ middle_resource.notifies(:purr, first_resource, :immediately)
- @run_context.resource_collection << second_resource
- second_resource.notifies(:purr, @first_resource, :delayed)
+ last_resource = Chef::Resource::Cat.new("snuffles", run_context)
+ last_resource.action = :purr
+ run_context.resource_collection << last_resource
+ last_resource.notifies(:purr, middle_resource, :immediately)
- @runner.converge
+ runner.converge
- @first_resource.should be_updated
- end
+ expect(last_resource).to be_updated # by action(:purr)
+ expect(middle_resource).to be_updated # by notification from last_resource
+ expect(first_resource).to be_updated # by notification from middle_resource
+ end
- it "should execute delayed notifications when a failure occurs in the chef client run" do
- @first_resource.action = :nothing
- second_resource = Chef::Resource::Cat.new("peanut", @run_context)
- second_resource.action = :purr
+ it "should execute delayed actions on changed resources" do
+ first_resource.action = :nothing
+ second_resource = Chef::Resource::Cat.new("peanut", run_context)
+ second_resource.action = :purr
- @run_context.resource_collection << second_resource
- second_resource.notifies(:purr, @first_resource, :delayed)
+ run_context.resource_collection << second_resource
+ second_resource.notifies(:purr, first_resource, :delayed)
- third_resource = FailureResource.new("explode", @run_context)
- @run_context.resource_collection << third_resource
+ runner.converge
- lambda {@runner.converge}.should raise_error(FailureProvider::ChefClientFail)
+ expect(first_resource).to be_updated
+ end
- @first_resource.should be_updated
- end
+ it "should execute delayed notifications when a failure occurs in the chef client run" do
+ first_resource.action = :nothing
+ second_resource = Chef::Resource::Cat.new("peanut", run_context)
+ second_resource.action = :purr
- it "should execute delayed notifications when a failure occurs in a notification" do
- @first_resource.action = :nothing
- second_resource = Chef::Resource::Cat.new("peanut", @run_context)
- second_resource.action = :purr
+ run_context.resource_collection << second_resource
+ second_resource.notifies(:purr, first_resource, :delayed)
- @run_context.resource_collection << second_resource
+ third_resource = FailureResource.new("explode", run_context)
+ run_context.resource_collection << third_resource
- third_resource = FailureResource.new("explode", @run_context)
- third_resource.action = :nothing
- @run_context.resource_collection << third_resource
+ expect { runner.converge }.to raise_error(FailureProvider::ChefClientFail)
- second_resource.notifies(:fail, third_resource, :delayed)
- second_resource.notifies(:purr, @first_resource, :delayed)
+ expect(first_resource).to be_updated
+ end
- lambda {@runner.converge}.should raise_error(FailureProvider::ChefClientFail)
+ it "should execute delayed notifications when a failure occurs in a notification" do
+ first_resource.action = :nothing
+ second_resource = Chef::Resource::Cat.new("peanut", run_context)
+ second_resource.action = :purr
- @first_resource.should be_updated
- end
+ run_context.resource_collection << second_resource
- it "should execute delayed notifications when a failure occurs in multiple notifications" do
- @first_resource.action = :nothing
- second_resource = Chef::Resource::Cat.new("peanut", @run_context)
- second_resource.action = :purr
+ third_resource = FailureResource.new("explode", run_context)
+ third_resource.action = :nothing
+ run_context.resource_collection << third_resource
- @run_context.resource_collection << second_resource
+ second_resource.notifies(:fail, third_resource, :delayed)
+ second_resource.notifies(:purr, first_resource, :delayed)
- third_resource = FailureResource.new("explode", @run_context)
- third_resource.action = :nothing
- @run_context.resource_collection << third_resource
+ expect {runner.converge}.to raise_error(FailureProvider::ChefClientFail)
- fourth_resource = FailureResource.new("explode again", @run_context)
- fourth_resource.action = :nothing
- @run_context.resource_collection << fourth_resource
+ expect(first_resource).to be_updated
+ end
- second_resource.notifies(:fail, third_resource, :delayed)
- second_resource.notifies(:fail, fourth_resource, :delayed)
- second_resource.notifies(:purr, @first_resource, :delayed)
+ it "should execute delayed notifications when a failure occurs in multiple notifications" do
+ first_resource.action = :nothing
+ second_resource = Chef::Resource::Cat.new("peanut", run_context)
+ second_resource.action = :purr
- exception = nil
- begin
- @runner.converge
- rescue => e
- exception = e
- end
- exception.should be_a(Chef::Exceptions::MultipleFailures)
+ run_context.resource_collection << second_resource
+
+ third_resource = FailureResource.new("explode", run_context)
+ third_resource.action = :nothing
+ run_context.resource_collection << third_resource
+
+ fourth_resource = FailureResource.new("explode again", run_context)
+ fourth_resource.action = :nothing
+ run_context.resource_collection << fourth_resource
+
+ second_resource.notifies(:fail, third_resource, :delayed)
+ second_resource.notifies(:fail, fourth_resource, :delayed)
+ second_resource.notifies(:purr, first_resource, :delayed)
+
+ exception = nil
+ begin
+ runner.converge
+ rescue => e
+ exception = e
+ end
+ expect(exception).to be_a(Chef::Exceptions::MultipleFailures)
- expected_message =<<-E
+ expected_message =<<-E
Multiple failures occurred:
* FailureProvider::ChefClientFail occurred in delayed notification: [explode] (dynamically defined) had an error: FailureProvider::ChefClientFail: chef had an error of some sort
* FailureProvider::ChefClientFail occurred in delayed notification: [explode again] (dynamically defined) had an error: FailureProvider::ChefClientFail: chef had an error of some sort
-E
- exception.message.should == expected_message
+ E
+ expect(exception.message).to eq(expected_message)
- @first_resource.should be_updated
- end
-
- it "does not duplicate delayed notifications" do
- SnitchyProvider.clear_action_record
-
- Chef::Platform.set(
- :resource => :cat,
- :provider => SnitchyProvider
- )
+ expect(first_resource).to be_updated
+ end
- @first_resource.action = :nothing
+ it "does not duplicate delayed notifications" do
+ SnitchyProvider.clear_action_record
- second_resource = Chef::Resource::Cat.new("peanut", @run_context)
- second_resource.action = :first_action
- @run_context.resource_collection << second_resource
+ first_resource.action = :nothing
+ first_resource.provider = SnitchyProvider
- third_resource = Chef::Resource::Cat.new("snickers", @run_context)
- third_resource.action = :first_action
- @run_context.resource_collection << third_resource
+ second_resource = Chef::Resource::Cat.new("peanut", run_context)
+ second_resource.action = :first_action
+ second_resource.provider = SnitchyProvider
+ run_context.resource_collection << second_resource
- second_resource.notifies(:second_action, @first_resource, :delayed)
- second_resource.notifies(:third_action, @first_resource, :delayed)
+ third_resource = Chef::Resource::Cat.new("snickers", run_context)
+ third_resource.action = :first_action
+ third_resource.provider = SnitchyProvider
+ run_context.resource_collection << third_resource
- third_resource.notifies(:second_action, @first_resource, :delayed)
- third_resource.notifies(:third_action, @first_resource, :delayed)
+ second_resource.notifies(:second_action, first_resource, :delayed)
+ second_resource.notifies(:third_action, first_resource, :delayed)
- @runner.converge
- # resources 2 and 3 call :first_action in the course of normal resource
- # execution, and schedule delayed actions :second and :third on the first
- # resource. The duplicate actions should "collapse" to a single notification
- # and order should be preserved.
- SnitchyProvider.all_actions_called.should == [:first, :first, :second, :third]
- end
+ third_resource.notifies(:second_action, first_resource, :delayed)
+ third_resource.notifies(:third_action, first_resource, :delayed)
- it "executes delayed notifications in the order they were declared" do
- SnitchyProvider.clear_action_record
+ runner.converge
+ # resources 2 and 3 call :first_action in the course of normal resource
+ # execution, and schedule delayed actions :second and :third on the first
+ # resource. The duplicate actions should "collapse" to a single notification
+ # and order should be preserved.
+ expect(SnitchyProvider.all_actions_called).to eq([:first, :first, :second, :third])
+ end
- Chef::Platform.set(
- :resource => :cat,
- :provider => SnitchyProvider
- )
+ it "executes delayed notifications in the order they were declared" do
+ SnitchyProvider.clear_action_record
- @first_resource.action = :nothing
+ first_resource.action = :nothing
+ first_resource.provider = SnitchyProvider
- second_resource = Chef::Resource::Cat.new("peanut", @run_context)
- second_resource.action = :first_action
- @run_context.resource_collection << second_resource
+ second_resource = Chef::Resource::Cat.new("peanut", run_context)
+ second_resource.action = :first_action
+ second_resource.provider = SnitchyProvider
+ run_context.resource_collection << second_resource
- third_resource = Chef::Resource::Cat.new("snickers", @run_context)
- third_resource.action = :first_action
- @run_context.resource_collection << third_resource
+ third_resource = Chef::Resource::Cat.new("snickers", run_context)
+ third_resource.action = :first_action
+ third_resource.provider = SnitchyProvider
+ run_context.resource_collection << third_resource
- second_resource.notifies(:second_action, @first_resource, :delayed)
- second_resource.notifies(:second_action, @first_resource, :delayed)
+ second_resource.notifies(:second_action, first_resource, :delayed)
+ second_resource.notifies(:second_action, first_resource, :delayed)
- third_resource.notifies(:third_action, @first_resource, :delayed)
- third_resource.notifies(:third_action, @first_resource, :delayed)
+ third_resource.notifies(:third_action, first_resource, :delayed)
+ third_resource.notifies(:third_action, first_resource, :delayed)
- @runner.converge
- SnitchyProvider.all_actions_called.should == [:first, :first, :second, :third]
- end
+ runner.converge
+ expect(SnitchyProvider.all_actions_called).to eq([:first, :first, :second, :third])
+ end
- it "does not fire notifications if the resource was not updated by the last action executed" do
- # REGRESSION TEST FOR CHEF-1452
- SnitchyProvider.clear_action_record
+ it "does not fire notifications if the resource was not updated by the last action executed" do
+ # REGRESSION TEST FOR CHEF-1452
+ SnitchyProvider.clear_action_record
- Chef::Platform.set(
- :resource => :cat,
- :provider => SnitchyProvider
- )
+ first_resource.action = :first_action
+ first_resource.provider = SnitchyProvider
- @first_resource.action = :first_action
+ second_resource = Chef::Resource::Cat.new("peanut", run_context)
+ second_resource.action = :nothing
+ second_resource.provider = SnitchyProvider
+ run_context.resource_collection << second_resource
- second_resource = Chef::Resource::Cat.new("peanut", @run_context)
- second_resource.action = :nothing
- @run_context.resource_collection << second_resource
+ third_resource = Chef::Resource::Cat.new("snickers", run_context)
+ third_resource.action = :nothing
+ third_resource.provider = SnitchyProvider
+ run_context.resource_collection << third_resource
- third_resource = Chef::Resource::Cat.new("snickers", @run_context)
- third_resource.action = :nothing
- @run_context.resource_collection << third_resource
+ first_resource.notifies(:second_action, second_resource, :immediately)
+ second_resource.notifies(:third_action, third_resource, :immediately)
- @first_resource.notifies(:second_action, second_resource, :immediately)
- second_resource.notifies(:third_action, third_resource, :immediately)
+ runner.converge
- @runner.converge
+ # All of the resources should only fire once:
+ expect(SnitchyProvider.all_actions_called).to eq([:first, :second, :third])
- # All of the resources should only fire once:
- SnitchyProvider.all_actions_called.should == [:first, :second, :third]
+ # all of the resources should be marked as updated for reporting purposes
+ expect(first_resource).to be_updated
+ expect(second_resource).to be_updated
+ expect(third_resource).to be_updated
+ end
- # all of the resources should be marked as updated for reporting purposes
- @first_resource.should be_updated
- second_resource.should be_updated
- third_resource.should be_updated
- end
+ it "should check a resource's only_if and not_if if notified by another resource" do
+ first_resource.action = :buy
- it "should check a resource's only_if and not_if if notified by another resource" do
- @first_resource.action = :buy
+ only_if_called_times = 0
+ first_resource.only_if {only_if_called_times += 1; true}
- only_if_called_times = 0
- @first_resource.only_if {only_if_called_times += 1; true}
+ not_if_called_times = 0
+ first_resource.not_if {not_if_called_times += 1; false}
- not_if_called_times = 0
- @first_resource.not_if {not_if_called_times += 1; false}
+ second_resource = Chef::Resource::Cat.new("carmel", run_context)
+ run_context.resource_collection << second_resource
+ second_resource.notifies(:purr, first_resource, :delayed)
+ second_resource.action = :purr
- second_resource = Chef::Resource::Cat.new("carmel", @run_context)
- @run_context.resource_collection << second_resource
- second_resource.notifies(:purr, @first_resource, :delayed)
- second_resource.action = :purr
+ # hits only_if first time when the resource is run in order, second on notify
+ runner.converge
- # hits only_if first time when the resource is run in order, second on notify
- @runner.converge
+ expect(only_if_called_times).to eq(2)
+ expect(not_if_called_times).to eq(2)
+ end
- only_if_called_times.should == 2
- not_if_called_times.should == 2
- end
+ it "should resolve resource references in notifications when resources are defined lazily" do
+ first_resource.action = :nothing
- it "should resolve resource references in notifications when resources are defined lazily" do
- @first_resource.action = :nothing
+ lazy_resources = lambda {
+ last_resource = Chef::Resource::Cat.new("peanut", run_context)
+ run_context.resource_collection << last_resource
+ last_resource.notifies(:purr, first_resource.to_s, :delayed)
+ last_resource.action = :purr
+ }
+ second_resource = Chef::Resource::RubyBlock.new("myblock", run_context)
+ run_context.resource_collection << second_resource
+ second_resource.block { lazy_resources.call }
- lazy_resources = lambda {
- last_resource = Chef::Resource::Cat.new("peanut", @run_context)
- @run_context.resource_collection << last_resource
- last_resource.notifies(:purr, @first_resource.to_s, :delayed)
- last_resource.action = :purr
- }
- second_resource = Chef::Resource::RubyBlock.new("myblock", @run_context)
- @run_context.resource_collection << second_resource
- second_resource.block { lazy_resources.call }
+ runner.converge
- @runner.converge
+ expect(first_resource).to be_updated
+ end
- @first_resource.should be_updated
end
-
end
-