summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md9
-rw-r--r--DOC_CHANGES.md24
-rw-r--r--Rakefile12
-rw-r--r--chef-config/Rakefile12
-rw-r--r--lib/chef/audit/audit_reporter.rb4
-rw-r--r--lib/chef/audit/logger.rb36
-rw-r--r--lib/chef/audit/runner.rb6
-rw-r--r--lib/chef/chef_class.rb35
-rw-r--r--lib/chef/client.rb798
-rw-r--r--lib/chef/dsl/recipe.rb101
-rw-r--r--lib/chef/dsl/resources.rb4
-rw-r--r--lib/chef/event_dispatch/base.rb4
-rw-r--r--lib/chef/formatters/doc.rb6
-rw-r--r--lib/chef/knife/core/subcommand_loader.rb2
-rw-r--r--lib/chef/mixin/deprecation.rb24
-rw-r--r--lib/chef/mixin/powershell_out.rb98
-rw-r--r--lib/chef/mixin/provides.rb23
-rw-r--r--lib/chef/mixin/windows_architecture_helper.rb7
-rw-r--r--lib/chef/node_map.rb164
-rw-r--r--lib/chef/platform/provider_mapping.rb269
-rw-r--r--lib/chef/platform/provider_priority_map.rb75
-rw-r--r--lib/chef/platform/query_helpers.rb5
-rw-r--r--lib/chef/platform/resource_priority_map.rb22
-rw-r--r--lib/chef/provider.rb19
-rw-r--r--lib/chef/provider/dsc_resource.rb9
-rw-r--r--lib/chef/provider/file.rb1
-rw-r--r--lib/chef/provider/group/aix.rb1
-rw-r--r--lib/chef/provider/group/dscl.rb2
-rw-r--r--lib/chef/provider/group/gpasswd.rb1
-rw-r--r--lib/chef/provider/group/groupmod.rb2
-rw-r--r--lib/chef/provider/group/pw.rb1
-rw-r--r--lib/chef/provider/group/suse.rb2
-rw-r--r--lib/chef/provider/group/usermod.rb3
-rw-r--r--lib/chef/provider/group/windows.rb2
-rw-r--r--lib/chef/provider/ifconfig.rb2
-rw-r--r--lib/chef/provider/ifconfig/aix.rb1
-rw-r--r--lib/chef/provider/ifconfig/debian.rb2
-rw-r--r--lib/chef/provider/ifconfig/redhat.rb1
-rw-r--r--lib/chef/provider/mount.rb1
-rw-r--r--lib/chef/provider/mount/aix.rb1
-rw-r--r--lib/chef/provider/mount/mount.rb2
-rw-r--r--lib/chef/provider/mount/solaris.rb2
-rw-r--r--lib/chef/provider/package.rb31
-rw-r--r--lib/chef/provider/package/homebrew.rb1
-rw-r--r--lib/chef/provider/package/macports.rb1
-rw-r--r--lib/chef/provider/package/portage.rb2
-rw-r--r--lib/chef/provider/package/rubygems.rb9
-rw-r--r--lib/chef/provider/powershell_script.rb176
-rw-r--r--lib/chef/provider/service.rb44
-rw-r--r--lib/chef/provider/service/init.rb1
-rw-r--r--lib/chef/provider/service/macosx.rb2
-rw-r--r--lib/chef/provider/service/windows.rb1
-rw-r--r--lib/chef/provider/user.rb2
-rw-r--r--lib/chef/provider/user/aix.rb5
-rw-r--r--lib/chef/provider/user/pw.rb1
-rw-r--r--lib/chef/provider/user/solaris.rb2
-rw-r--r--lib/chef/provider/user/useradd.rb1
-rw-r--r--lib/chef/provider_resolver.rb221
-rw-r--r--lib/chef/resource.rb226
-rw-r--r--lib/chef/resource/apt_package.rb3
-rw-r--r--lib/chef/resource/bash.rb3
-rw-r--r--lib/chef/resource/batch.rb3
-rw-r--r--lib/chef/resource/bff_package.rb8
-rw-r--r--lib/chef/resource/breakpoint.rb11
-rw-r--r--lib/chef/resource/chef_gem.rb3
-rw-r--r--lib/chef/resource/cookbook_file.rb6
-rw-r--r--lib/chef/resource/cron.rb8
-rw-r--r--lib/chef/resource/csh.rb3
-rw-r--r--lib/chef/resource/deploy.rb16
-rw-r--r--lib/chef/resource/deploy_revision.rb12
-rw-r--r--lib/chef/resource/directory.rb8
-rw-r--r--lib/chef/resource/dpkg_package.rb6
-rw-r--r--lib/chef/resource/dsc_resource.rb6
-rw-r--r--lib/chef/resource/dsc_script.rb6
-rw-r--r--lib/chef/resource/easy_install_package.rb7
-rw-r--r--lib/chef/resource/env.rb7
-rw-r--r--lib/chef/resource/erl_call.rb8
-rw-r--r--lib/chef/resource/execute.rb7
-rw-r--r--lib/chef/resource/file.rb7
-rw-r--r--lib/chef/resource/freebsd_package.rb6
-rw-r--r--lib/chef/resource/gem_package.rb3
-rw-r--r--lib/chef/resource/git.rb3
-rw-r--r--lib/chef/resource/group.rb8
-rw-r--r--lib/chef/resource/homebrew_package.rb3
-rw-r--r--lib/chef/resource/http_request.rb8
-rw-r--r--lib/chef/resource/ifconfig.rb8
-rw-r--r--lib/chef/resource/ips_package.rb5
-rw-r--r--lib/chef/resource/link.rb8
-rw-r--r--lib/chef/resource/log.rb7
-rw-r--r--lib/chef/resource/lwrp_base.rb69
-rw-r--r--lib/chef/resource/macosx_service.rb4
-rw-r--r--lib/chef/resource/macports_package.rb7
-rw-r--r--lib/chef/resource/mdadm.rb9
-rw-r--r--lib/chef/resource/mount.rb8
-rw-r--r--lib/chef/resource/ohai.rb7
-rw-r--r--lib/chef/resource/openbsd_package.rb7
-rw-r--r--lib/chef/resource/package.rb13
-rw-r--r--lib/chef/resource/pacman_package.rb6
-rw-r--r--lib/chef/resource/paludis_package.rb5
-rw-r--r--lib/chef/resource/perl.rb3
-rw-r--r--lib/chef/resource/portage_package.rb3
-rw-r--r--lib/chef/resource/powershell_script.rb3
-rw-r--r--lib/chef/resource/python.rb3
-rw-r--r--lib/chef/resource/reboot.rb6
-rw-r--r--lib/chef/resource/registry_key.rb8
-rw-r--r--lib/chef/resource/remote_directory.rb8
-rw-r--r--lib/chef/resource/remote_file.rb4
-rw-r--r--lib/chef/resource/route.rb8
-rw-r--r--lib/chef/resource/rpm_package.rb2
-rw-r--r--lib/chef/resource/ruby.rb3
-rw-r--r--lib/chef/resource/ruby_block.rb7
-rw-r--r--lib/chef/resource/scm.rb8
-rw-r--r--lib/chef/resource/script.rb3
-rw-r--r--lib/chef/resource/service.rb8
-rw-r--r--lib/chef/resource/smartos_package.rb8
-rw-r--r--lib/chef/resource/solaris_package.rb9
-rw-r--r--lib/chef/resource/subversion.rb5
-rw-r--r--lib/chef/resource/template.rb4
-rw-r--r--lib/chef/resource/timestamped_deploy.rb5
-rw-r--r--lib/chef/resource/user.rb8
-rw-r--r--lib/chef/resource/whyrun_safe_ruby_block.rb6
-rw-r--r--lib/chef/resource/windows_package.rb7
-rw-r--r--lib/chef/resource/windows_script.rb4
-rw-r--r--lib/chef/resource/windows_service.rb7
-rw-r--r--lib/chef/resource/yum_package.rb3
-rw-r--r--lib/chef/resource_builder.rb7
-rw-r--r--lib/chef/resource_resolver.rb90
-rw-r--r--lib/chef/server_api.rb2
-rw-r--r--lib/chef/util/path_helper.rb1
-rw-r--r--spec/functional/audit/runner_spec.rb64
-rw-r--r--spec/functional/mixin/powershell_out_spec.rb43
-rw-r--r--spec/functional/resource/execute_spec.rb11
-rw-r--r--spec/functional/resource/group_spec.rb5
-rw-r--r--spec/functional/resource/powershell_spec.rb45
-rw-r--r--spec/integration/recipes/provider_choice.rb9
-rw-r--r--spec/integration/recipes/recipe_dsl_spec.rb22
-rw-r--r--spec/integration/recipes/resource_definition_spec.rb18
-rw-r--r--spec/spec_helper.rb2
-rw-r--r--spec/support/lib/chef/resource/cat.rb3
-rw-r--r--spec/support/lib/chef/resource/one_two_three_four.rb7
-rw-r--r--spec/support/lib/chef/resource/with_state.rb11
-rw-r--r--spec/support/lib/chef/resource/zen_follower.rb7
-rw-r--r--spec/support/lib/chef/resource/zen_master.rb8
-rw-r--r--spec/support/shared/context/client.rb6
-rw-r--r--spec/support/shared/functional/windows_script.rb2
-rw-r--r--spec/unit/audit/audit_reporter_spec.rb8
-rw-r--r--spec/unit/audit/logger_spec.rb42
-rw-r--r--spec/unit/audit/runner_spec.rb4
-rw-r--r--spec/unit/deprecation_spec.rb55
-rw-r--r--spec/unit/dsl/resources_spec.rb85
-rw-r--r--spec/unit/knife/core/subcommand_loader_spec.rb22
-rw-r--r--spec/unit/lwrp_spec.rb16
-rw-r--r--spec/unit/mixin/powershell_out_spec.rb70
-rw-r--r--spec/unit/node_map_spec.rb5
-rw-r--r--spec/unit/platform_spec.rb60
-rw-r--r--spec/unit/provider/deploy_spec.rb2
-rw-r--r--spec/unit/provider/package/rubygems_spec.rb32
-rw-r--r--spec/unit/provider/powershell_spec.rb64
-rw-r--r--spec/unit/provider_resolver_spec.rb789
-rw-r--r--spec/unit/recipe_spec.rb31
-rw-r--r--spec/unit/resource/breakpoint_spec.rb2
-rw-r--r--spec/unit/resource/erl_call_spec.rb2
-rw-r--r--spec/unit/resource/file_spec.rb2
-rw-r--r--spec/unit/resource/ifconfig_spec.rb16
-rw-r--r--spec/unit/resource/route_spec.rb2
-rw-r--r--spec/unit/resource/ruby_block_spec.rb4
-rw-r--r--spec/unit/resource/timestamped_deploy_spec.rb3
-rw-r--r--spec/unit/resource/windows_service_spec.rb2
-rw-r--r--spec/unit/resource_spec.rb114
169 files changed, 2865 insertions, 1926 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c82a9d8ad7..cdaff78a22 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,13 +1,22 @@
## Unreleased
* [**Yukihiko SAWANOBORI**](https://github.com/sawanoboly): Pass name by
knife cil attribute [pr#3195](https://github.com/chef/chef/pull/3195)
+* [**Torben Knerr**](https://github.com/tknerr):
+ Allow knife sub-command loader to match platform specific gems. [pr#3281](https://github.com/chef/chef/pull/3281)
+* [Issue #2247](https://github.com/chef/chef/issues/2247): powershell_script returns 0 for scripts with syntax errors
+* [pr#3080](https://github.com/chef/chef/pull/3080): Issue 2247: powershell_script exit status should be nonzero for syntax errors
+* [pr#3441](https://github.com/chef/chef/pull/3441): Add powershell_out mixin to core chef
+* [pr#3448](https://github.com/chef/chef/pull/3448): Fix dsc_resource to work with wmf5 april preview
+* [pr#3392](https://github.com/chef/chef/pull/3392): Comment up Chef::Client and privatize/deprecate unused things
* [pr#3419](https://github.com/chef/chef/pull/3419): Fix cli issue with chef_repo_path when ENV variable is unset
* [pr#3358](https://github.com/chef/chef/pull/3358): Separate audit and converge failures
* [pr#3431](https://github.com/chef/chef/pull/3431): Fix backups on windows for the file resource
* [pr#3397](https://github.com/chef/chef/pull/3397): Validate owner exists in directory resources
* [pr#3418](https://github.com/chef/chef/pull/3418): Add `shell_out` mixin to Chef::Resource class for use in `not_if`/`only_if` conditionals, etc.
* [pr#3406](https://github.com/chef/chef/pull/3406): Add wide-char 'Environment' to `broadcast_env_change` mixin for setting windows environment variables
+* [pr#3442](https://github.com/chef/chef/pull/3442): Add resource_name to top-level Resource class to make defining resources easier. `use_automatic_resource_name` also added, to support convention-based resource naming.
+* [pr#3447](https://github.com/chef/chef/pull/3447): Add allowed_actions and default_action to top-level Resource class.
## 12.4.0
diff --git a/DOC_CHANGES.md b/DOC_CHANGES.md
index b0a8e0aaaf..cba06a26e6 100644
--- a/DOC_CHANGES.md
+++ b/DOC_CHANGES.md
@@ -6,23 +6,41 @@ Example Doc Change:
Description of the required change.
-->
-### Resources must now use `provides` to declare recipe DSL
+### Resources must now use `resource_name` to declare recipe DSL
Resources declared in `Chef::Resource` namespace will no longer get recipe DSL
-automatically. Instead, explicit `provides` is required in order to have DSL:
+automatically. Instead, `resource_name` is required in order to have DSL:
```ruby
module MyModule
class MyResource < Chef::Resource
- provides :my_resource
+ use_automatic_resource_name # Names the resource "my_resource"
end
end
```
+`resource_name :my_resource` may be used to explicitly set the resource name.
+
+`provides :my_resource` still works, but at least one resource_name *must* be
+set for the resource to work.
+
Authors of HWRPs need to be aware that in the future all resources and providers will be required to include a provides line. Starting with Chef 12.4.0 any HWRPs in the `Chef::Resource` or `Chef::Provider` namespaces that do not have provides lines will trigger deprecation warning messages when called. The LWRPBase code does `provides` automatically so LWRP authors and users who write classes that inherit from LWRPBase do not need to explicitly include provides lines.
Users are encouraged to declare resources in their own namespaces instead of putting them in the special `Chef::Resource` namespace.
+### Resources may now use `allowed_actions` and `default_action`
+
+Instead of overriding `Chef::Resource.initialize` and setting `@allowed_actions` and `@action` in the constructor, you may now use the `allowed_actions` and `default_action` DSL to declare them:
+
+```ruby
+class MyResource < Chef::Resource
+ use_automatic_resource_name
+
+ allowed_actions :create, :delete
+ default_action :create
+end
+```
+
### LWRPs are no longer automatically placed in the `Chef::Resource` namespace
Starting with Chef 12.4.0, accessing an LWRP class by name from the `Chef::Resource` namespace will trigger a deprecation warning message. This means that if your cookbook includes the LWRP `mycookbook/resources/myresource.rb`, you will no longer be able to extend or reference `Chef::Resource::MycookbookMyresource` in Ruby code. LWRP recipe DSL does not change: the LWRP will still be available to recipes as `mycookbook_myresource`.
diff --git a/Rakefile b/Rakefile
index d01a139c30..6a6e163a53 100644
--- a/Rakefile
+++ b/Rakefile
@@ -108,9 +108,19 @@ Dir[File.expand_path("../*gemspec", __FILE__)].reverse.each do |gemspec_path|
Gem::PackageTask.new(gemspec).define
end
+def with_clean_env(&block)
+ if defined?(Bundler)
+ Bundler.with_clean_env(&block)
+ else
+ block.call
+ end
+end
+
desc "Build and install a chef gem"
task :install => [:package] do
- sh %{gem install pkg/#{GEM_NAME}-#{VERSION}.gem --no-rdoc --no-ri}
+ with_clean_env do
+ sh %{gem install pkg/#{GEM_NAME}-#{VERSION}.gem --no-rdoc --no-ri}
+ end
end
task :uninstall do
diff --git a/chef-config/Rakefile b/chef-config/Rakefile
index 6eb195f672..10b6010de3 100644
--- a/chef-config/Rakefile
+++ b/chef-config/Rakefile
@@ -8,9 +8,19 @@ Dir[File.expand_path("../*gemspec", __FILE__)].reverse.each do |gemspec_path|
Gem::PackageTask.new(gemspec).define
end
+def with_clean_env(&block)
+ if defined?(Bundler)
+ Bundler.with_clean_env(&block)
+ else
+ block.call
+ end
+end
+
desc "Build and install a chef-config gem"
task :install => [:package] do
- sh %{gem install pkg/chef-config-#{ChefConfig::VERSION}.gem --no-rdoc --no-ri}
+ with_clean_env do
+ sh(%{gem install pkg/chef-config-#{ChefConfig::VERSION}.gem --no-rdoc --no-ri}, verbose: true)
+ end
end
task :default => :spec
diff --git a/lib/chef/audit/audit_reporter.rb b/lib/chef/audit/audit_reporter.rb
index b74bf07b8b..d952d8a249 100644
--- a/lib/chef/audit/audit_reporter.rb
+++ b/lib/chef/audit/audit_reporter.rb
@@ -47,7 +47,7 @@ class Chef
@run_status = run_status
end
- def audit_phase_complete
+ def audit_phase_complete(audit_output)
Chef::Log.debug("Audit Reporter completed successfully without errors.")
ordered_control_groups.each do |name, control_group|
audit_data.add_control_group(control_group)
@@ -58,7 +58,7 @@ class Chef
# that runs tests - normal errors are interpreted as EXAMPLE failures and captured.
# We still want to send available audit information to the server so we process the
# known control groups.
- def audit_phase_failed(error)
+ def audit_phase_failed(error, audit_output)
# The stacktrace information has already been logged elsewhere
@audit_phase_error = error
Chef::Log.debug("Audit Reporter failed.")
diff --git a/lib/chef/audit/logger.rb b/lib/chef/audit/logger.rb
new file mode 100644
index 0000000000..e46f54e582
--- /dev/null
+++ b/lib/chef/audit/logger.rb
@@ -0,0 +1,36 @@
+#
+# 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 'stringio'
+
+class Chef
+ class Audit
+ class Logger
+ def self.puts(message="")
+ @buffer ||= StringIO.new
+ @buffer.puts(message)
+
+ Chef::Log.info(message)
+ end
+
+ def self.read_buffer
+ return "" if @buffer.nil?
+ @buffer.string
+ end
+ end
+ end
+end
diff --git a/lib/chef/audit/runner.rb b/lib/chef/audit/runner.rb
index 801bf5ee58..234d83ab8f 100644
--- a/lib/chef/audit/runner.rb
+++ b/lib/chef/audit/runner.rb
@@ -16,6 +16,8 @@
# limitations under the License.
#
+require 'chef/audit/logger'
+
class Chef
class Audit
class Runner
@@ -115,8 +117,8 @@ class Chef
# the output stream to be changed for a formatter once the formatter has
# been added.
def set_streams
- RSpec.configuration.output_stream = Chef::Config[:log_location]
- RSpec.configuration.error_stream = Chef::Config[:log_location]
+ RSpec.configuration.output_stream = Chef::Audit::Logger
+ RSpec.configuration.error_stream = Chef::Audit::Logger
end
# Add formatters which we use to
diff --git a/lib/chef/chef_class.rb b/lib/chef/chef_class.rb
index d3f7ee55c7..7c0a2bf944 100644
--- a/lib/chef/chef_class.rb
+++ b/lib/chef/chef_class.rb
@@ -26,6 +26,9 @@
# injected" into this class by other objects and do not reference the class symbols in those files
# directly and we do not need to require those files here.
+require 'chef/platform/provider_priority_map'
+require 'chef/platform/resource_priority_map'
+
class Chef
class << self
@@ -48,7 +51,7 @@ class Chef
# @param resource_name [Symbol] name of the resource as a symbol
# @return [Array<Class>] Priority Array of Provider Classes to use for the resource_name on the node
def get_provider_priority_array(resource_name)
- @provider_priority_map.get_priority_array(node, resource_name).dup
+ provider_priority_map.get_priority_array(node, resource_name).dup
end
# Get the array of resources associated with a resource_name for the current node
@@ -56,27 +59,27 @@ class Chef
# @param resource_name [Symbol] name of the resource as a symbol
# @return [Array<Class>] Priority Array of Resource Classes to use for the resource_name on the node
def get_resource_priority_array(resource_name)
- @resource_priority_map.get_priority_array(node, resource_name).dup
+ resource_priority_map.get_priority_array(node, resource_name).dup
end
# Set the array of providers associated with a resource_name for the current node
#
# @param resource_name [Symbol] name of the resource as a symbol
- # @param priority_array [Array<Class>] Array of Classes to set as the priority for resource_name on the node
+ # @param priority_array [Class, Array<Class>] Class or Array of Classes to set as the priority for resource_name on the node
# @param filter [Hash] Chef::Nodearray-style filter
# @return [Array<Class>] Modified Priority Array of Provider Classes to use for the resource_name on the node
- def set_provider_priority_array(resource_name, priority_array, *filter)
- @provider_priority_map.set_priority_array(resource_name, priority_array, *filter).dup
+ def set_provider_priority_array(resource_name, priority_array, *filter, &block)
+ provider_priority_map.set_priority_array(resource_name, priority_array, *filter, &block).dup
end
# Get the array of resources associated with a resource_name for the current node
#
# @param resource_name [Symbol] name of the resource as a symbol
- # @param priority_array [Array<Class>] Array of Classes to set as the priority for resource_name on the node
+ # @param priority_array [Class, Array<Class>] Class or Array of Classes to set as the priority for resource_name on the node
# @param filter [Hash] Chef::Nodearray-style filter
# @return [Array<Class>] Modified Priority Array of Resource Classes to use for the resource_name on the node
- def set_resource_priority_array(resource_name, priority_array, *filter)
- @resource_priority_map.set_priority_array(resource_name, priority_array, *filter).dup
+ def set_resource_priority_array(resource_name, priority_array, *filter, &block)
+ resource_priority_map.set_priority_array(resource_name, priority_array, *filter, &block).dup
end
#
@@ -126,5 +129,21 @@ class Chef
@provider_priority_map = nil
@resource_priority_map = nil
end
+
+ private
+
+ def provider_priority_map
+ @provider_priority_map ||= begin
+ # these slurp in the resource+provider world, so be exceedingly lazy about requiring them
+ Chef::Platform::ProviderPriorityMap.instance
+ end
+ end
+ def resource_priority_map
+ @resource_priority_map ||= begin
+ Chef::Platform::ResourcePriorityMap.instance
+ end
+ end
end
+
+ reset!
end
diff --git a/lib/chef/client.rb b/lib/chef/client.rb
index f3e7722509..86e92585e3 100644
--- a/lib/chef/client.rb
+++ b/lib/chef/client.rb
@@ -50,6 +50,7 @@ require 'chef/run_lock'
require 'chef/policy_builder'
require 'chef/request_id'
require 'chef/platform/rebooter'
+require 'chef/mixin/deprecation'
require 'ohai'
require 'rbconfig'
@@ -60,121 +61,273 @@ class Chef
class Client
include Chef::Mixin::PathSanity
- # IO stream that will be used as 'STDOUT' for formatters. Formatters are
- # configured during `initialize`, so this provides a convenience for
- # setting alternative IO stream during tests.
- STDOUT_FD = STDOUT
-
- # IO stream that will be used as 'STDERR' for formatters. Formatters are
- # configured during `initialize`, so this provides a convenience for
- # setting alternative IO stream during tests.
- STDERR_FD = STDERR
-
- # Clears all notifications for client run status events.
- # Primarily for testing purposes.
- def self.clear_notifications
- @run_start_notifications = nil
- @run_completed_successfully_notifications = nil
- @run_failed_notifications = nil
- end
-
- # The list of notifications to be run when the client run starts.
- def self.run_start_notifications
- @run_start_notifications ||= []
- end
+ extend Chef::Mixin::Deprecation
- # The list of notifications to be run when the client run completes
- # successfully.
- def self.run_completed_successfully_notifications
- @run_completed_successfully_notifications ||= []
- end
-
- # The list of notifications to be run when the client run fails.
- def self.run_failed_notifications
- @run_failed_notifications ||= []
- end
-
- # Add a notification for the 'client run started' event. The notification
- # is provided as a block. The current Chef::RunStatus object will be passed
- # to the notification_block when the event is triggered.
- def self.when_run_starts(&notification_block)
- run_start_notifications << notification_block
- end
-
- # Add a notification for the 'client run success' event. The notification
- # is provided as a block. The current Chef::RunStatus object will be passed
- # to the notification_block when the event is triggered.
- def self.when_run_completes_successfully(&notification_block)
- run_completed_successfully_notifications << notification_block
- end
+ #
+ # The status of the Chef run.
+ #
+ # @return [Chef::RunStatus]
+ #
+ attr_reader :run_status
- # Add a notification for the 'client run failed' event. The notification
- # is provided as a block. The current Chef::RunStatus is passed to the
- # notification_block when the event is triggered.
- def self.when_run_fails(&notification_block)
- run_failed_notifications << notification_block
+ #
+ # The node represented by this client.
+ #
+ # @return [Chef::Node]
+ #
+ def node
+ run_status.node
end
-
- # Callback to fire notifications that the Chef run is starting
- def run_started
- self.class.run_start_notifications.each do |notification|
- notification.call(run_status)
- end
- @events.run_started(run_status)
+ def node=(value)
+ run_status.node = value
end
- # Callback to fire notifications that the run completed successfully
- def run_completed_successfully
- success_handlers = self.class.run_completed_successfully_notifications
- success_handlers.each do |notification|
- notification.call(run_status)
- end
- end
+ #
+ # The ohai system used by this client.
+ #
+ # @return [Ohai::System]
+ #
+ attr_reader :ohai
- # Callback to fire notifications that the Chef run failed
- def run_failed
- failure_handlers = self.class.run_failed_notifications
- failure_handlers.each do |notification|
- notification.call(run_status)
- end
- end
+ #
+ # The rest object used to communicate with the Chef server.
+ #
+ # @return [Chef::REST]
+ #
+ attr_reader :rest
- attr_accessor :node
- attr_accessor :ohai
- attr_accessor :rest
+ #
+ # The runner used to converge.
+ #
+ # @return [Chef::Runner]
+ #
attr_accessor :runner
+ #
+ # Extra node attributes that were applied to the node.
+ #
+ # @return [Hash]
+ #
attr_reader :json_attribs
- attr_reader :run_status
+
+ #
+ # The event dispatcher for the Chef run, including any configured output
+ # formatters and event loggers.
+ #
+ # @return [EventDispatch::Dispatcher]
+ #
+ # @see Chef::Formatters
+ # @see Chef::Config#formatters
+ # @see Chef::Config#stdout
+ # @see Chef::Config#stderr
+ # @see Chef::Config#force_logger
+ # @see Chef::Config#force_formatter
+ # TODO add stdout, stderr, and default formatters to Chef::Config so the
+ # defaults aren't calculated here. Remove force_logger and force_formatter
+ # from this code.
+ # @see Chef::EventLoggers
+ # @see Chef::Config#disable_event_logger
+ # @see Chef::Config#event_loggers
+ # @see Chef::Config#event_handlers
+ #
attr_reader :events
+ #
# Creates a new Chef::Client.
+ #
+ # @param json_attribs [Hash] Node attributes to layer into the node when it is
+ # fetched.
+ # @param args [Hash] Options:
+ # @option args [Array<RunList::RunListItem>] :override_runlist A runlist to
+ # use instead of the node's embedded run list.
+ # @option args [Array<String>] :specific_recipes A list of recipe file paths
+ # to load after the run list has been loaded.
+ #
def initialize(json_attribs=nil, args={})
@json_attribs = json_attribs || {}
- @node = nil
- @runner = nil
@ohai = Ohai::System.new
event_handlers = configure_formatters + configure_event_loggers
event_handlers += Array(Chef::Config[:event_handlers])
@events = EventDispatch::Dispatcher.new(*event_handlers)
+ # TODO it seems like a bad idea to be deletin' other peoples' hashes.
@override_runlist = args.delete(:override_runlist)
@specific_recipes = args.delete(:specific_recipes)
- @run_status = Chef::RunStatus.new(node, events)
+ @run_status = Chef::RunStatus.new(nil, events)
if new_runlist = args.delete(:runlist)
@json_attribs["run_list"] = new_runlist
end
+ end
- # these slurp in the resource+provider world, so be exceedingly lazy about requiring them
- require 'chef/platform/provider_priority_map' unless defined? Chef::Platform::ProviderPriorityMap
- require 'chef/platform/resource_priority_map' unless defined? Chef::Platform::ResourcePriorityMap
+ #
+ # Do a full run for this Chef::Client.
+ #
+ # Locks the run while doing its job.
+ #
+ # Fires run_start before doing anything and fires run_completed or
+ # run_failed when finished. Also notifies client listeners of run_started
+ # at the beginning of Compile, and run_completed_successfully or run_failed
+ # when all is complete.
+ #
+ # Phase 1: Setup
+ # --------------
+ # Gets information about the system and the run we are doing.
+ #
+ # 1. Run ohai to collect system information.
+ # 2. Register / connect to the Chef server (unless in solo mode).
+ # 3. Retrieve the node (or create a new one).
+ # 4. Merge in json_attribs, Chef::Config.environment, and override_run_list.
+ #
+ # @see #run_ohai
+ # @see #load_node
+ # @see #build_node
+ # @see Chef::Config#lockfile
+ # @see Chef::RunLock#acquire
+ #
+ # Phase 2: Compile
+ # ----------------
+ # Decides *what* we plan to converge by compiling recipes.
+ #
+ # 1. Sync required cookbooks to the local cache.
+ # 2. Load libraries from all cookbooks.
+ # 3. Load attributes from all cookbooks.
+ # 4. Load LWRPs from all cookbooks.
+ # 5. Load resource definitions from all cookbooks.
+ # 6. Load recipes in the run list.
+ # 7. Load recipes from the command line.
+ #
+ # @see #setup_run_context Syncs and compiles cookbooks.
+ # @see Chef::CookbookCompiler#compile
+ #
+ # Phase 3: Converge
+ # -----------------
+ # Brings the system up to date.
+ #
+ # 1. Converge the resources built from recipes in Phase 2.
+ # 2. Save the node.
+ # 3. Reboot if we were asked to.
+ #
+ # @see #converge_and_save
+ # @see Chef::Runner
+ #
+ # Phase 4: Audit
+ # --------------
+ # Runs 'control_group' audits in recipes. This entire section can be enabled or disabled with config.
+ #
+ # 1. 'control_group' DSL collects audits during Phase 2
+ # 2. Audits are run using RSpec
+ # 3. Errors are collected and reported using the formatters
+ #
+ # @see #run_audits
+ # @see Chef::Audit::Runner#run
+ #
+ # @raise [Chef::Exceptions::RunFailedWrappingError] If converge or audit failed.
+ #
+ # @see Chef::Config#enforce_path_sanity
+ # @see Chef::Config#solo
+ # @see Chef::Config#audit_mode
+ #
+ # @return Always returns true.
+ #
+ def run
+ run_error = nil
+
+ runlock = RunLock.new(Chef::Config.lockfile)
+ # TODO feels like acquire should have its own block arg for this
+ runlock.acquire
+ # don't add code that may fail before entering this section to be sure to release lock
+ begin
+ runlock.save_pid
- Chef.set_provider_priority_map(Chef::Platform::ProviderPriorityMap.instance)
- Chef.set_resource_priority_map(Chef::Platform::ResourcePriorityMap.instance)
+ request_id = Chef::RequestID.instance.request_id
+ run_context = nil
+ events.run_start(Chef::VERSION)
+ Chef::Log.info("*** Chef #{Chef::VERSION} ***")
+ Chef::Log.info "Chef-client pid: #{Process.pid}"
+ Chef::Log.debug("Chef-client request_id: #{request_id}")
+ enforce_path_sanity
+ run_ohai
+
+ register unless Chef::Config[:solo]
+
+ load_node
+
+ build_node
+
+ run_status.run_id = request_id
+ run_status.start_clock
+ Chef::Log.info("Starting Chef Run for #{node.name}")
+ run_started
+
+ do_windows_admin_check
+
+ run_context = setup_run_context
+
+ if Chef::Config[:audit_mode] != :audit_only
+ converge_error = converge_and_save(run_context)
+ end
+
+ if Chef::Config[:why_run] == true
+ # why_run should probably be renamed to why_converge
+ Chef::Log.debug("Not running controls in 'why_run' mode - this mode is used to see potential converge changes")
+ elsif Chef::Config[:audit_mode] != :disabled
+ audit_error = run_audits(run_context)
+ end
+
+ # Raise converge_error so run_failed reporters/events are processed.
+ raise converge_error if converge_error
+
+ run_status.stop_clock
+ Chef::Log.info("Chef Run complete in #{run_status.elapsed_time} seconds")
+ run_completed_successfully
+ events.run_completed(node)
+
+ # rebooting has to be the last thing we do, no exceptions.
+ Chef::Platform::Rebooter.reboot_if_needed!(node)
+ rescue Exception => run_error
+ # CHEF-3336: Send the error first in case something goes wrong below and we don't know why
+ Chef::Log.debug("Re-raising exception: #{run_error.class} - #{run_error.message}\n#{run_error.backtrace.join("\n ")}")
+ # If we failed really early, we may not have a run_status yet. Too early for these to be of much use.
+ if run_status
+ run_status.stop_clock
+ run_status.exception = run_error
+ run_failed
+ end
+ events.run_failed(run_error)
+ ensure
+ Chef::RequestID.instance.reset_request_id
+ request_id = nil
+ @run_status = nil
+ run_context = nil
+ runlock.release
+ GC.start
+ end
+
+ # Raise audit, converge, and other errors here so that we exit
+ # with the proper exit status code and everything gets raised
+ # as a RunFailedWrappingError
+ if run_error || converge_error || audit_error
+ error = if run_error == converge_error
+ Chef::Exceptions::RunFailedWrappingError.new(converge_error, audit_error)
+ else
+ Chef::Exceptions::RunFailedWrappingError.new(run_error, converge_error, audit_error)
+ end
+ error.fill_backtrace
+ Chef::Application.debug_stacktrace(error)
+ raise error
+ end
+
+ true
end
+ #
+ # Private API
+ # TODO make this stuff protected or private
+ #
+
+ # @api private
def configure_formatters
formatters_for_run.map do |formatter_name, output_path|
if output_path.nil?
@@ -187,6 +340,7 @@ class Chef
end
end
+ # @api private
def formatters_for_run
if Chef::Config.formatters.empty?
[default_formatter]
@@ -195,6 +349,7 @@ class Chef
end
end
+ # @api private
def default_formatter
if (STDOUT.tty? && !Chef::Config[:force_logger]) || Chef::Config[:force_formatter]
[:doc]
@@ -203,6 +358,7 @@ class Chef
end
end
+ # @api private
def configure_event_loggers
if Chef::Config.disable_event_logger
[]
@@ -219,8 +375,9 @@ class Chef
end
end
- # Resource repoters send event information back to the chef server for processing.
- # Can only be called after we have a @rest object
+ # Resource reporters send event information back to the chef server for
+ # processing. Can only be called after we have a @rest object
+ # @api private
def register_reporters
[
Chef::ResourceReporter.new(rest),
@@ -230,43 +387,123 @@ class Chef
end
end
+ #
+ # Callback to fire notifications that the Chef run is starting
+ #
+ # @api private
+ #
+ def run_started
+ self.class.run_start_notifications.each do |notification|
+ notification.call(run_status)
+ end
+ events.run_started(run_status)
+ end
+
+ #
+ # Callback to fire notifications that the run completed successfully
+ #
+ # @api private
+ #
+ def run_completed_successfully
+ success_handlers = self.class.run_completed_successfully_notifications
+ success_handlers.each do |notification|
+ notification.call(run_status)
+ end
+ end
+
+ #
+ # Callback to fire notifications that the Chef run failed
+ #
+ # @api private
+ #
+ def run_failed
+ failure_handlers = self.class.run_failed_notifications
+ failure_handlers.each do |notification|
+ notification.call(run_status)
+ end
+ end
+
+ #
# Instantiates a Chef::Node object, possibly loading the node's prior state
- # when using chef-client. Delegates to policy_builder. Injects the built node
- # into the Chef class.
+ # when using chef-client. Sets Chef.node to the new node.
#
# @return [Chef::Node] The node object for this Chef run
+ #
+ # @see Chef::PolicyBuilder#load_node
+ #
+ # @api private
+ #
def load_node
policy_builder.load_node
- @node = policy_builder.node
- Chef.set_node(@node)
+ run_status.node = policy_builder.node
+ Chef.set_node(policy_builder.node)
node
end
- # Mutates the `node` object to prepare it for the chef run. Delegates to
- # policy_builder
+ #
+ # Mutates the `node` object to prepare it for the chef run.
#
# @return [Chef::Node] The updated node object
+ #
+ # @see Chef::PolicyBuilder#build_node
+ #
+ # @api private
+ #
def build_node
policy_builder.build_node
- @run_status.node = node
+ run_status.node = node
node
end
+ #
+ # Sync cookbooks to local cache.
+ #
+ # TODO this appears to be unused.
+ #
+ # @see Chef::PolicyBuilder#sync_cookbooks
+ #
+ # @api private
+ #
+ def sync_cookbooks
+ policy_builder.sync_cookbooks
+ end
+
+ #
+ # Sets up the run context.
+ #
+ # @see Chef::PolicyBuilder#setup_run_context
+ #
+ # @return The newly set up run context
+ #
+ # @api private
def setup_run_context
- run_context = policy_builder.setup_run_context(@specific_recipes)
+ run_context = policy_builder.setup_run_context(specific_recipes)
assert_cookbook_path_not_empty(run_context)
run_status.run_context = run_context
run_context
end
- def sync_cookbooks
- policy_builder.sync_cookbooks
- end
-
+ #
+ # The PolicyBuilder strategy for figuring out run list and cookbooks.
+ #
+ # @return [Chef::PolicyBuilder::Policyfile, Chef::PolicyBuilder::ExpandNodeObject]
+ #
+ # @api private
+ #
def policy_builder
- @policy_builder ||= Chef::PolicyBuilder.strategy.new(node_name, ohai.data, json_attribs, @override_runlist, events)
+ @policy_builder ||= Chef::PolicyBuilder.strategy.new(node_name, ohai.data, json_attribs, override_runlist, events)
end
+ #
+ # Save the updated node to Chef.
+ #
+ # Does not save if we are in solo mode or using override_runlist.
+ #
+ # @see Chef::Node#save
+ # @see Chef::Config#solo
+ #
+ # @api private
+ #
def save_updated_node
if Chef::Config[:solo]
# nothing to do
@@ -274,16 +511,46 @@ class Chef
Chef::Log.warn("Skipping final node save because override_runlist was given")
else
Chef::Log.debug("Saving the current state of node #{node_name}")
- @node.save
+ node.save
end
end
+ #
+ # Run ohai plugins. Runs all ohai plugins unless minimal_ohai is specified.
+ #
+ # Sends the ohai_completed event when finished.
+ #
+ # @see Chef::EventDispatcher#
+ # @see Chef::Config#minimal_ohai
+ #
+ # @api private
+ #
def run_ohai
filter = Chef::Config[:minimal_ohai] ? %w[fqdn machinename hostname platform platform_version os os_version] : nil
ohai.all_plugins(filter)
- @events.ohai_completed(node)
+ events.ohai_completed(node)
end
+ #
+ # Figure out the node name we are working with.
+ #
+ # It tries these, in order:
+ # - Chef::Config.node_name
+ # - ohai[:fqdn]
+ # - ohai[:machinename]
+ # - ohai[:hostname]
+ #
+ # If we are running against a server with authentication protocol < 1.0, we
+ # *require* authentication protocol version 1.1.
+ #
+ # @raise [Chef::Exceptions::CannotDetermineNodeName] If the node name is not
+ # set and cannot be determined via ohai.
+ #
+ # @see Chef::Config#node_name
+ # @see Chef::Config#authentication_protocol_version
+ #
+ # @api private
+ #
def node_name
name = Chef::Config[:node_name] || ohai[:fqdn] || ohai[:machinename] || ohai[:hostname]
Chef::Config[:node_name] = name
@@ -292,6 +559,8 @@ class Chef
# node names > 90 bytes only work with authentication protocol >= 1.1
# see discussion in config.rb.
+ # TODO use a computed default in Chef::Config to determine this instead of
+ # setting it.
if name.bytesize > 90
Chef::Config[:authentication_protocol_version] = "1.1"
end
@@ -300,46 +569,86 @@ class Chef
end
#
- # === Returns
- # rest<Chef::REST>:: returns Chef::REST connection object
+ # Determine our private key and set up the connection to the Chef server.
+ #
+ # Skips registration and fires the `skipping_registration` event if
+ # Chef::Config.client_key is unspecified or already exists.
+ #
+ # If Chef::Config.client_key does not exist, we register the client with the
+ # Chef server and fire the registration_start and registration_completed events.
+ #
+ # @return [Chef::REST] The server connection object.
+ #
+ # @see Chef::Config#chef_server_url
+ # @see Chef::Config#client_key
+ # @see Chef::ApiClient::Registration#run
+ # @see Chef::EventDispatcher#skipping_registration
+ # @see Chef::EventDispatcher#registration_start
+ # @see Chef::EventDispatcher#registration_completed
+ # @see Chef::EventDispatcher#registration_failed
+ #
+ # @api private
+ #
def register(client_name=node_name, config=Chef::Config)
if !config[:client_key]
- @events.skipping_registration(client_name, config)
+ events.skipping_registration(client_name, config)
Chef::Log.debug("Client key is unspecified - skipping registration")
elsif File.exists?(config[:client_key])
- @events.skipping_registration(client_name, config)
+ events.skipping_registration(client_name, config)
Chef::Log.debug("Client key #{config[:client_key]} is present - skipping registration")
else
- @events.registration_start(node_name, config)
+ events.registration_start(node_name, config)
Chef::Log.info("Client key #{config[:client_key]} is not present - registering")
Chef::ApiClient::Registration.new(node_name, config[:client_key]).run
- @events.registration_completed
+ events.registration_completed
end
# We now have the client key, and should use it from now on.
@rest = Chef::REST.new(config[:chef_server_url], client_name, config[:client_key])
register_reporters
rescue Exception => e
+ # TODO this should probably only ever fire if we *started* registration.
+ # Move it to the block above.
# TODO: munge exception so a semantic failure message can be given to the
# user
- @events.registration_failed(client_name, e, config)
+ events.registration_failed(client_name, e, config)
raise
end
- # Converges the node.
#
- # === Returns
- # The thrown exception, if there was one. If this returns nil the converge was successful.
+ # Converges all compiled resources.
+ #
+ # Fires the converge_start, converge_complete and converge_failed events.
+ #
+ # If the exception `:end_client_run_early` is thrown during convergence, it
+ # does not mark the run complete *or* failed, and returns `nil`
+ #
+ # @param run_context The run context.
+ #
+ # @return The thrown exception, if we are in audit mode. `nil` means the
+ # converge was successful or ended early.
+ #
+ # @raise Any converge exception, unless we are in audit mode, in which case
+ # we *return* the exception.
+ #
+ # @see Chef::Runner#converge
+ # @see Chef::Config#audit_mode
+ # @see Chef::EventDispatch#converge_start
+ # @see Chef::EventDispatch#converge_complete
+ # @see Chef::EventDispatch#converge_failed
+ #
+ # @api private
+ #
def converge(run_context)
converge_exception = nil
catch(:end_client_run_early) do
begin
- @events.converge_start(run_context)
+ events.converge_start(run_context)
Chef::Log.debug("Converging node #{node_name}")
@runner = Chef::Runner.new(run_context)
@runner.converge
- @events.converge_complete
+ events.converge_complete
rescue Exception => e
- @events.converge_failed(e)
+ events.converge_failed(e)
raise e if Chef::Config[:audit_mode] == :disabled
converge_exception = e
end
@@ -347,8 +656,28 @@ class Chef
converge_exception
end
+ #
+ # Converge the node via and then save it if successful.
+ #
+ # @param run_context The run context.
+ #
+ # @return The thrown exception, if we are in audit mode. `nil` means the
+ # converge was successful or ended early.
+ #
+ # @raise Any converge or node save exception, unless we are in audit mode,
+ # in which case we *return* the exception.
+ #
+ # @see #converge
+ # @see #save_updated_mode
+ # @see Chef::Config#audit_mode
+ #
+ # @api private
+ #
# We don't want to change the old API on the `converge` method to have it perform
# saving. So we wrap it in this method.
+ # TODO given this seems to be pretty internal stuff, how badly do we need to
+ # split this stuff up?
+ #
def converge_and_save(run_context)
converge_exception = converge(run_context)
unless converge_exception
@@ -362,39 +691,67 @@ class Chef
converge_exception
end
+ #
+ # Run the audit phase.
+ #
+ # Triggers the audit_phase_start, audit_phase_complete and
+ # audit_phase_failed events.
+ #
+ # @param run_context The run context.
+ #
+ # @return Any thrown exceptions. `nil` if successful.
+ #
+ # @see Chef::Audit::Runner#run
+ # @see Chef::EventDispatch#audit_phase_start
+ # @see Chef::EventDispatch#audit_phase_complete
+ # @see Chef::EventDispatch#audit_phase_failed
+ #
+ # @api private
+ #
def run_audits(run_context)
- audit_exception = nil
begin
- @events.audit_phase_start(run_status)
+ events.audit_phase_start(run_status)
Chef::Log.info("Starting audit phase")
auditor = Chef::Audit::Runner.new(run_context)
auditor.run
if auditor.failed?
audit_exception = Chef::Exceptions::AuditsFailed.new(auditor.num_failed, auditor.num_total)
- @events.audit_phase_failed(audit_exception)
+ @events.audit_phase_failed(audit_exception, Chef::Audit::Logger.read_buffer)
else
- @events.audit_phase_complete
+ @events.audit_phase_complete(Chef::Audit::Logger.read_buffer)
end
rescue Exception => e
Chef::Log.error("Audit phase failed with error message: #{e.message}")
- @events.audit_phase_failed(e)
+ @events.audit_phase_failed(e, Chef::Audit::Logger.read_buffer)
audit_exception = e
end
audit_exception
end
- # Expands the run list. Delegates to the policy_builder.
#
- # Normally this does not need to be called from here, it will be called by
- # build_node. This is provided so external users (like the chefspec
- # project) can inject custom behavior into the run process.
+ # Expands the run list.
+ #
+ # @return [Chef::RunListExpansion] The expanded run list.
+ #
+ # @see Chef::PolicyBuilder#expand_run_list
#
- # === Returns
- # RunListExpansion: A RunListExpansion or API compatible object.
def expanded_run_list
policy_builder.expand_run_list
end
+ #
+ # Check if the user has Administrator privileges on windows.
+ #
+ # Throws an error if the user is not an admin, and
+ # `Chef::Config.fatal_windows_admin_check` is true.
+ #
+ # @raise [Chef::Exceptions::WindowsNotAdmin] If the user is not an admin.
+ #
+ # @see Chef::platform#windows?
+ # @see Chef::Config#fatal_windows_admin_check
+ #
+ # @api private
+ #
def do_windows_admin_check
if Chef::Platform.windows?
Chef::Log.debug("Checking for administrator privileges....")
@@ -414,108 +771,121 @@ class Chef
end
end
- # Do a full run for this Chef::Client. Calls:
- #
- # * run_ohai - Collect information about the system
- # * build_node - Get the last known state, merge with local changes
- # * register - If not in solo mode, make sure the server knows about this client
- # * sync_cookbooks - If not in solo mode, populate the local cache with the node's cookbooks
- # * converge - Bring this system up to date
- #
- # === Returns
- # true:: Always returns true.
- def run
- run_error = nil
-
- runlock = RunLock.new(Chef::Config.lockfile)
- runlock.acquire
- # don't add code that may fail before entering this section to be sure to release lock
- begin
- runlock.save_pid
-
- request_id = Chef::RequestID.instance.request_id
- run_context = nil
- @events.run_start(Chef::VERSION)
- Chef::Log.info("*** Chef #{Chef::VERSION} ***")
- Chef::Log.info "Chef-client pid: #{Process.pid}"
- Chef::Log.debug("Chef-client request_id: #{request_id}")
- enforce_path_sanity
- run_ohai
-
- register unless Chef::Config[:solo]
-
- load_node
-
- build_node
+ # Notification registration
+ class<<self
+ #
+ # Add a listener for the 'client run started' event.
+ #
+ # @param notification_block The callback (takes |run_status| parameter).
+ # @yieldparam [Chef::RunStatus] run_status The run status.
+ #
+ def when_run_starts(&notification_block)
+ run_start_notifications << notification_block
+ end
- run_status.run_id = request_id
- run_status.start_clock
- Chef::Log.info("Starting Chef Run for #{node.name}")
- run_started
+ #
+ # Add a listener for the 'client run success' event.
+ #
+ # @param notification_block The callback (takes |run_status| parameter).
+ # @yieldparam [Chef::RunStatus] run_status The run status.
+ #
+ def when_run_completes_successfully(&notification_block)
+ run_completed_successfully_notifications << notification_block
+ end
- do_windows_admin_check
+ #
+ # Add a listener for the 'client run failed' event.
+ #
+ # @param notification_block The callback (takes |run_status| parameter).
+ # @yieldparam [Chef::RunStatus] run_status The run status.
+ #
+ def when_run_fails(&notification_block)
+ run_failed_notifications << notification_block
+ end
- run_context = setup_run_context
+ #
+ # Clears all listeners for client run status events.
+ #
+ # Primarily for testing purposes.
+ #
+ # @api private
+ #
+ def clear_notifications
+ @run_start_notifications = nil
+ @run_completed_successfully_notifications = nil
+ @run_failed_notifications = nil
+ end
- if Chef::Config[:audit_mode] != :audit_only
- converge_error = converge_and_save(run_context)
- end
+ #
+ # TODO These seem protected to me.
+ #
+
+ #
+ # Listeners to be run when the client run starts.
+ #
+ # @return [Array<Proc>]
+ #
+ # @api private
+ #
+ def run_start_notifications
+ @run_start_notifications ||= []
+ end
- if Chef::Config[:why_run] == true
- # why_run should probably be renamed to why_converge
- Chef::Log.debug("Not running controls in 'why_run' mode - this mode is used to see potential converge changes")
- elsif Chef::Config[:audit_mode] != :disabled
- audit_error = run_audits(run_context)
- end
+ #
+ # Listeners to be run when the client run completes successfully.
+ #
+ # @return [Array<Proc>]
+ #
+ # @api private
+ #
+ def run_completed_successfully_notifications
+ @run_completed_successfully_notifications ||= []
+ end
- # Raise converge_error so run_failed reporters/events are processed.
- raise converge_error if converge_error
+ #
+ # Listeners to be run when the client run fails.
+ #
+ # @return [Array<Proc>]
+ #
+ # @api private
+ #
+ def run_failed_notifications
+ @run_failed_notifications ||= []
+ end
+ end
- run_status.stop_clock
- Chef::Log.info("Chef Run complete in #{run_status.elapsed_time} seconds")
- run_completed_successfully
- @events.run_completed(node)
+ #
+ # IO stream that will be used as 'STDOUT' for formatters. Formatters are
+ # configured during `initialize`, so this provides a convenience for
+ # setting alternative IO stream during tests.
+ #
+ # @api private
+ #
+ STDOUT_FD = STDOUT
- # rebooting has to be the last thing we do, no exceptions.
- Chef::Platform::Rebooter.reboot_if_needed!(node)
- rescue Exception => run_error
- # CHEF-3336: Send the error first in case something goes wrong below and we don't know why
- Chef::Log.debug("Re-raising exception: #{run_error.class} - #{run_error.message}\n#{run_error.backtrace.join("\n ")}")
- # If we failed really early, we may not have a run_status yet. Too early for these to be of much use.
- if run_status
- run_status.stop_clock
- run_status.exception = run_error
- run_failed
- end
- @events.run_failed(run_error)
- ensure
- Chef::RequestID.instance.reset_request_id
- request_id = nil
- @run_status = nil
- run_context = nil
- runlock.release
- GC.start
- end
+ #
+ # IO stream that will be used as 'STDERR' for formatters. Formatters are
+ # configured during `initialize`, so this provides a convenience for
+ # setting alternative IO stream during tests.
+ #
+ # @api private
+ #
+ STDERR_FD = STDERR
- # Raise audit, converge, and other errors here so that we exit
- # with the proper exit status code and everything gets raised
- # as a RunFailedWrappingError
- if run_error || converge_error || audit_error
- error = if run_error == converge_error
- Chef::Exceptions::RunFailedWrappingError.new(converge_error, audit_error)
- else
- Chef::Exceptions::RunFailedWrappingError.new(run_error, converge_error, audit_error)
- end
- error.fill_backtrace
- Chef::Application.debug_stacktrace(error)
- raise error
- end
+ #
+ # Deprecated writers
+ #
- true
- end
+ include Chef::Mixin::Deprecation
+ deprecated_attr_writer :ohai, "There is no alternative. Leave ohai alone!"
+ deprecated_attr_writer :rest, "There is no alternative. Leave rest alone!"
+ deprecated_attr :runner, "There is no alternative. Leave runner alone!"
private
+ attr_reader :override_runlist
+ attr_reader :specific_recipes
+
def empty_directory?(path)
!File.exists?(path) || (Dir.entries(path).size <= 2)
end
diff --git a/lib/chef/dsl/recipe.rb b/lib/chef/dsl/recipe.rb
index 97f5088b5d..ff398bc9e6 100644
--- a/lib/chef/dsl/recipe.rb
+++ b/lib/chef/dsl/recipe.rb
@@ -21,8 +21,10 @@ require 'chef/mixin/convert_to_class_name'
require 'chef/exceptions'
require 'chef/resource_builder'
require 'chef/mixin/shell_out'
+require 'chef/mixin/powershell_out'
require 'chef/dsl/resources'
require 'chef/dsl/definitions'
+require 'chef/resource'
class Chef
module DSL
@@ -33,58 +35,7 @@ class Chef
module Recipe
include Chef::Mixin::ShellOut
-
- # method_missing must live for backcompat purposes until Chef 13.
- def method_missing(method_symbol, *args, &block)
- #
- # If there is already DSL for this, someone must have called
- # method_missing manually. Not a fan. Not. A. Fan.
- #
- if respond_to?(method_symbol)
- Chef::Log.deprecation("Calling method_missing(#{method_symbol.inspect}) directly is deprecated in Chef 12 and will be removed in Chef 13.")
- Chef::Log.deprecation("Use public_send() or send() instead.")
- return send(method_symbol, *args, &block)
- end
-
- #
- # If a definition exists, then Chef::DSL::Definitions.add_definition was
- # never called. DEPRECATED.
- #
- if run_context.definitions.has_key?(method_symbol.to_sym)
- Chef::Log.deprecation("Definition #{method_symbol} (#{run_context.definitions[method_symbol.to_sym]}) was added to the run_context without calling Chef::DSL::Definitions.add_definition(#{method_symbol.to_sym.inspect}). This will become required in Chef 13.")
- Chef::DSL::Definitions.add_definition(method_symbol)
- return send(method_symbol, *args, &block)
- end
-
- #
- # See if the resource exists anyway. If the user had set
- # Chef::Resource::Blah = <resource>, a deprecation warning will be
- # emitted and the DSL method 'blah' will be added to the DSL.
- #
- resource_class = Chef::ResourceResolver.new(run_context ? run_context.node : nil, method_symbol).resolve
- if resource_class
- #
- # If the DSL method was *not* added, this is the case where the
- # matching class implements 'provides?' and matches resources that it
- # never declared "provides" for (which means we would never have
- # created DSL). Anything where we don't create DSL is deprecated.
- #
- if !respond_to?(method_symbol)
- Chef::Log.deprecation("#{resource_class} is marked as providing DSL #{method_symbol}, but provides #{method_symbol.inspect} was never called!")
- Chef::Log.deprecation("In Chef 13, this will break: you must call provides to mark the names you provide, even if you also override provides? yourself.")
- Chef::DSL::Resources.add_resource_dsl(method_symbol)
- end
- return send(method_symbol, *args, &block)
- end
-
- begin
- super
- rescue NoMethodError
- raise NoMethodError, "No resource or method named `#{method_symbol}' for #{describe_self_for_error}"
- rescue NameError
- raise NameError, "No resource, method, or local variable named `#{method_symbol}' for #{describe_self_for_error}"
- end
- end
+ include Chef::Mixin::PowershellOut
include Chef::DSL::Resources
include Chef::DSL::Definitions
@@ -183,14 +134,52 @@ class Chef
raise Chef::Exceptions::ResourceNotFound, "exec was called, but you probably meant to use an execute resource. If not, please call Kernel#exec explicitly. The exec block called was \"#{args}\""
end
+ # DEPRECATED:
+ # method_missing must live for backcompat purposes until Chef 13.
+ def method_missing(method_symbol, *args, &block)
+ #
+ # If there is already DSL for this, someone must have called
+ # method_missing manually. Not a fan. Not. A. Fan.
+ #
+ if respond_to?(method_symbol)
+ Chef::Log.deprecation("Calling method_missing(#{method_symbol.inspect}) directly is deprecated in Chef 12 and will be removed in Chef 13.")
+ Chef::Log.deprecation("Use public_send() or send() instead.")
+ return send(method_symbol, *args, &block)
+ end
+
+ #
+ # If a definition exists, then Chef::DSL::Definitions.add_definition was
+ # never called. DEPRECATED.
+ #
+ if run_context.definitions.has_key?(method_symbol.to_sym)
+ Chef::Log.deprecation("Definition #{method_symbol} (#{run_context.definitions[method_symbol.to_sym]}) was added to the run_context without calling Chef::DSL::Definitions.add_definition(#{method_symbol.to_sym.inspect}). This will become required in Chef 13.")
+ Chef::DSL::Definitions.add_definition(method_symbol)
+ return send(method_symbol, *args, &block)
+ end
+
+ #
+ # See if the resource exists anyway. If the user had set
+ # Chef::Resource::Blah = <resource>, a deprecation warning will be
+ # emitted and the DSL method 'blah' will be added to the DSL.
+ #
+ resource_class = Chef::ResourceResolver.new(run_context ? run_context.node : nil, method_symbol).resolve
+ if resource_class
+ Chef::DSL::Resources.add_resource_dsl(method_symbol)
+ return send(method_symbol, *args, &block)
+ end
+
+ begin
+ super
+ rescue NoMethodError
+ raise NoMethodError, "No resource or method named `#{method_symbol}' for #{describe_self_for_error}"
+ rescue NameError
+ raise NameError, "No resource, method, or local variable named `#{method_symbol}' for #{describe_self_for_error}"
+ end
+ end
end
end
end
-# We require this at the BOTTOM of this file to avoid circular requires (it is used
-# at runtime but not load time)
-require 'chef/resource'
-
# **DEPRECATED**
# This used to be part of chef/mixin/recipe_definition_dsl_core. Load the file to activate the deprecation code.
require 'chef/mixin/recipe_definition_dsl_core'
diff --git a/lib/chef/dsl/resources.rb b/lib/chef/dsl/resources.rb
index 4072ff2c89..a181c3be33 100644
--- a/lib/chef/dsl/resources.rb
+++ b/lib/chef/dsl/resources.rb
@@ -10,12 +10,12 @@ class Chef
def self.add_resource_dsl(dsl_name)
begin
module_eval(<<-EOM, __FILE__, __LINE__+1)
- def #{dsl_name}(name, created_at=nil, &block)
+ def #{dsl_name}(name=nil, created_at=nil, &block)
declare_resource(#{dsl_name.inspect}, name, created_at || caller[0], &block)
end
EOM
rescue SyntaxError
- define_method(dsl_name.to_sym) do |name, created_at=nil, &block|
+ define_method(dsl_name.to_sym) do |name=nil, created_at=nil, &block|
declare_resource(dsl_name, name, created_at || caller[0], &block)
end
end
diff --git a/lib/chef/event_dispatch/base.rb b/lib/chef/event_dispatch/base.rb
index 93caa62a65..73fe25ec13 100644
--- a/lib/chef/event_dispatch/base.rb
+++ b/lib/chef/event_dispatch/base.rb
@@ -244,13 +244,13 @@ class Chef
end
# Called when audit phase successfully finishes
- def audit_phase_complete
+ def audit_phase_complete(audit_output)
end
# Called if there is an uncaught exception during the audit phase. The audit runner should
# be catching and handling errors from the examples, so this is only uncaught errors (like
# bugs in our handling code)
- def audit_phase_failed(exception)
+ def audit_phase_failed(exception, audit_output)
end
# Signifies the start of a `control_group` block with a defined name
diff --git a/lib/chef/formatters/doc.rb b/lib/chef/formatters/doc.rb
index e63c764cbf..e76a940c38 100644
--- a/lib/chef/formatters/doc.rb
+++ b/lib/chef/formatters/doc.rb
@@ -179,11 +179,13 @@ class Chef
puts_line "Starting audit phase"
end
- def audit_phase_complete
+ def audit_phase_complete(audit_output)
+ puts_line audit_output
puts_line "Auditing complete"
end
- def audit_phase_failed(error)
+ def audit_phase_failed(error, audit_output)
+ puts_line audit_output
puts_line ""
puts_line "Audit phase exception:"
indent
diff --git a/lib/chef/knife/core/subcommand_loader.rb b/lib/chef/knife/core/subcommand_loader.rb
index 1f59515f44..a8705c724f 100644
--- a/lib/chef/knife/core/subcommand_loader.rb
+++ b/lib/chef/knife/core/subcommand_loader.rb
@@ -23,7 +23,7 @@ class Chef
class SubcommandLoader
MATCHES_CHEF_GEM = %r{/chef-[\d]+\.[\d]+\.[\d]+}.freeze
- MATCHES_THIS_CHEF_GEM = %r{/chef-#{Chef::VERSION}/}.freeze
+ MATCHES_THIS_CHEF_GEM = %r{/chef-#{Chef::VERSION}(-\w+)?(-\w+)?/}.freeze
attr_reader :chef_config_dir
attr_reader :env
diff --git a/lib/chef/mixin/deprecation.rb b/lib/chef/mixin/deprecation.rb
index 489f27c339..a3eacf75cb 100644
--- a/lib/chef/mixin/deprecation.rb
+++ b/lib/chef/mixin/deprecation.rb
@@ -95,6 +95,30 @@ class Chef
DeprecatedInstanceVariable.new(obj, name, level)
end
+ def deprecated_attr(name, alternative)
+ deprecated_attr_reader(name, alternative)
+ deprecated_attr_writer(name, alternative)
+ end
+
+ def deprecated_attr_reader(name, alternative, level=:warn)
+ define_method(name) do
+ Chef::Log.deprecation("#{self.class}.#{name} is deprecated. Support will be removed in a future release.")
+ Chef::Log.deprecation(alternative)
+ Chef::Log.deprecation("Called from:")
+ caller[0..3].each {|c| Chef::Log.deprecation(c)}
+ instance_variable_get("@#{name}")
+ end
+ end
+
+ def deprecated_attr_writer(name, alternative, level=:warn)
+ define_method("#{name}=") do |value|
+ Chef::Log.deprecation("Writing to #{self.class}.#{name} with #{name}= is deprecated. Support will be removed in a future release.")
+ Chef::Log.deprecation(alternative)
+ Chef::Log.deprecation("Called from:")
+ caller[0..3].each {|c| Chef::Log.deprecation(c)}
+ instance_variable_set("@#{name}", value)
+ end
+ end
end
end
end
diff --git a/lib/chef/mixin/powershell_out.rb b/lib/chef/mixin/powershell_out.rb
new file mode 100644
index 0000000000..e4f29c07c4
--- /dev/null
+++ b/lib/chef/mixin/powershell_out.rb
@@ -0,0 +1,98 @@
+#--
+# Copyright:: Copyright (c) 2015 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 'chef/mixin/shell_out'
+require 'chef/mixin/windows_architecture_helper'
+
+class Chef
+ module Mixin
+ module PowershellOut
+ include Chef::Mixin::ShellOut
+ include Chef::Mixin::WindowsArchitectureHelper
+
+ # Run a command under powershell with the same API as shell_out. The
+ # options hash is extended to take an "architecture" flag which
+ # can be set to :i386 or :x86_64 to force the windows architecture.
+ #
+ # @param script [String] script to run
+ # @param options [Hash] options hash
+ # @return [Mixlib::Shellout] mixlib-shellout object
+ def powershell_out(*command_args)
+ script = command_args.first
+ options = command_args.last.is_a?(Hash) ? command_args.last : nil
+
+ run_command_with_os_architecture(script, options)
+ end
+
+ # Run a command under powershell with the same API as shell_out!
+ # (raises exceptions on errors)
+ #
+ # @param script [String] script to run
+ # @param options [Hash] options hash
+ # @return [Mixlib::Shellout] mixlib-shellout object
+ def powershell_out!(*command_args)
+ cmd = powershell_out(*command_args)
+ cmd.error!
+ cmd
+ end
+
+ private
+
+ # Helper function to run shell_out and wrap it with the correct
+ # flags to possibly disable WOW64 redirection (which we often need
+ # because chef-client runs as a 32-bit app on 64-bit windows).
+ #
+ # @param script [String] script to run
+ # @param options [Hash] options hash
+ # @return [Mixlib::Shellout] mixlib-shellout object
+ def run_command_with_os_architecture(script, options)
+ options ||= {}
+ options = options.dup
+ arch = options.delete(:architecture)
+
+ with_os_architecture(nil, architecture: arch) do
+ shell_out(
+ build_powershell_command(script),
+ options
+ )
+ end
+ end
+
+ # Helper to build a powershell command around the script to run.
+ #
+ # @param script [String] script to run
+ # @retrurn [String] powershell command to execute
+ def build_powershell_command(script)
+ flags = [
+ # Hides the copyright banner at startup.
+ "-NoLogo",
+ # Does not present an interactive prompt to the user.
+ "-NonInteractive",
+ # Does not load the Windows PowerShell profile.
+ "-NoProfile",
+ # always set the ExecutionPolicy flag
+ # see http://technet.microsoft.com/en-us/library/ee176961.aspx
+ "-ExecutionPolicy Unrestricted",
+ # Powershell will hang if STDIN is redirected
+ # http://connect.microsoft.com/PowerShell/feedback/details/572313/powershell-exe-can-hang-if-stdin-is-redirected
+ "-InputFormat None"
+ ]
+
+ "powershell.exe #{flags.join(' ')} -Command \"#{script}\""
+ end
+ end
+ end
+end
diff --git a/lib/chef/mixin/provides.rb b/lib/chef/mixin/provides.rb
index c39c53a190..095e273dab 100644
--- a/lib/chef/mixin/provides.rb
+++ b/lib/chef/mixin/provides.rb
@@ -4,30 +4,17 @@ require 'chef/mixin/descendants_tracker'
class Chef
module Mixin
module Provides
+ # TODO no longer needed, remove or deprecate?
include Chef::Mixin::DescendantsTracker
- def node_map
- @node_map ||= Chef::NodeMap.new
- end
-
def provides(short_name, opts={}, &block)
- if !short_name.kind_of?(Symbol)
- # YAGNI: this is probably completely unnecessary and can be removed?
- Chef::Log.deprecation "Passing a non-Symbol to Chef::Resource#provides will be removed"
- if short_name.kind_of?(String)
- short_name.downcase!
- short_name.gsub!(/\s/, "_")
- end
- short_name = short_name.to_sym
- end
- node_map.set(short_name, true, opts, &block)
+ raise NotImplementedError, :provides
end
# Check whether this resource provides the resource_name DSL for the given
- # node
- def provides?(node, resource_name)
- resource_name = resource_name.resource_name if resource_name.is_a?(Chef::Resource)
- node_map.get(node, resource_name)
+ # node. TODO remove this when we stop checking unregistered things.
+ def provides?(node, resource)
+ raise NotImplementedError, :provides?
end
# Get the list of recipe DSL this resource is responsible for on the given
diff --git a/lib/chef/mixin/windows_architecture_helper.rb b/lib/chef/mixin/windows_architecture_helper.rb
index a0ac34f627..c5f3e1bd79 100644
--- a/lib/chef/mixin/windows_architecture_helper.rb
+++ b/lib/chef/mixin/windows_architecture_helper.rb
@@ -42,7 +42,7 @@ class Chef
is_i386_process_on_x86_64_windows?
end
- def with_os_architecture(node)
+ def with_os_architecture(node, architecture: nil)
node ||= begin
os_arch = ENV['PROCESSOR_ARCHITEW6432'] ||
ENV['PROCESSOR_ARCHITECTURE']
@@ -51,9 +51,12 @@ class Chef
n[:kernel][:machine] = os_arch == 'AMD64' ? :x86_64 : :i386
end
end
+
+ architecture ||= node_windows_architecture(node)
+
wow64_redirection_state = nil
- if wow64_architecture_override_required?(node, node_windows_architecture(node))
+ if wow64_architecture_override_required?(node, architecture)
wow64_redirection_state = disable_wow64_file_redirection(node)
end
diff --git a/lib/chef/node_map.rb b/lib/chef/node_map.rb
index 2ca6d9ba17..34f19d18b4 100644
--- a/lib/chef/node_map.rb
+++ b/lib/chef/node_map.rb
@@ -19,19 +19,6 @@
class Chef
class NodeMap
- VALID_OPTS = [
- :on_platform,
- :on_platforms,
- :platform,
- :os,
- :platform_family,
- ]
-
- DEPRECATED_OPTS = [
- :on_platform,
- :on_platforms,
- ]
-
# Create a new NodeMap
#
def initialize
@@ -47,14 +34,29 @@ class Chef
# @yield [node] Arbitrary node filter as a block which takes a node argument
# @return [NodeMap] Returns self for possible chaining
#
- def set(key, value, filters = {}, &block)
- validate_filter!(filters)
- deprecate_filter!(filters)
+ def set(key, value, platform: nil, platform_version: nil, platform_family: nil, os: nil, on_platform: nil, on_platforms: nil, &block)
+ Chef::Log.deprecation "The on_platform option to node_map has been deprecated" if on_platform
+ Chef::Log.deprecation "The on_platforms option to node_map has been deprecated" if on_platforms
+ platform ||= on_platform || on_platforms
+ filters = { platform: platform, platform_version: platform_version, platform_family: platform_family, os: os }
+ new_matcher = { filters: filters, block: block, value: value }
@map[key] ||= []
- # we match on the first value we find, so we want to unshift so that the
- # last setter wins
- # FIXME: need a test for this behavior
- @map[key].unshift({ filters: filters, block: block, value: value })
+ # Decide where to insert the matcher; the new value is preferred over
+ # anything more specific (see `priority_of`) and is preferred over older
+ # values of the same specificity. (So all other things being equal,
+ # newest wins.)
+ insert_at = nil
+ @map[key].each_with_index do |matcher, index|
+ if specificity(new_matcher) >= specificity(matcher)
+ insert_at = index
+ break
+ end
+ end
+ if insert_at
+ @map[key].insert(insert_at, new_matcher)
+ else
+ @map[key] << new_matcher
+ end
self
end
@@ -68,74 +70,90 @@ class Chef
def get(node, key)
# FIXME: real exception
raise "first argument must be a Chef::Node" unless node.is_a?(Chef::Node)
- return nil unless @map.has_key?(key)
- @map[key].each do |matcher|
- if filters_match?(node, matcher[:filters]) &&
- block_matches?(node, matcher[:block])
- return matcher[:value]
- end
- end
- nil
+ list(node, key).first
+ end
+
+ # List all matches for the given node and key from the NodeMap, from
+ # most-recently added to oldest.
+ #
+ # @param node [Chef::Node] The Chef::Node object for the run
+ # @param key [Object] Key to look up
+ # @return [Object] Value
+ #
+ def list(node, key)
+ # FIXME: real exception
+ raise "first argument must be a Chef::Node" unless node.is_a?(Chef::Node)
+ return [] unless @map.has_key?(key)
+ @map[key].select do |matcher|
+ filters_match?(node, matcher[:filters]) && block_matches?(node, matcher[:block])
+ end.map { |matcher| matcher[:value] }
end
private
- # only allow valid filter options
- def validate_filter!(filters)
- filters.each_key do |key|
- # FIXME: real exception
- raise "Bad key #{key} in Chef::NodeMap filter expression" unless VALID_OPTS.include?(key)
+ #
+ # Gives a value for "how specific" the matcher is.
+ # Things which specify more specific filters get a higher number
+ # (platform_version > platform > platform_family > os); things
+ # with a block have higher specificity than similar things without
+ # a block.
+ #
+ def specificity(matcher)
+ if matcher[:filters][:platform_version]
+ specificity = 8
+ elsif matcher[:filters][:platform]
+ specificity = 6
+ elsif matcher[:filters][:platform_family]
+ specificity = 4
+ elsif matcher[:filters][:os]
+ specificity = 2
+ else
+ specificity = 0
end
+ specificity += 1 if matcher[:block]
+ specificity
end
- # warn on deprecated filter options
- def deprecate_filter!(filters)
- filters.each_key do |key|
- Chef::Log.warn "The #{key} option to node_map has been deprecated" if DEPRECATED_OPTS.include?(key)
- end
- end
+ #
+ # Succeeds if:
+ # - no negative matches (!value)
+ # - at least one positive match (value or :all), or no positive filters
+ #
+ def matches_black_white_list?(node, filters, attribute)
+ # It's super common for the filter to be nil. Catch that so we don't
+ # spend any time here.
+ return true if !filters[attribute]
+ filter_values = Array(filters[attribute])
+ value = node[attribute]
- # @todo: this works fine, but is probably hard to understand
- def negative_match(filter, param)
- # We support strings prefaced by '!' to mean 'not'. In particular, this is most useful
- # for os matching on '!windows'.
- negative_matches = filter.select { |f| f[0] == '!' }
- return true if !negative_matches.empty? && negative_matches.include?('!' + param)
+ # Split the blacklist and whitelist
+ blacklist, whitelist = filter_values.partition { |v| v.is_a?(String) && v.start_with?('!') }
- # We support the symbol :all to match everything, for backcompat, but this can and should
- # simply be ommitted.
- positive_matches = filter.reject { |f| f[0] == '!' || f == :all }
- return true if !positive_matches.empty? && !positive_matches.include?(param)
+ # If any blacklist value matches, we don't match
+ return false if blacklist.any? { |v| v[1..-1] == value }
- # sorry double-negative: this means we pass this filter.
- false
+ # If the whitelist is empty, or anything matches, we match.
+ whitelist.empty? || whitelist.any? { |v| v == :all || v == value }
end
- def filters_match?(node, filters)
- return true if filters.empty?
+ def matches_version_list?(node, filters, attribute)
+ # It's super common for the filter to be nil. Catch that so we don't
+ # spend any time here.
+ return true if !filters[attribute]
+ filter_values = Array(filters[attribute])
+ value = node[attribute]
- # each filter is applied in turn. if any fail, then it shortcuts and returns false.
- # if it passes or does not exist it succeeds and continues on. so multiple filters are
- # effectively joined by 'and'. all filters can be single strings, or arrays which are
- # effectively joined by 'or'.
-
- os_filter = [ filters[:os] ].flatten.compact
- unless os_filter.empty?
- return false if negative_match(os_filter, node[:os])
- end
-
- platform_family_filter = [ filters[:platform_family] ].flatten.compact
- unless platform_family_filter.empty?
- return false if negative_match(platform_family_filter, node[:platform_family])
- end
-
- # :on_platform and :on_platforms here are synonyms which are deprecated
- platform_filter = [ filters[:platform] || filters[:on_platform] || filters[:on_platforms] ].flatten.compact
- unless platform_filter.empty?
- return false if negative_match(platform_filter, node[:platform])
+ filter_values.empty? ||
+ Array(filter_values).any? do |v|
+ Chef::VersionConstraint::Platform.new(v).include?(value)
end
+ end
- return true
+ def filters_match?(node, filters)
+ matches_black_white_list?(node, filters, :os) &&
+ matches_black_white_list?(node, filters, :platform_family) &&
+ matches_black_white_list?(node, filters, :platform) &&
+ matches_version_list?(node, filters, :platform_version)
end
def block_matches?(node, block)
diff --git a/lib/chef/platform/provider_mapping.rb b/lib/chef/platform/provider_mapping.rb
index 00458b6485..0440ff8601 100644
--- a/lib/chef/platform/provider_mapping.rb
+++ b/lib/chef/platform/provider_mapping.rb
@@ -20,13 +20,8 @@ require 'chef/log'
require 'chef/exceptions'
require 'chef/mixin/params_validate'
require 'chef/version_constraint/platform'
-
-# This file depends on nearly every provider in chef, but requiring them
-# directly causes circular requires resulting in uninitialized constant errors.
-# Therefore, we do the includes inline rather than up top.
require 'chef/provider'
-
class Chef
class Platform
@@ -34,267 +29,7 @@ class Chef
attr_writer :platforms
def platforms
- @platforms ||= begin
- require 'chef/providers'
-
- {
- :freebsd => {
- :default => {
- :group => Chef::Provider::Group::Pw,
- :user => Chef::Provider::User::Pw,
- }
- },
- :ubuntu => {
- :default => {
- :package => Chef::Provider::Package::Apt,
- :service => Chef::Provider::Service::Debian,
- },
- ">= 11.10" => {
- :ifconfig => Chef::Provider::Ifconfig::Debian
- }
- # Chef::Provider::Service::Upstart is a candidate to be used in
- # ubuntu versions >= 13.10 but it currently requires all the
- # services to have an entry under /etc/init. We need to update it
- # to use the service ctl apis in order to migrate to using it on
- # ubuntu >= 13.10.
- },
- :gcel => {
- :default => {
- :package => Chef::Provider::Package::Apt,
- :service => Chef::Provider::Service::Debian,
- }
- },
- :linaro => {
- :default => {
- :package => Chef::Provider::Package::Apt,
- :service => Chef::Provider::Service::Debian,
- }
- },
- :raspbian => {
- :default => {
- :package => Chef::Provider::Package::Apt,
- :service => Chef::Provider::Service::Debian,
- }
- },
- :linuxmint => {
- :default => {
- :package => Chef::Provider::Package::Apt,
- :service => Chef::Provider::Service::Upstart,
- }
- },
- :debian => {
- :default => {
- :package => Chef::Provider::Package::Apt,
- :service => Chef::Provider::Service::Debian,
- },
- ">= 6.0" => {
- :service => Chef::Provider::Service::Insserv
- },
- ">= 7.0" => {
- :ifconfig => Chef::Provider::Ifconfig::Debian
- }
- },
- :xenserver => {
- :default => {
- :service => Chef::Provider::Service::Redhat,
- :package => Chef::Provider::Package::Yum,
- }
- },
- :xcp => {
- :default => {
- :service => Chef::Provider::Service::Redhat,
- :package => Chef::Provider::Package::Yum,
- }
- },
- :centos => {
- :default => {
- :service => Chef::Provider::Service::Systemd,
- :package => Chef::Provider::Package::Yum,
- :ifconfig => Chef::Provider::Ifconfig::Redhat
- },
- "< 7" => {
- :service => Chef::Provider::Service::Redhat
- }
- },
- :amazon => {
- :default => {
- :service => Chef::Provider::Service::Redhat,
- :package => Chef::Provider::Package::Yum,
- }
- },
- :scientific => {
- :default => {
- :service => Chef::Provider::Service::Systemd,
- :package => Chef::Provider::Package::Yum,
- },
- "< 7" => {
- :service => Chef::Provider::Service::Redhat
- }
- },
- :fedora => {
- :default => {
- :service => Chef::Provider::Service::Systemd,
- :package => Chef::Provider::Package::Yum,
- :ifconfig => Chef::Provider::Ifconfig::Redhat
- },
- "< 15" => {
- :service => Chef::Provider::Service::Redhat
- }
- },
- :opensuse => {
- :default => {
- :service => Chef::Provider::Service::Redhat,
- :package => Chef::Provider::Package::Zypper,
- :group => Chef::Provider::Group::Suse
- },
- # Only OpenSuSE 12.3+ should use the Usermod group provider:
- ">= 12.3" => {
- :group => Chef::Provider::Group::Usermod
- }
- },
- :suse => {
- :default => {
- :service => Chef::Provider::Service::Systemd,
- :package => Chef::Provider::Package::Zypper,
- :group => Chef::Provider::Group::Gpasswd
- },
- "< 12.0" => {
- :group => Chef::Provider::Group::Suse,
- :service => Chef::Provider::Service::Redhat
- }
- },
- :oracle => {
- :default => {
- :service => Chef::Provider::Service::Systemd,
- :package => Chef::Provider::Package::Yum,
- },
- "< 7" => {
- :service => Chef::Provider::Service::Redhat
- }
- },
- :redhat => {
- :default => {
- :service => Chef::Provider::Service::Systemd,
- :package => Chef::Provider::Package::Yum,
- :ifconfig => Chef::Provider::Ifconfig::Redhat
- },
- "< 7" => {
- :service => Chef::Provider::Service::Redhat
- }
- },
- :ibm_powerkvm => {
- :default => {
- :service => Chef::Provider::Service::Redhat,
- :package => Chef::Provider::Package::Yum,
- :ifconfig => Chef::Provider::Ifconfig::Redhat
- }
- },
- :cloudlinux => {
- :default => {
- :service => Chef::Provider::Service::Redhat,
- :package => Chef::Provider::Package::Yum,
- :ifconfig => Chef::Provider::Ifconfig::Redhat
- }
- },
- :parallels => {
- :default => {
- :service => Chef::Provider::Service::Redhat,
- :package => Chef::Provider::Package::Yum,
- :ifconfig => Chef::Provider::Ifconfig::Redhat
- }
- },
- :gentoo => {
- :default => {
- :package => Chef::Provider::Package::Portage,
- :service => Chef::Provider::Service::Gentoo,
- }
- },
- :arch => {
- :default => {
- :package => Chef::Provider::Package::Pacman,
- :service => Chef::Provider::Service::Systemd,
- }
- },
- :solaris => {},
- :openindiana => {
- :default => {
- :mount => Chef::Provider::Mount::Solaris,
- :package => Chef::Provider::Package::Ips,
- :group => Chef::Provider::Group::Usermod
- }
- },
- :opensolaris => {
- :default => {
- :mount => Chef::Provider::Mount::Solaris,
- :package => Chef::Provider::Package::Ips,
- :group => Chef::Provider::Group::Usermod
- }
- },
- :nexentacore => {
- :default => {
- :mount => Chef::Provider::Mount::Solaris,
- :package => Chef::Provider::Package::Solaris,
- :group => Chef::Provider::Group::Usermod
- }
- },
- :omnios => {
- :default => {
- :mount => Chef::Provider::Mount::Solaris,
- :package => Chef::Provider::Package::Ips,
- :group => Chef::Provider::Group::Usermod,
- :user => Chef::Provider::User::Solaris,
- }
- },
- :solaris2 => {
- :default => {
- :mount => Chef::Provider::Mount::Solaris,
- :package => Chef::Provider::Package::Ips,
- :group => Chef::Provider::Group::Usermod,
- :user => Chef::Provider::User::Solaris,
- },
- "< 5.11" => {
- :mount => Chef::Provider::Mount::Solaris,
- :package => Chef::Provider::Package::Solaris,
- :group => Chef::Provider::Group::Usermod,
- :user => Chef::Provider::User::Solaris,
- }
- },
- :smartos => {
- :default => {
- :mount => Chef::Provider::Mount::Solaris,
- :package => Chef::Provider::Package::SmartOS,
- :group => Chef::Provider::Group::Usermod
- }
- },
- :hpux => {
- :default => {
- :group => Chef::Provider::Group::Usermod
- }
- },
- :aix => {
- :default => {
- :group => Chef::Provider::Group::Aix,
- :mount => Chef::Provider::Mount::Aix,
- :ifconfig => Chef::Provider::Ifconfig::Aix,
- :package => Chef::Provider::Package::Aix,
- :user => Chef::Provider::User::Aix,
- :service => Chef::Provider::Service::Aix
- }
- },
- :exherbo => {
- :default => {
- :package => Chef::Provider::Package::Paludis,
- :service => Chef::Provider::Service::Systemd,
- }
- },
- :default => {
- :mount => Chef::Provider::Mount::Mount,
- :user => Chef::Provider::User::Useradd,
- :group => Chef::Provider::Group::Gpasswd,
- :ifconfig => Chef::Provider::Ifconfig,
- }
- }
- end
+ @platforms ||= { default: {} }
end
include Chef::Mixin::ParamsValidate
@@ -304,7 +39,7 @@ class Chef
name_sym = name
if name.kind_of?(String)
- name.downcase!
+ name = name.downcase
name.gsub!(/\s/, "_")
name_sym = name.to_sym
end
diff --git a/lib/chef/platform/provider_priority_map.rb b/lib/chef/platform/provider_priority_map.rb
index 1539f61900..9d703c9178 100644
--- a/lib/chef/platform/provider_priority_map.rb
+++ b/lib/chef/platform/provider_priority_map.rb
@@ -1,88 +1,25 @@
+require 'singleton'
class Chef
class Platform
class ProviderPriorityMap
include Singleton
- def initialize
- load_default_map
- end
-
def get_priority_array(node, resource_name)
priority_map.get(node, resource_name.to_sym)
end
- def set_priority_array(resource_name, priority_array, *filter)
- priority(resource_name.to_sym, priority_array.to_a, *filter)
+ def set_priority_array(resource_name, priority_array, *filter, &block)
+ priority_map.set(resource_name.to_sym, Array(priority_array), *filter, &block)
end
- def priority(*args)
- priority_map.set(*args)
+ # @api private
+ def list_handlers(node, resource_name)
+ priority_map.list(node, resource_name.to_sym).flatten(1).uniq
end
private
- def load_default_map
- require 'chef/providers'
-
- #
- # Linux
- #
-
- # default block for linux O/Sen must come before platform_family exceptions
- priority :service, [
- Chef::Provider::Service::Systemd,
- Chef::Provider::Service::Insserv,
- Chef::Provider::Service::Redhat,
- ], os: "linux"
-
- priority :service, [
- Chef::Provider::Service::Systemd,
- Chef::Provider::Service::Arch,
- ], platform_family: "arch"
-
- priority :service, [
- Chef::Provider::Service::Systemd,
- Chef::Provider::Service::Gentoo,
- ], platform_family: "gentoo"
-
- priority :service, [
- # we can determine what systemd supports accurately
- Chef::Provider::Service::Systemd,
- # on debian-ish system if an upstart script exists that must win over sysv types
- Chef::Provider::Service::Upstart,
- Chef::Provider::Service::Insserv,
- Chef::Provider::Service::Debian,
- Chef::Provider::Service::Invokercd,
- ], platform_family: "debian"
-
- priority :service, [
- Chef::Provider::Service::Systemd,
- Chef::Provider::Service::Insserv,
- Chef::Provider::Service::Redhat,
- ], platform_family: [ "rhel", "fedora", "suse" ]
-
- #
- # BSDen
- #
-
- priority :service, Chef::Provider::Service::Freebsd, os: [ "freebsd", "netbsd" ]
- priority :service, Chef::Provider::Service::Openbsd, os: [ "openbsd" ]
-
- #
- # Solaris-en
- #
-
- priority :service, Chef::Provider::Service::Solaris, os: "solaris2"
-
- #
- # Mac
- #
-
- priority :service, Chef::Provider::Service::Macosx, os: "darwin"
- priority :package, Chef::Provider::Package::Homebrew, os: "darwin"
- end
-
def priority_map
require 'chef/node_map'
@priority_map ||= Chef::NodeMap.new
diff --git a/lib/chef/platform/query_helpers.rb b/lib/chef/platform/query_helpers.rb
index 03b1c9ca1e..b3948eac21 100644
--- a/lib/chef/platform/query_helpers.rb
+++ b/lib/chef/platform/query_helpers.rb
@@ -39,6 +39,11 @@ class Chef
is_server_2003
end
+ def supports_powershell_execution_bypass?(node)
+ node[:languages] && node[:languages][:powershell] &&
+ node[:languages][:powershell][:version].to_i >= 3
+ end
+
def supports_dsc?(node)
node[:languages] && node[:languages][:powershell] &&
node[:languages][:powershell][:version].to_i >= 4
diff --git a/lib/chef/platform/resource_priority_map.rb b/lib/chef/platform/resource_priority_map.rb
index fc43b3e7db..e98fc12413 100644
--- a/lib/chef/platform/resource_priority_map.rb
+++ b/lib/chef/platform/resource_priority_map.rb
@@ -1,33 +1,25 @@
+require 'singleton'
+
class Chef
class Platform
class ResourcePriorityMap
include Singleton
- def initialize
- load_default_map
- end
-
def get_priority_array(node, resource_name)
priority_map.get(node, resource_name.to_sym)
end
- def set_priority_array(resource_name, priority_array, *filter)
- priority resource_name.to_sym, priority_array.to_a, *filter
+ def set_priority_array(resource_name, priority_array, *filter, &block)
+ priority_map.set(resource_name.to_sym, Array(priority_array), *filter, &block)
end
- def priority(*args)
- priority_map.set(*args)
+ # @api private
+ def list_handlers(*args)
+ priority_map.list(*args).flatten(1).uniq
end
private
- def load_default_map
- require 'chef/resources'
-
- # MacOSX
- priority :package, Chef::Resource::HomebrewPackage, os: "darwin"
- end
-
def priority_map
require 'chef/node_map'
@priority_map ||= Chef::NodeMap.new
diff --git a/lib/chef/provider.rb b/lib/chef/provider.rb
index 99d09d0507..e50e374804 100644
--- a/lib/chef/provider.rb
+++ b/lib/chef/provider.rb
@@ -22,14 +22,19 @@ 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/powershell_out'
require 'chef/mixin/provides'
require 'chef/platform/service_helpers'
require 'chef/node_map'
class Chef
class Provider
+ require 'chef/mixin/why_run'
+ require 'chef/mixin/shell_out'
+ require 'chef/mixin/provides'
include Chef::Mixin::WhyRun
include Chef::Mixin::ShellOut
+ include Chef::Mixin::PowershellOut
extend Chef::Mixin::Provides
# supports the given resource and action (late binding)
@@ -170,6 +175,14 @@ class Chef
converge_actions.add_action(descriptions, &block)
end
+ def self.provides(short_name, opts={}, &block)
+ Chef.set_provider_priority_array(short_name, self, opts, &block)
+ end
+
+ def self.provides?(node, resource)
+ Chef::ProviderResolver.new(node, resource, :nothing).provided_by?(self)
+ end
+
protected
def converge_actions
@@ -226,3 +239,9 @@ class Chef
extend DeprecatedLWRPClass
end
end
+
+# Requiring things at the bottom breaks cycles
+require 'chef/chef_class'
+require 'chef/mixin/why_run'
+require 'chef/resource_collection'
+require 'chef/runner'
diff --git a/lib/chef/provider/dsc_resource.rb b/lib/chef/provider/dsc_resource.rb
index 2812c154c6..5fa84a21e9 100644
--- a/lib/chef/provider/dsc_resource.rb
+++ b/lib/chef/provider/dsc_resource.rb
@@ -121,7 +121,14 @@ class Chef
# however Invoke-DscResource is not correctly writing to that
# stream and instead just dumping to stdout
@converge_description = result.stdout
- result.return_value[0]["InDesiredState"]
+
+ if result.return_value.is_a?(Array)
+ # WMF Feb 2015 Preview
+ result.return_value[0]["InDesiredState"]
+ else
+ # WMF April 2015 Preview
+ result.return_value["InDesiredState"]
+ end
end
def set_resource
diff --git a/lib/chef/provider/file.rb b/lib/chef/provider/file.rb
index 4ce2c040a4..5ed7c6ac5b 100644
--- a/lib/chef/provider/file.rb
+++ b/lib/chef/provider/file.rb
@@ -26,6 +26,7 @@ require 'fileutils'
require 'chef/scan_access_control'
require 'chef/mixin/checksum'
require 'chef/mixin/file_class'
+require 'chef/mixin/enforce_ownership_and_permissions'
require 'chef/util/backup'
require 'chef/util/diff'
require 'chef/util/selinux'
diff --git a/lib/chef/provider/group/aix.rb b/lib/chef/provider/group/aix.rb
index 6ac9d03357..92bb8cb225 100644
--- a/lib/chef/provider/group/aix.rb
+++ b/lib/chef/provider/group/aix.rb
@@ -23,6 +23,7 @@ class Chef
class Provider
class Group
class Aix < Chef::Provider::Group::Groupadd
+ provides :group, platform: 'aix'
def required_binaries
[ "/usr/bin/mkgroup",
diff --git a/lib/chef/provider/group/dscl.rb b/lib/chef/provider/group/dscl.rb
index d7e8f2e827..9775ac8270 100644
--- a/lib/chef/provider/group/dscl.rb
+++ b/lib/chef/provider/group/dscl.rb
@@ -21,7 +21,7 @@ class Chef
class Group
class Dscl < Chef::Provider::Group
- provides :group, os: "darwin"
+ provides :group, os: 'darwin'
def dscl(*args)
host = "."
diff --git a/lib/chef/provider/group/gpasswd.rb b/lib/chef/provider/group/gpasswd.rb
index 521affac11..432c524acd 100644
--- a/lib/chef/provider/group/gpasswd.rb
+++ b/lib/chef/provider/group/gpasswd.rb
@@ -22,6 +22,7 @@ class Chef
class Provider
class Group
class Gpasswd < Chef::Provider::Group::Groupadd
+ provides :group
def load_current_resource
super
diff --git a/lib/chef/provider/group/groupmod.rb b/lib/chef/provider/group/groupmod.rb
index f9299546c8..82b68b8672 100644
--- a/lib/chef/provider/group/groupmod.rb
+++ b/lib/chef/provider/group/groupmod.rb
@@ -21,7 +21,7 @@ class Chef
class Group
class Groupmod < Chef::Provider::Group
- provides :group, os: "netbsd"
+ provides :group, os: 'netbsd'
def load_current_resource
super
diff --git a/lib/chef/provider/group/pw.rb b/lib/chef/provider/group/pw.rb
index 7a66ab4d69..f877ed2424 100644
--- a/lib/chef/provider/group/pw.rb
+++ b/lib/chef/provider/group/pw.rb
@@ -20,6 +20,7 @@ class Chef
class Provider
class Group
class Pw < Chef::Provider::Group
+ provides :group, platform: 'freebsd'
def load_current_resource
super
diff --git a/lib/chef/provider/group/suse.rb b/lib/chef/provider/group/suse.rb
index 7ac2831d02..b47ea33e80 100644
--- a/lib/chef/provider/group/suse.rb
+++ b/lib/chef/provider/group/suse.rb
@@ -22,6 +22,8 @@ class Chef
class Provider
class Group
class Suse < Chef::Provider::Group::Groupadd
+ provides :group, platform: 'opensuse', platform_version: '< 12.3'
+ provides :group, platform: 'suse', platform_version: '< 12.0'
def load_current_resource
super
diff --git a/lib/chef/provider/group/usermod.rb b/lib/chef/provider/group/usermod.rb
index e50e13c443..d78d42d6e1 100644
--- a/lib/chef/provider/group/usermod.rb
+++ b/lib/chef/provider/group/usermod.rb
@@ -23,7 +23,8 @@ class Chef
class Group
class Usermod < Chef::Provider::Group::Groupadd
- provides :group, os: "openbsd"
+ provides :group, os: %w(openbsd solaris2 hpux)
+ provides :group, platform: "opensuse"
def load_current_resource
super
diff --git a/lib/chef/provider/group/windows.rb b/lib/chef/provider/group/windows.rb
index 54e49b0e06..46d8afc7f6 100644
--- a/lib/chef/provider/group/windows.rb
+++ b/lib/chef/provider/group/windows.rb
@@ -26,7 +26,7 @@ class Chef
class Group
class Windows < Chef::Provider::Group
- provides :group, os: "windows"
+ provides :group, os: 'windows'
def initialize(new_resource,run_context)
super
diff --git a/lib/chef/provider/ifconfig.rb b/lib/chef/provider/ifconfig.rb
index 06080c90c3..468e1ec639 100644
--- a/lib/chef/provider/ifconfig.rb
+++ b/lib/chef/provider/ifconfig.rb
@@ -39,6 +39,8 @@ require 'erb'
class Chef
class Provider
class Ifconfig < Chef::Provider
+ provides :ifconfig
+
include Chef::Mixin::ShellOut
include Chef::Mixin::Command
diff --git a/lib/chef/provider/ifconfig/aix.rb b/lib/chef/provider/ifconfig/aix.rb
index 8fead44bc6..25c3de3040 100644
--- a/lib/chef/provider/ifconfig/aix.rb
+++ b/lib/chef/provider/ifconfig/aix.rb
@@ -22,6 +22,7 @@ class Chef
class Provider
class Ifconfig
class Aix < Chef::Provider::Ifconfig
+ provides :ifconfig, platform: %w(aix)
def load_current_resource
@current_resource = Chef::Resource::Ifconfig.new(@new_resource.name)
diff --git a/lib/chef/provider/ifconfig/debian.rb b/lib/chef/provider/ifconfig/debian.rb
index 7589971143..1e6863c8b5 100644
--- a/lib/chef/provider/ifconfig/debian.rb
+++ b/lib/chef/provider/ifconfig/debian.rb
@@ -23,6 +23,8 @@ class Chef
class Provider
class Ifconfig
class Debian < Chef::Provider::Ifconfig
+ provides :ifconfig, platform: %w(ubuntu), platform_version: '>= 11.10'
+ provides :ifconfig, platform: %w(debian), platform_version: '>= 7.0'
INTERFACES_FILE = "/etc/network/interfaces"
INTERFACES_DOT_D_DIR = "/etc/network/interfaces.d"
diff --git a/lib/chef/provider/ifconfig/redhat.rb b/lib/chef/provider/ifconfig/redhat.rb
index ef35b0e012..ee053d1e52 100644
--- a/lib/chef/provider/ifconfig/redhat.rb
+++ b/lib/chef/provider/ifconfig/redhat.rb
@@ -22,6 +22,7 @@ class Chef
class Provider
class Ifconfig
class Redhat < Chef::Provider::Ifconfig
+ provides :ifconfig, platform_family: %w(fedora rhel)
def initialize(new_resource, run_context)
super(new_resource, run_context)
diff --git a/lib/chef/provider/mount.rb b/lib/chef/provider/mount.rb
index 1631d87033..2039e9ae51 100644
--- a/lib/chef/provider/mount.rb
+++ b/lib/chef/provider/mount.rb
@@ -24,7 +24,6 @@ require 'chef/provider'
class Chef
class Provider
class Mount < Chef::Provider
-
include Chef::Mixin::ShellOut
attr_accessor :unmount_retries
diff --git a/lib/chef/provider/mount/aix.rb b/lib/chef/provider/mount/aix.rb
index 0d7e11a1b8..4ad7b24c15 100644
--- a/lib/chef/provider/mount/aix.rb
+++ b/lib/chef/provider/mount/aix.rb
@@ -22,6 +22,7 @@ class Chef
class Provider
class Mount
class Aix < Chef::Provider::Mount::Mount
+ provides :mount, platform: %w(aix)
# Override for aix specific handling
def initialize(new_resource, run_context)
diff --git a/lib/chef/provider/mount/mount.rb b/lib/chef/provider/mount/mount.rb
index 0a6e269d2d..ef074166a9 100644
--- a/lib/chef/provider/mount/mount.rb
+++ b/lib/chef/provider/mount/mount.rb
@@ -24,6 +24,8 @@ class Chef
class Mount
class Mount < Chef::Provider::Mount
+ provides :mount
+
def initialize(new_resource, run_context)
super
@real_device = nil
diff --git a/lib/chef/provider/mount/solaris.rb b/lib/chef/provider/mount/solaris.rb
index d8cec24138..deb04d4d7b 100644
--- a/lib/chef/provider/mount/solaris.rb
+++ b/lib/chef/provider/mount/solaris.rb
@@ -27,6 +27,8 @@ class Chef
class Mount
# Mount Solaris File systems
class Solaris < Chef::Provider::Mount
+ provides :mount, platform: %w(openindiana opensolaris nexentacore omnios solaris2 smartos)
+
extend Forwardable
VFSTAB = '/etc/vfstab'.freeze
diff --git a/lib/chef/provider/package.rb b/lib/chef/provider/package.rb
index bdc96cd070..291ff882f6 100644
--- a/lib/chef/provider/package.rb
+++ b/lib/chef/provider/package.rb
@@ -490,6 +490,37 @@ class Chef
false
end
end
+
+ # Set provider priority
+ require 'chef/chef_class'
+ require 'chef/provider/package/dpkg'
+ require 'chef/provider/package/homebrew'
+ require 'chef/provider/package/macports'
+ require 'chef/provider/package/apt'
+ require 'chef/provider/package/yum'
+ require 'chef/provider/package/zypper'
+ require 'chef/provider/package/portage'
+ require 'chef/provider/package/pacman'
+ require 'chef/provider/package/ips'
+ require 'chef/provider/package/solaris'
+ require 'chef/provider/package/smartos'
+ require 'chef/provider/package/aix'
+ require 'chef/provider/package/paludis'
+
+ Chef.set_provider_priority_array :package, [ Homebrew, Macports ], os: "darwin"
+
+ Chef.set_provider_priority_array :package, Apt, platform_family: "debian"
+ Chef.set_provider_priority_array :package, Yum, platform_family: %w(rhel fedora)
+ Chef.set_provider_priority_array :package, Zypper, platform_family: "suse"
+ Chef.set_provider_priority_array :package, Portage, platform: "gentoo"
+ Chef.set_provider_priority_array :package, Pacman, platform: "arch"
+ Chef.set_provider_priority_array :package, Ips, platform: %w(openindiana opensolaris omnios solaris2)
+ Chef.set_provider_priority_array :package, Solaris, platform: "nexentacore"
+ Chef.set_provider_priority_array :package, Solaris, platform: "solaris2", platform_version: '< 5.11'
+
+ Chef.set_provider_priority_array :package, SmartOS, platform: "smartos"
+ Chef.set_provider_priority_array :package, Aix, platform: "aix"
+ Chef.set_provider_priority_array :package, Paludis, platform: "exherbo"
end
end
end
diff --git a/lib/chef/provider/package/homebrew.rb b/lib/chef/provider/package/homebrew.rb
index 603899646f..e2bc24d1ec 100644
--- a/lib/chef/provider/package/homebrew.rb
+++ b/lib/chef/provider/package/homebrew.rb
@@ -27,7 +27,6 @@ class Chef
class Homebrew < Chef::Provider::Package
provides :homebrew_package
- provides :package, os: "darwin"
include Chef::Mixin::HomebrewUser
diff --git a/lib/chef/provider/package/macports.rb b/lib/chef/provider/package/macports.rb
index b252344c99..97c13fec73 100644
--- a/lib/chef/provider/package/macports.rb
+++ b/lib/chef/provider/package/macports.rb
@@ -4,7 +4,6 @@ class Chef
class Macports < Chef::Provider::Package
provides :macports_package
- provides :package, os: "darwin"
def load_current_resource
@current_resource = Chef::Resource::Package.new(@new_resource.name)
diff --git a/lib/chef/provider/package/portage.rb b/lib/chef/provider/package/portage.rb
index bb047ad2fa..4ba0160bb0 100644
--- a/lib/chef/provider/package/portage.rb
+++ b/lib/chef/provider/package/portage.rb
@@ -25,6 +25,8 @@ class Chef
class Provider
class Package
class Portage < Chef::Provider::Package
+ provides :portage_package
+
PACKAGE_NAME_PATTERN = %r{(?:([^/]+)/)?([^/]+)}
def load_current_resource
diff --git a/lib/chef/provider/package/rubygems.rb b/lib/chef/provider/package/rubygems.rb
index c53aa8934a..d120a64f0d 100644
--- a/lib/chef/provider/package/rubygems.rb
+++ b/lib/chef/provider/package/rubygems.rb
@@ -32,14 +32,7 @@ require 'rubygems/version'
require 'rubygems/dependency'
require 'rubygems/spec_fetcher'
require 'rubygems/platform'
-
-# Compatibility note: Rubygems 2.0 removes rubygems/format in favor of
-# rubygems/package.
-begin
- require 'rubygems/format'
-rescue LoadError
- require 'rubygems/package'
-end
+require 'rubygems/package'
require 'rubygems/dependency_installer'
require 'rubygems/uninstaller'
require 'rubygems/specification'
diff --git a/lib/chef/provider/powershell_script.rb b/lib/chef/provider/powershell_script.rb
index f9dcd6d80c..ed44dee6ae 100644
--- a/lib/chef/provider/powershell_script.rb
+++ b/lib/chef/provider/powershell_script.rb
@@ -24,71 +24,153 @@ class Chef
provides :powershell_script, os: "windows"
+ def initialize (new_resource, run_context)
+ super(new_resource, run_context, '.ps1')
+ add_exit_status_wrapper
+ end
+
+ def action_run
+ valid_syntax = validate_script_syntax!
+ super if valid_syntax
+ end
+
+ def flags
+ # Must use -File rather than -Command to launch the script
+ # file created by the base class that contains the script
+ # code -- otherwise, powershell.exe does not propagate the
+ # error status of a failed Windows process that ran at the
+ # end of the script, it gets changed to '1'.
+ interpreter_flags = [default_interpreter_flags, '-File'].join(' ')
+
+ if ! (@new_resource.flags.nil?)
+ interpreter_flags = [@new_resource.flags, interpreter_flags].join(' ')
+ end
+
+ interpreter_flags
+ end
+
protected
- EXIT_STATUS_EXCEPTION_HANDLER = "\ntrap [Exception] {write-error -exception ($_.Exception.Message);exit 1}".freeze
- EXIT_STATUS_NORMALIZATION_SCRIPT = "\nif ($? -ne $true) { if ( $LASTEXITCODE ) {exit $LASTEXITCODE} else { exit 1 }}".freeze
- EXIT_STATUS_RESET_SCRIPT = "\n$global:LASTEXITCODE=$null".freeze
- # Process exit codes are strange with PowerShell. Unless you
- # explicitly call exit in Powershell, the powershell.exe
- # interpreter returns only 0 for success or 1 for failure. Since
- # we'd like to get specific exit codes from executable tools run
- # with Powershell, we do some work using the automatic variables
- # $? and $LASTEXITCODE to return the process exit code of the
- # last process run in the script if it is the last command
- # executed, otherwise 0 or 1 based on whether $? is set to true
- # (success, where we return 0) or false (where we return 1).
- def normalize_script_exit_status( code )
- target_code = ( EXIT_STATUS_EXCEPTION_HANDLER +
- EXIT_STATUS_RESET_SCRIPT +
- "\n" +
- code.to_s +
- EXIT_STATUS_NORMALIZATION_SCRIPT )
- convert_boolean_return = @new_resource.convert_boolean_return
- self.code = <<EOH
-new-variable -name interpolatedexitcode -visibility private -value $#{convert_boolean_return}
-new-variable -name chefscriptresult -visibility private
-$chefscriptresult = {
-#{target_code}
-}.invokereturnasis()
-if ($interpolatedexitcode -and $chefscriptresult.gettype().name -eq 'boolean') { exit [int32](!$chefscriptresult) } else { exit 0 }
-EOH
- Chef::Log.debug("powershell_script provider called with script code:\n\n#{code}\n")
+ # Process exit codes are strange with PowerShell and require
+ # special handling to cover common use cases.
+ def add_exit_status_wrapper
+ self.code = wrapper_script
+ Chef::Log.debug("powershell_script provider called with script code:\n\n#{@new_resource.code}\n")
Chef::Log.debug("powershell_script provider will execute transformed code:\n\n#{self.code}\n")
end
- public
+ def validate_script_syntax!
+ interpreter_arguments = default_interpreter_flags.join(' ')
+ Tempfile.open(['chef_powershell_script-user-code', '.ps1']) do | user_script_file |
+ user_script_file.puts("{#{@new_resource.code}}")
+ user_script_file.close
- def initialize (new_resource, run_context)
- super(new_resource, run_context, '.ps1')
- normalize_script_exit_status(new_resource.code)
+ validation_command = "\"#{interpreter}\" #{interpreter_arguments} -Command #{user_script_file.path}"
+
+ # For consistency with other script resources, allow even syntax errors
+ # to be suppressed if the returns attribute would have suppressed it
+ # at converge.
+ valid_returns = [0]
+ specified_returns = @new_resource.returns.is_a?(Integer) ?
+ [@new_resource.returns] :
+ @new_resource.returns
+ valid_returns.concat([1]) if specified_returns.include?(1)
+
+ result = shell_out!(validation_command, {returns: valid_returns})
+ result.exitstatus == 0
+ end
end
- def flags
- default_flags = [
+ def default_interpreter_flags
+ # 'Bypass' is preferable since it doesn't require user input confirmation
+ # for files such as PowerShell modules downloaded from the
+ # Internet. However, 'Bypass' is not supported prior to
+ # PowerShell 3.0, so the fallback is 'Unrestricted'
+ execution_policy = Chef::Platform.supports_powershell_execution_bypass?(run_context.node) ? 'Bypass' : 'Unrestricted'
+
+ [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
- "-ExecutionPolicy Unrestricted",
+ "-ExecutionPolicy #{execution_policy}",
# Powershell will hang if STDIN is redirected
# http://connect.microsoft.com/PowerShell/feedback/details/572313/powershell-exe-can-hang-if-stdin-is-redirected
- "-InputFormat None",
- # Must use -File rather than -Command to launch the script
- # file created by the base class that contains the script
- # code -- otherwise, powershell.exe does not propagate the
- # error status of a failed Windows process that ran at the
- # end of the script, it gets changed to '1'.
- "-File"
+ "-InputFormat None"
]
+ end
- interpreter_flags = default_flags.join(' ')
+ # A wrapper script is used to launch user-supplied script while
+ # still obtaining useful process exit codes. Unless you
+ # explicitly call exit in Powershell, the powershell.exe
+ # interpreter returns only 0 for success or 1 for failure. Since
+ # we'd like to get specific exit codes from executable tools run
+ # with Powershell, we do some work using the automatic variables
+ # $? and $LASTEXITCODE to return the process exit code of the
+ # last process run in the script if it is the last command
+ # executed, otherwise 0 or 1 based on whether $? is set to true
+ # (success, where we return 0) or false (where we return 1).
+ def wrapper_script
+<<-EOH
+# Chef Client wrapper for powershell_script resources
- if ! (@new_resource.flags.nil?)
- interpreter_flags = [@new_resource.flags, interpreter_flags].join(' ')
- end
+# LASTEXITCODE can be uninitialized -- make it explictly 0
+# to avoid incorrect detection of failure (non-zero) codes
+$global:LASTEXITCODE = 0
- interpreter_flags
+# Catch any exceptions -- without this, exceptions will result
+# In a zero return code instead of the desired non-zero code
+# that indicates a failure
+trap [Exception] {write-error ($_.Exception.Message);exit 1}
+
+# Variable state that should not be accessible to the user code
+new-variable -name interpolatedexitcode -visibility private -value $#{@new_resource.convert_boolean_return}
+new-variable -name chefscriptresult -visibility private
+
+# Initialize a variable we use to capture $? inside a block
+$global:lastcmdlet = $null
+
+# Execute the user's code in a script block --
+$chefscriptresult =
+{
+ #{@new_resource.code}
+
+ # This assignment doesn't affect the block's return value
+ $global:lastcmdlet = $?
+}.invokereturnasis()
+
+# Assume failure status of 1 -- success cases
+# will have to override this
+$exitstatus = 1
+
+# If convert_boolean_return is enabled, the block's return value
+# gets precedence in determining our exit status
+if ($interpolatedexitcode -and $chefscriptresult -ne $null -and $chefscriptresult.gettype().name -eq 'boolean')
+{
+ $exitstatus = [int32](!$chefscriptresult)
+}
+elseif ($lastcmdlet)
+{
+ # Otherwise, a successful cmdlet execution defines the status
+ $exitstatus = 0
+}
+elseif ( $LASTEXITCODE -ne $null -and $LASTEXITCODE -ne 0 )
+{
+ # If the cmdlet status is failed, allow the Win32 status
+ # in $LASTEXITCODE to define exit status. This handles the case
+ # where no cmdlets, only Win32 processes have run since $?
+ # will be set to $false whenever a Win32 process returns a non-zero
+ # status.
+ $exitstatus = $LASTEXITCODE
+}
+
+# If this script is launched with -File, the process exit
+# status of PowerShell.exe will be $exitstatus. If it was
+# launched with -Command, it will be 0 if $exitstatus was 0,
+# 1 (i.e. failed) otherwise.
+exit $exitstatus
+EOH
end
+
end
end
end
diff --git a/lib/chef/provider/service.rb b/lib/chef/provider/service.rb
index 75da2ddb31..9c523b5e66 100644
--- a/lib/chef/provider/service.rb
+++ b/lib/chef/provider/service.rb
@@ -168,6 +168,50 @@ class Chef
@new_resource.respond_to?(method_name) &&
!!@new_resource.send(method_name)
end
+
+ module ServicePriorityInit
+
+ #
+ # Platform-specific versions
+ #
+
+ #
+ # Linux
+ #
+
+ require 'chef/chef_class'
+ require 'chef/provider/service/systemd'
+ require 'chef/provider/service/insserv'
+ require 'chef/provider/service/redhat'
+ require 'chef/provider/service/arch'
+ require 'chef/provider/service/gentoo'
+ require 'chef/provider/service/upstart'
+ require 'chef/provider/service/debian'
+ require 'chef/provider/service/invokercd'
+ require 'chef/provider/service/freebsd'
+ require 'chef/provider/service/openbsd'
+ require 'chef/provider/service/solaris'
+ require 'chef/provider/service/macosx'
+
+ def self.os(os, *providers)
+ Chef.set_provider_priority_array(:service, providers, os: os)
+ end
+ def self.platform_family(platform_family, *providers)
+ Chef.set_provider_priority_array(:service, providers, platform_family: platform_family)
+ end
+
+ os %w(freebsd netbsd), Freebsd
+ os %w(openbsd), Openbsd
+ os %w(solaris2), Solaris
+ os %w(darwin), Macosx
+ os %w(linux), Systemd, Insserv, Redhat
+
+ platform_family %w(arch), Systemd, Arch
+ platform_family %w(gentoo), Systemd, Gentoo
+ platform_family %w(debian), Systemd, Upstart, Insserv, Debian, Invokercd
+ platform_family %w(rhel fedora suse), Systemd, Insserv, Redhat
+
+ end
end
end
end
diff --git a/lib/chef/provider/service/init.rb b/lib/chef/provider/service/init.rb
index 0a219a69e1..355e98a0eb 100644
--- a/lib/chef/provider/service/init.rb
+++ b/lib/chef/provider/service/init.rb
@@ -18,6 +18,7 @@
require 'chef/provider/service/simple'
require 'chef/mixin/command'
+require 'chef/platform/service_helpers'
class Chef
class Provider
diff --git a/lib/chef/provider/service/macosx.rb b/lib/chef/provider/service/macosx.rb
index 7cfe57a92a..7324822eff 100644
--- a/lib/chef/provider/service/macosx.rb
+++ b/lib/chef/provider/service/macosx.rb
@@ -28,8 +28,8 @@ class Chef
class Service
class Macosx < Chef::Provider::Service::Simple
- provides :service, os: "darwin"
provides :macosx_service, os: "darwin"
+ provides :service, os: "darwin"
def self.gather_plist_dirs
locations = %w{/Library/LaunchAgents
diff --git a/lib/chef/provider/service/windows.rb b/lib/chef/provider/service/windows.rb
index ba53f0a3c3..355ffafc2a 100644
--- a/lib/chef/provider/service/windows.rb
+++ b/lib/chef/provider/service/windows.rb
@@ -25,7 +25,6 @@ if RUBY_PLATFORM =~ /mswin|mingw32|windows/
end
class Chef::Provider::Service::Windows < Chef::Provider::Service
-
provides :service, os: "windows"
provides :windows_service, os: "windows"
diff --git a/lib/chef/provider/user.rb b/lib/chef/provider/user.rb
index f6ac72448e..ad92a72a0a 100644
--- a/lib/chef/provider/user.rb
+++ b/lib/chef/provider/user.rb
@@ -23,6 +23,7 @@ require 'etc'
class Chef
class Provider
class User < Chef::Provider
+ provides :user
include Chef::Mixin::Command
@@ -208,7 +209,6 @@ class Chef
def unlock_user
raise NotImplementedError
end
-
end
end
end
diff --git a/lib/chef/provider/user/aix.rb b/lib/chef/provider/user/aix.rb
index af08ab4364..a575a41e54 100644
--- a/lib/chef/provider/user/aix.rb
+++ b/lib/chef/provider/user/aix.rb
@@ -18,9 +18,10 @@ class Chef
class Provider
class User
class Aix < Chef::Provider::User::Useradd
+ provides :user, platform: %w(aix)
UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:shell, "-s"], [:uid, "-u"]]
-
+
def create_user
super
add_password
@@ -88,7 +89,7 @@ class Chef
end
end
end
-
+
end
end
end
diff --git a/lib/chef/provider/user/pw.rb b/lib/chef/provider/user/pw.rb
index fe71e93561..810ffb9a8d 100644
--- a/lib/chef/provider/user/pw.rb
+++ b/lib/chef/provider/user/pw.rb
@@ -22,6 +22,7 @@ class Chef
class Provider
class User
class Pw < Chef::Provider::User
+ provides :user, platform: %w(freebsd)
def load_current_resource
super
diff --git a/lib/chef/provider/user/solaris.rb b/lib/chef/provider/user/solaris.rb
index d480acaced..b242095f0c 100644
--- a/lib/chef/provider/user/solaris.rb
+++ b/lib/chef/provider/user/solaris.rb
@@ -22,6 +22,8 @@ class Chef
class Provider
class User
class Solaris < Chef::Provider::User::Useradd
+ provides :user, platform: %w(omnios solaris2)
+
UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:shell, "-s"], [:uid, "-u"]]
attr_writer :password_file
diff --git a/lib/chef/provider/user/useradd.rb b/lib/chef/provider/user/useradd.rb
index cc770c0be2..a1b5b3459c 100644
--- a/lib/chef/provider/user/useradd.rb
+++ b/lib/chef/provider/user/useradd.rb
@@ -23,6 +23,7 @@ class Chef
class Provider
class User
class Useradd < Chef::Provider::User
+ provides :user
UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:password, "-p"], [:shell, "-s"], [:uid, "-u"]]
diff --git a/lib/chef/provider_resolver.rb b/lib/chef/provider_resolver.rb
index 7c7bac0443..5bfee343d1 100644
--- a/lib/chef/provider_resolver.rb
+++ b/lib/chef/provider_resolver.rb
@@ -24,88 +24,25 @@ class Chef
# Provider Resolution
# ===================
#
- # When you type `service 'myservice' { action :restart }` in a recipe, a whole
- # string of events happens eventually leading to convergence. The overview of
- # that process is described in `Chef::DSL::Recipe`. Provider resolution is
- # the process of taking a Resource object and an action, and determining the
- # Provider class that should be instantiated to handle the action.
+ # Provider resolution is the process of taking a Resource object and an
+ # action, and determining the Provider class that should be instantiated to
+ # handle the action.
#
- # The process happens in three steps:
- #
- # Explicit Provider on the Resource
- # ---------------------------------
# If the resource has its `provider` set, that is used.
#
- # Dynamic Provider Matches
- # ------------------------
- # In this stage, we call `provides?` to see if the Provider supports the
- # resource on this platform, and then we call `supports?` to determine if it
- # can handle the action. It's a little more complicated than that, though:
- #
- # ### Provider.provides?
- #
- # First, we go through all known provider classes (all descendants of
- # `Chef::Provider`), and call `provides?(node, resource)` to determine if it
- # supports this action for this resource on this OS. We get a list of all
- # matches.
- #
- # #### Defining provides
- #
- # The typical way of getting `provides?` is for the Provider class to call
- # `provides :name`.
- #
- # The Provider may pass the OS, platform family, platform, and platform version
- # to `provides`, and they will be matched against the values in the `node`
- # object. The Provider may also pass a block, which allows for custom logic
- # to decide whether it provides the resource or not.
- #
- # Some Providers also override `provides?` with custom logic.
- #
- # ### Provider.supports?
- #
- # Once we have the list of willing providers, we filter it by calling their
- # `supports?(resource, action)` method to see if they support the specific
- # action (`:create`, `:delete`) or not.
- #
- # If no provider supports the specific action, we fall back to the full list
- # of matches from step 1. (TODO The comment says it's for why run. I'm not
- # sure what that means specifically yet.)
- #
- # ### Priority lists: Chef.get_provider_priority_array
+ # Otherwise, we take the lists of Providers that have registered as
+ # providing the DSL through `provides :dsl_name, <filters>` or
+ # `Chef.set_resource_priority_array :dsl_name, <filters>`. We filter each
+ # list of Providers through:
#
- # Once we have the list of matches, we look at `Chef.get_provider_priority_array(node, resource)`
- # to see if anyone has set a *priority list*. This method takes
- # the the first matching priority list for this OS (which is the last list
- # that was registered).
+ # 1. The filters it was registered with (such as `os: 'linux'` or
+ # `platform_family: 'debian'`)
+ # 2. `provides?(node, resource)`
+ # 3. `supports?(resource, action)`
#
- # If any of our matches are on the priority list, we take the first one.
- #
- # If there is no priority list or no matches on it, we take the first result
- # alphabetically by class name.
- #
- # Chef::Platform Provider Map
- # ---------------------------
- # If we still have no matches, we try `Chef::Platform.find_provider_for_node(node, resource)`.
- # This does two new things:
- #
- # ### System Provider Map
- #
- # The system provider map is a large Hash loaded during `require` time,
- # which shows system-specific providers by os/platform, and platform_version.
- # It keys off of `node[:platform] || node[:os]`, and `node[:platform_version]
- # || node[:os_version] || node[:os_release]`. The version uses typical gem
- # constraints like > and <=.
- #
- # The first platform+version match wins over the first platform-only match,
- # which wins over the default.
- #
- # ### Chef::Provider::FooBar
- #
- # As a last resort, if there are *still* no classes, the system transforms the
- # DSL name `foo_bar` into `Chef::Provider::FooBar`, and returns the class if
- # it is there and descends from `Chef::Provider`.
- #
- # NOTE: this behavior is now deprecated.
+ # Anything that passes the filter and returns `true` to provides and supports,
+ # is considered a match. The first matching Provider in the *most recently
+ # registered list* is selected and returned.
#
class ProviderResolver
@@ -119,33 +56,14 @@ class Chef
@action = action
end
- # return a deterministically sorted list of Chef::Provider subclasses
- def providers
- @providers ||= Chef::Provider.descendants
- end
-
def resolve
maybe_explicit_provider(resource) ||
maybe_dynamic_provider_resolution(resource, action) ||
maybe_chef_platform_lookup(resource)
end
- # this cut looks at if the provider can handle the resource type on the node
- def enabled_handlers
- @enabled_handlers ||=
- providers.select do |klass|
- # NB: this is different from resource_resolver which must pass a resource_name
- # FIXME: deprecate this and normalize on passing resource_name here
- klass.provides?(node, resource)
- end.sort {|a,b| a.to_s <=> b.to_s }
- end
-
- # this cut looks at if the provider can handle the specific resource and action
- def supported_handlers
- @supported_handlers ||=
- enabled_handlers.select do |klass|
- klass.supports?(resource, action)
- end
+ def provided_by?(provider_class)
+ prioritized_handlers.include?(provider_class)
end
private
@@ -158,40 +76,37 @@ class Chef
# try dynamically finding a provider based on querying the providers to see what they support
def maybe_dynamic_provider_resolution(resource, action)
- # log this so we know what providers will work for the generic resource on the node (early cut)
- Chef::Log.debug "providers for generic #{resource.resource_name} resource enabled on node include: #{enabled_handlers}"
-
- # what providers were excluded by machine state (late cut)
- Chef::Log.debug "providers that refused resource #{resource} were: #{enabled_handlers - supported_handlers}"
- Chef::Log.debug "providers that support resource #{resource} include: #{supported_handlers}"
-
- # if none of the providers specifically support the resource, we still need to pick one of the providers that are
- # enabled on the node to handle the why-run use case.
- handlers = supported_handlers.empty? ? enabled_handlers : supported_handlers
- Chef::Log.debug "no providers supported the resource, falling back to enabled handlers" if supported_handlers.empty?
-
- if handlers.count >= 2
- # this magic stack ranks the providers by where they appear in the provider_priority_map, it is mostly used
- # to pick amongst N different ways to start init scripts on different debian/ubuntu systems.
- priority_list = [ get_priority_array(node, resource.resource_name) ].flatten.compact
- handlers = handlers.sort_by { |x| i = priority_list.index x; i.nil? ? Float::INFINITY : i }
- if priority_list.index(handlers.first).nil?
- # if we had more than one and we picked one with a precidence of infinity that means that the resource_priority_map
- # entry for this resource is missing -- we should probably raise here and force resolution of the ambiguity.
- Chef::Log.warn "Ambiguous provider precedence: #{handlers}, please use Chef.set_provider_priority_array to provide determinism"
- end
- handlers = [ handlers.first ]
+ Chef::Log.debug "Providers for generic #{resource.resource_name} resource enabled on node include: #{enabled_handlers}"
+
+ # Get all the handlers in the priority bucket
+ handlers = prioritized_handlers
+
+ # Narrow it down to handlers that return `true` to `provides?`
+ # TODO deprecate this and don't bother calling--the fact that they said
+ # `provides` should be enough. But we need to do it right now because
+ # some classes implement additional handling.
+ enabled_handlers = prioritized_handlers.select { |handler| handler.provides?(node, resource) }
+
+ # Narrow it down to handlers that return `true` to `supports?`
+ # TODO deprecate this and allow actions to be passed as a filter to
+ # `provides` so we don't have to have two separate things.
+ supported_handlers = enabled_handlers.select { |handler| handler.supports?(resource, action) }
+ if supported_handlers.empty?
+ # if none of the providers specifically support the resource, we still need to pick one of the providers that are
+ # enabled on the node to handle the why-run use case. FIXME we should only do this in why-run mode then.
+ Chef::Log.debug "No providers responded true to `supports?` for action #{action} on resource #{resource}, falling back to enabled handlers so we can return something anyway."
+ handler = enabled_handlers.first
+ else
+ handler = supported_handlers.first
end
- Chef::Log.debug "providers that survived replacement include: #{handlers}"
-
- raise Chef::Exceptions::AmbiguousProviderResolution.new(resource, handlers) if handlers.count >= 2
-
- Chef::Log.debug "dynamic provider resolver FAILED to resolve a provider" if handlers.empty?
-
- return nil if handlers.empty?
+ if handler
+ Chef::Log.debug "Provider for action #{action} on resource #{resource} is #{handler}"
+ else
+ Chef::Log.debug "Dynamic provider resolver FAILED to resolve a provider for action #{action} on resource #{resource}"
+ end
- handlers[0]
+ handler
end
# try the old static lookup of providers by platform
@@ -199,13 +114,51 @@ class Chef
Chef::Platform.find_provider_for_node(node, resource)
end
- # dep injection hooks
- def get_priority_array(node, resource_name)
- provider_priority_map.get_priority_array(node, resource_name)
- end
-
def provider_priority_map
Chef::Platform::ProviderPriorityMap.instance
end
+
+ def prioritized_handlers
+ @prioritized_handlers ||=
+ provider_priority_map.list_handlers(node, resource.resource_name).flatten(1).uniq
+ end
+
+ module Deprecated
+ # return a deterministically sorted list of Chef::Provider subclasses
+ def providers
+ @providers ||= Chef::Provider.descendants
+ end
+
+ # this cut looks at if the provider can handle the resource type on the node
+ def enabled_handlers
+ @enabled_handlers ||=
+ providers.select do |klass|
+ # NB: this is different from resource_resolver which must pass a resource_name
+ # FIXME: deprecate this and normalize on passing resource_name here
+ klass.provides?(node, resource)
+ end.sort {|a,b| a.to_s <=> b.to_s }
+ end
+
+ # this cut looks at if the provider can handle the specific resource and action
+ def supported_handlers
+ @supported_handlers ||=
+ enabled_handlers.select do |klass|
+ klass.supports?(resource, action)
+ end
+ end
+
+ # If there are no providers for a DSL, we search through the
+ def prioritized_handlers
+ @prioritized_handlers ||= super || begin
+ result = providers.select { |handler| handler.provides?(node, resource) }.sort_by(:name)
+ if !result.empty?
+ Chef::Log.deprecation("#{resource.resource_name.to_sym} is marked as providing DSL #{method_symbol}, but provides #{resource.resource_name.to_sym.inspect} was never called!")
+ Chef::Log.deprecation("In Chef 13, this will break: you must call provides to mark the names you provide, even if you also override provides? yourself.")
+ end
+ result
+ end
+ end
+ end
+ prepend Deprecated
end
end
diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb
index 757cd442af..b8bf53d6ec 100644
--- a/lib/chef/resource.rb
+++ b/lib/chef/resource.rb
@@ -34,10 +34,12 @@ require 'chef/platform'
require 'chef/resource/resource_notification'
require 'chef/provider_resolver'
require 'chef/resource_resolver'
+require 'set'
require 'chef/mixin/deprecation'
require 'chef/mixin/provides'
require 'chef/mixin/shell_out'
+require 'chef/mixin/powershell_out'
class Chef
class Resource
@@ -54,6 +56,9 @@ class Chef
# This lets user code do things like `not_if { shell_out!("command") }`
include Chef::Mixin::ShellOut
+ include Chef::Mixin::PowershellOut
+
+ NULL_ARG = Object.new
#
# The node the current Chef run is using.
@@ -86,7 +91,6 @@ class Chef
run_context.resource_collection.find(*args)
end
-
#
# Resource User Interface (for users)
#
@@ -105,8 +109,8 @@ class Chef
@before = nil
@params = Hash.new
@provider = nil
- @allowed_actions = [ :nothing ]
- @action = :nothing
+ @allowed_actions = self.class.allowed_actions.to_a
+ @action = self.class.default_action
@updated = false
@updated_by_last_action = false
@supports = {}
@@ -167,19 +171,24 @@ class Chef
# @param arg [Array[Symbol], Symbol] A list of actions (e.g. `:create`)
# @return [Array[Symbol]] the list of actions.
#
+ attr_accessor :action
def action(arg=nil)
if arg
- action_list = arg.kind_of?(Array) ? arg : [ arg ]
- action_list = action_list.collect { |a| a.to_sym }
- action_list.each do |action|
+ if arg.is_a?(Array)
+ arg = arg.map { |a| a.to_sym }
+ else
+ arg = arg.to_sym
+ end
+ Array(arg).each do |action|
validate(
{ action: action },
- { action: { kind_of: Symbol, equal_to: @allowed_actions } }
+ { action: { kind_of: Symbol, equal_to: allowed_actions } }
)
end
- @action = action_list
+ self.action = arg
else
- @action
+ # Pull the action from the class if it's not set
+ @action || self.class.default_action
end
end
@@ -187,8 +196,7 @@ class Chef
# Sets up a notification that will run a particular action on another resource
# if and when *this* resource is updated by an action.
#
- # If the action does nothing--does not update this resource, the
- # notification never triggers.)
+ # If the action does not update this resource, the notification never triggers.
#
# Only one resource may be specified per notification.
#
@@ -604,7 +612,7 @@ class Chef
#
def to_s
- "#{@resource_name}[#{@name}]"
+ "#{resource_name}[#{name}]"
end
def to_text
@@ -765,6 +773,12 @@ class Chef
# have.
#
attr_accessor :allowed_actions
+ def allowed_actions(value=NULL_ARG)
+ if value != NULL_ARG
+ self.allowed_actions = value
+ end
+ @allowed_actions
+ end
#
# Whether or not this resource was updated during an action. If multiple
@@ -823,23 +837,15 @@ class Chef
end
#
- # The DSL name of this resource (e.g. `package` or `yum_package`)
+ # The display name of this resource type, for printing purposes.
#
- # @return [String] The DSL name of this resource.
- def self.dsl_name
- Chef::Log.deprecation "Resource.dsl_name is deprecated and will be removed in Chef 11. Use resource.resource_name instead."
- if name
- name = self.name.split('::')[-1]
- convert_to_snake_case(name)
- end
- end
-
+ # Will be used to print out the resource in messages, e.g. resource_name[name]
#
- # The name of this resource (e.g. `file`)
+ # @return [Symbol] The name of this resource type (e.g. `:execute`).
#
- # @return [String] The name of this resource.
- #
- attr_reader :resource_name
+ def resource_name
+ @resource_name || self.class.resource_name
+ end
#
# Sets a list of capabilities of the real resource. For example, `:remount`
@@ -871,25 +877,142 @@ class Chef
nil
end
- #
- # The module where Chef should look for providers for this resource.
- # The provider for `MyResource` will be looked up using
- # `provider_base::MyResource`. Defaults to `Chef::Provider`.
- #
- # @param arg [Module] The module containing providers for this resource
- # @return [Module] The module containing providers for this resource
- #
- # @example
- # class MyResource < Chef::Resource
- # provider_base Chef::Provider::Deploy
- # # ...other stuff
- # end
- #
- def self.provider_base(arg=nil)
- @provider_base ||= arg
- @provider_base ||= Chef::Provider
- end
+ # Provider lookup and naming
+ class<<self
+ #
+ # The DSL name of this resource (e.g. `package` or `yum_package`)
+ #
+ # @return [String] The DSL name of this resource.
+ #
+ # @deprecated Use resource_name instead.
+ #
+ def dsl_name
+ Chef::Log.deprecation "Resource.dsl_name is deprecated and will be removed in Chef 13. Use resource_name instead."
+ if name
+ name = self.name.split('::')[-1]
+ convert_to_snake_case(name)
+ end
+ end
+ #
+ # The display name of this resource type, for printing purposes.
+ #
+ # This also automatically calls "provides" to provide DSL with the given
+ # name.
+ #
+ # @param value [Symbol] The desired name of this resource type (e.g.
+ # `execute`).
+ #
+ # @return [Symbol] The name of this resource type (e.g. `:execute`).
+ #
+ def resource_name(value=NULL_ARG)
+ if value != NULL_ARG
+ @resource_name = value.to_sym
+ provides self.resource_name
+ end
+ # Backcompat: set resource name for classes in Chef::Resource automatically
+ if !@resource_name && self.name
+ chef, resource, class_name, *extra = self.name.split('::')
+ if chef == 'Chef' && resource == 'Resource' && extra.size == 0
+ @resource_name = convert_to_snake_case(self.name.split('::')[-1])
+ end
+ end
+ @resource_name
+ end
+ alias :resource_name= :resource_name
+
+ #
+ # Use the class name as the resource name.
+ #
+ # Munges the last part of the class name from camel case to snake case,
+ # and sets the resource_name to that:
+ #
+ # A::B::BlahDBlah -> blah_d_blah
+ #
+ def use_automatic_resource_name
+ automatic_name = convert_to_snake_case(self.name.split('::')[-1])
+ resource_name automatic_name
+ end
+
+ #
+ # The module where Chef should look for providers for this resource.
+ # The provider for `MyResource` will be looked up using
+ # `provider_base::MyResource`. Defaults to `Chef::Provider`.
+ #
+ # @param arg [Module] The module containing providers for this resource
+ # @return [Module] The module containing providers for this resource
+ #
+ # @example
+ # class MyResource < Chef::Resource
+ # provider_base Chef::Provider::Deploy
+ # # ...other stuff
+ # end
+ #
+ # @deprecated Use `provides` on the provider, or `provider` on the resource, instead.
+ #
+ def provider_base(arg=nil)
+ if arg
+ Chef::Log.deprecation("Resource.provider_base is deprecated and will be removed in Chef 13. Use provides on the provider, or provider on the resource, instead.")
+ end
+ @provider_base ||= arg || Chef::Provider
+ end
+
+ #
+ # The list of allowed actions for the resource.
+ #
+ # @param actions [Array<Symbol>] The list of actions to add to allowed_actions.
+ #
+ # @return [Arrau<Symbol>] The list of actions, as symbols.
+ #
+ def allowed_actions(*actions)
+ @allowed_actions ||=
+ if superclass.respond_to?(:allowed_actions)
+ superclass.allowed_actions.dup
+ else
+ [ :nothing ]
+ end
+ @allowed_actions |= actions
+ end
+ def allowed_actions=(value)
+ @allowed_actions = value
+ end
+
+ #
+ # The action that will be run if no other action is specified.
+ #
+ # Setting default_action will automatially add the action to
+ # allowed_actions, if it isn't already there.
+ #
+ # Defaults to :nothing.
+ #
+ # @param action_name [Symbol,Array<Symbol>] The default action (or series
+ # of actions) to use.
+ #
+ # @return [Symbol,Array<Symbol>] The default actions for the resource.
+ #
+ def default_action(action_name=NULL_ARG)
+ unless action_name.equal?(NULL_ARG)
+ if action_name.is_a?(Array)
+ @default_action = action_name.map { |arg| arg.to_sym }
+ else
+ @default_action = action_name.to_sym
+ end
+
+ self.allowed_actions |= Array(@default_action)
+ end
+
+ if @default_action
+ @default_action
+ elsif superclass.respond_to?(:default_action)
+ superclass.default_action
+ else
+ :nothing
+ end
+ end
+ def default_action=(action_name)
+ default_action action_name
+ end
+ end
#
# Internal Resource Interface (for Chef)
@@ -980,12 +1103,16 @@ class Chef
end
end
- def self.provides(name, *args, &block)
- result = super
+ def self.provides(name, opts={}, &block)
+ result = Chef.set_resource_priority_array(name, self, opts, &block)
Chef::DSL::Resources.add_resource_dsl(name)
result
end
+ def self.provides?(node, resource)
+ Chef::ResourceResolver.new(node, resource).provided_by?(self)
+ end
+
# Helper for #notifies
def validate_resource_spec!(resource_spec)
run_context.resource_collection.validate_lookup_spec!(resource_spec)
@@ -1160,15 +1287,13 @@ class Chef
def const_missing(class_name)
if deprecated_constants[class_name.to_sym]
- Chef::Log.deprecation("Using an LWRP by its name (#{class_name}) directly is no longer supported in Chef 12 and will be removed. Use Chef::Resource.resource_for_node(node, name) instead.")
+ Chef::Log.deprecation("Using an LWRP by its name (#{class_name}) directly is no longer supported in Chef 13 and will be removed. Use Chef::Resource.resource_for_node(node, name) instead.")
deprecated_constants[class_name.to_sym]
else
raise NameError, "uninitialized constant Chef::Resource::#{class_name}"
end
end
- private
-
def deprecated_constants
@deprecated_constants ||= {}
end
@@ -1189,3 +1314,6 @@ class Chef
end
end
end
+
+# Requiring things at the bottom breaks cycles
+require 'chef/chef_class'
diff --git a/lib/chef/resource/apt_package.rb b/lib/chef/resource/apt_package.rb
index f944825ac3..83bb6906d4 100644
--- a/lib/chef/resource/apt_package.rb
+++ b/lib/chef/resource/apt_package.rb
@@ -23,12 +23,11 @@ class Chef
class Resource
class AptPackage < Chef::Resource::Package
- provides :apt_package
+ use_automatic_resource_name
provides :package, os: "linux", platform_family: [ "debian" ]
def initialize(name, run_context=nil)
super
- @resource_name = :apt_package
@default_release = nil
end
diff --git a/lib/chef/resource/bash.rb b/lib/chef/resource/bash.rb
index 366d8c7bd6..554d2de924 100644
--- a/lib/chef/resource/bash.rb
+++ b/lib/chef/resource/bash.rb
@@ -22,11 +22,10 @@ require 'chef/provider/script'
class Chef
class Resource
class Bash < Chef::Resource::Script
- provides :bash
+ use_automatic_resource_name
def initialize(name, run_context=nil)
super
- @resource_name = :bash
@interpreter = "bash"
end
diff --git a/lib/chef/resource/batch.rb b/lib/chef/resource/batch.rb
index c091ec56b6..8a19e04174 100644
--- a/lib/chef/resource/batch.rb
+++ b/lib/chef/resource/batch.rb
@@ -22,10 +22,11 @@ class Chef
class Resource
class Batch < Chef::Resource::WindowsScript
+ use_automatic_resource_name
provides :batch, os: "windows"
def initialize(name, run_context=nil)
- super(name, run_context, :batch, "cmd.exe")
+ super(name, run_context, nil, "cmd.exe")
end
end
diff --git a/lib/chef/resource/bff_package.rb b/lib/chef/resource/bff_package.rb
index d4139e7ffe..f31fe6a0d8 100644
--- a/lib/chef/resource/bff_package.rb
+++ b/lib/chef/resource/bff_package.rb
@@ -22,13 +22,7 @@ require 'chef/provider/package/aix'
class Chef
class Resource
class BffPackage < Chef::Resource::Package
- provides :bff_package
-
- def initialize(name, run_context=nil)
- super
- @resource_name = :bff_package
- end
-
+ use_automatic_resource_name
end
end
end
diff --git a/lib/chef/resource/breakpoint.rb b/lib/chef/resource/breakpoint.rb
index 5a55858f71..0107b8968a 100644
--- a/lib/chef/resource/breakpoint.rb
+++ b/lib/chef/resource/breakpoint.rb
@@ -22,15 +22,14 @@ require 'chef/resource'
class Chef
class Resource
class Breakpoint < Chef::Resource
- provides :breakpoint
+ use_automatic_resource_name
+
+ default_action :break
def initialize(action="break", *args)
- @name = caller.first
- super(@name, *args)
- @action = "break"
- @allowed_actions << :break
- @resource_name = :breakpoint
+ super(caller.first, *args)
end
+
end
end
end
diff --git a/lib/chef/resource/chef_gem.rb b/lib/chef/resource/chef_gem.rb
index 59f575a524..e4e3ccfbab 100644
--- a/lib/chef/resource/chef_gem.rb
+++ b/lib/chef/resource/chef_gem.rb
@@ -23,11 +23,10 @@ class Chef
class Resource
class ChefGem < Chef::Resource::Package::GemPackage
- provides :chef_gem
+ use_automatic_resource_name
def initialize(name, run_context=nil)
super
- @resource_name = :chef_gem
@compile_time = Chef::Config[:chef_gem_compile_time]
@gem_binary = RbConfig::CONFIG['bindir'] + "/gem"
end
diff --git a/lib/chef/resource/cookbook_file.rb b/lib/chef/resource/cookbook_file.rb
index 7be353b648..08f4733497 100644
--- a/lib/chef/resource/cookbook_file.rb
+++ b/lib/chef/resource/cookbook_file.rb
@@ -27,13 +27,13 @@ class Chef
class CookbookFile < Chef::Resource::File
include Chef::Mixin::Securable
- provides :cookbook_file
+ use_automatic_resource_name
+
+ default_action :create
def initialize(name, run_context=nil)
super
@provider = Chef::Provider::CookbookFile
- @resource_name = :cookbook_file
- @action = "create"
@source = ::File.basename(name)
@cookbook = nil
end
diff --git a/lib/chef/resource/cron.rb b/lib/chef/resource/cron.rb
index cb16506012..a399caebe9 100644
--- a/lib/chef/resource/cron.rb
+++ b/lib/chef/resource/cron.rb
@@ -27,13 +27,13 @@ class Chef
state_attrs :minute, :hour, :day, :month, :weekday, :user
- provides :cron
+ use_automatic_resource_name
+
+ default_action :create
+ allowed_actions :create, :delete
def initialize(name, run_context=nil)
super
- @resource_name = :cron
- @action = :create
- @allowed_actions.push(:create, :delete)
@minute = "*"
@hour = "*"
@day = "*"
diff --git a/lib/chef/resource/csh.rb b/lib/chef/resource/csh.rb
index d37f1a8e0c..1c89f2aca6 100644
--- a/lib/chef/resource/csh.rb
+++ b/lib/chef/resource/csh.rb
@@ -22,11 +22,10 @@ require 'chef/provider/script'
class Chef
class Resource
class Csh < Chef::Resource::Script
- provides :csh
+ use_automatic_resource_name
def initialize(name, run_context=nil)
super
- @resource_name = :csh
@interpreter = "csh"
end
diff --git a/lib/chef/resource/deploy.rb b/lib/chef/resource/deploy.rb
index 55e3547b25..f88133119a 100644
--- a/lib/chef/resource/deploy.rb
+++ b/lib/chef/resource/deploy.rb
@@ -50,17 +50,17 @@ class Chef
# release directory. Callback files can contain chef code (resources, etc.)
#
class Deploy < Chef::Resource
- provides :deploy
-
- provider_base Chef::Provider::Deploy
+ use_automatic_resource_name
identity_attr :repository
state_attrs :deploy_to, :revision
+ default_action :deploy
+ allowed_actions :force_deploy, :deploy, :rollback
+
def initialize(name, run_context=nil)
super
- @resource_name = :deploy
@deploy_to = name
@environment = nil
@repository_cache = 'cached-copy'
@@ -70,7 +70,6 @@ class Chef
@symlink_before_migrate = {"config/database.yml" => "config/database.yml"}
@symlinks = {"system" => "public/system", "pids" => "tmp/pids", "log" => "log"}
@revision = 'HEAD'
- @action = :deploy
@migrate = false
@rollback_on_error = false
@remote = "origin"
@@ -78,7 +77,6 @@ class Chef
@shallow_clone = false
@scm_provider = Chef::Provider::Git
@svn_force_export = false
- @allowed_actions.push(:force_deploy, :deploy, :rollback)
@additional_remotes = Hash[]
@keep_releases = 5
@enable_checkout = true
@@ -282,6 +280,12 @@ class Chef
)
end
+ # This is to support "provider :revision" without deprecation warnings.
+ # Do NOT copy this.
+ def self.provider_base
+ Chef::Provider::Deploy
+ end
+
def svn_force_export(arg=nil)
set_or_return(
:svn_force_export,
diff --git a/lib/chef/resource/deploy_revision.rb b/lib/chef/resource/deploy_revision.rb
index e144ce2162..86a8631ba7 100644
--- a/lib/chef/resource/deploy_revision.rb
+++ b/lib/chef/resource/deploy_revision.rb
@@ -23,22 +23,14 @@ class Chef
# deployment strategy (provider)
class DeployRevision < Chef::Resource::Deploy
- provides :deploy_revision
+ use_automatic_resource_name
- def initialize(*args, &block)
- super
- @resource_name = :deploy_revision
- end
end
class DeployBranch < Chef::Resource::DeployRevision
- provides :deploy_branch
+ use_automatic_resource_name
- def initialize(*args, &block)
- super
- @resource_name = :deploy_branch
- end
end
end
diff --git a/lib/chef/resource/directory.rb b/lib/chef/resource/directory.rb
index 1ab7f0d16d..304317e07a 100644
--- a/lib/chef/resource/directory.rb
+++ b/lib/chef/resource/directory.rb
@@ -32,15 +32,15 @@ class Chef
include Chef::Mixin::Securable
- provides :directory
+ use_automatic_resource_name
+
+ default_action :create
+ allowed_actions :create, :delete
def initialize(name, run_context=nil)
super
- @resource_name = :directory
@path = name
- @action = :create
@recursive = false
- @allowed_actions.push(:create, :delete)
end
def recursive(arg=nil)
diff --git a/lib/chef/resource/dpkg_package.rb b/lib/chef/resource/dpkg_package.rb
index 35a47e8a82..e0b86947f1 100644
--- a/lib/chef/resource/dpkg_package.rb
+++ b/lib/chef/resource/dpkg_package.rb
@@ -23,13 +23,9 @@ class Chef
class Resource
class DpkgPackage < Chef::Resource::Package
+ use_automatic_resource_name
provides :dpkg_package, os: "linux"
- def initialize(name, run_context=nil)
- super
- @resource_name = :dpkg_package
- end
-
end
end
end
diff --git a/lib/chef/resource/dsc_resource.rb b/lib/chef/resource/dsc_resource.rb
index 912b683434..7c822604e2 100644
--- a/lib/chef/resource/dsc_resource.rb
+++ b/lib/chef/resource/dsc_resource.rb
@@ -21,17 +21,17 @@ class Chef
class Resource
class DscResource < Chef::Resource
+ use_automatic_resource_name
provides :dsc_resource, os: "windows"
include Chef::DSL::Powershell
+ default_action :run
+
def initialize(name, run_context)
super
@properties = {}
- @resource_name = :dsc_resource
@resource = nil
- @allowed_actions.push(:run)
- @action = :run
end
def resource(value=nil)
diff --git a/lib/chef/resource/dsc_script.rb b/lib/chef/resource/dsc_script.rb
index cf96ef6b7f..0ff7988d7d 100644
--- a/lib/chef/resource/dsc_script.rb
+++ b/lib/chef/resource/dsc_script.rb
@@ -22,13 +22,13 @@ class Chef
class Resource
class DscScript < Chef::Resource
+ use_automatic_resource_name
provides :dsc_script, platform: "windows"
+ default_action :run
+
def initialize(name, run_context=nil)
super
- @allowed_actions.push(:run)
- @action = :run
- @resource_name = :dsc_script
@imports = {}
end
diff --git a/lib/chef/resource/easy_install_package.rb b/lib/chef/resource/easy_install_package.rb
index 5286e9a289..2483b0a8b7 100644
--- a/lib/chef/resource/easy_install_package.rb
+++ b/lib/chef/resource/easy_install_package.rb
@@ -22,12 +22,7 @@ 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
- end
+ use_automatic_resource_name
def easy_install_binary(arg=nil)
set_or_return(
diff --git a/lib/chef/resource/env.rb b/lib/chef/resource/env.rb
index 2072ae5d80..da7d48f062 100644
--- a/lib/chef/resource/env.rb
+++ b/lib/chef/resource/env.rb
@@ -25,16 +25,17 @@ class Chef
state_attrs :value
+ use_automatic_resource_name
provides :env, os: "windows"
+ default_action :create
+ allowed_actions :create, :delete, :modify
+
def initialize(name, run_context=nil)
super
- @resource_name = :env
@key_name = name
@value = nil
- @action = :create
@delim = nil
- @allowed_actions.push(:create, :delete, :modify)
end
def key_name(arg=nil)
diff --git a/lib/chef/resource/erl_call.rb b/lib/chef/resource/erl_call.rb
index 75422c55a1..b025259b4c 100644
--- a/lib/chef/resource/erl_call.rb
+++ b/lib/chef/resource/erl_call.rb
@@ -23,24 +23,22 @@ require 'chef/provider/erl_call'
class Chef
class Resource
class ErlCall < Chef::Resource
- provides :erl_call
+ use_automatic_resource_name
# erl_call : http://erlang.org/doc/man/erl_call.html
identity_attr :code
+ default_action :run
+
def initialize(name, run_context=nil)
super
- @resource_name = :erl_call
@code = "q()." # your erlang code goes here
@cookie = nil # cookie of the erlang node
@distributed = false # if you want to have a distributed erlang node
@name_type = "sname" # type of erlang hostname name or sname
@node_name = "chef@localhost" # the erlang node hostname
-
- @action = "run"
- @allowed_actions.push(:run)
end
def code(arg=nil)
diff --git a/lib/chef/resource/execute.rb b/lib/chef/resource/execute.rb
index 8fc97d748f..34ed6b1bd9 100644
--- a/lib/chef/resource/execute.rb
+++ b/lib/chef/resource/execute.rb
@@ -23,7 +23,7 @@ require 'chef/provider/execute'
class Chef
class Resource
class Execute < Chef::Resource
- provides :execute
+ use_automatic_resource_name
identity_attr :command
@@ -33,12 +33,12 @@ class Chef
# Only execute resources (and subclasses) can be guard interpreters.
attr_accessor :is_guard_interpreter
+ default_action :run
+
def initialize(name, run_context=nil)
super
- @resource_name = :execute
@command = name
@backup = 5
- @action = "run"
@creates = nil
@cwd = nil
@environment = nil
@@ -47,7 +47,6 @@ class Chef
@returns = 0
@timeout = nil
@user = nil
- @allowed_actions.push(:run)
@umask = nil
@default_guard_interpreter = :execute
@is_guard_interpreter = false
diff --git a/lib/chef/resource/file.rb b/lib/chef/resource/file.rb
index b36fcc2135..51969f65a0 100644
--- a/lib/chef/resource/file.rb
+++ b/lib/chef/resource/file.rb
@@ -47,15 +47,14 @@ class Chef
# @returns [String] Checksum of the file we actually rendered
attr_accessor :final_checksum
- provides :file
+ use_automatic_resource_name
+ default_action :create
+ allowed_actions :create, :delete, :touch, :create_if_missing
def initialize(name, run_context=nil)
super
- @resource_name = :file
@path = name
@backup = 5
- @action = "create"
- @allowed_actions.push(:create, :delete, :touch, :create_if_missing)
@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 9c8db506f8..f89e1813b9 100644
--- a/lib/chef/resource/freebsd_package.rb
+++ b/lib/chef/resource/freebsd_package.rb
@@ -29,13 +29,9 @@ class Chef
class FreebsdPackage < Chef::Resource::Package
include Chef::Mixin::ShellOut
+ use_automatic_resource_name
provides :package, platform: "freebsd"
- def initialize(name, run_context=nil)
- super
- @resource_name = :freebsd_package
- end
-
def after_created
assign_provider
end
diff --git a/lib/chef/resource/gem_package.rb b/lib/chef/resource/gem_package.rb
index 0e838ca040..5bd3a89100 100644
--- a/lib/chef/resource/gem_package.rb
+++ b/lib/chef/resource/gem_package.rb
@@ -22,11 +22,10 @@ class Chef
class Resource
class GemPackage < Chef::Resource::Package
- provides :gem_package
+ use_automatic_resource_name
def initialize(name, run_context=nil)
super
- @resource_name = :gem_package
@clear_sources = false
end
diff --git a/lib/chef/resource/git.rb b/lib/chef/resource/git.rb
index 7156873315..1229914766 100644
--- a/lib/chef/resource/git.rb
+++ b/lib/chef/resource/git.rb
@@ -22,11 +22,10 @@ class Chef
class Resource
class Git < Chef::Resource::Scm
- provides :git
+ use_automatic_resource_name
def initialize(name, run_context=nil)
super
- @resource_name = :git
@additional_remotes = Hash[]
end
diff --git a/lib/chef/resource/group.rb b/lib/chef/resource/group.rb
index 9e8f1309b0..49cf92a282 100644
--- a/lib/chef/resource/group.rb
+++ b/lib/chef/resource/group.rb
@@ -25,19 +25,19 @@ class Chef
state_attrs :members
- provides :group
+ use_automatic_resource_name
+
+ allowed_actions :create, :remove, :modify, :manage
+ default_action :create
def initialize(name, run_context=nil)
super
- @resource_name = :group
@group_name = name
@gid = nil
@members = []
@excluded_members = []
- @action = :create
@append = false
@non_unique = false
- @allowed_actions.push(:create, :remove, :modify, :manage)
end
def group_name(arg=nil)
diff --git a/lib/chef/resource/homebrew_package.rb b/lib/chef/resource/homebrew_package.rb
index 73409b13ac..fe0bd89ced 100644
--- a/lib/chef/resource/homebrew_package.rb
+++ b/lib/chef/resource/homebrew_package.rb
@@ -25,12 +25,11 @@ class Chef
class Resource
class HomebrewPackage < Chef::Resource::Package
- provides :homebrew_package
+ use_automatic_resource_name
provides :package, os: "darwin"
def initialize(name, run_context=nil)
super
- @resource_name = :homebrew_package
@homebrew_user = nil
end
diff --git a/lib/chef/resource/http_request.rb b/lib/chef/resource/http_request.rb
index 5986ebd4a0..192484f557 100644
--- a/lib/chef/resource/http_request.rb
+++ b/lib/chef/resource/http_request.rb
@@ -23,18 +23,18 @@ require 'chef/provider/http_request'
class Chef
class Resource
class HttpRequest < Chef::Resource
- provides :http_request
+ use_automatic_resource_name
identity_attr :url
+ default_action :get
+ allowed_actions :get, :put, :post, :delete, :head, :options
+
def initialize(name, run_context=nil)
super
- @resource_name = :http_request
@message = name
@url = nil
- @action = :get
@headers = {}
- @allowed_actions.push(:get, :put, :post, :delete, :head, :options)
end
def url(args=nil)
diff --git a/lib/chef/resource/ifconfig.rb b/lib/chef/resource/ifconfig.rb
index 60feba1704..47adc52425 100644
--- a/lib/chef/resource/ifconfig.rb
+++ b/lib/chef/resource/ifconfig.rb
@@ -22,18 +22,18 @@ require 'chef/resource'
class Chef
class Resource
class Ifconfig < Chef::Resource
- provides :ifconfig
+ use_automatic_resource_name
identity_attr :device
state_attrs :inet_addr, :mask
+ default_action :add
+ allowed_actions :add, :delete, :enable, :disable
+
def initialize(name, run_context=nil)
super
- @resource_name = :ifconfig
@target = name
- @action = :add
- @allowed_actions.push(:add, :delete, :enable, :disable)
@hwaddr = nil
@mask = nil
@inet_addr = nil
diff --git a/lib/chef/resource/ips_package.rb b/lib/chef/resource/ips_package.rb
index c0e699e31a..6b40fe138c 100644
--- a/lib/chef/resource/ips_package.rb
+++ b/lib/chef/resource/ips_package.rb
@@ -23,12 +23,13 @@ class Chef
class Resource
class IpsPackage < ::Chef::Resource::Package
+ use_automatic_resource_name
provides :ips_package, os: "solaris2"
+ allowed_actions :install, :remove, :upgrade
+
def initialize(name, run_context = nil)
super(name, run_context)
- @resource_name = :ips_package
- @allowed_actions.push(:install, :remove, :upgrade)
@accept_license = false
end
diff --git a/lib/chef/resource/link.rb b/lib/chef/resource/link.rb
index 30f8ec86d1..2fe4da718c 100644
--- a/lib/chef/resource/link.rb
+++ b/lib/chef/resource/link.rb
@@ -25,21 +25,21 @@ class Chef
class Link < Chef::Resource
include Chef::Mixin::Securable
- provides :link
+ use_automatic_resource_name
identity_attr :target_file
state_attrs :to, :owner, :group
+ default_action :create
+ allowed_actions :create, :delete
+
def initialize(name, run_context=nil)
verify_links_supported!
super
- @resource_name = :link
@to = nil
- @action = :create
@link_type = :symbolic
@target_file = name
- @allowed_actions.push(:create, :delete)
end
def to(arg=nil)
diff --git a/lib/chef/resource/log.rb b/lib/chef/resource/log.rb
index 87be01aaa9..5c119df4d8 100644
--- a/lib/chef/resource/log.rb
+++ b/lib/chef/resource/log.rb
@@ -23,10 +23,12 @@ require 'chef/provider/log'
class Chef
class Resource
class Log < Chef::Resource
- provides :log
+ use_automatic_resource_name
identity_attr :message
+ default_action :write
+
# Sends a string from a recipe to a log provider
#
# log "some string to log" do
@@ -49,10 +51,7 @@ class Chef
# node<Chef::Node>:: Node where resource will be used
def initialize(name, run_context=nil)
super
- @resource_name = :log
@level = :info
- @action = :write
- @allowed_actions.push(:write)
@message = name
end
diff --git a/lib/chef/resource/lwrp_base.rb b/lib/chef/resource/lwrp_base.rb
index a42261cfc4..20d236a161 100644
--- a/lib/chef/resource/lwrp_base.rb
+++ b/lib/chef/resource/lwrp_base.rb
@@ -35,8 +35,6 @@ class Chef
# so attributes, default action, etc. can be defined with pleasing syntax.
class LWRPBase < Resource
- NULL_ARG = Object.new
-
# Class methods
class <<self
@@ -55,12 +53,11 @@ class Chef
# We load the class first to give it a chance to set its own name
resource_class = Class.new(self)
- resource_class.resource_name = resource_name
+ resource_class.resource_name resource_name.to_sym
resource_class.run_context = run_context
- resource_class.provides resource_name.to_sym
resource_class.class_from_file(filename)
- # Respect resource_name set inside the LWRP
+ # Make a useful string for the class (rather than <Class:312894723894>)
resource_class.instance_eval do
define_singleton_method(:to_s) do
"LWRP resource #{resource_name} from cookbook #{cookbook_name}"
@@ -77,16 +74,6 @@ class Chef
resource_class
end
- def resource_name(arg = NULL_ARG)
- if arg.equal?(NULL_ARG)
- @resource_name
- else
- @resource_name = arg
- end
- end
-
- alias_method :resource_name=, :resource_name
-
# Define an attribute on this resource, including optional validation
# parameters.
def attribute(attr_name, validation_opts={})
@@ -95,42 +82,21 @@ class Chef
end
end
- # Sets the default action
- def default_action(action_name=NULL_ARG)
- unless action_name.equal?(NULL_ARG)
- @actions ||= []
- if action_name.is_a?(Array)
- action = action_name.map { |arg| arg.to_sym }
- @actions = actions | action
- @default_action = action
- else
- action = action_name.to_sym
- @actions.push(action) unless @actions.include?(action)
- @default_action = [action]
- end
- end
-
- @default_action ||= from_superclass(:default_action)
- end
-
# Adds +action_names+ to the list of valid actions for this resource.
+ # Does not include superclass's action list when appending.
def actions(*action_names)
- if action_names.empty?
- defined?(@actions) ? @actions : from_superclass(:actions, []).dup
+ if !action_names.empty? && !@allowed_actions
+ self.allowed_actions = action_names
else
- # BC-compat way for checking if actions have already been defined
- if defined?(@actions)
- @actions.push(*action_names)
- else
- @actions = action_names
- end
+ allowed_actions(*action_names)
end
end
+ alias :actions= :allowed_actions=
# @deprecated
def valid_actions(*args)
- Chef::Log.warn("`valid_actions' is deprecated, please use actions `instead'!")
- actions(*args)
+ Chef::Log.warn("`valid_actions' is deprecated, please use allowed_actions `instead'!")
+ allowed_actions(*args)
end
# Set the run context on the class. Used to provide access to the node
@@ -162,23 +128,6 @@ class Chef
superclass.respond_to?(m) ? superclass.send(m) : default
end
end
-
- private
-
- # Default initializer. Sets the default action and allowed actions.
- def initialize(name, run_context=nil)
- super(name, run_context)
-
- # Raise an exception if the resource_name was not defined
- if self.class.resource_name.nil?
- raise Chef::Exceptions::InvalidResourceSpecification,
- "You must specify `resource_name'!"
- end
-
- @resource_name = self.class.resource_name.to_sym
- @action = self.class.default_action
- allowed_actions.push(self.class.actions).flatten!
- end
end
end
end
diff --git a/lib/chef/resource/macosx_service.rb b/lib/chef/resource/macosx_service.rb
index 879ea99cf8..29da2e6309 100644
--- a/lib/chef/resource/macosx_service.rb
+++ b/lib/chef/resource/macosx_service.rb
@@ -22,8 +22,9 @@ class Chef
class Resource
class MacosxService < Chef::Resource::Service
- provides :service, os: "darwin"
+ use_automatic_resource_name
provides :macosx_service, os: "darwin"
+ provides :service, os: "darwin"
identity_attr :service_name
@@ -31,7 +32,6 @@ class Chef
def initialize(name, run_context=nil)
super
- @resource_name = :macosx_service
@plist = nil
@session_type = nil
end
diff --git a/lib/chef/resource/macports_package.rb b/lib/chef/resource/macports_package.rb
index 0d4e5dec65..3ccf831cf2 100644
--- a/lib/chef/resource/macports_package.rb
+++ b/lib/chef/resource/macports_package.rb
@@ -20,13 +20,8 @@ class Chef
class Resource
class MacportsPackage < Chef::Resource::Package
- provides :macports_package
+ use_automatic_resource_name
provides :package, os: "darwin"
-
- def initialize(name, run_context=nil)
- super
- @resource_name = :macports_package
- end
end
end
end
diff --git a/lib/chef/resource/mdadm.rb b/lib/chef/resource/mdadm.rb
index 971b6c51b4..2927cc8321 100644
--- a/lib/chef/resource/mdadm.rb
+++ b/lib/chef/resource/mdadm.rb
@@ -27,11 +27,13 @@ class Chef
state_attrs :devices, :level, :chunk
- provides :mdadm
+ use_automatic_resource_name
+
+ default_action :create
+ allowed_actions :create, :assemble, :stop
def initialize(name, run_context=nil)
super
- @resource_name = :mdadm
@chunk = 16
@devices = []
@@ -40,9 +42,6 @@ class Chef
@metadata = "0.90"
@bitmap = nil
@raid_device = name
-
- @action = :create
- @allowed_actions.push(:create, :assemble, :stop)
end
def chunk(arg=nil)
diff --git a/lib/chef/resource/mount.rb b/lib/chef/resource/mount.rb
index 142dec87f7..ce6d2cc232 100644
--- a/lib/chef/resource/mount.rb
+++ b/lib/chef/resource/mount.rb
@@ -27,11 +27,13 @@ class Chef
state_attrs :mount_point, :device_type, :fstype, :username, :password, :domain
- provides :mount
+ use_automatic_resource_name
+
+ default_action :mount
+ allowed_actions :mount, :umount, :remount, :enable, :disable
def initialize(name, run_context=nil)
super
- @resource_name = :mount
@mount_point = name
@device = nil
@device_type = :device
@@ -42,9 +44,7 @@ class Chef
@pass = 2
@mounted = false
@enabled = false
- @action = :mount
@supports = { :remount => false }
- @allowed_actions.push(:mount, :umount, :remount, :enable, :disable)
@username = nil
@password = nil
@domain = nil
diff --git a/lib/chef/resource/ohai.rb b/lib/chef/resource/ohai.rb
index e2d12ce395..005b149442 100644
--- a/lib/chef/resource/ohai.rb
+++ b/lib/chef/resource/ohai.rb
@@ -20,18 +20,17 @@
class Chef
class Resource
class Ohai < Chef::Resource
- provides :ohai
+ use_automatic_resource_name
identity_attr :name
state_attrs :plugin
+ default_action :reload
+
def initialize(name, run_context=nil)
super
- @resource_name = :ohai
@name = name
- @allowed_actions.push(:reload)
- @action = :reload
@plugin = nil
end
diff --git a/lib/chef/resource/openbsd_package.rb b/lib/chef/resource/openbsd_package.rb
index 20a2523e3a..1071958cd2 100644
--- a/lib/chef/resource/openbsd_package.rb
+++ b/lib/chef/resource/openbsd_package.rb
@@ -28,13 +28,9 @@ class Chef
class OpenbsdPackage < Chef::Resource::Package
include Chef::Mixin::ShellOut
+ use_automatic_resource_name
provides :package, os: "openbsd"
- def initialize(name, run_context=nil)
- super
- @resource_name = :openbsd_package
- end
-
def after_created
assign_provider
end
@@ -48,4 +44,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/resource/package.rb b/lib/chef/resource/package.rb
index 5bea894a02..0944b5e9d8 100644
--- a/lib/chef/resource/package.rb
+++ b/lib/chef/resource/package.rb
@@ -22,20 +22,20 @@ require 'chef/resource'
class Chef
class Resource
class Package < Chef::Resource
- provides :package
+ use_automatic_resource_name
identity_attr :package_name
state_attrs :version, :options
+ default_action :install
+ allowed_actions :install, :upgrade, :remove, :purge, :reconfig
+
def initialize(name, run_context=nil)
super
- @action = :install
- @allowed_actions.push(:install, :upgrade, :remove, :purge, :reconfig)
@candidate_version = nil
@options = nil
@package_name = name
- @resource_name = :package
@response_file = nil
@response_file_variables = Hash.new
@source = nil
@@ -102,3 +102,8 @@ class Chef
end
end
end
+
+require 'chef/chef_class'
+require 'chef/resource/homebrew_package'
+
+Chef.set_resource_priority_array :package, Chef::Resource::HomebrewPackage, os: "darwin"
diff --git a/lib/chef/resource/pacman_package.rb b/lib/chef/resource/pacman_package.rb
index 4c45dd004f..222fb3c78e 100644
--- a/lib/chef/resource/pacman_package.rb
+++ b/lib/chef/resource/pacman_package.rb
@@ -22,13 +22,9 @@ class Chef
class Resource
class PacmanPackage < Chef::Resource::Package
+ use_automatic_resource_name
provides :pacman_package, os: "linux"
- def initialize(name, run_context=nil)
- super
- @resource_name = :pacman_package
- end
-
end
end
end
diff --git a/lib/chef/resource/paludis_package.rb b/lib/chef/resource/paludis_package.rb
index 552c96857a..f0ddc5927a 100644
--- a/lib/chef/resource/paludis_package.rb
+++ b/lib/chef/resource/paludis_package.rb
@@ -23,12 +23,13 @@ class Chef
class Resource
class PaludisPackage < Chef::Resource::Package
+ use_automatic_resource_name
provides :paludis_package, os: "linux"
+ allowed_actions :install, :remove, :upgrade
+
def initialize(name, run_context=nil)
super(name, run_context)
- @resource_name = :paludis_package
- @allowed_actions.push(:install, :remove, :upgrade)
@timeout = 3600
end
end
diff --git a/lib/chef/resource/perl.rb b/lib/chef/resource/perl.rb
index cb741d145a..6870f487eb 100644
--- a/lib/chef/resource/perl.rb
+++ b/lib/chef/resource/perl.rb
@@ -22,11 +22,10 @@ require 'chef/provider/script'
class Chef
class Resource
class Perl < Chef::Resource::Script
- provides :perl
+ use_automatic_resource_name
def initialize(name, run_context=nil)
super
- @resource_name = :perl
@interpreter = "perl"
end
diff --git a/lib/chef/resource/portage_package.rb b/lib/chef/resource/portage_package.rb
index b03b69796a..009a525d22 100644
--- a/lib/chef/resource/portage_package.rb
+++ b/lib/chef/resource/portage_package.rb
@@ -21,11 +21,10 @@ require 'chef/resource/package'
class Chef
class Resource
class PortagePackage < Chef::Resource::Package
- provides :portage_package
+ use_automatic_resource_name
def initialize(name, run_context=nil)
super
- @resource_name = :portage_package
@provider = Chef::Provider::Package::Portage
end
diff --git a/lib/chef/resource/powershell_script.rb b/lib/chef/resource/powershell_script.rb
index 43aafe4df2..a3a24fce7f 100644
--- a/lib/chef/resource/powershell_script.rb
+++ b/lib/chef/resource/powershell_script.rb
@@ -21,10 +21,11 @@ class Chef
class Resource
class PowershellScript < Chef::Resource::WindowsScript
+ use_automatic_resource_name
provides :powershell_script, os: "windows"
def initialize(name, run_context=nil)
- super(name, run_context, :powershell_script, "powershell.exe")
+ super(name, run_context, nil, "powershell.exe")
@convert_boolean_return = false
end
diff --git a/lib/chef/resource/python.rb b/lib/chef/resource/python.rb
index fffd4d75f6..5c120d7d27 100644
--- a/lib/chef/resource/python.rb
+++ b/lib/chef/resource/python.rb
@@ -21,11 +21,10 @@ require 'chef/provider/script'
class Chef
class Resource
class Python < Chef::Resource::Script
- provides :python
+ use_automatic_resource_name
def initialize(name, run_context=nil)
super
- @resource_name = :python
@interpreter = "python"
end
diff --git a/lib/chef/resource/reboot.rb b/lib/chef/resource/reboot.rb
index 7cd53450ed..216367692f 100644
--- a/lib/chef/resource/reboot.rb
+++ b/lib/chef/resource/reboot.rb
@@ -24,13 +24,13 @@ require 'chef/resource'
class Chef
class Resource
class Reboot < Chef::Resource
- provides :reboot
+ use_automatic_resource_name
+
+ allowed_actions :request_reboot, :reboot_now, :cancel
def initialize(name, run_context=nil)
super
- @resource_name = :reboot
@provider = Chef::Provider::Reboot
- @allowed_actions.push(:request_reboot, :reboot_now, :cancel)
@reason = "Reboot by Chef"
@delay_mins = 0
diff --git a/lib/chef/resource/registry_key.rb b/lib/chef/resource/registry_key.rb
index cc8d05dd53..9ee031b751 100644
--- a/lib/chef/resource/registry_key.rb
+++ b/lib/chef/resource/registry_key.rb
@@ -22,11 +22,14 @@ require 'chef/digester'
class Chef
class Resource
class RegistryKey < Chef::Resource
- provides :registry_key
+ use_automatic_resource_name
identity_attr :key
state_attrs :values
+ default_action :create
+ allowed_actions :create, :create_if_missing, :delete, :delete_key
+
# Some registry key data types may not be safely reported as json.
# Example (CHEF-5323):
#
@@ -60,13 +63,10 @@ class Chef
def initialize(name, run_context=nil)
super
- @resource_name = :registry_key
- @action = :create
@architecture = :machine
@recursive = false
@key = name
@values, @unscrubbed_values = [], []
- @allowed_actions.push(:create, :create_if_missing, :delete, :delete_key)
end
def key(arg=nil)
diff --git a/lib/chef/resource/remote_directory.rb b/lib/chef/resource/remote_directory.rb
index d4108da47a..bb052d3bd4 100644
--- a/lib/chef/resource/remote_directory.rb
+++ b/lib/chef/resource/remote_directory.rb
@@ -26,19 +26,20 @@ class Chef
class RemoteDirectory < Chef::Resource::Directory
include Chef::Mixin::Securable
- provides :remote_directory
+ use_automatic_resource_name
identity_attr :path
state_attrs :files_owner, :files_group, :files_mode
+ default_action :create
+ allowed_actions :create, :create_if_missing, :delete
+
def initialize(name, run_context=nil)
super
- @resource_name = :remote_directory
@path = name
@source = ::File.basename(name)
@delete = false
- @action = :create
@recursive = true
@purge = false
@files_backup = 5
@@ -46,7 +47,6 @@ class Chef
@files_group = nil
@files_mode = 0644 unless Chef::Platform.windows?
@overwrite = true
- @allowed_actions.push(:create, :create_if_missing, :delete)
@cookbook = nil
end
diff --git a/lib/chef/resource/remote_file.rb b/lib/chef/resource/remote_file.rb
index df9fb7ad76..99c21cae52 100644
--- a/lib/chef/resource/remote_file.rb
+++ b/lib/chef/resource/remote_file.rb
@@ -28,12 +28,10 @@ class Chef
class RemoteFile < Chef::Resource::File
include Chef::Mixin::Securable
- provides :remote_file
+ use_automatic_resource_name
def initialize(name, run_context=nil)
super
- @resource_name = :remote_file
- @action = "create"
@source = []
@use_etag = true
@use_last_modified = true
diff --git a/lib/chef/resource/route.rb b/lib/chef/resource/route.rb
index 8f9172060b..3df767a128 100644
--- a/lib/chef/resource/route.rb
+++ b/lib/chef/resource/route.rb
@@ -22,18 +22,18 @@ require 'chef/resource'
class Chef
class Resource
class Route < Chef::Resource
- provides :route
+ use_automatic_resource_name
identity_attr :target
state_attrs :netmask, :gateway
+ default_action :add
+ allowed_actions :add, :delete
+
def initialize(name, run_context=nil)
super
- @resource_name = :route
@target = name
- @action = [:add]
- @allowed_actions.push(:add, :delete)
@netmask = nil
@gateway = nil
@metric = nil
diff --git a/lib/chef/resource/rpm_package.rb b/lib/chef/resource/rpm_package.rb
index f00121dd69..67a6c156d8 100644
--- a/lib/chef/resource/rpm_package.rb
+++ b/lib/chef/resource/rpm_package.rb
@@ -23,11 +23,11 @@ class Chef
class Resource
class RpmPackage < Chef::Resource::Package
+ use_automatic_resource_name
provides :rpm_package, os: [ "linux", "aix" ]
def initialize(name, run_context=nil)
super
- @resource_name = :rpm_package
@allow_downgrade = false
end
diff --git a/lib/chef/resource/ruby.rb b/lib/chef/resource/ruby.rb
index 2b7644562a..759955da42 100644
--- a/lib/chef/resource/ruby.rb
+++ b/lib/chef/resource/ruby.rb
@@ -22,11 +22,10 @@ require 'chef/provider/script'
class Chef
class Resource
class Ruby < Chef::Resource::Script
- provides :ruby
+ use_automatic_resource_name
def initialize(name, run_context=nil)
super
- @resource_name = :ruby
@interpreter = "ruby"
end
diff --git a/lib/chef/resource/ruby_block.rb b/lib/chef/resource/ruby_block.rb
index 07eec5599d..4ce7b2cee1 100644
--- a/lib/chef/resource/ruby_block.rb
+++ b/lib/chef/resource/ruby_block.rb
@@ -23,15 +23,14 @@ require 'chef/provider/ruby_block'
class Chef
class Resource
class RubyBlock < Chef::Resource
- provides :ruby_block
+ use_automatic_resource_name
+ default_action :run
+ allowed_actions :create, :run
identity_attr :block_name
def initialize(name, run_context=nil)
super
- @resource_name = :ruby_block
- @action = "run"
- @allowed_actions << :create << :run
@block_name = name
end
diff --git a/lib/chef/resource/scm.rb b/lib/chef/resource/scm.rb
index d41764d595..8379a3d8a9 100644
--- a/lib/chef/resource/scm.rb
+++ b/lib/chef/resource/scm.rb
@@ -22,24 +22,24 @@ require 'chef/resource'
class Chef
class Resource
class Scm < Chef::Resource
- provides :scm
+ use_automatic_resource_name
identity_attr :destination
state_attrs :revision
+ default_action :sync
+ allowed_actions :checkout, :export, :sync, :diff, :log
+
def initialize(name, run_context=nil)
super
@destination = name
- @resource_name = :scm
@enable_submodules = false
@enable_checkout = true
@revision = "HEAD"
@remote = "origin"
@ssh_wrapper = nil
@depth = nil
- @allowed_actions.push(:checkout, :export, :sync, :diff, :log)
- @action = [:sync]
@checkout_branch = "deploy"
@environment = nil
end
diff --git a/lib/chef/resource/script.rb b/lib/chef/resource/script.rb
index e2fbb29d0f..f3d3ef01f4 100644
--- a/lib/chef/resource/script.rb
+++ b/lib/chef/resource/script.rb
@@ -23,14 +23,13 @@ require 'chef/provider/script'
class Chef
class Resource
class Script < Chef::Resource::Execute
- provides :script
+ use_automatic_resource_name
# Chef-13: go back to using :name as the identity attr
identity_attr :command
def initialize(name, run_context=nil)
super
- @resource_name = :script
# Chef-13: the command variable should be initialized to nil
@command = name
@code = nil
diff --git a/lib/chef/resource/service.rb b/lib/chef/resource/service.rb
index 47d2ab9e12..9995eccb3f 100644
--- a/lib/chef/resource/service.rb
+++ b/lib/chef/resource/service.rb
@@ -22,15 +22,17 @@ require 'chef/resource'
class Chef
class Resource
class Service < Chef::Resource
- provides :service
+ use_automatic_resource_name
identity_attr :service_name
state_attrs :enabled, :running
+ default_action :nothing
+ allowed_actions :enable, :disable, :start, :stop, :restart, :reload
+
def initialize(name, run_context=nil)
super
- @resource_name = :service
@service_name = name
@enabled = nil
@running = nil
@@ -44,9 +46,7 @@ class Chef
@init_command = nil
@priority = nil
@timeout = nil
- @action = "nothing"
@supports = { :restart => false, :reload => false, :status => false }
- @allowed_actions.push(:enable, :disable, :start, :stop, :restart, :reload)
end
def service_name(arg=nil)
diff --git a/lib/chef/resource/smartos_package.rb b/lib/chef/resource/smartos_package.rb
index 99b3b953b0..7460f0f687 100644
--- a/lib/chef/resource/smartos_package.rb
+++ b/lib/chef/resource/smartos_package.rb
@@ -23,15 +23,9 @@ class Chef
class Resource
class SmartosPackage < Chef::Resource::Package
- provides :smartos_package
+ use_automatic_resource_name
provides :package, os: "solaris2", platform_family: "smartos"
- def initialize(name, run_context=nil)
- super
- @resource_name = :smartos_package
- end
-
end
end
end
-
diff --git a/lib/chef/resource/solaris_package.rb b/lib/chef/resource/solaris_package.rb
index 94be4693b6..545e783b75 100644
--- a/lib/chef/resource/solaris_package.rb
+++ b/lib/chef/resource/solaris_package.rb
@@ -24,20 +24,13 @@ class Chef
class Resource
class SolarisPackage < Chef::Resource::Package
- provides :solaris_package
+ use_automatic_resource_name
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
- end
-
end
end
end
-
-
diff --git a/lib/chef/resource/subversion.rb b/lib/chef/resource/subversion.rb
index e5a2e9d1a5..e12d939ca6 100644
--- a/lib/chef/resource/subversion.rb
+++ b/lib/chef/resource/subversion.rb
@@ -22,14 +22,13 @@ require "chef/resource/scm"
class Chef
class Resource
class Subversion < Chef::Resource::Scm
- provides :subversion
+ use_automatic_resource_name
+ allowed_actions :force_export
def initialize(name, run_context=nil)
super
@svn_arguments = '--no-auth-cache'
@svn_info_args = '--no-auth-cache'
- @resource_name = :subversion
- allowed_actions << :force_export
end
# Override exception to strip password if any, so it won't appear in logs and different Chef notifications
diff --git a/lib/chef/resource/template.rb b/lib/chef/resource/template.rb
index 67a9e6a418..a8e38aa5fb 100644
--- a/lib/chef/resource/template.rb
+++ b/lib/chef/resource/template.rb
@@ -27,15 +27,13 @@ class Chef
class Template < Chef::Resource::File
include Chef::Mixin::Securable
- provides :template
+ use_automatic_resource_name
attr_reader :inline_helper_blocks
attr_reader :inline_helper_modules
def initialize(name, run_context=nil)
super
- @resource_name = :template
- @action = "create"
@source = "#{::File.basename(name)}.erb"
@cookbook = nil
@local = false
diff --git a/lib/chef/resource/timestamped_deploy.rb b/lib/chef/resource/timestamped_deploy.rb
index b2109db85c..15ac296f78 100644
--- a/lib/chef/resource/timestamped_deploy.rb
+++ b/lib/chef/resource/timestamped_deploy.rb
@@ -21,10 +21,7 @@ class Chef
# 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)
- end
+ use_automatic_resource_name
end
end
end
diff --git a/lib/chef/resource/user.rb b/lib/chef/resource/user.rb
index 7d2ec25596..66c183ad7e 100644
--- a/lib/chef/resource/user.rb
+++ b/lib/chef/resource/user.rb
@@ -26,11 +26,13 @@ class Chef
state_attrs :uid, :gid, :home
- provides :user
+ use_automatic_resource_name
+
+ default_action :create
+ allowed_actions :create, :remove, :modify, :manage, :lock, :unlock
def initialize(name, run_context=nil)
super
- @resource_name = :user
@username = name
@comment = nil
@uid = nil
@@ -42,14 +44,12 @@ class Chef
@manage_home = false
@force = false
@non_unique = false
- @action = :create
@supports = {
:manage_home => false,
:non_unique => false
}
@iterations = 27855
@salt = nil
- @allowed_actions.push(:create, :remove, :modify, :manage, :lock, :unlock)
end
def username(arg=nil)
diff --git a/lib/chef/resource/whyrun_safe_ruby_block.rb b/lib/chef/resource/whyrun_safe_ruby_block.rb
index f512dc67fc..0ade9c981f 100644
--- a/lib/chef/resource/whyrun_safe_ruby_block.rb
+++ b/lib/chef/resource/whyrun_safe_ruby_block.rb
@@ -19,12 +19,8 @@
class Chef
class Resource
class WhyrunSafeRubyBlock < Chef::Resource::RubyBlock
- provides :whyrun_safe_ruby_block
- def initialize(name, run_context=nil)
- super
- @resource_name = :whyrun_safe_ruby_block
- end
+ use_automatic_resource_name
end
end
diff --git a/lib/chef/resource/windows_package.rb b/lib/chef/resource/windows_package.rb
index d4f8ae0603..bcf288e7b2 100644
--- a/lib/chef/resource/windows_package.rb
+++ b/lib/chef/resource/windows_package.rb
@@ -26,13 +26,14 @@ class Chef
class WindowsPackage < Chef::Resource::Package
include Chef::Mixin::Uris
- provides :package, os: "windows"
+ use_automatic_resource_name
provides :windows_package, os: "windows"
+ provides :package, os: "windows"
+
+ allowed_actions :install, :remove
def initialize(name, run_context=nil)
super
- @allowed_actions.push(:install, :remove)
- @resource_name = :windows_package
@source ||= source(@package_name)
# Unique to this resource
diff --git a/lib/chef/resource/windows_script.rb b/lib/chef/resource/windows_script.rb
index 1af7a48fe4..48e2b535a8 100644
--- a/lib/chef/resource/windows_script.rb
+++ b/lib/chef/resource/windows_script.rb
@@ -31,8 +31,8 @@ class Chef
def initialize(name, run_context, resource_name, interpreter_command)
super(name, run_context)
@interpreter = interpreter_command
- @resource_name = resource_name
- @default_guard_interpreter = resource_name
+ @resource_name = resource_name if resource_name
+ @default_guard_interpreter = self.resource_name
end
include Chef::Mixin::WindowsArchitectureHelper
diff --git a/lib/chef/resource/windows_service.rb b/lib/chef/resource/windows_service.rb
index 8090adceb0..099042840c 100644
--- a/lib/chef/resource/windows_service.rb
+++ b/lib/chef/resource/windows_service.rb
@@ -25,8 +25,11 @@ 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, os: "windows"
+ use_automatic_resource_name
provides :windows_service, os: "windows"
+ provides :service, os: "windows"
+
+ allowed_actions :configure_startup
identity_attr :service_name
@@ -34,8 +37,6 @@ class Chef
def initialize(name, run_context=nil)
super
- @resource_name = :windows_service
- @allowed_actions.push(:configure_startup)
@startup_type = :automatic
@run_as_user = ""
@run_as_password = ""
diff --git a/lib/chef/resource/yum_package.rb b/lib/chef/resource/yum_package.rb
index d8be8c9748..ae9c840582 100644
--- a/lib/chef/resource/yum_package.rb
+++ b/lib/chef/resource/yum_package.rb
@@ -23,12 +23,11 @@ class Chef
class Resource
class YumPackage < Chef::Resource::Package
- provides :yum_package
+ use_automatic_resource_name
provides :package, os: "linux", platform_family: [ "rhel", "fedora" ]
def initialize(name, run_context=nil)
super
- @resource_name = :yum_package
@flush_cache = { :before => false, :after => false }
@allow_downgrade = false
end
diff --git a/lib/chef/resource_builder.rb b/lib/chef/resource_builder.rb
index bb0962d128..9e9f7047a4 100644
--- a/lib/chef/resource_builder.rb
+++ b/lib/chef/resource_builder.rb
@@ -18,6 +18,10 @@
# NOTE: this was extracted from the Recipe DSL mixin, relevant specs are in spec/unit/recipe_spec.rb
+require 'chef/exceptions'
+require 'chef/resource'
+require 'chef/log'
+
class Chef
class ResourceBuilder
attr_reader :type
@@ -46,6 +50,9 @@ class Chef
raise ArgumentError, "You must supply a name when declaring a #{type} resource" if name.nil?
@resource = resource_class.new(name, run_context)
+ if resource.resource_name.nil?
+ raise Chef::Exceptions::InvalidResourceSpecification, "#{resource}.resource_name is `nil`! Did you forget to put `provides :blah` or `resource_name :blah` in your resource class?"
+ end
resource.source_line = created_at
resource.declared_type = type
diff --git a/lib/chef/resource_resolver.rb b/lib/chef/resource_resolver.rb
index a987b236c2..1bd8892239 100644
--- a/lib/chef/resource_resolver.rb
+++ b/lib/chef/resource_resolver.rb
@@ -18,7 +18,6 @@
require 'chef/exceptions'
require 'chef/platform/resource_priority_map'
-require 'chef/mixin/convert_to_class_name'
class Chef
class ResourceResolver
@@ -33,22 +32,13 @@ class Chef
@resource = resource.to_sym
end
- # return a deterministically sorted list of Chef::Resource subclasses
- def resources
- @resources ||= Chef::Resource.descendants
- end
-
def resolve
maybe_dynamic_resource_resolution ||
maybe_chef_platform_lookup
end
- # this cut looks at if the resource can handle the resource type on the node
- def enabled_handlers
- @enabled_handlers ||=
- resources.select do |klass|
- klass.provides?(node, resource)
- end.sort {|a,b| a.to_s <=> b.to_s }
+ def provided_by?(resource_class)
+ !prioritized_handlers.include?(resource_class)
end
#
@@ -61,37 +51,22 @@ class Chef
new(node, resource_name).resolve
end
- private
+ protected
# try dynamically finding a resource based on querying the resources to see what they support
- def maybe_dynamic_resource_resolution # log this so we know what resources will work for the generic resource on the node (early cut)
- Chef::Log.debug "resources for generic #{resource} resource enabled on node include: #{enabled_handlers}"
-
- # if none of the resources specifically support the resource, we still need to pick one of the resources that are
- # enabled on the node to handle the why-run use case.
- handlers = enabled_handlers
-
- if handlers.size >= 2
- # this magic stack ranks the resources by where they appear in the resource_priority_map
- priority_list = [ get_priority_array(node, resource) ].flatten.compact
- handlers = handlers.sort_by { |x| i = priority_list.index x; i.nil? ? Float::INFINITY : i }
- if priority_list.index(handlers.first).nil?
- # if we had more than one and we picked one with a precidence of infinity that means that the resource_priority_map
- # entry for this resource is missing -- we should probably raise here and force resolution of the ambiguity.
- Chef::Log.warn "Ambiguous resource precedence: #{handlers}, please use Chef.set_resource_priority_array to provide determinism"
- end
- handlers = handlers[0..0]
- end
-
- Chef::Log.debug "resources that survived replacement include: #{handlers}"
+ def maybe_dynamic_resource_resolution
+ # log this so we know what resources will work for the generic resource on the node (early cut)
+ Chef::Log.debug "Resources for generic #{resource} resource enabled on node include: #{enabled_handlers}"
- raise Chef::Exceptions::AmbiguousResourceResolution.new(resource, handlers) if handlers.count >= 2
+ handler = prioritized_handlers.first
- Chef::Log.debug "dynamic resource resolver FAILED to resolve a resource" if handlers.empty?
-
- return nil if handlers.empty?
+ if handler
+ Chef::Log.debug "Resource for #{resource} is #{handler}"
+ else
+ Chef::Log.debug "Dynamic resource resolver FAILED to resolve a resource for #{resource}"
+ end
- handlers[0]
+ handler
end
# try the old static lookup of resources by mangling name to resource klass
@@ -99,13 +74,42 @@ class Chef
Chef::Resource.resource_matching_short_name(resource)
end
- # dep injection hooks
- def get_priority_array(node, resource_name)
- resource_priority_map.get_priority_array(node, resource_name)
+ def priority_map
+ Chef::Platform::ResourcePriorityMap.instance
end
- def resource_priority_map
- Chef::Platform::ResourcePriorityMap.instance
+ def prioritized_handlers
+ @prioritized_handlers ||=
+ priority_map.list_handlers(node, resource)
+ end
+
+ module Deprecated
+ # return a deterministically sorted list of Chef::Resource subclasses
+ def resources
+ @resources ||= Chef::Resource.descendants
+ end
+
+ # this cut looks at if the resource can handle the resource type on the node
+ def enabled_handlers
+ @enabled_handlers ||=
+ resources.select do |klass|
+ klass.provides?(node, resource)
+ end.sort {|a,b| a.to_s <=> b.to_s }
+ end
+
+ protected
+
+ # If there are no providers for a DSL, we search through the
+ def prioritized_handlers
+ @prioritized_handlers ||= super || begin
+ if !enabled_handlers.empty?
+ Chef::Log.deprecation("#{resource} is marked as providing DSL #{resource}, but provides #{resource.inspect} was never called!")
+ Chef::Log.deprecation("In Chef 13, this will break: you must call provides to mark the names you provide, even if you also override provides? yourself.")
+ end
+ enabled_handlers
+ end
+ end
end
+ prepend Deprecated
end
end
diff --git a/lib/chef/server_api.rb b/lib/chef/server_api.rb
index ec4a864cb3..764296f8c8 100644
--- a/lib/chef/server_api.rb
+++ b/lib/chef/server_api.rb
@@ -42,3 +42,5 @@ class Chef
use Chef::HTTP::RemoteRequestID
end
end
+
+require 'chef/config'
diff --git a/lib/chef/util/path_helper.rb b/lib/chef/util/path_helper.rb
index 10527f8906..9ebc9319b8 100644
--- a/lib/chef/util/path_helper.rb
+++ b/lib/chef/util/path_helper.rb
@@ -23,4 +23,3 @@ class Chef
PathHelper = ChefConfig::PathHelper
end
end
-
diff --git a/spec/functional/audit/runner_spec.rb b/spec/functional/audit/runner_spec.rb
index 494942889a..aae8fcf582 100644
--- a/spec/functional/audit/runner_spec.rb
+++ b/spec/functional/audit/runner_spec.rb
@@ -46,22 +46,12 @@ describe Chef::Audit::Runner do
RSpec::Core::Sandbox.sandboxed { ex.run }
end
- before do
- Chef::Config[:log_location] = stdout
- end
-
describe "#run" do
let(:audits) { {} }
let(:run_context) { instance_double(Chef::RunContext, :events => events, :audits => audits) }
let(:control_group_name) { "control_group_name" }
- it "Correctly runs an empty controls block" do
- in_sub_process do
- runner.run
- end
- end
-
shared_context "passing audit" do
let(:audits) do
should_pass = lambda do
@@ -84,50 +74,40 @@ describe Chef::Audit::Runner do
end
end
- context "there is a single successful control" do
- include_context "passing audit"
- it "correctly runs" do
- in_sub_process do
- runner.run
-
- expect(stdout.string).to match(/1 example, 0 failures/)
+ describe "log location is stdout" do
+ before do
+ allow(Chef::Log).to receive(:info) do |msg|
+ stdout.puts(msg)
end
end
- end
- context "there is a single failing control" do
- include_context "failing audit"
- it "correctly runs" do
+ it "Correctly runs an empty controls block" do
in_sub_process do
runner.run
-
- expect(stdout.string).to match(/Failure\/Error: expect\(2 - 1\)\.to eq\(0\)/)
- expect(stdout.string).to match(/1 example, 1 failure/)
- expect(stdout.string).to match(/# control_group_name should fail/)
end
end
- end
- describe "log location is a file" do
- let(:tmpfile) { Tempfile.new("audit") }
- before do
- Chef::Config[:log_location] = tmpfile.path
- end
+ context "there is a single successful control" do
+ include_context "passing audit"
+ it "correctly runs" do
+ in_sub_process do
+ runner.run
- after do
- tmpfile.close
- tmpfile.unlink
+ expect(stdout.string).to match(/1 example, 0 failures/)
+ end
+ end
end
- include_context "failing audit"
- it "correctly runs" do
- in_sub_process do
- runner.run
+ context "there is a single failing control" do
+ include_context "failing audit"
+ it "correctly runs" do
+ in_sub_process do
+ runner.run
- contents = tmpfile.read
- expect(contents).to match(/Failure\/Error: expect\(2 - 1\)\.to eq\(0\)/)
- expect(contents).to match(/1 example, 1 failure/)
- expect(contents).to match(/# control_group_name should fail/)
+ expect(stdout.string).to match(/Failure\/Error: expect\(2 - 1\)\.to eq\(0\)/)
+ expect(stdout.string).to match(/1 example, 1 failure/)
+ expect(stdout.string).to match(/# control_group_name should fail/)
+ end
end
end
end
diff --git a/spec/functional/mixin/powershell_out_spec.rb b/spec/functional/mixin/powershell_out_spec.rb
new file mode 100644
index 0000000000..9cc8aeed7e
--- /dev/null
+++ b/spec/functional/mixin/powershell_out_spec.rb
@@ -0,0 +1,43 @@
+#
+# 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/mixin/powershell_out'
+
+describe Chef::Mixin::PowershellOut, windows_only: true do
+ include Chef::Mixin::PowershellOut
+
+ describe "#powershell_out" do
+ it "runs a powershell command and collects stdout" do
+ expect(powershell_out("get-process").run_command.stdout).to match /Handles\s+NPM\(K\)\s+PM\(K\)\s+WS\(K\)\s+VM\(M\)\s+CPU\(s\)\s+Id\s+ProcessName/
+ end
+
+ it "does not raise exceptions when the command is invalid" do
+ powershell_out("this-is-not-a-valid-command").run_command
+ end
+ end
+
+ describe "#powershell_out!" do
+ it "runs a powershell command and collects stdout" do
+ expect(powershell_out!("get-process").run_command.stdout).to match /Handles\s+NPM\(K\)\s+PM\(K\)\s+WS\(K\)\s+VM\(M\)\s+CPU\(s\)\s+Id\s+ProcessName/
+ end
+
+ it "raises exceptions when the command is invalid" do
+ expect { powershell_out!("this-is-not-a-valid-command").run_command }.to raise_exception(Mixlib::ShellOut::ShellCommandFailed)
+ end
+ end
+end
diff --git a/spec/functional/resource/execute_spec.rb b/spec/functional/resource/execute_spec.rb
index ffa4628cb2..692ccfb796 100644
--- a/spec/functional/resource/execute_spec.rb
+++ b/spec/functional/resource/execute_spec.rb
@@ -137,9 +137,16 @@ describe Chef::Resource::Execute do
end
end
+ # Ensure that CommandTimeout is raised, and is caused by resource.timeout really expiring.
+ # https://github.com/chef/chef/issues/2985
+ #
+ # resource.timeout should be short, this is what we're testing
+ # resource.command ruby sleep timer should be longer than resource.timeout to give us something to timeout
+ # Timeout::timeout should be longer than resource.timeout, but less than the resource.command ruby sleep timer,
+ # so we fail if we finish on resource.command instead of resource.timeout, but raise CommandTimeout anyway (#2175).
it "times out when a timeout is set on the resource" do
- Timeout::timeout(5) do
- resource.command %{ruby -e 'sleep 600'}
+ Timeout::timeout(30) do
+ resource.command %{ruby -e 'sleep 300'}
resource.timeout 0.1
expect { resource.run_action(:run) }.to raise_error(Mixlib::ShellOut::CommandTimeout)
end
diff --git a/spec/functional/resource/group_spec.rb b/spec/functional/resource/group_spec.rb
index 6676aa32e9..529af52d4e 100644
--- a/spec/functional/resource/group_spec.rb
+++ b/spec/functional/resource/group_spec.rb
@@ -372,6 +372,11 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
let(:tested_action) { :manage }
describe "when there is no group" do
+ before(:each) do
+ group_resource.run_action(:remove)
+ group_should_not_exist(group_name)
+ end
+
it "raises an error on modify" do
expect { group_resource.run_action(:modify) }.to raise_error
end
diff --git a/spec/functional/resource/powershell_spec.rb b/spec/functional/resource/powershell_spec.rb
index 56a905efe7..17ae8cbd2a 100644
--- a/spec/functional/resource/powershell_spec.rb
+++ b/spec/functional/resource/powershell_spec.rb
@@ -56,14 +56,13 @@ describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
resource.run_action(:run)
end
- it "returns the -27 for a powershell script that exits with -27", :windows_powershell_dsc_only do
- # This is broken on Powershell < 4.0
+ it "returns the exit status 27 for a powershell script that exits with 27" do
file = Tempfile.new(['foo', '.ps1'])
begin
- file.write "exit -27"
+ file.write "exit 27"
file.close
resource.code(". \"#{file.path}\"")
- resource.returns(-27)
+ resource.returns(27)
resource.run_action(:run)
ensure
file.close
@@ -71,6 +70,30 @@ describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
end
end
+ let (:negative_exit_status) { -27 }
+ let (:unsigned_exit_status) { (-negative_exit_status ^ 65535) + 1 }
+ it "returns the exit status -27 as a signed integer or an unsigned 16-bit 2's complement value of 65509 for a powershell script that exits with -27" do
+ # Versions of PowerShell prior to 4.0 return a 16-bit unsigned value --
+ # PowerShell 4.0 and later versions return a 32-bit signed value.
+ file = Tempfile.new(['foo', '.ps1'])
+ begin
+ file.write "exit #{negative_exit_status.to_s}"
+ file.close
+ resource.code(". \"#{file.path}\"")
+
+ # PowerShell earlier than 4.0 takes negative exit codes
+ # and returns them as the underlying unsigned 16-bit
+ # 2's complement representation. We cover multiple versions
+ # of PowerShell in this example by including both the signed
+ # exit code and its converted counterpart as permitted return values.
+ # See http://support.microsoft.com/en-us/kb/2646183/zh-cn
+ resource.returns([negative_exit_status, unsigned_exit_status])
+ expect { resource.run_action(:run) }.not_to raise_error
+ ensure
+ file.close
+ file.unlink
+ end
+ end
it "returns the process exit code" do
resource.code(arbitrary_nonzero_process_exit_code_content)
@@ -99,7 +122,19 @@ describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
it "returns 1 if the last command was a cmdlet that failed and was preceded by a successfully executed non-cmdlet Windows binary" do
resource.code([windows_process_exit_code_success_content, cmdlet_exit_code_not_found_content].join(';'))
resource.returns(1)
- resource.run_action(:run)
+ expect { resource.run_action(:run) }.not_to raise_error
+ end
+
+ it "raises an error if the script is not syntactically correct and returns is not set to 1" do
+ resource.code('if({)')
+ resource.returns(0)
+ expect { resource.run_action(:run) }.to raise_error(Mixlib::ShellOut::ShellCommandFailed)
+ end
+
+ it "returns 1 if the script provided to the code attribute is not syntactically correct" do
+ resource.code('if({)')
+ resource.returns(1)
+ expect { resource.run_action(:run) }.not_to raise_error
end
# This somewhat ambiguous case, two failures of different types,
diff --git a/spec/integration/recipes/provider_choice.rb b/spec/integration/recipes/provider_choice.rb
index 999765a1de..01537b2c05 100644
--- a/spec/integration/recipes/provider_choice.rb
+++ b/spec/integration/recipes/provider_choice.rb
@@ -6,13 +6,8 @@ describe "Recipe DSL methods" do
context "With resource class providing 'provider_thingy'" do
before :context do
class Chef::Resource::ProviderThingy < Chef::Resource
- def initialize(*args, &block)
- super
- @action = :create
- @allowed_actions = [ :create ]
- @resource_name = 'provider_thingy'
- end
- provides :provider_thingy
+ resource_name :provider_thingy
+ default_action :create
def to_s
"provider_thingy resource class"
end
diff --git a/spec/integration/recipes/recipe_dsl_spec.rb b/spec/integration/recipes/recipe_dsl_spec.rb
index 079baaa162..93270a9a19 100644
--- a/spec/integration/recipes/recipe_dsl_spec.rb
+++ b/spec/integration/recipes/recipe_dsl_spec.rb
@@ -9,11 +9,12 @@ describe "Recipe DSL methods" do
class BaseThingy < Chef::Resource
def initialize(*args, &block)
super
- @resource_name = 'base_thingy'
@allowed_actions = [ :create ]
@action = :create
end
+ resource_name 'base_thingy'
+
class<<self
attr_accessor :created_resource
attr_accessor :created_provider
@@ -54,7 +55,6 @@ describe "Recipe DSL methods" do
class Chef::Resource::BackcompatThingy < Chef::Resource
def initialize(*args, &block)
super
- @resource_name = 'backcompat_thingy'
@allowed_actions = [ :create ]
@action = :create
end
@@ -84,6 +84,7 @@ describe "Recipe DSL methods" do
class RecipeDSLSpecNamespace::BackcompatThingy < BaseThingy
provides :backcompat_thingy
+ resource_name :backcompat_thingy
end
}
@@ -118,7 +119,7 @@ describe "Recipe DSL methods" do
before(:context) {
class RecipeDSLSpecNamespace::MySupplier < BaseThingy
- provides :hemlock
+ resource_name :hemlock
end
}
@@ -141,7 +142,7 @@ describe "Recipe DSL methods" do
before(:context) {
class RecipeDSLSpecNamespace::Thingy3 < BaseThingy
- provides :thingy3
+ resource_name :thingy3
end
}
@@ -156,18 +157,17 @@ describe "Recipe DSL methods" do
context "And Thingy4 provides :thingy3" do
before(:context) {
- class RecipeDSLSpecNamespace::Thingy4 < Chef::Resource
- provides :thingy3
+ class RecipeDSLSpecNamespace::Thingy4 < BaseThingy
+ resource_name :thingy3
end
}
- it "thingy3 works in a recipe and yields " do
+ it "thingy3 works in a recipe and yields Foo::Thingy4 (the explicit one)" do
recipe = converge {
thingy3 'blah' do; end
}
- expect(recipe.logged_warnings).to match(/ambiguous resource precedence/i)
- expect(BaseThingy.created_resource).not_to be_nil
+ expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy4
end
it "thingy4 does not work in a recipe" do
@@ -182,7 +182,7 @@ describe "Recipe DSL methods" do
before(:context) {
class RecipeDSLSpecNamespace::Thingy5 < BaseThingy
- provides :thingy5
+ resource_name :thingy5
provides :twizzle
provides :twizzle2
end
@@ -214,10 +214,12 @@ describe "Recipe DSL methods" do
context "With platform-specific resources 'my_super_thingy_foo' and 'my_super_thingy_bar'" do
before(:context) {
class MySuperThingyFoo < BaseThingy
+ resource_name :my_super_thingy_foo
provides :my_super_thingy, platform: 'foo'
end
class MySuperThingyBar < BaseThingy
+ resource_name :my_super_thingy_bar
provides :my_super_thingy, platform: 'bar'
end
}
diff --git a/spec/integration/recipes/resource_definition_spec.rb b/spec/integration/recipes/resource_definition_spec.rb
new file mode 100644
index 0000000000..4e5bc53428
--- /dev/null
+++ b/spec/integration/recipes/resource_definition_spec.rb
@@ -0,0 +1,18 @@
+require 'support/shared/integration/integration_helper'
+
+describe "Resource definition" do
+ include IntegrationSupport
+
+ context "With a resource with only provides lines and no resource_name" do
+ before(:context) {
+ class ResourceDefinitionNoNameTest < Chef::Resource
+ provides :resource_definition_no_name_test
+ end
+ }
+ it "Creating said resource with the resource builder fails with an exception" do
+ expect_converge {
+ resource_definition_no_name_test 'blah'
+ }.to raise_error(Chef::Exceptions::InvalidResourceSpecification)
+ end
+ end
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 8b5e42e5b6..dcf244c3cc 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -151,7 +151,7 @@ RSpec.configure do |config|
config.filter_run_excluding :aes_256_gcm_only => true unless aes_256_gcm?
config.filter_run_excluding :broken => true
- running_platform_arch = `uname -m`.strip
+ running_platform_arch = `uname -m`.strip unless windows?
config.filter_run_excluding :arch => lambda {|target_arch|
running_platform_arch != target_arch
diff --git a/spec/support/lib/chef/resource/cat.rb b/spec/support/lib/chef/resource/cat.rb
index 641ce28795..9bfaebf07b 100644
--- a/spec/support/lib/chef/resource/cat.rb
+++ b/spec/support/lib/chef/resource/cat.rb
@@ -19,12 +19,11 @@
class Chef
class Resource
class Cat < Chef::Resource
- provides :cat
+ use_automatic_resource_name
attr_accessor :action
def initialize(name, run_context=nil)
- @resource_name = :cat
super
@action = "sell"
end
diff --git a/spec/support/lib/chef/resource/one_two_three_four.rb b/spec/support/lib/chef/resource/one_two_three_four.rb
index d7e5ea095e..4543744a28 100644
--- a/spec/support/lib/chef/resource/one_two_three_four.rb
+++ b/spec/support/lib/chef/resource/one_two_three_four.rb
@@ -19,15 +19,10 @@
class Chef
class Resource
class OneTwoThreeFour < Chef::Resource
- provides :one_two_three_four
+ use_automatic_resource_name
attr_reader :i_can_count
- def initialize(name, run_context)
- @resource_name = :one_two_three_four
- super
- end
-
def i_can_count(tf)
@i_can_count = tf
end
diff --git a/spec/support/lib/chef/resource/with_state.rb b/spec/support/lib/chef/resource/with_state.rb
index 226de0a6d2..efff2e7c12 100644
--- a/spec/support/lib/chef/resource/with_state.rb
+++ b/spec/support/lib/chef/resource/with_state.rb
@@ -22,16 +22,9 @@ require 'chef/json_compat'
class Chef
class Resource
class WithState < Chef::Resource
- attr_accessor :state
-
- def initialize(name, run_context=nil)
- @resource_name = :with_state
- super
- end
+ use_automatic_resource_name
- def state
- @state
- end
+ attr_accessor :state
end
end
end
diff --git a/spec/support/lib/chef/resource/zen_follower.rb b/spec/support/lib/chef/resource/zen_follower.rb
index 590aa0827b..90d33e6039 100644
--- a/spec/support/lib/chef/resource/zen_follower.rb
+++ b/spec/support/lib/chef/resource/zen_follower.rb
@@ -21,15 +21,10 @@ require 'chef/json_compat'
class Chef
class Resource
class ZenFollower < Chef::Resource
- provides :zen_follower
+ use_automatic_resource_name
provides :follower, platform: "zen"
- def initialize(name, run_context=nil)
- @resource_name = :zen_follower
- super
- end
-
def master(arg=nil)
if !arg.nil?
@master = arg
diff --git a/spec/support/lib/chef/resource/zen_master.rb b/spec/support/lib/chef/resource/zen_master.rb
index 145dd70e64..82cef0bb50 100644
--- a/spec/support/lib/chef/resource/zen_master.rb
+++ b/spec/support/lib/chef/resource/zen_master.rb
@@ -22,15 +22,11 @@ require 'chef/json_compat'
class Chef
class Resource
class ZenMaster < Chef::Resource
- provides :zen_master
+ use_automatic_resource_name
+ allowed_actions :win, :score
attr_reader :peace
- def initialize(name, run_context=nil)
- @resource_name = :zen_master
- super
- allowed_actions << :win << :score
- end
def peace(tf)
@peace = tf
diff --git a/spec/support/shared/context/client.rb b/spec/support/shared/context/client.rb
index e625185f7c..eb537e9889 100644
--- a/spec/support/shared/context/client.rb
+++ b/spec/support/shared/context/client.rb
@@ -215,8 +215,9 @@ shared_context "audit phase failed with error" do
def stub_for_audit
expect(Chef::Audit::Runner).to receive(:new).and_return(audit_runner)
+ expect(Chef::Audit::Logger).to receive(:read_buffer).and_return("Audit mode output!")
expect(audit_runner).to receive(:run).and_raise(audit_error)
- expect(client.events).to receive(:audit_phase_failed).with(audit_error)
+ expect(client.events).to receive(:audit_phase_failed).with(audit_error, "Audit mode output!")
end
end
@@ -232,11 +233,12 @@ shared_context "audit phase completed with failed controls" do
def stub_for_audit
expect(Chef::Audit::Runner).to receive(:new).and_return(audit_runner)
+ expect(Chef::Audit::Logger).to receive(:read_buffer).and_return("Audit mode output!")
expect(audit_runner).to receive(:run)
expect(Chef::Exceptions::AuditsFailed).to receive(:new).with(
audit_runner.num_failed, audit_runner.num_total
).and_return(audit_error)
- expect(client.events).to receive(:audit_phase_failed).with(audit_error)
+ expect(client.events).to receive(:audit_phase_failed).with(audit_error, "Audit mode output!")
end
end
diff --git a/spec/support/shared/functional/windows_script.rb b/spec/support/shared/functional/windows_script.rb
index 35b86dc4e8..3499cc98ec 100644
--- a/spec/support/shared/functional/windows_script.rb
+++ b/spec/support/shared/functional/windows_script.rb
@@ -114,7 +114,7 @@ shared_context Chef::Resource::WindowsScript do
describe "when the run action is invoked on Windows" do
it "executes the script code" do
- resource.code("@whoami > #{script_output_path}")
+ resource.code("whoami > #{script_output_path}")
resource.returns(0)
resource.run_action(:run)
end
diff --git a/spec/unit/audit/audit_reporter_spec.rb b/spec/unit/audit/audit_reporter_spec.rb
index 75c96155da..46c2a96b4c 100644
--- a/spec/unit/audit/audit_reporter_spec.rb
+++ b/spec/unit/audit/audit_reporter_spec.rb
@@ -314,14 +314,14 @@ EOM
it "notifies audit phase finished to debug log" do
expect(Chef::Log).to receive(:debug).with(/Audit Reporter completed/)
- reporter.audit_phase_complete
+ reporter.audit_phase_complete("Output from audit mode")
end
it "collects audit data" do
ordered_control_groups.each do |_name, group|
expect(audit_data).to receive(:add_control_group).with(group)
end
- reporter.audit_phase_complete
+ reporter.audit_phase_complete("Output from audit mode")
end
end
@@ -332,14 +332,14 @@ EOM
it "notifies audit phase failed to debug log" do
expect(Chef::Log).to receive(:debug).with(/Audit Reporter failed/)
- reporter.audit_phase_failed(error)
+ reporter.audit_phase_failed(error, "Output from audit mode")
end
it "collects audit data" do
ordered_control_groups.each do |_name, group|
expect(audit_data).to receive(:add_control_group).with(group)
end
- reporter.audit_phase_failed(error)
+ reporter.audit_phase_failed(error, "Output from audit mode")
end
end
diff --git a/spec/unit/audit/logger_spec.rb b/spec/unit/audit/logger_spec.rb
new file mode 100644
index 0000000000..9dd9ce2cd9
--- /dev/null
+++ b/spec/unit/audit/logger_spec.rb
@@ -0,0 +1,42 @@
+#
+# 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'
+
+describe Chef::Audit::Logger do
+
+ before(:each) do
+ Chef::Audit::Logger.instance_variable_set(:@buffer, nil)
+ end
+
+ it 'calling puts creates @buffer and adds the message' do
+ Chef::Audit::Logger.puts("Output message")
+ expect(Chef::Audit::Logger.read_buffer).to eq("Output message\n")
+ end
+
+ it 'calling puts multiple times adds to the message' do
+ Chef::Audit::Logger.puts("Output message")
+ Chef::Audit::Logger.puts("Output message")
+ Chef::Audit::Logger.puts("Output message")
+ expect(Chef::Audit::Logger.read_buffer).to eq("Output message\nOutput message\nOutput message\n")
+ end
+
+ it 'calling it before @buffer is set returns an empty string' do
+ expect(Chef::Audit::Logger.read_buffer).to eq("")
+ end
+
+end
diff --git a/spec/unit/audit/runner_spec.rb b/spec/unit/audit/runner_spec.rb
index 0bd4c18388..1de024260f 100644
--- a/spec/unit/audit/runner_spec.rb
+++ b/spec/unit/audit/runner_spec.rb
@@ -68,8 +68,8 @@ describe Chef::Audit::Runner do
in_sub_process do
runner.send(:setup)
- expect(RSpec.configuration.output_stream).to eq(log_location)
- expect(RSpec.configuration.error_stream).to eq(log_location)
+ expect(RSpec.configuration.output_stream).to eq(Chef::Audit::Logger)
+ expect(RSpec.configuration.error_stream).to eq(Chef::Audit::Logger)
expect(RSpec.configuration.formatters.size).to eq(2)
expect(RSpec.configuration.formatters).to include(instance_of(Chef::Audit::AuditEventProxy))
diff --git a/spec/unit/deprecation_spec.rb b/spec/unit/deprecation_spec.rb
index f824cb7c76..2e1f3c39f3 100644
--- a/spec/unit/deprecation_spec.rb
+++ b/spec/unit/deprecation_spec.rb
@@ -95,4 +95,59 @@ describe Chef::Deprecation do
expect { test_instance.deprecated_method(10) }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
end
+ context "When a class has deprecated_attr, _reader and _writer" do
+ before(:context) do
+ class DeprecatedAttrTest
+ extend Chef::Mixin::Deprecation
+ def initialize
+ @a = @r = @w = 1
+ end
+ deprecated_attr :a, "a"
+ deprecated_attr_reader :r, "r"
+ deprecated_attr_writer :w, "w"
+ end
+ end
+
+ it "The deprecated_attr emits warnings" do
+ test = DeprecatedAttrTest.new
+ expect { test.a = 10 }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
+ expect { test.a }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
+ end
+
+ it "The deprecated_attr_writer emits warnings, and does not create a reader" do
+ test = DeprecatedAttrTest.new
+ expect { test.w = 10 }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
+ expect { test.w }.to raise_error(NoMethodError)
+ end
+
+ it "The deprecated_attr_reader emits warnings, and does not create a writer" do
+ test = DeprecatedAttrTest.new
+ expect { test.r = 10 }.to raise_error(NoMethodError)
+ expect { test.r }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
+ end
+
+ context "With deprecation warnings not throwing exceptions" do
+ before do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ end
+
+ it "The deprecated_attr can be written to and read from" do
+ test = DeprecatedAttrTest.new
+ test.a = 10
+ expect(test.a).to eq 10
+ end
+
+ it "The deprecated_attr_reader can be read from" do
+ test = DeprecatedAttrTest.new
+ expect(test.r).to eq 1
+ end
+
+ it "The deprecated_attr_writer can be written to" do
+ test = DeprecatedAttrTest.new
+ test.w = 10
+ expect(test.instance_eval { @w }).to eq 10
+ end
+ end
+ end
+
end
diff --git a/spec/unit/dsl/resources_spec.rb b/spec/unit/dsl/resources_spec.rb
new file mode 100644
index 0000000000..581c835290
--- /dev/null
+++ b/spec/unit/dsl/resources_spec.rb
@@ -0,0 +1,85 @@
+#
+# Author:: Noah Kantrowitz (<noah@coderanger.net>)
+# Copyright:: Copyright (c) 2015 Noah Kantrowitz
+# 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/dsl/resources'
+
+describe Chef::DSL::Resources do
+ let(:declared_resources) { [] }
+ let(:test_class) do
+ r = declared_resources
+ Class.new do
+ include Chef::DSL::Resources
+ define_method(:declare_resource) do |dsl_name, name, _created_at, &_block|
+ r << [dsl_name, name]
+ end
+ end
+ end
+ subject { declared_resources }
+ after do
+ # Always clean up after ourselves.
+ described_class.remove_resource_dsl(:test_resource)
+ end
+
+ context 'with a resource added' do
+ before do
+ Chef::DSL::Resources.add_resource_dsl(:test_resource)
+ test_class.new.instance_eval do
+ test_resource 'test_name' do
+ end
+ end
+ end
+ it { is_expected.to eq [[:test_resource, 'test_name']]}
+ end
+
+ context 'with no resource added' do
+ subject do
+ test_class.new.instance_eval do
+ test_resource 'test_name' do
+ end
+ end
+ end
+
+ it { expect { subject }.to raise_error NoMethodError }
+ end
+
+ context 'with a resource added and removed' do
+ before do
+ Chef::DSL::Resources.add_resource_dsl(:test_resource)
+ Chef::DSL::Resources.remove_resource_dsl(:test_resource)
+ end
+ subject do
+ test_class.new.instance_eval do
+ test_resource 'test_name' do
+ end
+ end
+ end
+
+ it { expect { subject }.to raise_error NoMethodError }
+ end
+
+ context 'with a nameless resource' do
+ before do
+ Chef::DSL::Resources.add_resource_dsl(:test_resource)
+ test_class.new.instance_eval do
+ test_resource { }
+ end
+ end
+ it { is_expected.to eq [[:test_resource, nil]]}
+ end
+end
diff --git a/spec/unit/knife/core/subcommand_loader_spec.rb b/spec/unit/knife/core/subcommand_loader_spec.rb
index 76ebf154db..219a1f2906 100644
--- a/spec/unit/knife/core/subcommand_loader_spec.rb
+++ b/spec/unit/knife/core/subcommand_loader_spec.rb
@@ -22,14 +22,14 @@ describe Chef::Knife::SubcommandLoader do
let(:loader) { Chef::Knife::SubcommandLoader.new(File.join(CHEF_SPEC_DATA, 'knife-site-subcommands')) }
let(:home) { File.join(CHEF_SPEC_DATA, 'knife-home') }
let(:plugin_dir) { File.join(home, '.chef', 'plugins', 'knife') }
-
+
before do
allow(ChefConfig).to receive(:windows?) { false }
- Chef::Util::PathHelper.class_variable_set(:@@home_dir, home)
+ Chef::Util::PathHelper.class_variable_set(:@@home_dir, home)
end
after do
- Chef::Util::PathHelper.class_variable_set(:@@home_dir, nil)
+ Chef::Util::PathHelper.class_variable_set(:@@home_dir, nil)
end
it "builds a list of the core subcommand file require paths" do
@@ -106,6 +106,18 @@ describe Chef::Knife::SubcommandLoader do
# Chef 12.0.0.rc.0 gem also:
"/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}.rc.0/lib/chef/knife/thing.rb",
+ # Test that we ignore the platform suffix when checking for different
+ # gem versions.
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-x86-mingw32/lib/chef/knife/valid.rb",
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-i386-mingw64/lib/chef/knife/valid-too.rb",
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-mswin32/lib/chef/knife/also-valid.rb",
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-universal-mingw32/lib/chef/knife/universal-is-valid.rb",
+ # ...but don't ignore the .rc / .dev parts in the case when we have
+ # platform suffixes
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}.rc.0-x86-mingw32/lib/chef/knife/invalid.rb",
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}.dev-mswin32/lib/chef/knife/invalid-too.rb",
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}.dev.0-x86-mingw64/lib/chef/knife/still-invalid.rb",
+
# This command is "extra" compared to what's in the embedded/apps/chef install:
"/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-1.0.0/lib/chef/knife/data_bag_secret_options.rb",
"/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-vault-2.2.4/lib/chef/knife/decrypt.rb",
@@ -133,6 +145,10 @@ describe Chef::Knife::SubcommandLoader do
"/opt/chefdk/embedded/apps/chef/lib/chef/knife/bootstrap.rb",
"/opt/chefdk/embedded/apps/chef/lib/chef/knife/client_bulk_delete.rb",
"/opt/chefdk/embedded/apps/chef/lib/chef/knife/client_create.rb",
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-x86-mingw32/lib/chef/knife/valid.rb",
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-i386-mingw64/lib/chef/knife/valid-too.rb",
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-mswin32/lib/chef/knife/also-valid.rb",
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-universal-mingw32/lib/chef/knife/universal-is-valid.rb",
"/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-vault-2.2.4/lib/chef/knife/decrypt.rb",
"/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/knife-spork-1.4.1/lib/chef/knife/spork-bump.rb",
"/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-foo-#{Chef::VERSION}/lib/chef/knife/chef-foo.rb",
diff --git a/spec/unit/lwrp_spec.rb b/spec/unit/lwrp_spec.rb
index 659696fd28..f83678308a 100644
--- a/spec/unit/lwrp_spec.rb
+++ b/spec/unit/lwrp_spec.rb
@@ -146,7 +146,7 @@ describe "LWRP" do
it "Should load the old content, and not the new" do
resource = Chef::Resource.resource_for_node(:lwrp_foo, Chef::Node.new)
expect(resource).to eq @original_resource
- expect(resource.default_action).to eq([:pass_buck])
+ expect(resource.default_action).to eq(:pass_buck)
expect(Chef.method_defined?(:method_created_by_override_lwrp_foo)).to be_falsey
end
end
@@ -185,7 +185,7 @@ describe "LWRP" do
end
it "should set the specified action as the default action" do
- expect(get_lwrp(:lwrp_foo).new("blah").action).to eq([:pass_buck])
+ expect(get_lwrp(:lwrp_foo).new("blah").action).to eq(:pass_buck)
end
it "should create a method for each attribute" do
@@ -229,14 +229,6 @@ describe "LWRP" do
expect(klass.resource_name).to eq(:foo)
end
- context "when creating a new instance" do
- it "raises an exception if resource_name is nil" do
- expect {
- klass.new('blah')
- }.to raise_error(Chef::Exceptions::InvalidResourceSpecification)
- end
- end
-
context "lazy default values" do
let(:klass) do
Class.new(Chef::Resource::LWRPBase) do
@@ -289,7 +281,7 @@ describe "LWRP" do
end
it "delegates #default_action to the parent" do
- expect(child.default_action).to eq([:eat])
+ expect(child.default_action).to eq(:eat)
end
end
@@ -306,7 +298,7 @@ describe "LWRP" do
end
it "does not delegate #default_action to the parent" do
- expect(child.default_action).to eq([:dont_eat])
+ expect(child.default_action).to eq(:dont_eat)
end
end
diff --git a/spec/unit/mixin/powershell_out_spec.rb b/spec/unit/mixin/powershell_out_spec.rb
new file mode 100644
index 0000000000..0fede582fa
--- /dev/null
+++ b/spec/unit/mixin/powershell_out_spec.rb
@@ -0,0 +1,70 @@
+#
+# Copyright:: Copyright (c) 2015 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/mixin/powershell_out'
+
+describe Chef::Mixin::PowershellOut do
+ let(:shell_out_class) { Class.new { include Chef::Mixin::PowershellOut } }
+ subject(:object) { shell_out_class.new }
+ let(:architecture) { "something" }
+ let(:flags) {
+ "-NoLogo -NonInteractive -NoProfile -ExecutionPolicy Unrestricted -InputFormat None"
+ }
+
+ describe "#powershell_out" do
+ it "runs a command and returns the shell_out object" do
+ ret = double("Mixlib::ShellOut")
+ expect(object).to receive(:shell_out).with(
+ "powershell.exe #{flags} -Command \"Get-Process\"",
+ {}
+ ).and_return(ret)
+ expect(object.powershell_out("Get-Process")).to eql(ret)
+ end
+
+ it "passes options" do
+ ret = double("Mixlib::ShellOut")
+ expect(object).to receive(:shell_out).with(
+ "powershell.exe #{flags} -Command \"Get-Process\"",
+ timeout: 600
+ ).and_return(ret)
+ expect(object.powershell_out("Get-Process", timeout: 600)).to eql(ret)
+ end
+ end
+
+ describe "#powershell_out!" do
+ it "runs a command and returns the shell_out object" do
+ mixlib_shellout = double("Mixlib::ShellOut")
+ expect(object).to receive(:shell_out).with(
+ "powershell.exe #{flags} -Command \"Get-Process\"",
+ {}
+ ).and_return(mixlib_shellout)
+ expect(mixlib_shellout).to receive(:error!)
+ expect(object.powershell_out!("Get-Process")).to eql(mixlib_shellout)
+ end
+
+ it "passes options" do
+ mixlib_shellout = double("Mixlib::ShellOut")
+ expect(object).to receive(:shell_out).with(
+ "powershell.exe #{flags} -Command \"Get-Process\"",
+ timeout: 600
+ ).and_return(mixlib_shellout)
+ expect(mixlib_shellout).to receive(:error!)
+ expect(object.powershell_out!("Get-Process", timeout: 600)).to eql(mixlib_shellout)
+ end
+ end
+end
diff --git a/spec/unit/node_map_spec.rb b/spec/unit/node_map_spec.rb
index fe7372961b..9b5ff5e8c6 100644
--- a/spec/unit/node_map_spec.rb
+++ b/spec/unit/node_map_spec.rb
@@ -134,6 +134,10 @@ describe Chef::NodeMap do
end
describe "resource back-compat testing" do
+ before :each do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ end
+
it "should handle :on_platforms => :all" do
node_map.set(:chef_gem, :foo, :on_platforms => :all)
allow(node).to receive(:[]).with(:platform).and_return("windows")
@@ -152,4 +156,3 @@ describe Chef::NodeMap do
end
end
-
diff --git a/spec/unit/platform_spec.rb b/spec/unit/platform_spec.rb
index e0115bc42a..36325d5411 100644
--- a/spec/unit/platform_spec.rb
+++ b/spec/unit/platform_spec.rb
@@ -18,29 +18,6 @@
require 'spec_helper'
-describe "Chef::Platform supports" do
- [
- :freebsd,
- :ubuntu,
- :debian,
- :centos,
- :fedora,
- :suse,
- :opensuse,
- :redhat,
- :oracle,
- :gentoo,
- :arch,
- :solaris,
- :gcel,
- :ibm_powerkvm
- ].each do |platform|
- it "#{platform}" do
- expect(Chef::Platform.platforms).to have_key(platform)
- end
- end
-end
-
describe Chef::Platform do
context "while testing with fake data" do
@@ -261,41 +238,4 @@ describe Chef::Platform do
end
- context "while testing the configured platform data" do
-
- it "should use the solaris package provider on Solaris <11" do
- pmap = Chef::Platform.find("Solaris2", "5.9")
- expect(pmap[:package]).to eql(Chef::Provider::Package::Solaris)
- end
-
- it "should use the IPS package provider on Solaris 11" do
- pmap = Chef::Platform.find("Solaris2", "5.11")
- expect(pmap[:package]).to eql(Chef::Provider::Package::Ips)
- end
-
- it "should use the Redhat service provider on SLES11" do
- 1.upto(3) do |sp|
- pmap = Chef::Platform.find("SUSE", "11.#{sp}")
- expect(pmap[:service]).to eql(Chef::Provider::Service::Redhat)
- end
- end
-
- it "should use the Systemd service provider on SLES12" do
- pmap = Chef::Platform.find("SUSE", "12.0")
- expect(pmap[:service]).to eql(Chef::Provider::Service::Systemd)
- end
-
- it "should use the SUSE group provider on SLES11" do
- 1.upto(3) do |sp|
- pmap = Chef::Platform.find("SUSE", "11.#{sp}")
- expect(pmap[:group]).to eql(Chef::Provider::Group::Suse)
- end
- end
-
- it "should use the Gpasswd group provider on SLES12" do
- pmap = Chef::Platform.find("SUSE", "12.0")
- expect(pmap[:group]).to eql(Chef::Provider::Group::Gpasswd)
- end
- end
-
end
diff --git a/spec/unit/provider/deploy_spec.rb b/spec/unit/provider/deploy_spec.rb
index a2997d8399..63658ac601 100644
--- a/spec/unit/provider/deploy_spec.rb
+++ b/spec/unit/provider/deploy_spec.rb
@@ -622,7 +622,7 @@ describe Chef::Provider::Deploy do
gems = @provider.send(:gem_packages)
- expect(gems.map { |g| g.action }).to eq([[:install]])
+ expect(gems.map { |g| g.action }).to eq([:install])
expect(gems.map { |g| g.name }).to eq(%w{eventmachine})
expect(gems.map { |g| g.version }).to eq(%w{0.12.9})
end
diff --git a/spec/unit/provider/package/rubygems_spec.rb b/spec/unit/provider/package/rubygems_spec.rb
index 3ccc69652f..d3cee82623 100644
--- a/spec/unit/provider/package/rubygems_spec.rb
+++ b/spec/unit/provider/package/rubygems_spec.rb
@@ -107,38 +107,6 @@ describe Chef::Provider::Package::Rubygems::CurrentGemEnvironment do
expect(@gem_env.candidate_version_from_remote(Gem::Dependency.new('rspec', '>= 0'))).to eq(Gem::Version.new('1.3.0'))
end
- context "when rubygems was upgraded from 1.8->2.0" do
- # https://github.com/rubygems/rubygems/issues/404
- # tl;dr rubygems 1.8 and 2.0 can both be in the load path, which means that
- # require "rubygems/format" will load even though rubygems 2.0 doesn't have
- # that file.
-
- before do
- if defined?(Gem::Format)
- # tests are running under rubygems 1.8, or 2.0 upgraded from 1.8
- @remove_gem_format = false
- else
- Gem.const_set(:Format, Object.new)
- @remove_gem_format = true
- end
- allow(Gem::Package).to receive(:respond_to?).and_call_original
- allow(Gem::Package).to receive(:respond_to?).with(:open).and_return(false)
- end
-
- after do
- if @remove_gem_format
- Gem.send(:remove_const, :Format)
- end
- end
-
- it "finds a matching gem candidate version on rubygems 2.0+ with some rubygems 1.8 code loaded" do
- package = double("Gem::Package", :spec => "a gemspec from package")
- expect(Gem::Package).to receive(:new).with("/path/to/package.gem").and_return(package)
- expect(@gem_env.spec_from_file("/path/to/package.gem")).to eq("a gemspec from package")
- end
-
- end
-
it "gives the candidate version as nil if none is found" do
dep = Gem::Dependency.new('rspec', '>= 0')
latest = []
diff --git a/spec/unit/provider/powershell_spec.rb b/spec/unit/provider/powershell_spec.rb
index 60dbcf80b0..855c18af9b 100644
--- a/spec/unit/provider/powershell_spec.rb
+++ b/spec/unit/provider/powershell_spec.rb
@@ -19,20 +19,62 @@
require 'spec_helper'
describe Chef::Provider::PowershellScript, "action_run" do
- before(:each) do
- @node = Chef::Node.new
+ let(:powershell_version) { nil }
+ let(:node) {
+ node = Chef::Node.new
+ node.default["kernel"] = Hash.new
+ node.default["kernel"][:machine] = :x86_64.to_s
+ if ! powershell_version.nil?
+ node.default[:languages] = { :powershell => { :version => powershell_version } }
+ end
+ node
+ }
- @node.default["kernel"] = Hash.new
- @node.default["kernel"][:machine] = :x86_64.to_s
+ let(:provider) {
+ empty_events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, {}, empty_events)
+ new_resource = Chef::Resource::PowershellScript.new('run some powershell code', run_context)
+ Chef::Provider::PowershellScript.new(new_resource, run_context)
+ }
- @run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::PowershellScript.new('run some powershell code', @run_context)
+ context 'when setting interpreter flags' do
+ it "should set the -File flag as the last flag" do
+ expect(provider.flags.split(' ').pop).to eq("-File")
+ end
- @provider = Chef::Provider::PowershellScript.new(@new_resource, @run_context)
- end
+ let(:execution_policy_flag) do
+ execution_policy_index = 0
+ provider_flags = provider.flags.split(' ')
+ execution_policy_specified = false
- it "should set the -File flag as the last flag" do
- expect(@provider.flags.split(' ').pop).to eq("-File")
- end
+ provider_flags.find do | value |
+ execution_policy_index += 1
+ execution_policy_specified = value.downcase == '-ExecutionPolicy'.downcase
+ end
+
+ execution_policy = execution_policy_specified ? provider_flags[execution_policy_index] : nil
+ end
+ context 'when running with an unspecified PowerShell version' do
+ let(:powershell_version) { nil }
+ it "should set the -ExecutionPolicy flag to 'Unrestricted' by default" do
+ expect(execution_policy_flag.downcase).to eq('unrestricted'.downcase)
+ end
+ end
+
+ { '2.0' => 'Unrestricted',
+ '2.5' => 'Unrestricted',
+ '3.0' => 'Bypass',
+ '3.6' => 'Bypass',
+ '4.0' => 'Bypass',
+ '5.0' => 'Bypass' }.each do | version_policy |
+ let(:powershell_version) { version_policy[0].to_f }
+ context "when running PowerShell version #{version_policy[0]}" do
+ let(:powershell_version) { version_policy[0].to_f }
+ it "should set the -ExecutionPolicy flag to '#{version_policy[1]}'" do
+ expect(execution_policy_flag.downcase).to eq(version_policy[1].downcase)
+ end
+ end
+ end
+ end
end
diff --git a/spec/unit/provider_resolver_spec.rb b/spec/unit/provider_resolver_spec.rb
index bdf6d06e09..a27074e0bc 100644
--- a/spec/unit/provider_resolver_spec.rb
+++ b/spec/unit/provider_resolver_spec.rb
@@ -19,9 +19,13 @@
require 'spec_helper'
require 'chef/mixin/convert_to_class_name'
require 'chef/provider_resolver'
+require 'chef/platform/service_helpers'
include Chef::Mixin::ConvertToClassName
+# Open up Provider so we can write things down easier in here
+#module Chef::Provider
+
describe Chef::ProviderResolver do
let(:node) do
@@ -50,6 +54,51 @@ describe Chef::ProviderResolver do
allow(resource).to receive(:is_a?).with(Chef::Resource).and_return(true)
end
+ def self.on_platform(platform, *tags,
+ platform_version: '11.0.1',
+ platform_family: nil,
+ os: nil,
+ &block)
+ Array(platform).each do |platform|
+ Array(platform_version).each do |platform_version|
+ on_one_platform(platform, platform_version, platform_family || platform, os || platform_family || platform, *tags, &block)
+ end
+ end
+ end
+
+ def self.on_one_platform(platform, platform_version, platform_family, os, *tags, &block)
+ describe "on #{platform} #{platform_version}, platform_family: #{platform_family}, os: #{os}", *tags do
+ let(:os) { os }
+ let(:platform) { platform }
+ let(:platform_family) { platform_family }
+ let(:platform_version) { platform_version }
+
+ define_singleton_method(:os) { os }
+ define_singleton_method(:platform) { platform }
+ define_singleton_method(:platform_family) { platform_family }
+ define_singleton_method(:platform_version) { platform_version }
+
+ instance_eval(&block)
+ end
+ end
+
+ def self.expect_providers(**providers)
+ providers.each do |name, provider|
+ describe name.to_s do
+ let(:resource_name) { name }
+ if provider
+ it "resolves to a #{provider}" do
+ expect(resolved_provider).to eql(provider)
+ end
+ else
+ it "Fails to resolve (since #{name.inspect} is unsupported on #{platform} #{platform_version})" do
+ expect { resolved_provider }.to raise_error /Cannot find a provider/
+ end
+ end
+ end
+ end
+ end
+
describe "resolving service resource" do
def stub_service_providers(*services)
services ||= []
@@ -301,389 +350,477 @@ describe Chef::ProviderResolver do
end
end
- describe "on Ubuntu 14.10" do
- let(:os) { "linux" }
- let(:platform) { "ubuntu" }
- let(:platform_family) { "debian" }
- let(:platform_version) { "14.04" }
-
+ on_platform "ubuntu", platform_version: "14.10", platform_family: "debian", os: "linux" do
it_behaves_like "an ubuntu platform with upstart, update-rc.d and systemd"
end
- describe "on Ubuntu 14.04" do
- let(:os) { "linux" }
- let(:platform) { "ubuntu" }
- let(:platform_family) { "debian" }
- let(:platform_version) { "14.04" }
-
+ on_platform "ubuntu", platform_version: "14.04", platform_family: "debian", os: "linux" do
it_behaves_like "an ubuntu platform with upstart and update-rc.d"
end
- describe "on Ubuntu 10.04" do
- let(:os) { "linux" }
- let(:platform) { "ubuntu" }
- let(:platform_family) { "debian" }
- let(:platform_version) { "10.04" }
-
+ on_platform "ubuntu", platform_version: "10.04", platform_family: "debian", os: "linux" do
it_behaves_like "an ubuntu platform with upstart and update-rc.d"
end
# old debian uses the Debian provider (does not have insserv or upstart, or update-rc.d???)
- describe "on Debian 4.0" do
- let(:os) { "linux" }
- let(:platform) { "debian" }
- let(:platform_family) { "debian" }
- let(:platform_version) { "4.0" }
-
+ on_platform "debian", platform_version: "4.0", os: "linux" do
#it_behaves_like "a debian platform using the debian provider"
end
# Debian replaced the debian provider with insserv in the FIXME:VERSION distro
- describe "on Debian 7.0" do
- let(:os) { "linux" }
- let(:platform) { "debian" }
- let(:platform_family) { "debian" }
- let(:platform_version) { "7.0" }
-
+ on_platform "debian", platform_version: "7.0", os: "linux" do
it_behaves_like "a debian platform using the insserv provider"
end
- %w{solaris2 openindiana opensolaris nexentacore omnios smartos}.each do |platform|
- describe "on #{platform}" do
- let(:os) { "solaris2" }
- let(:platform) { platform }
- let(:platform_family) { platform }
- let(:platform_version) { "5.11" }
-
- it "returns a Solaris provider" do
- stub_service_providers
- stub_service_configs
- expect(resolved_provider).to eql(Chef::Provider::Service::Solaris)
- end
+ on_platform %w{solaris2 openindiana opensolaris nexentacore omnios smartos}, os: "solaris2", platform_version: "5.11" do
+ it "returns a Solaris provider" do
+ stub_service_providers
+ stub_service_configs
+ expect(resolved_provider).to eql(Chef::Provider::Service::Solaris)
+ end
- it "always returns a Solaris provider" do
- # no matter what we stub on the next two lines we should get a Solaris provider
- stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
- stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd)
- expect(resolved_provider).to eql(Chef::Provider::Service::Solaris)
- end
+ it "always returns a Solaris provider" do
+ # no matter what we stub on the next two lines we should get a Solaris provider
+ stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
+ stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Solaris)
end
end
- %w{mswin mingw32 windows}.each do |platform|
- describe "on #{platform}" do
- let(:os) { "windows" }
- let(:platform) { platform }
- let(:platform_family) { "windows" }
- let(:platform_version) { "5.11" }
-
- it "returns a Windows provider" do
- stub_service_providers
- stub_service_configs
- expect(resolved_provider).to eql(Chef::Provider::Service::Windows)
- end
+ on_platform %w{mswin mingw32 windows}, platform_family: "windows", platform_version: "5.11" do
+ it "returns a Windows provider" do
+ stub_service_providers
+ stub_service_configs
+ expect(resolved_provider).to eql(Chef::Provider::Service::Windows)
+ end
- it "always returns a Windows provider" do
- # no matter what we stub on the next two lines we should get a Windows provider
- stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
- stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd)
- expect(resolved_provider).to eql(Chef::Provider::Service::Windows)
- end
+ it "always returns a Windows provider" do
+ # no matter what we stub on the next two lines we should get a Windows provider
+ stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
+ stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Windows)
end
end
- %w{mac_os_x mac_os_x_server}.each do |platform|
- describe "on #{platform}" do
- let(:os) { "darwin" }
- let(:platform) { platform }
- let(:platform_family) { "mac_os_x" }
- let(:platform_version) { "10.9.2" }
-
- it "returns a Macosx provider" do
- stub_service_providers
- stub_service_configs
- expect(resolved_provider).to eql(Chef::Provider::Service::Macosx)
- end
+ on_platform %w{mac_os_x mac_os_x_server}, os: "darwin", platform_family: "mac_os_x", platform_version: "10.9.2" do
+ it "returns a Macosx provider" do
+ stub_service_providers
+ stub_service_configs
+ expect(resolved_provider).to eql(Chef::Provider::Service::Macosx)
+ end
- it "always returns a Macosx provider" do
- # no matter what we stub on the next two lines we should get a Macosx provider
- stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
- stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd)
- expect(resolved_provider).to eql(Chef::Provider::Service::Macosx)
- end
+ it "always returns a Macosx provider" do
+ # no matter what we stub on the next two lines we should get a Macosx provider
+ stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
+ stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Macosx)
end
end
- %w{freebsd netbsd}.each do |platform|
- describe "on #{platform}" do
- let(:os) { platform }
- let(:platform) { platform }
- let(:platform_family) { platform }
- let(:platform_version) { "10.0-RELEASE" }
-
- it "returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do
- stub_service_providers
- stub_service_configs(:usr_local_etc_rcd)
- expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
- end
+ on_platform %w(freebsd netbsd), platform_version: '3.1.4' do
+ it "returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do
+ stub_service_providers
+ stub_service_configs(:usr_local_etc_rcd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
+ end
- it "returns a Freebsd provider if it finds the /etc/rc.d initscript" do
- stub_service_providers
- stub_service_configs(:etc_rcd)
- expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
- end
+ it "returns a Freebsd provider if it finds the /etc/rc.d initscript" do
+ stub_service_providers
+ stub_service_configs(:etc_rcd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
+ end
- it "always returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do
- # should only care about :usr_local_etc_rcd stub in the service configs
- stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
- stub_service_configs(:usr_local_etc_rcd, :initd, :upstart, :xinetd, :systemd)
- expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
- end
+ it "always returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do
+ # should only care about :usr_local_etc_rcd stub in the service configs
+ stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
+ stub_service_configs(:usr_local_etc_rcd, :initd, :upstart, :xinetd, :systemd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
+ end
- it "always returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do
- # should only care about :etc_rcd stub in the service configs
- stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
- stub_service_configs(:etc_rcd, :initd, :upstart, :xinetd, :systemd)
- expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
- end
+ it "always returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do
+ # should only care about :etc_rcd stub in the service configs
+ stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
+ stub_service_configs(:etc_rcd, :initd, :upstart, :xinetd, :systemd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
+ end
- it "foo" do
- stub_service_providers
- stub_service_configs
- expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
- end
+ it "foo" do
+ stub_service_providers
+ stub_service_configs
+ expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
end
end
end
- describe "for the package provider" do
- let(:resource_name) { :package }
-
- before do
- expect(provider_resolver).not_to receive(:maybe_chef_platform_lookup)
- end
-
- %w{mac_os_x mac_os_x_server}.each do |platform|
- describe "on #{platform}" do
- let(:os) { "darwin" }
- let(:platform) { platform }
- let(:platform_family) { "mac_os_x" }
- let(:platform_version) { "10.9.2" }
-
-
- it "returns a Chef::Provider::Package::Homebrew provider" do
- expect(resolved_provider).to eql(Chef::Provider::Package::Homebrew)
- end
- end
- end
- end
+ PROVIDERS =
+ {
+ bash: Chef::Provider::Script,
+ breakpoint: Chef::Provider::Breakpoint,
+ chef_gem: Chef::Provider::Package::Rubygems,
+ cookbook_file: Chef::Provider::CookbookFile,
+ csh: Chef::Provider::Script,
+ deploy: Chef::Provider::Deploy::Timestamped,
+ deploy_revision: Chef::Provider::Deploy::Revision,
+ directory: Chef::Provider::Directory,
+ easy_install_package: Chef::Provider::Package::EasyInstall,
+ erl_call: Chef::Provider::ErlCall,
+ execute: Chef::Provider::Execute,
+ file: Chef::Provider::File,
+ gem_package: Chef::Provider::Package::Rubygems,
+ git: Chef::Provider::Git,
+ group: Chef::Provider::Group::Gpasswd,
+ homebrew_package: Chef::Provider::Package::Homebrew,
+ http_request: Chef::Provider::HttpRequest,
+ ifconfig: Chef::Provider::Ifconfig,
+ link: Chef::Provider::Link,
+ log: Chef::Provider::Log::ChefLog,
+ macports_package: Chef::Provider::Package::Macports,
+ mdadm: Chef::Provider::Mdadm,
+ mount: Chef::Provider::Mount::Mount,
+ perl: Chef::Provider::Script,
+ portage_package: Chef::Provider::Package::Portage,
+ python: Chef::Provider::Script,
+ remote_directory: Chef::Provider::RemoteDirectory,
+ route: Chef::Provider::Route,
+ rpm_package: Chef::Provider::Package::Rpm,
+ ruby: Chef::Provider::Script,
+ ruby_block: Chef::Provider::RubyBlock,
+ script: Chef::Provider::Script,
+ subversion: Chef::Provider::Subversion,
+ template: Chef::Provider::Template,
+ timestamped_deploy: Chef::Provider::Deploy::Timestamped,
+ user: Chef::Provider::User::Useradd,
+ whyrun_safe_ruby_block: Chef::Provider::WhyrunSafeRubyBlock,
+
+ # We want to check that these are unsupported:
+ apt_package: nil,
+ bff_package: nil,
+ dsc_script: nil,
+ dpkg_package: nil,
+ ips_package: nil,
+ pacman_package: nil,
+ paludis_package: nil,
+ rpm_package: nil,
+ smartos_package: nil,
+ solaris_package: nil,
+ yum_package: nil,
+ windows_package: nil,
+ windows_service: nil,
+
+ "linux" => {
+ apt_package: Chef::Provider::Package::Apt,
+ dpkg_package: Chef::Provider::Package::Dpkg,
+ pacman_package: Chef::Provider::Package::Pacman,
+ paludis_package: Chef::Provider::Package::Paludis,
+ rpm_package: Chef::Provider::Package::Rpm,
+ yum_package: Chef::Provider::Package::Yum,
+
+ "debian" => {
+ ifconfig: Chef::Provider::Ifconfig::Debian,
+ package: Chef::Provider::Package::Apt,
+# service: Chef::Provider::Service::Debian,
+
+ "debian" => {
+ "7.0" => {
+ },
+ "6.0" => {
+ ifconfig: Chef::Provider::Ifconfig,
+# service: Chef::Provider::Service::Insserv,
+ },
+ "5.0" => {
+ ifconfig: Chef::Provider::Ifconfig,
+ },
+ },
+ "gcel" => {
+ "3.1.4" => {
+ ifconfig: Chef::Provider::Ifconfig,
+ },
+ },
+ "linaro" => {
+ "3.1.4" => {
+ ifconfig: Chef::Provider::Ifconfig,
+ },
+ },
+ "linuxmint" => {
+ "3.1.4" => {
+ ifconfig: Chef::Provider::Ifconfig,
+# service: Chef::Provider::Service::Upstart,
+ },
+ },
+ "raspbian" => {
+ "3.1.4" => {
+ ifconfig: Chef::Provider::Ifconfig,
+ },
+ },
+ "ubuntu" => {
+ "11.10" => {
+ },
+ "10.04" => {
+ ifconfig: Chef::Provider::Ifconfig,
+ },
+ },
+ },
+
+ "arch" => {
+ package: Chef::Provider::Package::Pacman,
+
+ "arch" => {
+ "3.1.4" => {
+ }
+ },
+ },
+
+ "freebsd" => {
+ group: Chef::Provider::Group::Pw,
+ user: Chef::Provider::User::Pw,
+
+ "freebsd" => {
+ "3.1.4" => {
+ },
+ },
+ },
+ "suse" => {
+ group: Chef::Provider::Group::Gpasswd,
+ "suse" => {
+ "12.0" => {
+ },
+ %w(11.1 11.2 11.3) => {
+ group: Chef::Provider::Group::Suse,
+ },
+ },
+ "opensuse" => {
+# service: Chef::Provider::Service::Redhat,
+ package: Chef::Provider::Package::Zypper,
+ group: Chef::Provider::Group::Usermod,
+ "12.3" => {
+ },
+ "12.2" => {
+ group: Chef::Provider::Group::Suse,
+ },
+ },
+ },
+
+ "gentoo" => {
+ package: Chef::Provider::Package::Portage,
+ portage_package: Chef::Provider::Package::Portage,
+# service: Chef::Provider::Service::Gentoo,
+
+ "gentoo" => {
+ "3.1.4" => {
+ },
+ },
+ },
+
+ "rhel" => {
+# service: Chef::Provider::Service::Systemd,
+ package: Chef::Provider::Package::Yum,
+ ifconfig: Chef::Provider::Ifconfig::Redhat,
+
+ %w(amazon xcp xenserver ibm_powerkvm cloudlinux parallels) => {
+ "3.1.4" => {
+# service: Chef::Provider::Service::Redhat,
+ },
+ },
+ %w(redhat centos scientific oracle) => {
+ "7.0" => {
+ },
+ "6.0" => {
+# service: Chef::Provider::Service::Redhat,
+ },
+ },
+ "fedora" => {
+ "15.0" => {
+ },
+ "14.0" => {
+# service: Chef::Provider::Service::Redhat,
+ },
+ },
+ },
- provider_mapping = {
- "mac_os_x" => {
- :package => Chef::Provider::Package::Homebrew,
- :user => Chef::Provider::User::Dscl,
- :group => Chef::Provider::Group::Dscl,
},
- "mac_os_x_server" => {
- :package => Chef::Provider::Package::Homebrew,
- :user => Chef::Provider::User::Dscl,
- :group => Chef::Provider::Group::Dscl,
- },
- "mswin" => {
- :env => Chef::Provider::Env::Windows,
- :user => Chef::Provider::User::Windows,
- :group => Chef::Provider::Group::Windows,
- :mount => Chef::Provider::Mount::Windows,
- :batch => Chef::Provider::Batch,
- :powershell_script => Chef::Provider::PowershellScript,
- },
- "mingw32" => {
- :env => Chef::Provider::Env::Windows,
- :user => Chef::Provider::User::Windows,
- :group => Chef::Provider::Group::Windows,
- :mount => Chef::Provider::Mount::Windows,
- :batch => Chef::Provider::Batch,
- :powershell_script => Chef::Provider::PowershellScript,
+
+ "darwin" => {
+ %w(mac_os_x mac_os_x_server) => {
+ group: Chef::Provider::Group::Dscl,
+ package: Chef::Provider::Package::Homebrew,
+ user: Chef::Provider::User::Dscl,
+
+ "mac_os_x" => {
+ "10.9.2" => {
+ },
+ },
+ },
},
+
"windows" => {
- :env => Chef::Provider::Env::Windows,
- :user => Chef::Provider::User::Windows,
- :group => Chef::Provider::Group::Windows,
- :mount => Chef::Provider::Mount::Windows,
- :batch => Chef::Provider::Batch,
- :powershell_script => Chef::Provider::PowershellScript,
+ batch: Chef::Provider::Batch,
+ dsc_script: Chef::Provider::DscScript,
+ env: Chef::Provider::Env::Windows,
+ group: Chef::Provider::Group::Windows,
+ mount: Chef::Provider::Mount::Windows,
+ package: Chef::Provider::Package::Windows,
+ powershell_script: Chef::Provider::PowershellScript,
+ service: Chef::Provider::Service::Windows,
+ user: Chef::Provider::User::Windows,
+ windows_package: Chef::Provider::Package::Windows,
+ windows_service: Chef::Provider::Service::Windows,
+
+ "windows" => {
+ %w(mswin mingw32 windows) => {
+ "10.9.2" => {
+ },
+ },
+ },
},
+
"aix" => {
- :cron => Chef::Provider::Cron::Aix,
- },
- "netbsd"=> {
- :group => Chef::Provider::Group::Groupmod,
+ bff_package: Chef::Provider::Package::Aix,
+ cron: Chef::Provider::Cron::Aix,
+ group: Chef::Provider::Group::Aix,
+ ifconfig: Chef::Provider::Ifconfig::Aix,
+ mount: Chef::Provider::Mount::Aix,
+ package: Chef::Provider::Package::Aix,
+ rpm_package: Chef::Provider::Package::Rpm,
+ user: Chef::Provider::User::Aix,
+# service: Chef::Provider::Service::Aix,
+
+ "aix" => {
+ "aix" => {
+ "5.6" => {
+ },
+ },
+ },
},
- "openbsd" => {
- :group => Chef::Provider::Group::Usermod,
- :package => Chef::Provider::Package::Openbsd,
- },
- }
-
- def self.do_platform(platform_hash)
- platform_hash.each do |resource, provider|
- describe "for #{resource}" do
- let(:resource_name) { resource }
-
- it "resolves to a #{provider}" do
- expect(resolved_provider).to eql(provider)
- end
- end
- end
- end
-
- describe "individual platform mappings" do
- let(:resource_name) { :user }
-
- before do
- expect(provider_resolver).not_to receive(:maybe_chef_platform_lookup)
- end
-
- %w{mac_os_x mac_os_x_server}.each do |platform|
- describe "on #{platform}" do
- let(:os) { "darwin" }
- let(:platform) { platform }
- let(:platform_family) { "mac_os_x" }
- let(:platform_version) { "10.9.2" }
- do_platform(provider_mapping[platform])
- end
- end
-
- %w{mswin mingw32 windows}.each do |platform|
- describe "on #{platform}" do
- let(:os) { "windows" }
- let(:platform) { platform }
- let(:platform_family) { "windows" }
- let(:platform_version) { "10.9.2" }
+ "hpux" => {
+ "hpux" => {
+ "hpux" => {
+ "3.1.4" => {
+ group: Chef::Provider::Group::Usermod
+ }
+ }
+ }
+ },
- do_platform(provider_mapping[platform])
- end
- end
+ "netbsd" => {
+ "netbsd" => {
+ "netbsd" => {
+ "3.1.4" => {
+ group: Chef::Provider::Group::Groupmod,
+ },
+ },
+ },
+ },
- describe "on AIX" do
- let(:os) { "aix" }
- let(:platform) { "aix" }
- let(:platform_family) { "aix" }
- let(:platform_version) { "6.2" }
+ "openbsd" => {
+ group: Chef::Provider::Group::Usermod,
+ package: Chef::Provider::Package::Openbsd,
+
+ "openbsd" => {
+ "openbsd" => {
+ "3.1.4" => {
+ },
+ },
+ },
+ },
- do_platform(provider_mapping['aix'])
- end
+ "solaris2" => {
+ group: Chef::Provider::Group::Usermod,
+ ips_package: Chef::Provider::Package::Ips,
+ package: Chef::Provider::Package::Ips,
+ mount: Chef::Provider::Mount::Solaris,
+ solaris_package: Chef::Provider::Package::Solaris,
+
+ "smartos" => {
+ smartos_package: Chef::Provider::Package::SmartOS,
+ package: Chef::Provider::Package::SmartOS,
+
+ "smartos" => {
+ "3.1.4" => {
+ },
+ },
+ },
+
+ "solaris2" => {
+ "nexentacore" => {
+ "3.1.4" => {
+ package: Chef::Provider::Package::Solaris,
+ },
+ },
+ "omnios" => {
+ "3.1.4" => {
+ user: Chef::Provider::User::Solaris,
+ }
+ },
+ "openindiana" => {
+ "3.1.4" => {
+ },
+ },
+ "opensolaris" => {
+ "3.1.4" => {
+ },
+ },
+ "solaris2" => {
+ user: Chef::Provider::User::Solaris,
+ "5.11" => {
+ },
+ "5.9" => {
+ package: Chef::Provider::Package::Solaris,
+ },
+ },
+ },
- %w{netbsd openbsd}.each do |platform|
- describe "on #{platform}" do
- let(:os) { platform }
- let(:platform) { platform }
- let(:platform_family) { platform }
- let(:platform_version) { "10.0-RELEASE" }
+ },
- do_platform(provider_mapping[platform])
- end
- end
- end
+ "solaris" => {
+ "solaris" => {
+ "solaris" => {
+ "3.1.4" => {
+ },
+ },
+ },
+ },
- describe "resolving static providers" do
- def resource_class(resource)
- Chef::Resource.const_get(convert_to_class_name(resource.to_s))
- end
- static_mapping = {
- apt_package: Chef::Provider::Package::Apt,
- bash: Chef::Provider::Script,
- bff_package: Chef::Provider::Package::Aix,
- breakpoint: Chef::Provider::Breakpoint,
- chef_gem: Chef::Provider::Package::Rubygems,
- cookbook_file: Chef::Provider::CookbookFile,
- csh: Chef::Provider::Script,
- deploy: Chef::Provider::Deploy::Timestamped,
- deploy_revision: Chef::Provider::Deploy::Revision,
- directory: Chef::Provider::Directory,
- dpkg_package: Chef::Provider::Package::Dpkg,
- dsc_script: Chef::Provider::DscScript,
- easy_install_package: Chef::Provider::Package::EasyInstall,
- erl_call: Chef::Provider::ErlCall,
- execute: Chef::Provider::Execute,
- file: Chef::Provider::File,
- gem_package: Chef::Provider::Package::Rubygems,
- git: Chef::Provider::Git,
- homebrew_package: Chef::Provider::Package::Homebrew,
- http_request: Chef::Provider::HttpRequest,
- ips_package: Chef::Provider::Package::Ips,
- link: Chef::Provider::Link,
- log: Chef::Provider::Log::ChefLog,
- macports_package: Chef::Provider::Package::Macports,
- mdadm: Chef::Provider::Mdadm,
- pacman_package: Chef::Provider::Package::Pacman,
- paludis_package: Chef::Provider::Package::Paludis,
- perl: Chef::Provider::Script,
- portage_package: Chef::Provider::Package::Portage,
- python: Chef::Provider::Script,
- remote_directory: Chef::Provider::RemoteDirectory,
- route: Chef::Provider::Route,
- rpm_package: Chef::Provider::Package::Rpm,
- ruby: Chef::Provider::Script,
- ruby_block: Chef::Provider::RubyBlock,
- script: Chef::Provider::Script,
- smartos_package: Chef::Provider::Package::SmartOS,
- solaris_package: Chef::Provider::Package::Solaris,
- subversion: Chef::Provider::Subversion,
- template: Chef::Provider::Template,
- timestamped_deploy: Chef::Provider::Deploy::Timestamped,
- whyrun_safe_ruby_block: Chef::Provider::WhyrunSafeRubyBlock,
- windows_package: Chef::Provider::Package::Windows,
- windows_service: Chef::Provider::Service::Windows,
- yum_package: Chef::Provider::Package::Yum,
+ "exherbo" => {
+ "exherbo" => {
+ "exherbo" => {
+ "3.1.4" => {
+ package: Chef::Provider::Package::Paludis
+ }
+ }
}
+ }
+ }
- describe "on Ubuntu 14.04" do
- let(:os) { "linux" }
- let(:platform) { "ubuntu" }
- let(:platform_family) { "debian" }
- let(:platform_version) { "14.04" }
-
- supported_providers = [
- :apt_package, :bash, :breakpoint, :chef_gem, :cookbook_file, :csh, :deploy,
- :deploy_revision, :directory, :dpkg_package, :easy_install_package, :erl_call,
- :execute, :file, :gem_package, :git, :homebrew_package, :http_request, :link,
- :log, :macports_package, :pacman_package, :paludis_package, :perl, :python,
- :remote_directory, :route, :rpm_package, :ruby, :ruby_block, :script, :subversion,
- :template, :timestamped_deploy, :whyrun_safe_ruby_block, :yum_package,
- ]
-
- supported_providers.each do |static_resource|
- static_provider = static_mapping[static_resource]
- context "when the resource is a #{static_resource}" do
- let(:resource) { double(Chef::Resource, provider: nil, resource_name: static_resource) }
- let(:action) { :start } # in reality this doesn't matter much
- it "should resolve to a #{static_provider} provider" do
- expect(provider_resolver).not_to receive(:maybe_chef_platform_lookup)
- expect(resolved_provider).to eql(static_provider)
+ def self.create_provider_tests(providers, test, expected, filter)
+ expected = expected.merge(providers.select { |key, value| key.is_a?(Symbol) })
+ providers.each do |key, value|
+ if !key.is_a?(Symbol)
+ next_test = test.merge({ filter => key })
+ next_filter =
+ case filter
+ when :os
+ :platform_family
+ when :platform_family
+ :platform
+ when :platform
+ :platform_version
+ when :platform_version
+ nil
+ else
+ raise "Hash too deep; only os, platform_family, platform and platform_version supported"
end
- end
+ create_provider_tests(value, next_test, expected, next_filter)
end
-
- unsupported_providers = [
- :bff_package, :dsc_script, :ips_package, :smartos_package,
- :solaris_package, :windows_package, :windows_service,
- ]
-
- unsupported_providers.each do |static_resource|
- static_provider = static_mapping[static_resource]
- context "when the resource is a #{static_resource}" do
- let(:resource) { double(Chef::Resource, provider: nil, resource_name: static_resource) }
- let(:action) { :start } # in reality this doesn't matter much
- it "should fall back into the old provider mapper code and hooks" do
- retval = Object.new
- expect(provider_resolver).to receive(:maybe_chef_platform_lookup).and_return(retval)
- expect(resolved_provider).to equal(retval)
- end
- end
+ end
+ # If there is no filter, we're as deep as we need to go
+ if !filter
+ on_platform test.delete(:platform), test do
+ expect_providers(expected)
end
end
end
+
+ create_provider_tests(PROVIDERS, {}, {}, :os)
end
diff --git a/spec/unit/recipe_spec.rb b/spec/unit/recipe_spec.rb
index 9c4fb49497..618c742998 100644
--- a/spec/unit/recipe_spec.rb
+++ b/spec/unit/recipe_spec.rb
@@ -121,7 +121,8 @@ describe Chef::Recipe do
it "locate resource for particular platform" do
ShaunTheSheep = Class.new(Chef::Resource)
- ShaunTheSheep.provides :laughter, :on_platforms => ["television"]
+ ShaunTheSheep.use_automatic_resource_name
+ ShaunTheSheep.provides :laughter, :platform => ["television"]
node.automatic[:platform] = "television"
node.automatic[:platform_version] = "123"
res = recipe.laughter "timmy"
@@ -131,6 +132,7 @@ describe Chef::Recipe do
it "locate a resource for all platforms" do
YourMom = Class.new(Chef::Resource)
+ YourMom.use_automatic_resource_name
YourMom.provides :love_and_caring
res = recipe.love_and_caring "mommy"
expect(res.name).to eql("mommy")
@@ -141,9 +143,9 @@ describe Chef::Recipe do
before do
node.automatic[:platform] = "nbc_sports"
Sounders = Class.new(Chef::Resource)
- Sounders.provides :football, platform: "nbc_sports"
+ Sounders.use_automatic_resource_name
TottenhamHotspur = Class.new(Chef::Resource)
- TottenhamHotspur.provides :football, platform: "nbc_sports"
+ TottenhamHotspur.use_automatic_resource_name
end
after do
@@ -151,16 +153,12 @@ describe Chef::Recipe do
Object.send(:remove_const, :TottenhamHotspur)
end
- it "warns if resolution of the two resources is ambiguous" do
- expect(Chef::Log).to receive(:warn).at_least(:once).with(/Ambiguous resource precedence/)
- res1 = recipe.football "club world cup"
- expect(res1.name).to eql("club world cup")
- # the class of res1 is not defined.
- end
-
- it "selects one if it is given priority" do
+ it "selects one if it is the last declared" do
expect(Chef::Log).not_to receive(:warn)
- Chef::Platform::ResourcePriorityMap.instance.send(:priority, :football, TottenhamHotspur, platform: "nbc_sports")
+
+ Sounders.provides :football, platform: "nbc_sports"
+ TottenhamHotspur.provides :football, platform: "nbc_sports"
+
res1 = recipe.football "club world cup"
expect(res1.name).to eql("club world cup")
expect(res1).to be_a_kind_of(TottenhamHotspur)
@@ -168,7 +166,10 @@ describe Chef::Recipe do
it "selects the other one if it is given priority" do
expect(Chef::Log).not_to receive(:warn)
- Chef::Platform::ResourcePriorityMap.instance.send(:priority, :football, Sounders, platform: "nbc_sports")
+
+ TottenhamHotspur.provides :football, platform: "nbc_sports"
+ Sounders.provides :football, platform: "nbc_sports"
+
res1 = recipe.football "club world cup"
expect(res1.name).to eql("club world cup")
expect(res1).to be_a_kind_of(Sounders)
@@ -408,7 +409,7 @@ describe Chef::Recipe do
end
it "does not copy the action from the first resource" do
- expect(original_resource.action).to eq([:score])
+ expect(original_resource.action).to eq(:score)
expect(duplicated_resource.action).to eq(:nothing)
end
@@ -504,7 +505,7 @@ describe Chef::Recipe do
recipe.from_file(File.join(CHEF_SPEC_DATA, "recipes", "test.rb"))
res = recipe.resources(:file => "/etc/nsswitch.conf")
expect(res.name).to eql("/etc/nsswitch.conf")
- expect(res.action).to eql([:create])
+ expect(res.action).to eql(:create)
expect(res.owner).to eql("root")
expect(res.group).to eql("root")
expect(res.mode).to eql(0644)
diff --git a/spec/unit/resource/breakpoint_spec.rb b/spec/unit/resource/breakpoint_spec.rb
index ed1f3ebcd5..9c867ebcc7 100644
--- a/spec/unit/resource/breakpoint_spec.rb
+++ b/spec/unit/resource/breakpoint_spec.rb
@@ -37,7 +37,7 @@ describe Chef::Resource::Breakpoint do
end
it "defaults to the break action" do
- expect(@breakpoint.action).to eq("break")
+ expect(@breakpoint.action).to eq(:break)
end
it "names itself after the line number of the file where it's created" do
diff --git a/spec/unit/resource/erl_call_spec.rb b/spec/unit/resource/erl_call_spec.rb
index 8ec182665f..008d27372a 100644
--- a/spec/unit/resource/erl_call_spec.rb
+++ b/spec/unit/resource/erl_call_spec.rb
@@ -35,7 +35,7 @@ describe Chef::Resource::ErlCall do
end
it "should have a default action of run" do
- expect(@resource.action).to eql("run")
+ expect(@resource.action).to eql(:run)
end
it "should accept run as an action" do
diff --git a/spec/unit/resource/file_spec.rb b/spec/unit/resource/file_spec.rb
index db52e35004..dd20f5f03a 100644
--- a/spec/unit/resource/file_spec.rb
+++ b/spec/unit/resource/file_spec.rb
@@ -29,7 +29,7 @@ describe Chef::Resource::File do
end
it "should have a default action of 'create'" do
- expect(@resource.action).to eql("create")
+ expect(@resource.action).to eql(:create)
end
it "should have a default content of nil" do
diff --git a/spec/unit/resource/ifconfig_spec.rb b/spec/unit/resource/ifconfig_spec.rb
index ea5282acd5..e3e1f6daa2 100644
--- a/spec/unit/resource/ifconfig_spec.rb
+++ b/spec/unit/resource/ifconfig_spec.rb
@@ -47,21 +47,23 @@ describe Chef::Resource::Ifconfig do
end
end
- shared_examples "being a platform using the default ifconfig provider" do |platform, version|
+ shared_examples "being a platform based on an old Debian" do |platform, version|
before do
+ @node.automatic_attrs[:os] = 'linux'
+ @node.automatic_attrs[:platform_family] = 'debian'
@node.automatic_attrs[:platform] = platform
@node.automatic_attrs[:platform_version] = version
end
it "should use an ordinary Provider::Ifconfig as a provider for #{platform} #{version}" do
- expect(@resource.provider_for_action(:add)).to be_a_kind_of(Chef::Provider::Ifconfig)
- expect(@resource.provider_for_action(:add)).not_to be_a_kind_of(Chef::Provider::Ifconfig::Debian)
- expect(@resource.provider_for_action(:add)).not_to be_a_kind_of(Chef::Provider::Ifconfig::Redhat)
+ expect(@resource.provider_for_action(:add).class).to eq(Chef::Provider::Ifconfig)
end
end
shared_examples "being a platform based on RedHat" do |platform, version|
before do
+ @node.automatic_attrs[:os] = 'linux'
+ @node.automatic_attrs[:platform_family] = 'rhel'
@node.automatic_attrs[:platform] = platform
@node.automatic_attrs[:platform_version] = version
end
@@ -73,6 +75,8 @@ describe Chef::Resource::Ifconfig do
shared_examples "being a platform based on a recent Debian" do |platform, version|
before do
+ @node.automatic_attrs[:os] = 'linux'
+ @node.automatic_attrs[:platform_family] = 'debian'
@node.automatic_attrs[:platform] = platform
@node.automatic_attrs[:platform_version] = version
end
@@ -87,7 +91,7 @@ describe Chef::Resource::Ifconfig do
end
describe "when it is an old Debian platform" do
- it_should_behave_like "being a platform using the default ifconfig provider", "debian", "6.0"
+ it_should_behave_like "being a platform based on an old Debian", "debian", "6.0"
end
describe "when it is a new Debian platform" do
@@ -95,7 +99,7 @@ describe Chef::Resource::Ifconfig do
end
describe "when it is an old Ubuntu platform" do
- it_should_behave_like "being a platform using the default ifconfig provider", "ubuntu", "11.04"
+ it_should_behave_like "being a platform based on an old Debian", "ubuntu", "11.04"
end
describe "when it is a new Ubuntu platform" do
diff --git a/spec/unit/resource/route_spec.rb b/spec/unit/resource/route_spec.rb
index ec1d369932..ffb9304511 100644
--- a/spec/unit/resource/route_spec.rb
+++ b/spec/unit/resource/route_spec.rb
@@ -35,7 +35,7 @@ describe Chef::Resource::Route do
end
it "should have a default action of 'add'" do
- expect(@resource.action).to eql([:add])
+ expect(@resource.action).to eql(:add)
end
it "should accept add or delete for action" do
diff --git a/spec/unit/resource/ruby_block_spec.rb b/spec/unit/resource/ruby_block_spec.rb
index 9f19fecd4f..5d83f7e367 100644
--- a/spec/unit/resource/ruby_block_spec.rb
+++ b/spec/unit/resource/ruby_block_spec.rb
@@ -31,7 +31,7 @@ describe Chef::Resource::RubyBlock do
end
it "should have a default action of 'create'" do
- expect(@resource.action).to eql("run")
+ expect(@resource.action).to eql(:run)
end
it "should have a resource name of :ruby_block" do
@@ -46,7 +46,7 @@ describe Chef::Resource::RubyBlock do
it "allows the action to be 'create'" do
@resource.action :create
- expect(@resource.action).to eq([:create])
+ expect(@resource.action).to eq(:create)
end
describe "when it has been initialized with block code" do
diff --git a/spec/unit/resource/timestamped_deploy_spec.rb b/spec/unit/resource/timestamped_deploy_spec.rb
index eca6c570d4..4ebfdaf059 100644
--- a/spec/unit/resource/timestamped_deploy_spec.rb
+++ b/spec/unit/resource/timestamped_deploy_spec.rb
@@ -23,11 +23,10 @@ describe Chef::Resource::TimestampedDeploy, "initialize" do
static_provider_resolution(
resource: Chef::Resource::TimestampedDeploy,
provider: Chef::Provider::Deploy::Timestamped,
- name: :deploy,
+ name: :timestamped_deploy,
action: :deploy,
os: 'linux',
platform_family: 'rhel',
)
end
-
diff --git a/spec/unit/resource/windows_service_spec.rb b/spec/unit/resource/windows_service_spec.rb
index 45a295c24e..8866cad1bf 100644
--- a/spec/unit/resource/windows_service_spec.rb
+++ b/spec/unit/resource/windows_service_spec.rb
@@ -44,6 +44,6 @@ describe Chef::Resource::WindowsService, "initialize" do
it "allows the action to be 'configure_startup'" do
resource.action :configure_startup
- expect(resource.action).to eq([:configure_startup])
+ expect(resource.action).to eq(:configure_startup)
end
end
diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb
index 3bfd63f5ab..1d20fcf604 100644
--- a/spec/unit/resource_spec.rb
+++ b/spec/unit/resource_spec.rb
@@ -21,10 +21,6 @@
require 'spec_helper'
-class ResourceTestHarness < Chef::Resource
- provider_base Chef::Provider::Package
-end
-
describe Chef::Resource do
before(:each) do
@cookbook_repo_path = File.join(CHEF_SPEC_DATA, 'cookbooks')
@@ -336,6 +332,85 @@ describe Chef::Resource do
end
end
+ describe "self.resource_name" do
+ context "When resource_name is not set" do
+ it "and there are no provides lines, resource_name is nil" do
+ c = Class.new(Chef::Resource) do
+ end
+
+ r = c.new('hi')
+ r.declared_type = :d
+ expect(c.resource_name).to be_nil
+ expect(r.resource_name).to be_nil
+ expect(r.declared_type).to eq :d
+ end
+ it "and there are no provides lines, @resource_name is used" do
+ c = Class.new(Chef::Resource) do
+ def initialize(*args, &block)
+ @resource_name = :blah
+ super
+ end
+ end
+
+ r = c.new('hi')
+ r.declared_type = :d
+ expect(c.resource_name).to be_nil
+ expect(r.resource_name).to eq :blah
+ expect(r.declared_type).to eq :d
+ end
+ end
+
+ it "resource_name without provides is honored" do
+ c = Class.new(Chef::Resource) do
+ resource_name 'blah'
+ end
+
+ r = c.new('hi')
+ r.declared_type = :d
+ expect(c.resource_name).to eq :blah
+ expect(r.resource_name).to eq :blah
+ expect(r.declared_type).to eq :d
+ end
+ it "setting class.resource_name with 'resource_name = blah' overrides declared_type" do
+ c = Class.new(Chef::Resource) do
+ provides :self_resource_name_test_2
+ end
+ c.resource_name = :blah
+
+ r = c.new('hi')
+ r.declared_type = :d
+ expect(c.resource_name).to eq :blah
+ expect(r.resource_name).to eq :blah
+ expect(r.declared_type).to eq :d
+ end
+ it "setting class.resource_name with 'resource_name blah' overrides declared_type" do
+ c = Class.new(Chef::Resource) do
+ resource_name :blah
+ provides :self_resource_name_test_3
+ end
+
+ r = c.new('hi')
+ r.declared_type = :d
+ expect(c.resource_name).to eq :blah
+ expect(r.resource_name).to eq :blah
+ expect(r.declared_type).to eq :d
+ end
+ it "use_automatic_resource_name yields a resource name from the class name" do
+ class SelfResourceNameTestBlahDBlah4 < Chef::Resource
+ use_automatic_resource_name
+ end
+
+ c = SelfResourceNameTestBlahDBlah4
+
+ r = c.new('hi')
+ r.declared_type = :d
+ expect(c.resource_name).to eq :self_resource_name_test_blah_d_blah4
+ expect(r.resource_name).to eq :self_resource_name_test_blah_d_blah4
+ expect(r.declared_type).to eq :d
+
+ end
+ end
+
describe "is" do
it "should return the arguments passed with 'is'" do
zm = Chef::Resource::ZenMaster.new("coffee")
@@ -459,8 +534,21 @@ describe Chef::Resource do
expect(Chef::Resource.provider_base).to eq(Chef::Provider)
end
- it "allows the base provider to be overriden by a " do
- expect(ResourceTestHarness.provider_base).to eq(Chef::Provider::Package)
+ it "allows the base provider to be overridden" do
+ Chef::Config.treat_deprecation_warnings_as_errors(false)
+ class OverrideProviderBaseTest < Chef::Resource
+ provider_base Chef::Provider::Package
+ end
+
+ expect(OverrideProviderBaseTest.provider_base).to eq(Chef::Provider::Package)
+ end
+
+ it "warns when setting provider_base" do
+ expect {
+ class OverrideProviderBaseTest2 < Chef::Resource
+ provider_base Chef::Provider::Package
+ end
+ }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
end
end
@@ -721,22 +809,22 @@ describe Chef::Resource do
end
it 'adds mappings for a single platform' do
- expect(Chef::Resource::Klz.node_map).to receive(:set).with(
- :dinobot, true, { platform: ['autobots'] }
+ expect(Chef).to receive(:set_resource_priority_array).with(
+ :dinobot, Chef::Resource::Klz, { platform: ['autobots'] }
)
klz.provides :dinobot, platform: ['autobots']
end
it 'adds mappings for multiple platforms' do
- expect(Chef::Resource::Klz.node_map).to receive(:set).with(
- :energy, true, { platform: ['autobots', 'decepticons']}
+ expect(Chef).to receive(:set_resource_priority_array).with(
+ :energy, Chef::Resource::Klz, { platform: ['autobots', 'decepticons']}
)
klz.provides :energy, platform: ['autobots', 'decepticons']
end
it 'adds mappings for all platforms' do
- expect(Chef::Resource::Klz.node_map).to receive(:set).with(
- :tape_deck, true, {}
+ expect(Chef).to receive(:set_resource_priority_array).with(
+ :tape_deck, Chef::Resource::Klz, {}
)
klz.provides :tape_deck
end
@@ -776,7 +864,7 @@ describe Chef::Resource do
@node.name("bumblebee")
@node.automatic[:platform] = "autobots"
@node.automatic[:platform_version] = "6.1"
- klz2.provides :dinobot, :on_platforms => ['autobots']
+ klz2.provides :dinobot, :platform => ['autobots']
Object.const_set('Grimlock', klz2)
klz2.provides :grimlock
end