summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaire McQuin <claire@getchef.com>2014-09-23 13:28:54 -0700
committerClaire McQuin <claire@getchef.com>2014-09-23 13:28:54 -0700
commitb3ef58b5569c289df86feb1007b27be88608400a (patch)
tree07e37ac08f3b73fc5ca8e92075934023101f145e
parent8fb2ef7c795ec3df5c9ab5c91413e32edf758dba (diff)
parented907ef4d64027212ceb0c082895b303844ff43f (diff)
downloadchef-b3ef58b5569c289df86feb1007b27be88608400a.tar.gz
Merge branch 'master' into mcquin/Issue-1944
Conflicts: DOC_CHANGES.md
-rw-r--r--CHANGELOG.md9
-rw-r--r--CHEF_MVPS.md1
-rw-r--r--DOC_CHANGES.md27
-rw-r--r--RELEASE_NOTES.md28
-rw-r--r--chef.gemspec4
-rw-r--r--lib/chef/application.rb6
-rw-r--r--lib/chef/application/apply.rb4
-rw-r--r--lib/chef/chef_fs/chef_fs_data_store.rb54
-rw-r--r--lib/chef/chef_fs/config.rb67
-rw-r--r--lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb18
-rw-r--r--lib/chef/chef_fs/file_system/chef_server_root_dir.rb31
-rw-r--r--lib/chef/client.rb9
-rw-r--r--lib/chef/config.rb54
-rw-r--r--lib/chef/dsl/reboot_pending.rb9
-rw-r--r--lib/chef/exceptions.rb6
-rw-r--r--lib/chef/knife/bootstrap/archlinux-gems.erb5
-rw-r--r--lib/chef/knife/bootstrap/chef-aix.erb5
-rw-r--r--lib/chef/knife/bootstrap/chef-full.erb5
-rw-r--r--lib/chef/knife/core/bootstrap_context.rb26
-rw-r--r--lib/chef/mixin/homebrew_owner.rb58
-rw-r--r--lib/chef/mixin/shell_out.rb46
-rw-r--r--lib/chef/mixin/windows_architecture_helper.rb16
-rw-r--r--lib/chef/platform/provider_mapping.rb4
-rw-r--r--lib/chef/platform/query_helpers.rb6
-rw-r--r--lib/chef/platform/rebooter.rb54
-rw-r--r--lib/chef/provider/dsc_script.rb148
-rw-r--r--lib/chef/provider/ifconfig.rb31
-rw-r--r--lib/chef/provider/link.rb2
-rw-r--r--lib/chef/provider/package/aix.rb16
-rw-r--r--lib/chef/provider/package/homebrew.rb121
-rw-r--r--lib/chef/provider/package/ips.rb20
-rw-r--r--lib/chef/provider/package/macports.rb16
-rw-r--r--lib/chef/provider/package/pacman.rb8
-rw-r--r--lib/chef/provider/package/portage.rb8
-rw-r--r--lib/chef/provider/package/rpm.rb16
-rw-r--r--lib/chef/provider/package/solaris.rb16
-rw-r--r--lib/chef/provider/reboot.rb69
-rw-r--r--lib/chef/provider/service/debian.rb20
-rw-r--r--lib/chef/provider/service/freebsd.rb6
-rw-r--r--lib/chef/provider/service/gentoo.rb4
-rw-r--r--lib/chef/provider/service/init.rb8
-rw-r--r--lib/chef/provider/service/insserv.rb6
-rw-r--r--lib/chef/provider/service/macosx.rb4
-rw-r--r--lib/chef/provider/service/simple.rb8
-rw-r--r--lib/chef/provider/service/solaris.rb2
-rw-r--r--lib/chef/provider/service/systemd.rb18
-rw-r--r--lib/chef/provider/service/upstart.rb12
-rw-r--r--lib/chef/provider/subversion.rb12
-rw-r--r--lib/chef/provider/whyrun_safe_ruby_block.rb2
-rw-r--r--lib/chef/providers.rb3
-rw-r--r--lib/chef/resource/dsc_script.rb140
-rw-r--r--lib/chef/resource/homebrew_package.rb34
-rw-r--r--lib/chef/resource/reboot.rb48
-rw-r--r--lib/chef/resources.rb3
-rw-r--r--lib/chef/run_context.rb25
-rw-r--r--lib/chef/util/dsc/configuration_generator.rb115
-rw-r--r--lib/chef/util/dsc/lcm_output_parser.rb133
-rw-r--r--lib/chef/util/dsc/local_configuration_manager.rb137
-rw-r--r--lib/chef/util/dsc/resource_info.rb26
-rw-r--r--lib/chef/util/powershell/cmdlet.rb136
-rw-r--r--lib/chef/util/powershell/cmdlet_result.rb46
-rw-r--r--lib/chef/version.rb2
-rw-r--r--lib/chef/win32/api/file.rb6
-rw-r--r--pedant.gemfile3
-rw-r--r--spec/functional/mixin/shell_out_spec.rb4
-rw-r--r--spec/functional/provider/whyrun_safe_ruby_block_spec.rb51
-rw-r--r--spec/functional/rebooter_spec.rb105
-rw-r--r--spec/functional/resource/deploy_revision_spec.rb4
-rw-r--r--spec/functional/resource/dsc_script_spec.rb337
-rw-r--r--spec/functional/resource/file_spec.rb29
-rw-r--r--spec/functional/resource/link_spec.rb32
-rw-r--r--spec/functional/resource/reboot_spec.rb103
-rw-r--r--spec/functional/util/powershell/cmdlet_spec.rb114
-rw-r--r--spec/integration/client/client_spec.rb2
-rw-r--r--spec/integration/client/ipv6_spec.rb2
-rw-r--r--spec/integration/knife/cookbook_api_ipv6_spec.rb2
-rw-r--r--spec/integration/recipes/lwrp_inline_resources_spec.rb2
-rw-r--r--spec/spec_helper.rb3
-rw-r--r--spec/support/platform_helpers.rb24
-rw-r--r--spec/support/shared/functional/file_resource.rb6
-rw-r--r--spec/support/shared/integration/integration_helper.rb5
-rw-r--r--spec/unit/application/apply.rb12
-rw-r--r--spec/unit/config_spec.rb4
-rw-r--r--spec/unit/dsl/reboot_pending_spec.rb8
-rw-r--r--spec/unit/knife/bootstrap_spec.rb38
-rw-r--r--spec/unit/knife/core/bootstrap_context_spec.rb15
-rw-r--r--spec/unit/mixin/homebrew_owner_spec.rb65
-rw-r--r--spec/unit/mixin/shell_out_spec.rb198
-rw-r--r--spec/unit/platform/query_helpers_spec.rb23
-rw-r--r--spec/unit/provider/dsc_script_spec.rb145
-rw-r--r--spec/unit/provider/ifconfig/debian_spec.rb44
-rw-r--r--spec/unit/provider/ifconfig/redhat_spec.rb30
-rw-r--r--spec/unit/provider/ifconfig_spec.rb6
-rw-r--r--spec/unit/provider/link_spec.rb10
-rw-r--r--spec/unit/provider/package/aix_spec.rb22
-rw-r--r--spec/unit/provider/package/homebrew_spec.rb251
-rw-r--r--spec/unit/provider/package/ips_spec.rb29
-rw-r--r--spec/unit/provider/package/macports_spec.rb24
-rw-r--r--spec/unit/provider/package/pacman_spec.rb16
-rw-r--r--spec/unit/provider/package/portage_spec.rb20
-rw-r--r--spec/unit/provider/package/rpm_spec.rb29
-rw-r--r--spec/unit/provider/package/solaris_spec.rb21
-rw-r--r--spec/unit/provider/service/arch_service_spec.rb22
-rw-r--r--spec/unit/provider/service/debian_service_spec.rb2
-rw-r--r--spec/unit/provider/service/freebsd_service_spec.rb12
-rw-r--r--spec/unit/provider/service/gentoo_service_spec.rb4
-rw-r--r--spec/unit/provider/service/init_service_spec.rb20
-rw-r--r--spec/unit/provider/service/insserv_service_spec.rb7
-rw-r--r--spec/unit/provider/service/invokercd_service_spec.rb17
-rw-r--r--spec/unit/provider/service/macosx_spec.rb10
-rw-r--r--spec/unit/provider/service/simple_service_spec.rb8
-rw-r--r--spec/unit/provider/service/solaris_smf_service_spec.rb4
-rw-r--r--spec/unit/provider/service/systemd_service_spec.rb40
-rw-r--r--spec/unit/provider/service/upstart_service_spec.rb32
-rw-r--r--spec/unit/provider/subversion_spec.rb11
-rw-r--r--spec/unit/provider/whyrun_safe_ruby_block_spec.rb4
-rw-r--r--spec/unit/resource/dsc_script_spec.rb127
-rw-r--r--spec/unit/resource/homebrew_package_spec.rb36
-rw-r--r--spec/unit/run_context_spec.rb15
-rw-r--r--spec/unit/util/dsc/configuration_generator_spec.rb171
-rw-r--r--spec/unit/util/dsc/lcm_output_parser_spec.rb169
-rw-r--r--spec/unit/util/dsc/local_configuration_manager_spec.rb134
-rw-r--r--spec/unit/util/powershell/cmdlet_spec.rb106
-rw-r--r--spec/unit/workstation_config_loader_spec.rb12
124 files changed, 4224 insertions, 556 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 50be057943..73abae07d4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
## Unreleased: 12.0.0
+* [**Nolan Davidson**](https://github.com/nsdavidson):
+ The chef-apply command now prints usage information when called without arguments
+* [**Kazuki Saito**](https://github.com/sakazuki):
+ CHEF-4933: idempotency fixes for ifconfig provider
+* [**Kirill Shirinkin**](https://github.com/Fodoj):
+ The knife bootstrap command expands the path of the secret-file
* [**Malte Swart**](https://github.com/mswart):
[CHEF-4101] DeepMerge - support overwriting hash values with nil
* [**James Belchamber**](https://github.com/JamesBelchamber):
@@ -126,6 +132,9 @@
* Add `:node_ssl_verify_mode` & `:node_verify_api_cert` options to bootstrap
to be able to configure these settings on the bootstrapped node.
* Add partial_search dsl method to Chef::Search::Query, add result filtering to search.
+* Transfer trusted certificates under :trusted_certs_dir during bootstrap.
+* Set :ssl_verify_mode to :verify_peer by default.
+* Add homebrew provider for package resource, use it by default on OS X (Issue #1709)
## Last Release: 11.14.2
diff --git a/CHEF_MVPS.md b/CHEF_MVPS.md
index 620a516080..28dbe3c8e8 100644
--- a/CHEF_MVPS.md
+++ b/CHEF_MVPS.md
@@ -18,6 +18,7 @@ After receiving three MVP awards, we add someone to the hall of fame. We want to
| Release | Date | MVP |
|---------|------|-----|
+| [Client 11.16.0](http://www.getchef.com/blog/2014/09/08/release-chef-client-11-16-0-ohai-7-4-0/) | 2014-09-08 | Jesse Hu |
| [Client 11.14.2](http://www.getchef.com/blog/2014/08/01/release-chef-client-11-14-2/) | 2014-08-01 | Nikhil Benesch |
| [Client 11.12.0](http://www.getchef.com/blog/2014/04/08/release-chef-client-11-12-0-10-32-2/) | 2014-04-08 | Chris Bandy |
| [Client 11.10.4](http://www.getchef.com/blog/2014/02/20/chef-client-patch-release-11-10-4/) | 2014-02-20 | Jon Cowie |
diff --git a/DOC_CHANGES.md b/DOC_CHANGES.md
index c6fe7087c3..736dc4f8a5 100644
--- a/DOC_CHANGES.md
+++ b/DOC_CHANGES.md
@@ -367,3 +367,30 @@ DNS.3 = systems.example.net
IP.1 = 192.168.1.1
IP.2 = 192.168.69.14
```
+
+### Reboot resource in core
+The `reboot` resource will reboot the server, a necessary step in some installations, especially on Windows. If this resource is used with notifications, it must receive explicit `:immediate` notifications only: results of delayed notifications are undefined. Currently supported on Windows, Linux, and OS X; will work incidentally on some other Unixes.
+
+There are three actions:
+
+```ruby
+reboot "app_requires_reboot" do
+ action :request_reboot
+ reason "Need to reboot when the run completes successfully."
+ delay_mins 5
+end
+
+reboot "cancel_reboot_request" do
+ action :cancel
+ reason "Cancel a previous end-of-run reboot request."
+end
+
+reboot "now" do
+ action :reboot_now
+ reason "Cannot continue Chef run without a reboot."
+ delay_mins 2
+end
+
+# the `:immediate` is required for results to be defined.
+notifies :reboot_now, "reboot[now]", :immediate
+```
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index f5a74d6a43..12e0351623 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -66,6 +66,34 @@ In order to support configuring passwords for the users using shadow hashes two
User resource on Mac supports setting password both using plain-text password or using the shadow hash. You can simply set the `password` attribute to the plain text password to configure the password for the user. However this is not ideal since including plain text passwords in cookbooks (even if they are private) is not a good idea. In order to set passwords using shadow hash you can follow the instructions below based on your Mac OS X version.
+## Mac OS X default package provider is now Homebrew
+
+Per [Chef RFC 016](https://github.com/opscode/chef-rfc/blob/master/rfc016-homebrew-osx-package-provider.md), the default provider for the `package` resource on Mac OS X is now [Homebrew](http://brew.sh). The [homebrew cookbook's](https://supermarket.getchef.com/cookbooks/homebrew) default recipe, or some other method is still required for getting homebrew installed on the system. The cookbook won't be strictly required just to install packages from homebrew on OS X, though. To use this, simply use the `package` resource, or the `homebrew_package` shortcut resource:
+
+```ruby
+package 'emacs'
+```
+
+Or,
+
+```ruby
+homebrew_package 'emacs'
+```
+
+The macports provider will still be available, and can be used with the shortcut resource, or by using the `provider` attribute:
+
+```ruby
+macports_package 'emacs'
+```
+
+Or,
+
+```ruby
+package 'emacs' do
+ provider Chef::Provider::Package::Macports
+end
+```
+
### Mac OS X 10.7
10.7 calculates the password hash using **SALTED-SHA512**. Stored shadow hash length is 68 bytes; first 4 bytes being salt and the next 64 bytes being the shadow hash itself. You can use below code in order to calculate password hashes to be used in `password` attribute on Mac OS X 10.7:
diff --git a/chef.gemspec b/chef.gemspec
index 89b4ac2665..481b120fe6 100644
--- a/chef.gemspec
+++ b/chef.gemspec
@@ -19,8 +19,8 @@ Gem::Specification.new do |s|
s.add_dependency "mixlib-cli", "~> 1.4"
s.add_dependency "mixlib-log", "~> 1.3"
s.add_dependency "mixlib-authentication", "~> 1.3"
- s.add_dependency "mixlib-shellout", "~> 1.4"
- s.add_dependency "ohai", "~> 7.2"
+ s.add_dependency "mixlib-shellout", ">= 2.0.0.rc.0", "< 3.0"
+ s.add_dependency "ohai", ">= 7.6.0.rc.0"
s.add_dependency "ffi-yajl", "~> 1.0", ">= 1.0.2"
s.add_dependency "net-ssh", "~> 2.6"
diff --git a/lib/chef/application.rb b/lib/chef/application.rb
index 5b1d53d741..0430d4acfa 100644
--- a/lib/chef/application.rb
+++ b/lib/chef/application.rb
@@ -46,6 +46,7 @@ class Chef::Application
configure_chef
configure_logging
configure_proxy_environment_variables
+ configure_encoding
end
# Get this party started
@@ -175,6 +176,11 @@ class Chef::Application
configure_no_proxy
end
+ # Sets the default external encoding to UTF-8 (users can change this, but they shouldn't)
+ def configure_encoding
+ Encoding.default_external = Chef::Config[:ruby_encoding]
+ end
+
# Called prior to starting the application, by the run method
def setup_application
raise Chef::Exceptions::Application, "#{self.to_s}: you must override setup_application"
diff --git a/lib/chef/application/apply.rb b/lib/chef/application/apply.rb
index ab35b35389..ea9154c6f2 100644
--- a/lib/chef/application/apply.rb
+++ b/lib/chef/application/apply.rb
@@ -134,6 +134,10 @@ class Chef::Application::Apply < Chef::Application
@recipe_text = STDIN.read
temp_recipe_file
else
+ if !ARGV[0]
+ puts opt_parser
+ Chef::Application.exit! "No recipe file provided", 1
+ end
@recipe_filename = ARGV[0]
@recipe_text,@recipe_fh = read_recipe_file @recipe_filename
end
diff --git a/lib/chef/chef_fs/chef_fs_data_store.rb b/lib/chef/chef_fs/chef_fs_data_store.rb
index 09a66a9ab2..484ab07390 100644
--- a/lib/chef/chef_fs/chef_fs_data_store.rb
+++ b/lib/chef/chef_fs/chef_fs_data_store.rb
@@ -27,7 +27,61 @@ require 'fileutils'
class Chef
module ChefFS
+ #
+ # Translation layer between chef-zero's DataStore (a place where it expects
+ # files to be stored) and ChefFS (the user's repository directory layout).
+ #
+ # chef-zero expects the data store to store files *its* way--for example, it
+ # expects get("nodes/blah") to return the JSON text for the blah node, and
+ # it expects get("cookbooks/blah/1.0.0") to return the JSON definition of
+ # the blah cookbook version 1.0.0.
+ #
+ # The repository is defined the way the *user* wants their layout. These
+ # two things are very similar in layout (for example, nodes are stored under
+ # the nodes/ directory and their filename is the name of the node).
+ #
+ # However, there are a few differences that make this more than just a raw
+ # file store:
+ #
+ # 1. Cookbooks are stored much differently.
+ # - chef-zero places JSON text with the checksums for the cookbook at
+ # /cookbooks/NAME/VERSION, and expects the JSON to contain URLs to the
+ # actual files, which are stored elsewhere.
+ # - The repository contains an actual directory with just the cookbook
+ # files and a metadata.rb containing a version #. There is no JSON to
+ # be found.
+ # - Further, if versioned_cookbooks is false, that directory is named
+ # /cookbooks/NAME and only one version exists. If versioned_cookbooks
+ # is true, the directory is named /cookbooks/NAME-VERSION.
+ # - Therefore, ChefFSDataStore calculates the cookbook JSON by looking at
+ # the files in the cookbook and checksumming them, and reading metadata.rb
+ # for the version and dependency information.
+ # - ChefFSDataStore also modifies the cookbook file URLs so that they point
+ # to /file_store/repo/<filename> (the path to the actual file under the
+ # repository root). For example, /file_store/repo/apache2/metadata.rb or
+ # /file_store/repo/cookbooks/apache2/recipes/default.rb).
+ #
+ # 2. Sandboxes don't exist in the repository.
+ # - ChefFSDataStore lets cookbooks be uploaded into a temporary memory
+ # storage, and when the cookbook is committed, copies the files onto the
+ # disk in the correct place (/cookbooks/apache2/recipes/default.rb).
+ # 3. Data bags:
+ # - The Chef server expects data bags in /data/BAG/ITEM
+ # - The repository stores data bags in /data_bags/BAG/ITEM
+ #
+ # 4. JSON filenames are generally NAME.json in the repository (e.g. /nodes/foo.json).
+ #
class ChefFSDataStore
+ #
+ # Create a new ChefFSDataStore
+ #
+ # ==== Arguments
+ #
+ # [chef_fs]
+ # A +ChefFS::FileSystem+ object representing the repository root.
+ # Generally will be a +ChefFS::FileSystem::ChefRepositoryFileSystemRoot+
+ # object, created from +ChefFS::Config.local_fs+.
+ #
def initialize(chef_fs)
@chef_fs = chef_fs
@memory_store = ChefZero::DataStore::MemoryStore.new
diff --git a/lib/chef/chef_fs/config.rb b/lib/chef/chef_fs/config.rb
index ca273b2cca..fcad6c919f 100644
--- a/lib/chef/chef_fs/config.rb
+++ b/lib/chef/chef_fs/config.rb
@@ -22,9 +22,74 @@ require 'chef/chef_fs/path_utils'
class Chef
module ChefFS
#
- # Helpers to take Chef::Config and create chef_fs and local_fs from it
+ # Helpers to take Chef::Config and create chef_fs and local_fs (ChefFS
+ # objects representing the server and local repository, respectively).
#
class Config
+ #
+ # Create a new Config object which can produce a chef_fs and local_fs.
+ #
+ # ==== Arguments
+ #
+ # [chef_config]
+ # A hash that looks suspiciously like +Chef::Config+. These hash keys
+ # include:
+ #
+ # :chef_repo_path::
+ # The root where all local chef object data is stored. Mirrors
+ # +Chef::Config.chef_repo_path+
+ # :cookbook_path, node_path, ...::
+ # Paths to cookbooks/, nodes/, data_bags/, etc. Mirrors
+ # +Chef::Config.cookbook_path+, etc. Defaults to
+ # +<chef_repo_path>/cookbooks+, etc.
+ # :repo_mode::
+ # The directory format on disk. 'everything', 'hosted_everything' and
+ # 'static'. Default: autodetected based on whether the URL has
+ # "/organizations/NAME."
+ # :versioned_cookbooks::
+ # If true, the repository contains cookbooks with versions in their
+ # name (apache2-1.0.0). If false, the repository just has one version
+ # of each cookbook and the directory has the cookbook name (apache2).
+ # Default: +false+
+ # :chef_server_url::
+ # The URL to the Chef server, e.g. https://api.opscode.com/organizations/foo.
+ # Used as the server for the remote chef_fs, and to "guess" repo_mode
+ # if not specified.
+ # :node_name:: The username to authenticate to the Chef server with.
+ # :client_key:: The private key for the user for authentication
+ # :environment:: The environment in which you are presently working
+ # :repo_mode::
+ # The repository mode, :hosted_everything, :everything or :static.
+ # This determines the set of subdirectories the Chef server will offer
+ # up.
+ # :versioned_cookbooks:: Whether or not to include versions in cookbook names
+ #
+ # [cwd]
+ # The current working directory to base relative Chef paths from.
+ # Defaults to +Dir.pwd+.
+ #
+ # [options]
+ # A hash of other, not-suspiciously-like-chef-config options:
+ # :cookbook_version::
+ # When downloading cookbooks, download this cookbook version instead
+ # of the latest.
+ #
+ # [ui]
+ # The object to print output to, with "output", "warn" and "error"
+ # (looks a little like a Chef::Knife::UI object, obtainable from
+ # Chef::Knife.ui).
+ #
+ # ==== Example
+ #
+ # require 'chef/chef_fs/config'
+ # config = Chef::ChefFS::Config.new
+ # config.chef_fs.child('cookbooks').children.each do |cookbook|
+ # puts "Cookbook on server: #{cookbook.name}"
+ # end
+ # config.local_fs.child('cookbooks').children.each do |cookbook|
+ # puts "Local cookbook: #{cookbook.name}"
+ # end
+ #
def initialize(chef_config = Chef::Config, cwd = Dir.pwd, options = {}, ui = nil)
@chef_config = chef_config
@cwd = cwd
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb
index 050da60389..ac272d4c1a 100644
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb
+++ b/lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb
@@ -42,15 +42,17 @@ class Chef
# Create a new Chef Repository File System root.
#
# == Parameters
- # - child_paths - a hash of child paths, e.g.:
- # "nodes" => [ '/var/nodes', '/home/jkeiser/nodes' ],
- # "roles" => [ '/var/roles' ],
- # ...
- # - root_paths - an array of paths representing the top level, where
- # org.json, members.json, and invites.json will be stored.
- # - chef_config - a hash of options that looks suspiciously like the ones
+ # [child_paths]
+ # A hash of child paths, e.g.:
+ # "nodes" => [ '/var/nodes', '/home/jkeiser/nodes' ],
+ # "roles" => [ '/var/roles' ],
+ # ...
+ # [root_paths]
+ # An array of paths representing the top level, where
+ # +org.json+, +members.json+, and +invites.json+ will be stored.
+ # [chef_config] - a hash of options that looks suspiciously like the ones
# stored in Chef::Config, containing at least these keys:
- # - :versioned_cookbooks - whether to include versions in cookbook names
+ # :versioned_cookbooks:: whether to include versions in cookbook names
def initialize(child_paths, root_paths=[], chef_config=Chef::Config)
super("", nil)
@child_paths = child_paths
diff --git a/lib/chef/chef_fs/file_system/chef_server_root_dir.rb b/lib/chef/chef_fs/file_system/chef_server_root_dir.rb
index 61a224c307..370308ee0a 100644
--- a/lib/chef/chef_fs/file_system/chef_server_root_dir.rb
+++ b/lib/chef/chef_fs/file_system/chef_server_root_dir.rb
@@ -46,19 +46,24 @@ class Chef
#
# == Parameters
#
- # - root_name - a friendly name for the root, for printing--like "remote" or "chef_central".
- # - chef_config - a hash with options that look suspiciously like Chef::Config, including the
- # following keys:
- # - :chef_server_url - the URL to the Chef server or top of the organization
- # - :node_name - the username to authenticate to the Chef server with
- # - :client_key - the private key for the user for authentication
- # - :environment - the environment in which you are presently working
- # - :repo_mode - the repository mode, :hosted_everything, :everything or :static.
- # This determines the set of subdirectories the Chef server
- # will offer up.
- # - :versioned_cookbooks - whether or not to include versions in cookbook names
- # - options - other options:
- # - :cookbook_version - when cookbooks are retrieved, grab this version for them.
+ # [root_name]
+ # A friendly name for the root, for printing--like "remote" or "chef_central".
+ # [chef_config]
+ # A hash with options that look suspiciously like Chef::Config, including the
+ # following keys:
+ # :chef_server_url:: The URL to the Chef server or top of the organization
+ # :node_name:: The username to authenticate to the Chef server with
+ # :client_key:: The private key for the user for authentication
+ # :environment:: The environment in which you are presently working
+ # :repo_mode::
+ # The repository mode, :hosted_everything, :everything or :static.
+ # This determines the set of subdirectories the Chef server will
+ # offer up.
+ # :versioned_cookbooks:: whether or not to include versions in cookbook names
+ # [options]
+ # Other options:
+ # :cookbook_version:: when cookbooks are retrieved, grab this version for them.
+ # :freeze:: freeze cookbooks on upload
#
def initialize(root_name, chef_config, options = {})
super("", nil)
diff --git a/lib/chef/client.rb b/lib/chef/client.rb
index 2de3ca3e64..161ecddb0f 100644
--- a/lib/chef/client.rb
+++ b/lib/chef/client.rb
@@ -44,6 +44,7 @@ require 'chef/resource_reporter'
require 'chef/run_lock'
require 'chef/policy_builder'
require 'chef/request_id'
+require 'chef/platform/rebooter'
require 'ohai'
require 'rbconfig'
@@ -427,7 +428,9 @@ class Chef
run_context = setup_run_context
- converge(run_context)
+ catch (:end_client_run_early) do
+ converge(run_context)
+ end
save_updated_node
@@ -435,6 +438,10 @@ class Chef
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)
+
true
rescue Exception => e
# CHEF-3336: Send the error first in case something goes wrong below and we don't know why
diff --git a/lib/chef/config.rb b/lib/chef/config.rb
index 4e71645dcc..74607e8368 100644
--- a/lib/chef/config.rb
+++ b/lib/chef/config.rb
@@ -331,10 +331,11 @@ class Chef
default :ssl_client_cert, nil
default :ssl_client_key, nil
- # Whether or not to verify the SSL cert for all HTTPS requests. If set to
- # :verify_peer, all HTTPS requests will be validated regardless of other
- # SSL verification settings.
- default :ssl_verify_mode, :verify_none
+ # Whether or not to verify the SSL cert for all HTTPS requests. When set to
+ # :verify_peer (default), all HTTPS requests will be validated regardless of other
+ # SSL verification settings. When set to :verify_none no HTTPS requests will
+ # be validated.
+ default :ssl_verify_mode, :verify_peer
# Whether or not to verify the SSL cert for HTTPS requests to the Chef
# server API. If set to `true`, the server's cert will be validated
@@ -587,6 +588,51 @@ class Chef
default :normal_attribute_whitelist, nil
default :override_attribute_whitelist, nil
+ # Chef requires an English-language UTF-8 locale to function properly. We attempt
+ # to use the 'locale -a' command and search through a list of preferences until we
+ # find one that we can use. On Ubuntu systems we should find 'C.UTF-8' and be
+ # able to use that even if there is no English locale on the server, but Mac, Solaris,
+ # AIX, etc do not have that locale. We then try to find an English locale and fall
+ # back to 'C' if we do not. The choice of fallback is pick-your-poison. If we try
+ # to do the work to return a non-US UTF-8 locale then we fail inside of providers when
+ # things like 'svn info' return Japanese and we can't parse them. OTOH, if we pick 'C' then
+ # we will blow up on UTF-8 characters. Between the warn we throw and the Encoding
+ # exception that ruby will throw it is more obvious what is broken if we drop UTF-8 by
+ # default rather than drop English.
+ #
+ # If there is no 'locale -a' then we return 'en_US.UTF-8' since that is the most commonly
+ # available English UTF-8 locale. However, all modern POSIXen should support 'locale -a'.
+ default :internal_locale do
+ begin
+ locales = `locale -a`.split
+ case
+ when locales.include?('C.UTF-8')
+ 'C.UTF-8'
+ when locales.include?('en_US.UTF-8')
+ 'en_US.UTF-8'
+ when locales.include?('en.UTF-8')
+ 'en.UTF-8'
+ when guesses = locales.select { |l| l =~ /^en_.*UTF-8$'/ }
+ guesses.first
+ else
+ Chef::Log.warn "Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support."
+ 'C'
+ end
+ rescue
+ Chef::Log.warn "No usable locale -a command found, assuming you have en_US.UTF-8 installed."
+ 'en_US.UTF-8'
+ end
+ end
+
+ # Force UTF-8 Encoding, for when we fire up in the 'C' locale or other strange locales (e.g.
+ # japanese windows encodings). If we do not do this, then knife upload will fail when a cookbook's
+ # README.md has UTF-8 characters that do not encode in whatever surrounding encoding we have been
+ # passed. Effectively, the Chef Ecosystem is globally UTF-8 by default. Anyone who wants to be
+ # able to upload Shift_JIS or ISO-8859-1 files needs to mark *those* files explicitly with
+ # magic tags to make ruby correctly identify the encoding being used. Changing this default will
+ # break Chef community cookbooks and is very highly discouraged.
+ default :ruby_encoding, Encoding::UTF_8
+
# If installed via an omnibus installer, this gives the path to the
# "embedded" directory which contains all of the software packaged with
# omnibus. This is used to locate the cacert.pem file on windows.
diff --git a/lib/chef/dsl/reboot_pending.rb b/lib/chef/dsl/reboot_pending.rb
index 9f80d38c61..a81debce99 100644
--- a/lib/chef/dsl/reboot_pending.rb
+++ b/lib/chef/dsl/reboot_pending.rb
@@ -27,10 +27,13 @@ class Chef
include Chef::DSL::PlatformIntrospection
# Returns true if the system needs a reboot or is expected to reboot
- # Raises UnsupportedPlatform if this functionality isn't provided yet
+ # Note that we will silently miss any other platform-specific reboot notices besides Windows+Ubuntu.
def reboot_pending?
- if platform?("windows")
+ # don't break when used as a mixin in contexts without #node (e.g. specs).
+ if self.respond_to?(:node, true) && node.run_context.reboot_requested?
+ true
+ elsif platform?("windows")
# PendingFileRenameOperations contains pairs (REG_MULTI_SZ) of filenames that cannot be updated
# due to a file being in use (usually a temporary file and a system file)
# \??\c:\temp\test.sys!\??\c:\winnt\system32\test.sys
@@ -53,7 +56,7 @@ class Chef
# This should work for Debian as well if update-notifier-common happens to be installed. We need an API for that.
File.exists?('/var/run/reboot-required')
else
- raise Chef::Exceptions::UnsupportedPlatform.new(node[:platform])
+ false
end
end
end
diff --git a/lib/chef/exceptions.rb b/lib/chef/exceptions.rb
index 23e223f204..67429ac5a2 100644
--- a/lib/chef/exceptions.rb
+++ b/lib/chef/exceptions.rb
@@ -118,6 +118,10 @@ class Chef
class InvalidDataBagPath < ArgumentError; end
class DuplicateDataBagItem < RuntimeError; end
+ class PowershellCmdletException < RuntimeError; end
+
+ class CannotDetermineHomebrewOwner < Package; end
+
# A different version of a cookbook was added to a
# VersionedRecipeList than the one already there.
class CookbookVersionConflict < ArgumentError ; end
@@ -179,6 +183,8 @@ class Chef
class ChildConvergeError < RuntimeError; end
+ class NoProviderAvailable < RuntimeError; end
+
class MissingRole < RuntimeError
NULL = Object.new
diff --git a/lib/chef/knife/bootstrap/archlinux-gems.erb b/lib/chef/knife/bootstrap/archlinux-gems.erb
index bb84340c05..eb134b90d5 100644
--- a/lib/chef/knife/bootstrap/archlinux-gems.erb
+++ b/lib/chef/knife/bootstrap/archlinux-gems.erb
@@ -23,6 +23,11 @@ EOP
chmod 0600 /etc/chef/encrypted_data_bag_secret
<% end -%>
+<% unless trusted_certs.empty? -%>
+mkdir -p /etc/chef/trusted_certs
+<%= trusted_certs %>
+<% end -%>
+
<%# Generate Ohai Hints -%>
<% unless @chef_config[:knife][:hints].nil? || @chef_config[:knife][:hints].empty? -%>
mkdir -p /etc/chef/ohai/hints
diff --git a/lib/chef/knife/bootstrap/chef-aix.erb b/lib/chef/knife/bootstrap/chef-aix.erb
index 59993b478a..3a031ee738 100644
--- a/lib/chef/knife/bootstrap/chef-aix.erb
+++ b/lib/chef/knife/bootstrap/chef-aix.erb
@@ -36,6 +36,11 @@ EOP
chmod 0600 /etc/chef/encrypted_data_bag_secret
<% end -%>
+<% unless trusted_certs.empty? -%>
+mkdir -p /etc/chef/trusted_certs
+<%= trusted_certs %>
+<% end -%>
+
<%# Generate Ohai Hints -%>
<% unless @chef_config[:knife][:hints].nil? || @chef_config[:knife][:hints].empty? -%>
mkdir -p /etc/chef/ohai/hints
diff --git a/lib/chef/knife/bootstrap/chef-full.erb b/lib/chef/knife/bootstrap/chef-full.erb
index a4e85b9d67..6edb485f44 100644
--- a/lib/chef/knife/bootstrap/chef-full.erb
+++ b/lib/chef/knife/bootstrap/chef-full.erb
@@ -50,6 +50,11 @@ EOP
chmod 0600 /etc/chef/encrypted_data_bag_secret
<% end -%>
+<% unless trusted_certs.empty? -%>
+mkdir -p /etc/chef/trusted_certs
+<%= trusted_certs %>
+<% end -%>
+
<%# Generate Ohai Hints -%>
<% unless @chef_config[:knife][:hints].nil? || @chef_config[:knife][:hints].empty? -%>
mkdir -p /etc/chef/ohai/hints
diff --git a/lib/chef/knife/core/bootstrap_context.rb b/lib/chef/knife/core/bootstrap_context.rb
index 12d422a162..87c25ca160 100644
--- a/lib/chef/knife/core/bootstrap_context.rb
+++ b/lib/chef/knife/core/bootstrap_context.rb
@@ -44,14 +44,20 @@ class Chef
def encrypted_data_bag_secret
knife_config[:secret] || begin
- if knife_config[:secret_file] && File.exist?(knife_config[:secret_file])
- IO.read(File.expand_path(knife_config[:secret_file]))
+ secret_file_path = knife_config[:secret_file]
+ expanded_secret_file_path = File.expand_path(secret_file_path.to_s)
+ if secret_file_path && File.exist?(expanded_secret_file_path)
+ IO.read(expanded_secret_file_path)
else
nil
end
end
end
+ def trusted_certs
+ @trusted_certs ||= trusted_certs_content
+ end
+
def config_content
client_rb = <<-CONFIG
log_location STDOUT
@@ -107,6 +113,10 @@ CONFIG
client_rb << %Q{encrypted_data_bag_secret "/etc/chef/encrypted_data_bag_secret"\n}
end
+ unless trusted_certs.empty?
+ client_rb << %Q{trusted_certs_dir "/etc/chef/trusted_certs"\n}
+ end
+
client_rb
end
@@ -153,6 +163,18 @@ CONFIG
(@config[:first_boot_attributes] || {}).merge(:run_list => @run_list)
end
+ private
+ def trusted_certs_content
+ content = ""
+ if @chef_config[:trusted_certs_dir]
+ Dir.glob(File.join(@chef_config[:trusted_certs_dir], "*.{crt,pem}")).each do |cert|
+ content << "cat > /etc/chef/trusted_certs/#{File.basename(cert)} <<'EOP'\n" +
+ IO.read(File.expand_path(cert)) + "\nEOP\n"
+ end
+ end
+ content
+ end
+
end
end
end
diff --git a/lib/chef/mixin/homebrew_owner.rb b/lib/chef/mixin/homebrew_owner.rb
new file mode 100644
index 0000000000..73bb22ddf5
--- /dev/null
+++ b/lib/chef/mixin/homebrew_owner.rb
@@ -0,0 +1,58 @@
+#
+# Author:: Joshua Timberman (<joshua@getchef.com>)
+# Author:: Graeme Mathieson (<mathie@woss.name>)
+#
+# Copyright 2011-2013, Opscode, Inc.
+# Copyright 2014, Chef Software, Inc <legal@getchef.com>
+#
+# 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.
+#
+# Ported from the homebrew cookbook's Homebrew::Mixin owner helpers
+#
+# This lives here in Chef::Mixin because Chef's namespacing makes it
+# awkward to use modules elsewhere (e.g., chef/provider/package/homebrew/owner)
+
+class Chef
+ module Mixin
+ module HomebrewOwner
+ def homebrew_owner(node)
+ @homebrew_owner ||= calculate_owner(node)
+ end
+
+ private
+
+ def calculate_owner(node)
+ owner = homebrew_owner_attr(node) || sudo_user || current_user
+ if owner == 'root'
+ raise Chef::Exceptions::CannotDetermineHomebrewOwner,
+ 'The homebrew owner is not specified and the current user is \"root\"' +
+ 'Homebrew does not support root installs, please specify the homebrew' +
+ 'owner by setting the attribute `node[\'homebrew\'][\'owner\']`.'
+ end
+ owner
+ end
+
+ def homebrew_owner_attr(node)
+ node['homebrew']['owner'] if node.attribute?('homebrew') && node['homebrew'].attribute?('owner')
+ end
+
+ def sudo_user
+ ENV['SUDO_USER']
+ end
+
+ def current_user
+ ENV['USER']
+ end
+ end
+ end
+end
diff --git a/lib/chef/mixin/shell_out.rb b/lib/chef/mixin/shell_out.rb
index 881c94b862..82772b584a 100644
--- a/lib/chef/mixin/shell_out.rb
+++ b/lib/chef/mixin/shell_out.rb
@@ -30,32 +30,39 @@ class Chef
# Generally speaking, 'extend Chef::Mixin::ShellOut' in your recipes and include 'Chef::Mixin::ShellOut' in your LWRPs
# You can also call Mixlib::Shellout.new directly, but you lose all of the above functionality
+ # we use 'en_US.UTF-8' by default because we parse localized strings in English as an API and
+ # generally must support UTF-8 unicode.
def shell_out(*command_args)
- cmd = Mixlib::ShellOut.new(*run_command_compatible_options(command_args))
- cmd.live_stream ||= io_for_live_stream
- cmd.run_command
- cmd
+ args = command_args.dup
+ if args.last.is_a?(Hash)
+ options = args.pop.dup
+ env_key = options.has_key?(:env) ? :env : :environment
+ options[env_key] ||= {}
+ options[env_key] = options[env_key].dup
+ options[env_key]['LC_ALL'] ||= Chef::Config[:internal_locale] unless options[env_key].has_key?('LC_ALL')
+ args << options
+ else
+ args << { :environment => { 'LC_ALL' => Chef::Config[:internal_locale] } }
+ end
+
+ shell_out_command(*args)
end
+ # call shell_out (using en_US.UTF-8) and raise errors
def shell_out!(*command_args)
- cmd= shell_out(*command_args)
+ cmd = shell_out(*command_args)
cmd.error!
cmd
end
- # environment['LC_ALL'] should be nil or what the user specified
def shell_out_with_systems_locale(*command_args)
- args = command_args.dup
- if args.last.is_a?(Hash)
- options = args.last
- env_key = options.has_key?(:env) ? :env : :environment
- options[env_key] ||= {}
- options[env_key]['LC_ALL'] ||= nil
- else
- args << { :environment => { 'LC_ALL' => nil } }
- end
+ shell_out_command(*command_args)
+ end
- shell_out(*args)
+ def shell_out_with_systems_locale!(*command_args)
+ cmd = shell_out_with_systems_locale(*command_args)
+ cmd.error!
+ cmd
end
DEPRECATED_OPTIONS =
@@ -82,6 +89,13 @@ class Chef
private
+ def shell_out_command(*command_args)
+ cmd = Mixlib::ShellOut.new(*run_command_compatible_options(command_args))
+ cmd.live_stream ||= io_for_live_stream
+ cmd.run_command
+ cmd
+ end
+
def deprecate_option(old_option, new_option)
Chef::Log.logger.warn "DEPRECATION: Chef::Mixin::ShellOut option :#{old_option} is deprecated. Use :#{new_option}"
end
diff --git a/lib/chef/mixin/windows_architecture_helper.rb b/lib/chef/mixin/windows_architecture_helper.rb
index ff118c1d3d..65ad042910 100644
--- a/lib/chef/mixin/windows_architecture_helper.rb
+++ b/lib/chef/mixin/windows_architecture_helper.rb
@@ -42,6 +42,22 @@ class Chef
is_i386_process_on_x86_64_windows?
end
+ def with_os_architecture(node)
+ wow64_redirection_state = nil
+
+ if wow64_architecture_override_required?(node, node_windows_architecture(node))
+ wow64_redirection_state = disable_wow64_file_redirection(node)
+ end
+
+ begin
+ yield
+ ensure
+ if wow64_redirection_state
+ restore_wow64_file_redirection(node, wow64_redirection_state)
+ end
+ end
+ end
+
def node_supports_windows_architecture?(node, desired_architecture)
assert_valid_windows_architecture!(desired_architecture)
return (node_windows_architecture(node) == :x86_64 ||
diff --git a/lib/chef/platform/provider_mapping.rb b/lib/chef/platform/provider_mapping.rb
index 7f79c38a6a..b10fecc53e 100644
--- a/lib/chef/platform/provider_mapping.rb
+++ b/lib/chef/platform/provider_mapping.rb
@@ -40,7 +40,7 @@ class Chef
{
:mac_os_x => {
:default => {
- :package => Chef::Provider::Package::Macports,
+ :package => Chef::Provider::Package::Homebrew,
:service => Chef::Provider::Service::Macosx,
:user => Chef::Provider::User::Dscl,
:group => Chef::Provider::Group::Dscl
@@ -48,7 +48,7 @@ class Chef
},
:mac_os_x_server => {
:default => {
- :package => Chef::Provider::Package::Macports,
+ :package => Chef::Provider::Package::Homebrew,
:service => Chef::Provider::Service::Macosx,
:user => Chef::Provider::User::Dscl,
:group => Chef::Provider::Group::Dscl
diff --git a/lib/chef/platform/query_helpers.rb b/lib/chef/platform/query_helpers.rb
index f6f5309de5..334ab278d1 100644
--- a/lib/chef/platform/query_helpers.rb
+++ b/lib/chef/platform/query_helpers.rb
@@ -45,7 +45,11 @@ class Chef
is_server_2003
end
- end
+ def supports_dsc?(node)
+ node[:languages] && node[:languages][:powershell] &&
+ node[:languages][:powershell][:version].to_i >= 4
+ end
+ end
end
end
diff --git a/lib/chef/platform/rebooter.rb b/lib/chef/platform/rebooter.rb
new file mode 100644
index 0000000000..b46f0e394c
--- /dev/null
+++ b/lib/chef/platform/rebooter.rb
@@ -0,0 +1,54 @@
+#
+# Author:: Chris Doherty <cdoherty@getchef.com>)
+# Copyright:: Copyright (c) 2014 Chef, 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/dsl/reboot_pending'
+require 'chef/log'
+require 'chef/platform'
+
+class Chef
+ class Platform
+ module Rebooter
+ extend Chef::Mixin::ShellOut
+
+ class << self
+
+ def reboot!(node)
+ reboot_info = node.run_context.reboot_info
+
+ cmd = if Chef::Platform.windows?
+ # should this do /f as well? do we then need a minimum delay to let apps quit?
+ "shutdown /r /t #{reboot_info[:delay_mins]} /c \"#{reboot_info[:reason]}\""
+ else
+ # probably Linux-only.
+ "shutdown -r +#{reboot_info[:delay_mins]} \"#{reboot_info[:reason]}\""
+ end
+
+ Chef::Log.warn "Rebooting server at a recipe's request. Details: #{reboot_info.inspect}"
+ shell_out!(cmd)
+ end
+
+ # this is a wrapper function so Chef::Client only needs a single line of code.
+ def reboot_if_needed!(node)
+ if node.run_context.reboot_requested?
+ reboot!(node)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/dsc_script.rb b/lib/chef/provider/dsc_script.rb
new file mode 100644
index 0000000000..5d7322842c
--- /dev/null
+++ b/lib/chef/provider/dsc_script.rb
@@ -0,0 +1,148 @@
+#
+# Author:: Adam Edwards (<adamed@getchef.com>)
+#
+# Copyright:: 2014, Chef Software, Inc.
+#
+# 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/util/powershell/cmdlet'
+require 'chef/util/dsc/configuration_generator'
+require 'chef/util/dsc/local_configuration_manager'
+
+class Chef
+ class Provider
+ class DscScript < Chef::Provider
+ def initialize(dsc_resource, run_context)
+ super(dsc_resource, run_context)
+ @dsc_resource = dsc_resource
+ @resource_converged = false
+ @operations = {
+ :set => Proc.new { |config_manager, document|
+ config_manager.set_configuration(document)
+ },
+ :test => Proc.new { |config_manager, document|
+ config_manager.test_configuration(document)
+ }}
+ end
+
+ def action_run
+ if ! @resource_converged
+ converge_by(generate_description) do
+ run_configuration(:set)
+ Chef::Log.info("DSC resource configuration completed successfully")
+ end
+ end
+ end
+
+ def load_current_resource
+ @dsc_resources_info = run_configuration(:test)
+ @resource_converged = @dsc_resources_info.all? do |resource|
+ !resource.changes_state?
+ end
+ end
+
+ def whyrun_supported?
+ true
+ end
+
+ protected
+
+ def run_configuration(operation)
+ config_directory = ::Dir.mktmpdir("chef-dsc-script")
+ configuration_data_path = get_configuration_data_path(config_directory)
+ configuration_flags = get_augmented_configuration_flags(configuration_data_path)
+
+ config_manager = Chef::Util::DSC::LocalConfigurationManager.new(@run_context.node, config_directory)
+
+ begin
+ configuration_document = generate_configuration_document(config_directory, configuration_flags)
+ @operations[operation].call(config_manager, configuration_document)
+ rescue Exception => e
+ Chef::Log.error("DSC operation failed: #{e.message.to_s}")
+ raise e
+ ensure
+ ::FileUtils.rm_rf(config_directory)
+ end
+ end
+
+ def get_augmented_configuration_flags(configuration_data_path)
+ updated_flags = nil
+ if configuration_data_path
+ updated_flags = @dsc_resource.flags.nil? ? {} : @dsc_resource.flags.dup
+ Chef::Util::PathHelper.validate_path(configuration_data_path)
+ updated_flags[:configurationdata] = configuration_data_path
+ end
+ updated_flags
+ end
+
+ def generate_configuration_document(config_directory, configuration_flags)
+ shellout_flags = {
+ :cwd => @dsc_resource.cwd,
+ :environment => @dsc_resource.environment,
+ :timeout => @dsc_resource.timeout
+ }
+
+ generator = Chef::Util::DSC::ConfigurationGenerator.new(@run_context.node, config_directory)
+
+ if @dsc_resource.command
+ generator.configuration_document_from_script_path(@dsc_resource.command, configuration_name, configuration_flags, shellout_flags)
+ else
+ # If code is also not provided, we mimic what the other script resources do (execute nothing)
+ Chef::Log.warn("Neither code or command were provided for dsc_resource[#{@dsc_resource.name}].") unless @dsc_resource.code
+ generator.configuration_document_from_script_code(@dsc_resource.code || '', configuration_flags, shellout_flags)
+ end
+ end
+
+ def get_configuration_data_path(config_directory)
+ if @dsc_resource.configuration_data_script
+ @dsc_resource.configuration_data_script
+ elsif @dsc_resource.configuration_data
+ configuration_data_path = "#{config_directory}/chef_dsc_config_data.psd1"
+ ::File.open(configuration_data_path, 'wt') do | script |
+ script.write(@dsc_resource.configuration_data)
+ end
+ configuration_data_path
+ end
+ end
+
+ def configuration_name
+ @dsc_resource.configuration_name || @dsc_resource.name
+ end
+
+ def configuration_friendly_name
+ if @dsc_resource.code
+ @dsc_resource.name
+ else
+ configuration_name
+ end
+ end
+
+ private
+
+ def generate_description
+ ["converge DSC configuration '#{configuration_friendly_name}'"] +
+ @dsc_resources_info.map do |resource|
+ if resource.changes_state?
+ # We ignore the last log message because it only contains the time it took, which looks weird
+ cleaned_messages = resource.change_log[0..-2].map { |c| c.sub(/^#{Regexp.escape(resource.name)}/, '').strip }
+ "converge DSC resource #{resource.name} by #{cleaned_messages.find_all{ |c| c != ''}.join("\n")}"
+ else
+ # This is needed because a dsc script can have resouces that are both converged and not
+ "converge DSC resource #{resource.name} by doing nothing because it is already converged"
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/ifconfig.rb b/lib/chef/provider/ifconfig.rb
index 31f88e5406..ac52100b56 100644
--- a/lib/chef/provider/ifconfig.rb
+++ b/lib/chef/provider/ifconfig.rb
@@ -19,6 +19,7 @@
require 'chef/log'
require 'chef/mixin/command'
require 'chef/provider'
+require 'chef/resource/file'
require 'chef/exceptions'
require 'erb'
@@ -109,11 +110,11 @@ class Chef
:command => command
)
Chef::Log.info("#{@new_resource} added")
- # Write out the config files
- generate_config
end
end
end
+ # Write out the config files
+ generate_config
end
def action_enable
@@ -140,12 +141,12 @@ class Chef
run_command(
:command => command
)
- delete_config
Chef::Log.info("#{@new_resource} deleted")
end
else
Chef::Log.debug("#{@new_resource} does not exist - nothing to do")
end
+ delete_config
end
def action_disable
@@ -168,27 +169,25 @@ class Chef
! @config_template.nil? and ! @config_path.nil?
end
+ def resource_for_config(path)
+ Chef::Resource::File.new(path, run_context)
+ end
+
def generate_config
return unless can_generate_config?
b = binding
template = ::ERB.new(@config_template)
- converge_by ("generate configuration file : #{@config_path}") do
- network_file = ::File.new(@config_path, "w")
- network_file.puts(template.result(b))
- network_file.close
- end
- Chef::Log.info("#{@new_resource} created configuration file")
+ config = resource_for_config(@config_path)
+ config.content(template.result(b))
+ config.run_action(:create)
+ @new_resource.updated_by_last_action(true) if config.updated?
end
def delete_config
return unless can_generate_config?
- require 'fileutils'
- if ::File.exist?(@config_path)
- converge_by ("delete the #{@config_path}") do
- FileUtils.rm_f(@config_path, :verbose => false)
- end
- end
- Chef::Log.info("#{@new_resource} deleted configuration file")
+ config = resource_for_config(@config_path)
+ config.run_action(:delete)
+ @new_resource.updated_by_last_action(true) if config.updated?
end
private
diff --git a/lib/chef/provider/link.rb b/lib/chef/provider/link.rb
index d6602c2e03..af2fe4a84f 100644
--- a/lib/chef/provider/link.rb
+++ b/lib/chef/provider/link.rb
@@ -83,7 +83,7 @@ class Chef
end
def canonicalize(path)
- Chef::Platform.windows? ? path.gsub('/', '\\') : path
+ Chef::Util::PathHelper.canonical_path(path)
end
def action_create
diff --git a/lib/chef/provider/package/aix.rb b/lib/chef/provider/package/aix.rb
index 9fb87d6ea0..da3e6d1684 100644
--- a/lib/chef/provider/package/aix.rb
+++ b/lib/chef/provider/package/aix.rb
@@ -112,14 +112,10 @@ class Chef
def install_package(name, version)
Chef::Log.debug("#{@new_resource} package install options: #{@new_resource.options}")
if @new_resource.options.nil?
- run_command_with_systems_locale(
- :command => "installp -aYF -d #{@new_resource.source} #{@new_resource.package_name}"
- )
+ shell_out!( "installp -aYF -d #{@new_resource.source} #{@new_resource.package_name}" )
Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}")
else
- run_command_with_systems_locale(
- :command => "installp -aYF #{expand_options(@new_resource.options)} -d #{@new_resource.source} #{@new_resource.package_name}"
- )
+ shell_out!( "installp -aYF #{expand_options(@new_resource.options)} -d #{@new_resource.source} #{@new_resource.package_name}" )
Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}")
end
end
@@ -128,14 +124,10 @@ class Chef
def remove_package(name, version)
if @new_resource.options.nil?
- run_command_with_systems_locale(
- :command => "installp -u #{name}"
- )
+ shell_out!( "installp -u #{name}" )
Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}")
else
- run_command_with_systems_locale(
- :command => "installp -u #{expand_options(@new_resource.options)} #{name}"
- )
+ shell_out!( "installp -u #{expand_options(@new_resource.options)} #{name}" )
Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}")
end
end
diff --git a/lib/chef/provider/package/homebrew.rb b/lib/chef/provider/package/homebrew.rb
new file mode 100644
index 0000000000..d964703c87
--- /dev/null
+++ b/lib/chef/provider/package/homebrew.rb
@@ -0,0 +1,121 @@
+#
+# Author:: Joshua Timberman (<joshua@getchef.com>)
+# Author:: Graeme Mathieson (<mathie@woss.name>)
+#
+# Copyright 2011-2013, Opscode, Inc.
+# Copyright 2014, Chef Software, Inc <legal@getchef.com>
+#
+# 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 'etc'
+require 'chef/mixin/homebrew_owner'
+
+class Chef
+ class Provider
+ class Package
+ class Homebrew < Chef::Provider::Package
+ include Chef::Mixin::HomebrewOwner
+ def load_current_resource
+ self.current_resource = Chef::Resource::Package.new(new_resource.name)
+ current_resource.package_name(new_resource.package_name)
+ current_resource.version(current_installed_version)
+ Chef::Log.debug("#{new_resource} current version is #{current_resource.version}") if current_resource.version
+
+ @candidate_version = candidate_version
+
+ Chef::Log.debug("#{new_resource} candidate version is #{@candidate_version}") if @candidate_version
+
+ current_resource
+ end
+
+ def install_package(name, version)
+ unless current_resource.version == version
+ brew('install', new_resource.options, name)
+ end
+ end
+
+ def upgrade_package(name, version)
+ current_version = current_resource.version
+
+ if current_version.nil? or current_version.empty?
+ install_package(name, version)
+ elsif current_version != version
+ brew('upgrade', new_resource.options, name)
+ end
+ end
+
+ def remove_package(name, version)
+ if current_resource.version
+ brew('uninstall', new_resource.options, name)
+ end
+ end
+
+ # Homebrew doesn't really have a notion of purging, do a "force remove"
+ def purge_package(name, version)
+ new_resource.options((new_resource.options || '') << ' --force').strip
+ remove_package(name, version)
+ end
+
+ def brew(*args)
+ get_response_from_command("brew #{args.join(' ')}")
+ end
+
+ # We implement a querying method that returns the JSON-as-Hash
+ # data for a formula per the Homebrew documentation. Previous
+ # implementations of this provider in the homebrew cookbook
+ # performed a bit of magic with the load path to get this
+ # information, but that is not any more robust than using the
+ # command-line interface that returns the same thing.
+ #
+ # https://github.com/Homebrew/homebrew/wiki/Querying-Brew
+ def brew_info
+ @brew_info ||= Chef::JSONCompat.from_json(brew('info', '--json=v1', new_resource.package_name)).first
+ end
+
+ # Some packages (formula) are "keg only" and aren't linked,
+ # because multiple versions installed can cause conflicts. We
+ # handle this by using the last installed version as the
+ # "current" (as in latest). Otherwise, we will use the version
+ # that brew thinks is linked as the current version.
+ #
+ def current_installed_version
+ brew_info['keg_only'] ? brew_info['installed'].last['version'] : brew_info['linked_keg']
+ end
+
+ # Packages (formula) available to install should have a
+ # "stable" version, per the Homebrew project's acceptable
+ # formula documentation, so we will rely on that being the
+ # case. Older implementations of this provider in the homebrew
+ # cookbook would fall back to +brew_info['version']+, but the
+ # schema has changed, and homebrew is a constantly rolling
+ # forward project.
+ #
+ # https://github.com/Homebrew/homebrew/wiki/Acceptable-Formulae#stable-versions
+ def candidate_version
+ brew_info['versions']['stable']
+ end
+
+ private
+
+ def get_response_from_command(command)
+ home_dir = Etc.getpwnam(homebrew_owner(node)).dir
+
+ Chef::Log.debug "Executing '#{command}' as user '#{homebrew_owner(node)}'"
+ output = shell_out!(command, :timeout => 1800, :user => homebrew_owner(node), :environment => { 'HOME' => home_dir, 'RUBYOPT' => nil })
+ output.stdout.chomp
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/package/ips.rb b/lib/chef/provider/package/ips.rb
index 92b41b3627..4090507303 100644
--- a/lib/chef/provider/package/ips.rb
+++ b/lib/chef/provider/package/ips.rb
@@ -65,15 +65,13 @@ class Chef
def install_package(name, version)
package_name = "#{name}@#{version}"
normal_command = "pkg#{expand_options(@new_resource.options)} install -q #{package_name}"
- if @new_resource.respond_to?(:accept_license) and @new_resource.accept_license
- command = normal_command.gsub('-q', '-q --accept')
- else
- command = normal_command
- end
- begin
- run_command_with_systems_locale(:command => command)
- rescue
- end
+ command =
+ if @new_resource.respond_to?(:accept_license) and @new_resource.accept_license
+ normal_command.gsub('-q', '-q --accept')
+ else
+ normal_command
+ end
+ shell_out(command)
end
def upgrade_package(name, version)
@@ -82,9 +80,7 @@ class Chef
def remove_package(name, version)
package_name = "#{name}@#{version}"
- run_command_with_systems_locale(
- :command => "pkg#{expand_options(@new_resource.options)} uninstall -q #{package_name}"
- )
+ shell_out!( "pkg#{expand_options(@new_resource.options)} uninstall -q #{package_name}" )
end
end
end
diff --git a/lib/chef/provider/package/macports.rb b/lib/chef/provider/package/macports.rb
index 6ef303ee4f..05247e6d31 100644
--- a/lib/chef/provider/package/macports.rb
+++ b/lib/chef/provider/package/macports.rb
@@ -45,27 +45,21 @@ class Chef
unless @current_resource.version == version
command = "port#{expand_options(@new_resource.options)} install #{name}"
command << " @#{version}" if version and !version.empty?
- run_command_with_systems_locale(
- :command => command
- )
+ shell_out!(command)
end
end
def purge_package(name, version)
command = "port#{expand_options(@new_resource.options)} uninstall #{name}"
command << " @#{version}" if version and !version.empty?
- run_command_with_systems_locale(
- :command => command
- )
+ shell_out!(command)
end
def remove_package(name, version)
command = "port#{expand_options(@new_resource.options)} deactivate #{name}"
command << " @#{version}" if version and !version.empty?
- run_command_with_systems_locale(
- :command => command
- )
+ shell_out!(command)
end
def upgrade_package(name, version)
@@ -78,9 +72,7 @@ class Chef
# that hasn't been installed.
install_package(name, version)
elsif current_version != version
- run_command_with_systems_locale(
- :command => "port#{expand_options(@new_resource.options)} upgrade #{name} @#{version}"
- )
+ shell_out!( "port#{expand_options(@new_resource.options)} upgrade #{name} @#{version}" )
end
end
diff --git a/lib/chef/provider/package/pacman.rb b/lib/chef/provider/package/pacman.rb
index 2e8bb7850b..1014ebcaa5 100644
--- a/lib/chef/provider/package/pacman.rb
+++ b/lib/chef/provider/package/pacman.rb
@@ -86,9 +86,7 @@ class Chef
end
def install_package(name, version)
- run_command_with_systems_locale(
- :command => "pacman --sync --noconfirm --noprogressbar#{expand_options(@new_resource.options)} #{name}"
- )
+ shell_out!( "pacman --sync --noconfirm --noprogressbar#{expand_options(@new_resource.options)} #{name}" )
end
def upgrade_package(name, version)
@@ -96,9 +94,7 @@ class Chef
end
def remove_package(name, version)
- run_command_with_systems_locale(
- :command => "pacman --remove --noconfirm --noprogressbar#{expand_options(@new_resource.options)} #{name}"
- )
+ shell_out!( "pacman --remove --noconfirm --noprogressbar#{expand_options(@new_resource.options)} #{name}" )
end
def purge_package(name, version)
diff --git a/lib/chef/provider/package/portage.rb b/lib/chef/provider/package/portage.rb
index 6a3587558a..7e0eebd0d9 100644
--- a/lib/chef/provider/package/portage.rb
+++ b/lib/chef/provider/package/portage.rb
@@ -110,9 +110,7 @@ class Chef
pkg = "~#{name}-#{$1}"
end
- run_command_with_systems_locale(
- :command => "emerge -g --color n --nospinner --quiet#{expand_options(@new_resource.options)} #{pkg}"
- )
+ shell_out!( "emerge -g --color n --nospinner --quiet#{expand_options(@new_resource.options)} #{pkg}" )
end
def upgrade_package(name, version)
@@ -126,9 +124,7 @@ class Chef
pkg = "#{@new_resource.package_name}"
end
- run_command_with_systems_locale(
- :command => "emerge --unmerge --color n --nospinner --quiet#{expand_options(@new_resource.options)} #{pkg}"
- )
+ shell_out!( "emerge --unmerge --color n --nospinner --quiet#{expand_options(@new_resource.options)} #{pkg}" )
end
def purge_package(name, version)
diff --git a/lib/chef/provider/package/rpm.rb b/lib/chef/provider/package/rpm.rb
index bbb561bd15..c0a6444252 100644
--- a/lib/chef/provider/package/rpm.rb
+++ b/lib/chef/provider/package/rpm.rb
@@ -90,13 +90,9 @@ class Chef
def install_package(name, version)
unless @current_resource.version
- run_command_with_systems_locale(
- :command => "rpm #{@new_resource.options} -i #{@new_resource.source}"
- )
+ shell_out!( "rpm #{@new_resource.options} -i #{@new_resource.source}" )
else
- run_command_with_systems_locale(
- :command => "rpm #{@new_resource.options} -U #{@new_resource.source}"
- )
+ shell_out!( "rpm #{@new_resource.options} -U #{@new_resource.source}" )
end
end
@@ -104,13 +100,9 @@ class Chef
def remove_package(name, version)
if version
- run_command_with_systems_locale(
- :command => "rpm #{@new_resource.options} -e #{name}-#{version}"
- )
+ shell_out!( "rpm #{@new_resource.options} -e #{name}-#{version}" )
else
- run_command_with_systems_locale(
- :command => "rpm #{@new_resource.options} -e #{name}"
- )
+ shell_out!( "rpm #{@new_resource.options} -e #{name}" )
end
end
diff --git a/lib/chef/provider/package/solaris.rb b/lib/chef/provider/package/solaris.rb
index 0f45b61e18..19f844b66a 100644
--- a/lib/chef/provider/package/solaris.rb
+++ b/lib/chef/provider/package/solaris.rb
@@ -112,9 +112,7 @@ class Chef
else
command = "pkgadd -n -d #{@new_resource.source} all"
end
- run_command_with_systems_locale(
- :command => command
- )
+ shell_out!(command)
Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}")
else
if ::File.directory?(@new_resource.source) # CHEF-4469
@@ -122,23 +120,17 @@ class Chef
else
command = "pkgadd -n#{expand_options(@new_resource.options)} -d #{@new_resource.source} all"
end
- run_command_with_systems_locale(
- :command => command
- )
+ shell_out!(command)
Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}")
end
end
def remove_package(name, version)
if @new_resource.options.nil?
- run_command_with_systems_locale(
- :command => "pkgrm -n #{name}"
- )
+ shell_out!( "pkgrm -n #{name}" )
Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}")
else
- run_command_with_systems_locale(
- :command => "pkgrm -n#{expand_options(@new_resource.options)} #{name}"
- )
+ shell_out!( "pkgrm -n#{expand_options(@new_resource.options)} #{name}" )
Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}")
end
end
diff --git a/lib/chef/provider/reboot.rb b/lib/chef/provider/reboot.rb
new file mode 100644
index 0000000000..8dde4653ec
--- /dev/null
+++ b/lib/chef/provider/reboot.rb
@@ -0,0 +1,69 @@
+#
+# Author:: Chris Doherty <cdoherty@getchef.com>)
+# Copyright:: Copyright (c) 2014 Chef, 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/log'
+require 'chef/provider'
+
+class Chef
+ class Provider
+ class Reboot < Chef::Provider
+
+ def whyrun_supported?
+ true
+ end
+
+ def load_current_resource
+ @current_resource ||= Chef::Resource::Reboot.new(@new_resource.name)
+ @current_resource.reason(@new_resource.reason)
+ @current_resource.delay_mins(@new_resource.delay_mins)
+ @current_resource
+ end
+
+ def request_reboot
+ node.run_context.request_reboot(
+ :delay_mins => @new_resource.delay_mins,
+ :reason => @new_resource.reason,
+ :timestamp => Time.now,
+ :requested_by => @new_resource.name
+ )
+ end
+
+ def action_request_reboot
+ converge_by("request a system reboot to occur if the run succeeds") do
+ Chef::Log.warn "Reboot requested:'#{@new_resource.name}'"
+ request_reboot
+ end
+ end
+
+ def action_reboot_now
+ converge_by("rebooting the system immediately") do
+ Chef::Log.warn "Rebooting system immediately, requested by '#{@new_resource.name}'"
+ request_reboot
+ throw :end_client_run_early
+ end
+ end
+
+ def action_cancel
+ converge_by("cancel any existing end-of-run reboot request") do
+ Chef::Log.warn "Reboot canceled: '#{@new_resource.name}'"
+ node.run_context.cancel_reboot
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/service/debian.rb b/lib/chef/provider/service/debian.rb
index 06fe7fc480..1ebef90349 100644
--- a/lib/chef/provider/service/debian.rb
+++ b/lib/chef/provider/service/debian.rb
@@ -130,15 +130,15 @@ class Chef
def enable_service
if @new_resource.priority.is_a? Integer
- run_command(:command => "/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
- run_command(:command => "/usr/sbin/update-rc.d #{@new_resource.service_name} defaults #{@new_resource.priority} #{100 - @new_resource.priority}")
+ shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
+ shell_out!("/usr/sbin/update-rc.d #{@new_resource.service_name} defaults #{@new_resource.priority} #{100 - @new_resource.priority}")
elsif @new_resource.priority.is_a? Hash
# we call the same command regardless of we're enabling or disabling
# users passing a Hash are responsible for setting their own start priorities
set_priority
else # No priority, go with update-rc.d defaults
- run_command(:command => "/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
- run_command(:command => "/usr/sbin/update-rc.d #{@new_resource.service_name} defaults")
+ shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
+ shell_out!("/usr/sbin/update-rc.d #{@new_resource.service_name} defaults")
end
end
@@ -146,16 +146,16 @@ class Chef
def disable_service
if @new_resource.priority.is_a? Integer
# Stop processes in reverse order of start using '100 - start_priority'
- run_command(:command => "/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
- run_command(:command => "/usr/sbin/update-rc.d -f #{@new_resource.service_name} stop #{100 - @new_resource.priority} 2 3 4 5 .")
+ shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
+ shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} stop #{100 - @new_resource.priority} 2 3 4 5 .")
elsif @new_resource.priority.is_a? Hash
# we call the same command regardless of we're enabling or disabling
# users passing a Hash are responsible for setting their own stop priorities
set_priority
else
# no priority, using '100 - 20 (update-rc.d default)' to stop in reverse order of start
- run_command(:command => "/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
- run_command(:command => "/usr/sbin/update-rc.d -f #{@new_resource.service_name} stop 80 2 3 4 5 .")
+ shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
+ shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} stop 80 2 3 4 5 .")
end
end
@@ -166,8 +166,8 @@ class Chef
priority = o[1]
args += "#{action} #{priority} #{level} . "
end
- run_command(:command => "/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
- run_command(:command => "/usr/sbin/update-rc.d #{@new_resource.service_name} #{args}")
+ shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
+ shell_out!("/usr/sbin/update-rc.d #{@new_resource.service_name} #{args}")
end
end
end
diff --git a/lib/chef/provider/service/freebsd.rb b/lib/chef/provider/service/freebsd.rb
index 7b69957cc6..08d58232e1 100644
--- a/lib/chef/provider/service/freebsd.rb
+++ b/lib/chef/provider/service/freebsd.rb
@@ -78,7 +78,7 @@ class Chef
if new_resource.start_command
super
else
- shell_out!("#{init_command} faststart")
+ shell_out_with_systems_locale!("#{init_command} faststart")
end
end
@@ -86,7 +86,7 @@ class Chef
if new_resource.stop_command
super
else
- shell_out!("#{init_command} faststop")
+ shell_out_with_systems_locale!("#{init_command} faststop")
end
end
@@ -94,7 +94,7 @@ class Chef
if new_resource.restart_command
super
elsif new_resource.supports[:restart]
- shell_out!("#{init_command} fastrestart")
+ shell_out_with_systems_locale!("#{init_command} fastrestart")
else
stop_service
sleep 1
diff --git a/lib/chef/provider/service/gentoo.rb b/lib/chef/provider/service/gentoo.rb
index 1559c7893f..a68abfebc9 100644
--- a/lib/chef/provider/service/gentoo.rb
+++ b/lib/chef/provider/service/gentoo.rb
@@ -58,10 +58,10 @@ class Chef::Provider::Service::Gentoo < Chef::Provider::Service::Init
end
def enable_service()
- run_command(:command => "/sbin/rc-update add #{@new_resource.service_name} default")
+ shell_out!("/sbin/rc-update add #{@new_resource.service_name} default")
end
def disable_service()
- run_command(:command => "/sbin/rc-update del #{@new_resource.service_name} default")
+ shell_out!("/sbin/rc-update del #{@new_resource.service_name} default")
end
end
diff --git a/lib/chef/provider/service/init.rb b/lib/chef/provider/service/init.rb
index 23d9dde80a..5d8bb5bb38 100644
--- a/lib/chef/provider/service/init.rb
+++ b/lib/chef/provider/service/init.rb
@@ -50,7 +50,7 @@ class Chef
if @new_resource.start_command
super
else
- shell_out!("#{default_init_command} start")
+ shell_out_with_systems_locale!("#{default_init_command} start")
end
end
@@ -58,7 +58,7 @@ class Chef
if @new_resource.stop_command
super
else
- shell_out!("#{default_init_command} stop")
+ shell_out_with_systems_locale!("#{default_init_command} stop")
end
end
@@ -66,7 +66,7 @@ class Chef
if @new_resource.restart_command
super
elsif @new_resource.supports[:restart]
- shell_out!("#{default_init_command} restart")
+ shell_out_with_systems_locale!("#{default_init_command} restart")
else
stop_service
sleep 1
@@ -78,7 +78,7 @@ class Chef
if @new_resource.reload_command
super
elsif @new_resource.supports[:reload]
- shell_out!("#{default_init_command} reload")
+ shell_out_with_systems_locale!("#{default_init_command} reload")
end
end
end
diff --git a/lib/chef/provider/service/insserv.rb b/lib/chef/provider/service/insserv.rb
index 35767ee7b9..f4c85dd9d3 100644
--- a/lib/chef/provider/service/insserv.rb
+++ b/lib/chef/provider/service/insserv.rb
@@ -37,12 +37,12 @@ class Chef
end
def enable_service()
- run_command(:command => "/sbin/insserv -r -f #{@new_resource.service_name}")
- run_command(:command => "/sbin/insserv -d -f #{@new_resource.service_name}")
+ shell_out!("/sbin/insserv -r -f #{@new_resource.service_name}")
+ shell_out!("/sbin/insserv -d -f #{@new_resource.service_name}")
end
def disable_service()
- run_command(:command => "/sbin/insserv -r -f #{@new_resource.service_name}")
+ shell_out!("/sbin/insserv -r -f #{@new_resource.service_name}")
end
end
end
diff --git a/lib/chef/provider/service/macosx.rb b/lib/chef/provider/service/macosx.rb
index 36930ee4ac..cf5e554559 100644
--- a/lib/chef/provider/service/macosx.rb
+++ b/lib/chef/provider/service/macosx.rb
@@ -83,7 +83,7 @@ class Chef
if @new_resource.start_command
super
else
- shell_out!("launchctl load -w '#{@plist}'", :user => @owner_uid, :group => @owner_gid)
+ shell_out_with_systems_locale!("launchctl load -w '#{@plist}'", :user => @owner_uid, :group => @owner_gid)
end
end
end
@@ -95,7 +95,7 @@ class Chef
if @new_resource.stop_command
super
else
- shell_out!("launchctl unload '#{@plist}'", :user => @owner_uid, :group => @owner_gid)
+ shell_out_with_systems_locale!("launchctl unload '#{@plist}'", :user => @owner_uid, :group => @owner_gid)
end
end
end
diff --git a/lib/chef/provider/service/simple.rb b/lib/chef/provider/service/simple.rb
index 0eb983a0bf..bd51d15f84 100644
--- a/lib/chef/provider/service/simple.rb
+++ b/lib/chef/provider/service/simple.rb
@@ -85,16 +85,16 @@ class Chef
end
def start_service
- shell_out!(@new_resource.start_command)
+ shell_out_with_systems_locale!(@new_resource.start_command)
end
def stop_service
- shell_out!(@new_resource.stop_command)
+ shell_out_with_systems_locale!(@new_resource.stop_command)
end
def restart_service
if @new_resource.restart_command
- shell_out!(@new_resource.restart_command)
+ shell_out_with_systems_locale!(@new_resource.restart_command)
else
stop_service
sleep 1
@@ -103,7 +103,7 @@ class Chef
end
def reload_service
- shell_out!(@new_resource.reload_command)
+ shell_out_with_systems_locale!(@new_resource.reload_command)
end
protected
diff --git a/lib/chef/provider/service/solaris.rb b/lib/chef/provider/service/solaris.rb
index 0c47a3462b..f0584dcf6d 100644
--- a/lib/chef/provider/service/solaris.rb
+++ b/lib/chef/provider/service/solaris.rb
@@ -56,7 +56,7 @@ class Chef
alias_method :start_service, :enable_service
def reload_service
- shell_out!("#{default_init_command} refresh #{@new_resource.service_name}")
+ shell_out_with_systems_locale!("#{default_init_command} refresh #{@new_resource.service_name}")
end
def restart_service
diff --git a/lib/chef/provider/service/systemd.rb b/lib/chef/provider/service/systemd.rb
index 6231603d03..31feee65d4 100644
--- a/lib/chef/provider/service/systemd.rb
+++ b/lib/chef/provider/service/systemd.rb
@@ -28,7 +28,7 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
if @new_resource.status_command
Chef::Log.debug("#{@new_resource} you have specified a status command, running..")
- unless shell_out_with_systems_locale(@new_resource.status_command).error?
+ unless shell_out(@new_resource.status_command).error?
@current_resource.running(true)
else
@status_check_success = false
@@ -61,7 +61,7 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
if @new_resource.start_command
super
else
- shell_out_with_systems_locale("/bin/systemctl start #{@new_resource.service_name}")
+ shell_out_with_systems_locale!("/bin/systemctl start #{@new_resource.service_name}")
end
end
end
@@ -73,7 +73,7 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
if @new_resource.stop_command
super
else
- shell_out_with_systems_locale("/bin/systemctl stop #{@new_resource.service_name}")
+ shell_out_with_systems_locale!("/bin/systemctl stop #{@new_resource.service_name}")
end
end
end
@@ -82,7 +82,7 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
if @new_resource.restart_command
super
else
- shell_out_with_systems_locale("/bin/systemctl restart #{@new_resource.service_name}")
+ shell_out_with_systems_locale!("/bin/systemctl restart #{@new_resource.service_name}")
end
end
@@ -91,7 +91,7 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
super
else
if @current_resource.running
- shell_out_with_systems_locale("/bin/systemctl reload #{@new_resource.service_name}")
+ shell_out_with_systems_locale!("/bin/systemctl reload #{@new_resource.service_name}")
else
start_service
end
@@ -99,18 +99,18 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
end
def enable_service
- shell_out_with_systems_locale("/bin/systemctl enable #{@new_resource.service_name}")
+ shell_out!("/bin/systemctl enable #{@new_resource.service_name}")
end
def disable_service
- shell_out_with_systems_locale("/bin/systemctl disable #{@new_resource.service_name}")
+ shell_out!("/bin/systemctl disable #{@new_resource.service_name}")
end
def is_active?
- shell_out_with_systems_locale("/bin/systemctl is-active #{@new_resource.service_name} --quiet").exitstatus == 0
+ shell_out("/bin/systemctl is-active #{@new_resource.service_name} --quiet").exitstatus == 0
end
def is_enabled?
- shell_out_with_systems_locale("/bin/systemctl is-enabled #{@new_resource.service_name} --quiet").exitstatus == 0
+ shell_out("/bin/systemctl is-enabled #{@new_resource.service_name} --quiet").exitstatus == 0
end
end
diff --git a/lib/chef/provider/service/upstart.rb b/lib/chef/provider/service/upstart.rb
index c81a8a50dc..670bf9e5f8 100644
--- a/lib/chef/provider/service/upstart.rb
+++ b/lib/chef/provider/service/upstart.rb
@@ -97,10 +97,10 @@ class Chef
Chef::Log.debug("#{@new_resource} you have specified a status command, running..")
begin
- if run_command_with_systems_locale(:command => @new_resource.status_command) == 0
+ if shell_out!(@new_resource.status_command) == 0
@current_resource.running true
end
- rescue Chef::Exceptions::Exec
+ rescue
@command_success = false
@current_resource.running false
nil
@@ -153,7 +153,7 @@ class Chef
if @new_resource.start_command
super
else
- run_command_with_systems_locale(:command => "/sbin/start #{@job}")
+ shell_out_with_systems_locale!("/sbin/start #{@job}")
end
end
end
@@ -167,7 +167,7 @@ class Chef
if @new_resource.stop_command
super
else
- run_command_with_systems_locale(:command => "/sbin/stop #{@job}")
+ shell_out_with_systems_locale!("/sbin/stop #{@job}")
end
end
end
@@ -179,7 +179,7 @@ class Chef
# Older versions of upstart would fail on restart if the service was currently stopped, check for that. LP:430883
else
if @current_resource.running
- run_command_with_systems_locale(:command => "/sbin/restart #{@job}")
+ shell_out_with_systems_locale!("/sbin/restart #{@job}")
else
start_service
end
@@ -191,7 +191,7 @@ class Chef
super
else
# upstart >= 0.6.3-4 supports reload (HUP)
- run_command_with_systems_locale(:command => "/sbin/reload #{@job}")
+ shell_out_with_systems_locale!("/sbin/reload #{@job}")
end
end
diff --git a/lib/chef/provider/subversion.rb b/lib/chef/provider/subversion.rb
index 81ed639c53..6cf31c8ec8 100644
--- a/lib/chef/provider/subversion.rb
+++ b/lib/chef/provider/subversion.rb
@@ -60,7 +60,7 @@ class Chef
def action_checkout
if target_dir_non_existent_or_empty?
converge_by("perform checkout of #{@new_resource.repository} into #{@new_resource.destination}") do
- run_command(run_options(:command => checkout_command))
+ shell_out!(run_options(command: checkout_command))
end
else
Chef::Log.debug "#{@new_resource} checkout destination #{@new_resource.destination} already exists or is a non-empty directory - nothing to do"
@@ -77,7 +77,7 @@ class Chef
def action_force_export
converge_by("export #{@new_resource.repository} into #{@new_resource.destination}") do
- run_command(run_options(:command => export_command))
+ shell_out!(run_options(command: export_command))
end
end
@@ -88,7 +88,7 @@ class Chef
Chef::Log.debug "#{@new_resource} current revision: #{current_rev} target revision: #{revision_int}"
unless current_revision_matches_target_revision?
converge_by("sync #{@new_resource.destination} from #{@new_resource.repository}") do
- run_command(run_options(:command => sync_command))
+ shell_out!(run_options(command: sync_command))
Chef::Log.info "#{@new_resource} updated to revision: #{revision_int}"
end
end
@@ -100,14 +100,14 @@ class Chef
def sync_command
c = scm :update, @new_resource.svn_arguments, verbose, authentication, "-r#{revision_int}", @new_resource.destination
Chef::Log.debug "#{@new_resource} updated working copy #{@new_resource.destination} to revision #{@new_resource.revision}"
- c
+ c
end
def checkout_command
c = scm :checkout, @new_resource.svn_arguments, verbose, authentication,
"-r#{revision_int}", @new_resource.repository, @new_resource.destination
Chef::Log.info "#{@new_resource} checked out #{@new_resource.repository} at revision #{@new_resource.revision} to #{@new_resource.destination}"
- c
+ c
end
def export_command
@@ -116,7 +116,7 @@ class Chef
"-r#{revision_int}" << @new_resource.repository << @new_resource.destination
c = scm :export, *args
Chef::Log.info "#{@new_resource} exported #{@new_resource.repository} at revision #{@new_resource.revision} to #{@new_resource.destination}"
- c
+ c
end
# If the specified revision isn't an integer ("HEAD" for example), look
diff --git a/lib/chef/provider/whyrun_safe_ruby_block.rb b/lib/chef/provider/whyrun_safe_ruby_block.rb
index 4b491a4f60..e5f35debd7 100644
--- a/lib/chef/provider/whyrun_safe_ruby_block.rb
+++ b/lib/chef/provider/whyrun_safe_ruby_block.rb
@@ -19,7 +19,7 @@
class Chef
class Provider
class WhyrunSafeRubyBlock < Chef::Provider::RubyBlock
- def action_create
+ def action_run
@new_resource.block.call
@new_resource.updated_by_last_action(true)
@run_context.events.resource_update_applied(@new_resource, :create, "execute the whyrun_safe_ruby_block #{@new_resource.name}")
diff --git a/lib/chef/providers.rb b/lib/chef/providers.rb
index 3c9e94e6f7..fec00d0e63 100644
--- a/lib/chef/providers.rb
+++ b/lib/chef/providers.rb
@@ -24,6 +24,7 @@ require 'chef/provider/cron/solaris'
require 'chef/provider/cron/aix'
require 'chef/provider/deploy'
require 'chef/provider/directory'
+require 'chef/provider/dsc_script'
require 'chef/provider/env'
require 'chef/provider/erl_call'
require 'chef/provider/execute'
@@ -39,6 +40,7 @@ require 'chef/provider/mdadm'
require 'chef/provider/mount'
require 'chef/provider/package'
require 'chef/provider/powershell_script'
+require 'chef/provider/reboot'
require 'chef/provider/remote_directory'
require 'chef/provider/remote_file'
require 'chef/provider/route'
@@ -58,6 +60,7 @@ require 'chef/provider/package/easy_install'
require 'chef/provider/package/freebsd/port'
require 'chef/provider/package/freebsd/pkg'
require 'chef/provider/package/freebsd/pkgng'
+require 'chef/provider/package/homebrew'
require 'chef/provider/package/ips'
require 'chef/provider/package/macports'
require 'chef/provider/package/pacman'
diff --git a/lib/chef/resource/dsc_script.rb b/lib/chef/resource/dsc_script.rb
new file mode 100644
index 0000000000..2972ace1aa
--- /dev/null
+++ b/lib/chef/resource/dsc_script.rb
@@ -0,0 +1,140 @@
+#
+# Author:: Adam Edwards (<adamed@getchef.com>)
+# 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 'chef/exceptions'
+
+class Chef
+ class Resource
+ class DscScript < Chef::Resource
+
+ provides :dsc_script, :on_platforms => ["windows"]
+
+ def initialize(name, run_context=nil)
+ super
+ @allowed_actions.push(:run)
+ @action = :run
+ if(run_context && Chef::Platform.supports_dsc?(run_context.node))
+ @provider = Chef::Provider::DscScript
+ else
+ raise Chef::Exceptions::NoProviderAvailable,
+ "#{powershell_info_str(run_context)}\nPowershell 4.0 or higher was not detected on your system and is required to use the dsc_script resource."
+ end
+ end
+
+ def code(arg=nil)
+ if arg && command
+ raise ArgumentError, "Only one of 'code' and 'command' attributes may be specified"
+ end
+ if arg && configuration_name
+ raise ArgumentError, "The 'code' and 'command' attributes may not be used together"
+ end
+ set_or_return(
+ :code,
+ arg,
+ :kind_of => [ String ]
+ )
+ end
+
+ def configuration_name(arg=nil)
+ if arg && code
+ raise ArgumentError, "Attribute `configuration_name` may not be set if `code` is set"
+ end
+ set_or_return(
+ :configuration_name,
+ arg,
+ :kind_of => [ String ]
+ )
+ end
+
+ def command(arg=nil)
+ if arg && code
+ raise ArgumentError, "The 'code' and 'command' attributes may not be used together"
+ end
+ set_or_return(
+ :command,
+ arg,
+ :kind_of => [ String ]
+ )
+ end
+
+ def configuration_data(arg=nil)
+ if arg && configuration_data_script
+ raise ArgumentError, "The 'configuration_data' and 'configuration_data_script' attributes may not be used together"
+ end
+ set_or_return(
+ :configuration_data,
+ arg,
+ :kind_of => [ String ]
+ )
+ end
+
+ def configuration_data_script(arg=nil)
+ if arg && configuration_data
+ raise ArgumentError, "The 'configuration_data' and 'configuration_data_script' attributes may not be used together"
+ end
+ set_or_return(
+ :configuration_data_script,
+ arg,
+ :kind_of => [ String ]
+ )
+ end
+
+ def flags(arg=nil)
+ set_or_return(
+ :flags,
+ arg,
+ :kind_of => [ Hash ]
+ )
+ end
+
+ def cwd(arg=nil)
+ set_or_return(
+ :cwd,
+ arg,
+ :kind_of => [ String ]
+ )
+ end
+
+ def environment(arg=nil)
+ set_or_return(
+ :environment,
+ arg,
+ :kind_of => [ Hash ]
+ )
+ end
+
+ def timeout(arg=nil)
+ set_or_return(
+ :timeout,
+ arg,
+ :kind_of => [ Integer ]
+ )
+ end
+
+ private
+
+ def powershell_info_str(run_context)
+ if run_context && run_context.node[:languages] && run_context.node[:languages][:powershell]
+ install_info = "Powershell #{run_context.node[:languages][:powershell][:version]} was found on the system."
+ else
+ install_info = 'Powershell was not found.'
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/resource/homebrew_package.rb b/lib/chef/resource/homebrew_package.rb
new file mode 100644
index 0000000000..c3fa9ddffc
--- /dev/null
+++ b/lib/chef/resource/homebrew_package.rb
@@ -0,0 +1,34 @@
+#
+# Author:: Joshua Timberman (<joshua@getchef.com>)
+# Author:: Graeme Mathieson (<mathie@woss.name>)
+#
+# Copyright 2011-2013, Opscode, Inc.
+# Copyright 2014, Chef Software, Inc <legal@getchef.com>
+#
+# 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/provider/package'
+require 'chef/resource/package'
+
+class Chef
+ class Resource
+ class HomebrewPackage < Chef::Resource::Package
+ def initialize(name, run_context=nil)
+ super
+ @resource_name = :homebrew_package
+ @provider = Chef::Provider::Package::Homebrew
+ end
+ end
+ end
+end
diff --git a/lib/chef/resource/reboot.rb b/lib/chef/resource/reboot.rb
new file mode 100644
index 0000000000..d6caafdea8
--- /dev/null
+++ b/lib/chef/resource/reboot.rb
@@ -0,0 +1,48 @@
+#
+# Author:: Chris Doherty <cdoherty@getchef.com>)
+# Copyright:: Copyright (c) 2014 Chef, 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/resource'
+
+# In using this resource via notifications, it's important to *only* use
+# immediate notifications. Delayed notifications produce unintuitive and
+# probably undesired results.
+class Chef
+ class Resource
+ class Reboot < Chef::Resource
+ def initialize(name, run_context=nil)
+ super
+ @resource_name = :reboot
+ @provider = Chef::Provider::Reboot
+ @allowed_actions = [:request_reboot, :reboot_now, :cancel]
+
+ @reason = "Reboot by Chef"
+ @delay_mins = 0
+
+ # no default action.
+ end
+
+ def reason(arg=nil)
+ set_or_return(:reason, arg, :kind_of => String)
+ end
+
+ def delay_mins(arg=nil)
+ set_or_return(:delay_mins, arg, :kind_of => Fixnum)
+ end
+ end
+ end
+end
diff --git a/lib/chef/resources.rb b/lib/chef/resources.rb
index 93ff682288..5b938095c6 100644
--- a/lib/chef/resources.rb
+++ b/lib/chef/resources.rb
@@ -28,6 +28,7 @@ require 'chef/resource/deploy'
require 'chef/resource/deploy_revision'
require 'chef/resource/directory'
require 'chef/resource/dpkg_package'
+require 'chef/resource/dsc_script'
require 'chef/resource/easy_install_package'
require 'chef/resource/env'
require 'chef/resource/erl_call'
@@ -39,6 +40,7 @@ require 'chef/resource/gem_package'
require 'chef/resource/git'
require 'chef/resource/group'
require 'chef/resource/http_request'
+require 'chef/resource/homebrew_package'
require 'chef/resource/ifconfig'
require 'chef/resource/link'
require 'chef/resource/log'
@@ -53,6 +55,7 @@ require 'chef/resource/perl'
require 'chef/resource/portage_package'
require 'chef/resource/powershell_script'
require 'chef/resource/python'
+require 'chef/resource/reboot'
require 'chef/resource/registry_key'
require 'chef/resource/remote_directory'
require 'chef/resource/remote_file'
diff --git a/lib/chef/run_context.rb b/lib/chef/run_context.rb
index 3dd53f0f8f..bbe2f9eba0 100644
--- a/lib/chef/run_context.rb
+++ b/lib/chef/run_context.rb
@@ -61,6 +61,9 @@ class Chef
# Event dispatcher for this run.
attr_reader :events
+ # Hash of factoids for a reboot request.
+ attr_reader :reboot_info
+
# Creates a new Chef::RunContext object and populates its fields. This object gets
# used by the Chef Server to generate a fully compiled recipe list for a node.
#
@@ -76,6 +79,7 @@ class Chef
@loaded_recipes = {}
@loaded_attributes = {}
@events = events
+ @reboot_info = {}
@node.run_context = self
@@ -271,6 +275,27 @@ ERROR_MESSAGE
end
end
+ # there are options for how to handle multiple calls to these functions:
+ # 1. first call always wins (never change @reboot_info once set).
+ # 2. last call always wins (happily change @reboot_info whenever).
+ # 3. raise an exception on the first conflict.
+ # 4. disable reboot after this run if anyone ever calls :cancel.
+ # 5. raise an exception on any second call.
+ # 6. ?
+ def request_reboot(reboot_info)
+ Chef::Log::info "Changing reboot status from #{@reboot_info.inspect} to #{reboot_info.inspect}"
+ @reboot_info = reboot_info
+ end
+
+ def cancel_reboot
+ Chef::Log::info "Changing reboot status from #{@reboot_info.inspect} to {}"
+ @reboot_info = {}
+ end
+
+ def reboot_requested?
+ @reboot_info.size > 0
+ end
+
private
def loaded_recipe(cookbook, recipe)
diff --git a/lib/chef/util/dsc/configuration_generator.rb b/lib/chef/util/dsc/configuration_generator.rb
new file mode 100644
index 0000000000..12cd5dc3a2
--- /dev/null
+++ b/lib/chef/util/dsc/configuration_generator.rb
@@ -0,0 +1,115 @@
+#
+# Author:: Adam Edwards (<adamed@getchef.com>)
+#
+# Copyright:: 2014, Chef Software, Inc.
+#
+# 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/util/powershell/cmdlet'
+
+class Chef::Util::DSC
+ class ConfigurationGenerator
+ def initialize(node, config_directory)
+ @node = node
+ @config_directory = config_directory
+ end
+
+ def configuration_document_from_script_code(code, configuration_flags, shellout_flags)
+ Chef::Log.debug("DSC: DSC code:\n '#{code}'")
+ generated_script_path = write_document_generation_script(code, 'chef_dsc')
+ begin
+ configuration_document_from_script_path(generated_script_path, 'chef_dsc', configuration_flags, shellout_flags)
+ ensure
+ ::FileUtils.rm(generated_script_path)
+ end
+ end
+
+ def configuration_document_from_script_path(script_path, configuration_name, configuration_flags, shellout_flags)
+ validate_configuration_name!(configuration_name)
+
+ document_generation_cmdlet = Chef::Util::Powershell::Cmdlet.new(
+ @node,
+ configuration_document_generation_code(script_path, configuration_name))
+
+ merged_configuration_flags = get_merged_configuration_flags!(configuration_flags, configuration_name)
+
+ document_generation_cmdlet.run!(merged_configuration_flags, shellout_flags)
+ configuration_document_location = find_configuration_document(configuration_name)
+
+ if ! configuration_document_location
+ raise RuntimeError, "No DSC configuration for '#{configuration_name}' was generated from supplied DSC script"
+ end
+
+ configuration_document = get_configuration_document(configuration_document_location)
+ ::FileUtils.rm_rf(configuration_document_location)
+ configuration_document
+ end
+
+ protected
+
+ # From PowerShell error help for the Configuration language element:
+ # Standard names may only contain letters (a-z, A-Z), numbers (0-9), and underscore (_).
+ # The name may not be null or empty, and should start with a letter.
+ def validate_configuration_name!(configuration_name)
+ if !!(configuration_name =~ /\A[A-Za-z]+[_a-zA-Z0-9]*\Z/) == false
+ raise ArgumentError, 'Configuration `#{configuration_name}` is not a valid PowerShell cmdlet name'
+ end
+ end
+
+ def get_merged_configuration_flags!(configuration_flags, configuration_name)
+ merged_configuration_flags = { :outputpath => configuration_document_directory(configuration_name) }
+ if configuration_flags
+ configuration_flags.map do | switch, value |
+ if merged_configuration_flags.key?(switch.to_s.downcase.to_sym)
+ raise ArgumentError, "The `flags` attribute for the dsc_script resource contained a command line switch :#{switch.to_s} that is disallowed."
+ end
+ merged_configuration_flags[switch.to_s.downcase.to_sym] = value
+ end
+ end
+ merged_configuration_flags
+ end
+
+ def configuration_code(code, configuration_name)
+ "$ProgressPreference = 'SilentlyContinue';Configuration '#{configuration_name}'\n{\n\tnode 'localhost'\n{\n\t#{code}\n}}\n"
+ end
+
+ def configuration_document_generation_code(configuration_script, configuration_name)
+ ". '#{configuration_script}';#{configuration_name}"
+ end
+
+ def write_document_generation_script(code, configuration_name)
+ script_path = "#{@config_directory}/chef_dsc_config.ps1"
+ ::File.open(script_path, 'wt') do | script |
+ script.write(configuration_code(code, configuration_name))
+ end
+ script_path
+ end
+
+ def find_configuration_document(configuration_name)
+ document_directory = configuration_document_directory(configuration_name)
+ document_file_name = ::Dir.entries(document_directory).find { | path | path =~ /.*.mof/ }
+ ::File.join(document_directory, document_file_name) if document_file_name
+ end
+
+ def configuration_document_directory(configuration_name)
+ ::File.join(@config_directory, configuration_name)
+ end
+
+ def get_configuration_document(document_path)
+ ::File.open(document_path, 'rb') do | file |
+ file.read
+ end
+ end
+ end
+end
diff --git a/lib/chef/util/dsc/lcm_output_parser.rb b/lib/chef/util/dsc/lcm_output_parser.rb
new file mode 100644
index 0000000000..f8f853a33a
--- /dev/null
+++ b/lib/chef/util/dsc/lcm_output_parser.rb
@@ -0,0 +1,133 @@
+#
+# Author:: Jay Mundrawala (<jdm@getchef.com>)
+#
+# Copyright:: 2014, Chef Software, Inc.
+#
+# 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/log'
+require 'chef/util/dsc/resource_info'
+
+class Chef
+ class Util
+ class DSC
+ class LocalConfigurationManager
+ module Parser
+ # Parses the output from LCM and returns a list of Chef::Util::DSC::ResourceInfo objects
+ # that describe how the resources affected the system
+ #
+ # Example:
+ # parse <<-EOF
+ # What if: [Machine]: LCM: [Start Set ]
+ # What if: [Machine]: LCM: [Start Resource ] [[File]FileToNotBeThere]
+ # What if: [Machine]: LCM: [Start Set ] [[File]FileToNotBeThere]
+ # What if: [C:\ShouldNotExist.txt] removed
+ # What if: [Machine]: LCM: [End Set ] [[File]FileToNotBeThere] in 0.1 seconds
+ # What if: [Machine]: LCM: [End Resource ] [[File]FileToNotBeThere]
+ # What if: [Machine]: LCM: [End Set ]
+ # EOF
+ #
+ # would return
+ #
+ # [
+ # Chef::Util::DSC::ResourceInfo.new(
+ # '[[File]FileToNotBeThere]',
+ # true,
+ # [
+ # '[[File]FileToNotBeThere]',
+ # '[C:\Shouldnotexist.txt]',
+ # '[[File]FileToNotBeThere] in 0.1 seconds'
+ # ]
+ # )
+ # ]
+ #
+ def self.parse(lcm_output)
+ return [] unless lcm_output
+
+ current_resource = Hash.new
+
+ resources = []
+ lcm_output.lines.each do |line|
+ op_action, op_type, info = parse_line(line)
+
+ case op_action
+ when :start
+ case op_type
+ when :set
+ if current_resource[:name]
+ current_resource[:context] = :logging
+ current_resource[:logs] = [info]
+ end
+ when :resource
+ if current_resource[:name]
+ resources.push(current_resource)
+ end
+ current_resource = {:name => info}
+ else
+ Chef::Log.debug("Ignoring op_action #{op_action}: Read line #{line}")
+ end
+ when :end
+ # Make sure we log the last line
+ if current_resource[:context] == :logging and info.include? current_resource[:name]
+ current_resource[:logs].push(info)
+ end
+ current_resource[:context] = nil
+ when :skip
+ current_resource[:skipped] = true
+ when :info
+ if current_resource[:context] == :logging
+ current_resource[:logs].push(info)
+ end
+ end
+ end
+
+ if current_resource[:name]
+ resources.push(current_resource)
+ end
+
+ build_resource_info(resources)
+ end
+
+ def self.parse_line(line)
+ if match = line.match(/^.*?:.*?:\s*LCM:\s*\[(.*?)\](.*)/)
+ # If the line looks like
+ # What If: [machinename]: LCM: [op_action op_type] message
+ # extract op_action, op_type, and message
+ operation, info = match.captures
+ op_action, op_type = operation.strip.split(' ').map {|m| m.downcase.to_sym}
+ else
+ op_action = op_type = :info
+ if match = line.match(/^.*?:.*?: \s+(.*)/)
+ info = match.captures[0]
+ else
+ info = line
+ end
+ end
+ info.strip! # Because this was formatted for humans
+ return [op_action, op_type, info]
+ end
+ private_class_method :parse_line
+
+ def self.build_resource_info(resources)
+ resources.map do |r|
+ Chef::Util::DSC::ResourceInfo.new(r[:name], !r[:skipped], r[:logs])
+ end
+ end
+ private_class_method :build_resource_info
+
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/util/dsc/local_configuration_manager.rb b/lib/chef/util/dsc/local_configuration_manager.rb
new file mode 100644
index 0000000000..4a56b6a397
--- /dev/null
+++ b/lib/chef/util/dsc/local_configuration_manager.rb
@@ -0,0 +1,137 @@
+#
+# Author:: Adam Edwards (<adamed@getchef.com>)
+#
+# Copyright:: 2014, Chef Software, Inc.
+#
+# 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/util/powershell/cmdlet'
+require 'chef/util/dsc/lcm_output_parser'
+
+class Chef::Util::DSC
+ class LocalConfigurationManager
+ def initialize(node, configuration_path)
+ @node = node
+ @configuration_path = configuration_path
+ clear_execution_time
+ end
+
+ def test_configuration(configuration_document)
+ status = run_configuration_cmdlet(configuration_document)
+ handle_what_if_exception!(status.stderr) unless status.succeeded?
+ configuration_update_required?(status.return_value)
+ end
+
+ def set_configuration(configuration_document)
+ run_configuration_cmdlet(configuration_document, true)
+ end
+
+ def last_operation_execution_time_seconds
+ if @operation_start_time && @operation_end_time
+ @operation_end_time - @operation_start_time
+ end
+ end
+
+ private
+
+ def run_configuration_cmdlet(configuration_document, apply_configuration = false)
+ Chef::Log.debug("DSC: Calling DSC Local Config Manager to #{apply_configuration ? "set" : "test"} configuration document.")
+ test_only_parameters = ! apply_configuration ? '-whatif; if (! $?) { exit 1 }' : ''
+
+ start_operation_timing
+ command_code = lcm_command_code(@configuration_path, test_only_parameters)
+ status = nil
+
+ begin
+ save_configuration_document(configuration_document)
+ cmdlet = ::Chef::Util::Powershell::Cmdlet.new(@node, "#{command_code}")
+ if apply_configuration
+ status = cmdlet.run!
+ else
+ status = cmdlet.run
+ end
+ ensure
+ end_operation_timing
+ remove_configuration_document
+ if last_operation_execution_time_seconds
+ Chef::Log.debug("DSC: DSC operation completed in #{last_operation_execution_time_seconds} seconds.")
+ end
+ end
+ Chef::Log.debug("DSC: Completed call to DSC Local Config Manager")
+ status
+ end
+
+ def lcm_command_code(configuration_path, test_only_parameters)
+ <<-EOH
+$ProgressPreference = 'SilentlyContinue';start-dscconfiguration -path #{@configuration_path} -wait -erroraction 'continue' -force #{test_only_parameters}
+EOH
+ end
+
+ def handle_what_if_exception!(what_if_exception_output)
+ if what_if_exception_output.gsub(/\s+/, ' ') =~ /A parameter cannot be found that matches parameter name 'Whatif'/i
+ # LCM returns an error if any of the resources do not support the opptional What-If
+ Chef::Log::warn("Received error while testing configuration due to resource not supporting 'WhatIf'")
+ elsif output_has_dsc_module_failure?(what_if_exception_output)
+ Chef::Log::warn("Received error while testing configuration due to a module for an imported resource possibly not being fully installed:\n#{what_if_exception_output.gsub(/\s+/, ' ')}")
+ else
+ raise Chef::Exceptions::PowershellCmdletException, "Powershell Cmdlet failed: #{what_if_exception_output.gsub(/\s+/, ' ')}"
+ end
+ end
+
+ def output_has_dsc_module_failure?(what_if_output)
+ !! (what_if_output =~ /\sCimException/ &&
+ what_if_output =~ /ProviderOperationExecutionFailure/ &&
+ what_if_output =~ /\smodule\s+is\s+installed/)
+ end
+
+ def configuration_update_required?(what_if_output)
+ Chef::Log.debug("DSC: DSC returned the following '-whatif' output from test operation:\n#{what_if_output}")
+ begin
+ Parser::parse(what_if_output)
+ rescue Chef::Util::DSC::LocalConfigurationManager::Parser => e
+ Chef::Log::warn("Could not parse LCM output: #{e}")
+ [Chef::Util::DSC::ResourceInfo.new('Unknown DSC Resources', true, ['Unknown changes because LCM output was not parsable.'])]
+ end
+ end
+
+ def save_configuration_document(configuration_document)
+ ::FileUtils.mkdir_p(@configuration_path)
+ ::File.open(configuration_document_path, 'wb') do | file |
+ file.write(configuration_document)
+ end
+ end
+
+ def remove_configuration_document
+ ::FileUtils.rm(configuration_document_path)
+ end
+
+ def configuration_document_path
+ File.join(@configuration_path,'..mof')
+ end
+
+ def clear_execution_time
+ @operation_start_time = nil
+ @operation_end_time = nil
+ end
+
+ def start_operation_timing
+ clear_execution_time
+ @operation_start_time = Time.now
+ end
+
+ def end_operation_timing
+ @operation_end_time = Time.now
+ end
+ end
+end
diff --git a/lib/chef/util/dsc/resource_info.rb b/lib/chef/util/dsc/resource_info.rb
new file mode 100644
index 0000000000..4a32451721
--- /dev/null
+++ b/lib/chef/util/dsc/resource_info.rb
@@ -0,0 +1,26 @@
+
+class Chef
+ class Util
+ class DSC
+ class ResourceInfo
+ # The name is the text following [Start Set]
+ attr_reader :name
+
+ # A list of all log messages between [Start Set] and [End Set].
+ # Each line is an element in the list.
+ attr_reader :change_log
+
+ def initialize(name, sets, change_log)
+ @name = name
+ @sets = sets
+ @change_log = change_log || []
+ end
+
+ # Does this resource change the state of the system?
+ def changes_state?
+ @sets
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/util/powershell/cmdlet.rb b/lib/chef/util/powershell/cmdlet.rb
new file mode 100644
index 0000000000..40edbb13c6
--- /dev/null
+++ b/lib/chef/util/powershell/cmdlet.rb
@@ -0,0 +1,136 @@
+#
+# Author:: Adam Edwards (<adamed@getchef.com>)
+#
+# Copyright:: 2014, Chef Software, Inc.
+#
+# 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 'mixlib/shellout'
+require 'chef/mixin/windows_architecture_helper'
+require 'chef/util/powershell/cmdlet_result'
+
+class Chef::Util::Powershell
+ class Cmdlet
+ def initialize(node, cmdlet, output_format=nil, output_format_options={})
+ @output_format = output_format
+ @node = node
+
+ case output_format
+ when nil
+ @json_format = false
+ when :json
+ @json_format = true
+ when :text
+ @json_format = false
+ when :object
+ @json_format = true
+ else
+ raise ArgumentError, "Invalid output format #{output_format.to_s} specified"
+ end
+
+ @cmdlet = cmdlet
+ @output_format_options = output_format_options
+ end
+
+ attr_reader :output_format
+
+ def run(switches={}, execution_options={}, *arguments)
+ arguments_string = arguments.join(' ')
+
+ switches_string = command_switches_string(switches)
+
+ json_depth = 5
+
+ if @json_format && @output_format_options.has_key?(:depth)
+ json_depth = @output_format_options[:depth]
+ end
+
+ json_command = @json_format ? " | convertto-json -compress -depth #{json_depth}" : ""
+ command_string = "powershell.exe -executionpolicy bypass -noprofile -noninteractive -command \"trap [Exception] {write-error -exception ($_.Exception.Message);exit 1};#{@cmdlet} #{switches_string} #{arguments_string}#{json_command}\";if ( ! $? ) { exit 1 }"
+
+ augmented_options = {:returns => [0], :live_stream => false}.merge(execution_options)
+ command = Mixlib::ShellOut.new(command_string, augmented_options)
+
+ os_architecture = "#{ENV['PROCESSOR_ARCHITEW6432']}" == 'AMD64' ? :x86_64 : :i386
+
+ status = nil
+
+ with_os_architecture(@node) do
+ status = command.run_command
+ end
+
+ CmdletResult.new(status, @output_format)
+ end
+
+ def run!(switches={}, execution_options={}, *arguments)
+ result = run(switches, execution_options, arguments)
+
+ if ! result.succeeded?
+ raise Chef::Exceptions::PowershellCmdletException, "Powershell Cmdlet failed: #{result.stderr}"
+ end
+
+ result
+ end
+
+ protected
+
+ include Chef::Mixin::WindowsArchitectureHelper
+
+ def validate_switch_name!(switch_parameter_name)
+ if !!(switch_parameter_name =~ /\A[A-Za-z]+[_a-zA-Z0-9]*\Z/) == false
+ raise ArgumentError, "`#{switch_parameter_name}` is not a valid PowerShell cmdlet switch parameter name"
+ end
+ end
+
+ def escape_parameter_value(parameter_value)
+ parameter_value.gsub(/(`|'|"|#)/,'`\1')
+ end
+
+ def escape_string_parameter_value(parameter_value)
+ "'#{escape_parameter_value(parameter_value)}'"
+ end
+
+ def command_switches_string(switches)
+ command_switches = switches.map do | switch_name, switch_value |
+ if switch_name.class != Symbol
+ raise ArgumentError, "Invalid type `#{switch_name} `for PowerShell switch '#{switch_name.to_s}'. The switch must be specified as a Symbol'"
+ end
+
+ validate_switch_name!(switch_name)
+
+ switch_argument = ''
+ switch_present = true
+
+ case switch_value
+ when Numeric
+ switch_argument = switch_value.to_s
+ when Float
+ switch_argument = switch_value.to_s
+ when FalseClass
+ switch_present = false
+ when TrueClass
+ when String
+ switch_argument = escape_string_parameter_value(switch_value)
+ else
+ raise ArgumentError, "Invalid argument type `#{switch_value.class}` specified for PowerShell switch `:#{switch_name.to_s}`. Arguments to PowerShell must be of type `String`, `Numeric`, `Float`, `FalseClass`, or `TrueClass`"
+ end
+
+ switch_present ? ["-#{switch_name.to_s.downcase}", switch_argument].join(' ').strip : ''
+ end
+
+ command_switches.join(' ')
+ end
+ end
+end
+
diff --git a/lib/chef/util/powershell/cmdlet_result.rb b/lib/chef/util/powershell/cmdlet_result.rb
new file mode 100644
index 0000000000..af7b3607cd
--- /dev/null
+++ b/lib/chef/util/powershell/cmdlet_result.rb
@@ -0,0 +1,46 @@
+#
+# Author:: Adam Edwards (<adamed@getchef.com>)
+#
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+#
+# 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 'json'
+
+class Chef::Util::Powershell
+ class CmdletResult
+ attr_reader :output_format
+
+ def initialize(status, output_format)
+ @status = status
+ @output_format = output_format
+ end
+
+ def stderr
+ @status.stderr
+ end
+
+ def return_value
+ if output_format == :object
+ JSON.parse(@status.stdout)
+ else
+ @status.stdout
+ end
+ end
+
+ def succeeded?
+ @succeeded = @status.status.exitstatus == 0
+ end
+ end
+end
diff --git a/lib/chef/version.rb b/lib/chef/version.rb
index be449d4fa0..b2d3fe57ee 100644
--- a/lib/chef/version.rb
+++ b/lib/chef/version.rb
@@ -17,7 +17,7 @@
class Chef
CHEF_ROOT = File.dirname(File.expand_path(File.dirname(__FILE__)))
- VERSION = '12.0.0.alpha.1'
+ VERSION = '12.0.0.alpha.2'
end
#
diff --git a/lib/chef/win32/api/file.rb b/lib/chef/win32/api/file.rb
index 7a8dafd8b5..da9713e119 100644
--- a/lib/chef/win32/api/file.rb
+++ b/lib/chef/win32/api/file.rb
@@ -459,11 +459,7 @@ BOOL WINAPI DeviceIoControl(
# to be passed to the *W vesion of WinAPI File
# functions
def encode_path(path)
- (path_prepender << path.gsub(::File::SEPARATOR, ::File::ALT_SEPARATOR)).to_wstring
- end
-
- def path_prepender
- "\\\\?\\"
+ Chef::Util::PathHelper.canonical_path(path).to_wstring
end
# retrieves a file search handle and passes it
diff --git a/pedant.gemfile b/pedant.gemfile
index 7b135bdef4..d4ac849707 100644
--- a/pedant.gemfile
+++ b/pedant.gemfile
@@ -7,6 +7,9 @@ gem 'chef-pedant', :github => 'opscode/chef-pedant', :branch => "metadata-name-f
# TODO figure out how to grab this stuff from the main Gemfile
gem "activesupport", "< 4.0.0", :group => :compat_testing, :platform => "ruby"
+gem "mixlib-shellout", github: "opscode/mixlib-shellout", branch: "master"
+gem "ohai", github: "opscode/ohai", branch: "master"
+
group(:docgen) do
gem "yard"
end
diff --git a/spec/functional/mixin/shell_out_spec.rb b/spec/functional/mixin/shell_out_spec.rb
index 92492fcf6f..35e5b30eae 100644
--- a/spec/functional/mixin/shell_out_spec.rb
+++ b/spec/functional/mixin/shell_out_spec.rb
@@ -29,7 +29,7 @@ describe Chef::Mixin::ShellOut do
shell_out_with_systems_locale('echo $LC_ALL')
end
- cmd.stdout.chomp.should match_environment_variable('LC_ALL')
+ expect(cmd.stdout.chomp).to match_environment_variable('LC_ALL')
end
end
@@ -41,7 +41,7 @@ describe Chef::Mixin::ShellOut do
shell_out_with_systems_locale('echo $LC_ALL', :environment => {'LC_ALL' => 'POSIX'})
end
- cmd.stdout.chomp.should eq 'POSIX'
+ expect(cmd.stdout.chomp).to eq 'POSIX'
end
end
end
diff --git a/spec/functional/provider/whyrun_safe_ruby_block_spec.rb b/spec/functional/provider/whyrun_safe_ruby_block_spec.rb
new file mode 100644
index 0000000000..150d46d384
--- /dev/null
+++ b/spec/functional/provider/whyrun_safe_ruby_block_spec.rb
@@ -0,0 +1,51 @@
+#
+# Author:: Serdar Sutay (<serdar@opscode.com>)
+# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+describe Chef::Resource::WhyrunSafeRubyBlock do
+ let(:node) { Chef::Node.new }
+
+ let(:run_context) {
+ events = Chef::EventDispatch::Dispatcher.new
+ Chef::RunContext.new(node, {}, events)
+ }
+
+ before do
+ $evil_global_evil_laugh = :wahwah
+ Chef::Config[:why_run] = true
+ end
+
+ after do
+ Chef::Config[:why_run] = false
+ end
+
+ describe "when testing the resource" do
+ let(:new_resource) do
+ r = Chef::Resource::WhyrunSafeRubyBlock.new("reload all", run_context)
+ r.block { $evil_global_evil_laugh = :mwahahaha }
+ r
+ end
+
+ it "updates the evil laugh, even in why-run mode" do
+ new_resource.run_action(new_resource.action)
+ $evil_global_evil_laugh.should == :mwahahaha
+ new_resource.should be_updated
+ end
+ end
+end
diff --git a/spec/functional/rebooter_spec.rb b/spec/functional/rebooter_spec.rb
new file mode 100644
index 0000000000..8006580d5c
--- /dev/null
+++ b/spec/functional/rebooter_spec.rb
@@ -0,0 +1,105 @@
+#
+# Author:: Chris Doherty <cdoherty@getchef.com>)
+# Copyright:: Copyright (c) 2014 Chef, 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::Platform::Rebooter do
+
+ let(:reboot_info) do
+ {
+ :delay_mins => 5,
+ :requested_by => "reboot resource functional test",
+ :reason => "rebooter spec test"
+ }
+ end
+
+ def create_resource
+ resource = Chef::Resource::Reboot.new(expected[:requested_by], run_context)
+ resource.delay_mins(expected[:delay_mins])
+ resource.reason(expected[:reason])
+ resource
+ end
+
+ let(:run_context) do
+ node = Chef::Node.new
+ events = Chef::EventDispatch::Dispatcher.new
+ Chef::RunContext.new(node, {}, events)
+ end
+
+ let(:expected) do
+ {
+ :windows => 'shutdown /r /t 5 /c "rebooter spec test"',
+ :linux => 'shutdown -r +5 "rebooter spec test"'
+ }
+ end
+
+ let(:rebooter) { Chef::Platform::Rebooter }
+
+ describe '#reboot_if_needed!' do
+
+ it 'should not call #shell_out! when reboot has not been requested' do
+ expect(rebooter).to receive(:shell_out!).exactly(0).times
+ expect(rebooter).to receive(:reboot_if_needed!).once.and_call_original
+ rebooter.reboot_if_needed!(run_context.node)
+ end
+
+ describe 'calling #shell_out! to reboot' do
+
+ before(:each) do
+ run_context.request_reboot(reboot_info)
+ end
+
+ after(:each) do
+ run_context.cancel_reboot
+ end
+
+ shared_context 'test a reboot method' do
+ def test_rebooter_method(method_sym, is_windows, expected_reboot_str)
+ Chef::Platform.stub(:windows?).and_return(is_windows)
+ expect(rebooter).to receive(:shell_out!).once.with(expected_reboot_str)
+ expect(rebooter).to receive(method_sym).once.and_call_original
+ rebooter.send(method_sym, run_context.node)
+ end
+ end
+
+ describe 'when using #reboot_if_needed!' do
+ include_context 'test a reboot method'
+
+ it 'should produce the correct string on Windows' do
+ test_rebooter_method(:reboot_if_needed!, true, expected[:windows])
+ end
+
+ it 'should produce the correct (Linux-specific) string on non-Windows' do
+ test_rebooter_method(:reboot_if_needed!, false, expected[:linux])
+ end
+ end
+
+ describe 'when using #reboot!' do
+ include_context 'test a reboot method'
+
+ it 'should produce the correct string on Windows' do
+ test_rebooter_method(:reboot!, true, expected[:windows])
+ end
+
+ it 'should produce the correct (Linux-specific) string on non-Windows' do
+ test_rebooter_method(:reboot!, false, expected[:linux])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/functional/resource/deploy_revision_spec.rb b/spec/functional/resource/deploy_revision_spec.rb
index 9ff1391e35..eae422ac1d 100644
--- a/spec/functional/resource/deploy_revision_spec.rb
+++ b/spec/functional/resource/deploy_revision_spec.rb
@@ -59,7 +59,6 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
let(:event_dispatch) { Chef::EventDispatch::Dispatcher.new }
let(:run_context) { Chef::RunContext.new(node, {}, event_dispatch) }
-
# These tests use git's bundle feature, which is a way to export an entire
# git repo (or subset of commits) as a single file.
#
@@ -799,7 +798,6 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
deploy_to_latest_with_callback_tracking.run_action(:deploy)
end
-
let(:deploy_that_fails) do
resource = deploy_to_latest_rev.dup
errant_callback = lambda {|x| raise Exception, "I am a failed deploy" }
@@ -882,5 +880,3 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
end
end
-
-
diff --git a/spec/functional/resource/dsc_script_spec.rb b/spec/functional/resource/dsc_script_spec.rb
new file mode 100644
index 0000000000..fa13296c02
--- /dev/null
+++ b/spec/functional/resource/dsc_script_spec.rb
@@ -0,0 +1,337 @@
+#
+# Author:: Adam Edwards (<adamed@getchef.com>)
+# 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/shell_out'
+require 'chef/mixin/windows_architecture_helper'
+
+describe Chef::Resource::DscScript, :windows_powershell_dsc_only do
+ include Chef::Mixin::WindowsArchitectureHelper
+ before(:all) do
+ @temp_dir = ::Dir.mktmpdir("dsc-functional-test")
+ end
+
+ after(:all) do
+ ::FileUtils.rm_rf(@temp_dir) if ::Dir.exist?(@temp_dir)
+ end
+
+ include Chef::Mixin::ShellOut
+
+ def create_config_script_from_code(code, configuration_name, data = false)
+ script_code = data ? code : "Configuration '#{configuration_name}'\n{\n\t#{code}\n}\n"
+ data_suffix = data ? '_config_data' : ''
+ extension = data ? 'psd1' : 'ps1'
+ script_path = "#{@temp_dir}/dsc_functional_test#{data_suffix}.#{extension}"
+ ::File.open(script_path, 'wt') do | script |
+ script.write(script_code)
+ end
+ script_path
+ end
+
+ def user_exists?(target_user)
+ result = false
+ begin
+ shell_out!("net user #{target_user}")
+ result = true
+ rescue Mixlib::ShellOut::ShellCommandFailed
+ end
+ result
+ end
+
+ def delete_user(target_user)
+ begin
+ shell_out!("net user #{target_user} /delete")
+ rescue Mixlib::ShellOut::ShellCommandFailed
+ end
+ end
+
+ let(:dsc_env_variable) { 'chefenvtest' }
+ let(:dsc_env_value1) { 'value1' }
+ let(:env_value2) { 'value2' }
+ let(:dsc_test_run_context) {
+ node = Chef::Node.new
+ node.automatic['platform'] = 'windows'
+ node.automatic['platform_version'] = '6.1'
+ node.automatic['kernel'][:machine] =
+ is_i386_process_on_x86_64_windows? ? :x86_64 : :i386
+ node.automatic[:languages][:powershell][:version] = '4.0'
+ empty_events = Chef::EventDispatch::Dispatcher.new
+ Chef::RunContext.new(node, {}, empty_events)
+ }
+ let(:dsc_test_resource_name) { 'DSCTest' }
+ let(:dsc_test_resource_base) {
+ Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context)
+ }
+ let(:test_registry_key) { 'HKEY_LOCAL_MACHINE\Software\Chef\Spec\Functional\Resource\dsc_script_spec' }
+ let(:test_registry_value) { 'Registration' }
+ let(:test_registry_data1) { 'LL927' }
+ let(:test_registry_data2) { 'LL928' }
+ let(:dsc_code) { <<-EOH
+ Registry "ChefRegKey"
+ {
+ Key = '#{test_registry_key}'
+ ValueName = '#{test_registry_value}'
+ ValueData = '#{test_registry_data}'
+ Ensure = 'Present'
+ }
+EOH
+ }
+
+ let(:dsc_user_prefix) { 'dsc' }
+ let(:dsc_user_suffix) { 'chefx' }
+ let(:dsc_user) {"#{dsc_user_prefix}_usr_#{dsc_user_suffix}" }
+ let(:dsc_user_prefix_env_var_name) { 'dsc_user_env_prefix' }
+ let(:dsc_user_suffix_env_var_name) { 'dsc_user_env_suffix' }
+ let(:dsc_user_prefix_env_code) { "$env:#{dsc_user_prefix_env_var_name}"}
+ let(:dsc_user_suffix_env_code) { "$env:#{dsc_user_suffix_env_var_name}"}
+ let(:dsc_user_prefix_param_name) { 'dsc_user_prefix_param' }
+ let(:dsc_user_suffix_param_name) { 'dsc_user_suffix_param' }
+ let(:dsc_user_prefix_param_code) { "$#{dsc_user_prefix_param_name}"}
+ let(:dsc_user_suffix_param_code) { "$#{dsc_user_suffix_param_name}"}
+ let(:dsc_user_env_code) { "\"$(#{dsc_user_prefix_env_code})_usr_$(#{dsc_user_suffix_env_code})\""}
+ let(:dsc_user_param_code) { "\"$(#{dsc_user_prefix_param_code})_usr_$(#{dsc_user_suffix_param_code})\""}
+
+ let(:config_flags) { nil }
+ let(:config_params) { <<-EOH
+
+ [CmdletBinding()]
+ param
+ (
+ $#{dsc_user_prefix_param_name},
+ $#{dsc_user_suffix_param_name}
+ )
+EOH
+ }
+
+ let(:config_param_section) { '' }
+ let(:dsc_user_code) { "'#{dsc_user}'" }
+ let(:dsc_user_prefix_code) { dsc_user_prefix }
+ let(:dsc_user_suffix_code) { dsc_user_suffix }
+ let(:dsc_script_environment_attribute) { nil }
+ let(:dsc_user_resources_code) { <<-EOH
+ #{config_param_section}
+node localhost
+{
+$testuser = #{dsc_user_code}
+$testpassword = ConvertTo-SecureString -String "jf9a8m49jrajf4#" -AsPlainText -Force
+$testcred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $testuser, $testpassword
+
+User dsctestusercreate
+{
+ UserName = $testuser
+ Password = $testcred
+ Description = "DSC test user"
+ Ensure = "Present"
+ Disabled = $false
+ PasswordNeverExpires = $true
+ PasswordChangeRequired = $false
+}
+}
+EOH
+ }
+
+ let(:dsc_user_config_data) {
+<<-EOH
+@{
+ AllNodes = @(
+ @{
+ NodeName = "localhost";
+ PSDscAllowPlainTextPassword = $true
+ }
+ )
+}
+
+EOH
+ }
+
+ let(:dsc_environment_env_var_name) { 'dsc_test_cwd' }
+ let(:dsc_environment_no_fail_not_etc_directory) { "#{ENV['systemroot']}\\system32" }
+ let(:dsc_environment_fail_etc_directory) { "#{ENV['systemroot']}\\system32\\drivers\\etc" }
+ let(:exception_message_signature) { 'LL927-LL928' }
+ let(:dsc_environment_config) {<<-EOH
+if (($pwd.path -eq '#{dsc_environment_fail_etc_directory}') -and (test-path('#{dsc_environment_fail_etc_directory}')))
+{
+ throw 'Signature #{exception_message_signature}: Purposefully failing because cwd == #{dsc_environment_fail_etc_directory}'
+}
+environment "whatsmydir"
+{
+ Name = '#{dsc_environment_env_var_name}'
+ Value = $pwd.path
+ Ensure = 'Present'
+}
+EOH
+ }
+
+ let(:dsc_config_name) {
+ dsc_test_resource_base.name
+ }
+ let(:dsc_resource_from_code) {
+ dsc_test_resource_base.code(dsc_code)
+ dsc_test_resource_base
+ }
+ let(:config_name_value) { dsc_test_resource_base.name }
+
+ let(:dsc_resource_from_path) {
+ dsc_test_resource_base.command(create_config_script_from_code(dsc_code, config_name_value))
+ dsc_test_resource_base
+ }
+
+ before(:each) do
+ test_key_resource = Chef::Resource::RegistryKey.new(test_registry_key, dsc_test_run_context)
+ test_key_resource.recursive(true)
+ test_key_resource.run_action(:delete_key)
+ end
+
+ after(:each) do
+ test_key_resource = Chef::Resource::RegistryKey.new(test_registry_key, dsc_test_run_context)
+ test_key_resource.recursive(true)
+ test_key_resource.run_action(:delete_key)
+ end
+
+ shared_examples_for 'a dsc_script resource with specified PowerShell configuration code' do
+ let(:test_registry_data) { test_registry_data1 }
+ it 'should create a registry key with a specific registry value and data' do
+ expect(dsc_test_resource.registry_key_exists?(test_registry_key)).to eq(false)
+ dsc_test_resource.run_action(:run)
+ expect(dsc_test_resource.registry_key_exists?(test_registry_key)).to eq(true)
+ expect(dsc_test_resource.registry_value_exists?(test_registry_key, {:name => test_registry_value, :type => :string, :data => test_registry_data})).to eq(true)
+ end
+
+ it_should_behave_like 'a dsc_script resource with configuration affected by cwd'
+ end
+
+ shared_examples_for 'a dsc_script resource with configuration affected by cwd' do
+ after(:each) do
+ removal_resource = Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context)
+ removal_resource.code <<-EOH
+environment 'removethis'
+{
+ Name = '#{dsc_environment_env_var_name}'
+ Ensure = 'Absent'
+}
+EOH
+ removal_resource.run_action(:run)
+ end
+ let(:dsc_code) { dsc_environment_config }
+ it 'should not raise an exception if the cwd is not etc' do
+ dsc_test_resource.cwd(dsc_environment_no_fail_not_etc_directory)
+ expect {dsc_test_resource.run_action(:run)}.not_to raise_error
+ end
+
+ it 'should raise an exception if the cwd is etc' do
+ dsc_test_resource.cwd(dsc_environment_fail_etc_directory)
+ expect {dsc_test_resource.run_action(:run)}.to raise_error(Chef::Exceptions::PowershellCmdletException)
+ begin
+ dsc_test_resource.run_action(:run)
+ rescue Chef::Exceptions::PowershellCmdletException => e
+ expect(e.message).to match(exception_message_signature)
+ end
+ end
+ end
+
+ shared_examples_for 'a parameterized DSC configuration script' do
+ context 'when specifying environment variables in the environment attribute' do
+ let(:dsc_user_prefix_code) { dsc_user_prefix_env_code }
+ let(:dsc_user_suffix_code) { dsc_user_suffix_env_code }
+ it_behaves_like 'a dsc_script with configuration that uses environment variables'
+ end
+ end
+
+ shared_examples_for 'a dsc_script with configuration data' do
+ context 'when using the configuration_data attribute' do
+ let(:configuration_data_attribute) { 'configuration_data' }
+ it_behaves_like 'a dsc_script with configuration data set via an attribute'
+ end
+
+ context 'when using the configuration_data_script attribute' do
+ let(:configuration_data_attribute) { 'configuration_data_script' }
+ it_behaves_like 'a dsc_script with configuration data set via an attribute'
+ end
+ end
+
+ shared_examples_for 'a dsc_script with configuration data set via an attribute' do
+ it 'should run a configuration script that creates a user' do
+ config_data_value = dsc_user_config_data
+ dsc_test_resource.configuration_name(config_name_value)
+ if configuration_data_attribute == 'configuration_data_script'
+ config_data_value = create_config_script_from_code(dsc_user_config_data, '', true)
+ end
+ dsc_test_resource.environment({dsc_user_prefix_env_var_name => dsc_user_prefix,
+ dsc_user_suffix_env_var_name => dsc_user_suffix})
+ dsc_test_resource.send(configuration_data_attribute, config_data_value)
+ dsc_test_resource.flags(config_flags)
+ expect(user_exists?(dsc_user)).to eq(false)
+ expect {dsc_test_resource.run_action(:run)}.not_to raise_error
+ expect(user_exists?(dsc_user)).to eq(true)
+ end
+ end
+
+ shared_examples_for 'a dsc_script with configuration data that takes parameters' do
+ context 'when script code takes parameters for configuration' do
+ let(:dsc_user_code) { dsc_user_param_code }
+ let(:config_param_section) { config_params }
+ let(:config_flags) {{:"#{dsc_user_prefix_param_name}" => "#{dsc_user_prefix}", :"#{dsc_user_suffix_param_name}" => "#{dsc_user_suffix}"}}
+ it 'does not directly contain the user name' do
+ configuration_script_content = ::File.open(dsc_test_resource.command) do | file |
+ file.read
+ end
+ expect(configuration_script_content.include?(dsc_user)).to be(false)
+ end
+ it_behaves_like 'a dsc_script with configuration data'
+ end
+
+ end
+
+ shared_examples_for 'a dsc_script with configuration data that uses environment variables' do
+ context 'when script code uses environment variables' do
+ let(:dsc_user_code) { dsc_user_env_code }
+
+ it 'does not directly contain the user name' do
+ configuration_script_content = ::File.open(dsc_test_resource.command) do | file |
+ file.read
+ end
+ expect(configuration_script_content.include?(dsc_user)).to be(false)
+ end
+ it_behaves_like 'a dsc_script with configuration data'
+ end
+ end
+
+ context 'when supplying configuration through the configuration attribute' do
+ let(:dsc_test_resource) { dsc_resource_from_code }
+ it_behaves_like 'a dsc_script resource with specified PowerShell configuration code'
+ end
+
+ context 'when supplying configuration using the path attribute' do
+ let(:dsc_test_resource) { dsc_resource_from_path }
+ it_behaves_like 'a dsc_script resource with specified PowerShell configuration code'
+ end
+
+ context 'when running a configuration that manages users' do
+ before(:each) do
+ delete_user(dsc_user)
+ end
+
+ let(:dsc_code) { dsc_user_resources_code }
+ let(:config_name_value) { 'DSCTestConfig' }
+ let(:dsc_test_resource) { dsc_resource_from_path }
+
+ it_behaves_like 'a dsc_script with configuration data'
+ it_behaves_like 'a dsc_script with configuration data that uses environment variables'
+ it_behaves_like 'a dsc_script with configuration data that takes parameters'
+ end
+end
diff --git a/spec/functional/resource/file_spec.rb b/spec/functional/resource/file_spec.rb
index d6f56db3e9..99966f85c8 100644
--- a/spec/functional/resource/file_spec.rb
+++ b/spec/functional/resource/file_spec.rb
@@ -24,12 +24,18 @@ describe Chef::Resource::File do
let(:file_base) { "file_spec" }
let(:expected_content) { "Don't fear the ruby." }
- def create_resource
+ def create_resource(opts={})
events = Chef::EventDispatch::Dispatcher.new
node = Chef::Node.new
run_context = Chef::RunContext.new(node, {}, events)
- resource = Chef::Resource::File.new(path, run_context)
- resource
+
+ use_path = if opts[:use_relative_path]
+ File.basename(path)
+ else
+ path
+ end
+
+ Chef::Resource::File.new(use_path, run_context)
end
let(:resource) do
@@ -42,6 +48,10 @@ describe Chef::Resource::File do
create_resource
end
+ let(:resource_with_relative_path) do
+ create_resource(:use_relative_path => true)
+ end
+
let(:unmanaged_content) do
"This is file content that is not managed by chef"
end
@@ -74,6 +84,19 @@ describe Chef::Resource::File do
end
end
+ # github issue 1842.
+ describe "when running action :create on a relative path" do
+ before do
+ resource_with_relative_path.run_action(:create)
+ end
+
+ context "and the file exists" do
+ it "should run without an exception" do
+ resource_with_relative_path.run_action(:create)
+ end
+ end
+ end
+
describe "when running action :touch" do
context "and the target file does not exist" do
before do
diff --git a/spec/functional/resource/link_spec.rb b/spec/functional/resource/link_spec.rb
index 8e630d84f2..2220e973cf 100644
--- a/spec/functional/resource/link_spec.rb
+++ b/spec/functional/resource/link_spec.rb
@@ -72,8 +72,8 @@ describe Chef::Resource::Link do
end
end
- def canonicalize(path)
- windows? ? path.gsub('/', '\\') : path
+ def paths_eql?(path1, path2)
+ Chef::Util::PathHelper.paths_eql?(path1, path2)
end
def symlink(a, b)
@@ -180,7 +180,7 @@ describe Chef::Resource::Link do
it 'links to the target file' do
symlink?(target_file).should be_true
- readlink(target_file).should == canonicalize(to)
+ paths_eql?(readlink(target_file), to).should be_true
end
it 'marks the resource updated' do
resource.should be_updated
@@ -201,7 +201,7 @@ describe Chef::Resource::Link do
it 'leaves the file linked' do
symlink?(target_file).should be_true
- readlink(target_file).should == canonicalize(to)
+ paths_eql?(readlink(target_file), to).should be_true
end
it 'does not mark the resource updated' do
resource.should_not be_updated
@@ -279,7 +279,7 @@ describe Chef::Resource::Link do
before(:each) do
symlink(to, target_file)
symlink?(target_file).should be_true
- readlink(target_file).should == canonicalize(to)
+ paths_eql?(readlink(target_file), to).should be_true
end
include_context 'create symbolic link is noop'
include_context 'delete succeeds'
@@ -294,7 +294,7 @@ describe Chef::Resource::Link do
File.open(@other_target, 'w') { |file| file.write('eek') }
symlink(@other_target, target_file)
symlink?(target_file).should be_true
- readlink(target_file).should == canonicalize(@other_target)
+ paths_eql?(readlink(target_file), @other_target).should be_true
end
after(:each) do
File.delete(@other_target)
@@ -311,7 +311,7 @@ describe Chef::Resource::Link do
nonexistent = File.join(test_file_dir, make_tmpname('nonexistent_spec'))
symlink(nonexistent, target_file)
symlink?(target_file).should be_true
- readlink(target_file).should == canonicalize(nonexistent)
+ paths_eql?(readlink(target_file), nonexistent).should be_true
end
include_context 'create symbolic link succeeds'
include_context 'delete succeeds'
@@ -393,7 +393,7 @@ describe Chef::Resource::Link do
File.open(@other_target, "w") { |file| file.write("eek") }
symlink(@other_target, to)
symlink?(to).should be_true
- readlink(to).should == canonicalize(@other_target)
+ paths_eql?(readlink(to), @other_target).should be_true
end
after(:each) do
File.delete(@other_target)
@@ -408,7 +408,7 @@ describe Chef::Resource::Link do
@other_target = File.join(test_file_dir, make_tmpname("other_spec"))
symlink(@other_target, to)
symlink?(to).should be_true
- readlink(to).should == canonicalize(@other_target)
+ paths_eql?(readlink(to), @other_target).should be_true
end
context 'and the link does not yet exist' do
include_context 'create symbolic link succeeds'
@@ -441,7 +441,7 @@ describe Chef::Resource::Link do
before(:each) do
symlink(to, target_file)
symlink?(target_file).should be_true
- readlink(target_file).should == canonicalize(to)
+ paths_eql?(readlink(target_file), to).should be_true
end
include_context 'create symbolic link is noop'
include_context 'delete succeeds'
@@ -450,7 +450,7 @@ describe Chef::Resource::Link do
before(:each) do
symlink(absolute_to, target_file)
symlink?(target_file).should be_true
- readlink(target_file).should == canonicalize(absolute_to)
+ paths_eql?(readlink(target_file), absolute_to).should be_true
end
include_context 'create symbolic link succeeds'
include_context 'delete succeeds'
@@ -478,7 +478,7 @@ describe Chef::Resource::Link do
before(:each) do
symlink(to, target_file)
symlink?(target_file).should be_true
- readlink(target_file).should == canonicalize(to)
+ paths_eql?(readlink(target_file), to).should be_true
end
include_context 'create hard link succeeds'
it_behaves_like 'delete errors out'
@@ -552,7 +552,7 @@ describe Chef::Resource::Link do
File.open(@other_target, "w") { |file| file.write("eek") }
symlink(@other_target, to)
symlink?(to).should be_true
- readlink(to).should == canonicalize(@other_target)
+ paths_eql?(readlink(to), @other_target).should be_true
end
after(:each) do
File.delete(@other_target)
@@ -564,7 +564,7 @@ describe Chef::Resource::Link do
# OS X gets angry about this sort of link. Bug in OS X, IMO.
pending('OS X/FreeBSD/AIX symlink? and readlink working on hard links to symlinks', :if => (os_x? or freebsd? or aix?)) do
symlink?(target_file).should be_true
- readlink(target_file).should == canonicalize(@other_target)
+ paths_eql?(readlink(target_file), @other_target).should be_true
end
end
include_context 'delete is noop'
@@ -575,7 +575,7 @@ describe Chef::Resource::Link do
@other_target = File.join(test_file_dir, make_tmpname("other_spec"))
symlink(@other_target, to)
symlink?(to).should be_true
- readlink(to).should == canonicalize(@other_target)
+ paths_eql?(readlink(to), @other_target).should be_true
end
context 'and the link does not yet exist' do
it 'links to the target file' do
@@ -588,7 +588,7 @@ describe Chef::Resource::Link do
File.exists?(target_file).should be_false
end
symlink?(target_file).should be_true
- readlink(target_file).should == canonicalize(@other_target)
+ paths_eql?(readlink(target_file), @other_target).should be_true
end
end
include_context 'delete is noop'
diff --git a/spec/functional/resource/reboot_spec.rb b/spec/functional/resource/reboot_spec.rb
new file mode 100644
index 0000000000..735ca994c8
--- /dev/null
+++ b/spec/functional/resource/reboot_spec.rb
@@ -0,0 +1,103 @@
+#
+# Author:: Chris Doherty <cdoherty@getchef.com>)
+# Copyright:: Copyright (c) 2014 Chef, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+describe Chef::Resource::Reboot do
+
+ let(:expected) do
+ {
+ :delay_mins => 5,
+ :requested_by => "reboot resource functional test",
+ :reason => "reboot resource spec test"
+ }
+ end
+
+ def create_resource
+ node = Chef::Node.new
+ events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, {}, events)
+ resource = Chef::Resource::Reboot.new(expected[:requested_by], run_context)
+ resource.delay_mins(expected[:delay_mins])
+ resource.reason(expected[:reason])
+ resource
+ end
+
+ let(:resource) do
+ create_resource
+ end
+
+ shared_context 'testing run context modification' do
+ def test_reboot_action(resource)
+ reboot_info = resource.run_context.reboot_info
+ expect(reboot_info.keys.sort).to eq([:delay_mins, :reason, :requested_by, :timestamp])
+ expect(reboot_info[:delay_mins]).to eq(expected[:delay_mins])
+ expect(reboot_info[:reason]).to eq(expected[:reason])
+ expect(reboot_info[:requested_by]).to eq(expected[:requested_by])
+
+ expect(resource.run_context.reboot_requested?).to be_true
+ end
+ end
+
+ # the currently defined behavior for multiple calls to this resource is "last one wins."
+ describe 'the request_reboot_on_successful_run action' do
+ include_context 'testing run context modification'
+
+ before do
+ resource.run_action(:request_reboot)
+ end
+
+ after do
+ resource.run_context.cancel_reboot
+ end
+
+ it 'should have modified the run context correctly' do
+ test_reboot_action(resource)
+ end
+ end
+
+ describe 'the reboot_interrupt_run action' do
+ include_context 'testing run context modification'
+
+ after do
+ resource.run_context.cancel_reboot
+ end
+
+ it 'should have modified the run context correctly' do
+ # this doesn't actually test the flow of Chef::Client#do_run, unfortunately.
+ expect {
+ resource.run_action(:reboot_now)
+ }.to throw_symbol(:end_client_run_early)
+
+ test_reboot_action(resource)
+ end
+ end
+
+ describe "the cancel action" do
+ before do
+ resource.run_context.request_reboot(expected)
+ resource.run_action(:cancel)
+ end
+
+ it 'should have cleared the reboot request' do
+ # arguably we shouldn't be querying RunContext's internal data directly.
+ expect(resource.run_context.reboot_info).to eq({})
+ expect(resource.run_context.reboot_requested?).to be_false
+ end
+ end
+end
diff --git a/spec/functional/util/powershell/cmdlet_spec.rb b/spec/functional/util/powershell/cmdlet_spec.rb
new file mode 100644
index 0000000000..63d1ac09b5
--- /dev/null
+++ b/spec/functional/util/powershell/cmdlet_spec.rb
@@ -0,0 +1,114 @@
+#
+# Author:: Adam Edwards (<adamed@getchef.com>)
+#
+# Copyright:: 2014, Chef Software, Inc.
+#
+# 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 'json'
+require File.expand_path('../../../../spec_helper', __FILE__)
+
+describe Chef::Util::Powershell::Cmdlet, :windows_only do
+ before(:all) do
+ ohai = Ohai::System.new
+ ohai.load_plugins
+ ohai.run_plugins(true, ['platform', 'kernel'])
+ @node = Chef::Node.new
+ @node.consume_external_attrs(ohai.data, {})
+ end
+ let(:cmd_output_format) { :text }
+ let(:simple_cmdlet) { Chef::Util::Powershell::Cmdlet.new(@node, 'get-childitem', cmd_output_format, {:depth => 2}) }
+ let(:invalid_cmdlet) { Chef::Util::Powershell::Cmdlet.new(@node, 'get-idontexist', cmd_output_format) }
+ let(:cmdlet_get_item_requires_switch_or_argument) { Chef::Util::Powershell::Cmdlet.new(@node, 'get-item', cmd_output_format, {:depth => 2}) }
+ let(:cmdlet_alias_requires_switch_or_argument) { Chef::Util::Powershell::Cmdlet.new(@node, 'alias', cmd_output_format, {:depth => 2}) }
+ let(:etc_directory) { "#{ENV['systemroot']}\\system32\\drivers\\etc" }
+ let(:architecture_cmdlet) { Chef::Util::Powershell::Cmdlet.new(@node, "$env:PROCESSOR_ARCHITECTURE")}
+
+ it "executes a simple process" do
+ result = simple_cmdlet.run
+ expect(result.succeeded?).to eq(true)
+ end
+
+ it "#run does not raise a PowershellCmdletException exception if the command cannot be executed" do
+ expect {invalid_cmdlet.run}.not_to raise_error
+ end
+
+ it "#run! raises a PowershellCmdletException exception if the command cannot be executed" do
+ expect {invalid_cmdlet.run!}.to raise_error(Chef::Exceptions::PowershellCmdletException)
+ end
+
+ it "executes a 64-bit command on a 64-bit OS, 32-bit otherwise" do
+ os_arch = ENV['PROCESSOR_ARCHITEW6432']
+ if os_arch.nil?
+ os_arch = ENV['PROCESSOR_ARCHITECTURE']
+ end
+
+ result = architecture_cmdlet.run
+ execution_arch = result.return_value
+ execution_arch.strip!
+ expect(execution_arch).to eq(os_arch)
+ end
+
+ it "passes command line switches to the command" do
+ result = cmdlet_alias_requires_switch_or_argument.run({:name => 'ls'})
+ expect(result.succeeded?).to eq(true)
+ end
+
+ it "passes command line arguments to the command" do
+ result = cmdlet_alias_requires_switch_or_argument.run({},{},'ls')
+ expect(result.succeeded?).to eq(true)
+ end
+
+ it "passes command line arguments and switches to the command" do
+ result = cmdlet_get_item_requires_switch_or_argument.run({:path => etc_directory},{},' | select-object -property fullname | format-table -hidetableheaders')
+ expect(result.succeeded?).to eq(true)
+ returned_directory = result.return_value
+ returned_directory.strip!
+ expect(returned_directory).to eq(etc_directory)
+ end
+
+ it "passes execution options to the command" do
+ result = cmdlet_get_item_requires_switch_or_argument.run({},{:cwd => etc_directory},'. | select-object -property fullname | format-table -hidetableheaders')
+ expect(result.succeeded?).to eq(true)
+ returned_directory = result.return_value
+ returned_directory.strip!
+ expect(returned_directory).to eq(etc_directory)
+ end
+
+ context "when returning json" do
+ let(:cmd_output_format) { :json }
+ it "returns json format data", :windows_powershell_dsc_only do
+ result = cmdlet_alias_requires_switch_or_argument.run({},{},'ls')
+ expect(result.succeeded?).to eq(true)
+ expect(lambda{JSON.parse(result.return_value)}).not_to raise_error
+ end
+ end
+
+ context "when returning Ruby objects" do
+ let(:cmd_output_format) { :object }
+ it "returns object format data", :windows_powershell_dsc_only do
+ result = simple_cmdlet.run({},{:cwd => etc_directory}, 'hosts')
+ expect(result.succeeded?).to eq(true)
+ data = result.return_value
+ expect(data['Name']).to eq('hosts')
+ end
+ end
+
+ context "when constructor is given invalid arguments" do
+ let(:cmd_output_format) { :invalid }
+ it "throws an exception if an invalid format is passed to the constructor" do
+ expect(lambda{simple_cmdlet}).to raise_error
+ end
+ end
+end
diff --git a/spec/integration/client/client_spec.rb b/spec/integration/client/client_spec.rb
index 8a1a65249b..0144ae0ce3 100644
--- a/spec/integration/client/client_spec.rb
+++ b/spec/integration/client/client_spec.rb
@@ -16,7 +16,7 @@ describe "chef-client" do
# machine that has omnibus chef installed. In that case we need to ensure
# we're running `chef-client` from the source tree and not the external one.
# cf. CHEF-4914
- let(:chef_client) { "ruby #{chef_dir}/chef-client" }
+ let(:chef_client) { "ruby '#{chef_dir}/chef-client'" }
when_the_repository "has a cookbook with a no-op recipe" do
before { file 'cookbooks/x/recipes/default.rb', '' }
diff --git a/spec/integration/client/ipv6_spec.rb b/spec/integration/client/ipv6_spec.rb
index f49b7b7711..76dd1938f7 100644
--- a/spec/integration/client/ipv6_spec.rb
+++ b/spec/integration/client/ipv6_spec.rb
@@ -76,7 +76,7 @@ END_CLIENT_RB
let(:chef_dir) { File.join(File.dirname(__FILE__), "..", "..", "..", "bin") }
- let(:chef_client_cmd) { %Q[ruby #{chef_dir}/chef-client -c "#{path_to('config/client.rb')}" -lwarn] }
+ let(:chef_client_cmd) { %Q[ruby '#{chef_dir}/chef-client' -c "#{path_to('config/client.rb')}" -lwarn] }
after do
FileUtils.rm_rf(cache_path)
diff --git a/spec/integration/knife/cookbook_api_ipv6_spec.rb b/spec/integration/knife/cookbook_api_ipv6_spec.rb
index 4191bb1731..c5b5b81abe 100644
--- a/spec/integration/knife/cookbook_api_ipv6_spec.rb
+++ b/spec/integration/knife/cookbook_api_ipv6_spec.rb
@@ -62,7 +62,7 @@ END_VALIDATION_PEM
end
let(:chef_dir) { File.join(File.dirname(__FILE__), "..", "..", "..", "bin") }
- let(:knife) { "ruby #{chef_dir}/knife" }
+ let(:knife) { "ruby '#{chef_dir}/knife'" }
let(:knife_config_flag) { "-c '#{path_to("config/knife.rb")}'" }
diff --git a/spec/integration/recipes/lwrp_inline_resources_spec.rb b/spec/integration/recipes/lwrp_inline_resources_spec.rb
index 9e2cf3fc8d..a0c13da6f7 100644
--- a/spec/integration/recipes/lwrp_inline_resources_spec.rb
+++ b/spec/integration/recipes/lwrp_inline_resources_spec.rb
@@ -16,7 +16,7 @@ describe "LWRPs with inline resources" do
# machine that has omnibus chef installed. In that case we need to ensure
# we're running `chef-client` from the source tree and not the external one.
# cf. CHEF-4914
- let(:chef_client) { "ruby #{chef_dir}/chef-client" }
+ let(:chef_client) { "ruby '#{chef_dir}/chef-client'" }
when_the_repository "has a cookbook with a nested LWRP" do
before do
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 7c11957997..ed0a8f89f6 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -107,8 +107,11 @@ RSpec.configure do |config|
config.filter_run_excluding :not_supported_on_win2k3 => true if windows_win2k3?
config.filter_run_excluding :not_supported_on_solaris => true if solaris?
config.filter_run_excluding :win2k3_only => true unless windows_win2k3?
+ config.filter_run_excluding :windows_2008r2_or_later => true unless windows_2008r2_or_later?
config.filter_run_excluding :windows64_only => true unless windows64?
config.filter_run_excluding :windows32_only => true unless windows32?
+ config.filter_run_excluding :windows_powershell_dsc_only => true unless windows_powershell_dsc?
+ config.filter_run_excluding :windows_powershell_no_dsc_only => true unless ! windows_powershell_dsc?
config.filter_run_excluding :windows_domain_joined_only => true unless windows_domain_joined?
config.filter_run_excluding :solaris_only => true unless solaris?
config.filter_run_excluding :system_windows_service_gem_only => true unless system_windows_service_gem?
diff --git a/spec/support/platform_helpers.rb b/spec/support/platform_helpers.rb
index a7c616d7a7..f8cad6de7f 100644
--- a/spec/support/platform_helpers.rb
+++ b/spec/support/platform_helpers.rb
@@ -52,6 +52,30 @@ def windows_win2k3?
(host['version'] && host['version'].start_with?("5.2"))
end
+def windows_2008r2_or_later?
+ return false unless windows?
+ wmi = WmiLite::Wmi.new
+ host = wmi.first_of('Win32_OperatingSystem')
+ version = host['version']
+ return false unless version
+ components = version.split('.').map do | component |
+ component.to_i
+ end
+ components.length >=2 && components[0] >= 6 && components[1] >= 1
+end
+
+def windows_powershell_dsc?
+ return false unless windows?
+ supports_dsc = false
+ begin
+ wmi = WmiLite::Wmi.new('root/microsoft/windows/desiredstateconfiguration')
+ lcm = wmi.query("SELECT * FROM meta_class WHERE __this ISA 'MSFT_DSCLocalConfigurationManager'")
+ supports_dsc = !! lcm
+ rescue WmiLite::WmiException
+ end
+ supports_dsc
+end
+
def mac_osx_106?
if File.exists? "/usr/bin/sw_vers"
result = shell_out("/usr/bin/sw_vers")
diff --git a/spec/support/shared/functional/file_resource.rb b/spec/support/shared/functional/file_resource.rb
index 804830fcdc..72b72912bd 100644
--- a/spec/support/shared/functional/file_resource.rb
+++ b/spec/support/shared/functional/file_resource.rb
@@ -284,6 +284,7 @@ shared_examples_for "a file resource" do
before do
Chef::Config[:why_run] = true
+ Chef::Config[:ssl_verify_mode] = :verify_none
end
after do
@@ -333,6 +334,10 @@ shared_examples_for "file resource not pointing to a real file" do
!symlink?(file_path) && File.file?(file_path)
end
+ before do
+ Chef::Config[:ssl_verify_mode] = :verify_none
+ end
+
describe "when force_unlink is set to true" do
it ":create unlinks the target" do
real_file?(path).should be_false
@@ -363,6 +368,7 @@ shared_examples_for "a configured file resource" do
before do
Chef::Log.level = :info
+ Chef::Config[:ssl_verify_mode] = :verify_none
end
# note the stripping of the drive letter from the tmpdir on windows
diff --git a/spec/support/shared/integration/integration_helper.rb b/spec/support/shared/integration/integration_helper.rb
index 465633b9e0..b42f7f69d9 100644
--- a/spec/support/shared/integration/integration_helper.rb
+++ b/spec/support/shared/integration/integration_helper.rb
@@ -118,7 +118,10 @@ module IntegrationSupport
Chef::Config.delete("#{object_name}_path".to_sym)
end
Chef::Config.delete(:chef_repo_path)
- FileUtils.remove_entry_secure(@repository_dir)
+ # TODO: "force" actually means "silence all exceptions". this
+ # silences a weird permissions error on Windows that we should track
+ # down, but for now there's no reason for it to blow up our CI.
+ FileUtils.remove_entry_secure(@repository_dir, force=Chef::Platform.windows?)
ensure
@repository_dir = nil
end
diff --git a/spec/unit/application/apply.rb b/spec/unit/application/apply.rb
index 32c98c6ed6..62a53c2a31 100644
--- a/spec/unit/application/apply.rb
+++ b/spec/unit/application/apply.rb
@@ -20,7 +20,7 @@ require 'spec_helper'
describe Chef::Application::Apply do
before do
- @app = Chef::Application::Recipe.new
+ @app = Chef::Application::Apply.new
@app.stub(:configure_logging).and_return(true)
@recipe_text = "package 'nyancat'"
Chef::Config[:solo] = true
@@ -73,4 +73,14 @@ describe Chef::Application::Apply do
@recipe_fh.path.should == @app.instance_variable_get(:@recipe_filename)
end
end
+ describe "recipe_file_arg" do
+ before do
+ ARGV.clear
+ end
+ it "should exit and log message" do
+ Chef::Log.should_receive(:debug).with(/^No recipe file provided/)
+ lambda { @app.run }.should raise_error(SystemExit) { |e| e.status.should == 1 }
+ end
+
+ end
end
diff --git a/spec/unit/config_spec.rb b/spec/unit/config_spec.rb
index af71c43b77..41411669e6 100644
--- a/spec/unit/config_spec.rb
+++ b/spec/unit/config_spec.rb
@@ -242,8 +242,8 @@ describe Chef::Config do
Chef::Config[:file_backup_path].should == backup_path
end
- it "Chef::Config[:ssl_verify_mode] defaults to :verify_none" do
- Chef::Config[:ssl_verify_mode].should == :verify_none
+ it "Chef::Config[:ssl_verify_mode] defaults to :verify_peer" do
+ Chef::Config[:ssl_verify_mode].should == :verify_peer
end
it "Chef::Config[:ssl_ca_path] defaults to nil" do
diff --git a/spec/unit/dsl/reboot_pending_spec.rb b/spec/unit/dsl/reboot_pending_spec.rb
index 8576ae168a..0d643514e0 100644
--- a/spec/unit/dsl/reboot_pending_spec.rb
+++ b/spec/unit/dsl/reboot_pending_spec.rb
@@ -21,7 +21,7 @@ require "spec_helper"
describe Chef::DSL::RebootPending do
describe "reboot_pending?" do
- describe "in isoloation" do
+ describe "in isolation" do
let(:recipe) { Object.new.extend(Chef::DSL::RebootPending) }
before do
@@ -74,12 +74,6 @@ describe Chef::DSL::RebootPending do
end
end
- context "platform is not supported" do
- it 'should raise an exception' do
- recipe.stub_chain(:node, :[]).with(:platform).and_return('msdos')
- expect { recipe.reboot_pending? }.to raise_error(Chef::Exceptions::UnsupportedPlatform)
- end
- end
end # describe in isolation
describe "in a recipe" do
diff --git a/spec/unit/knife/bootstrap_spec.rb b/spec/unit/knife/bootstrap_spec.rb
index 78be9632f6..a1c5d168dd 100644
--- a/spec/unit/knife/bootstrap_spec.rb
+++ b/spec/unit/knife/bootstrap_spec.rb
@@ -355,6 +355,44 @@ describe Chef::Knife::Bootstrap do
end
end
+ describe "when transferring trusted certificates" do
+ let(:trusted_certs_dir) { File.join(CHEF_SPEC_DATA, 'trusted_certs') }
+
+ let(:rendered_template) do
+ knife.merge_configs
+ knife.render_template
+ end
+
+ before do
+ Chef::Config[:trusted_certs_dir] = trusted_certs_dir
+ IO.stub(:read).and_call_original
+ IO.stub(:read).with(File.expand_path(Chef::Config[:validation_key])).and_return("")
+ end
+
+ def certificates
+ Dir[File.join(trusted_certs_dir, "*.{crt,pem}")]
+ end
+
+ it "creates /etc/chef/trusted_certs" do
+ rendered_template.should match(%r{mkdir -p /etc/chef/trusted_certs})
+ end
+
+ it "copies the certificates in the directory" do
+ certificates.each do |cert|
+ IO.should_receive(:read).with(File.expand_path(cert))
+ end
+
+ certificates.each do |cert|
+ rendered_template.should match(%r{cat > /etc/chef/trusted_certs/#{File.basename(cert)} <<'EOP'})
+ end
+ end
+
+ it "doesn't create /etc/chef/trusted_certs if :trusted_certs_dir is empty" do
+ Dir.should_receive(:glob).with(File.join(trusted_certs_dir, "*.{crt,pem}")).and_return([])
+ rendered_template.should_not match(%r{mkdir -p /etc/chef/trusted_certs})
+ end
+ end
+
describe "when configuring the underlying knife ssh command" do
context "from the command line" do
let(:knife_ssh) do
diff --git a/spec/unit/knife/core/bootstrap_context_spec.rb b/spec/unit/knife/core/bootstrap_context_spec.rb
index 064f8c5621..6427071a6b 100644
--- a/spec/unit/knife/core/bootstrap_context_spec.rb
+++ b/spec/unit/knife/core/bootstrap_context_spec.rb
@@ -119,7 +119,20 @@ EXPECTED
context "via config[:secret_file]" do
let(:chef_config) do
{
- :knife => {:secret_file => secret_file}
+ :knife => {:secret_file => secret_file}
+ }
+ end
+ it "reads the encrypted_data_bag_secret" do
+ bootstrap_context.encrypted_data_bag_secret.should eq IO.read(secret_file)
+ end
+ end
+
+ context "via config[:secret_file] with short home path" do
+ let(:chef_config) do
+ home_path = File.expand_path("~")
+ shorted_secret_file_path = secret_file.gsub(home_path, "~")
+ {
+ :knife => {:secret_file => shorted_secret_file_path}
}
end
it "reads the encrypted_data_bag_secret" do
diff --git a/spec/unit/mixin/homebrew_owner_spec.rb b/spec/unit/mixin/homebrew_owner_spec.rb
new file mode 100644
index 0000000000..428cd827d9
--- /dev/null
+++ b/spec/unit/mixin/homebrew_owner_spec.rb
@@ -0,0 +1,65 @@
+#
+# Author:: Joshua Timberman (<joshua@getchef.com>)
+#
+# Copyright 2014, Chef Software, Inc <legal@getchef.com>
+#
+# 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/homebrew_owner'
+
+class ExampleHomebrewOwner
+ include Chef::Mixin::HomebrewOwner
+end
+
+describe Chef::Mixin::HomebrewOwner do
+ before(:each) do
+ node.default['homebrew']['owner'] = nil
+ end
+
+ let(:homebrew_owner) { ExampleHomebrewOwner.new }
+ let(:node) { Chef::Node.new }
+
+ describe 'when the homebrew owner node attribute is set' do
+ it 'raises an exception if the owner is root' do
+ node.default['homebrew']['owner'] = 'root'
+ expect { homebrew_owner.homebrew_owner(node) }.to raise_exception(Chef::Exceptions::CannotDetermineHomebrewOwner)
+ end
+
+ it 'returns the owner set by attribute' do
+ node.default['homebrew']['owner'] = 'siouxsie'
+ expect(homebrew_owner.homebrew_owner(node)).to eql('siouxsie')
+ end
+ end
+
+ describe 'when the owner attribute is not set and we use sudo' do
+ before(:each) do
+ ENV.stub(:[]).with('SUDO_USER').and_return('john_lydon')
+ end
+
+ it 'uses the SUDO_USER environment variable' do
+ expect(homebrew_owner.homebrew_owner(node)).to eql('john_lydon')
+ end
+ end
+
+ describe 'when the owner attribute is not set and we arent using sudo' do
+ before(:each) do
+ ENV.stub(:[]).with('USER').and_return('sid_vicious')
+ ENV.stub(:[]).with('SUDO_USER').and_return(nil)
+ end
+
+ it 'uses the current user' do
+ expect(homebrew_owner.homebrew_owner(node)).to eql('sid_vicious')
+ end
+ end
+end
diff --git a/spec/unit/mixin/shell_out_spec.rb b/spec/unit/mixin/shell_out_spec.rb
index 1f85ec6bf1..38a63a32ee 100644
--- a/spec/unit/mixin/shell_out_spec.rb
+++ b/spec/unit/mixin/shell_out_spec.rb
@@ -32,7 +32,7 @@ describe Chef::Mixin::ShellOut do
let(:output) { StringIO.new }
let!(:capture_log_output) { Chef::Log.logger = Logger.new(output) }
- let(:assume_deprecation_log_level) { Chef::Log.stub(:level).and_return(:warn) }
+ let(:assume_deprecation_log_level) { allow(Chef::Log).to receive(:level).and_return(:warn) }
context 'without options' do
let(:command_args) { [ cmd ] }
@@ -55,9 +55,9 @@ describe Chef::Mixin::ShellOut do
it 'should emit a deprecation warning' do
assume_deprecation_log_level and capture_log_output
subject
- output.string.should match /DEPRECATION:/
- output.string.should match Regexp.escape(old_option.to_s)
- output.string.should match Regexp.escape(new_option.to_s)
+ expect(output.string).to match /DEPRECATION:/
+ expect(output.string).to match Regexp.escape(old_option.to_s)
+ expect(output.string).to match Regexp.escape(new_option.to_s)
end
end
@@ -106,7 +106,7 @@ describe Chef::Mixin::ShellOut do
end
end
- describe "#shell_out_with_systems_locale" do
+ context "when testing individual methods" do
before(:each) do
@original_env = ENV.to_hash
ENV.clear
@@ -120,82 +120,152 @@ describe Chef::Mixin::ShellOut do
let(:shell_out) { Chef::Mixin::ShellOut }
let(:cmd) { "echo '#{rand(1000)}'" }
- describe "when the last argument is a Hash" do
- describe "and environment is an option" do
- it "should not change environment['LC_ALL'] when set to nil" do
- options = { :environment => { 'LC_ALL' => nil } }
- shell_out.should_receive(:shell_out).with(cmd, options).and_return(true)
- shell_out.shell_out_with_systems_locale(cmd, options)
+ describe "#shell_out" do
+
+ describe "when the last argument is a Hash" do
+ describe "and environment is an option" do
+ it "should not change environment['LC_ALL'] when set to nil" do
+ options = { :environment => { 'LC_ALL' => nil } }
+ expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true)
+ shell_out.shell_out(cmd, options)
+ end
+
+ it "should not change environment['LC_ALL'] when set to non-nil" do
+ options = { :environment => { 'LC_ALL' => 'en_US.UTF-8' } }
+ expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true)
+ shell_out.shell_out(cmd, options)
+ end
+
+ it "should set environment['LC_ALL'] to 'en_US.UTF-8' when 'LC_ALL' not present" do
+ options = { :environment => { 'HOME' => '/Users/morty' } }
+ expect(shell_out).to receive(:shell_out_command).with(cmd, {
+ :environment => { 'HOME' => '/Users/morty', 'LC_ALL' => Chef::Config[:internal_locale] },
+ }).and_return(true)
+ shell_out.shell_out(cmd, options)
+ end
+
+ it "should not mutate the options hash when it adds LC_ALL" do
+ options = { :environment => { 'HOME' => '/Users/morty' } }
+ expect(shell_out).to receive(:shell_out_command).with(cmd, {
+ :environment => { 'HOME' => '/Users/morty', 'LC_ALL' => Chef::Config[:internal_locale] },
+ }).and_return(true)
+ shell_out.shell_out(cmd, options)
+ expect(options[:environment].has_key?('LC_ALL')).to be false
+ end
end
- it "should not change environment['LC_ALL'] when set to non-nil" do
- options = { :environment => { 'LC_ALL' => 'en_US.UTF-8' } }
- shell_out.should_receive(:shell_out).with(cmd, options).and_return(true)
- shell_out.shell_out_with_systems_locale(cmd, options)
+ describe "and env is an option" do
+ it "should not change env when set to nil" do
+ options = { :env => { 'LC_ALL' => nil } }
+ expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true)
+ shell_out.shell_out(cmd, options)
+ end
+
+ it "should not change env when set to non-nil" do
+ options = { :env => { 'LC_ALL' => 'de_DE.UTF-8'}}
+ expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true)
+ shell_out.shell_out(cmd, options)
+ end
+
+ it "should set env['LC_ALL'] to 'en_US.UTF-8' when 'LC_ALL' not present" do
+ options = { :env => { 'HOME' => '/Users/morty' } }
+ expect(shell_out).to receive(:shell_out_command).with(cmd, {
+ :env => { 'HOME' => '/Users/morty', 'LC_ALL' => Chef::Config[:internal_locale] },
+ }).and_return(true)
+ shell_out.shell_out(cmd, options)
+ end
+
+ it "should not mutate the options hash when it adds LC_ALL" do
+ options = { :env => { 'HOME' => '/Users/morty' } }
+ expect(shell_out).to receive(:shell_out_command).with(cmd, {
+ :env => { 'HOME' => '/Users/morty', 'LC_ALL' => Chef::Config[:internal_locale] },
+ }).and_return(true)
+ shell_out.shell_out(cmd, options)
+ expect(options[:env].has_key?('LC_ALL')).to be false
+ end
end
- it "should set environment['LC_ALL'] to nil when 'LC_ALL' not present" do
- options = { :environment => { 'HOME' => '/Users/morty' } }
- shell_out.should_receive(:shell_out).with(
- cmd,
- { :environment => {
- 'HOME' => '/Users/morty',
- 'LC_ALL' => nil }
- }
- ).and_return(true)
- shell_out.shell_out_with_systems_locale(cmd, options)
+ describe "and no env/environment option is present" do
+ it "should add environment option and set environment['LC_ALL'] to 'en_US.UTF_8'" do
+ options = { :user => 'morty' }
+ expect(shell_out).to receive(:shell_out_command).with(cmd, {
+ :user => 'morty', :environment => { 'LC_ALL' => Chef::Config[:internal_locale] },
+ }).and_return(true)
+ shell_out.shell_out(cmd, options)
+ end
end
end
- describe "and env is an option" do
- it "should not change env when set to nil" do
- options = { :env => { 'LC_ALL' => nil } }
- shell_out.should_receive(:shell_out).with(cmd, options).and_return(true)
- shell_out.shell_out_with_systems_locale(cmd, options)
+ describe "when the last argument is not a Hash" do
+ it "should add environment options and set environment['LC_ALL'] to 'en_US.UTF-8'" do
+ expect(shell_out).to receive(:shell_out_command).with(cmd, {
+ :environment => { 'LC_ALL' => Chef::Config[:internal_locale] },
+ }).and_return(true)
+ shell_out.shell_out(cmd)
end
+ end
+
+ end
- it "should not change env when set to non-nil" do
- options = { :env => { 'LC_ALL' => 'en_US.UTF-8'}}
- shell_out.should_receive(:shell_out).with(cmd, options).and_return(true)
- shell_out.shell_out_with_systems_locale(cmd, options)
+ describe "#shell_out_with_systems_locale" do
+
+ describe "when the last argument is a Hash" do
+ describe "and environment is an option" do
+ it "should not change environment['LC_ALL'] when set to nil" do
+ options = { :environment => { 'LC_ALL' => nil } }
+ expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true)
+ shell_out.shell_out_with_systems_locale(cmd, options)
+ end
+
+ it "should not change environment['LC_ALL'] when set to non-nil" do
+ options = { :environment => { 'LC_ALL' => 'en_US.UTF-8' } }
+ expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true)
+ shell_out.shell_out_with_systems_locale(cmd, options)
+ end
+
+ it "should no longer set environment['LC_ALL'] to nil when 'LC_ALL' not present" do
+ options = { :environment => { 'HOME' => '/Users/morty' } }
+ expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true)
+ shell_out.shell_out_with_systems_locale(cmd, options)
+ end
end
- it "should set env['LC_ALL'] to nil when 'LC_ALL' not present" do
- options = { :env => { 'HOME' => '/Users/morty' } }
- shell_out.should_receive(:shell_out).with(
- cmd,
- { :env => {
- 'HOME' => '/Users/morty',
- 'LC_ALL' => nil }
- }
- ).and_return(true)
- shell_out.shell_out_with_systems_locale(cmd, options)
+ describe "and env is an option" do
+ it "should not change env when set to nil" do
+ options = { :env => { 'LC_ALL' => nil } }
+ expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true)
+ shell_out.shell_out_with_systems_locale(cmd, options)
+ end
+
+ it "should not change env when set to non-nil" do
+ options = { :env => { 'LC_ALL' => 'en_US.UTF-8'}}
+ expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true)
+ shell_out.shell_out_with_systems_locale(cmd, options)
+ end
+
+ it "should no longer set env['LC_ALL'] to nil when 'LC_ALL' not present" do
+ options = { :env => { 'HOME' => '/Users/morty' } }
+ expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true)
+ shell_out.shell_out_with_systems_locale(cmd, options)
+ end
end
- end
- describe "and no env/environment option is present" do
- it "should add environment option and set environment['LC_ALL'] to nil" do
- options = { :user => 'morty' }
- shell_out.should_receive(:shell_out).with(
- cmd,
- { :environment => { 'LC_ALL' => nil },
- :user => 'morty'
- }
- ).and_return(true)
- shell_out.shell_out_with_systems_locale(cmd, options)
+ describe "and no env/environment option is present" do
+ it "should no longer add environment option and set environment['LC_ALL'] to nil" do
+ options = { :user => 'morty' }
+ expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true)
+ shell_out.shell_out_with_systems_locale(cmd, options)
+ end
end
end
- end
- describe "when the last argument is not a Hash" do
- it "should add environment options and set environment['LC_ALL'] to nil" do
- shell_out.should_receive(:shell_out).with(
- cmd,
- { :environment => { 'LC_ALL' => nil } }
- ).and_return(true)
- shell_out.shell_out_with_systems_locale(cmd)
+ describe "when the last argument is not a Hash" do
+ it "should no longer add environment options and set environment['LC_ALL'] to nil" do
+ expect(shell_out).to receive(:shell_out_command).with(cmd).and_return(true)
+ shell_out.shell_out_with_systems_locale(cmd)
+ end
end
end
- end
+ end
end
diff --git a/spec/unit/platform/query_helpers_spec.rb b/spec/unit/platform/query_helpers_spec.rb
index 2414bdf552..6adea5eecf 100644
--- a/spec/unit/platform/query_helpers_spec.rb
+++ b/spec/unit/platform/query_helpers_spec.rb
@@ -30,3 +30,26 @@ describe "Chef::Platform#windows_server_2003?" do
expect { Thread.fork { Chef::Platform.windows_server_2003? }.join }.not_to raise_error
end
end
+
+describe 'Chef::Platform#supports_dsc?' do
+ it 'returns false if powershell is not present' do
+ node = Chef::Node.new
+ Chef::Platform.supports_dsc?(node).should be_false
+ end
+
+ ['1.0', '2.0', '3.0'].each do |version|
+ it "returns false for Powershell #{version}" do
+ node = Chef::Node.new
+ node.automatic[:languages][:powershell][:version] = version
+ Chef::Platform.supports_dsc?(node).should be_false
+ end
+ end
+
+ ['4.0', '5.0'].each do |version|
+ it "returns true for Powershell #{version}" do
+ node = Chef::Node.new
+ node.automatic[:languages][:powershell][:version] = version
+ Chef::Platform.supports_dsc?(node).should be_true
+ end
+ end
+end
diff --git a/spec/unit/provider/dsc_script_spec.rb b/spec/unit/provider/dsc_script_spec.rb
new file mode 100644
index 0000000000..8a7a7b5c6a
--- /dev/null
+++ b/spec/unit/provider/dsc_script_spec.rb
@@ -0,0 +1,145 @@
+#
+# Author:: Jay Mundrawala (<jdm@getchef.com>)
+#
+# 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 'chef'
+require 'chef/util/dsc/resource_info'
+require 'spec_helper'
+
+describe Chef::Provider::DscScript do
+ let (:node) {
+ node = Chef::Node.new
+ node.automatic[:languages][:powershell][:version] = '4.0'
+ node
+ }
+ let (:events) { Chef::EventDispatch::Dispatcher.new }
+ let (:run_context) { Chef::RunContext.new(node, {}, events) }
+ let (:resource) { Chef::Resource::DscScript.new("script", run_context) }
+ let (:provider) do
+ Chef::Provider::DscScript.new(resource, run_context)
+ end
+
+ describe '#load_current_resource' do
+ it "describes the resource as converged if there were 0 DSC resources" do
+ allow(provider).to receive(:run_configuration).with(:test).and_return([])
+ provider.load_current_resource
+ provider.instance_variable_get('@resource_converged').should be_true
+ end
+
+ it "describes the resource as not converged if there is 1 DSC resources that is converged" do
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
+ allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
+ provider.load_current_resource
+ provider.instance_variable_get('@resource_converged').should be_true
+ end
+
+ it "describes the resource as not converged if there is 1 DSC resources that is not converged" do
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
+ allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
+ provider.load_current_resource
+ provider.instance_variable_get('@resource_converged').should be_false
+ end
+
+ it "describes the resource as not converged if there are any DSC resources that are not converged" do
+ dsc_resource_info1 = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
+ dsc_resource_info2 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
+
+ allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info1, dsc_resource_info2])
+ provider.load_current_resource
+ provider.instance_variable_get('@resource_converged').should be_false
+ end
+
+ it "describes the resource as converged if all DSC resources that are converged" do
+ dsc_resource_info1 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
+ dsc_resource_info2 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
+
+ allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info1, dsc_resource_info2])
+ provider.load_current_resource
+ provider.instance_variable_get('@resource_converged').should be_true
+ end
+ end
+
+ describe '#generate_configuration_document' do
+ # I think integration tests should cover these cases
+
+ it 'uses configuration_document_from_script_path when a dsc script file is given' do
+ allow(provider).to receive(:load_current_resource)
+ resource.command("path_to_script")
+ generator = double('Chef::Util::DSC::ConfigurationGenerator')
+ generator.should_receive(:configuration_document_from_script_path)
+ allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
+ provider.send(:generate_configuration_document, 'tmp', nil)
+ end
+
+ it 'uses configuration_document_from_script_code when a the dsc resource is given' do
+ allow(provider).to receive(:load_current_resource)
+ resource.code("ImADSCResource{}")
+ generator = double('Chef::Util::DSC::ConfigurationGenerator')
+ generator.should_receive(:configuration_document_from_script_code)
+ allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
+ provider.send(:generate_configuration_document, 'tmp', nil)
+ end
+
+ it 'should noop if neither code or command are provided' do
+ allow(provider).to receive(:load_current_resource)
+ generator = double('Chef::Util::DSC::ConfigurationGenerator')
+ generator.should_receive(:configuration_document_from_script_code).with('', anything(), anything())
+ allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
+ provider.send(:generate_configuration_document, 'tmp', nil)
+ end
+ end
+
+ describe 'action_run' do
+ it 'should converge the script if it is not converged' do
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
+ allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
+ allow(provider).to receive(:run_configuration).with(:set)
+
+ provider.run_action(:run)
+ resource.should be_updated
+ end
+
+ it 'should not converge if the script is already converged' do
+ allow(provider).to receive(:run_configuration).with(:test).and_return([])
+
+ provider.run_action(:run)
+ resource.should_not be_updated
+ end
+ end
+
+ describe '#generate_description' do
+ it 'removes the resource name from the beginning of any log line from the LCM' do
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', true, ['resourcename doing something', 'lastline'])
+ provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
+ provider.send(:generate_description)[1].should match(/converge DSC resource resourcename by doing something/)
+ end
+
+ it 'ignores the last line' do
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', true, ['resourcename doing something', 'lastline'])
+ provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
+ provider.send(:generate_description)[1].should_not match(/lastline/)
+ end
+
+ it 'reports a dsc resource has not been changed if the LCM reported no change was required' do
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', false, ['resourcename does nothing', 'lastline'])
+ provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
+ provider.send(:generate_description)[1].should match(/converge DSC resource resourcename by doing nothing/)
+ end
+ end
+end
+
diff --git a/spec/unit/provider/ifconfig/debian_spec.rb b/spec/unit/provider/ifconfig/debian_spec.rb
index c6a37fdd5b..ebb16e22af 100644
--- a/spec/unit/provider/ifconfig/debian_spec.rb
+++ b/spec/unit/provider/ifconfig/debian_spec.rb
@@ -56,8 +56,6 @@ describe Chef::Provider::Ifconfig::Debian do
describe "generate_config" do
context "when writing a file" do
- let(:config_file_ifcfg) { StringIO.new }
-
let(:tempfile) { Tempfile.new("rspec-chef-ifconfig-debian") }
let(:tempdir_path) { Dir.mktmpdir("rspec-chef-ifconfig-debian-dir") }
@@ -67,14 +65,13 @@ describe Chef::Provider::Ifconfig::Debian do
before do
stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_FILE", tempfile.path)
stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_DOT_D_DIR", tempdir_path)
- expect(File).to receive(:new).with(config_filename_ifcfg, "w").and_return(config_file_ifcfg)
end
it "should write a network-script" do
provider.run_action(:add)
- expect(config_file_ifcfg.string).to match(/^iface eth0 inet static\s*$/)
- expect(config_file_ifcfg.string).to match(/^\s+address 10\.0\.0\.1\s*$/)
- expect(config_file_ifcfg.string).to match(/^\s+netmask 255\.255\.254\.0\s*$/)
+ expect(File.read(config_filename_ifcfg)).to match(/^iface eth0 inet static\s*$/)
+ expect(File.read(config_filename_ifcfg)).to match(/^\s+address 10\.0\.0\.1\s*$/)
+ expect(File.read(config_filename_ifcfg)).to match(/^\s+netmask 255\.255\.254\.0\s*$/)
end
context "when the interface_dot_d directory does not exist" do
@@ -123,7 +120,6 @@ iface eth0 inet static
netmask 255.255.254.0
EOF
)
- expect(File).to receive(:new).with(config_filename_ifcfg, "w").and_return(config_file_ifcfg)
expect(File.exists?(tempdir_path)).to be_true # since the file exists, the enclosing dir must also exist
end
@@ -139,6 +135,8 @@ EOF
before do
tempfile.write(expected_string)
tempfile.close
+
+ expect(provider).not_to receive(:converge_by).with(/modifying #{tempfile.path} to source #{tempdir_path}/)
end
it "should preserve all the contents" do
@@ -165,6 +163,9 @@ EOF
before do
tempfile.write("a line\nanother line\n")
tempfile.close
+
+ allow(provider).to receive(:converge_by).and_call_original
+ expect(provider).to receive(:converge_by).with(/modifying #{tempfile.path} to source #{tempdir_path}/).and_call_original
end
it "should preserve the original contents and add the source line" do
@@ -316,12 +317,37 @@ source #{tempdir_path}/*
describe "delete_config for action_delete" do
+ let(:tempfile) { Tempfile.new("rspec-chef-ifconfig-debian") }
+
+ let(:tempdir_path) { Dir.mktmpdir("rspec-chef-ifconfig-debian-dir") }
+
+ let(:config_filename_ifcfg) { "#{tempdir_path}/ifcfg-#{new_resource.device}" }
+
+ before do
+ stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_FILE", tempfile.path)
+ stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_DOT_D_DIR", tempdir_path)
+ File.open(config_filename_ifcfg, "w") do |fh|
+ fh.write "arbitrary text\n"
+ fh.close
+ end
+ end
+
+ after do
+ Dir.rmdir(tempdir_path)
+ end
+
it "should delete network-script if it exists" do
current_resource.device new_resource.device
- expect(File).to receive(:exist?).with(config_filename_ifcfg).and_return(true)
- expect(FileUtils).to receive(:rm_f).with(config_filename_ifcfg, :verbose => false)
+ # belt and suspenders testing?
+ Chef::Util::Backup.any_instance.should_receive(:do_backup).and_call_original
+
+ # internal implementation detail of Ifconfig.
+ Chef::Provider::File.any_instance.should_receive(:action_delete).and_call_original
+
+ expect(File.exist?(config_filename_ifcfg)).to be_true
provider.run_action(:delete)
+ expect(File.exist?(config_filename_ifcfg)).to be_false
end
end
diff --git a/spec/unit/provider/ifconfig/redhat_spec.rb b/spec/unit/provider/ifconfig/redhat_spec.rb
index f4b98dfc32..138c2a389d 100644
--- a/spec/unit/provider/ifconfig/redhat_spec.rb
+++ b/spec/unit/provider/ifconfig/redhat_spec.rb
@@ -37,22 +37,26 @@ describe Chef::Provider::Ifconfig::Redhat do
status = double("Status", :exitstatus => 0)
@provider.instance_variable_set("@status", status)
@provider.current_resource = @current_resource
- end
+
+ config_filename = "/etc/sysconfig/network-scripts/ifcfg-#{@new_resource.device}"
+ @config = double("chef-resource-file")
+ @provider.should_receive(:resource_for_config).with(config_filename).and_return(@config)
+ end
describe "generate_config for action_add" do
- it "should write network-script for centos" do
+ it "should write network-script for centos" do
@provider.stub(:load_current_resource)
@provider.stub(:run_command)
- config_filename = "/etc/sysconfig/network-scripts/ifcfg-#{@new_resource.device}"
- config_file = StringIO.new
- File.should_receive(:new).with(config_filename, "w").and_return(config_file)
-
+ @config.should_receive(:content) do |arg|
+ arg.should match(/^\s*DEVICE=eth0\s*$/)
+ arg.should match(/^\s*IPADDR=10\.0\.0\.1\s*$/)
+ arg.should match(/^\s*NETMASK=255\.255\.254\.0\s*$/)
+ end
+ @config.should_receive(:run_action).with(:create)
+ @config.should_receive(:updated?).and_return(true)
@provider.run_action(:add)
- config_file.string.should match(/^\s*DEVICE=eth0\s*$/)
- config_file.string.should match(/^\s*IPADDR=10\.0\.0\.1\s*$/)
- config_file.string.should match(/^\s*NETMASK=255\.255\.254\.0\s*$/)
- end
+ end
end
describe "delete_config for action_delete" do
@@ -61,10 +65,8 @@ describe Chef::Provider::Ifconfig::Redhat do
@current_resource.device @new_resource.device
@provider.stub(:load_current_resource)
@provider.stub(:run_command)
- config_filename = "/etc/sysconfig/network-scripts/ifcfg-#{@new_resource.device}"
- File.should_receive(:exist?).with(config_filename).and_return(true)
- FileUtils.should_receive(:rm_f).with(config_filename, :verbose => false)
-
+ @config.should_receive(:run_action).with(:delete)
+ @config.should_receive(:updated?).and_return(true)
@provider.run_action(:delete)
end
end
diff --git a/spec/unit/provider/ifconfig_spec.rb b/spec/unit/provider/ifconfig_spec.rb
index fb8d0956d7..b09e365c65 100644
--- a/spec/unit/provider/ifconfig_spec.rb
+++ b/spec/unit/provider/ifconfig_spec.rb
@@ -72,7 +72,7 @@ describe Chef::Provider::Ifconfig do
@provider.stub(:load_current_resource)
@provider.should_not_receive(:run_command)
@current_resource.inet_addr "10.0.0.1"
- @provider.should_not_receive(:generate_config)
+ @provider.should_receive(:generate_config)
@provider.run_action(:add)
@new_resource.should_not be_updated
@@ -123,7 +123,7 @@ describe Chef::Provider::Ifconfig do
it "should not delete interface if it does not exist" do
@provider.stub(:load_current_resource)
@provider.should_not_receive(:run_command)
- @provider.should_not_receive(:delete_config)
+ @provider.should_receive(:delete_config)
@provider.run_action(:delete)
@new_resource.should_not be_updated
@@ -171,7 +171,7 @@ describe Chef::Provider::Ifconfig do
@provider.stub(:load_current_resource)
# This is so that nothing actually runs
@provider.should_not_receive(:run_command)
- @provider.should_not_receive(:delete_config)
+ @provider.should_receive(:delete_config)
@provider.run_action(:delete)
@new_resource.should_not be_updated
diff --git a/spec/unit/provider/link_spec.rb b/spec/unit/provider/link_spec.rb
index 6052f5dd3b..2f0a5f2020 100644
--- a/spec/unit/provider/link_spec.rb
+++ b/spec/unit/provider/link_spec.rb
@@ -38,8 +38,8 @@ describe Chef::Resource::Link, :not_supported_on_win2k3 do
result
end
- def canonicalize(path)
- Chef::Platform.windows? ? path.gsub('/', '\\') : path
+ def paths_eql?(path1, path2)
+ Chef::Util::PathHelper.paths_eql?(path1, path2)
end
describe "when the target is a symlink" do
@@ -68,7 +68,7 @@ describe Chef::Resource::Link, :not_supported_on_win2k3 do
provider.current_resource.link_type.should == :symbolic
end
it "should update the source of the existing link with the links target" do
- provider.current_resource.to.should == canonicalize("#{CHEF_SPEC_DATA}/fofile")
+ paths_eql?(provider.current_resource.to, "#{CHEF_SPEC_DATA}/fofile").should be_true
end
it "should set the owner" do
provider.current_resource.owner.should == 501
@@ -110,7 +110,7 @@ describe Chef::Resource::Link, :not_supported_on_win2k3 do
provider.current_resource.link_type.should == :symbolic
end
it "should update the source of the existing link to the link's target" do
- provider.current_resource.to.should == canonicalize("#{CHEF_SPEC_DATA}/fofile")
+ paths_eql?(provider.current_resource.to, "#{CHEF_SPEC_DATA}/fofile").should be_true
end
it "should not set the owner" do
provider.current_resource.owner.should be_nil
@@ -221,7 +221,7 @@ describe Chef::Resource::Link, :not_supported_on_win2k3 do
provider.current_resource.link_type.should == :hard
end
it "should update the source of the existing link to the link's target" do
- provider.current_resource.to.should == canonicalize("#{CHEF_SPEC_DATA}/fofile")
+ paths_eql?(provider.current_resource.to, "#{CHEF_SPEC_DATA}/fofile").should be_true
end
it "should not set the owner" do
provider.current_resource.owner.should == nil
diff --git a/spec/unit/provider/package/aix_spec.rb b/spec/unit/provider/package/aix_spec.rb
index 35f85b628f..5d6e23302f 100644
--- a/spec/unit/provider/package/aix_spec.rb
+++ b/spec/unit/provider/package/aix_spec.rb
@@ -59,7 +59,6 @@ describe Chef::Provider::Package::Aix do
lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Package)
end
-
it "should get the source package version from lslpp if provided" do
@stdout = StringIO.new(@bffinfo)
@stdin, @stderr = StringIO.new, StringIO.new
@@ -125,9 +124,7 @@ describe Chef::Provider::Package::Aix do
describe "install and upgrade" do
it "should run installp -aYF -d with the package source to install" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "installp -aYF -d /tmp/samba.base samba.base"
- })
+ @provider.should_receive(:shell_out!).with("installp -aYF -d /tmp/samba.base samba.base")
@provider.install_package("samba.base", "3.3.12.0")
end
@@ -135,37 +132,28 @@ describe Chef::Provider::Package::Aix do
@new_resource = Chef::Resource::Package.new("/tmp/samba.base")
@provider = Chef::Provider::Package::Aix.new(@new_resource, @run_context)
@new_resource.source.should == "/tmp/samba.base"
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "installp -aYF -d /tmp/samba.base /tmp/samba.base"
- })
+ @provider.should_receive(:shell_out!).with("installp -aYF -d /tmp/samba.base /tmp/samba.base")
@provider.install_package("/tmp/samba.base", "3.3.12.0")
end
it "should run installp with -eLogfile option." do
@new_resource.stub(:options).and_return("-e/tmp/installp.log")
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "installp -aYF -e/tmp/installp.log -d /tmp/samba.base samba.base"
- })
+ @provider.should_receive(:shell_out!).with("installp -aYF -e/tmp/installp.log -d /tmp/samba.base samba.base")
@provider.install_package("samba.base", "3.3.12.0")
end
end
describe "remove" do
it "should run installp -u samba.base to remove the package" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "installp -u samba.base"
- })
+ @provider.should_receive(:shell_out!).with("installp -u samba.base")
@provider.remove_package("samba.base", "3.3.12.0")
end
it "should run installp -u -e/tmp/installp.log with options -e/tmp/installp.log" do
@new_resource.stub(:options).and_return("-e/tmp/installp.log")
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "installp -u -e/tmp/installp.log samba.base"
- })
+ @provider.should_receive(:shell_out!).with("installp -u -e/tmp/installp.log samba.base")
@provider.remove_package("samba.base", "3.3.12.0")
end
end
end
-
diff --git a/spec/unit/provider/package/homebrew_spec.rb b/spec/unit/provider/package/homebrew_spec.rb
new file mode 100644
index 0000000000..9f105c13b8
--- /dev/null
+++ b/spec/unit/provider/package/homebrew_spec.rb
@@ -0,0 +1,251 @@
+#
+# Author:: Joshua Timberman (<joshua@getchef.com>)
+# Copyright (c) 2014, Chef Software, Inc. <legal@getchef.com>
+#
+# 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::Provider::Package::Homebrew do
+ let(:node) { Chef::Node.new }
+ let(:events) { double('Chef::Events').as_null_object }
+ let(:run_context) { double('Chef::RunContext', node: node, events: events) }
+ let(:new_resource) { Chef::Resource::HomebrewPackage.new('emacs') }
+ let(:current_resource) { Chef::Resource::HomebrewPackage.new('emacs')}
+
+ let(:provider) do
+ Chef::Provider::Package::Homebrew.new(new_resource, run_context)
+ end
+
+ let(:uninstalled_brew_info) do
+ {
+ 'name' => 'emacs',
+ 'homepage' => 'http://www.gnu.org/software/emacs',
+ 'versions' => {
+ 'stable' => '24.3',
+ 'bottle' => false,
+ 'devel' => nil,
+ 'head' => nil
+ },
+ 'revision' => 0,
+ 'installed' => [],
+ 'linked_keg' => nil,
+ 'keg_only' => nil,
+ 'dependencies' => [],
+ 'conflicts_with' => [],
+ 'caveats' => nil,
+ 'options' => []
+ }
+ end
+
+ let(:installed_brew_info) do
+ {
+ 'name' => 'emacs',
+ 'homepage' => 'http://www.gnu.org/software/emacs/',
+ 'versions' => {
+ 'stable' => '24.3',
+ 'bottle' => false,
+ 'devel' => nil,
+ 'head' => 'HEAD'
+ },
+ 'revision' => 0,
+ 'installed' => [{ 'version' => '24.3' }],
+ 'linked_keg' => '24.3',
+ 'keg_only' => nil,
+ 'dependencies' => [],
+ 'conflicts_with' => [],
+ 'caveats' => '',
+ 'options' => []
+ }
+ end
+
+ let(:keg_only_brew_info) do
+ {
+ 'name' => 'emacs-kegger',
+ 'homepage' => 'http://www.gnu.org/software/emacs/',
+ 'versions' => {
+ 'stable' => '24.3-keggy',
+ 'bottle' => false,
+ 'devel' => nil,
+ 'head' => 'HEAD'
+ },
+ 'revision' => 0,
+ 'installed' => [{ 'version' => '24.3-keggy' }],
+ 'linked_keg' => nil,
+ 'keg_only' => true,
+ 'dependencies' => [],
+ 'conflicts_with' => [],
+ 'caveats' => '',
+ 'options' => []
+ }
+ end
+
+ before(:each) do
+ node.default['homebrew']['owner'] = 'sid_vicious'
+ allow(Etc).to receive(:getpwnam).with('sid_vicious').and_return('/Users/sid_vicious')
+ end
+
+ describe 'load_current_resource' do
+ before(:each) do
+ allow(provider).to receive(:current_installed_version).and_return(nil)
+ allow(provider).to receive(:candidate_version).and_return('24.3')
+ end
+
+ it 'creates a current resource with the name of the new resource' do
+ provider.load_current_resource
+ expect(provider.current_resource).to be_a(Chef::Resource::Package)
+ expect(provider.current_resource.name).to eql('emacs')
+ end
+
+ it 'creates a current resource with the version if the package is installed' do
+ expect(provider).to receive(:current_installed_version).and_return('24.3')
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eql('24.3')
+ end
+
+ it 'creates a current resource with a nil version if the package is not installed' do
+ provider.load_current_resource
+ expect(provider.current_resource.version).to be_nil
+ end
+
+ it 'sets a candidate version if one exists' do
+ provider.load_current_resource
+ expect(provider.candidate_version).to eql('24.3')
+ end
+ end
+
+ describe 'current_installed_version' do
+ it 'returns the latest version from brew info if the package is keg only' do
+ allow(provider).to receive(:brew_info).and_return(keg_only_brew_info)
+ expect(provider.current_installed_version).to eql('24.3-keggy')
+ end
+
+ it 'returns the linked keg version if the package is not keg only' do
+ allow(provider).to receive(:brew_info).and_return(installed_brew_info)
+ expect(provider.current_installed_version).to eql('24.3')
+ end
+
+ it 'returns nil if the package is not installed' do
+ allow(provider).to receive(:brew_info).and_return(uninstalled_brew_info)
+ expect(provider.current_installed_version).to be_nil
+ end
+ end
+
+ describe 'brew' do
+ it 'passes a single to the brew command and return stdout' do
+ allow(provider).to receive(:get_response_from_command).and_return('zombo')
+ expect(provider.brew).to eql('zombo')
+ end
+
+ it 'takes multiple arguments as an array' do
+ allow(provider).to receive(:get_response_from_command).and_return('homestarrunner')
+ expect(provider.brew('info', 'opts', 'bananas')).to eql('homestarrunner')
+ end
+ end
+
+ context 'when testing actions' do
+ before(:each) do
+ provider.current_resource = current_resource
+ end
+
+ describe 'install_package' do
+ before(:each) do
+ allow(provider).to receive(:candidate_version).and_return('24.3')
+ end
+
+ it 'installs the named package with brew install' do
+ allow(provider.new_resource).to receive(:version).and_return('24.3')
+ allow(provider.current_resource).to receive(:version).and_return(nil)
+ allow(provider).to receive(:brew_info).and_return(uninstalled_brew_info)
+ expect(provider).to receive(:get_response_from_command).with('brew install emacs')
+ provider.install_package('emacs', '24.3')
+ end
+
+ it 'does not do anything if the package is installed' do
+ allow(provider.current_resource).to receive(:version).and_return('24.3')
+ allow(provider).to receive(:brew_info).and_return(installed_brew_info)
+ expect(provider).not_to receive(:get_response_from_command)
+ provider.install_package('emacs', '24.3')
+ end
+
+ it 'uses options to the brew command if specified' do
+ allow(provider.new_resource).to receive(:options).and_return('--cocoa')
+ allow(provider.current_resource).to receive(:version).and_return('24.3')
+ allow(provider).to receive(:get_response_from_command).with('brew install --cocoa emacs')
+ provider.install_package('emacs', '24.3')
+ end
+ end
+
+ describe 'upgrade_package' do
+ it 'uses brew upgrade to upgrade the package if it is installed' do
+ allow(provider.current_resource).to receive(:version).and_return('24')
+ allow(provider).to receive(:brew_info).and_return(installed_brew_info)
+ expect(provider).to receive(:get_response_from_command).with('brew upgrade emacs')
+ provider.upgrade_package('emacs', '24.3')
+ end
+
+ it 'does not do anything if the package version is already installed' do
+ allow(provider.current_resource).to receive(:version).and_return('24.3')
+ allow(provider).to receive(:brew_info).and_return(installed_brew_info)
+ expect(provider).not_to receive(:get_response_from_command)
+ provider.install_package('emacs', '24.3')
+ end
+
+ it 'uses brew install to install the package if it is not installed' do
+ allow(provider.current_resource).to receive(:version).and_return(nil)
+ allow(provider).to receive(:brew_info).and_return(uninstalled_brew_info)
+ expect(provider).to receive(:get_response_from_command).with('brew install emacs')
+ provider.upgrade_package('emacs', '24.3')
+ end
+
+ it 'uses options to the brew command if specified' do
+ allow(provider.current_resource).to receive(:version).and_return('24')
+ allow(provider).to receive(:brew_info).and_return(installed_brew_info)
+ allow(provider.new_resource).to receive(:options).and_return('--cocoa')
+ expect(provider).to receive(:get_response_from_command).with('brew upgrade --cocoa emacs')
+ provider.upgrade_package('emacs', '24.3')
+ end
+ end
+
+ describe 'remove_package' do
+ it 'uninstalls the package with brew uninstall' do
+ allow(provider.current_resource).to receive(:version).and_return('24.3')
+ allow(provider).to receive(:brew_info).and_return(installed_brew_info)
+ expect(provider).to receive(:get_response_from_command).with('brew uninstall emacs')
+ provider.remove_package('emacs', '24.3')
+ end
+
+ it 'does not do anything if the package is not installed' do
+ allow(provider).to receive(:brew_info).and_return(uninstalled_brew_info)
+ expect(provider).not_to receive(:get_response_from_command)
+ provider.remove_package('emacs', '24.3')
+ end
+ end
+
+ describe 'purge_package' do
+ it 'uninstalls the package with brew uninstall --force' do
+ allow(provider.current_resource).to receive(:version).and_return('24.3')
+ allow(provider).to receive(:brew_info).and_return(installed_brew_info)
+ expect(provider).to receive(:get_response_from_command).with('brew uninstall --force emacs')
+ provider.purge_package('emacs', '24.3')
+ end
+
+ it 'does not do anything if the package is not installed' do
+ allow(provider).to receive(:brew_info).and_return(uninstalled_brew_info)
+ expect(provider).not_to receive(:get_response_from_command)
+ provider.purge_package('emacs', '24.3')
+ end
+ end
+ end
+end
diff --git a/spec/unit/provider/package/ips_spec.rb b/spec/unit/provider/package/ips_spec.rb
index c5941c2a91..07bca7f6d5 100644
--- a/spec/unit/provider/package/ips_spec.rb
+++ b/spec/unit/provider/package/ips_spec.rb
@@ -39,7 +39,7 @@ describe Chef::Provider::Package::Ips do
pkg: info: no packages matching the following patterns you specified are
installed on the system. Try specifying -r to query remotely:
- crypto/gnupg
+ crypto/gnupg
PKG_STATUS
return OpenStruct.new(:stdout => stdout,:stdin => stdin,:stderr => stderr,:status => @status,:exitstatus => 1)
end
@@ -59,7 +59,7 @@ Packaging Date: April 1, 2012 05:55:52 PM
FMRI: pkg://omnios/security/sudo@1.8.4.1,5.11-0.151002:20120401T175552Z
PKG_STATUS
stdin = StringIO.new
- stderr = ''
+ stderr = ''
return OpenStruct.new(:stdout => stdout,:stdin => stdin,:stderr => stderr,:status => @status,:exitstatus => 0)
end
@@ -123,17 +123,12 @@ INSTALLED
context "when installing a package" do
it "should run pkg install with the package name and version" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "pkg install -q crypto/gnupg@2.0.17"
- })
+ @provider.should_receive(:shell_out).with("pkg install -q crypto/gnupg@2.0.17")
@provider.install_package("crypto/gnupg", "2.0.17")
end
-
it "should run pkg install with the package name and version and options if specified" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "pkg --no-refresh install -q crypto/gnupg@2.0.17"
- })
+ @provider.should_receive(:shell_out).with("pkg --no-refresh install -q crypto/gnupg@2.0.17")
@new_resource.stub(:options).and_return("--no-refresh")
@provider.install_package("crypto/gnupg", "2.0.17")
end
@@ -206,9 +201,7 @@ REMOTE
end
it "should run pkg install with the --accept flag" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "pkg install -q --accept crypto/gnupg@2.0.17"
- })
+ @provider.should_receive(:shell_out).with("pkg install -q --accept crypto/gnupg@2.0.17")
@provider.install_package("crypto/gnupg", "2.0.17")
end
end
@@ -216,25 +209,19 @@ REMOTE
context "when upgrading a package" do
it "should run pkg install with the package name and version" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "pkg install -q crypto/gnupg@2.0.17"
- })
+ @provider.should_receive(:shell_out).with("pkg install -q crypto/gnupg@2.0.17")
@provider.upgrade_package("crypto/gnupg", "2.0.17")
end
end
context "when uninstalling a package" do
it "should run pkg uninstall with the package name and version" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "pkg uninstall -q crypto/gnupg@2.0.17"
- })
+ @provider.should_receive(:shell_out!).with("pkg uninstall -q crypto/gnupg@2.0.17")
@provider.remove_package("crypto/gnupg", "2.0.17")
end
it "should run pkg uninstall with the package name and version and options if specified" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "pkg --no-refresh uninstall -q crypto/gnupg@2.0.17"
- })
+ @provider.should_receive(:shell_out!).with("pkg --no-refresh uninstall -q crypto/gnupg@2.0.17")
@new_resource.stub(:options).and_return("--no-refresh")
@provider.remove_package("crypto/gnupg", "2.0.17")
end
diff --git a/spec/unit/provider/package/macports_spec.rb b/spec/unit/provider/package/macports_spec.rb
index 9ebf23860d..535a5d2459 100644
--- a/spec/unit/provider/package/macports_spec.rb
+++ b/spec/unit/provider/package/macports_spec.rb
@@ -105,7 +105,7 @@ EOF
it "should run the port install command with the correct version" do
@current_resource.should_receive(:version).and_return("4.1.6")
@provider.current_resource = @current_resource
- @provider.should_receive(:run_command_with_systems_locale).with(:command => "port install zsh @4.2.7")
+ @provider.should_receive(:shell_out!).with("port install zsh @4.2.7")
@provider.install_package("zsh", "4.2.7")
end
@@ -113,7 +113,7 @@ EOF
it "should not do anything if a package already exists with the same version" do
@current_resource.should_receive(:version).and_return("4.2.7")
@provider.current_resource = @current_resource
- @provider.should_not_receive(:run_command_with_systems_locale)
+ @provider.should_not_receive(:shell_out!)
@provider.install_package("zsh", "4.2.7")
end
@@ -122,7 +122,7 @@ EOF
@current_resource.should_receive(:version).and_return("4.1.6")
@provider.current_resource = @current_resource
@new_resource.stub(:options).and_return("-f")
- @provider.should_receive(:run_command_with_systems_locale).with(:command => "port -f install zsh @4.2.7")
+ @provider.should_receive(:shell_out!).with("port -f install zsh @4.2.7")
@provider.install_package("zsh", "4.2.7")
end
@@ -130,36 +130,36 @@ EOF
describe "purge_package" do
it "should run the port uninstall command with the correct version" do
- @provider.should_receive(:run_command_with_systems_locale).with(:command => "port uninstall zsh @4.2.7")
+ @provider.should_receive(:shell_out!).with("port uninstall zsh @4.2.7")
@provider.purge_package("zsh", "4.2.7")
end
it "should purge the currently active version if no explicit version is passed in" do
- @provider.should_receive(:run_command_with_systems_locale).with(:command => "port uninstall zsh")
+ @provider.should_receive(:shell_out!).with("port uninstall zsh")
@provider.purge_package("zsh", nil)
end
it "should add options to the port command when specified" do
@new_resource.stub(:options).and_return("-f")
- @provider.should_receive(:run_command_with_systems_locale).with(:command => "port -f uninstall zsh @4.2.7")
+ @provider.should_receive(:shell_out!).with("port -f uninstall zsh @4.2.7")
@provider.purge_package("zsh", "4.2.7")
end
end
describe "remove_package" do
it "should run the port deactivate command with the correct version" do
- @provider.should_receive(:run_command_with_systems_locale).with(:command => "port deactivate zsh @4.2.7")
+ @provider.should_receive(:shell_out!).with("port deactivate zsh @4.2.7")
@provider.remove_package("zsh", "4.2.7")
end
it "should remove the currently active version if no explicit version is passed in" do
- @provider.should_receive(:run_command_with_systems_locale).with(:command => "port deactivate zsh")
+ @provider.should_receive(:shell_out!).with("port deactivate zsh")
@provider.remove_package("zsh", nil)
end
it "should add options to the port command when specified" do
@new_resource.stub(:options).and_return("-f")
- @provider.should_receive(:run_command_with_systems_locale).with(:command => "port -f deactivate zsh @4.2.7")
+ @provider.should_receive(:shell_out!).with("port -f deactivate zsh @4.2.7")
@provider.remove_package("zsh", "4.2.7")
end
end
@@ -169,7 +169,7 @@ EOF
@current_resource.should_receive(:version).at_least(:once).and_return("4.1.6")
@provider.current_resource = @current_resource
- @provider.should_receive(:run_command_with_systems_locale).with(:command => "port upgrade zsh @4.2.7")
+ @provider.should_receive(:shell_out!).with("port upgrade zsh @4.2.7")
@provider.upgrade_package("zsh", "4.2.7")
end
@@ -177,7 +177,7 @@ EOF
it "should not run the port upgrade command if the version is already installed" do
@current_resource.should_receive(:version).at_least(:once).and_return("4.2.7")
@provider.current_resource = @current_resource
- @provider.should_not_receive(:run_command_with_systems_locale)
+ @provider.should_not_receive(:shell_out!)
@provider.upgrade_package("zsh", "4.2.7")
end
@@ -195,7 +195,7 @@ EOF
@current_resource.should_receive(:version).at_least(:once).and_return("4.1.6")
@provider.current_resource = @current_resource
- @provider.should_receive(:run_command_with_systems_locale).with(:command => "port -f upgrade zsh @4.2.7")
+ @provider.should_receive(:shell_out!).with("port -f upgrade zsh @4.2.7")
@provider.upgrade_package("zsh", "4.2.7")
end
diff --git a/spec/unit/provider/package/pacman_spec.rb b/spec/unit/provider/package/pacman_spec.rb
index 528f7097e8..0c1c487980 100644
--- a/spec/unit/provider/package/pacman_spec.rb
+++ b/spec/unit/provider/package/pacman_spec.rb
@@ -155,16 +155,12 @@ PACMAN_CONF
describe Chef::Provider::Package::Pacman, "install_package" do
it "should run pacman install with the package name and version" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "pacman --sync --noconfirm --noprogressbar nano"
- })
+ @provider.should_receive(:shell_out!).with("pacman --sync --noconfirm --noprogressbar nano")
@provider.install_package("nano", "1.0")
end
it "should run pacman install with the package name and version and options if specified" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "pacman --sync --noconfirm --noprogressbar --debug nano"
- })
+ @provider.should_receive(:shell_out!).with("pacman --sync --noconfirm --noprogressbar --debug nano")
@new_resource.stub(:options).and_return("--debug")
@provider.install_package("nano", "1.0")
@@ -180,16 +176,12 @@ PACMAN_CONF
describe Chef::Provider::Package::Pacman, "remove_package" do
it "should run pacman remove with the package name" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "pacman --remove --noconfirm --noprogressbar nano"
- })
+ @provider.should_receive(:shell_out!).with("pacman --remove --noconfirm --noprogressbar nano")
@provider.remove_package("nano", "1.0")
end
it "should run pacman remove with the package name and options if specified" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "pacman --remove --noconfirm --noprogressbar --debug nano"
- })
+ @provider.should_receive(:shell_out!).with("pacman --remove --noconfirm --noprogressbar --debug nano")
@new_resource.stub(:options).and_return("--debug")
@provider.remove_package("nano", "1.0")
diff --git a/spec/unit/provider/package/portage_spec.rb b/spec/unit/provider/package/portage_spec.rb
index 6f22952da2..570f123168 100644
--- a/spec/unit/provider/package/portage_spec.rb
+++ b/spec/unit/provider/package/portage_spec.rb
@@ -278,23 +278,17 @@ EOF
describe Chef::Provider::Package::Portage, "install_package" do
it "should install a normally versioned package using portage" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "emerge -g --color n --nospinner --quiet =dev-util/git-1.0.0"
- })
+ @provider.should_receive(:shell_out!).with("emerge -g --color n --nospinner --quiet =dev-util/git-1.0.0")
@provider.install_package("dev-util/git", "1.0.0")
end
it "should install a tilde versioned package using portage" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "emerge -g --color n --nospinner --quiet ~dev-util/git-1.0.0"
- })
+ @provider.should_receive(:shell_out!).with("emerge -g --color n --nospinner --quiet ~dev-util/git-1.0.0")
@provider.install_package("dev-util/git", "~1.0.0")
end
it "should add options to the emerge command when specified" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "emerge -g --color n --nospinner --quiet --oneshot =dev-util/git-1.0.0"
- })
+ @provider.should_receive(:shell_out!).with("emerge -g --color n --nospinner --quiet --oneshot =dev-util/git-1.0.0")
@new_resource.stub(:options).and_return("--oneshot")
@provider.install_package("dev-util/git", "1.0.0")
@@ -303,16 +297,12 @@ EOF
describe Chef::Provider::Package::Portage, "remove_package" do
it "should un-emerge the package with no version specified" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "emerge --unmerge --color n --nospinner --quiet dev-util/git"
- })
+ @provider.should_receive(:shell_out!).with("emerge --unmerge --color n --nospinner --quiet dev-util/git")
@provider.remove_package("dev-util/git", nil)
end
it "should un-emerge the package with a version specified" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "emerge --unmerge --color n --nospinner --quiet =dev-util/git-1.0.0"
- })
+ @provider.should_receive(:shell_out!).with("emerge --unmerge --color n --nospinner --quiet =dev-util/git-1.0.0")
@provider.remove_package("dev-util/git", "1.0.0")
end
end
diff --git a/spec/unit/provider/package/rpm_spec.rb b/spec/unit/provider/package/rpm_spec.rb
index 6e46cf5e98..9a96d829b8 100644
--- a/spec/unit/provider/package/rpm_spec.rb
+++ b/spec/unit/provider/package/rpm_spec.rb
@@ -102,25 +102,19 @@ describe Chef::Provider::Package::Rpm do
describe "when installing or upgrading" do
it "should run rpm -i with the package source to install" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "rpm -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm"
- })
+ @provider.should_receive(:shell_out!).with("rpm -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
@provider.install_package("ImageMagick-c++", "6.5.4.7-7.el6_5")
end
it "should run rpm -U with the package source to upgrade" do
@current_resource.version("21.4-19.el5")
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm"
- })
+ @provider.should_receive(:shell_out!).with("rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
@provider.upgrade_package("ImageMagick-c++", "6.5.4.7-7.el6_5")
end
it "should install package if missing and set to upgrade" do
@current_resource.version("ImageMagick-c++")
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm"
- })
+ @provider.should_receive(:shell_out!).with("rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
@provider.upgrade_package("ImageMagick-c++", "6.5.4.7-7.el6_5")
end
@@ -130,9 +124,7 @@ describe Chef::Provider::Package::Rpm do
@new_resource.source.should == "/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm"
@current_resource = Chef::Resource::Package.new("ImageMagick-c++")
@provider.current_resource = @current_resource
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "rpm -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm"
- })
+ @provider.should_receive(:shell_out!).with("rpm -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
@provider.install_package("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", "6.5.4.7-7.el6_5")
end
@@ -143,30 +135,23 @@ describe Chef::Provider::Package::Rpm do
@current_resource = Chef::Resource::Package.new("ImageMagick-c++")
@current_resource.version("21.4-19.el5")
@provider.current_resource = @current_resource
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm"
- })
+ @provider.should_receive(:shell_out!).with("rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
@provider.upgrade_package("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", "6.5.4.7-7.el6_5")
end
it "installs with custom options specified in the resource" do
@provider.candidate_version = '11'
@new_resource.options("--dbpath /var/lib/rpm")
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "rpm --dbpath /var/lib/rpm -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm"
- })
+ @provider.should_receive(:shell_out!).with("rpm --dbpath /var/lib/rpm -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
@provider.install_package(@new_resource.name, @provider.candidate_version)
end
end
describe "when removing the package" do
it "should run rpm -e to remove the package" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "rpm -e ImageMagick-c++-6.5.4.7-7.el6_5"
- })
+ @provider.should_receive(:shell_out!).with("rpm -e ImageMagick-c++-6.5.4.7-7.el6_5")
@provider.remove_package("ImageMagick-c++", "6.5.4.7-7.el6_5")
end
end
end
end
-
diff --git a/spec/unit/provider/package/solaris_spec.rb b/spec/unit/provider/package/solaris_spec.rb
index 086e327cce..d83ccbdf06 100644
--- a/spec/unit/provider/package/solaris_spec.rb
+++ b/spec/unit/provider/package/solaris_spec.rb
@@ -69,7 +69,6 @@ PKGINFO
lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Package)
end
-
it "should get the source package version from pkginfo if provided" do
@stdout = StringIO.new(@pkginfo)
@stdin, @stderr = StringIO.new, StringIO.new
@@ -136,9 +135,7 @@ PKGINFO
describe "install and upgrade" do
it "should run pkgadd -n -d with the package source to install" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "pkgadd -n -d /tmp/bash.pkg all"
- })
+ @provider.should_receive(:shell_out!).with("pkgadd -n -d /tmp/bash.pkg all")
@provider.install_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16")
end
@@ -146,34 +143,26 @@ PKGINFO
@new_resource = Chef::Resource::Package.new("/tmp/bash.pkg")
@provider = Chef::Provider::Package::Solaris.new(@new_resource, @run_context)
@new_resource.source.should == "/tmp/bash.pkg"
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "pkgadd -n -d /tmp/bash.pkg all"
- })
+ @provider.should_receive(:shell_out!).with("pkgadd -n -d /tmp/bash.pkg all")
@provider.install_package("/tmp/bash.pkg", "11.10.0,REV=2005.01.08.05.16")
end
it "should run pkgadd -n -a /tmp/myadmin -d with the package options -a /tmp/myadmin" do
@new_resource.stub(:options).and_return("-a /tmp/myadmin")
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "pkgadd -n -a /tmp/myadmin -d /tmp/bash.pkg all"
- })
+ @provider.should_receive(:shell_out!).with("pkgadd -n -a /tmp/myadmin -d /tmp/bash.pkg all")
@provider.install_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16")
end
end
describe "remove" do
it "should run pkgrm -n to remove the package" do
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "pkgrm -n SUNWbash"
- })
+ @provider.should_receive(:shell_out!).with("pkgrm -n SUNWbash")
@provider.remove_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16")
end
it "should run pkgrm -n -a /tmp/myadmin with options -a /tmp/myadmin" do
@new_resource.stub(:options).and_return("-a /tmp/myadmin")
- @provider.should_receive(:run_command_with_systems_locale).with({
- :command => "pkgrm -n -a /tmp/myadmin SUNWbash"
- })
+ @provider.should_receive(:shell_out!).with("pkgrm -n -a /tmp/myadmin SUNWbash")
@provider.remove_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16")
end
diff --git a/spec/unit/provider/service/arch_service_spec.rb b/spec/unit/provider/service/arch_service_spec.rb
index b267915e44..38ed74cdee 100644
--- a/spec/unit/provider/service/arch_service_spec.rb
+++ b/spec/unit/provider/service/arch_service_spec.rb
@@ -20,7 +20,6 @@
require 'spec_helper'
require 'ostruct'
-
# most of this code has been ripped from init_service_spec.rb
# and is only slightly modified to match "arch" needs.
@@ -36,7 +35,6 @@ describe Chef::Provider::Service::Arch, "load_current_resource" do
@new_resource.pattern("chef")
@new_resource.supports({:status => false})
-
@provider = Chef::Provider::Service::Arch.new(@new_resource, @run_context)
::File.stub(:exists?).with("/etc/rc.conf").and_return(true)
@@ -51,7 +49,6 @@ describe Chef::Provider::Service::Arch, "load_current_resource" do
end
end
-
describe "when the service supports status" do
before do
@new_resource.supports({:status => true})
@@ -82,7 +79,6 @@ describe Chef::Provider::Service::Arch, "load_current_resource" do
end
-
describe "when a status command has been specified" do
before do
@new_resource.status_command("/etc/rc.d/chefhasmonkeypants status")
@@ -109,7 +105,6 @@ describe Chef::Provider::Service::Arch, "load_current_resource" do
lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service)
end
-
it "should fail if file /etc/rc.conf does not exist" do
::File.stub(:exists?).with("/etc/rc.conf").and_return(false)
lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Service)
@@ -211,7 +206,6 @@ RUNNING_PS
end
end
-
describe Chef::Provider::Service::Arch, "start_service" do
# before(:each) do
# @new_resource = double("Chef::Resource::Service",
@@ -228,12 +222,12 @@ RUNNING_PS
it "should call the start command if one is specified" do
@new_resource.stub(:start_command).and_return("/etc/rc.d/chef startyousillysally")
- @provider.should_receive(:shell_out!).with("/etc/rc.d/chef startyousillysally")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/rc.d/chef startyousillysally")
@provider.start_service()
end
it "should call '/etc/rc.d/service_name start' if no start command is specified" do
- @provider.should_receive(:shell_out!).with("/etc/rc.d/#{@new_resource.service_name} start")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{@new_resource.service_name} start")
@provider.start_service()
end
end
@@ -254,12 +248,12 @@ RUNNING_PS
it "should call the stop command if one is specified" do
@new_resource.stub(:stop_command).and_return("/etc/rc.d/chef itoldyoutostop")
- @provider.should_receive(:shell_out!).with("/etc/rc.d/chef itoldyoutostop")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/rc.d/chef itoldyoutostop")
@provider.stop_service()
end
it "should call '/etc/rc.d/service_name stop' if no stop command is specified" do
- @provider.should_receive(:shell_out!).with("/etc/rc.d/#{@new_resource.service_name} stop")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{@new_resource.service_name} stop")
@provider.stop_service()
end
end
@@ -281,13 +275,13 @@ RUNNING_PS
it "should call 'restart' on the service_name if the resource supports it" do
@new_resource.stub(:supports).and_return({:restart => true})
- @provider.should_receive(:shell_out!).with("/etc/rc.d/#{@new_resource.service_name} restart")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{@new_resource.service_name} restart")
@provider.restart_service()
end
it "should call the restart_command if one has been specified" do
@new_resource.stub(:restart_command).and_return("/etc/rc.d/chef restartinafire")
- @provider.should_receive(:shell_out!).with("/etc/rc.d/#{@new_resource.service_name} restartinafire")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{@new_resource.service_name} restartinafire")
@provider.restart_service()
end
@@ -316,13 +310,13 @@ RUNNING_PS
it "should call 'reload' on the service if it supports it" do
@new_resource.stub(:supports).and_return({:reload => true})
- @provider.should_receive(:shell_out!).with("/etc/rc.d/#{@new_resource.service_name} reload")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{@new_resource.service_name} reload")
@provider.reload_service()
end
it "should should run the user specified reload command if one is specified and the service doesn't support reload" do
@new_resource.stub(:reload_command).and_return("/etc/rc.d/chef lollerpants")
- @provider.should_receive(:shell_out!).with("/etc/rc.d/#{@new_resource.service_name} lollerpants")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{@new_resource.service_name} lollerpants")
@provider.reload_service()
end
end
diff --git a/spec/unit/provider/service/debian_service_spec.rb b/spec/unit/provider/service/debian_service_spec.rb
index 567eb6744a..3e60857cbf 100644
--- a/spec/unit/provider/service/debian_service_spec.rb
+++ b/spec/unit/provider/service/debian_service_spec.rb
@@ -301,7 +301,7 @@ insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop
def expect_commands(provider, commands)
commands.each do |command|
- provider.should_receive(:run_command).with({:command => command})
+ provider.should_receive(:shell_out!).with(command)
end
end
diff --git a/spec/unit/provider/service/freebsd_service_spec.rb b/spec/unit/provider/service/freebsd_service_spec.rb
index 6e58e82b97..eb55fac820 100644
--- a/spec/unit/provider/service/freebsd_service_spec.rb
+++ b/spec/unit/provider/service/freebsd_service_spec.rb
@@ -452,12 +452,12 @@ EOF
describe Chef::Provider::Service::Freebsd, "start_service" do
it "should call the start command if one is specified" do
new_resource.start_command("/etc/rc.d/chef startyousillysally")
- expect(provider).to receive(:shell_out!).with("/etc/rc.d/chef startyousillysally")
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("/etc/rc.d/chef startyousillysally")
provider.start_service()
end
it "should call '/usr/local/etc/rc.d/service_name faststart' if no start command is specified" do
- expect(provider).to receive(:shell_out!).with("/usr/local/etc/rc.d/#{new_resource.service_name} faststart")
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("/usr/local/etc/rc.d/#{new_resource.service_name} faststart")
provider.start_service()
end
end
@@ -465,12 +465,12 @@ EOF
describe Chef::Provider::Service::Freebsd, "stop_service" do
it "should call the stop command if one is specified" do
new_resource.stop_command("/etc/init.d/chef itoldyoutostop")
- expect(provider).to receive(:shell_out!).with("/etc/init.d/chef itoldyoutostop")
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("/etc/init.d/chef itoldyoutostop")
provider.stop_service()
end
it "should call '/usr/local/etc/rc.d/service_name faststop' if no stop command is specified" do
- expect(provider).to receive(:shell_out!).with("/usr/local/etc/rc.d/#{new_resource.service_name} faststop")
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("/usr/local/etc/rc.d/#{new_resource.service_name} faststop")
provider.stop_service()
end
end
@@ -478,13 +478,13 @@ EOF
describe Chef::Provider::Service::Freebsd, "restart_service" do
it "should call 'restart' on the service_name if the resource supports it" do
new_resource.supports({:restart => true})
- expect(provider).to receive(:shell_out!).with("/usr/local/etc/rc.d/#{new_resource.service_name} fastrestart")
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("/usr/local/etc/rc.d/#{new_resource.service_name} fastrestart")
provider.restart_service()
end
it "should call the restart_command if one has been specified" do
new_resource.restart_command("/etc/init.d/chef restartinafire")
- expect(provider).to receive(:shell_out!).with("/etc/init.d/chef restartinafire")
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("/etc/init.d/chef restartinafire")
provider.restart_service()
end
diff --git a/spec/unit/provider/service/gentoo_service_spec.rb b/spec/unit/provider/service/gentoo_service_spec.rb
index 95dc04108d..022a73cc9a 100644
--- a/spec/unit/provider/service/gentoo_service_spec.rb
+++ b/spec/unit/provider/service/gentoo_service_spec.rb
@@ -128,14 +128,14 @@ describe Chef::Provider::Service::Gentoo do
describe Chef::Provider::Service::Gentoo, "enable_service" do
it "should call rc-update add *service* default" do
- @provider.should_receive(:run_command).with({:command => "/sbin/rc-update add chef default"})
+ @provider.should_receive(:shell_out!).with("/sbin/rc-update add chef default")
@provider.enable_service()
end
end
describe Chef::Provider::Service::Gentoo, "disable_service" do
it "should call rc-update del *service* default" do
- @provider.should_receive(:run_command).with({:command => "/sbin/rc-update del chef default"})
+ @provider.should_receive(:shell_out!).with("/sbin/rc-update del chef default")
@provider.disable_service()
end
end
diff --git a/spec/unit/provider/service/init_service_spec.rb b/spec/unit/provider/service/init_service_spec.rb
index ad887c84a5..b523f6d3a9 100644
--- a/spec/unit/provider/service/init_service_spec.rb
+++ b/spec/unit/provider/service/init_service_spec.rb
@@ -100,7 +100,7 @@ PS
end
it "should use the init_command if one has been specified" do
- @provider.should_receive(:shell_out!).with("/opt/chef-server/service/erchef start")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/opt/chef-server/service/erchef start")
@provider.start_service
end
@@ -126,7 +126,6 @@ PS
end
-
describe "when we have a 'ps' attribute" do
it "should shell_out! the node's ps command" do
@provider.should_receive(:shell_out!).and_return(@status)
@@ -165,12 +164,12 @@ RUNNING_PS
describe "when starting the service" do
it "should call the start command if one is specified" do
@new_resource.start_command("/etc/init.d/chef startyousillysally")
- @provider.should_receive(:shell_out!).with("/etc/init.d/chef startyousillysally")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/chef startyousillysally")
@provider.start_service()
end
it "should call '/etc/init.d/service_name start' if no start command is specified" do
- @provider.should_receive(:shell_out!).with("/etc/init.d/#{@new_resource.service_name} start")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/#{@new_resource.service_name} start")
@provider.start_service()
end
end
@@ -178,12 +177,12 @@ RUNNING_PS
describe Chef::Provider::Service::Init, "stop_service" do
it "should call the stop command if one is specified" do
@new_resource.stop_command("/etc/init.d/chef itoldyoutostop")
- @provider.should_receive(:shell_out!).with("/etc/init.d/chef itoldyoutostop")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/chef itoldyoutostop")
@provider.stop_service()
end
it "should call '/etc/init.d/service_name stop' if no stop command is specified" do
- @provider.should_receive(:shell_out!).with("/etc/init.d/#{@new_resource.service_name} stop")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/#{@new_resource.service_name} stop")
@provider.stop_service()
end
end
@@ -191,13 +190,13 @@ RUNNING_PS
describe "when restarting a service" do
it "should call 'restart' on the service_name if the resource supports it" do
@new_resource.supports({:restart => true})
- @provider.should_receive(:shell_out!).with("/etc/init.d/#{@new_resource.service_name} restart")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/#{@new_resource.service_name} restart")
@provider.restart_service()
end
it "should call the restart_command if one has been specified" do
@new_resource.restart_command("/etc/init.d/chef restartinafire")
- @provider.should_receive(:shell_out!).with("/etc/init.d/#{@new_resource.service_name} restartinafire")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/#{@new_resource.service_name} restartinafire")
@provider.restart_service()
end
@@ -212,13 +211,13 @@ RUNNING_PS
describe "when reloading a service" do
it "should call 'reload' on the service if it supports it" do
@new_resource.supports({:reload => true})
- @provider.should_receive(:shell_out!).with("/etc/init.d/chef reload")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/chef reload")
@provider.reload_service()
end
it "should should run the user specified reload command if one is specified and the service doesn't support reload" do
@new_resource.reload_command("/etc/init.d/chef lollerpants")
- @provider.should_receive(:shell_out!).with("/etc/init.d/chef lollerpants")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/chef lollerpants")
@provider.reload_service()
end
end
@@ -226,6 +225,7 @@ RUNNING_PS
describe "when a custom command has been specified" do
before do
@new_resource.start_command("/etc/init.d/chef startyousillysally")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/chef startyousillysally")
end
it "should still pass all why run assertions" do
diff --git a/spec/unit/provider/service/insserv_service_spec.rb b/spec/unit/provider/service/insserv_service_spec.rb
index 04e63458a0..9ed03b519f 100644
--- a/spec/unit/provider/service/insserv_service_spec.rb
+++ b/spec/unit/provider/service/insserv_service_spec.rb
@@ -60,17 +60,16 @@ describe Chef::Provider::Service::Insserv do
describe "enable_service" do
it "should call insserv and create the default links" do
- @provider.should_receive(:run_command).with({:command=>"/sbin/insserv -r -f #{@new_resource.service_name}"})
- @provider.should_receive(:run_command).with({:command=>"/sbin/insserv -d -f #{@new_resource.service_name}"})
+ @provider.should_receive(:shell_out!).with("/sbin/insserv -r -f #{@new_resource.service_name}")
+ @provider.should_receive(:shell_out!).with("/sbin/insserv -d -f #{@new_resource.service_name}")
@provider.enable_service
end
end
describe "disable_service" do
it "should call insserv and remove the links" do
- @provider.should_receive(:run_command).with({:command=>"/sbin/insserv -r -f #{@new_resource.service_name}"})
+ @provider.should_receive(:shell_out!).with("/sbin/insserv -r -f #{@new_resource.service_name}")
@provider.disable_service
end
end
end
-
diff --git a/spec/unit/provider/service/invokercd_service_spec.rb b/spec/unit/provider/service/invokercd_service_spec.rb
index b638b08b72..d8a9851837 100644
--- a/spec/unit/provider/service/invokercd_service_spec.rb
+++ b/spec/unit/provider/service/invokercd_service_spec.rb
@@ -110,7 +110,6 @@ PS
end
-
describe "when we have a 'ps' attribute" do
it "should shell_out! the node's ps command" do
@status = double("Status", :exitstatus => 0, :stdout => @stdout)
@@ -152,12 +151,12 @@ RUNNING_PS
describe "when starting the service" do
it "should call the start command if one is specified" do
@new_resource.start_command("/usr/sbin/invoke-rc.d chef startyousillysally")
- @provider.should_receive(:shell_out!).with("/usr/sbin/invoke-rc.d chef startyousillysally")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/usr/sbin/invoke-rc.d chef startyousillysally")
@provider.start_service()
end
it "should call '/usr/sbin/invoke-rc.d service_name start' if no start command is specified" do
- @provider.should_receive(:shell_out!).with("/usr/sbin/invoke-rc.d #{@new_resource.service_name} start")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/usr/sbin/invoke-rc.d #{@new_resource.service_name} start")
@provider.start_service()
end
end
@@ -165,12 +164,12 @@ RUNNING_PS
describe Chef::Provider::Service::Invokercd, "stop_service" do
it "should call the stop command if one is specified" do
@new_resource.stop_command("/usr/sbin/invoke-rc.d chef itoldyoutostop")
- @provider.should_receive(:shell_out!).with("/usr/sbin/invoke-rc.d chef itoldyoutostop")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/usr/sbin/invoke-rc.d chef itoldyoutostop")
@provider.stop_service()
end
it "should call '/usr/sbin/invoke-rc.d service_name stop' if no stop command is specified" do
- @provider.should_receive(:shell_out!).with("/usr/sbin/invoke-rc.d #{@new_resource.service_name} stop")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/usr/sbin/invoke-rc.d #{@new_resource.service_name} stop")
@provider.stop_service()
end
end
@@ -178,13 +177,13 @@ RUNNING_PS
describe "when restarting a service" do
it "should call 'restart' on the service_name if the resource supports it" do
@new_resource.supports({:restart => true})
- @provider.should_receive(:shell_out!).with("/usr/sbin/invoke-rc.d #{@new_resource.service_name} restart")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/usr/sbin/invoke-rc.d #{@new_resource.service_name} restart")
@provider.restart_service()
end
it "should call the restart_command if one has been specified" do
@new_resource.restart_command("/usr/sbin/invoke-rc.d chef restartinafire")
- @provider.should_receive(:shell_out!).with("/usr/sbin/invoke-rc.d #{@new_resource.service_name} restartinafire")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/usr/sbin/invoke-rc.d #{@new_resource.service_name} restartinafire")
@provider.restart_service()
end
@@ -199,13 +198,13 @@ RUNNING_PS
describe "when reloading a service" do
it "should call 'reload' on the service if it supports it" do
@new_resource.supports({:reload => true})
- @provider.should_receive(:shell_out!).with("/usr/sbin/invoke-rc.d chef reload")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/usr/sbin/invoke-rc.d chef reload")
@provider.reload_service()
end
it "should should run the user specified reload command if one is specified and the service doesn't support reload" do
@new_resource.reload_command("/usr/sbin/invoke-rc.d chef lollerpants")
- @provider.should_receive(:shell_out!).with("/usr/sbin/invoke-rc.d chef lollerpants")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/usr/sbin/invoke-rc.d chef lollerpants")
@provider.reload_service()
end
end
diff --git a/spec/unit/provider/service/macosx_spec.rb b/spec/unit/provider/service/macosx_spec.rb
index 1202d80873..c5df1e0637 100644
--- a/spec/unit/provider/service/macosx_spec.rb
+++ b/spec/unit/provider/service/macosx_spec.rb
@@ -226,7 +226,7 @@ SVC_LIST
it "calls the start command if one is specified and service is not running" do
new_resource.stub(:start_command).and_return("cowsay dirty")
- provider.should_receive(:shell_out!).with("cowsay dirty")
+ provider.should_receive(:shell_out_with_systems_locale!).with("cowsay dirty")
provider.start_service
end
@@ -238,7 +238,7 @@ SVC_LIST
end
it "starts service via launchctl if service found" do
- provider.should_receive(:shell_out!).
+ provider.should_receive(:shell_out_with_systems_locale!).
with("launchctl load -w '/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist'",
:group => 1001, :user => 101).
and_return(0)
@@ -258,7 +258,7 @@ SVC_LIST
it "calls the stop command if one is specified and service is running" do
new_resource.stub(:stop_command).and_return("kill -9 123")
- provider.should_receive(:shell_out!).with("kill -9 123")
+ provider.should_receive(:shell_out_with_systems_locale!).with("kill -9 123")
provider.stop_service
end
@@ -270,7 +270,7 @@ SVC_LIST
end
it "stops the service via launchctl if service found" do
- provider.should_receive(:shell_out!).
+ provider.should_receive(:shell_out_with_systems_locale!).
with("launchctl unload '/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist'",
:group => 1001, :user => 101).
and_return(0)
@@ -291,7 +291,7 @@ SVC_LIST
it "issues a command if given" do
new_resource.stub(:restart_command).and_return("reload that thing")
- provider.should_receive(:shell_out!).with("reload that thing")
+ provider.should_receive(:shell_out_with_systems_locale!).with("reload that thing")
provider.restart_service
end
diff --git a/spec/unit/provider/service/simple_service_spec.rb b/spec/unit/provider/service/simple_service_spec.rb
index 61fb30fe13..11ebf74725 100644
--- a/spec/unit/provider/service/simple_service_spec.rb
+++ b/spec/unit/provider/service/simple_service_spec.rb
@@ -107,7 +107,7 @@ NOMOCKINGSTRINGSPLZ
describe "when starting the service" do
it "should call the start command if one is specified" do
@new_resource.stub(:start_command).and_return("#{@new_resource.start_command}")
- @provider.should_receive(:shell_out!).with("#{@new_resource.start_command}")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("#{@new_resource.start_command}")
@provider.start_service()
end
@@ -121,7 +121,7 @@ NOMOCKINGSTRINGSPLZ
describe "when stopping a service" do
it "should call the stop command if one is specified" do
@new_resource.stop_command("/etc/init.d/themadness stop")
- @provider.should_receive(:shell_out!).with("/etc/init.d/themadness stop")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/themadness stop")
@provider.stop_service()
end
@@ -135,7 +135,7 @@ NOMOCKINGSTRINGSPLZ
describe Chef::Provider::Service::Simple, "restart_service" do
it "should call the restart command if one has been specified" do
@new_resource.restart_command("/etc/init.d/foo restart")
- @provider.should_receive(:shell_out!).with("/etc/init.d/foo restart")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/foo restart")
@provider.restart_service()
end
@@ -162,7 +162,7 @@ NOMOCKINGSTRINGSPLZ
it "should should run the user specified reload command if one is specified" do
@new_resource.reload_command("kill -9 1")
- @provider.should_receive(:shell_out!).with("kill -9 1")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("kill -9 1")
@provider.reload_service()
end
end
diff --git a/spec/unit/provider/service/solaris_smf_service_spec.rb b/spec/unit/provider/service/solaris_smf_service_spec.rb
index 978f149258..8df22efa7e 100644
--- a/spec/unit/provider/service/solaris_smf_service_spec.rb
+++ b/spec/unit/provider/service/solaris_smf_service_spec.rb
@@ -59,7 +59,6 @@ describe Chef::Provider::Service::Solaris do
@provider.load_current_resource
end
-
it "should return the current resource" do
@provider.stub(:shell_out!).with("/bin/svcs -l chef").and_return(@status)
@provider.load_current_resource.should eql(@current_resource)
@@ -131,7 +130,6 @@ describe Chef::Provider::Service::Solaris do
end
end
-
describe "when disabling the service" do
before(:each) do
@provider.current_resource = @current_resource
@@ -159,7 +157,7 @@ describe Chef::Provider::Service::Solaris do
end
it "should call svcadm refresh chef" do
- @provider.should_receive(:shell_out!).with("/usr/sbin/svcadm refresh chef").and_return(@status)
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/usr/sbin/svcadm refresh chef").and_return(@status)
@provider.reload_service
end
diff --git a/spec/unit/provider/service/systemd_service_spec.rb b/spec/unit/provider/service/systemd_service_spec.rb
index 2aa7b539f2..7358f63b5e 100644
--- a/spec/unit/provider/service/systemd_service_spec.rb
+++ b/spec/unit/provider/service/systemd_service_spec.rb
@@ -74,25 +74,25 @@ describe Chef::Provider::Service::Systemd do
end
it "should run the services status command if one has been specified" do
- @provider.stub(:shell_out_with_systems_locale).and_return(@shell_out_success)
+ @provider.stub(:shell_out).and_return(@shell_out_success)
@current_resource.should_receive(:running).with(true)
@provider.load_current_resource
end
it "should run the services status command if one has been specified and properly set status check state" do
- @provider.stub(:shell_out_with_systems_locale).with("/bin/chefhasmonkeypants status").and_return(@shell_out_success)
+ @provider.stub(:shell_out).with("/bin/chefhasmonkeypants status").and_return(@shell_out_success)
@provider.load_current_resource
@provider.instance_variable_get("@status_check_success").should be_true
end
it "should set running to false if a status command fails" do
- @provider.stub(:shell_out_with_systems_locale).and_return(@shell_out_failure)
+ @provider.stub(:shell_out).and_return(@shell_out_failure)
@current_resource.should_receive(:running).with(false)
@provider.load_current_resource
end
it "should update state to indicate status check failed when a status command fails" do
- @provider.stub(:shell_out_with_systems_locale).and_return(@shell_out_failure)
+ @provider.stub(:shell_out).and_return(@shell_out_failure)
@provider.load_current_resource
@provider.instance_variable_get("@status_check_success").should be_false
end
@@ -129,31 +129,31 @@ describe Chef::Provider::Service::Systemd do
it "should call the start command if one is specified" do
@new_resource.stub(:start_command).and_return("/sbin/rsyslog startyousillysally")
- @provider.should_receive(:shell_out!).with("/sbin/rsyslog startyousillysally")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog startyousillysally")
@provider.start_service
end
it "should call '/bin/systemctl start service_name' if no start command is specified" do
- @provider.should_receive(:shell_out_with_systems_locale).with("/bin/systemctl start #{@new_resource.service_name}").and_return(@shell_out_success)
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/bin/systemctl start #{@new_resource.service_name}").and_return(@shell_out_success)
@provider.start_service
end
it "should not call '/bin/systemctl start service_name' if it is already running" do
@current_resource.stub(:running).and_return(true)
- @provider.should_not_receive(:shell_out_with_systems_locale).with("/bin/systemctl start #{@new_resource.service_name}")
+ @provider.should_not_receive(:shell_out_with_systems_locale!).with("/bin/systemctl start #{@new_resource.service_name}")
@provider.start_service
end
it "should call the restart command if one is specified" do
@current_resource.stub(:running).and_return(true)
@new_resource.stub(:restart_command).and_return("/sbin/rsyslog restartyousillysally")
- @provider.should_receive(:shell_out!).with("/sbin/rsyslog restartyousillysally")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog restartyousillysally")
@provider.restart_service
end
it "should call '/bin/systemctl restart service_name' if no restart command is specified" do
@current_resource.stub(:running).and_return(true)
- @provider.should_receive(:shell_out_with_systems_locale).with("/bin/systemctl restart #{@new_resource.service_name}").and_return(@shell_out_success)
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/bin/systemctl restart #{@new_resource.service_name}").and_return(@shell_out_success)
@provider.restart_service
end
@@ -162,7 +162,7 @@ describe Chef::Provider::Service::Systemd do
it "should call the reload command" do
@current_resource.stub(:running).and_return(true)
@new_resource.stub(:reload_command).and_return("/sbin/rsyslog reloadyousillysally")
- @provider.should_receive(:shell_out!).with("/sbin/rsyslog reloadyousillysally")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog reloadyousillysally")
@provider.reload_service
end
end
@@ -170,7 +170,7 @@ describe Chef::Provider::Service::Systemd do
context "when a reload command is not specified" do
it "should call '/bin/systemctl reload service_name' if the service is running" do
@current_resource.stub(:running).and_return(true)
- @provider.should_receive(:shell_out_with_systems_locale).with("/bin/systemctl reload #{@new_resource.service_name}").and_return(@shell_out_success)
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/bin/systemctl reload #{@new_resource.service_name}").and_return(@shell_out_success)
@provider.reload_service
end
@@ -185,19 +185,19 @@ describe Chef::Provider::Service::Systemd do
it "should call the stop command if one is specified" do
@current_resource.stub(:running).and_return(true)
@new_resource.stub(:stop_command).and_return("/sbin/rsyslog stopyousillysally")
- @provider.should_receive(:shell_out!).with("/sbin/rsyslog stopyousillysally")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog stopyousillysally")
@provider.stop_service
end
it "should call '/bin/systemctl stop service_name' if no stop command is specified" do
@current_resource.stub(:running).and_return(true)
- @provider.should_receive(:shell_out_with_systems_locale).with("/bin/systemctl stop #{@new_resource.service_name}").and_return(@shell_out_success)
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/bin/systemctl stop #{@new_resource.service_name}").and_return(@shell_out_success)
@provider.stop_service
end
it "should not call '/bin/systemctl stop service_name' if it is already stopped" do
@current_resource.stub(:running).and_return(false)
- @provider.should_not_receive(:shell_out_with_systems_locale).with("/bin/systemctl stop #{@new_resource.service_name}")
+ @provider.should_not_receive(:shell_out_with_systems_locale!).with("/bin/systemctl stop #{@new_resource.service_name}")
@provider.stop_service
end
end
@@ -210,12 +210,12 @@ describe Chef::Provider::Service::Systemd do
end
it "should call '/bin/systemctl enable service_name' to enable the service" do
- @provider.should_receive(:shell_out_with_systems_locale).with("/bin/systemctl enable #{@new_resource.service_name}").and_return(@shell_out_success)
+ @provider.should_receive(:shell_out!).with("/bin/systemctl enable #{@new_resource.service_name}").and_return(@shell_out_success)
@provider.enable_service
end
it "should call '/bin/systemctl disable service_name' to disable the service" do
- @provider.should_receive(:shell_out_with_systems_locale).with("/bin/systemctl disable #{@new_resource.service_name}").and_return(@shell_out_success)
+ @provider.should_receive(:shell_out!).with("/bin/systemctl disable #{@new_resource.service_name}").and_return(@shell_out_success)
@provider.disable_service
end
end
@@ -227,12 +227,12 @@ describe Chef::Provider::Service::Systemd do
end
it "should return true if '/bin/systemctl is-active service_name' returns 0" do
- @provider.should_receive(:shell_out_with_systems_locale).with('/bin/systemctl is-active rsyslog.service --quiet').and_return(@shell_out_success)
+ @provider.should_receive(:shell_out).with('/bin/systemctl is-active rsyslog.service --quiet').and_return(@shell_out_success)
@provider.is_active?.should be_true
end
it "should return false if '/bin/systemctl is-active service_name' returns anything except 0" do
- @provider.should_receive(:shell_out_with_systems_locale).with('/bin/systemctl is-active rsyslog.service --quiet').and_return(@shell_out_failure)
+ @provider.should_receive(:shell_out).with('/bin/systemctl is-active rsyslog.service --quiet').and_return(@shell_out_failure)
@provider.is_active?.should be_false
end
end
@@ -244,12 +244,12 @@ describe Chef::Provider::Service::Systemd do
end
it "should return true if '/bin/systemctl is-enabled service_name' returns 0" do
- @provider.should_receive(:shell_out_with_systems_locale).with('/bin/systemctl is-enabled rsyslog.service --quiet').and_return(@shell_out_success)
+ @provider.should_receive(:shell_out).with('/bin/systemctl is-enabled rsyslog.service --quiet').and_return(@shell_out_success)
@provider.is_enabled?.should be_true
end
it "should return false if '/bin/systemctl is-enabled service_name' returns anything except 0" do
- @provider.should_receive(:shell_out_with_systems_locale).with('/bin/systemctl is-enabled rsyslog.service --quiet').and_return(@shell_out_failure)
+ @provider.should_receive(:shell_out).with('/bin/systemctl is-enabled rsyslog.service --quiet').and_return(@shell_out_failure)
@provider.is_enabled?.should be_false
end
end
diff --git a/spec/unit/provider/service/upstart_service_spec.rb b/spec/unit/provider/service/upstart_service_spec.rb
index efe4e0481f..499a794ff4 100644
--- a/spec/unit/provider/service/upstart_service_spec.rb
+++ b/spec/unit/provider/service/upstart_service_spec.rb
@@ -161,7 +161,6 @@ describe Chef::Provider::Service::Upstart do
@provider.load_current_resource
end
-
it "should track state when the upstart configuration file fails to load" do
File.should_receive(:exists?).and_return false
@provider.load_current_resource
@@ -174,19 +173,19 @@ describe Chef::Provider::Service::Upstart do
end
it "should run the services status command if one has been specified" do
- @provider.stub(:run_command_with_systems_locale).with({:command => "/bin/chefhasmonkeypants status"}).and_return(0)
+ @provider.stub(:shell_out!).with("/bin/chefhasmonkeypants status").and_return(0)
@current_resource.should_receive(:running).with(true)
@provider.load_current_resource
end
it "should track state when the user-provided status command fails" do
- @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_raise(Chef::Exceptions::Exec)
+ @provider.stub(:shell_out!).and_raise(Errno::ENOENT)
@provider.load_current_resource
@provider.instance_variable_get("@command_success").should == false
end
it "should set running to false if it catches a Chef::Exceptions::Exec when using a status command" do
- @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_raise(Chef::Exceptions::Exec)
+ @provider.stub(:shell_out!).and_raise(Errno::ENOENT)
@current_resource.should_receive(:running).with(false)
@provider.load_current_resource
end
@@ -202,7 +201,6 @@ describe Chef::Provider::Service::Upstart do
@provider.load_current_resource.should eql(@current_resource)
end
-
end
describe "enable and disable service" do
@@ -243,18 +241,18 @@ describe Chef::Provider::Service::Upstart do
it "should call the start command if one is specified" do
@new_resource.stub(:start_command).and_return("/sbin/rsyslog startyousillysally")
- @provider.should_receive(:shell_out!).with("/sbin/rsyslog startyousillysally")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog startyousillysally")
@provider.start_service()
end
it "should call '/sbin/start service_name' if no start command is specified" do
- @provider.should_receive(:run_command_with_systems_locale).with({:command => "/sbin/start #{@new_resource.service_name}"}).and_return(0)
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/start #{@new_resource.service_name}").and_return(0)
@provider.start_service()
end
it "should not call '/sbin/start service_name' if it is already running" do
@current_resource.stub(:running).and_return(true)
- @provider.should_not_receive(:run_command_with_systems_locale).with({:command => "/sbin/start #{@new_resource.service_name}"})
+ @provider.should_not_receive(:shell_out_with_systems_locale!)
@provider.start_service()
end
@@ -263,58 +261,58 @@ describe Chef::Provider::Service::Upstart do
@new_resource.parameters({ "OSD_ID" => "2" })
@provider = Chef::Provider::Service::Upstart.new(@new_resource, @run_context)
@provider.current_resource = @current_resource
- @provider.should_receive(:run_command_with_systems_locale).with({:command => "/sbin/start rsyslog OSD_ID=2"}).and_return(0)
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/start rsyslog OSD_ID=2").and_return(0)
@provider.start_service()
end
it "should call the restart command if one is specified" do
@current_resource.stub(:running).and_return(true)
@new_resource.stub(:restart_command).and_return("/sbin/rsyslog restartyousillysally")
- @provider.should_receive(:shell_out!).with("/sbin/rsyslog restartyousillysally")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog restartyousillysally")
@provider.restart_service()
end
it "should call '/sbin/restart service_name' if no restart command is specified" do
@current_resource.stub(:running).and_return(true)
- @provider.should_receive(:run_command_with_systems_locale).with({:command => "/sbin/restart #{@new_resource.service_name}"}).and_return(0)
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/restart #{@new_resource.service_name}").and_return(0)
@provider.restart_service()
end
it "should call '/sbin/start service_name' if restart_service is called for a stopped service" do
@current_resource.stub(:running).and_return(false)
- @provider.should_receive(:run_command_with_systems_locale).with({:command => "/sbin/start #{@new_resource.service_name}"}).and_return(0)
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/start #{@new_resource.service_name}").and_return(0)
@provider.restart_service()
end
it "should call the reload command if one is specified" do
@current_resource.stub(:running).and_return(true)
@new_resource.stub(:reload_command).and_return("/sbin/rsyslog reloadyousillysally")
- @provider.should_receive(:shell_out!).with("/sbin/rsyslog reloadyousillysally")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog reloadyousillysally")
@provider.reload_service()
end
it "should call '/sbin/reload service_name' if no reload command is specified" do
@current_resource.stub(:running).and_return(true)
- @provider.should_receive(:run_command_with_systems_locale).with({:command => "/sbin/reload #{@new_resource.service_name}"}).and_return(0)
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/reload #{@new_resource.service_name}").and_return(0)
@provider.reload_service()
end
it "should call the stop command if one is specified" do
@current_resource.stub(:running).and_return(true)
@new_resource.stub(:stop_command).and_return("/sbin/rsyslog stopyousillysally")
- @provider.should_receive(:shell_out!).with("/sbin/rsyslog stopyousillysally")
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog stopyousillysally")
@provider.stop_service()
end
it "should call '/sbin/stop service_name' if no stop command is specified" do
@current_resource.stub(:running).and_return(true)
- @provider.should_receive(:run_command_with_systems_locale).with({:command => "/sbin/stop #{@new_resource.service_name}"}).and_return(0)
+ @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/stop #{@new_resource.service_name}").and_return(0)
@provider.stop_service()
end
it "should not call '/sbin/stop service_name' if it is already stopped" do
@current_resource.stub(:running).and_return(false)
- @provider.should_not_receive(:run_command_with_systems_locale).with({:command => "/sbin/stop #{@new_resource.service_name}"})
+ @provider.should_not_receive(:shell_out_with_systems_locale!).with("/sbin/stop #{@new_resource.service_name}")
@provider.stop_service()
end
end
diff --git a/spec/unit/provider/subversion_spec.rb b/spec/unit/provider/subversion_spec.rb
index f37a42d235..5d9d1cec1e 100644
--- a/spec/unit/provider/subversion_spec.rb
+++ b/spec/unit/provider/subversion_spec.rb
@@ -16,7 +16,6 @@
# limitations under the License.
#
-
require 'spec_helper'
describe Chef::Provider::Subversion do
@@ -199,7 +198,7 @@ describe Chef::Provider::Subversion do
it "runs an export with the --force option" do
::File.stub(:directory?).with("/my/deploy").and_return(true)
expected_cmd = "svn export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir"
- @provider.should_receive(:run_command).with(:command => expected_cmd)
+ @provider.should_receive(:shell_out!).with(command: expected_cmd)
@provider.run_action(:force_export)
@resource.should be_updated
end
@@ -207,7 +206,7 @@ describe Chef::Provider::Subversion do
it "runs the checkout command for action_checkout" do
::File.stub(:directory?).with("/my/deploy").and_return(true)
expected_cmd = "svn checkout -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir"
- @provider.should_receive(:run_command).with(:command => expected_cmd)
+ @provider.should_receive(:shell_out!).with(command: expected_cmd)
@provider.run_action(:checkout)
@resource.should be_updated
end
@@ -231,7 +230,7 @@ describe Chef::Provider::Subversion do
@resource.user "whois"
@resource.group "thisis"
expected_cmd = "svn checkout -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir"
- @provider.should_receive(:run_command).with(:command => expected_cmd, :user => "whois", :group => "thisis")
+ @provider.should_receive(:shell_out!).with(command: expected_cmd, user: "whois", group: "thisis")
@provider.run_action(:checkout)
@resource.should be_updated
end
@@ -256,7 +255,7 @@ describe Chef::Provider::Subversion do
@provider.stub(:find_current_revision).and_return("11410")
@provider.stub(:current_revision_matches_target_revision?).and_return(false)
expected_cmd = "svn update -q -r12345 /my/deploy/dir"
- @provider.should_receive(:run_command).with(:command => expected_cmd)
+ @provider.should_receive(:shell_out!).with(command: expected_cmd)
@provider.run_action(:sync)
@resource.should be_updated
end
@@ -273,7 +272,7 @@ describe Chef::Provider::Subversion do
it "runs the export_command on action_export" do
::File.stub(:directory?).with("/my/deploy").and_return(true)
expected_cmd = "svn export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir"
- @provider.should_receive(:run_command).with(:command => expected_cmd)
+ @provider.should_receive(:shell_out!).with(command: expected_cmd)
@provider.run_action(:export)
@resource.should be_updated
end
diff --git a/spec/unit/provider/whyrun_safe_ruby_block_spec.rb b/spec/unit/provider/whyrun_safe_ruby_block_spec.rb
index 5a17aacbd9..d5209248b3 100644
--- a/spec/unit/provider/whyrun_safe_ruby_block_spec.rb
+++ b/spec/unit/provider/whyrun_safe_ruby_block_spec.rb
@@ -30,14 +30,14 @@ describe Chef::Provider::WhyrunSafeRubyBlock, "initialize" do
end
it "should call the block and flag the resource as updated" do
- @provider.run_action(:create)
+ @provider.run_action(:run)
$evil_global_evil_laugh.should == :mwahahaha
@new_resource.should be_updated
end
it "should call the block and flat the resource as updated - even in whyrun" do
Chef::Config[:why_run] = true
- @provider.run_action(:create)
+ @provider.run_action(:run)
$evil_global_evil_laugh.should == :mwahahaha
@new_resource.should be_updated
Chef::Config[:why_run] = false
diff --git a/spec/unit/resource/dsc_script_spec.rb b/spec/unit/resource/dsc_script_spec.rb
new file mode 100644
index 0000000000..cbd502a61c
--- /dev/null
+++ b/spec/unit/resource/dsc_script_spec.rb
@@ -0,0 +1,127 @@
+#
+# Author:: Adam Edwards (<adamed@getchef.com>)
+# 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::Resource::DscScript do
+ let(:dsc_test_resource_name) { 'DSCTest' }
+
+ context 'when Powershell supports Dsc' do
+ let(:dsc_test_run_context) {
+ node = Chef::Node.new
+ node.automatic[:languages][:powershell][:version] = '4.0'
+ empty_events = Chef::EventDispatch::Dispatcher.new
+ Chef::RunContext.new(node, {}, empty_events)
+ }
+ let(:dsc_test_resource) {
+ Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context)
+ }
+ let(:configuration_code) {'echo "This is supposed to create a configuration document."'}
+ let(:configuration_path) {'c:/myconfigs/formatc.ps1'}
+ let(:configuration_name) { 'formatme' }
+ let(:configuration_data) { '@{AllNodes = @( @{ NodeName = "localhost"; PSDscAllowPlainTextPassword = $true })}' }
+ let(:configuration_data_script) { 'c:/myconfigs/data/safedata.psd1' }
+
+ it "has a default action of `:run`" do
+ expect(dsc_test_resource.action).to eq(:run)
+ end
+
+ it "has an allowed_actions attribute with only the `:run` and `:nothing` attributes" do
+ expect(dsc_test_resource.allowed_actions.to_set).to eq([:run,:nothing].to_set)
+ end
+
+ it "allows the code attribute to be set" do
+ dsc_test_resource.code(configuration_code)
+ expect(dsc_test_resource.code).to eq(configuration_code)
+ end
+
+ it "allows the command attribute to be set" do
+ dsc_test_resource.command(configuration_path)
+ expect(dsc_test_resource.command).to eq(configuration_path)
+ end
+
+ it "allows the configuration_name attribute to be set" do
+ dsc_test_resource.configuration_name(configuration_name)
+ expect(dsc_test_resource.configuration_name).to eq(configuration_name)
+ end
+
+ it "allows the configuration_data attribute to be set" do
+ dsc_test_resource.configuration_data(configuration_data)
+ expect(dsc_test_resource.configuration_data).to eq(configuration_data)
+ end
+
+ it "allows the configuration_data_script attribute to be set" do
+ dsc_test_resource.configuration_data_script(configuration_data_script)
+ expect(dsc_test_resource.configuration_data_script).to eq(configuration_data_script)
+ end
+
+ it "raises an ArgumentError exception if an attempt is made to set the code attribute when the command attribute is already set" do
+ dsc_test_resource.command(configuration_path)
+ expect { dsc_test_resource.code(configuration_code) }.to raise_error(ArgumentError)
+ end
+
+ it "raises an ArgumentError exception if an attempt is made to set the command attribute when the code attribute is already set" do
+ dsc_test_resource.code(configuration_code)
+ expect { dsc_test_resource.command(configuration_path) }.to raise_error(ArgumentError)
+ end
+
+ it "raises an ArgumentError exception if an attempt is made to set the configuration_name attribute when the code attribute is already set" do
+ dsc_test_resource.code(configuration_code)
+ expect { dsc_test_resource.configuration_name(configuration_name) }.to raise_error(ArgumentError)
+ end
+
+ it "raises an ArgumentError exception if an attempt is made to set the configuration_data attribute when the configuration_data_script attribute is already set" do
+ dsc_test_resource.configuration_data_script(configuration_data_script)
+ expect { dsc_test_resource.configuration_data(configuration_data) }.to raise_error(ArgumentError)
+ end
+
+ it "raises an ArgumentError exception if an attempt is made to set the configuration_data_script attribute when the configuration_data attribute is already set" do
+ dsc_test_resource.configuration_data(configuration_data)
+ expect { dsc_test_resource.configuration_data_script(configuration_data_script) }.to raise_error(ArgumentError)
+ end
+ end
+
+ context 'when Powershell does not supported Dsc' do
+ ['1.0', '2.0', '3.0'].each do |version|
+ it "raises an exception for powershell version '#{version}'" do
+ node = Chef::Node.new
+ node.automatic[:languages][:powershell][:version] = version
+ empty_events = Chef::EventDispatch::Dispatcher.new
+ dsc_test_run_context = Chef::RunContext.new(node, {}, empty_events)
+
+ expect {
+ Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context)
+ }.to raise_error(Chef::Exceptions::NoProviderAvailable)
+ end
+ end
+ end
+
+ context 'when Powershell is not present' do
+ let (:dsc_test_run_context) {
+ node = Chef::Node.new
+ empty_events = Chef::EventDispatch::Dispatcher.new
+ dsc_test_run_context = Chef::RunContext.new(node, {}, empty_events)
+ }
+
+ it 'raises an exception if powershell is not present' do
+ expect {
+ Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context)
+ }.to raise_error(Chef::Exceptions::NoProviderAvailable)
+ end
+ end
+end
diff --git a/spec/unit/resource/homebrew_package_spec.rb b/spec/unit/resource/homebrew_package_spec.rb
new file mode 100644
index 0000000000..4b4f9afe5e
--- /dev/null
+++ b/spec/unit/resource/homebrew_package_spec.rb
@@ -0,0 +1,36 @@
+#
+# Author:: Joshua Timberman (<joshua@getchef.com>)
+# Copyright (c) 2014, Chef Software, Inc. <legal@getchef.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+describe Chef::Resource::HomebrewPackage, 'initialize' do
+
+ let(:resource) { Chef::Resource::HomebrewPackage.new('emacs') }
+
+ it 'returns a Chef::Resource::HomebrewPackage' do
+ expect(resource).to be_a_kind_of(Chef::Resource::HomebrewPackage)
+ end
+
+ it 'sets the resource_name to :homebrew_package' do
+ expect(resource.resource_name).to eql(:homebrew_package)
+ end
+
+ it 'sets the provider to Chef::Provider::Package::Homebrew' do
+ expect(resource.provider).to eql(Chef::Provider::Package::Homebrew)
+ end
+
+end
diff --git a/spec/unit/run_context_spec.rb b/spec/unit/run_context_spec.rb
index 1def10faf5..21ece2abaa 100644
--- a/spec/unit/run_context_spec.rb
+++ b/spec/unit/run_context_spec.rb
@@ -134,4 +134,19 @@ describe Chef::RunContext do
end
end
+ describe "handling reboot requests" do
+ let(:expected) do
+ { :reason => "spec tests require a reboot" }
+ end
+
+ it "stores and deletes the reboot request" do
+ @run_context.request_reboot(expected)
+ expect(@run_context.reboot_info).to eq(expected)
+ expect(@run_context.reboot_requested?).to be_true
+
+ @run_context.cancel_reboot
+ expect(@run_context.reboot_info).to eq({})
+ expect(@run_context.reboot_requested?).to be_false
+ end
+ end
end
diff --git a/spec/unit/util/dsc/configuration_generator_spec.rb b/spec/unit/util/dsc/configuration_generator_spec.rb
new file mode 100644
index 0000000000..03f3ffe25c
--- /dev/null
+++ b/spec/unit/util/dsc/configuration_generator_spec.rb
@@ -0,0 +1,171 @@
+#
+# Author:: Jay Mundrawala <jmundrawala@getchef.com>
+# 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 'chef'
+require 'chef/util/dsc/configuration_generator'
+
+describe Chef::Util::DSC::ConfigurationGenerator do
+ let(:conf_man) do
+ node = Chef::Node.new
+ Chef::Util::DSC::ConfigurationGenerator.new(node, 'tmp')
+ end
+
+ describe '#validate_configuration_name!' do
+ it 'should not raise an error if a name contains all upper case letters' do
+ conf_man.send(:validate_configuration_name!, "HELLO")
+ end
+
+ it 'should not raise an error if the name contains all lower case letters' do
+ conf_man.send(:validate_configuration_name!, "hello")
+ end
+
+ it 'should not raise an error if no special characters are used except _' do
+ conf_man.send(:validate_configuration_name!, "hello_world")
+ end
+
+ %w{! @ # $ % ^ & * & * ( ) - = + \{ \} . ? < > \\ /}.each do |sym|
+ it "raises an Argument error if it configuration name contains #{sym}" do
+ expect {
+ conf_man.send(:validate_configuration_name!, "Hello#{sym}")
+ }.to raise_error(ArgumentError)
+ end
+ end
+ end
+
+ describe "#get_merged_configuration_flags" do
+ context 'when strings are used as switches' do
+ it 'should merge the hash if there are no restricted switches' do
+ merged = conf_man.send(:get_merged_configuration_flags!, {'flag' => 'a'}, 'hello')
+ merged.should include(:flag)
+ merged[:flag].should eql('a')
+ merged.should include(:outputpath)
+ end
+
+ it 'should raise an ArgumentError if you try to override outputpath' do
+ expect {
+ conf_man.send(:get_merged_configuration_flags!, {'outputpath' => 'a'}, 'hello')
+ }.to raise_error(ArgumentError)
+ end
+
+ it 'should be case insensitive for switches that are not allowed' do
+ expect {
+ conf_man.send(:get_merged_configuration_flags!, {'OutputPath' => 'a'}, 'hello')
+ }.to raise_error(ArgumentError)
+ end
+
+ it 'should be case insensitive to switches that are allowed' do
+ merged = conf_man.send(:get_merged_configuration_flags!, {'FLAG' => 'a'}, 'hello')
+ merged.should include(:flag)
+ end
+ end
+
+ context 'when symbols are used as switches' do
+ it 'should merge the hash if there are no restricted switches' do
+ merged = conf_man.send(:get_merged_configuration_flags!, {:flag => 'a'}, 'hello')
+ merged.should include(:flag)
+ merged[:flag].should eql('a')
+ merged.should include(:outputpath)
+ end
+
+ it 'should raise an ArgumentError if you try to override outputpath' do
+ expect {
+ conf_man.send(:get_merged_configuration_flags!, {:outputpath => 'a'}, 'hello')
+ }.to raise_error(ArgumentError)
+ end
+
+ it 'should be case insensitive for switches that are not allowed' do
+ expect {
+ conf_man.send(:get_merged_configuration_flags!, {:OutputPath => 'a'}, 'hello')
+ }.to raise_error(ArgumentError)
+ end
+
+ it 'should be case insensitive to switches that are allowed' do
+ merged = conf_man.send(:get_merged_configuration_flags!, {:FLAG => 'a'}, 'hello')
+ merged.should include(:flag)
+ end
+ end
+
+ context 'when there are no flags' do
+ it 'should supply an output path if configuration_flags is an empty hash' do
+ merged = conf_man.send(:get_merged_configuration_flags!, {}, 'hello')
+ merged.should include(:outputpath)
+ merged.length.should eql(1)
+ end
+
+ it 'should supply an output path if configuration_flags is an empty hash' do
+ merged = conf_man.send(:get_merged_configuration_flags!, nil, 'hello')
+ merged.should include(:outputpath)
+ merged.length.should eql(1)
+ end
+ end
+
+ # What should happen if configuration flags contains duplicates?
+ # flagA => 'a', flaga => 'a'
+ # or
+ # flagA => 'a', flaga => 'b'
+ #
+ end
+
+ describe '#write_document_generation_script' do
+ let(:file_like_object) { double("file like object") }
+
+ it "should write the input to a file" do
+ allow(File).to receive(:open).and_yield(file_like_object)
+ allow(File).to receive(:join) do |a, b|
+ [a,b].join("++")
+ end
+ allow(file_like_object).to receive(:write)
+ conf_man.send(:write_document_generation_script, 'file', 'hello')
+ expect(file_like_object).to have_received(:write)
+ end
+ end
+
+ describe "#find_configuration_document" do
+ it "should find the mof file" do
+ # These tests seem way too implementation specific. Unfortunatly, File and Dir
+ # need to be mocked because they are OS specific
+ allow(File).to receive(:join) do |a, b|
+ [a,b].join("++")
+ end
+
+ allow(Dir).to receive(:entries).with("tmp++hello") {['f1', 'f2', 'hello.mof', 'f3']}
+ expect(conf_man.send(:find_configuration_document, 'hello')).to eql('tmp++hello++hello.mof')
+ end
+
+ it "should return nil if the mof file is not found" do
+ allow(File).to receive(:join) do |a, b|
+ [a,b].join("++")
+ end
+ allow(Dir).to receive(:entries).with("tmp++hello") {['f1', 'f2', 'f3']}
+ expect(conf_man.send(:find_configuration_document, 'hello')).to be_nil
+ end
+ end
+
+ describe "#configuration_code" do
+ it "should build dsc" do
+ dsc = conf_man.send(:configuration_code, 'archive{}', 'hello')
+ found_configuration = false
+ dsc.split(';').each do |command|
+ if command.downcase =~ /\s*configuration\s+'hello'\s*\{\s*node\s+'localhost'\s*\{\s*archive\s*\{\s*\}\s*\}\s*\}\s*/
+ found_configuration = true
+ end
+ end
+ expect(found_configuration).to be_true
+ end
+ end
+end
diff --git a/spec/unit/util/dsc/lcm_output_parser_spec.rb b/spec/unit/util/dsc/lcm_output_parser_spec.rb
new file mode 100644
index 0000000000..23a3dbd3ec
--- /dev/null
+++ b/spec/unit/util/dsc/lcm_output_parser_spec.rb
@@ -0,0 +1,169 @@
+#
+# Author:: Bryan McLellan <btm@loftninjas.org>
+# 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 'chef/util/dsc/lcm_output_parser'
+
+describe Chef::Util::DSC::LocalConfigurationManager::Parser do
+ context 'empty input parameter' do
+ it 'returns an empty array for a 0 length string' do
+ Chef::Util::DSC::LocalConfigurationManager::Parser::parse('').should be_empty
+ end
+
+ it 'returns an empty array for a nil input' do
+ Chef::Util::DSC::LocalConfigurationManager::Parser::parse('').should be_empty
+ end
+ end
+
+ context 'correctly formatted output from lcm' do
+ it 'returns an empty array for a log with no resources' do
+ str = <<EOF
+logtype: [machinename]: LCM: [ Start Set ]
+logtype: [machinename]: LCM: [ End Set ]
+EOF
+ Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str).should be_empty
+ end
+
+ it 'returns a single resource when only 1 logged with the correct name' do
+ str = <<EOF
+logtype: [machinename]: LCM: [ Start Set ]
+logtype: [machinename]: LCM: [ Start Resource ] [name]
+logtype: [machinename]: LCM: [ End Resource ] [name]
+logtype: [machinename]: LCM: [ End Set ]
+EOF
+ resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)
+ resources.length.should eq(1)
+ resources[0].name.should eq('[name]')
+ end
+
+ it 'identifies when a resource changes the state of the system' do
+ str = <<EOF
+logtype: [machinename]: LCM: [ Start Set ]
+logtype: [machinename]: LCM: [ Start Resource ] [name]
+logtype: [machinename]: LCM: [ Start Set ] [name]
+logtype: [machinename]: LCM: [ End Set ] [name]
+logtype: [machinename]: LCM: [ End Resource ] [name]
+logtype: [machinename]: LCM: [ End Set ]
+EOF
+ resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)
+ resources[0].changes_state?.should be_true
+ end
+
+ it 'preserves the log provided for how the system changed the state' do
+ str = <<EOF
+logtype: [machinename]: LCM: [ Start Set ]
+logtype: [machinename]: LCM: [ Start Resource ] [name]
+logtype: [machinename]: LCM: [ Start Set ] [name]
+logtype: [machinename]: [message]
+logtype: [machinename]: LCM: [ End Set ] [name]
+logtype: [machinename]: LCM: [ End Resource ] [name]
+logtype: [machinename]: LCM: [ End Set ]
+EOF
+ resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)
+ resources[0].change_log.should match_array(["[name]","[message]","[name]"])
+ end
+
+ it 'should return false for changes_state?' do
+ str = <<EOF
+logtype: [machinename]: LCM: [ Start Set ]
+logtype: [machinename]: LCM: [ Start Resource ] [name]
+logtype: [machinename]: LCM: [ Skip Set ] [name]
+logtype: [machinename]: LCM: [ End Resource ] [name]
+logtype: [machinename]: LCM: [ End Set ]
+EOF
+ resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)
+ resources[0].changes_state?.should be_false
+ end
+
+ it 'should return an empty array for change_log if changes_state? is false' do
+ str = <<EOF
+logtype: [machinename]: LCM: [ Start Set ]
+logtype: [machinename]: LCM: [ Start Resource ] [name]
+logtype: [machinename]: LCM: [ Skip Set ] [name]
+logtype: [machinename]: LCM: [ End Resource ] [name]
+logtype: [machinename]: LCM: [ End Set ]
+EOF
+ resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)
+ resources[0].change_log.should be_empty
+ end
+ end
+
+ context 'Incorrectly formatted output from LCM' do
+ it 'should allow missing a [End Resource] when its the last one and still find all the resource' do
+ str = <<-EOF
+logtype: [machinename]: LCM: [ Start Set ]
+logtype: [machinename]: LCM: [ Start Resource ] [name]
+logtype: [machinename]: LCM: [ Start Test ]
+logtype: [machinename]: LCM: [ End Test ]
+logtype: [machinename]: LCM: [ Skip Set ]
+logtype: [machinename]: LCM: [ End Resource ]
+logtype: [machinename]: LCM: [ Start Resource ] [name2]
+logtype: [machinename]: LCM: [ Start Test ]
+logtype: [machinename]: LCM: [ End Test ]
+logtype: [machinename]: LCM: [ Start Set ]
+logtype: [machinename]: LCM: [ End Set ]
+logtype: [machinename]: LCM: [ End Set ]
+EOF
+
+ resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)
+ resources[0].changes_state?.should be_false
+ resources[1].changes_state?.should be_true
+ end
+
+ it 'should allow missing a [End Resource] when its the first one and still find all the resource' do
+ str = <<-EOF
+logtype: [machinename]: LCM: [ Start Set ]
+logtype: [machinename]: LCM: [ Start Resource ] [name]
+logtype: [machinename]: LCM: [ Start Test ]
+logtype: [machinename]: LCM: [ End Test ]
+logtype: [machinename]: LCM: [ Skip Set ]
+logtype: [machinename]: LCM: [ Start Resource ] [name2]
+logtype: [machinename]: LCM: [ Start Test ]
+logtype: [machinename]: LCM: [ End Test ]
+logtype: [machinename]: LCM: [ Start Set ]
+logtype: [machinename]: LCM: [ End Set ]
+logtype: [machinename]: LCM: [ End Resource ]
+logtype: [machinename]: LCM: [ End Set ]
+EOF
+
+ resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)
+ resources[0].changes_state?.should be_false
+ resources[1].changes_state?.should be_true
+ end
+
+ it 'should allow missing set and end resource and assume an unconverged resource in this case' do
+ str = <<-EOF
+logtype: [machinename]: LCM: [ Start Set ]
+logtype: [machinename]: LCM: [ Start Resource ] [name]
+logtype: [machinename]: LCM: [ Start Test ]
+logtype: [machinename]: LCM: [ End Test ]
+logtype: [machinename]: LCM: [ Start Resource ] [name2]
+logtype: [machinename]: LCM: [ Start Test ]
+logtype: [machinename]: LCM: [ End Test ]
+logtype: [machinename]: LCM: [ Start Set ]
+logtype: [machinename]: LCM: [ End Set ]
+logtype: [machinename]: LCM: [ End Resource ]
+logtype: [machinename]: LCM: [ End Set ]
+EOF
+ resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)
+ resources[0].changes_state?.should be_true
+ resources[0].name.should eql('[name]')
+ resources[1].changes_state?.should be_true
+ resources[1].name.should eql('[name2]')
+ end
+ end
+end
diff --git a/spec/unit/util/dsc/local_configuration_manager_spec.rb b/spec/unit/util/dsc/local_configuration_manager_spec.rb
new file mode 100644
index 0000000000..fb6664bd40
--- /dev/null
+++ b/spec/unit/util/dsc/local_configuration_manager_spec.rb
@@ -0,0 +1,134 @@
+#
+# Author:: Adam Edwards <adamed@getchef.com>
+# 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 'chef'
+require 'chef/util/dsc/local_configuration_manager'
+
+describe Chef::Util::DSC::LocalConfigurationManager do
+
+ let(:lcm) { Chef::Util::DSC::LocalConfigurationManager.new(nil, 'tmp') }
+
+ let(:normal_lcm_output) { <<-EOH
+logtype: [machinename]: LCM: [ Start Set ]
+logtype: [machinename]: LCM: [ Start Resource ] [name]
+logtype: [machinename]: LCM: [ End Resource ] [name]
+logtype: [machinename]: LCM: [ End Set ]
+EOH
+ }
+
+ let(:no_whatif_lcm_output) { <<-EOH
+Start-DscConfiguration : A parameter cannot be found that matches parameter name 'whatif'.
+At line:1 char:123
++ run-somecommand -whatif
++ ~~~~~~~~
+ + CategoryInfo : InvalidArgument: (:) [Start-DscConfiguration], ParameterBindingException
+ + FullyQualifiedErrorId : NamedParameterNotFound,SomeCompany.SomeAssembly.Commands.RunSomeCommand
+EOH
+ }
+
+ let(:dsc_resource_import_failure_output) { <<-EOH
+PowerShell provider MSFT_xWebsite failed to execute Test-TargetResource functionality with error message: Please ensure that WebAdministration module is installed. + CategoryInfo : InvalidOperation: (:) [], CimException + FullyQualifiedErrorId : ProviderOperationExecutionFailure + PSComputerName : . PowerShell provider MSFT_xWebsite failed to execute Test-TargetResource functionality with error message: Please ensure that WebAdministration module is installed. + CategoryInfo : InvalidOperation: (:) [], CimException + FullyQualifiedErrorId : ProviderOperationExecutionFailure + PSComputerName : . The SendConfigurationApply function did not succeed. + CategoryInfo : NotSpecified: (root/Microsoft/...gurationManager:String) [], CimException + FullyQualifiedErrorId : MI RESULT 1 + PSComputerName : .
+EOH
+ }
+
+ let(:lcm_status) {
+ double("LCM cmdlet status", :stderr => lcm_standard_error, :return_value => lcm_standard_output, :succeeded? => lcm_cmdlet_success)
+ }
+
+ describe 'test_configuration method invocation' do
+ context 'when interacting with the LCM using a PowerShell cmdlet' do
+ before(:each) do
+ allow(lcm).to receive(:run_configuration_cmdlet).and_return(lcm_status)
+ end
+ context 'that returns successfully' do
+ before(:each) do
+ allow(lcm).to receive(:run_configuration_cmdlet).and_return(lcm_status)
+ end
+
+ let(:lcm_standard_output) { normal_lcm_output }
+ let(:lcm_standard_error) { nil }
+ let(:lcm_cmdlet_success) { true }
+
+ it 'should successfully return resource information for normally formatted output when cmdlet the cmdlet succeeds' do
+ test_configuration_result = lcm.test_configuration('config')
+ expect(test_configuration_result.class).to be(Array)
+ expect(test_configuration_result.length).to be > 0
+ expect(Chef::Log).not_to receive(:warn)
+ end
+ end
+
+ context 'that fails due to missing what-if switch in DSC resource cmdlet implementation' do
+ let(:lcm_standard_output) { '' }
+ let(:lcm_standard_error) { no_whatif_lcm_output }
+ let(:lcm_cmdlet_success) { false }
+
+ it 'should should return a (possibly empty) array of ResourceInfo instances' do
+ expect(Chef::Log).to receive(:warn)
+ test_configuration_result = nil
+ expect {test_configuration_result = lcm.test_configuration('config')}.not_to raise_error
+ expect(test_configuration_result.class).to be(Array)
+ end
+ end
+
+ context 'that fails due to a DSC resource not being imported before StartDSCConfiguration -whatif is executed' do
+ let(:lcm_standard_output) { '' }
+ let(:lcm_standard_error) { dsc_resource_import_failure_output }
+ let(:lcm_cmdlet_success) { false }
+
+ it 'should log a warning if the message is formatted as expected when a resource import failure occurs' do
+ expect(Chef::Log).to receive(:warn)
+ expect(lcm).to receive(:output_has_dsc_module_failure?).and_call_original
+ test_configuration_result = nil
+ expect {test_configuration_result = lcm.test_configuration('config')}.not_to raise_error
+ end
+
+ it 'should return a (possibly empty) array of ResourceInfo instances' do
+ expect(Chef::Log).to receive(:warn)
+ test_configuration_result = nil
+ expect {test_configuration_result = lcm.test_configuration('config')}.not_to raise_error
+ expect(test_configuration_result.class).to be(Array)
+ end
+ end
+
+ context 'that fails due to an PowerShell cmdlet error that cannot be handled' do
+ let(:lcm_standard_output) { 'some output' }
+ let(:lcm_standard_error) { 'Abort, Retry, Fail?' }
+ let(:lcm_cmdlet_success) { false }
+
+ it 'should raise a Chef::Exceptions::PowershellCmdletException' do
+ expect(Chef::Log).not_to receive(:warn)
+ expect(lcm).to receive(:output_has_dsc_module_failure?).and_call_original
+ expect {lcm.test_configuration('config')}.to raise_error(Chef::Exceptions::PowershellCmdletException)
+ end
+ end
+ end
+
+ it 'should identify a correctly formatted error message as a resource import failure' do
+ expect(lcm.send(:output_has_dsc_module_failure?, dsc_resource_import_failure_output)).to be(true)
+ end
+
+ it 'should not identify an incorrectly formatted error message as a resource import failure' do
+ expect(lcm.send(:output_has_dsc_module_failure?, dsc_resource_import_failure_output.gsub('module', 'gibberish'))).to be(false)
+ end
+
+ it 'should not identify a message without a CimException reference as a resource import failure' do
+ expect(lcm.send(:output_has_dsc_module_failure?, dsc_resource_import_failure_output.gsub('CimException', 'ArgumentException'))).to be(false)
+ end
+ end
+end
+
diff --git a/spec/unit/util/powershell/cmdlet_spec.rb b/spec/unit/util/powershell/cmdlet_spec.rb
new file mode 100644
index 0000000000..a964f607c8
--- /dev/null
+++ b/spec/unit/util/powershell/cmdlet_spec.rb
@@ -0,0 +1,106 @@
+#
+# Author:: Jay Mundrawala <jdm@getchef.com>
+# 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 'chef'
+require 'chef/util/powershell/cmdlet'
+
+describe Chef::Util::Powershell::Cmdlet do
+ before (:all) do
+ @node = Chef::Node.new
+ @cmdlet = Chef::Util::Powershell::Cmdlet.new(@node, 'Some-Commandlet')
+ end
+
+ describe '#validate_switch_name!' do
+ it 'should not raise an error if a name contains all upper case letters' do
+ @cmdlet.send(:validate_switch_name!, "HELLO")
+ end
+
+ it 'should not raise an error if the name contains all lower case letters' do
+ @cmdlet.send(:validate_switch_name!, "hello")
+ end
+
+ it 'should not raise an error if no special characters are used except _' do
+ @cmdlet.send(:validate_switch_name!, "hello_world")
+ end
+
+ %w{! @ # $ % ^ & * & * ( ) - = + \{ \} . ? < > \\ /}.each do |sym|
+ it "raises an Argument error if it configuration name contains #{sym}" do
+ expect {
+ @cmdlet.send(:validate_switch_name!, "Hello#{sym}")
+ }.to raise_error(ArgumentError)
+ end
+ end
+ end
+
+ describe '#escape_parameter_value' do
+ # Is this list really complete?
+ %w{` " # '}.each do |c|
+ it "escapse #{c}" do
+ @cmdlet.send(:escape_parameter_value, "stuff #{c}").should eql("stuff `#{c}")
+ end
+ end
+
+ it 'does not do anything to a string without special characters' do
+ @cmdlet.send(:escape_parameter_value, 'stuff').should eql('stuff')
+ end
+ end
+
+ describe '#escape_string_parameter_value' do
+ it "surrounds a string with ''" do
+ @cmdlet.send(:escape_string_parameter_value, 'stuff').should eql("'stuff'")
+ end
+ end
+
+ describe '#command_switches_string' do
+ it 'raises an ArgumentError if the key is not a symbol' do
+ expect {
+ @cmdlet.send(:command_switches_string, {'foo' => 'bar'})
+ }.to raise_error(ArgumentError)
+ end
+
+ it 'does not allow invalid switch names' do
+ expect {
+ @cmdlet.send(:command_switches_string, {:foo! => 'bar'})
+ }.to raise_error(ArgumentError)
+ end
+
+ it 'ignores switches with a false value' do
+ @cmdlet.send(:command_switches_string, {foo: false}).should eql('')
+ end
+
+ it 'should correctly handle a value type of string' do
+ @cmdlet.send(:command_switches_string, {foo: 'bar'}).should eql("-foo 'bar'")
+ end
+
+ it 'should correctly handle a value type of string even when it is 0 length' do
+ @cmdlet.send(:command_switches_string, {foo: ''}).should eql("-foo ''")
+ end
+
+ it 'should not quote integers' do
+ @cmdlet.send(:command_switches_string, {foo: 1}).should eql("-foo 1")
+ end
+
+ it 'should not quote floats' do
+ @cmdlet.send(:command_switches_string, {foo: 1.0}).should eql("-foo 1.0")
+ end
+
+ it 'has just the switch when the value is true' do
+ @cmdlet.send(:command_switches_string, {foo: true}).should eql("-foo")
+ end
+ end
+end
diff --git a/spec/unit/workstation_config_loader_spec.rb b/spec/unit/workstation_config_loader_spec.rb
index 78313aec37..de108ff6d7 100644
--- a/spec/unit/workstation_config_loader_spec.rb
+++ b/spec/unit/workstation_config_loader_spec.rb
@@ -88,7 +88,12 @@ describe Chef::WorkstationConfigLoader do
let(:env_pwd) { "/path/to/cwd" }
before do
- env["PWD"] = env_pwd
+ if Chef::Platform.windows?
+ env["CD"] = env_pwd
+ else
+ env["PWD"] = env_pwd
+ end
+
allow(config_loader).to receive(:path_exists?).with("#{env_pwd}/.chef/knife.rb").and_return(true)
allow(File).to receive(:exist?).with("#{env_pwd}/.chef").and_return(true)
allow(File).to receive(:directory?).with("#{env_pwd}/.chef").and_return(true)
@@ -229,13 +234,14 @@ describe Chef::WorkstationConfigLoader do
let(:config_content) { "" }
let(:explicit_config_location) do
- t = Tempfile.new("#{described_class}-rspec-test")
+ # could use described_class, but remove all ':' from the path if so.
+ t = Tempfile.new("Chef-WorkstationConfigLoader-rspec-test")
t.print(config_content)
t.close
t.path
end
- after { File.unlink(explicit_config_location) }
+ after { File.unlink(explicit_config_location) if File.exists?(explicit_config_location) }
context "and is valid" do