summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md65
-rw-r--r--CHEF_MVPS.md5
-rw-r--r--CONTRIBUTING.md8
-rw-r--r--DOC_CHANGES.md4
-rw-r--r--RELEASE_NOTES.md40
-rw-r--r--lib/chef/chef_fs/file_system/cookbooks_dir.rb4
-rw-r--r--lib/chef/config.rb3
-rw-r--r--lib/chef/cookbook/file_system_file_vendor.rb3
-rw-r--r--lib/chef/cookbook/file_vendor.rb32
-rw-r--r--lib/chef/cookbook/metadata.rb33
-rw-r--r--lib/chef/cookbook/remote_file_vendor.rb3
-rw-r--r--lib/chef/cookbook/syntax_check.rb2
-rw-r--r--lib/chef/cookbook_uploader.rb31
-rw-r--r--lib/chef/cookbook_version.rb1
-rw-r--r--lib/chef/data_bag.rb36
-rw-r--r--lib/chef/dsl/recipe.rb1
-rw-r--r--lib/chef/encrypted_data_bag_item.rb1
-rw-r--r--lib/chef/encrypted_data_bag_item/assertions.rb57
-rw-r--r--lib/chef/encrypted_data_bag_item/decryptor.rb73
-rw-r--r--lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb37
-rw-r--r--lib/chef/encrypted_data_bag_item/encryption_failure.rb22
-rw-r--r--lib/chef/encrypted_data_bag_item/encryptor.rb87
-rw-r--r--lib/chef/exceptions.rb1
-rw-r--r--lib/chef/formatters/base.rb7
-rw-r--r--lib/chef/http/json_input.rb13
-rw-r--r--lib/chef/knife/client_delete.rb2
-rw-r--r--lib/chef/knife/cookbook_site_share.rb2
-rw-r--r--lib/chef/knife/cookbook_upload.rb4
-rw-r--r--lib/chef/mixin/shell_out.rb2
-rw-r--r--lib/chef/platform/provider_mapping.rb39
-rw-r--r--lib/chef/policy_builder/expand_node_object.rb4
-rw-r--r--lib/chef/policy_builder/policyfile.rb5
-rw-r--r--lib/chef/provider.rb2
-rw-r--r--lib/chef/provider/cookbook_file.rb1
-rw-r--r--lib/chef/provider/deploy.rb6
-rw-r--r--lib/chef/provider/env.rb2
-rw-r--r--lib/chef/provider/execute.rb3
-rw-r--r--lib/chef/provider/file.rb3
-rw-r--r--lib/chef/provider/git.rb8
-rw-r--r--lib/chef/provider/group/aix.rb19
-rw-r--r--lib/chef/provider/group/dscl.rb36
-rw-r--r--lib/chef/provider/group/gpasswd.rb3
-rw-r--r--lib/chef/provider/group/groupmod.rb4
-rw-r--r--lib/chef/provider/group/suse.rb3
-rw-r--r--lib/chef/provider/group/usermod.rb3
-rw-r--r--lib/chef/provider/http_request.rb8
-rw-r--r--lib/chef/provider/link.rb2
-rw-r--r--lib/chef/provider/log.rb21
-rw-r--r--lib/chef/provider/mdadm.rb3
-rw-r--r--lib/chef/provider/mount/mount.rb6
-rw-r--r--lib/chef/provider/mount/solaris.rb2
-rw-r--r--lib/chef/provider/package.rb1
-rw-r--r--lib/chef/provider/package/apt.rb3
-rw-r--r--lib/chef/provider/package/easy_install.rb4
-rw-r--r--lib/chef/provider/package/freebsd/base.rb3
-rw-r--r--lib/chef/provider/package/freebsd/pkgng.rb2
-rw-r--r--lib/chef/provider/package/freebsd/port.rb2
-rw-r--r--lib/chef/provider/package/ips.rb3
-rw-r--r--lib/chef/provider/package/paludis.rb9
-rw-r--r--lib/chef/provider/package/portage.rb2
-rw-r--r--lib/chef/provider/package/rpm.rb6
-rw-r--r--lib/chef/provider/package/rubygems.rb2
-rw-r--r--lib/chef/provider/package/smartos.rb3
-rw-r--r--lib/chef/provider/package/windows/msi.rb2
-rw-r--r--lib/chef/provider/package/yum.rb4
-rw-r--r--lib/chef/provider/package/zypper.rb5
-rw-r--r--lib/chef/provider/registry_key.rb2
-rw-r--r--lib/chef/provider/remote_directory.rb1
-rw-r--r--lib/chef/provider/remote_file.rb1
-rw-r--r--lib/chef/provider/remote_file/cache_control_data.rb2
-rw-r--r--lib/chef/provider/remote_file/fetcher.rb2
-rw-r--r--lib/chef/provider/remote_file/ftp.rb1
-rw-r--r--lib/chef/provider/resource_update.rb3
-rw-r--r--lib/chef/provider/service/freebsd.rb3
-rw-r--r--lib/chef/provider/service/init.rb3
-rw-r--r--lib/chef/provider/service/macosx.rb1
-rw-r--r--lib/chef/provider/service/redhat.rb2
-rw-r--r--lib/chef/provider/service/simple.rb3
-rw-r--r--lib/chef/provider/service/solaris.rb3
-rw-r--r--lib/chef/provider/service/systemd.rb1
-rw-r--r--lib/chef/provider/service/windows.rb3
-rw-r--r--lib/chef/provider/subversion.rb2
-rw-r--r--lib/chef/provider/template.rb2
-rw-r--r--lib/chef/provider/template/content.rb1
-rw-r--r--lib/chef/provider/user/aix.rb95
-rw-r--r--lib/chef/provider/user/dscl.rb2
-rw-r--r--lib/chef/provider/user/solaris.rb1
-rw-r--r--lib/chef/provider/user/useradd.rb4
-rw-r--r--lib/chef/providers.rb1
-rw-r--r--lib/chef/resource/paludis_package.rb1
-rw-r--r--lib/chef/resource/user.rb9
-rw-r--r--lib/chef/resource_reporter.rb14
-rw-r--r--lib/chef/role.rb4
-rw-r--r--lib/chef/shell/shell_session.rb4
-rw-r--r--lib/chef/version_constraint.rb8
-rw-r--r--spec/data/cookbooks/openldap/files/default/remotedir/not_a_template.erb2
-rw-r--r--spec/functional/resource/base.rb10
-rw-r--r--spec/functional/resource/cookbook_file_spec.rb2
-rw-r--r--spec/functional/resource/group_spec.rb12
-rw-r--r--spec/functional/resource/package_spec.rb4
-rw-r--r--spec/functional/resource/remote_directory_spec.rb2
-rw-r--r--spec/functional/resource/template_spec.rb2
-rw-r--r--spec/functional/resource/user_spec.rb209
-rw-r--r--spec/spec_helper.rb3
-rw-r--r--spec/support/platform_helpers.rb17
-rw-r--r--spec/support/shared/unit/provider/useradd_based_user_provider.rb11
-rw-r--r--spec/unit/cookbook/file_vendor_spec.rb78
-rw-r--r--spec/unit/cookbook_uploader_spec.rb160
-rw-r--r--spec/unit/data_bag_spec.rb101
-rw-r--r--spec/unit/dsl/recipe_spec.rb12
-rw-r--r--spec/unit/encrypted_data_bag_item_spec.rb154
-rw-r--r--spec/unit/formatters/base_spec.rb48
-rw-r--r--spec/unit/http/json_input_spec.rb128
-rw-r--r--spec/unit/knife/client_delete_spec.rb8
-rw-r--r--spec/unit/knife/cookbook_site_share_spec.rb4
-rw-r--r--spec/unit/knife/cookbook_upload_spec.rb5
-rw-r--r--spec/unit/mixin/template_spec.rb2
-rw-r--r--spec/unit/platform_spec.rb10
-rw-r--r--spec/unit/provider/deploy_spec.rb4
-rw-r--r--spec/unit/provider/env_spec.rb19
-rw-r--r--spec/unit/provider/git_spec.rb4
-rw-r--r--spec/unit/provider/group/dscl_spec.rb39
-rw-r--r--spec/unit/provider/http_request_spec.rb16
-rw-r--r--spec/unit/provider/log_spec.rb86
-rw-r--r--spec/unit/provider/mount/mount_spec.rb15
-rw-r--r--spec/unit/provider/package/paludis_spec.rb10
-rw-r--r--spec/unit/provider/package/rpm_spec.rb12
-rw-r--r--spec/unit/provider/package/zypper_spec.rb44
-rw-r--r--spec/unit/provider/package_spec.rb2
-rw-r--r--spec/unit/provider/remote_directory_spec.rb2
-rw-r--r--spec/unit/provider/template/content_spec.rb2
-rw-r--r--spec/unit/provider_spec.rb12
-rw-r--r--spec/unit/resource/user_spec.rb4
-rw-r--r--spec/unit/resource_reporter_spec.rb48
-rw-r--r--spec/unit/role_spec.rb6
-rw-r--r--spec/unit/shell/shell_session_spec.rb2
-rw-r--r--spec/unit/version_constraint_spec.rb28
137 files changed, 1852 insertions, 479 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0f5faced2e..cfefc0c597 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,12 @@
# Chef Client Changelog
## Unreleased:
+
+* Fix a bug in the experimental Policyfile mode that caused errors when
+ using templates.
+* Disable JSON encoding of request body when non-JSON content type is
+ specified.
+* Clean up FileVendor and CookbookUploader internal APIs
* [**Vasiliy Tolstov**](https://github.com/vtolstov):
Reload systemd service only if it's running, otherwise start.
* [**Chris Jerdonek**](https://github.com/cjerdonek):
@@ -8,6 +14,9 @@
* [**Xabier de Zuazo**](https://github.com/zuazo):
Remove the unused StreamingCookbookUploader class (CHEF-4586)
+* log resource now marks itself as supporting why-run
+* http_request no longer appends "?message=" query string to GET and HEAD requests
+* added shell_out commands directly to the recipe DSL
* cookbook synchronizer deletes old files from cookbooks
* do not clear file cache when override run list is set (CHEF-3684)
* ruby 1.8.7/1.9.1/1.9.2 support is dropped
@@ -18,8 +27,50 @@
* Fix knife cookbook site share on windows (CHEF-4994)
* chef-repo rake tasks are deprecated; print relevant information for
each one.
+* Fix RPM package version detection (Issue 1554)
+* Don't override :default provider map if :default passed as platform (OC-11667).
+* Fix SuSE package removal failure (Issue 1732).
+
+
+* [**Phil Dibowitz**](https://github.com/jaymzh):
+ 'group' provider on OSX properly uses 'dscl' to determine existing groups
+* [**Hugo Lopes Tavares**](https://github.com/hltbra):
+ Catch StandardError in Chef::ResourceReporter#post_reporting_data (Issue 1550).
+* [**Daniel O'Connor**](https://github.com/CloCkWeRX):
+ Fix regex causing DuplicateRole error (Issue 1739).
+* [**Xeron**](https://github.com/xeron):
+ Ability to specify an array for data_bag_path. (CHEF-3399, CHEF-4753)
+* [**Jordan**](https://github.com/jordane):
+ Use Systemd for recent Fedora and RHEL 7.
+* [**Xabier de Zuazo**](https://github.com/zuazo):
+ Encrypted data bags should use different HMAC key and include the IV in the HMAC (CHEF-5356).
+* [**Pierre Ynard**](https://github.com/linkfanel):
+ Don't modify variable passed to env resource when updating.
+* [**Chris Aumann**](https://github.com/chr4):
+ Add "force" attribute to resource/user, pass "-f" to userdel. (Issue 1601)
+* [**Brian Cobb**](https://github.com/bcobb):
+ Chef::VersionConstraint#to_s should accurately reflect constraint's behavior.
+* [**Kevin Graham**](https://github.com/kgraham):
+ Do not override ShellOut:live_stream if already set.
+* [**Mike Heijmans**](https://github.com/parabuzzle):
+ Change knife option --force to --delete-validators. (Issue 1652)
+* [**Pavel Yudin**](https://github.com/Kasen):
+ Add Parallels Cloud Server (PCS) platform support.
+* [**tbe**](https://github.com/tbe):
+ Minor fixes for the Paludis package provider:
+ * only search for non-masked packages,
+ * increase command timeout length for package installation.
+* [**sawanoboly**](https://github.com/sawanoboly):
+ Use shared_path for deploy resource.
+* [**Victor Hahn**](https://github.com/victorhahncastell):
+ Add template syntax check to files in the templates/ dir only.
+* [**Jordan**](https://github.com/jordane):
+ Allow git provider to checkout existing branch names.
+* [**Eric Herot**](https://github.com/eherot):
+ Add whitespace boundaries to some mount point references in mount provider.
+
-## Last Release: 11.14.0
+## Last Release: 11.14.2
* [**Jess Mink**](https://github.com/jmink):
Symlinks to directories should be swingable on windows (CHEF-3960)
@@ -66,8 +117,6 @@
Add Code Climate badge to README.
* [**Phil Sturgeon**](https://github.com/philsturgeon):
Documentation that -E is not respected by knife ssh [search]. (CHEF-4778)
-* [**kaustubh**](https://github.com/kaustubh-d):
- Use 'guest' user on AIX for RSpec tests. (OC-9954)
* [**Stephan Renatus**](https://github.com/srenatus):
Fix resource_spec.rb.
* [**Sander van Harmelen**](https://github.com/svanharmelen):
@@ -113,8 +162,9 @@
* [**Vasiliy Tolstov**](https://github.com/vtolstov):
Added the initial exherbo linux support for Chef providers.
-
-
+* Fix knife cookbook site share on windows (CHEF-4994)
+* YAJL Allows Invalid JSON File Sending To The Server (CHEF-4899)
+* YAJL Silently Ingesting Invalid JSON and "Normalizing" Incorrectly (CHEF-4565)
* Update rpm provider checking regex to allow for special characters (CHEF-4893)
* Allow for spaces in selinux controlled directories (CHEF-5095)
* Windows batch resource run action fails: " TypeError: can't convert nil into String" (CHEF-5287)
@@ -147,7 +197,10 @@
* Send md5 checksummed data for registry key if data type is binary, dword, or qword. (Chef-5323)
* Add warning if host resembles winrm command and knife-windows is not present.
* Use FFI binders to attach :SendMessageTimeout to avoid DL deprecation warning. (ChefDK Issues 69)
-
+* Use 'guest' user on AIX for RSpec tests. (OC-9954)
+* Added DelayedEvaluator support in LWRP using the `lazy {}` key
+* Fixed a bug where nested resources that inherited from Resource::LWRPBase
+ would not share the same actions/default_action as their parent
## Previous Release: 11.12.8
* Fix OS X service provider actions that don't require the service label
diff --git a/CHEF_MVPS.md b/CHEF_MVPS.md
index dfd0985bba..620a516080 100644
--- a/CHEF_MVPS.md
+++ b/CHEF_MVPS.md
@@ -12,11 +12,14 @@ After receiving three MVP awards, we add someone to the hall of fame. We want to
* Thom May
* Bryan Berry
* Bryan McLellan
+* Jeff Blaine
#### The MVP recipients
| Release | Date | MVP |
|---------|------|-----|
+| [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 |
| [Client 11.10.2](http://www.getchef.com/blog/2014/02/18/chef-client-release-11-10-2-10-30-4/) | 2014-02-18 | Eric Tucker |
| [Client 11.10.0](http://www.getchef.com/blog/2014/02/06/chef-client-11-10-0-release/) | 2014-02-06 | Nikhil Benesch |
@@ -27,6 +30,7 @@ After receiving three MVP awards, we add someone to the hall of fame. We want to
| [Client 11.4.0](http://www.opscode.com/blog/2013/02/13/chef-client-11-4-0-10-22-0-released/) | 2013-02-13 | Vaidas Jablonskis |
| [Client 11.2.0](http://www.opscode.com/blog/2013/02/07/chef-client-11-2-0-10-20-0-released/) | 2013-02-06 | Mike Javorski |
| [Chef 11.0.0](http://www.opscode.com/blog/2013/02/04/chef-11-released/) | 2013-02-04 | Andrea Campi, Bryan Berry |
+| [Chef 10.32.2](http://www.getchef.com/blog/2014/04/08/release-chef-client-11-12-0-10-32-2/) | 2014-04-08 | Phil Dibowitz |
| [Chef 10.30.4](http://www.getchef.com/blog/2014/02/18/chef-client-release-11-10-2-10-30-4/) | 2014-02-18 | Christopher Laco |
| [Chef 10.30.2](http://www.getchef.com/blog/2013/12/06/release-chef-client-10-30-2-11-8-2-mixlib-shellout-1-3-0/) | 2013-12-06 | Phil Dibowitz |
| [Chef 10.28.2](http://www.getchef.com/blog/2013/10/08/release-chef-client-11-6-2-10-28-2/) | 2013-10-08 | Jeff Blaine |
@@ -81,4 +85,3 @@ After receiving three MVP awards, we add someone to the hall of fame. We want to
| [Chef 0.5.6](http://www.opscode.com/blog/2009/03/06/chef-0-5-6/) | 2009-03-06 | Sean Cribbs |
| [Chef 0.5.4](http://www.opscode.com/blog/2009/02/13/chef-0-5-4/) | 2009-02-13 | Arjuna Christensen |
| [Chef 0.5.2](http://www.opscode.com/blog/2009/02/01/chef-0-5-2-and-ohai-0-1-4/) | 2009-02-01 | Bryan McLellan |
-
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 20b8be8c40..6cc27697eb 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -12,8 +12,8 @@ We utilize **Github Issues** for issue tracking and contributions. You can contr
We have a 3 step process that utilizes **Github Issues**:
1. Sign our
- [Individual Contributor License Agreement (CLA)](https://secure.echosign.com/public/hostedForm?formid=PJIF5694K6L)
- or [Corporate CLA](https://secure.echosign.com/public/hostedForm?formid=PIE6C7AX856) online once.
+ [Individual Contributor License Agreement (CLA)](https://supermarket.getchef.com/icla-signatures/new)
+ or [Corporate CLA](https://supermarket.getchef.com/ccla-signatures/new) online once.
2. Create a Github Pull Request.
3. Do [Code Review](#cr) with the **Chef Engineering Team** or **Chef Core Committers** on the pull request.
@@ -83,10 +83,10 @@ To make a good faith effort to ensure these criteria are met, Chef requires an I
It only takes a few minutes to complete a CLA, and you retain the copyright to your contribution.
You can complete our
- [Individual CLA](https://secure.echosign.com/public/hostedForm?formid=PJIF5694K6L) online.
+ [Individual CLA](https://supermarket.getchef.com/icla-signatures/new) online.
If you're contributing on behalf of your employer and they retain the copyright for your works,
have your employer fill out our
- [Corporate CLA](https://secure.echosign.com/public/hostedForm?formid=PIE6C7AX856) instead.
+ [Corporate CLA](https://supermarket.getchef.com/ccla-signatures/new) instead.
### Chef Obvious Fix Policy
diff --git a/DOC_CHANGES.md b/DOC_CHANGES.md
index 76b28d0586..71ded60df8 100644
--- a/DOC_CHANGES.md
+++ b/DOC_CHANGES.md
@@ -105,3 +105,7 @@ knife now includes a warning in the -E/--environment option that this setting is
### New configurable option :yum-lock-timeout
You can now set the timeout for receiving the yum lock in `config.rb` by adding `yum-lock-timeout SECONDS` (default is 30 seconds).
+
+### Encrypted Data Bags Version 3
+
+Encrypted Data Bag version 3 uses [GCM](http://en.wikipedia.org/wiki/Galois/Counter_Mode) internally. Ruby 2 and OpenSSL version 1.0.1 or higher are required to use it.
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 6cd6b5cb52..cf28b05592 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,4 +1,16 @@
-# Chef Client Release Notes:
+# Chef Client Release Notes 11.14.2:
+
+## http_request resource no longer appends query string
+
+Previously the http_request GET and HEAD requests appended a hard-coded "?message=resource_name"
+query parameter that could not be overridden. That feature has been dropped. Cookbooks that
+actually relied on that should manually add the message query string to the URL they pass to
+the resource.
+
+## Added Chef::Mixin::ShellOut methods to Recipe DSL
+
+Added the ability to use shell_out, shell_out! and shell_out_with_systems_locale in the Recipe
+DSL without needing to explicitly extend/include the mixin.
## Cookbook Synchronizer Cleans Deleted Files
@@ -51,3 +63,29 @@ directory will also be inherited correctly.
## Knife now logs to stderr
Informational messages from knife are now sent to stderr, allowing you to pipe the output of knife to other commands without having to filter these messages out.
+
+# Internal API Changes in this Release
+
+These changes do not impact any cookbook code, but may impact tools that
+use the code base as a library. Authors of tools that rely on Chef
+internals should review these changes carefully and update their
+applications.
+
+## Changes to CookbookUpload
+
+`Chef::CookbookUpload.new` previously took a path as the second
+argument, but due to internal changes, this parameter was not used, and
+it has been removed. See: https://github.com/opscode/chef/commit/12c9bed3a5a7ab86ff78cb660d96f8b77ad6395d
+
+## Changes to FileVendor
+
+`Chef::Cookbook::FileVendor` was previously configured by passing a
+block to the `on_create` method; it is now configured by calling either
+`fetch_from_remote` or `fetch_from_disk`. See: https://github.com/opscode/chef/commit/3b2b4de8e7f0d55524f2a0ccaf3e1aa9f2d371eb
+
+## 'group' provider on OSX properly uses 'dscl' to determine existing groups
+
+On OSX, the 'group' provider would use 'etc' to determine existing groups,
+but 'dscl' to add groups, causing broken idempotency if something existed
+in /etc/group. The provider now uses 'dscl' for both idempotenty checks and
+modifications.
diff --git a/lib/chef/chef_fs/file_system/cookbooks_dir.rb b/lib/chef/chef_fs/file_system/cookbooks_dir.rb
index a58bfdd1f2..d4857cdabd 100644
--- a/lib/chef/chef_fs/file_system/cookbooks_dir.rb
+++ b/lib/chef/chef_fs/file_system/cookbooks_dir.rb
@@ -106,7 +106,7 @@ class Chef
cookbook_to_upload.freeze_version if options[:freeze]
# Instantiate a new uploader based on the proxy loader
- uploader = Chef::CookbookUploader.new(cookbook_to_upload, proxy_cookbook_path, :force => options[:force], :rest => root.chef_rest)
+ uploader = Chef::CookbookUploader.new(cookbook_to_upload, :force => options[:force], :rest => root.chef_rest)
with_actual_cookbooks_dir(temp_cookbooks_path) do
upload_cookbook!(uploader)
@@ -128,7 +128,7 @@ class Chef
def upload_unversioned_cookbook(other, options)
cookbook_to_upload = other.chef_object
cookbook_to_upload.freeze_version if options[:freeze]
- uploader = Chef::CookbookUploader.new(cookbook_to_upload, other.parent.file_path, :force => options[:force], :rest => root.chef_rest)
+ uploader = Chef::CookbookUploader.new(cookbook_to_upload, :force => options[:force], :rest => root.chef_rest)
with_actual_cookbooks_dir(other.parent.file_path) do
upload_cookbook!(uploader)
diff --git a/lib/chef/config.rb b/lib/chef/config.rb
index 93cd05d0ef..9d465a3cea 100644
--- a/lib/chef/config.rb
+++ b/lib/chef/config.rb
@@ -432,7 +432,8 @@ class Chef
# format. Version "2" is available which adds encrypt-then-mac protection.
# To maintain compatibility, versions other than 1 must be opt-in.
#
- # Set this to `2` if you have chef-client 11.6.0+ in your infrastructure:
+ # Set this to `2` if you have chef-client 11.6.0+ in your infrastructure.
+ # Set this to `3` if you have chef-client 11.?.0+, ruby 2 and OpenSSL >= 1.0.1 in your infrastructure. (TODO)
default :data_bag_encrypt_version, 1
# When reading data bag items, any supported version is accepted. However,
diff --git a/lib/chef/cookbook/file_system_file_vendor.rb b/lib/chef/cookbook/file_system_file_vendor.rb
index 8896e3ed30..e351ec4702 100644
--- a/lib/chef/cookbook/file_system_file_vendor.rb
+++ b/lib/chef/cookbook/file_system_file_vendor.rb
@@ -31,6 +31,9 @@ class Chef
# non-sensical.
class FileSystemFileVendor < FileVendor
+ attr_reader :cookbook_name
+ attr_reader :repo_paths
+
def initialize(manifest, *repo_paths)
@cookbook_name = manifest[:cookbook_name]
@repo_paths = repo_paths.flatten
diff --git a/lib/chef/cookbook/file_vendor.rb b/lib/chef/cookbook/file_vendor.rb
index 406f23ca25..b82b52f90c 100644
--- a/lib/chef/cookbook/file_vendor.rb
+++ b/lib/chef/cookbook/file_vendor.rb
@@ -24,15 +24,39 @@ class Chef
# This class handles fetching of cookbook files based on specificity.
class FileVendor
- def self.on_create(&block)
- @instance_creator = block
+ @vendor_class = nil
+ @initialization_options = nil
+
+ # Configures FileVendor to use the RemoteFileVendor implementation. After
+ # calling this, subsequent calls to create_from_manifest will return a
+ # RemoteFileVendor object initialized with the given http_client
+ def self.fetch_from_remote(http_client)
+ @vendor_class = RemoteFileVendor
+ @initialization_options = http_client
+ end
+
+ def self.fetch_from_disk(cookbook_paths)
+ @vendor_class = FileSystemFileVendor
+ @initialization_options = cookbook_paths
+ end
+
+ # Returns the implementation class that is currently configured, or `nil`
+ # if one has not been configured yet.
+ def self.vendor_class
+ @vendor_class
+ end
+
+ def self.initialization_options
+ @initialization_options
end
# Factory method that creates the appropriate kind of
# Cookbook::FileVendor to serve the contents of the manifest
def self.create_from_manifest(manifest)
- raise "Must call Chef::Cookbook::FileVendor.on_create before calling create_from_manifest factory" unless defined?(@instance_creator)
- @instance_creator.call(manifest)
+ if @vendor_class.nil?
+ raise "Must configure FileVendor to use a specific implementation before creating an instance"
+ end
+ @vendor_class.new(manifest, @initialization_options)
end
# Gets the on-disk location for the given cookbook file.
diff --git a/lib/chef/cookbook/metadata.rb b/lib/chef/cookbook/metadata.rb
index 7da1ae70de..32574c75e2 100644
--- a/lib/chef/cookbook/metadata.rb
+++ b/lib/chef/cookbook/metadata.rb
@@ -242,8 +242,8 @@ class Chef
# versions<Array>:: Returns the list of versions for the platform
def supports(platform, *version_args)
version = new_args_format(:supports, platform, version_args)
- normalized_version = normalize_version_constraint(:supports, platform, version)
- @platforms[platform] = normalized_version
+ constraint = validate_version_constraint(:supports, platform, version)
+ @platforms[platform] = constraint.to_s
@platforms[platform]
end
@@ -259,8 +259,8 @@ class Chef
# versions<Array>:: Returns the list of versions for the platform
def depends(cookbook, *version_args)
version = new_args_format(:depends, cookbook, version_args)
- normalized_version = normalize_version_constraint(:depends, cookbook, version)
- @dependencies[cookbook] = normalized_version
+ constraint = validate_version_constraint(:depends, cookbook, version)
+ @dependencies[cookbook] = constraint.to_s
@dependencies[cookbook]
end
@@ -276,8 +276,8 @@ class Chef
# versions<Array>:: Returns the list of versions for the platform
def recommends(cookbook, *version_args)
version = new_args_format(:recommends, cookbook, version_args)
- normalized_version = normalize_version_constraint(:recommends, cookbook, version)
- @recommendations[cookbook] = normalized_version
+ constraint = validate_version_constraint(:recommends, cookbook, version)
+ @recommendations[cookbook] = constraint.to_s
@recommendations[cookbook]
end
@@ -293,8 +293,8 @@ class Chef
# versions<Array>:: Returns the list of versions for the platform
def suggests(cookbook, *version_args)
version = new_args_format(:suggests, cookbook, version_args)
- normalized_version = normalize_version_constraint(:suggests, cookbook, version)
- @suggestions[cookbook] = normalized_version
+ constraint = validate_version_constraint(:suggests, cookbook, version)
+ @suggestions[cookbook] = constraint.to_s
@suggestions[cookbook]
end
@@ -310,8 +310,8 @@ class Chef
# versions<Array>:: Returns the list of versions for the platform
def conflicts(cookbook, *version_args)
version = new_args_format(:conflicts, cookbook, version_args)
- normalized_version = normalize_version_constraint(:conflicts, cookbook, version)
- @conflicting[cookbook] = normalized_version
+ constraint = validate_version_constraint(:conflicts, cookbook, version)
+ @conflicting[cookbook] = constraint.to_s
@conflicting[cookbook]
end
@@ -331,8 +331,8 @@ class Chef
# versions<Array>:: Returns the list of versions for the platform
def provides(cookbook, *version_args)
version = new_args_format(:provides, cookbook, version_args)
- normalized_version = normalize_version_constraint(:provides, cookbook, version)
- @providing[cookbook] = normalized_version
+ constraint = validate_version_constraint(:provides, cookbook, version)
+ @providing[cookbook] = constraint.to_s
@providing[cookbook]
end
@@ -347,8 +347,8 @@ class Chef
# versions<Array>:: Returns the list of versions for the platform
def replaces(cookbook, *version_args)
version = new_args_format(:replaces, cookbook, version_args)
- normalized_version = normalize_version_constraint(:replaces, cookbook, version)
- @replacing[cookbook] = normalized_version
+ constraint = validate_version_constraint(:replaces, cookbook, version)
+ @replacing[cookbook] = constraint.to_s
@replacing[cookbook]
end
@@ -533,11 +533,6 @@ INVALID
raise Exceptions::InvalidVersionConstraint, msg
end
- def normalize_version_constraint(caller_name, dep_name, constraint_str)
- version_constraint = validate_version_constraint(caller_name, dep_name, constraint_str)
- "#{version_constraint.op} #{version_constraint.raw_version}"
- end
-
# Verify that the given array is an array of strings
#
# Raise an exception if the members of the array are not Strings
diff --git a/lib/chef/cookbook/remote_file_vendor.rb b/lib/chef/cookbook/remote_file_vendor.rb
index 49de62cf65..2ddce31001 100644
--- a/lib/chef/cookbook/remote_file_vendor.rb
+++ b/lib/chef/cookbook/remote_file_vendor.rb
@@ -25,6 +25,9 @@ class Chef
# if not available, loading them from the remote server.
class RemoteFileVendor < FileVendor
+ attr_reader :rest
+ attr_reader :cookbook_name
+
def initialize(manifest, rest)
@manifest = manifest
@cookbook_name = @manifest[:cookbook_name]
diff --git a/lib/chef/cookbook/syntax_check.rb b/lib/chef/cookbook/syntax_check.rb
index 9fee7c2a54..092fb47eba 100644
--- a/lib/chef/cookbook/syntax_check.rb
+++ b/lib/chef/cookbook/syntax_check.rb
@@ -125,7 +125,7 @@ class Chef
end
def template_files
- remove_ignored_files Dir[File.join(cookbook_path, '**', '*.erb')]
+ remove_ignored_files Dir[File.join(cookbook_path, '**/templates/**', '*.erb')]
end
def untested_template_files
diff --git a/lib/chef/cookbook_uploader.rb b/lib/chef/cookbook_uploader.rb
index adad55b4ca..2d8bf5bc7e 100644
--- a/lib/chef/cookbook_uploader.rb
+++ b/lib/chef/cookbook_uploader.rb
@@ -35,8 +35,8 @@ class Chef
# in Chef::Config.
# * :concurrency An integer that decided how many threads will be used to
# perform concurrent uploads
- def initialize(cookbooks, path, opts={})
- @path, @opts = path, opts
+ def initialize(cookbooks, opts={})
+ @opts = opts
@cookbooks = Array(cookbooks)
@rest = opts[:rest] || Chef::REST.new(Chef::Config[:chef_server_url])
@concurrency = opts[:concurrency] || 10
@@ -53,7 +53,7 @@ class Chef
end
checksums = checksum_files.inject({}){|memo,elt| memo[elt.first]=nil ; memo}
- new_sandbox = rest.post_rest("sandboxes", { :checksums => checksums })
+ new_sandbox = rest.post("sandboxes", { :checksums => checksums })
Chef::Log.info("Uploading files")
@@ -80,7 +80,7 @@ class Chef
# in eventual consistency)
retries = 0
begin
- rest.put_rest(sandbox_url, {:is_completed => true})
+ rest.put(sandbox_url, {:is_completed => true})
rescue Net::HTTPServerException => e
if e.message =~ /^400/ && (retries += 1) <= 5
sleep 2
@@ -94,7 +94,7 @@ class Chef
cookbooks.each do |cb|
save_url = opts[:force] ? cb.force_save_url : cb.save_url
begin
- rest.put_rest(save_url, cb)
+ rest.put(save_url, cb)
rescue Net::HTTPServerException => e
case e.response.code
when "409"
@@ -108,32 +108,19 @@ class Chef
Chef::Log.info("Upload complete!")
end
- def worker_thread(work_queue)
- end
-
def uploader_function_for(file, checksum, url, checksums_to_upload)
lambda do
# Checksum is the hexadecimal representation of the md5,
# but we need the base64 encoding for the content-md5
# header
checksum64 = Base64.encode64([checksum].pack("H*")).strip
- timestamp = Time.now.utc.iso8601
file_contents = File.open(file, "rb") {|f| f.read}
- # TODO - 5/28/2010, cw: make signing and sending the request streaming
+
+ # Custom headers. 'content-type' disables JSON serialization of the request body.
headers = { 'content-type' => 'application/x-binary', 'content-md5' => checksum64, "accept" => 'application/json' }
- if rest.signing_key
- sign_obj = Mixlib::Authentication::SignedHeaderAuth.signing_object(
- :http_method => :put,
- :path => URI.parse(url).path,
- :body => file_contents,
- :timestamp => timestamp,
- :user_id => rest.client_name
- )
- headers.merge!(sign_obj.sign(OpenSSL::PKey::RSA.new(rest.signing_key)))
- end
begin
- Chef::HTTP::Simple.new(url, :headers=>headers).put(url, file_contents)
+ rest.put(url, file_contents, headers)
checksums_to_upload.delete(checksum)
rescue Net::HTTPServerException, Net::HTTPFatalError, Errno::ECONNREFUSED, Timeout::Error, Errno::ETIMEDOUT, SocketError => e
error_message = "Failed to upload #{file} (#{checksum}) to #{url} : #{e.message}"
@@ -146,7 +133,7 @@ class Chef
def validate_cookbooks
cookbooks.each do |cb|
- syntax_checker = Chef::Cookbook::SyntaxCheck.for_cookbook(cb.name, @user_cookbook_path)
+ syntax_checker = Chef::Cookbook::SyntaxCheck.for_cookbook(cb.name)
Chef::Log.info("Validating ruby files")
exit(1) unless syntax_checker.validate_ruby_files
Chef::Log.info("Validating templates")
diff --git a/lib/chef/cookbook_version.rb b/lib/chef/cookbook_version.rb
index 3d8b9fb908..778a6043bf 100644
--- a/lib/chef/cookbook_version.rb
+++ b/lib/chef/cookbook_version.rb
@@ -25,6 +25,7 @@ require 'chef/cookbook/metadata'
require 'chef/version_class'
require 'pathname'
require 'chef/monkey_patches/pathname'
+require 'chef/digester'
class Chef
diff --git a/lib/chef/data_bag.rb b/lib/chef/data_bag.rb
index 639d71a74d..1133aa3e73 100644
--- a/lib/chef/data_bag.rb
+++ b/lib/chef/data_bag.rb
@@ -83,11 +83,15 @@ class Chef
def self.list(inflate=false)
if Chef::Config[:solo]
- unless File.directory?(Chef::Config[:data_bag_path])
- raise Chef::Exceptions::InvalidDataBagPath, "Data bag path '#{Chef::Config[:data_bag_path]}' is invalid"
- end
+ paths = Array(Chef::Config[:data_bag_path])
+ names = []
+ paths.each do |path|
+ unless File.directory?(path)
+ raise Chef::Exceptions::InvalidDataBagPath, "Data bag path '#{path}' is invalid"
+ end
- names = Dir.glob(File.join(Chef::Config[:data_bag_path], "*")).map{|f|File.basename(f)}.sort
+ names += Dir.glob(File.join(path, "*")).map{|f|File.basename(f)}.sort
+ end
names.inject({}) {|h, n| h[n] = n; h}
else
if inflate
@@ -105,15 +109,25 @@ class Chef
# Load a Data Bag by name via either the RESTful API or local data_bag_path if run in solo mode
def self.load(name)
if Chef::Config[:solo]
- unless File.directory?(Chef::Config[:data_bag_path])
- raise Chef::Exceptions::InvalidDataBagPath, "Data bag path '#{Chef::Config[:data_bag_path]}' is invalid"
- end
+ paths = Array(Chef::Config[:data_bag_path])
+ data_bag = {}
+ paths.each do |path|
+ unless File.directory?(path)
+ raise Chef::Exceptions::InvalidDataBagPath, "Data bag path '#{path}' is invalid"
+ end
+
+ Dir.glob(File.join(path, name.to_s, "*.json")).inject({}) do |bag, f|
+ item = Chef::JSONCompat.from_json(IO.read(f))
- Dir.glob(File.join(Chef::Config[:data_bag_path], "#{name}", "*.json")).inject({}) do |bag, f|
- item = Chef::JSONCompat.from_json(IO.read(f))
- bag[item['id']] = item
- bag
+ # Check if we have multiple items with similar names (ids) and raise if their content differs
+ if data_bag.has_key?(item["id"]) && data_bag[item["id"]] != item
+ raise Chef::Exceptions::DuplicateDataBagItem, "Data bag '#{name}' has items with the same name '#{item["id"]}' but different content."
+ else
+ data_bag[item["id"]] = item
+ end
+ end
end
+ return data_bag
else
Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("data/#{name}")
end
diff --git a/lib/chef/dsl/recipe.rb b/lib/chef/dsl/recipe.rb
index 6846703f09..23cfbd558c 100644
--- a/lib/chef/dsl/recipe.rb
+++ b/lib/chef/dsl/recipe.rb
@@ -28,6 +28,7 @@ class Chef
# objects via method calls.
module Recipe
+ include Chef::Mixin::ShellOut
include Chef::Mixin::ConvertToClassName
def method_missing(method_symbol, *args, &block)
diff --git a/lib/chef/encrypted_data_bag_item.rb b/lib/chef/encrypted_data_bag_item.rb
index b0d9337212..f722b5dc38 100644
--- a/lib/chef/encrypted_data_bag_item.rb
+++ b/lib/chef/encrypted_data_bag_item.rb
@@ -48,6 +48,7 @@ require 'open-uri'
#
class Chef::EncryptedDataBagItem
ALGORITHM = 'aes-256-cbc'
+ AEAD_ALGORITHM = 'aes-256-gcm'
#
# === Synopsis
diff --git a/lib/chef/encrypted_data_bag_item/assertions.rb b/lib/chef/encrypted_data_bag_item/assertions.rb
new file mode 100644
index 0000000000..e9acebbd29
--- /dev/null
+++ b/lib/chef/encrypted_data_bag_item/assertions.rb
@@ -0,0 +1,57 @@
+#
+# Author:: Xabier de Zuazo (<xabier@onddo.com>)
+# Copyright:: Copyright (c) 2014 Onddo Labs, SL.
+# 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/encrypted_data_bag_item/unacceptable_encrypted_data_bag_item_format'
+require 'chef/encrypted_data_bag_item/unsupported_cipher'
+
+class Chef::EncryptedDataBagItem
+
+ class EncryptedDataBagRequirementsFailure < StandardError
+ end
+
+ module Assertions
+
+ def assert_format_version_acceptable!(format_version)
+ unless format_version.kind_of?(Integer) and format_version >= Chef::Config[:data_bag_decrypt_minimum_version]
+ raise UnacceptableEncryptedDataBagItemFormat,
+ "The encrypted data bag item has format version `#{format_version}', " +
+ "but the config setting 'data_bag_decrypt_minimum_version' requires version `#{Chef::Config[:data_bag_decrypt_minimum_version]}'"
+ end
+ end
+
+ def assert_valid_cipher!(requested_cipher, algorithm)
+ # In the future, chef may support configurable ciphers. For now, only
+ # aes-256-cbc and aes-256-gcm are supported.
+ unless requested_cipher == algorithm
+ raise UnsupportedCipher,
+ "Cipher '#{requested_cipher}' is not supported by this version of Chef. Available ciphers: ['#{ALGORITHM}', '#{AEAD_ALGORITHM}']"
+ end
+ end
+
+ def assert_aead_requirements_met!(algorithm)
+ unless OpenSSL::Cipher.method_defined?(:auth_data=)
+ raise EncryptedDataBagRequirementsFailure, "The used Encrypted Data Bags version requires Ruby >= 1.9"
+ end
+ unless OpenSSL::Cipher.ciphers.include?(algorithm)
+ raise EncryptedDataBagRequirementsFailure, "The used Encrypted Data Bags version requires an OpenSSL version with \"#{algorithm}\" algorithm support"
+ end
+ end
+
+ end
+
+end
diff --git a/lib/chef/encrypted_data_bag_item/decryptor.rb b/lib/chef/encrypted_data_bag_item/decryptor.rb
index 69b8d62e3b..0fe323870b 100644
--- a/lib/chef/encrypted_data_bag_item/decryptor.rb
+++ b/lib/chef/encrypted_data_bag_item/decryptor.rb
@@ -23,9 +23,8 @@ require 'base64'
require 'digest/sha2'
require 'chef/encrypted_data_bag_item'
require 'chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format'
-require 'chef/encrypted_data_bag_item/unacceptable_encrypted_data_bag_item_format'
require 'chef/encrypted_data_bag_item/decryption_failure'
-require 'chef/encrypted_data_bag_item/unsupported_cipher'
+require 'chef/encrypted_data_bag_item/assertions'
class Chef::EncryptedDataBagItem
@@ -37,6 +36,7 @@ class Chef::EncryptedDataBagItem
# to create an instance of the appropriate strategy for the given encrypted
# data bag value.
module Decryptor
+ extend Chef::EncryptedDataBagItem::Assertions
# Detects the encrypted data bag item format version and instantiates a
# decryptor object for that version. Call #for_decrypted_item on the
@@ -45,6 +45,8 @@ class Chef::EncryptedDataBagItem
format_version = format_version_of(encrypted_value)
assert_format_version_acceptable!(format_version)
case format_version
+ when 3
+ Version3Decryptor.new(encrypted_value, key)
when 2
Version2Decryptor.new(encrypted_value, key)
when 1
@@ -65,15 +67,8 @@ class Chef::EncryptedDataBagItem
end
end
- def self.assert_format_version_acceptable!(format_version)
- unless format_version.kind_of?(Integer) and format_version >= Chef::Config[:data_bag_decrypt_minimum_version]
- raise UnacceptableEncryptedDataBagItemFormat,
- "The encrypted data bag item has format version `#{format_version}', " +
- "but the config setting 'data_bag_decrypt_minimum_version' requires version `#{Chef::Config[:data_bag_decrypt_minimum_version]}'"
- end
- end
-
class Version0Decryptor
+ include Chef::EncryptedDataBagItem::Assertions
attr_reader :encrypted_data
attr_reader :key
@@ -83,6 +78,11 @@ class Chef::EncryptedDataBagItem
@key = key
end
+ # Returns the used decryption algorithm
+ def algorithm
+ ALGORITHM
+ end
+
def for_decrypted_item
YAML.load(decrypted_data)
end
@@ -102,7 +102,7 @@ class Chef::EncryptedDataBagItem
def openssl_decryptor
@openssl_decryptor ||= begin
- d = OpenSSL::Cipher::Cipher.new(ALGORITHM)
+ d = OpenSSL::Cipher.new(algorithm)
d.decrypt
d.pkcs5_keyivgen(key)
d
@@ -110,7 +110,7 @@ class Chef::EncryptedDataBagItem
end
end
- class Version1Decryptor
+ class Version1Decryptor < Version0Decryptor
attr_reader :encrypted_data
attr_reader :key
@@ -148,24 +148,16 @@ class Chef::EncryptedDataBagItem
def openssl_decryptor
@openssl_decryptor ||= begin
- assert_valid_cipher!
- d = OpenSSL::Cipher::Cipher.new(ALGORITHM)
+ assert_valid_cipher!(@encrypted_data["cipher"], algorithm)
+ d = OpenSSL::Cipher.new(algorithm)
d.decrypt
+ # We must set key before iv: https://bugs.ruby-lang.org/issues/8221
d.key = Digest::SHA256.digest(key)
d.iv = iv
d
end
end
- def assert_valid_cipher!
- # In the future, chef may support configurable ciphers. For now, only
- # aes-256-cbc is supported.
- requested_cipher = @encrypted_data["cipher"]
- unless requested_cipher == ALGORITHM
- raise UnsupportedCipher,
- "Cipher '#{requested_cipher}' is not supported by this version of Chef. Available ciphers: ['#{ALGORITHM}']"
- end
- end
end
class Version2Decryptor < Version1Decryptor
@@ -176,7 +168,7 @@ class Chef::EncryptedDataBagItem
end
def validate_hmac!
- digest = OpenSSL::Digest::Digest.new("sha256")
+ digest = OpenSSL::Digest.new("sha256")
raw_hmac = OpenSSL::HMAC.digest(digest, key, @encrypted_data["encrypted_data"])
if candidate_hmac_matches?(raw_hmac)
@@ -197,5 +189,38 @@ class Chef::EncryptedDataBagItem
valid == 0
end
end
+
+ class Version3Decryptor < Version1Decryptor
+
+ def initialize(encrypted_data, key)
+ super
+ assert_aead_requirements_met!(algorithm)
+ end
+
+
+ # Returns the used decryption algorithm
+ def algorithm
+ AEAD_ALGORITHM
+ end
+
+ def auth_tag
+ auth_tag_b64 = @encrypted_data["auth_tag"]
+ if auth_tag_b64.nil?
+ raise DecryptionFailure, "Error decrypting data bag value: invalid authentication tag. Most likely the data is corrupted"
+ end
+ Base64.decode64(auth_tag_b64)
+ end
+
+ def openssl_decryptor
+ @openssl_decryptor ||= begin
+ d = super
+ d.auth_tag = auth_tag
+ d.auth_data = ''
+ d
+ end
+ end
+
+ end
+
end
end
diff --git a/lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb b/lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb
new file mode 100644
index 0000000000..3567925844
--- /dev/null
+++ b/lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb
@@ -0,0 +1,37 @@
+#
+# Author:: Xabier de Zuazo (<xabier@onddo.com>)
+# Copyright:: Copyright (c) 2014 Onddo Labs, SL.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef::EncryptedDataBagItem
+
+ class EncryptedDataBagRequirementsFailure < StandardError
+ end
+
+ module Assertions
+
+ def assert_requirements_met!
+ unless OpenSSL::Cipher.method_defined?(:auth_data=)
+ raise EncryptedDataBagRequirementsFailure, "The used Encrypted Data Bags version requires Ruby >= 1.9"
+ end
+ unless OpenSSL::Cipher.ciphers.include?(algorithm)
+ raise EncryptedDataBagRequirementsFailure, "The used Encrypted Data Bags version requires an OpenSSL version with \"#{algorithm}\" algorithm support"
+ end
+ end
+
+ end
+
+end
diff --git a/lib/chef/encrypted_data_bag_item/encryption_failure.rb b/lib/chef/encrypted_data_bag_item/encryption_failure.rb
new file mode 100644
index 0000000000..380e9bc1f7
--- /dev/null
+++ b/lib/chef/encrypted_data_bag_item/encryption_failure.rb
@@ -0,0 +1,22 @@
+#
+# Author:: Xabier de Zuazo (<xabier@onddo.com>)
+# Copyright:: Copyright (c) 2014 Onddo Labs, SL.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef::EncryptedDataBagItem
+ class EncryptionFailure < StandardError
+ end
+end
diff --git a/lib/chef/encrypted_data_bag_item/encryptor.rb b/lib/chef/encrypted_data_bag_item/encryptor.rb
index 9686e84b34..673b52a3c3 100644
--- a/lib/chef/encrypted_data_bag_item/encryptor.rb
+++ b/lib/chef/encrypted_data_bag_item/encryptor.rb
@@ -22,6 +22,8 @@ require 'openssl'
require 'ffi_yajl'
require 'chef/encrypted_data_bag_item'
require 'chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format'
+require 'chef/encrypted_data_bag_item/encryption_failure'
+require 'chef/encrypted_data_bag_item/assertions'
class Chef::EncryptedDataBagItem
@@ -40,9 +42,11 @@ class Chef::EncryptedDataBagItem
Version1Encryptor.new(value, secret, iv)
when 2
Version2Encryptor.new(value, secret, iv)
+ when 3
+ Version3Encryptor.new(value, secret, iv)
else
raise UnsupportedEncryptedDataBagItemFormat,
- "Invalid encrypted data bag format version `#{format_version}'. Supported versions are '1', '2'"
+ "Invalid encrypted data bag format version `#{format_version}'. Supported versions are '1', '2', '3'"
end
end
@@ -50,6 +54,8 @@ class Chef::EncryptedDataBagItem
attr_reader :key
attr_reader :plaintext_data
+ include Chef::EncryptedDataBagItem::Assertions
+
# Create a new Encryptor for +data+, which will be encrypted with the given
# +key+.
#
@@ -65,6 +71,11 @@ class Chef::EncryptedDataBagItem
@iv = iv && Base64.decode64(iv)
end
+ # Returns the used encryption algorithm
+ def algorithm
+ ALGORITHM
+ end
+
# Returns a wrapped and encrypted version of +plaintext_data+ suitable for
# using as the value in an encrypted data bag item.
def for_encrypted_item
@@ -72,27 +83,28 @@ class Chef::EncryptedDataBagItem
"encrypted_data" => encrypted_data,
"iv" => Base64.encode64(iv),
"version" => 1,
- "cipher" => ALGORITHM
+ "cipher" => algorithm
}
end
# Generates or returns the IV.
def iv
- # Generated IV comes from OpenSSL::Cipher::Cipher#random_iv
+ # Generated IV comes from OpenSSL::Cipher#random_iv
# This gets generated when +openssl_encryptor+ gets created.
openssl_encryptor if @iv.nil?
@iv
end
- # Generates (and memoizes) an OpenSSL::Cipher::Cipher object and configures
+ # Generates (and memoizes) an OpenSSL::Cipher object and configures
# it for the specified iv and encryption key.
def openssl_encryptor
@openssl_encryptor ||= begin
- encryptor = OpenSSL::Cipher::Cipher.new(ALGORITHM)
+ encryptor = OpenSSL::Cipher.new(algorithm)
encryptor.encrypt
+ # We must set key before iv: https://bugs.ruby-lang.org/issues/8221
+ encryptor.key = Digest::SHA256.digest(key)
@iv ||= encryptor.random_iv
encryptor.iv = @iv
- encryptor.key = Digest::SHA256.digest(key)
encryptor
end
end
@@ -125,18 +137,77 @@ class Chef::EncryptedDataBagItem
"hmac" => hmac,
"iv" => Base64.encode64(iv),
"version" => 2,
- "cipher" => ALGORITHM
+ "cipher" => algorithm
}
end
# Generates an HMAC-SHA2-256 of the encrypted data (encrypt-then-mac)
def hmac
@hmac ||= begin
- digest = OpenSSL::Digest::Digest.new("sha256")
+ digest = OpenSSL::Digest.new("sha256")
raw_hmac = OpenSSL::HMAC.digest(digest, key, encrypted_data)
Base64.encode64(raw_hmac)
end
end
end
+
+ class Version3Encryptor < Version1Encryptor
+ include Chef::EncryptedDataBagItem::Assertions
+
+ def initialize(plaintext_data, key, iv=nil)
+ super
+ assert_aead_requirements_met!(algorithm)
+ @auth_tag = nil
+ end
+
+ # Returns a wrapped and encrypted version of +plaintext_data+ suitable for
+ # using as the value in an encrypted data bag item.
+ def for_encrypted_item
+ {
+ "encrypted_data" => encrypted_data,
+ "iv" => Base64.encode64(iv),
+ "auth_tag" => Base64.encode64(auth_tag),
+ "version" => 3,
+ "cipher" => algorithm
+ }
+ end
+
+ # Returns the used encryption algorithm
+ def algorithm
+ AEAD_ALGORITHM
+ end
+
+ # Returns a wrapped and encrypted version of +plaintext_data+ suitable for
+ # Returns the auth_tag.
+ def auth_tag
+ # Generated auth_tag comes from OpenSSL::Cipher#auth_tag
+ # This must be generated after the data is encrypted
+ if @auth_tag.nil?
+ raise EncryptionFailure, "Internal Error: GCM authentication tag read before encryption"
+ end
+ @auth_tag
+ end
+
+ # Generates (and memoizes) an OpenSSL::Cipher object and configures
+ # it for the specified iv and encryption key using AEAD
+ def openssl_encryptor
+ @openssl_encryptor ||= begin
+ encryptor = super
+ encryptor.auth_data = ''
+ encryptor
+ end
+ end
+
+ # Encrypts, Base64 encodes +serialized_data+ and gets the authentication tag
+ def encrypted_data
+ @encrypted_data ||= begin
+ enc_data_b64 = super
+ @auth_tag = openssl_encryptor.auth_tag
+ enc_data_b64
+ end
+ end
+
+ end
+
end
end
diff --git a/lib/chef/exceptions.rb b/lib/chef/exceptions.rb
index e3c7d630ce..26d9f612f1 100644
--- a/lib/chef/exceptions.rb
+++ b/lib/chef/exceptions.rb
@@ -115,6 +115,7 @@ class Chef
class Win32ArchitectureIncorrect < RuntimeError; end
class ObsoleteDependencySyntax < ArgumentError; end
class InvalidDataBagPath < ArgumentError; end
+ class DuplicateDataBagItem < RuntimeError; end
# A different version of a cookbook was added to a
# VersionedRecipeList than the one already there.
diff --git a/lib/chef/formatters/base.rb b/lib/chef/formatters/base.rb
index 636ba9c83f..c901068aa0 100644
--- a/lib/chef/formatters/base.rb
+++ b/lib/chef/formatters/base.rb
@@ -93,6 +93,13 @@ class Chef
def indent_by(amount)
@output.indent += amount
+ if @output.indent < 0
+ # This is left commented out for now. We need to uncomment it and fix at least one bug in
+ # the formatter, and then leave this line uncommented in the future.
+ #Chef::Log.warn "Internal Formatter Error -- Attempt to indent by negative number of spaces"
+ @output.indent = 0
+ end
+ @output.indent
end
# Input: a Formatters::ErrorDescription object.
diff --git a/lib/chef/http/json_input.rb b/lib/chef/http/json_input.rb
index 1e4e736030..23ccc3a8a7 100644
--- a/lib/chef/http/json_input.rb
+++ b/lib/chef/http/json_input.rb
@@ -29,7 +29,8 @@ class Chef
end
def handle_request(method, url, headers={}, data=false)
- if data
+ if data && should_encode_as_json?(headers)
+ headers.delete_if { |key, _value| key.downcase == 'content-type' }
headers["Content-Type"] = 'application/json'
data = Chef::JSONCompat.to_json(data)
# Force encoding to binary to fix SSL related EOFErrors
@@ -52,6 +53,16 @@ class Chef
[http_response, rest_request, return_value]
end
+ private
+
+ def should_encode_as_json?(headers)
+ # ruby/Net::HTTP don't enforce capitalized headers (it normalizes them
+ # for you before sending the request), so we have to account for all
+ # the variations we might find
+ requested_content_type = headers.find {|k, v| k.downcase == "content-type" }
+ requested_content_type.nil? || requested_content_type.last.include?("json")
+ end
+
end
end
end
diff --git a/lib/chef/knife/client_delete.rb b/lib/chef/knife/client_delete.rb
index 1902145c8d..d7d302ee1d 100644
--- a/lib/chef/knife/client_delete.rb
+++ b/lib/chef/knife/client_delete.rb
@@ -47,7 +47,7 @@ class Chef
object = Chef::ApiClient.load(@client_name)
if object.validator
unless config[:delete_validators]
- ui.fatal("You must specify --force to delete the validator client #{@client_name}")
+ ui.fatal("You must specify --delete-validators to delete the validator client #{@client_name}")
exit 2
end
end
diff --git a/lib/chef/knife/cookbook_site_share.rb b/lib/chef/knife/cookbook_site_share.rb
index 4dcce42d7f..330f3cb229 100644
--- a/lib/chef/knife/cookbook_site_share.rb
+++ b/lib/chef/knife/cookbook_site_share.rb
@@ -54,7 +54,7 @@ class Chef
cl = Chef::CookbookLoader.new(config[:cookbook_path])
if cl.cookbook_exists?(cookbook_name)
cookbook = cl[cookbook_name]
- Chef::CookbookUploader.new(cookbook,config[:cookbook_path]).validate_cookbooks
+ Chef::CookbookUploader.new(cookbook).validate_cookbooks
tmp_cookbook_dir = Chef::CookbookSiteStreamingUploader.create_build_dir(cookbook)
begin
Chef::Log.debug("Temp cookbook directory is #{tmp_cookbook_dir.inspect}")
diff --git a/lib/chef/knife/cookbook_upload.rb b/lib/chef/knife/cookbook_upload.rb
index 9d6e0d438d..f5002be3a7 100644
--- a/lib/chef/knife/cookbook_upload.rb
+++ b/lib/chef/knife/cookbook_upload.rb
@@ -184,7 +184,7 @@ class Chef
def cookbook_repo
@cookbook_loader ||= begin
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, config[:cookbook_path]) }
+ Chef::Cookbook::FileVendor.fetch_from_disk(config[:cookbook_path])
Chef::CookbookLoader.new(config[:cookbook_path])
end
end
@@ -240,7 +240,7 @@ WARNING
check_for_broken_links!(cb)
check_for_dependencies!(cb)
end
- Chef::CookbookUploader.new(cookbooks, config[:cookbook_path], :force => config[:force], :concurrency => config[:concurrency]).upload_cookbooks
+ Chef::CookbookUploader.new(cookbooks, :force => config[:force], :concurrency => config[:concurrency]).upload_cookbooks
rescue Chef::Exceptions::CookbookFrozen => e
ui.error e
raise
diff --git a/lib/chef/mixin/shell_out.rb b/lib/chef/mixin/shell_out.rb
index 97aa7041fd..3f80290f90 100644
--- a/lib/chef/mixin/shell_out.rb
+++ b/lib/chef/mixin/shell_out.rb
@@ -33,7 +33,7 @@ class Chef
def shell_out(*command_args)
cmd = Mixlib::ShellOut.new(*run_command_compatible_options(command_args))
- cmd.live_stream = io_for_live_stream
+ cmd.live_stream ||= io_for_live_stream
cmd.run_command
cmd
end
diff --git a/lib/chef/platform/provider_mapping.rb b/lib/chef/platform/provider_mapping.rb
index ebcc8c2fe3..d61298e182 100644
--- a/lib/chef/platform/provider_mapping.rb
+++ b/lib/chef/platform/provider_mapping.rb
@@ -142,11 +142,14 @@ class Chef
},
:centos => {
:default => {
- :service => Chef::Provider::Service::Redhat,
+ :service => Chef::Provider::Service::Systemd,
:cron => Chef::Provider::Cron,
:package => Chef::Provider::Package::Yum,
:mdadm => Chef::Provider::Mdadm,
:ifconfig => Chef::Provider::Ifconfig::Redhat
+ },
+ "< 7" => {
+ :service => Chef::Provider::Service::Redhat
}
},
:amazon => {
@@ -159,19 +162,25 @@ class Chef
},
:scientific => {
:default => {
- :service => Chef::Provider::Service::Redhat,
+ :service => Chef::Provider::Service::Systemd,
:cron => Chef::Provider::Cron,
:package => Chef::Provider::Package::Yum,
:mdadm => Chef::Provider::Mdadm
+ },
+ "< 7" => {
+ :service => Chef::Provider::Service::Redhat
}
},
:fedora => {
:default => {
- :service => Chef::Provider::Service::Redhat,
+ :service => Chef::Provider::Service::Systemd,
:cron => Chef::Provider::Cron,
:package => Chef::Provider::Package::Yum,
:mdadm => Chef::Provider::Mdadm,
:ifconfig => Chef::Provider::Ifconfig::Redhat
+ },
+ "< 15" => {
+ :service => Chef::Provider::Service::Redhat
}
},
:opensuse => {
@@ -196,19 +205,25 @@ class Chef
},
:oracle => {
:default => {
- :service => Chef::Provider::Service::Redhat,
+ :service => Chef::Provider::Service::Systemd,
:cron => Chef::Provider::Cron,
:package => Chef::Provider::Package::Yum,
:mdadm => Chef::Provider::Mdadm
+ },
+ "< 7" => {
+ :service => Chef::Provider::Service::Redhat
}
},
:redhat => {
:default => {
- :service => Chef::Provider::Service::Redhat,
+ :service => Chef::Provider::Service::Systemd,
:cron => Chef::Provider::Cron,
:package => Chef::Provider::Package::Yum,
:mdadm => Chef::Provider::Mdadm,
:ifconfig => Chef::Provider::Ifconfig::Redhat
+ },
+ "< 7" => {
+ :service => Chef::Provider::Service::Systemd
}
},
:ibm_powerkvm => {
@@ -229,6 +244,15 @@ class Chef
:ifconfig => Chef::Provider::Ifconfig::Redhat
}
},
+ :parallels => {
+ :default => {
+ :service => Chef::Provider::Service::Redhat,
+ :cron => Chef::Provider::Cron,
+ :package => Chef::Provider::Package::Yum,
+ :mdadm => Chef::Provider::Mdadm,
+ :ifconfig => Chef::Provider::Ifconfig::Redhat
+ }
+ },
:gentoo => {
:default => {
:package => Chef::Provider::Package::Portage,
@@ -365,7 +389,8 @@ class Chef
:mount => Chef::Provider::Mount::Aix,
:ifconfig => Chef::Provider::Ifconfig::Aix,
:cron => Chef::Provider::Cron::Aix,
- :package => Chef::Provider::Package::Aix
+ :package => Chef::Provider::Package::Aix,
+ :user => Chef::Provider::User::Aix
}
},
:exherbo => {
@@ -523,6 +548,8 @@ class Chef
if platforms.has_key?(args[:platform])
if platforms[args[:platform]].has_key?(:default)
platforms[args[:platform]][:default][args[:resource].to_sym] = args[:provider]
+ elsif args[:platform] == :default
+ platforms[:default][args[:resource].to_sym] = args[:provider]
else
platforms[args[:platform]] = { :default => { args[:resource].to_sym => args[:provider] } }
end
diff --git a/lib/chef/policy_builder/expand_node_object.rb b/lib/chef/policy_builder/expand_node_object.rb
index 63964a2a0d..2ee8a23258 100644
--- a/lib/chef/policy_builder/expand_node_object.rb
+++ b/lib/chef/policy_builder/expand_node_object.rb
@@ -56,13 +56,13 @@ class Chef
def setup_run_context(specific_recipes=nil)
if Chef::Config[:solo]
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, Chef::Config[:cookbook_path]) }
+ Chef::Cookbook::FileVendor.fetch_from_disk(Chef::Config[:cookbook_path])
cl = Chef::CookbookLoader.new(Chef::Config[:cookbook_path])
cl.load_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cl)
run_context = Chef::RunContext.new(node, cookbook_collection, @events)
else
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::RemoteFileVendor.new(manifest, api_service) }
+ Chef::Cookbook::FileVendor.fetch_from_remote(api_service)
cookbook_hash = sync_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cookbook_hash)
run_context = Chef::RunContext.new(node, cookbook_collection, @events)
diff --git a/lib/chef/policy_builder/policyfile.rb b/lib/chef/policy_builder/policyfile.rb
index 4baa6340d4..0df3dd5dd2 100644
--- a/lib/chef/policy_builder/policyfile.rb
+++ b/lib/chef/policy_builder/policyfile.rb
@@ -154,10 +154,7 @@ class Chef
end
def setup_run_context(specific_recipes=nil)
- # TODO: This file vendor stuff is duplicated and initializing it with a
- # block traps a reference to this object in a global context which will
- # prevent it from getting GC'd. Simplify it.
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::RemoteFileVendor.new(manifest, api_service) }
+ Chef::Cookbook::FileVendor.fetch_from_remote(http_api)
sync_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cookbooks_to_sync)
run_context = Chef::RunContext.new(node, cookbook_collection, events)
diff --git a/lib/chef/provider.rb b/lib/chef/provider.rb
index 90b6ead716..db7629dbcb 100644
--- a/lib/chef/provider.rb
+++ b/lib/chef/provider.rb
@@ -22,11 +22,13 @@ require 'chef/mixin/convert_to_class_name'
require 'chef/dsl/recipe'
require 'chef/mixin/enforce_ownership_and_permissions'
require 'chef/mixin/why_run'
+require 'chef/mixin/shell_out'
class Chef
class Provider
include Chef::DSL::Recipe
include Chef::Mixin::WhyRun
+ include Chef::Mixin::ShellOut
attr_accessor :new_resource
attr_accessor :current_resource
diff --git a/lib/chef/provider/cookbook_file.rb b/lib/chef/provider/cookbook_file.rb
index 18af70d415..26d6ebf1d9 100644
--- a/lib/chef/provider/cookbook_file.rb
+++ b/lib/chef/provider/cookbook_file.rb
@@ -49,4 +49,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/provider/deploy.rb b/lib/chef/provider/deploy.rb
index 516aee6159..426e69644e 100644
--- a/lib/chef/provider/deploy.rb
+++ b/lib/chef/provider/deploy.rb
@@ -21,7 +21,7 @@ require "chef/mixin/from_file"
require "chef/monkey_patches/fileutils"
require "chef/provider/git"
require "chef/provider/subversion"
-require 'chef/dsl/recipe'
+require "chef/dsl/recipe"
class Chef
class Provider
@@ -31,7 +31,7 @@ class Chef
include Chef::Mixin::FromFile
include Chef::Mixin::Command
- attr_reader :scm_provider, :release_path, :previous_release_path
+ attr_reader :scm_provider, :release_path, :shared_path, :previous_release_path
def initialize(new_resource, run_context)
super(new_resource, run_context)
@@ -53,6 +53,7 @@ class Chef
def load_current_resource
@scm_provider.load_current_resource
@release_path = @new_resource.deploy_to + "/releases/#{release_slug}"
+ @shared_path = @new_resource.shared_path
end
def sudo(command,&block)
@@ -174,7 +175,6 @@ class Chef
restart
end
-
def callback(what, callback_code=nil)
@collection = Chef::ResourceCollection.new
case callback_code
diff --git a/lib/chef/provider/env.rb b/lib/chef/provider/env.rb
index e857d74d68..e91b8bbb97 100644
--- a/lib/chef/provider/env.rb
+++ b/lib/chef/provider/env.rb
@@ -143,7 +143,7 @@ class Chef
def modify_env
if @new_resource.delim
#e.g. add to PATH
- @new_resource.value << @new_resource.delim << @current_resource.value
+ @new_resource.value(@new_resource.value + @new_resource.delim + @current_resource.value)
end
create_env
end
diff --git a/lib/chef/provider/execute.rb b/lib/chef/provider/execute.rb
index 2907688e88..d469bea769 100644
--- a/lib/chef/provider/execute.rb
+++ b/lib/chef/provider/execute.rb
@@ -16,7 +16,6 @@
# limitations under the License.
#
-require 'chef/mixin/shell_out'
require 'chef/log'
require 'chef/provider'
@@ -24,8 +23,6 @@ class Chef
class Provider
class Execute < Chef::Provider
- include Chef::Mixin::ShellOut
-
def load_current_resource
true
end
diff --git a/lib/chef/provider/file.rb b/lib/chef/provider/file.rb
index e7c5ca856f..256248f240 100644
--- a/lib/chef/provider/file.rb
+++ b/lib/chef/provider/file.rb
@@ -25,7 +25,6 @@ require 'etc'
require 'fileutils'
require 'chef/scan_access_control'
require 'chef/mixin/checksum'
-require 'chef/mixin/shell_out'
require 'chef/mixin/file_class'
require 'chef/util/backup'
require 'chef/util/diff'
@@ -48,7 +47,6 @@ class Chef
class File < Chef::Provider
include Chef::Mixin::EnforceOwnershipAndPermissions
include Chef::Mixin::Checksum
- include Chef::Mixin::ShellOut
include Chef::Util::Selinux
include Chef::Mixin::FileClass
@@ -278,7 +276,6 @@ class Chef
"Assuming symlink source would be created by a previous resource" ]
end
-
def content
@content ||= begin
load_current_resource if @current_resource.nil?
diff --git a/lib/chef/provider/git.rb b/lib/chef/provider/git.rb
index 3999edc16a..525249a726 100644
--- a/lib/chef/provider/git.rb
+++ b/lib/chef/provider/git.rb
@@ -16,19 +16,15 @@
# limitations under the License.
#
-
require 'chef/exceptions'
require 'chef/log'
require 'chef/provider'
-require 'chef/mixin/shell_out'
require 'fileutils'
class Chef
class Provider
class Git < Chef::Provider
- include Chef::Mixin::ShellOut
-
def whyrun_supported?
true
end
@@ -51,7 +47,6 @@ class Chef
"Cannot clone #{@new_resource} to #{@new_resource.destination}, the enclosing directory #{dirname} does not exist")
end
-
requirements.assert(:all_actions) do |a|
a.assertion { !(@new_resource.revision =~ /^origin\//) }
a.failure_message Chef::Exceptions::InvalidRemoteGitReference,
@@ -107,7 +102,6 @@ class Chef
end
end
-
def existing_git_clone?
::File.exist?(::File.join(@new_resource.destination, ".git"))
end
@@ -156,7 +150,7 @@ class Chef
converge_by("checkout ref #{sha_ref} branch #{@new_resource.revision}") do
# checkout into a local branch rather than a detached HEAD
- shell_out!("git checkout -b #{@new_resource.checkout_branch} #{sha_ref}", run_options(:cwd => @new_resource.destination))
+ shell_out!("git checkout -B #{@new_resource.checkout_branch} #{sha_ref}", run_options(:cwd => @new_resource.destination))
Chef::Log.info "#{@new_resource} checked out branch: #{@new_resource.revision} onto: #{@new_resource.checkout_branch} reference: #{sha_ref}"
end
end
diff --git a/lib/chef/provider/group/aix.rb b/lib/chef/provider/group/aix.rb
index 9dedef351a..6ac9d03357 100644
--- a/lib/chef/provider/group/aix.rb
+++ b/lib/chef/provider/group/aix.rb
@@ -16,16 +16,18 @@
# limitations under the License.
#
-require 'chef/provider/group/usermod'
+require 'chef/provider/group/groupadd'
+require 'chef/mixin/shell_out'
class Chef
class Provider
class Group
- class Aix < Chef::Provider::Group::Usermod
+ class Aix < Chef::Provider::Group::Groupadd
def required_binaries
[ "/usr/bin/mkgroup",
"/usr/bin/chgroup",
+ "/usr/bin/chgrpmem",
"/usr/sbin/rmgroup" ]
end
@@ -51,6 +53,19 @@ class Chef
run_command(:command => "rmgroup #{@new_resource.group_name}")
end
+ def add_member(member)
+ shell_out!("chgrpmem -m + #{member} #{@new_resource.group_name}")
+ end
+
+ def set_members(members)
+ return if members.empty?
+ shell_out!("chgrpmem -m = #{members.join(',')} #{@new_resource.group_name}")
+ end
+
+ def remove_member(member)
+ shell_out!("chgrpmem -m - #{member} #{@new_resource.group_name}")
+ end
+
def set_options
opts = ""
{ :gid => "id" }.sort { |a,b| a[0] <=> b[0] }.each do |field, option|
diff --git a/lib/chef/provider/group/dscl.rb b/lib/chef/provider/group/dscl.rb
index c204c09321..04ca9bc929 100644
--- a/lib/chef/provider/group/dscl.rb
+++ b/lib/chef/provider/group/dscl.rb
@@ -39,11 +39,33 @@ class Chef
return result[2]
end
- # This is handled in providers/group.rb by Etc.getgrnam()
- # def group_exists?(group)
- # groups = safe_dscl("list /Groups")
- # !! ( groups =~ Regexp.new("\n#{group}\n") )
- # end
+ def load_current_resource
+ @current_resource = Chef::Resource::Group.new(@new_resource.name)
+ @current_resource.group_name(@new_resource.name)
+ group_info = nil
+ begin
+ group_info = safe_dscl("read /Groups/#{@new_resource.name}")
+ rescue Chef::Exceptions::Group
+ @group_exists = false
+ Chef::Log.debug("#{@new_resource} group does not exist")
+ end
+
+ if group_info
+ group_info.each_line do |line|
+ key, val = line.split(': ')
+ val.strip! if val
+ case key.downcase
+ when 'primarygroupid'
+ @new_resource.gid(val) unless @new_resource.gid
+ @current_resource.gid(val)
+ when 'groupmembership'
+ @current_resource.members(val.split(' '))
+ end
+ end
+ end
+
+ @current_resource
+ end
# get a free GID greater than 200
def get_free_gid(search_limit=1000)
@@ -115,10 +137,6 @@ class Chef
end
end
- def load_current_resource
- super
- end
-
def create_group
dscl_create_group
set_gid
diff --git a/lib/chef/provider/group/gpasswd.rb b/lib/chef/provider/group/gpasswd.rb
index a65a7ffd53..521affac11 100644
--- a/lib/chef/provider/group/gpasswd.rb
+++ b/lib/chef/provider/group/gpasswd.rb
@@ -17,15 +17,12 @@
#
require 'chef/provider/group/groupadd'
-require 'chef/mixin/shell_out'
class Chef
class Provider
class Group
class Gpasswd < Chef::Provider::Group::Groupadd
- include Chef::Mixin::ShellOut
-
def load_current_resource
super
end
diff --git a/lib/chef/provider/group/groupmod.rb b/lib/chef/provider/group/groupmod.rb
index c8b6458db0..7ad762af8d 100644
--- a/lib/chef/provider/group/groupmod.rb
+++ b/lib/chef/provider/group/groupmod.rb
@@ -16,15 +16,11 @@
# limitations under the License.
#
-require 'chef/mixin/shell_out'
-
class Chef
class Provider
class Group
class Groupmod < Chef::Provider::Group
- include Chef::Mixin::ShellOut
-
def load_current_resource
super
[ "group", "user" ].each do |binary|
diff --git a/lib/chef/provider/group/suse.rb b/lib/chef/provider/group/suse.rb
index 14380f1705..7ac2831d02 100644
--- a/lib/chef/provider/group/suse.rb
+++ b/lib/chef/provider/group/suse.rb
@@ -17,15 +17,12 @@
#
require 'chef/provider/group/groupadd'
-require 'chef/mixin/shell_out'
class Chef
class Provider
class Group
class Suse < Chef::Provider::Group::Groupadd
- include Chef::Mixin::ShellOut
-
def load_current_resource
super
end
diff --git a/lib/chef/provider/group/usermod.rb b/lib/chef/provider/group/usermod.rb
index e6f3fc9e0f..e9dcc38b43 100644
--- a/lib/chef/provider/group/usermod.rb
+++ b/lib/chef/provider/group/usermod.rb
@@ -17,15 +17,12 @@
#
require 'chef/provider/group/groupadd'
-require 'chef/mixin/shell_out'
class Chef
class Provider
class Group
class Usermod < Chef::Provider::Group::Groupadd
- include Chef::Mixin::ShellOut
-
def load_current_resource
super
end
diff --git a/lib/chef/provider/http_request.rb b/lib/chef/provider/http_request.rb
index 2bbd20aa2c..ba54b10195 100644
--- a/lib/chef/provider/http_request.rb
+++ b/lib/chef/provider/http_request.rb
@@ -33,13 +33,13 @@ class Chef
@http = Chef::HTTP::Simple.new(@new_resource.url)
end
- # Send a HEAD request to @new_resource.url, with ?message=@new_resource.message
+ # Send a HEAD request to @new_resource.url
def action_head
message = check_message(@new_resource.message)
# CHEF-4762: we expect a nil return value from Chef::HTTP for a "200 Success" response
# and false for a "304 Not Modified" response
modified = @http.head(
- "#{@new_resource.url}?message=#{message}",
+ "#{@new_resource.url}",
@new_resource.headers
)
Chef::Log.info("#{@new_resource} HEAD to #{@new_resource.url} successful")
@@ -50,13 +50,13 @@ class Chef
end
end
- # Send a GET request to @new_resource.url, with ?message=@new_resource.message
+ # Send a GET request to @new_resource.url
def action_get
converge_by("#{@new_resource} GET to #{@new_resource.url}") do
message = check_message(@new_resource.message)
body = @http.get(
- "#{@new_resource.url}?message=#{message}",
+ "#{@new_resource.url}",
@new_resource.headers
)
Chef::Log.info("#{@new_resource} GET to #{@new_resource.url} successful")
diff --git a/lib/chef/provider/link.rb b/lib/chef/provider/link.rb
index c41fbcad95..d6602c2e03 100644
--- a/lib/chef/provider/link.rb
+++ b/lib/chef/provider/link.rb
@@ -18,7 +18,6 @@
require 'chef/config'
require 'chef/log'
-require 'chef/mixin/shell_out'
require 'chef/mixin/file_class'
require 'chef/resource/link'
require 'chef/provider'
@@ -29,7 +28,6 @@ class Chef
class Link < Chef::Provider
include Chef::Mixin::EnforceOwnershipAndPermissions
- include Chef::Mixin::ShellOut
include Chef::Mixin::FileClass
def negative_complement(big)
diff --git a/lib/chef/provider/log.rb b/lib/chef/provider/log.rb
index e65f01e69a..9379ceeefa 100644
--- a/lib/chef/provider/log.rb
+++ b/lib/chef/provider/log.rb
@@ -25,8 +25,9 @@ class Chef
# Chef log provider, allows logging to chef's logs from recipes
class ChefLog < Chef::Provider
- # ordered array of the log levels
- @@levels = [ :debug, :info, :warn, :error, :fatal ]
+ def whyrun_supported?
+ true
+ end
# No concept of a 'current' resource for logs, this is a no-op
#
@@ -42,18 +43,7 @@ class Chef
# true:: Always return true
def action_write
Chef::Log.send(@new_resource.level, @new_resource.message)
-
- # resolve the integers for the current log levels
- global_level = Mixlib::Log::LEVELS.fetch(Chef::Log.level)
- resource_level = Mixlib::Log::LEVELS.fetch(@new_resource.level)
-
- # If the resource level is greater than or the same os the global
- # level, then it should have been written to the log. Mark the
- # resource as updated.
- if resource_level >= global_level
- @new_resource.updated_by_last_action(true)
- end
-
+ @new_resource.updated_by_last_action(true)
end
end
@@ -63,6 +53,3 @@ class Chef
end
end
-
-
-
diff --git a/lib/chef/provider/mdadm.rb b/lib/chef/provider/mdadm.rb
index 51c9b8d3c6..d156e49d48 100644
--- a/lib/chef/provider/mdadm.rb
+++ b/lib/chef/provider/mdadm.rb
@@ -17,15 +17,12 @@
#
require 'chef/log'
-require 'chef/mixin/shell_out'
require 'chef/provider'
class Chef
class Provider
class Mdadm < Chef::Provider
- include Chef::Mixin::ShellOut
-
def popen4
raise Exception, "deprecated"
end
diff --git a/lib/chef/provider/mount/mount.rb b/lib/chef/provider/mount/mount.rb
index 22d61a9236..207b0cde6c 100644
--- a/lib/chef/provider/mount/mount.rb
+++ b/lib/chef/provider/mount/mount.rb
@@ -18,13 +18,11 @@
require 'chef/provider/mount'
require 'chef/log'
-require 'chef/mixin/shell_out'
class Chef
class Provider
class Mount
class Mount < Chef::Provider::Mount
- include Chef::Mixin::ShellOut
def initialize(new_resource, run_context)
super
@@ -87,7 +85,7 @@ class Chef
shell_out!("mount").stdout.each_line do |line|
case line
- when /^#{device_mount_regex}\s+on\s+#{Regexp.escape(real_mount_point)}/
+ when /^#{device_mount_regex}\s+on\s+#{Regexp.escape(real_mount_point)}\s/
mounted = true
Chef::Log.debug("Special device #{device_logstring} mounted as #{real_mount_point}")
when /^([\/\w])+\son\s#{Regexp.escape(real_mount_point)}\s+/
@@ -169,7 +167,7 @@ class Chef
found = false
::File.readlines("/etc/fstab").reverse_each do |line|
- if !found && line =~ /^#{device_fstab_regex}\s+#{Regexp.escape(@new_resource.mount_point)}/
+ if !found && line =~ /^#{device_fstab_regex}\s+#{Regexp.escape(@new_resource.mount_point)}\s/
found = true
Chef::Log.debug("#{@new_resource} is removed from fstab")
next
diff --git a/lib/chef/provider/mount/solaris.rb b/lib/chef/provider/mount/solaris.rb
index 85158eb564..462fa32b71 100644
--- a/lib/chef/provider/mount/solaris.rb
+++ b/lib/chef/provider/mount/solaris.rb
@@ -20,14 +20,12 @@
require 'chef/provider/mount'
require 'chef/log'
-require 'chef/mixin/shell_out'
require 'forwardable'
class Chef
class Provider
class Mount
class Solaris < Chef::Provider::Mount
- include Chef::Mixin::ShellOut
extend Forwardable
VFSTAB = "/etc/vfstab".freeze
diff --git a/lib/chef/provider/package.rb b/lib/chef/provider/package.rb
index adae880b7f..a4a056dfec 100644
--- a/lib/chef/provider/package.rb
+++ b/lib/chef/provider/package.rb
@@ -198,7 +198,6 @@ class Chef
Chef::Log.debug("#{@new_resource} fetching preseed file to #{cache_seed_to}")
-
if template_available?(@new_resource.response_file)
Chef::Log.debug("#{@new_resource} fetching preseed file via Template")
remote_file = Chef::Resource::Template.new(cache_seed_to, run_context)
diff --git a/lib/chef/provider/package/apt.rb b/lib/chef/provider/package/apt.rb
index 76d90a5a97..0d91d0d1f0 100644
--- a/lib/chef/provider/package/apt.rb
+++ b/lib/chef/provider/package/apt.rb
@@ -19,15 +19,12 @@
require 'chef/provider/package'
require 'chef/mixin/command'
require 'chef/resource/package'
-require 'chef/mixin/shell_out'
-
class Chef
class Provider
class Package
class Apt < Chef::Provider::Package
- include Chef::Mixin::ShellOut
attr_accessor :is_virtual_package
def load_current_resource
diff --git a/lib/chef/provider/package/easy_install.rb b/lib/chef/provider/package/easy_install.rb
index 6c9dacc55d..2af8a72e61 100644
--- a/lib/chef/provider/package/easy_install.rb
+++ b/lib/chef/provider/package/easy_install.rb
@@ -18,17 +18,13 @@
require 'chef/provider/package'
require 'chef/mixin/command'
-require 'chef/mixin/shell_out'
require 'chef/resource/package'
-require 'chef/mixin/shell_out'
class Chef
class Provider
class Package
class EasyInstall < Chef::Provider::Package
- include Chef::Mixin::ShellOut
-
def install_check(name)
check = false
diff --git a/lib/chef/provider/package/freebsd/base.rb b/lib/chef/provider/package/freebsd/base.rb
index 24f79484f0..b0f05667ff 100644
--- a/lib/chef/provider/package/freebsd/base.rb
+++ b/lib/chef/provider/package/freebsd/base.rb
@@ -21,7 +21,6 @@
require 'chef/resource/package'
require 'chef/provider/package'
-require 'chef/mixin/shell_out'
require 'chef/mixin/get_source_from_package'
class Chef
@@ -63,9 +62,7 @@ class Chef
end
end
-
class Base < Chef::Provider::Package
- include Chef::Mixin::ShellOut
include Chef::Mixin::GetSourceFromPackage
def initialize(*args)
diff --git a/lib/chef/provider/package/freebsd/pkgng.rb b/lib/chef/provider/package/freebsd/pkgng.rb
index da531facc1..0741a4d95f 100644
--- a/lib/chef/provider/package/freebsd/pkgng.rb
+++ b/lib/chef/provider/package/freebsd/pkgng.rb
@@ -52,8 +52,6 @@ class Chef
@new_resource.source ? file_candidate_version : repo_candidate_version
end
-
-
private
def file_candidate_version
diff --git a/lib/chef/provider/package/freebsd/port.rb b/lib/chef/provider/package/freebsd/port.rb
index 6f4471a6f7..4b3510f0e9 100644
--- a/lib/chef/provider/package/freebsd/port.rb
+++ b/lib/chef/provider/package/freebsd/port.rb
@@ -54,8 +54,6 @@ class Chef
super(@new_resource.package_name)
end
-
-
private
def supports_pkgng?
diff --git a/lib/chef/provider/package/ips.rb b/lib/chef/provider/package/ips.rb
index 2c6d98d81a..fed3e34124 100644
--- a/lib/chef/provider/package/ips.rb
+++ b/lib/chef/provider/package/ips.rb
@@ -21,14 +21,12 @@ require 'open3'
require 'chef/provider/package'
require 'chef/mixin/command'
require 'chef/resource/package'
-require 'chef/mixin/shell_out'
class Chef
class Provider
class Package
class Ips < Chef::Provider::Package
- include Chef::Mixin::ShellOut
attr_accessor :virtual
def define_resource_requirements
@@ -98,4 +96,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/provider/package/paludis.rb b/lib/chef/provider/package/paludis.rb
index e304cd3b8e..7c5245fc97 100644
--- a/lib/chef/provider/package/paludis.rb
+++ b/lib/chef/provider/package/paludis.rb
@@ -18,15 +18,12 @@
require 'chef/provider/package'
require 'chef/resource/package'
-require 'chef/mixin/shell_out'
class Chef
class Provider
class Package
class Paludis < Chef::Provider::Package
- include Chef::Mixin::ShellOut
-
def load_current_resource
@current_resource = Chef::Resource::Package.new(@new_resource.package_name)
@current_resource.package_name(@new_resource.package_name)
@@ -37,7 +34,7 @@ class Chef
installed = false
re = Regexp.new('(.*)[[:blank:]](.*)[[:blank:]](.*)$')
- shell_out!("cave -L warning print-ids -m \"*/#{@new_resource.package_name.split('/').last}\" -f \"%c/%p %v %r\n\"").stdout.each_line do |line|
+ shell_out!("cave -L warning print-ids -M none -m \"*/#{@new_resource.package_name.split('/').last}\" -f \"%c/%p %v %r\n\"").stdout.each_line do |line|
res = re.match(line)
unless res.nil?
case res[3]
@@ -62,7 +59,7 @@ class Chef
else
pkg = "#{@new_resource.package_name}"
end
- shell_out!("cave -L warning resolve -x#{expand_options(@new_resource.options)} \"#{pkg}\"")
+ shell_out!("cave -L warning resolve -x#{expand_options(@new_resource.options)} \"#{pkg}\"",:timeout => @new_resource.timeout)
end
def upgrade_package(name, version)
@@ -87,5 +84,3 @@ class Chef
end
end
end
-
-
diff --git a/lib/chef/provider/package/portage.rb b/lib/chef/provider/package/portage.rb
index ea8e37e5d4..6a3587558a 100644
--- a/lib/chef/provider/package/portage.rb
+++ b/lib/chef/provider/package/portage.rb
@@ -55,7 +55,6 @@ class Chef
@current_resource
end
-
def parse_emerge(package, txt)
availables = {}
found_package_name = nil
@@ -103,7 +102,6 @@ class Chef
end
-
def install_package(name, version)
pkg = "=#{name}-#{version}"
diff --git a/lib/chef/provider/package/rpm.rb b/lib/chef/provider/package/rpm.rb
index 74baddb062..bbb561bd15 100644
--- a/lib/chef/provider/package/rpm.rb
+++ b/lib/chef/provider/package/rpm.rb
@@ -60,7 +60,7 @@ class Chef
status = popen4("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@new_resource.source}") do |pid, stdin, stdout, stderr|
stdout.each do |line|
case line
- when /([\w\d+_.-]+)\s([\w\d_.-]+)/
+ when /^([\w\d+_.-]+)\s([\w\d_.-]+)$/
@current_resource.package_name($1)
@new_resource.version($2)
@candidate_version = $2
@@ -78,14 +78,13 @@ class Chef
@rpm_status = popen4("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@current_resource.package_name}") do |pid, stdin, stdout, stderr|
stdout.each do |line|
case line
- when /([\w\d+_.-]+)\s([\w\d_.-]+)/
+ when /^([\w\d+_.-]+)\s([\w\d_.-]+)$/
Chef::Log.debug("#{@new_resource} current version is #{$2}")
@current_resource.version($2)
end
end
end
-
@current_resource
end
@@ -119,4 +118,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/provider/package/rubygems.rb b/lib/chef/provider/package/rubygems.rb
index b423c199a0..be0022f4aa 100644
--- a/lib/chef/provider/package/rubygems.rb
+++ b/lib/chef/provider/package/rubygems.rb
@@ -352,8 +352,6 @@ class Chef
end
- include Chef::Mixin::ShellOut
-
attr_reader :gem_env
attr_reader :cleanup_gem_env
diff --git a/lib/chef/provider/package/smartos.rb b/lib/chef/provider/package/smartos.rb
index 28d56ddc2c..19a6b9efef 100644
--- a/lib/chef/provider/package/smartos.rb
+++ b/lib/chef/provider/package/smartos.rb
@@ -20,7 +20,6 @@
#
require 'chef/provider/package'
-require 'chef/mixin/shell_out'
require 'chef/resource/package'
require 'chef/mixin/get_source_from_package'
@@ -28,10 +27,8 @@ class Chef
class Provider
class Package
class SmartOS < Chef::Provider::Package
- include Chef::Mixin::ShellOut
attr_accessor :is_virtual_package
-
def load_current_resource
Chef::Log.debug("#{@new_resource} loading current resource")
@current_resource = Chef::Resource::Package.new(@new_resource.name)
diff --git a/lib/chef/provider/package/windows/msi.rb b/lib/chef/provider/package/windows/msi.rb
index a342600678..cc07909d8e 100644
--- a/lib/chef/provider/package/windows/msi.rb
+++ b/lib/chef/provider/package/windows/msi.rb
@@ -18,7 +18,6 @@
# TODO: Allow @new_resource.source to be a Product Code as a GUID for uninstall / network install
-require 'chef/mixin/shell_out'
require 'chef/win32/api/installer' if RUBY_PLATFORM =~ /mswin|mingw32|windows/
class Chef
@@ -27,7 +26,6 @@ class Chef
class Windows
class MSI
include Chef::ReservedNames::Win32::API::Installer if RUBY_PLATFORM =~ /mswin|mingw32|windows/
- include Chef::Mixin::ShellOut
def initialize(resource)
@new_resource = resource
diff --git a/lib/chef/provider/package/yum.rb b/lib/chef/provider/package/yum.rb
index c241c7fd6d..d15f22ae16 100644
--- a/lib/chef/provider/package/yum.rb
+++ b/lib/chef/provider/package/yum.rb
@@ -19,12 +19,10 @@
require 'chef/config'
require 'chef/provider/package'
require 'chef/mixin/command'
-require 'chef/mixin/shell_out'
require 'chef/resource/package'
require 'singleton'
require 'chef/mixin/get_source_from_package'
-
class Chef
class Provider
class Package
@@ -647,7 +645,6 @@ class Chef
# Cache for our installed and available packages, pulled in from yum-dump.py
class YumCache
include Chef::Mixin::Command
- include Chef::Mixin::ShellOut
include Singleton
def initialize
@@ -949,7 +946,6 @@ class Chef
end # YumCache
include Chef::Mixin::GetSourceFromPackage
- include Chef::Mixin::ShellOut
def initialize(new_resource, run_context)
super
diff --git a/lib/chef/provider/package/zypper.rb b/lib/chef/provider/package/zypper.rb
index b288d5d954..b00bef0f92 100644
--- a/lib/chef/provider/package/zypper.rb
+++ b/lib/chef/provider/package/zypper.rb
@@ -22,7 +22,6 @@
require 'chef/provider/package'
require 'chef/mixin/command'
require 'chef/resource/package'
-require 'chef/mixin/shell_out'
require 'singleton'
class Chef
@@ -30,8 +29,6 @@ class Chef
class Package
class Zypper < Chef::Provider::Package
- include Chef::Mixin::ShellOut
-
def load_current_resource
@current_resource = Chef::Resource::Package.new(@new_resource.name)
@current_resource.package_name(@new_resource.package_name)
@@ -106,7 +103,7 @@ class Chef
private
def zypper_package(command, pkgname, version)
- version = "=#{version}" unless version.empty?
+ version = "=#{version}" unless version.nil? || version.empty?
if zypper_version < 1.0
shell_out!("zypper#{gpg_checks} #{command} -y #{pkgname}")
else
diff --git a/lib/chef/provider/registry_key.rb b/lib/chef/provider/registry_key.rb
index 3b5be93ba1..01ee57895e 100644
--- a/lib/chef/provider/registry_key.rb
+++ b/lib/chef/provider/registry_key.rb
@@ -25,7 +25,6 @@ require 'chef/provider'
require 'etc'
require 'fileutils'
require 'chef/scan_access_control'
-require 'chef/mixin/shell_out'
require 'chef/win32/registry'
class Chef
@@ -33,7 +32,6 @@ class Chef
class Provider
class RegistryKey < Chef::Provider
include Chef::Mixin::Checksum
- include Chef::Mixin::ShellOut
def whyrun_supported?
true
diff --git a/lib/chef/provider/remote_directory.rb b/lib/chef/provider/remote_directory.rb
index 129c5208f0..77e2754b08 100644
--- a/lib/chef/provider/remote_directory.rb
+++ b/lib/chef/provider/remote_directory.rb
@@ -40,7 +40,6 @@ class Chef
name !~ /(?:^|#{Regexp.escape(::File::SEPARATOR)})\.\.?$/
end)
-
files_to_transfer.each do |cookbook_file_relative_path|
create_cookbook_file(cookbook_file_relative_path)
# the file is removed from the purge list
diff --git a/lib/chef/provider/remote_file.rb b/lib/chef/provider/remote_file.rb
index ed99c0bb84..da2573dacb 100644
--- a/lib/chef/provider/remote_file.rb
+++ b/lib/chef/provider/remote_file.rb
@@ -50,4 +50,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/provider/remote_file/cache_control_data.rb b/lib/chef/provider/remote_file/cache_control_data.rb
index 0add74f50a..8331f3d31a 100644
--- a/lib/chef/provider/remote_file/cache_control_data.rb
+++ b/lib/chef/provider/remote_file/cache_control_data.rb
@@ -161,5 +161,3 @@ class Chef
end
end
end
-
-
diff --git a/lib/chef/provider/remote_file/fetcher.rb b/lib/chef/provider/remote_file/fetcher.rb
index c3a098ed35..249b29186f 100644
--- a/lib/chef/provider/remote_file/fetcher.rb
+++ b/lib/chef/provider/remote_file/fetcher.rb
@@ -17,7 +17,6 @@
# limitations under the License.
#
-
class Chef
class Provider
class RemoteFile
@@ -40,4 +39,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/provider/remote_file/ftp.rb b/lib/chef/provider/remote_file/ftp.rb
index 7f3fdbf383..3f78286aa3 100644
--- a/lib/chef/provider/remote_file/ftp.rb
+++ b/lib/chef/provider/remote_file/ftp.rb
@@ -81,7 +81,6 @@ class Chef
@filename
end
-
def fetch
with_connection do
get
diff --git a/lib/chef/provider/resource_update.rb b/lib/chef/provider/resource_update.rb
index 54f25738ed..e069a8201c 100644
--- a/lib/chef/provider/resource_update.rb
+++ b/lib/chef/provider/resource_update.rb
@@ -50,6 +50,3 @@ class Chef
end
end
end
-
-
-
diff --git a/lib/chef/provider/service/freebsd.rb b/lib/chef/provider/service/freebsd.rb
index 7da29851c2..800cd4ec13 100644
--- a/lib/chef/provider/service/freebsd.rb
+++ b/lib/chef/provider/service/freebsd.rb
@@ -16,7 +16,6 @@
# limitations under the License.
#
-require 'chef/mixin/shell_out'
require 'chef/resource/service'
require 'chef/provider/service/init'
require 'chef/mixin/command'
@@ -26,8 +25,6 @@ class Chef
class Service
class Freebsd < Chef::Provider::Service::Init
- include Chef::Mixin::ShellOut
-
def load_current_resource
@current_resource = Chef::Resource::Service.new(@new_resource.name)
@current_resource.service_name(@new_resource.service_name)
diff --git a/lib/chef/provider/service/init.rb b/lib/chef/provider/service/init.rb
index 64f4074d8b..cf5da852c3 100644
--- a/lib/chef/provider/service/init.rb
+++ b/lib/chef/provider/service/init.rb
@@ -16,7 +16,6 @@
# limitations under the License.
#
-require 'chef/mixin/shell_out'
require 'chef/provider/service/simple'
require 'chef/mixin/command'
@@ -25,8 +24,6 @@ class Chef
class Service
class Init < Chef::Provider::Service::Simple
- include Chef::Mixin::ShellOut
-
def initialize(new_resource, run_context)
super
@init_command = "/etc/init.d/#{@new_resource.service_name}"
diff --git a/lib/chef/provider/service/macosx.rb b/lib/chef/provider/service/macosx.rb
index 2642a7e204..36930ee4ac 100644
--- a/lib/chef/provider/service/macosx.rb
+++ b/lib/chef/provider/service/macosx.rb
@@ -24,7 +24,6 @@ class Chef
class Provider
class Service
class Macosx < Chef::Provider::Service::Simple
- include Chef::Mixin::ShellOut
def self.gather_plist_dirs
locations = %w{/Library/LaunchAgents
diff --git a/lib/chef/provider/service/redhat.rb b/lib/chef/provider/service/redhat.rb
index 5275bcac29..7a7b2a1c40 100644
--- a/lib/chef/provider/service/redhat.rb
+++ b/lib/chef/provider/service/redhat.rb
@@ -17,13 +17,11 @@
#
require 'chef/provider/service/init'
-require 'chef/mixin/shell_out'
class Chef
class Provider
class Service
class Redhat < Chef::Provider::Service::Init
- include Chef::Mixin::ShellOut
CHKCONFIG_ON = /\d:on/
CHKCONFIG_MISSING = /No such/
diff --git a/lib/chef/provider/service/simple.rb b/lib/chef/provider/service/simple.rb
index 3b3e539d40..f03b8a18a1 100644
--- a/lib/chef/provider/service/simple.rb
+++ b/lib/chef/provider/service/simple.rb
@@ -16,7 +16,6 @@
# limitations under the License.
#
-require 'chef/mixin/shell_out'
require 'chef/provider/service'
require 'chef/resource/service'
require 'chef/mixin/command'
@@ -26,8 +25,6 @@ class Chef
class Service
class Simple < Chef::Provider::Service
- include Chef::Mixin::ShellOut
-
def load_current_resource
@current_resource = Chef::Resource::Service.new(@new_resource.name)
@current_resource.service_name(@new_resource.service_name)
diff --git a/lib/chef/provider/service/solaris.rb b/lib/chef/provider/service/solaris.rb
index 69a79e6226..0c47a3462b 100644
--- a/lib/chef/provider/service/solaris.rb
+++ b/lib/chef/provider/service/solaris.rb
@@ -16,7 +16,6 @@
# limitations under the License.
#
-require 'chef/mixin/shell_out'
require 'chef/provider/service'
require 'chef/resource/service'
require 'chef/mixin/command'
@@ -25,7 +24,6 @@ class Chef
class Provider
class Service
class Solaris < Chef::Provider::Service
- include Chef::Mixin::ShellOut
attr_reader :maintenance
def initialize(new_resource, run_context=nil)
@@ -35,7 +33,6 @@ class Chef
@maintenace = false
end
-
def load_current_resource
@current_resource = Chef::Resource::Service.new(@new_resource.name)
@current_resource.service_name(@new_resource.service_name)
diff --git a/lib/chef/provider/service/systemd.rb b/lib/chef/provider/service/systemd.rb
index ea43e658e4..6231603d03 100644
--- a/lib/chef/provider/service/systemd.rb
+++ b/lib/chef/provider/service/systemd.rb
@@ -18,7 +18,6 @@
require 'chef/resource/service'
require 'chef/provider/service/simple'
-require 'chef/mixin/shell_out'
class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
def load_current_resource
diff --git a/lib/chef/provider/service/windows.rb b/lib/chef/provider/service/windows.rb
index 2cfa9d44c1..2d478fa9fe 100644
--- a/lib/chef/provider/service/windows.rb
+++ b/lib/chef/provider/service/windows.rb
@@ -18,7 +18,6 @@
# limitations under the License.
#
-require 'chef/mixin/shell_out'
require 'chef/provider/service/simple'
if RUBY_PLATFORM =~ /mswin|mingw32|windows/
require 'win32/service'
@@ -26,8 +25,6 @@ end
class Chef::Provider::Service::Windows < Chef::Provider::Service
- include Chef::Mixin::ShellOut
-
#Win32::Service.get_start_type
AUTO_START = 'auto start'
DISABLED = 'disabled'
diff --git a/lib/chef/provider/subversion.rb b/lib/chef/provider/subversion.rb
index 6ceb3e592a..81ed639c53 100644
--- a/lib/chef/provider/subversion.rb
+++ b/lib/chef/provider/subversion.rb
@@ -16,7 +16,6 @@
# limitations under the License.
#
-
#TODO subversion and git should both extend from a base SCM provider.
require 'chef/log'
@@ -199,7 +198,6 @@ class Chef
['svn', *args].compact.join(" ")
end
-
def target_dir_non_existent_or_empty?
!::File.exist?(@new_resource.destination) || Dir.entries(@new_resource.destination).sort == ['.','..']
end
diff --git a/lib/chef/provider/template.rb b/lib/chef/provider/template.rb
index 555f4f14f0..48cc45f3a8 100644
--- a/lib/chef/provider/template.rb
+++ b/lib/chef/provider/template.rb
@@ -22,7 +22,6 @@ require 'chef/provider/file'
require 'chef/deprecation/provider/template'
require 'chef/deprecation/warnings'
-
class Chef
class Provider
class Template < Chef::Provider::File
@@ -63,4 +62,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/provider/template/content.rb b/lib/chef/provider/template/content.rb
index 472ea331a3..7fc680ec85 100644
--- a/lib/chef/provider/template/content.rb
+++ b/lib/chef/provider/template/content.rb
@@ -58,4 +58,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/provider/user/aix.rb b/lib/chef/provider/user/aix.rb
new file mode 100644
index 0000000000..af08ab4364
--- /dev/null
+++ b/lib/chef/provider/user/aix.rb
@@ -0,0 +1,95 @@
+#
+# Copyright:: Copyright (c) 2012 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.
+
+class Chef
+ class Provider
+ class User
+ class Aix < Chef::Provider::User::Useradd
+
+ UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:shell, "-s"], [:uid, "-u"]]
+
+ def create_user
+ super
+ add_password
+ end
+
+ def manage_user
+ add_password
+ manage_home
+ super
+ end
+
+ # Aix does not support -r like other unix, sytem account is created by adding to 'system' group
+ def useradd_options
+ opts = []
+ opts << "-g" << "system" if new_resource.system
+ opts
+ end
+
+ def check_lock
+ lock_info = shell_out!("lsuser -a account_locked #{new_resource.username}")
+ if whyrun_mode? && passwd_s.stdout.empty? && lock_info.stderr.match(/does not exist/)
+ # if we're in whyrun mode and the user is not yet created we assume it would be
+ return false
+ end
+ raise Chef::Exceptions::User, "Cannot determine if #{@new_resource} is locked!" if lock_info.stdout.empty?
+
+ status = /\S+\s+account_locked=(\S+)/.match(lock_info.stdout)
+ if status && status[1] == "true"
+ @locked = true
+ else
+ @locked = false
+ end
+
+ @locked
+ end
+
+ def lock_user
+ shell_out!("chuser account_locked=true #{new_resource.username}")
+ end
+
+ def unlock_user
+ shell_out!("chuser account_locked=false #{new_resource.username}")
+ end
+
+ private
+ def add_password
+ if @current_resource.password != @new_resource.password && @new_resource.password
+ Chef::Log.debug("#{@new_resource.username} setting password to #{@new_resource.password}")
+ command = "echo '#{@new_resource.username}:#{@new_resource.password}' | chpasswd -e"
+ shell_out!(command)
+ end
+ end
+
+ # Aix specific handling to update users home directory.
+ def manage_home
+ # -m option does not work on aix, so move dir.
+ if updating_home? and managing_home_dir?
+ universal_options.delete("-m")
+ if ::File.directory?(@current_resource.home)
+ Chef::Log.debug("Changing users home directory from #{@current_resource.home} to #{new_resource.home}")
+ shell_out!("mv #{@current_resource.home} #{new_resource.home}")
+ else
+ Chef::Log.debug("Creating users home directory #{new_resource.home}")
+ shell_out!("mkdir -p #{new_resource.home}")
+ end
+ end
+ end
+
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/user/dscl.rb b/lib/chef/provider/user/dscl.rb
index b01931609e..96b5db24ba 100644
--- a/lib/chef/provider/user/dscl.rb
+++ b/lib/chef/provider/user/dscl.rb
@@ -16,7 +16,6 @@
# limitations under the License.
#
-require 'chef/mixin/shell_out'
require 'chef/provider/user'
require 'openssl'
@@ -24,7 +23,6 @@ class Chef
class Provider
class User
class Dscl < Chef::Provider::User
- include Chef::Mixin::ShellOut
NFS_HOME_DIRECTORY = %r{^NFSHomeDirectory: (.*)$}
AUTHENTICATION_AUTHORITY = %r{^AuthenticationAuthority: (.*)$}
diff --git a/lib/chef/provider/user/solaris.rb b/lib/chef/provider/user/solaris.rb
index df491ac697..d480acaced 100644
--- a/lib/chef/provider/user/solaris.rb
+++ b/lib/chef/provider/user/solaris.rb
@@ -89,4 +89,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/provider/user/useradd.rb b/lib/chef/provider/user/useradd.rb
index 201bcbe542..cc770c0be2 100644
--- a/lib/chef/provider/user/useradd.rb
+++ b/lib/chef/provider/user/useradd.rb
@@ -17,7 +17,6 @@
#
require 'pathname'
-require 'chef/mixin/shell_out'
require 'chef/provider/user'
class Chef
@@ -25,8 +24,6 @@ class Chef
class User
class Useradd < Chef::Provider::User
- include Chef::Mixin::ShellOut
-
UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:password, "-p"], [:shell, "-s"], [:uid, "-u"]]
def create_user
@@ -49,6 +46,7 @@ class Chef
def remove_user
command = [ "userdel" ]
command << "-r" if managing_home_dir?
+ command << "-f" if new_resource.force
command << new_resource.username
shell_out!(*command)
end
diff --git a/lib/chef/providers.rb b/lib/chef/providers.rb
index c89037df31..3c9e94e6f7 100644
--- a/lib/chef/providers.rb
+++ b/lib/chef/providers.rb
@@ -91,6 +91,7 @@ require 'chef/provider/user/pw'
require 'chef/provider/user/useradd'
require 'chef/provider/user/windows'
require 'chef/provider/user/solaris'
+require 'chef/provider/user/aix'
require 'chef/provider/group/aix'
require 'chef/provider/group/dscl'
diff --git a/lib/chef/resource/paludis_package.rb b/lib/chef/resource/paludis_package.rb
index e456750b70..fde25e69b3 100644
--- a/lib/chef/resource/paludis_package.rb
+++ b/lib/chef/resource/paludis_package.rb
@@ -27,6 +27,7 @@ class Chef
@resource_name = :paludis_package
@provider = Chef::Provider::Package::Paludis
@allowed_actions = [ :install, :remove, :upgrade ]
+ @timeout = 3600
end
end
end
diff --git a/lib/chef/resource/user.rb b/lib/chef/resource/user.rb
index 357d6d12ea..05c076229f 100644
--- a/lib/chef/resource/user.rb
+++ b/lib/chef/resource/user.rb
@@ -38,6 +38,7 @@ class Chef
@password = nil
@system = false
@manage_home = false
+ @force = false
@non_unique = false
@action = :create
@supports = {
@@ -121,6 +122,14 @@ class Chef
)
end
+ def force(arg=nil)
+ set_or_return(
+ :force,
+ arg,
+ :kind_of => [ TrueClass, FalseClass ]
+ )
+ end
+
def non_unique(arg=nil)
set_or_return(
:non_unique,
diff --git a/lib/chef/resource_reporter.rb b/lib/chef/resource_reporter.rb
index 47bbd13741..046e4e82c6 100644
--- a/lib/chef/resource_reporter.rb
+++ b/lib/chef/resource_reporter.rb
@@ -231,17 +231,17 @@ class Chef
Chef::Log.info("Sending resource update report (run-id: #{run_id})")
Chef::Log.debug run_data.inspect
compressed_data = encode_gzip(run_data.to_json)
+ Chef::Log.debug("Sending compressed run data...")
+ # Since we're posting compressed data we can not directly call post_rest which expects JSON
+ reporting_url = @rest_client.create_url(resource_history_url)
begin
- Chef::Log.debug("Sending compressed run data...")
- # Since we're posting compressed data we can not directly call post_rest which expects JSON
- reporting_url = @rest_client.create_url(resource_history_url)
@rest_client.raw_http_request(:POST, reporting_url, headers({'Content-Encoding' => 'gzip'}), compressed_data)
- rescue Net::HTTPServerException => e
- if e.response.code.to_s == "400"
+ rescue StandardError => e
+ if e.respond_to? :response
Chef::FileCache.store("failed-reporting-data.json", Chef::JSONCompat.to_json_pretty(run_data), 0640)
- Chef::Log.error("Failed to post reporting data to server (HTTP 400), saving to #{Chef::FileCache.load("failed-reporting-data.json", false)}")
+ Chef::Log.error("Failed to post reporting data to server (HTTP #{e.response.code}), saving to #{Chef::FileCache.load("failed-reporting-data.json", false)}")
else
- Chef::Log.error("Failed to post reporting data to server (HTTP #{e.response.code.to_s})")
+ Chef::Log.error("Failed to post reporting data to server (#{e})")
end
end
else
diff --git a/lib/chef/role.rb b/lib/chef/role.rb
index 64952c6ab2..57f3a2aa29 100644
--- a/lib/chef/role.rb
+++ b/lib/chef/role.rb
@@ -236,8 +236,8 @@ class Chef
paths = Array(Chef::Config[:role_path])
paths.each do |path|
roles_files = Dir.glob(File.join(path, "**", "**"))
- js_files = roles_files.select { |file| file.match /#{name}\.json$/ }
- rb_files = roles_files.select { |file| file.match /#{name}\.rb$/ }
+ js_files = roles_files.select { |file| file.match /\/#{name}\.json$/ }
+ rb_files = roles_files.select { |file| file.match /\/#{name}\.rb$/ }
if js_files.count > 1 or rb_files.count > 1
raise Chef::Exceptions::DuplicateRole, "Multiple roles of same type found named #{name}"
end
diff --git a/lib/chef/shell/shell_session.rb b/lib/chef/shell/shell_session.rb
index a158020116..73e6c34ebb 100644
--- a/lib/chef/shell/shell_session.rb
+++ b/lib/chef/shell/shell_session.rb
@@ -169,7 +169,7 @@ module Shell
def rebuild_context
@run_status = Chef::RunStatus.new(@node, @events)
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, Chef::Config[:cookbook_path]) }
+ Chef::Cookbook::FileVendor.fetch_from_disk(Chef::Config[:cookbook_path])
cl = Chef::CookbookLoader.new(Chef::Config[:cookbook_path])
cl.load_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cl)
@@ -201,7 +201,7 @@ module Shell
def rebuild_context
@run_status = Chef::RunStatus.new(@node, @events)
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::RemoteFileVendor.new(manifest, Chef::REST.new(Chef::Config[:server_url])) }
+ Chef::Cookbook::FileVendor.fetch_from_remote(Chef::REST.new(Chef::Config[:chef_server_url]))
cookbook_hash = @client.sync_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cookbook_hash)
@run_context = Chef::RunContext.new(node, cookbook_collection, @events)
diff --git a/lib/chef/version_constraint.rb b/lib/chef/version_constraint.rb
index 7bfde41e74..a78e32e94f 100644
--- a/lib/chef/version_constraint.rb
+++ b/lib/chef/version_constraint.rb
@@ -24,7 +24,7 @@ class Chef
PATTERN = /^(#{OPS.join('|')}) *([0-9].*)$/
VERSION_CLASS = Chef::Version
- attr_reader :op, :version, :raw_version
+ attr_reader :op, :version
def initialize(constraint_spec=DEFAULT_CONSTRAINT)
case constraint_spec
@@ -50,11 +50,11 @@ class Chef
end
def inspect
- "(#{@op} #{@version})"
+ "(#{to_s})"
end
def to_s
- "#{@op} #{@version}"
+ "#{@op} #{@raw_version}"
end
def eql?(o)
@@ -106,7 +106,7 @@ class Chef
@op = $1
@raw_version = $2
@version = self.class::VERSION_CLASS.new(@raw_version)
- if raw_version.split('.').size <= 2
+ if @raw_version.split('.').size <= 2
@missing_patch_level = true
end
else
diff --git a/spec/data/cookbooks/openldap/files/default/remotedir/not_a_template.erb b/spec/data/cookbooks/openldap/files/default/remotedir/not_a_template.erb
new file mode 100644
index 0000000000..fc68ce83a1
--- /dev/null
+++ b/spec/data/cookbooks/openldap/files/default/remotedir/not_a_template.erb
@@ -0,0 +1,2 @@
+# This file is not a chef template despite being and erb.
+# It should not be included in a cookbook syntax check
diff --git a/spec/functional/resource/base.rb b/spec/functional/resource/base.rb
index 056db39877..cdb52fbc1b 100644
--- a/spec/functional/resource/base.rb
+++ b/spec/functional/resource/base.rb
@@ -16,16 +16,6 @@
# limitations under the License.
#
-require 'spec_helper'
-
-def ohai
- # provider is platform-dependent, we need platform ohai data:
- @OHAI_SYSTEM ||= begin
- ohai = Ohai::System.new
- ohai.all_plugins("platform")
- ohai
- end
-end
def run_context
@run_context ||= begin
diff --git a/spec/functional/resource/cookbook_file_spec.rb b/spec/functional/resource/cookbook_file_spec.rb
index 173dac8268..7797ed0041 100644
--- a/spec/functional/resource/cookbook_file_spec.rb
+++ b/spec/functional/resource/cookbook_file_spec.rb
@@ -40,7 +40,7 @@ describe Chef::Resource::CookbookFile do
# set up cookbook collection for this run to use, based on our
# spec data.
cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, 'cookbooks'))
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, cookbook_repo) }
+ Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_repo)
loader = Chef::CookbookLoader.new(cookbook_repo)
loader.load_cookbooks
cookbook_collection = Chef::CookbookCollection.new(loader)
diff --git a/spec/functional/resource/group_spec.rb b/spec/functional/resource/group_spec.rb
index 3c2c1a86ba..681c9abc46 100644
--- a/spec/functional/resource/group_spec.rb
+++ b/spec/functional/resource/group_spec.rb
@@ -248,7 +248,7 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
end
end
- let(:group_name) { "cheftest-#{SecureRandom.random_number(9999)}" }
+ let(:group_name) { "t-#{SecureRandom.random_number(9999)}" }
let(:included_members) { nil }
let(:excluded_members) { nil }
let(:group_resource) {
@@ -330,7 +330,7 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
end
describe "group modify action", :not_supported_on_solaris do
- let(:spec_members){ ["spec-Gordon", "spec-Eric", "spec-Anthony"] }
+ let(:spec_members){ ["Gordon", "Eric", "Anthony"] }
let(:included_members) { [spec_members[0], spec_members[1]] }
let(:excluded_members) { [spec_members[2]] }
let(:tested_action) { :modify }
@@ -358,7 +358,7 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
end
describe "group manage action", :not_supported_on_solaris do
- let(:spec_members){ ["spec-Gordon", "spec-Eric", "spec-Anthony"] }
+ let(:spec_members){ ["Gordon", "Eric", "Anthony"] }
let(:included_members) { [spec_members[0], spec_members[1]] }
let(:excluded_members) { [spec_members[2]] }
let(:tested_action) { :manage }
@@ -388,7 +388,7 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
describe "group resource with Usermod provider", :solaris_only do
describe "when excluded_members is set" do
- let(:excluded_members) { ["spec-Anthony"] }
+ let(:excluded_members) { ["Anthony"] }
it ":manage should raise an error" do
lambda {group_resource.run_action(:manage) }.should raise_error
@@ -404,7 +404,7 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
end
describe "when append is not set" do
- let(:included_members) { ["spec-Gordon", "spec-Eric"] }
+ let(:included_members) { ["Gordon", "Eric"] }
before(:each) do
group_resource.append(false)
@@ -421,3 +421,5 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
end
end
+
+
diff --git a/spec/functional/resource/package_spec.rb b/spec/functional/resource/package_spec.rb
index 797f308cf9..548db40e79 100644
--- a/spec/functional/resource/package_spec.rb
+++ b/spec/functional/resource/package_spec.rb
@@ -135,9 +135,7 @@ describe Chef::Resource::Package, metadata do
cookbook_path = File.join(CHEF_SPEC_DATA, "cookbooks")
cl = Chef::CookbookLoader.new(cookbook_path)
cl.load_cookbooks
- Chef::Cookbook::FileVendor.on_create do |manifest|
- Chef::Cookbook::FileSystemFileVendor.new(manifest, cookbook_path)
- end
+ Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_path)
Chef::CookbookCollection.new(cl)
end
diff --git a/spec/functional/resource/remote_directory_spec.rb b/spec/functional/resource/remote_directory_spec.rb
index 70e575abb0..f9eb20711e 100644
--- a/spec/functional/resource/remote_directory_spec.rb
+++ b/spec/functional/resource/remote_directory_spec.rb
@@ -26,7 +26,7 @@ describe Chef::Resource::RemoteDirectory do
def create_resource
cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, cookbook_repo) }
+ Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_repo)
node = Chef::Node.new
cl = Chef::CookbookLoader.new(cookbook_repo)
cl.load_cookbooks
diff --git a/spec/functional/resource/template_spec.rb b/spec/functional/resource/template_spec.rb
index 7816d6357b..fefd995743 100644
--- a/spec/functional/resource/template_spec.rb
+++ b/spec/functional/resource/template_spec.rb
@@ -37,7 +37,7 @@ describe Chef::Resource::Template do
def create_resource
cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, cookbook_repo) }
+ Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_repo)
cl = Chef::CookbookLoader.new(cookbook_repo)
cl.load_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cl)
diff --git a/spec/functional/resource/user_spec.rb b/spec/functional/resource/user_spec.rb
index 434faec408..1e9f924b34 100644
--- a/spec/functional/resource/user_spec.rb
+++ b/spec/functional/resource/user_spec.rb
@@ -18,11 +18,21 @@
#
require 'spec_helper'
+require 'functional/resource/base'
require 'chef/mixin/shell_out'
+def user_provider_for_platform
+ case ohai[:platform]
+ when "aix"
+ Chef::Provider::User::Aix
+ else
+ Chef::Provider::User::Useradd
+ end
+end
+
metadata = { :unix_only => true,
:requires_root => true,
- :provider => {:user => Chef::Provider::User::Useradd}
+ :provider => {:user => user_provider_for_platform}
}
describe Chef::Resource::User, metadata do
@@ -46,15 +56,27 @@ describe Chef::Resource::User, metadata do
end
def etc_shadow
- File.open("/etc/shadow") {|f| f.read }
+ case ohai[:platform]
+ when "aix"
+ File.open("/etc/security/passwd") {|f| f.read }
+ else
+ File.open("/etc/shadow") {|f| f.read }
+ end
end
def supports_quote_in_username?
OHAI_SYSTEM["platform_family"] == "debian"
end
+ def password_should_be_set
+ if ohai[:platform] == "aix"
+ pw_entry.passwd.should == "!"
+ else
+ pw_entry.passwd.should == "x"
+ end
+ end
+
before do
- pending "porting implementation for user provider in aix" if OHAI_SYSTEM[:platform] == 'aix'
# Silence shell_out live stream
Chef::Log.level = :warn
end
@@ -62,7 +84,7 @@ describe Chef::Resource::User, metadata do
after do
begin
pw_entry # will raise if the user doesn't exist
- shell_out!("userdel", "-f", "-r", username, :returns => [0,12])
+ shell_out!("userdel", "-r", username, :returns => [0,12])
rescue UserNotFound
# nothing to remove
end
@@ -83,7 +105,7 @@ describe Chef::Resource::User, metadata do
end
let(:username) do
- "chef-functional-test"
+ "cf-test"
end
let(:uid) { nil }
@@ -105,6 +127,14 @@ describe Chef::Resource::User, metadata do
r
end
+ let(:expected_shadow) do
+ if ohai[:platform] == "aix"
+ expected_shadow = "cf-test" # For aix just check user entry in shadow file
+ else
+ expected_shadow = "cf-test:$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/"
+ end
+ end
+
let(:skip) { false }
describe "action :create" do
@@ -218,10 +248,17 @@ describe Chef::Resource::User, metadata do
context "when a password is specified" do
# openssl passwd -1 "secretpassword"
- let(:password) { "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" }
+ let(:password) do
+ case ohai[:platform]
+ when "aix"
+ "eL5qfEVznSNss"
+ else
+ "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/"
+ end
+ end
+
it "sets the user's shadow password" do
- pw_entry.passwd.should == "x"
- expected_shadow = "chef-functional-test:$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/"
+ password_should_be_set
etc_shadow.should include(expected_shadow)
end
end
@@ -229,14 +266,21 @@ describe Chef::Resource::User, metadata do
context "when a system user is specified" do
let(:system) { true }
let(:uid_min) do
- # from `man useradd`, login user means uid will be between
- # UID_SYS_MIN and UID_SYS_MAX defined in /etc/login.defs. On my
- # Ubuntu 13.04 system, these are commented out, so we'll look at
- # UID_MIN to find the lower limit of the non-system-user range, and
- # use that value in our assertions.
- login_defs = File.open("/etc/login.defs", "rb") {|f| f.read }
- uid_min_scan = /^UID_MIN\s+(\d+)/
- login_defs.match(uid_min_scan)[1]
+ case ohai[:platform]
+ when "aix"
+ # UIDs and GIDs below 100 are typically reserved for system accounts and services
+ # http://www.ibm.com/developerworks/aix/library/au-satuidgid/
+ 100
+ else
+ # from `man useradd`, login user means uid will be between
+ # UID_SYS_MIN and UID_SYS_MAX defined in /etc/login.defs. On my
+ # Ubuntu 13.04 system, these are commented out, so we'll look at
+ # UID_MIN to find the lower limit of the non-system-user range, and
+ # use that value in our assertions.
+ login_defs = File.open("/etc/login.defs", "rb") {|f| f.read }
+ uid_min_scan = /^UID_MIN\s+(\d+)/
+ login_defs.match(uid_min_scan)[1]
+ end
end
it "ensures the user has the properties of a system user" do
@@ -284,7 +328,15 @@ describe Chef::Resource::User, metadata do
let(:home) { "/home/bobo" }
let(:manage_home) { true }
# openssl passwd -1 "secretpassword"
- let(:password) { "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" }
+ let(:password) do
+ case ohai[:platform]
+ when "aix"
+ "eL5qfEVznSNss"
+ else
+ "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/"
+ end
+ end
+
let(:system) { false }
let(:comment) { "hello this is dog" }
@@ -347,6 +399,11 @@ describe Chef::Resource::User, metadata do
File.should_not exist("/home/foo")
File.should exist("/home/bar")
end
+ elsif ohai[:platform] == "aix"
+ it "creates the home dir in the desired location" do
+ File.should_not exist("/home/foo")
+ File.should exist("/home/bar")
+ end
else
it "does not create the home dir in the desired location (XXX)" do
# This behavior seems contrary to expectation and non-convergent.
@@ -370,11 +427,18 @@ describe Chef::Resource::User, metadata do
context "and a password is added" do
# openssl passwd -1 "secretpassword"
- let(:password) { "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" }
+ let(:password) do
+ case ohai[:platform]
+ when "aix"
+ "eL5qfEVznSNss"
+ else
+ "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/"
+ end
+ end
+
it "ensures the password is set" do
- pw_entry.passwd.should == "x"
- expected_shadow = "chef-functional-test:$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/"
+ password_should_be_set
etc_shadow.should include(expected_shadow)
end
@@ -382,13 +446,28 @@ describe Chef::Resource::User, metadata do
context "and the password is updated" do
# openssl passwd -1 "OLDpassword"
- let(:existing_password) { "$1$1dVmwm4z$CftsFn8eBDjDRUytYKkXB." }
+ let(:existing_password) do
+ case ohai[:platform]
+ when "aix"
+ "jkzG6MvUxjk2g"
+ else
+ "$1$1dVmwm4z$CftsFn8eBDjDRUytYKkXB."
+ end
+ end
+
# openssl passwd -1 "secretpassword"
- let(:password) { "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" }
+ let(:password) do
+ case ohai[:platform]
+ when "aix"
+ "eL5qfEVznSNss"
+ else
+ "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/"
+ end
+ end
+
it "ensures the password is set to the desired value" do
- pw_entry.passwd.should == "x"
- expected_shadow = "chef-functional-test:$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/"
+ password_should_be_set
etc_shadow.should include(expected_shadow)
end
end
@@ -427,15 +506,47 @@ describe Chef::Resource::User, metadata do
shadow_entry.split(':')[1]
end
+ def aix_user_lock_status
+ lock_info = shell_out!("lsuser -a account_locked #{username}")
+ status = /\S+\s+account_locked=(\S+)/.match(lock_info.stdout)[1]
+ end
+
+ def user_account_should_be_locked
+ case ohai[:platform]
+ when "aix"
+ aix_user_lock_status.should == "true"
+ else
+ shadow_password.should include("!")
+ end
+ end
+
+ def user_account_should_be_unlocked
+ case ohai[:platform]
+ when "aix"
+ aix_user_lock_status.should == "false"
+ else
+ shadow_password.should_not include("!")
+ end
+ end
+
+ def lock_user_account
+ case ohai[:platform]
+ when "aix"
+ shell_out!("chuser account_locked=true #{username}")
+ else
+ shell_out!("usermod -L #{username}")
+ end
+ end
+
before do
# create user and setup locked/unlocked state
user_resource.dup.run_action(:create)
if user_locked_context?
- shell_out!("usermod -L #{username}")
- shadow_password.should include("!")
+ lock_user_account
+ user_account_should_be_locked
elsif password
- shadow_password.should_not include("!")
+ user_account_should_be_unlocked
end
end
end
@@ -457,16 +568,32 @@ describe Chef::Resource::User, metadata do
context "and the user is not locked" do
# user will be locked if it has no password
- let(:password) { "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" }
+ let(:password) do
+ case ohai[:platform]
+ when "aix"
+ "eL5qfEVznSNss"
+ else
+ "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/"
+ end
+ end
+
it "locks the user's password" do
- shadow_password.should include("!")
+ user_account_should_be_locked
end
end
context "and the user is locked" do
# user will be locked if it has no password
- let(:password) { "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" }
+ let(:password) do
+ case ohai[:platform]
+ when "aix"
+ "eL5qfEVznSNss"
+ else
+ "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/"
+ end
+ end
+
let(:user_locked_context?) { true }
it "does not update the user" do
user_resource.should_not be_updated_by_last_action
@@ -518,14 +645,26 @@ describe Chef::Resource::User, metadata do
# DEBUG: ---- End output of usermod -U chef-functional-test ----
# DEBUG: Ran usermod -U chef-functional-test returned 0
@error.should be_nil
- pw_entry.passwd.should == 'x'
- shadow_password.should == "!"
+ if ohai[:platform] == "aix"
+ pw_entry.passwd.should == '*'
+ else
+ pw_entry.passwd.should == 'x'
+ end
+ user_account_should_be_unlocked
end
end
end
context "and has a password" do
- let(:password) { "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" }
+ let(:password) do
+ case ohai[:platform]
+ when "aix"
+ "eL5qfEVznSNss"
+ else
+ "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/"
+ end
+ end
+
context "and the user is not locked" do
it "does not update the user" do
user_resource.should_not be_updated_by_last_action
@@ -536,9 +675,7 @@ describe Chef::Resource::User, metadata do
let(:user_locked_context?) { true }
it "unlocks the user's password" do
- shadow_entry = etc_shadow.lines.select {|l| l.include?(username) }.first
- shadow_password = shadow_entry.split(':')[1]
- shadow_password.should_not include("!")
+ user_account_should_be_unlocked
end
end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 09e7642d98..7c11957997 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -124,6 +124,9 @@ RSpec.configure do |config|
config.filter_run_excluding :requires_root_or_running_windows => true unless (root? || windows?)
config.filter_run_excluding :requires_unprivileged_user => true if root?
config.filter_run_excluding :uses_diff => true unless has_diff?
+ config.filter_run_excluding :ruby_gte_20_and_openssl_gte_101 => true unless (ruby_gte_20? && openssl_gte_101?)
+ config.filter_run_excluding :openssl_lt_101 => true unless openssl_lt_101?
+ config.filter_run_excluding :ruby_lt_20 => true unless ruby_lt_20?
running_platform_arch = `uname -m`.strip
diff --git a/spec/support/platform_helpers.rb b/spec/support/platform_helpers.rb
index 75ab0c9cde..a7c616d7a7 100644
--- a/spec/support/platform_helpers.rb
+++ b/spec/support/platform_helpers.rb
@@ -7,6 +7,10 @@ def ruby_gte_20?
RUBY_VERSION.to_f >= 2.0
end
+def ruby_lt_20?
+ !ruby_gte_20?
+end
+
def ruby_gte_19?
RUBY_VERSION.to_f >= 1.9
end
@@ -27,6 +31,11 @@ def windows?
!!(RUBY_PLATFORM =~ /mswin|mingw|windows/)
end
+def ohai
+ # This is defined in spec_helper; it has the `platform` populated.
+ OHAI_SYSTEM
+end
+
require 'wmi-lite/wmi' if windows?
def windows_domain_joined?
@@ -124,3 +133,11 @@ def root?
return false if windows?
Process.euid == 0
end
+
+def openssl_gte_101?
+ OpenSSL::OPENSSL_VERSION_NUMBER >= 10001000
+end
+
+def openssl_lt_101?
+ !openssl_gte_101?
+end
diff --git a/spec/support/shared/unit/provider/useradd_based_user_provider.rb b/spec/support/shared/unit/provider/useradd_based_user_provider.rb
index a95d19d33c..42f948d494 100644
--- a/spec/support/shared/unit/provider/useradd_based_user_provider.rb
+++ b/spec/support/shared/unit/provider/useradd_based_user_provider.rb
@@ -33,6 +33,7 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
@new_resource.password "abracadabra"
@new_resource.system false
@new_resource.manage_home false
+ @new_resource.force false
@new_resource.non_unique false
@current_resource = Chef::Resource::User.new("adam", @run_context)
@current_resource.comment "Adam Jacob"
@@ -43,6 +44,7 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
@current_resource.password "abracadabra"
@current_resource.system false
@current_resource.manage_home false
+ @current_resource.force false
@current_resource.non_unique false
@current_resource.supports({:manage_home => false, :non_unique => false})
end
@@ -71,6 +73,7 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
it "should set the option for #{attribute} if the new resources #{attribute} is not nil, without homedir management (using real attributes)" do
@new_resource.stub(:manage_home).and_return(false)
@new_resource.stub(:non_unique).and_return(false)
+ @new_resource.stub(:non_unique).and_return(false)
@new_resource.stub(attribute).and_return("hola")
provider.universal_options.should eql([option, 'hola'])
end
@@ -255,6 +258,12 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
provider.should_receive(:shell_out!).with("userdel", @new_resource.username).and_return(true)
provider.remove_user
end
+
+ it "should run userdel with the new resources user name and -f if force is true" do
+ @new_resource.force(true)
+ provider.should_receive(:shell_out!).with("userdel", "-f", @new_resource.username).and_return(true)
+ provider.remove_user
+ end
end
describe "when checking the lock" do
@@ -344,7 +353,7 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
and_return(passwd_status)
Chef::Config[:why_run] = true
end
-
+
it "should return false if the user does not exist" do
provider.check_lock.should eql(false)
end
diff --git a/spec/unit/cookbook/file_vendor_spec.rb b/spec/unit/cookbook/file_vendor_spec.rb
new file mode 100644
index 0000000000..4fad7d5808
--- /dev/null
+++ b/spec/unit/cookbook/file_vendor_spec.rb
@@ -0,0 +1,78 @@
+#--
+# Author:: Daniel DeLeo (<dan@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::Cookbook::FileVendor do
+
+ let(:file_vendor_class) { Class.new(described_class) }
+
+ # A manifest is a Hash of the format defined by Chef::CookbookVersion#manifest
+ let(:manifest) { {:cookbook_name => "bob"} }
+
+ context "when configured to fetch files over http" do
+
+ let(:http) { double("Chef::REST") }
+
+ before do
+ file_vendor_class.fetch_from_remote(http)
+ end
+
+ it "sets the vendor class to RemoteFileVendor" do
+ expect(file_vendor_class.vendor_class).to eq(Chef::Cookbook::RemoteFileVendor)
+ end
+
+ it "sets the initialization options to the given http object" do
+ expect(file_vendor_class.initialization_options).to eq(http)
+ end
+
+ it "creates a RemoteFileVendor for a given manifest" do
+ file_vendor = file_vendor_class.create_from_manifest(manifest)
+ expect(file_vendor).to be_a_kind_of(Chef::Cookbook::RemoteFileVendor)
+ expect(file_vendor.rest).to eq(http)
+ expect(file_vendor.cookbook_name).to eq("bob")
+ end
+
+ end
+
+ context "when configured to load files from disk" do
+
+ let(:cookbook_path) { %w[/var/chef/cookbooks /var/chef/other_cookbooks] }
+
+ before do
+ file_vendor_class.fetch_from_disk(cookbook_path)
+ end
+
+ it "sets the vendor class to FileSystemFileVendor" do
+ expect(file_vendor_class.vendor_class).to eq(Chef::Cookbook::FileSystemFileVendor)
+ end
+
+ it "sets the initialization options to the given cookbook paths" do
+ expect(file_vendor_class.initialization_options).to eq(cookbook_path)
+ end
+
+ it "creates a FileSystemFileVendor for a given manifest" do
+ file_vendor = file_vendor_class.create_from_manifest(manifest)
+ expect(file_vendor).to be_a_kind_of(Chef::Cookbook::FileSystemFileVendor)
+ expect(file_vendor.cookbook_name).to eq("bob")
+ expect(file_vendor.repo_paths).to eq(cookbook_path)
+ end
+
+ end
+
+end
+
diff --git a/spec/unit/cookbook_uploader_spec.rb b/spec/unit/cookbook_uploader_spec.rb
new file mode 100644
index 0000000000..af25baff13
--- /dev/null
+++ b/spec/unit/cookbook_uploader_spec.rb
@@ -0,0 +1,160 @@
+#
+# Author:: Daniel DeLeo (<dan@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::CookbookUploader do
+
+ let(:http_client) { double("Chef::REST") }
+
+ let(:cookbook_loader) do
+ loader = Chef::CookbookLoader.new(File.join(CHEF_SPEC_DATA, "cookbooks"))
+ loader.load_cookbooks
+ loader
+ end
+
+ let(:apache2_cookbook) { cookbook_loader.cookbooks_by_name["apache2"] }
+
+ let(:java_cookbook) { cookbook_loader.cookbooks_by_name["java"] }
+
+ let(:cookbooks_to_upload) { [apache2_cookbook, java_cookbook] }
+
+ let(:checksums_of_cookbook_files) { apache2_cookbook.checksums.merge(java_cookbook.checksums) }
+
+ let(:checksums_set) do
+ checksums_of_cookbook_files.keys.inject({}) do |set, cksum|
+ set[cksum] = nil
+ set
+ end
+ end
+
+ let(:sandbox_commit_uri) { "https://chef.example.org/sandboxes/abc123" }
+
+ let(:uploader) { described_class.new(cookbooks_to_upload, :rest => http_client) }
+
+ it "has a list of cookbooks to upload" do
+ expect(uploader.cookbooks).to eq(cookbooks_to_upload)
+ end
+
+ it "creates an HTTP client with default configuration when not initialized with one" do
+ default_http_client = double("Chef::REST")
+ expect(Chef::REST).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(default_http_client)
+ uploader = described_class.new(cookbooks_to_upload)
+ expect(uploader.rest).to eq(default_http_client)
+ end
+
+ describe "uploading cookbooks" do
+
+ def url_for(cksum)
+ "https://storage.example.com/#{cksum}"
+ end
+
+ let(:sandbox_response) do
+ sandbox_checksums = cksums_not_on_remote.inject({}) do |cksum_map, cksum|
+ cksum_map[cksum] = { "needs_upload" => true, "url" => url_for(cksum)}
+ cksum_map
+ end
+ { "checksums" => sandbox_checksums, "uri" => sandbox_commit_uri }
+ end
+
+ def expect_sandbox_create
+ expect(http_client).to receive(:post).
+ with("sandboxes", {:checksums => checksums_set}).
+ and_return(sandbox_response)
+ end
+
+ def expect_checksum_upload
+ checksums_of_cookbook_files.each do |md5, file_path|
+ next unless cksums_not_on_remote.include?(md5)
+
+ upload_headers = {
+ "content-type" => "application/x-binary",
+ "content-md5" => an_instance_of(String),
+ "accept" => "application/json"
+ }
+
+ expect(http_client).to receive(:put).
+ with(url_for(md5), IO.binread(file_path), upload_headers)
+
+ end
+ end
+
+ def expect_sandbox_commit
+ expect(http_client).to receive(:put).with(sandbox_commit_uri, {:is_completed => true})
+ end
+
+ def expect_cookbook_create
+ cookbooks_to_upload.each do |cookbook|
+
+ expect(http_client).to receive(:put).
+ with(cookbook.save_url, cookbook)
+
+ end
+ end
+
+ context "when no files exist on the server" do
+
+ let(:cksums_not_on_remote) do
+ checksums_of_cookbook_files.keys
+ end
+
+ it "uploads all files in a sandbox transaction, then creates cookbooks on the server" do
+ expect_sandbox_create
+ expect_checksum_upload
+ expect_sandbox_commit
+ expect_cookbook_create
+
+ uploader.upload_cookbooks
+ end
+
+ end
+
+ context "when some files exist on the server" do
+
+ let(:cksums_not_on_remote) do
+ checksums_of_cookbook_files.keys[0, 1]
+ end
+
+ it "uploads all files in a sandbox transaction, then creates cookbooks on the server" do
+ expect_sandbox_create
+ expect_checksum_upload
+ expect_sandbox_commit
+ expect_cookbook_create
+
+ uploader.upload_cookbooks
+ end
+
+ end
+
+ context "when all files already exist on the server" do
+
+ let(:cksums_not_on_remote) { [] }
+
+ it "uploads all files in a sandbox transaction, then creates cookbooks on the server" do
+ expect_sandbox_create
+ expect_checksum_upload
+ expect_sandbox_commit
+ expect_cookbook_create
+
+ uploader.upload_cookbooks
+ end
+
+ end
+ end
+
+end
diff --git a/spec/unit/data_bag_spec.rb b/spec/unit/data_bag_spec.rb
index 4ac843c869..167c1b4134 100644
--- a/spec/unit/data_bag_spec.rb
+++ b/spec/unit/data_bag_spec.rb
@@ -128,10 +128,19 @@ describe Chef::DataBag do
end
end
- describe "in solo mode" do
+ def file_dir_stub(path, returns = true)
+ File.should_receive(:directory?).with(path).and_return(returns)
+ end
+
+ def dir_glob_stub(path, returns = [])
+ Dir.should_receive(:glob).with(File.join(path, 'foo/*.json')).and_return(returns)
+ end
+
+ shared_examples_for "data bag in solo mode" do |data_bag_path|
before do
Chef::Config[:solo] = true
- Chef::Config[:data_bag_path] = '/var/chef/data_bags'
+ Chef::Config[:data_bag_path] = data_bag_path
+ @paths = Array(data_bag_path)
end
after do
@@ -139,35 +148,93 @@ describe Chef::DataBag do
end
it "should get the data bag from the data_bag_path" do
- File.should_receive(:directory?).with('/var/chef/data_bags').and_return(true)
- Dir.should_receive(:glob).with('/var/chef/data_bags/foo/*.json').and_return([])
+ @paths.each do |path|
+ file_dir_stub(path)
+ dir_glob_stub(path)
+ end
Chef::DataBag.load('foo')
end
it "should get the data bag from the data_bag_path by symbolic name" do
- File.should_receive(:directory?).with('/var/chef/data_bags').and_return(true)
- Dir.should_receive(:glob).with('/var/chef/data_bags/foo/*.json').and_return([])
+ @paths.each do |path|
+ file_dir_stub(path)
+ dir_glob_stub(path)
+ end
Chef::DataBag.load(:foo)
end
it "should return the data bag" do
- File.should_receive(:directory?).with('/var/chef/data_bags').and_return(true)
- Dir.stub(:glob).and_return(["/var/chef/data_bags/foo/bar.json", "/var/chef/data_bags/foo/baz.json"])
- IO.should_receive(:read).with('/var/chef/data_bags/foo/bar.json').and_return('{"id": "bar", "name": "Bob Bar" }')
- IO.should_receive(:read).with('/var/chef/data_bags/foo/baz.json').and_return('{"id": "baz", "name": "John Baz" }')
+ @paths.each do |path|
+ file_dir_stub(path)
+ if path == @paths.first
+ dir_glob_stub(path, [File.join(path, 'foo/bar.json'), File.join(path, 'foo/baz.json')])
+ else
+ dir_glob_stub(path)
+ end
+ end
+ IO.should_receive(:read).with(File.join(@paths.first, 'foo/bar.json')).and_return('{"id": "bar", "name": "Bob Bar" }')
+ IO.should_receive(:read).with(File.join(@paths.first, 'foo/baz.json')).and_return('{"id": "baz", "name": "John Baz" }')
data_bag = Chef::DataBag.load('foo')
data_bag.should == { 'bar' => { 'id' => 'bar', 'name' => 'Bob Bar' }, 'baz' => { 'id' => 'baz', 'name' => 'John Baz' }}
end
+ it "should raise if data bag has items with similar names but different content" do
+ @paths.each do |path|
+ file_dir_stub(path)
+ item_with_different_content = "{\"id\": \"bar\", \"name\": \"Bob Bar\", \"path\": \"#{path}\"}"
+ IO.should_receive(:read).with(File.join(path, 'foo/bar.json')).and_return(item_with_different_content)
+ if data_bag_path.is_a?(String)
+ dir_glob_stub(path, [File.join(path, 'foo/bar.json'), File.join(path, 'foo/baz.json')])
+ item_2_with_different_content = '{"id": "bar", "name": "John Baz"}'
+ IO.should_receive(:read).with(File.join(path, 'foo/baz.json')).and_return(item_2_with_different_content)
+ else
+ dir_glob_stub(path, [File.join(path, 'foo/bar.json')])
+ end
+ end
+ expect { Chef::DataBag.load('foo') }.to raise_error(Chef::Exceptions::DuplicateDataBagItem)
+ end
+
+ it "should return data bag if it has items with similar names and the same content" do
+ @paths.each do |path|
+ file_dir_stub(path)
+ dir_glob_stub(path, [File.join(path, 'foo/bar.json'), File.join(path, 'foo/baz.json')])
+ item_with_same_content = '{"id": "bar", "name": "Bob Bar"}'
+ IO.should_receive(:read).with(File.join(path, 'foo/bar.json')).and_return(item_with_same_content)
+ IO.should_receive(:read).with(File.join(path, 'foo/baz.json')).and_return(item_with_same_content)
+ end
+ data_bag = Chef::DataBag.load('foo')
+ test_data_bag = { 'bar' => { 'id' => 'bar', 'name' => 'Bob Bar'} }
+ data_bag.should == test_data_bag
+ end
+
+ it "should merge data bag items if there are no conflicts" do
+ @paths.each_with_index do |path, index|
+ file_dir_stub(path)
+ dir_glob_stub(path, [File.join(path, 'foo/bar.json'), File.join(path, 'foo/baz.json')])
+ test_item_with_same_content = '{"id": "bar", "name": "Bob Bar"}'
+ IO.should_receive(:read).with(File.join(path, 'foo/bar.json')).and_return(test_item_with_same_content)
+ test_uniq_item = "{\"id\": \"baz_#{index}\", \"name\": \"John Baz\", \"path\": \"#{path}\"}"
+ IO.should_receive(:read).with(File.join(path, 'foo/baz.json')).and_return(test_uniq_item)
+ end
+ data_bag = Chef::DataBag.load('foo')
+ test_data_bag = { 'bar' => { 'id' => 'bar', 'name' => 'Bob Bar'} }
+ @paths.each_with_index do |path, index|
+ test_data_bag["baz_#{index}"] = { "id" => "baz_#{index}", "name" => "John Baz", "path" => path }
+ end
+ data_bag.should == test_data_bag
+ end
+
it "should return the data bag list" do
- File.should_receive(:directory?).with('/var/chef/data_bags').and_return(true)
- Dir.should_receive(:glob).and_return(["/var/chef/data_bags/foo", "/var/chef/data_bags/bar"])
+ @paths.each do |path|
+ file_dir_stub(path)
+ Dir.should_receive(:glob).and_return([File.join(path, 'foo'), File.join(path, 'bar')])
+ end
data_bag_list = Chef::DataBag.list
data_bag_list.should == { 'bar' => 'bar', 'foo' => 'foo' }
end
it 'should raise an error if the configured data_bag_path is invalid' do
- File.should_receive(:directory?).with('/var/chef/data_bags').and_return(false)
+ file_dir_stub(@paths.first, false)
lambda {
Chef::DataBag.load('foo')
@@ -175,6 +242,14 @@ describe Chef::DataBag do
end
end
+
+ describe "data bag with string path" do
+ it_should_behave_like "data bag in solo mode", "/var/chef/data_bags"
+ end
+
+ describe "data bag with array path" do
+ it_should_behave_like "data bag in solo mode", ["/var/chef/data_bags", "/var/chef/data_bags_2"]
+ end
end
end
diff --git a/spec/unit/dsl/recipe_spec.rb b/spec/unit/dsl/recipe_spec.rb
index 14ee30be44..dfaad0b73e 100644
--- a/spec/unit/dsl/recipe_spec.rb
+++ b/spec/unit/dsl/recipe_spec.rb
@@ -46,6 +46,18 @@ describe Chef::DSL::Recipe do
it "responds to recipe_name" do
expect(recipe.recipe_name).to eq(recipe_name)
end
+
+ it "responds to shell_out" do
+ expect(recipe.respond_to?(:shell_out)).to be true
+ end
+
+ it "responds to shell_out" do
+ expect(recipe.respond_to?(:shell_out!)).to be true
+ end
+
+ it "responds to shell_out" do
+ expect(recipe.respond_to?(:shell_out_with_systems_locale)).to be true
+ end
end
context "when included in a class that defines the required interface directly" do
diff --git a/spec/unit/encrypted_data_bag_item_spec.rb b/spec/unit/encrypted_data_bag_item_spec.rb
index 1e662a0b7c..24ceb452ef 100644
--- a/spec/unit/encrypted_data_bag_item_spec.rb
+++ b/spec/unit/encrypted_data_bag_item_spec.rb
@@ -23,7 +23,7 @@ module Version0Encryptor
def self.encrypt_value(plaintext_data, key)
data = plaintext_data.to_yaml
- cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
+ cipher = OpenSSL::Cipher.new("aes-256-cbc")
cipher.encrypt
cipher.pkcs5_keyivgen(key)
encrypted_bytes = cipher.update(data)
@@ -39,14 +39,14 @@ describe Chef::EncryptedDataBagItem::Encryptor do
let(:key) { "passwd" }
it "encrypts to format version 1 by default" do
- encryptor.should be_a_kind_of(Chef::EncryptedDataBagItem::Encryptor::Version1Encryptor)
+ encryptor.should be_a_instance_of(Chef::EncryptedDataBagItem::Encryptor::Version1Encryptor)
end
describe "generating a random IV" do
it "generates a new IV for each encryption pass" do
encryptor2 = Chef::EncryptedDataBagItem::Encryptor.new(plaintext_data, key)
- # No API in ruby OpenSSL to get the iv it used for the encryption back
+ # No API in ruby OpenSSL to get the iv is used for the encryption back
# out. Instead we test if the encrypted data is the same. If it *is* the
# same, we assume the IV was the same each time.
encryptor.encrypted_data.should_not eq encryptor2.encrypted_data
@@ -56,7 +56,7 @@ describe Chef::EncryptedDataBagItem::Encryptor do
describe "when encrypting a non-hash non-array value" do
let(:plaintext_data) { 5 }
it "serializes the value in a de-serializable way" do
- Chef::JSONCompat.from_json(subject.serialized_data)["json_wrapper"].should eq 5
+ Chef::JSONCompat.from_json(encryptor.serialized_data)["json_wrapper"].should eq 5
end
end
@@ -78,10 +78,10 @@ describe Chef::EncryptedDataBagItem::Encryptor do
end
it "creates a version 2 encryptor" do
- encryptor.should be_a_kind_of(Chef::EncryptedDataBagItem::Encryptor::Version2Encryptor)
+ encryptor.should be_a_instance_of(Chef::EncryptedDataBagItem::Encryptor::Version2Encryptor)
end
- it "generates an hmac based on ciphertext including iv" do
+ it "generates an hmac based on ciphertext with different iv" do
encryptor2 = Chef::EncryptedDataBagItem::Encryptor.new(plaintext_data, key)
encryptor.hmac.should_not eq(encryptor2.hmac)
end
@@ -92,6 +92,74 @@ describe Chef::EncryptedDataBagItem::Encryptor do
end
end
+ describe "when using version 3 format" do
+ before do
+ Chef::Config[:data_bag_encrypt_version] = 3
+ end
+
+ context "on supported platforms", :ruby_gte_20_and_openssl_gte_101 do
+
+ it "creates a version 3 encryptor" do
+ encryptor.should be_a_instance_of(Chef::EncryptedDataBagItem::Encryptor::Version3Encryptor)
+ end
+
+ it "generates different authentication tags" do
+ encryptor3 = Chef::EncryptedDataBagItem::Encryptor.new(plaintext_data, key)
+ encryptor.for_encrypted_item # required to generate the auth_tag
+ encryptor3.for_encrypted_item
+ encryptor.auth_tag.should_not eq(encryptor3.auth_tag)
+ end
+
+ it "includes the auth_tag in the envelope" do
+ final_data = encryptor.for_encrypted_item
+ final_data["auth_tag"].should eq(Base64::encode64(encryptor.auth_tag))
+ end
+
+ it "throws an error if auth tag is read before encrypting the data" do
+ lambda { encryptor.auth_tag }.should raise_error(Chef::EncryptedDataBagItem::EncryptionFailure)
+ end
+
+ end # context on supported platforms
+
+ context "on unsupported platforms" do
+ let(:aead_algorithm) { Chef::EncryptedDataBagItem::AEAD_ALGORITHM }
+
+ it "throws an error warning about the Ruby version if it has no GCM support" do
+ # Force OpenSSL with AEAD support
+ OpenSSL::Cipher.stub(:ciphers).and_return([ aead_algorithm ])
+ # Ruby without AEAD support
+ OpenSSL::Cipher.should_receive(:method_defined?).with(:auth_data=).and_return(false)
+ lambda { encryptor }.should raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires Ruby/)
+ end
+
+ it "throws an error warning about the OpenSSL version if it has no GCM support" do
+ # Force Ruby with AEAD support
+ OpenSSL::Cipher.stub(:method_defined?).with(:auth_data=).and_return(true)
+ # OpenSSL without AEAD support
+ OpenSSL::Cipher.should_receive(:ciphers).and_return([])
+ lambda { encryptor }.should raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires an OpenSSL/)
+ end
+
+ context "on platforms with old Ruby", :ruby_lt_20 do
+
+ it "throws an error warning about the Ruby version" do
+ lambda { encryptor }.should raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires Ruby/)
+ end
+
+ end # context on platforms with old Ruby
+
+ context "on platforms with old OpenSSL", :openssl_lt_101 do
+
+ it "throws an error warning about the OpenSSL version" do
+ lambda { encryptor }.should raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires an OpenSSL/)
+ end
+
+ end # context on platforms with old OpenSSL
+
+ end # context on unsupported platforms
+
+ end # when using version 3 format
+
end
describe Chef::EncryptedDataBagItem::Decryptor do
@@ -101,17 +169,85 @@ describe Chef::EncryptedDataBagItem::Decryptor do
let(:encryption_key) { "passwd" }
let(:decryption_key) { encryption_key }
+ context "when decrypting a version 3 (JSON+aes-256-gcm+random iv+auth tag) encrypted value" do
+
+ context "on supported platforms", :ruby_gte_20_and_openssl_gte_101 do
+
+ let(:encrypted_value) do
+ Chef::EncryptedDataBagItem::Encryptor::Version3Encryptor.new(plaintext_data, encryption_key).for_encrypted_item
+ end
+
+ let(:bogus_auth_tag) { "bogus_auth_tag" }
+
+ it "decrypts the encrypted value" do
+ decryptor.decrypted_data.should eq({"json_wrapper" => plaintext_data}.to_json)
+ end
+
+ it "unwraps the encrypted data and returns it" do
+ decryptor.for_decrypted_item.should eq plaintext_data
+ end
+
+ it "rejects the data if the authentication tag is wrong" do
+ encrypted_value["auth_tag"] = bogus_auth_tag
+ lambda { decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::DecryptionFailure)
+ end
+
+ it "rejects the data if the authentication tag is missing" do
+ encrypted_value.delete("auth_tag")
+ lambda { decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::DecryptionFailure)
+ end
+
+ end # context on supported platforms
+
+ context "on unsupported platforms" do
+ let(:encrypted_value) do
+ {
+ "encrypted_data" => "",
+ "iv" => "",
+ "version" => 3,
+ "cipher" => "aes-256-cbc",
+ }
+ end
+
+ context "on platforms with old Ruby", :ruby_lt_20 do
+
+ it "throws an error warning about the Ruby version" do
+ lambda { decryptor }.should raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires Ruby/)
+ end
+
+ end # context on platforms with old Ruby
+
+ context "on platforms with old OpenSSL", :openssl_lt_101 do
+
+ it "throws an error warning about the OpenSSL version" do
+ lambda { decryptor }.should raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires an OpenSSL/)
+ end
+
+ end # context on unsupported platforms
+
+ end # context on platforms with old OpenSSL
+
+ end # context when decrypting a version 3
+
context "when decrypting a version 2 (JSON+aes-256-cbc+hmac-sha256+random iv) encrypted value" do
let(:encrypted_value) do
Chef::EncryptedDataBagItem::Encryptor::Version2Encryptor.new(plaintext_data, encryption_key).for_encrypted_item
end
let(:bogus_hmac) do
- digest = OpenSSL::Digest::Digest.new("sha256")
+ digest = OpenSSL::Digest.new("sha256")
raw_hmac = OpenSSL::HMAC.digest(digest, "WRONG", encrypted_value["encrypted_data"])
Base64.encode64(raw_hmac)
end
+ it "decrypts the encrypted value" do
+ decryptor.decrypted_data.should eq({"json_wrapper" => plaintext_data}.to_json)
+ end
+
+ it "unwraps the encrypted data and returns it" do
+ decryptor.for_decrypted_item.should eq plaintext_data
+ end
+
it "rejects the data if the hmac is wrong" do
encrypted_value["hmac"] = bogus_hmac
lambda { decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::DecryptionFailure)
@@ -131,7 +267,7 @@ describe Chef::EncryptedDataBagItem::Decryptor do
end
it "selects the correct strategy for version 1" do
- decryptor.should be_a_kind_of Chef::EncryptedDataBagItem::Decryptor::Version1Decryptor
+ decryptor.should be_a_instance_of Chef::EncryptedDataBagItem::Decryptor::Version1Decryptor
end
it "decrypts the encrypted value" do
@@ -191,7 +327,7 @@ describe Chef::EncryptedDataBagItem::Decryptor do
end
it "selects the correct strategy for version 0" do
- decryptor.should be_a_kind_of(Chef::EncryptedDataBagItem::Decryptor::Version0Decryptor)
+ decryptor.should be_a_instance_of(Chef::EncryptedDataBagItem::Decryptor::Version0Decryptor)
end
it "decrypts the encrypted value" do
diff --git a/spec/unit/formatters/base_spec.rb b/spec/unit/formatters/base_spec.rb
new file mode 100644
index 0000000000..6a843ea775
--- /dev/null
+++ b/spec/unit/formatters/base_spec.rb
@@ -0,0 +1,48 @@
+#
+# Author:: Lamont Granquist (<lamont@getchef.com>)
+#
+# Copyright:: Copyright (c) 2012 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::Formatters::Base do
+ let(:out) { double("out") }
+ let(:err) { double("err") }
+ let(:formatter) { Chef::Formatters::Base.new(out, err) }
+
+ it "starts with an indentation of zero" do
+ expect(formatter.output.indent).to eql(0)
+ end
+
+ it "increments it to two correctly" do
+ formatter.indent_by(2)
+ expect(formatter.output.indent).to eql(2)
+ end
+
+ it "increments it and then decrements it corectly" do
+ formatter.indent_by(2)
+ formatter.indent_by(-2)
+ expect(formatter.output.indent).to eql(0)
+ end
+
+ it "does not allow negative indentation" do
+ formatter.indent_by(-2)
+ expect(formatter.output.indent).to eql(0)
+ end
+end
+
+
diff --git a/spec/unit/http/json_input_spec.rb b/spec/unit/http/json_input_spec.rb
new file mode 100644
index 0000000000..fbf8f22503
--- /dev/null
+++ b/spec/unit/http/json_input_spec.rb
@@ -0,0 +1,128 @@
+#--
+# Author:: Daniel DeLeo (<dan@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/http/json_input'
+
+describe Chef::HTTP::JSONInput do
+
+ let(:json_encoder) { described_class.new() }
+
+ let(:url) { URI.parse("http://example.com") }
+ let(:headers) { {} }
+
+ def handle_request
+ json_encoder.handle_request(http_method, url, headers, data)
+ end
+
+ it "passes the response unmodified" do
+ http_response = double("Net::HTTPSuccess")
+ request = double("Chef::HTTP::HTTPRequest")
+ return_value = "response body"
+
+ result = json_encoder.handle_response(http_response, request, return_value)
+ expect(result).to eq([http_response, request, return_value])
+ end
+
+ it "doesn't handle streaming responses" do
+ http_response = double("Net::HTTPSuccess")
+ expect(json_encoder.stream_response_handler(http_response)).to be nil
+ end
+
+ it "does nothing for stream completion" do
+ http_response = double("Net::HTTPSuccess")
+ request = double("Chef::HTTP::HTTPRequest")
+ return_value = "response body"
+
+ result = json_encoder.handle_response(http_response, request, return_value)
+ expect(result).to eq([http_response, request, return_value])
+ end
+
+ context "when handling a request with no body" do
+
+ let(:http_method) { :get }
+ let(:data) { nil }
+
+ it "passes the request unmodified" do
+ expect(handle_request).to eq([http_method, url, headers, data])
+ end
+ end
+
+ context "when the request should be serialized" do
+
+ let(:http_method) { :put }
+ let(:data) { {foo: "bar"} }
+ let(:expected_data) { %q[{"foo":"bar"}] }
+
+ context "and the request has a ruby object as the body and no explicit content-type" do
+
+ it "serializes the body to json" do
+ # Headers Hash get mutated, so we start by asserting it's empty:
+ expect(headers).to be_empty
+
+ expect(handle_request).to eq([http_method, url, headers, expected_data])
+
+ # Now the headers Hash should have json content type:
+ expect(headers).to have_key("Content-Type")
+ expect(headers["Content-Type"]).to eq("application/json")
+ end
+ end
+
+ context "ant the request has an explicit content type of json" do
+
+ it "serializes the body to json when content-type is all lowercase" do
+ headers["content-type"] = "application/json"
+
+ expect(handle_request).to eq([http_method, url, headers, expected_data])
+
+ # Content-Type header should be normalized:
+ expect(headers.size).to eq(1)
+ expect(headers).to have_key("Content-Type")
+ expect(headers["Content-Type"]).to eq("application/json")
+ end
+
+ end
+
+ end
+
+ context "when handling a request with an explicit content type other than json" do
+
+ let(:http_method) { :put }
+ let(:data) { "some arbitrary bytes" }
+
+ it "does not serialize the body to json when content type is given as lowercase" do
+ headers["content-type"] = "application/x-binary"
+
+ expect(handle_request).to eq([http_method, url, headers, data])
+
+ # not normalized
+ expect(headers).to eq({"content-type" => "application/x-binary"})
+ end
+
+ it "does not serialize the body to json when content type is given in capitalized form" do
+ headers["Content-Type"] = "application/x-binary"
+
+ expect(handle_request).to eq([http_method, url, headers, data])
+
+ # not normalized
+ expect(headers).to eq({"Content-Type" => "application/x-binary"})
+ end
+
+ end
+
+end
diff --git a/spec/unit/knife/client_delete_spec.rb b/spec/unit/knife/client_delete_spec.rb
index 01b49b3d7c..c7908a0934 100644
--- a/spec/unit/knife/client_delete_spec.rb
+++ b/spec/unit/knife/client_delete_spec.rb
@@ -50,7 +50,7 @@ describe Chef::Knife::ClientDelete do
Chef::ApiClient.should_receive(:load).and_return(@client)
end
- it 'should delete non-validator client if --force is not set' do
+ it 'should delete non-validator client if --delete-validators is not set' do
@knife.config[:delete_validators] = false
@client.should_receive(:destroy).and_return(@client)
@knife.should_receive(:msg)
@@ -58,7 +58,7 @@ describe Chef::Knife::ClientDelete do
@knife.run
end
- it 'should delete non-validator client if --force is set' do
+ it 'should delete non-validator client if --delete-validators is set' do
@knife.config[:delete_validators] = true
@client.should_receive(:destroy).and_return(@client)
@knife.should_receive(:msg)
@@ -66,13 +66,13 @@ describe Chef::Knife::ClientDelete do
@knife.run
end
- it 'should not delete validator client if --force is not set' do
+ it 'should not delete validator client if --delete-validators is not set' do
@client.validator(true)
@knife.ui.should_receive(:fatal)
lambda { @knife.run}.should raise_error(SystemExit)
end
- it 'should delete validator client if --force is set' do
+ it 'should delete validator client if --delete-validators is set' do
@knife.config[:delete_validators] = true
@client.should_receive(:destroy).and_return(@client)
@knife.should_receive(:msg)
diff --git a/spec/unit/knife/cookbook_site_share_spec.rb b/spec/unit/knife/cookbook_site_share_spec.rb
index 28b2a509fd..a46783274b 100644
--- a/spec/unit/knife/cookbook_site_share_spec.rb
+++ b/spec/unit/knife/cookbook_site_share_spec.rb
@@ -34,7 +34,7 @@ describe Chef::Knife::CookbookSiteShare do
@cookbook_loader.stub(:[]).and_return(@cookbook)
Chef::CookbookLoader.stub(:new).and_return(@cookbook_loader)
- @cookbook_uploader = Chef::CookbookUploader.new('herpderp', File.join(CHEF_SPEC_DATA, 'cookbooks'), :rest => "norest")
+ @cookbook_uploader = Chef::CookbookUploader.new('herpderp', :rest => "norest")
Chef::CookbookUploader.stub(:new).and_return(@cookbook_uploader)
@cookbook_uploader.stub(:validate_cookbooks).and_return(true)
Chef::CookbookSiteStreamingUploader.stub(:create_build_dir).and_return(Dir.mktmpdir)
@@ -77,7 +77,7 @@ describe Chef::Knife::CookbookSiteShare do
it 'should make a tarball of the cookbook' do
@knife.should_receive(:shell_out!) do |args|
- args.to_s.should match /tar -czf/
+ args.to_s.should match(/tar -czf/)
end
@knife.run
end
diff --git a/spec/unit/knife/cookbook_upload_spec.rb b/spec/unit/knife/cookbook_upload_spec.rb
index 6a99a80459..e5c9a40cf1 100644
--- a/spec/unit/knife/cookbook_upload_spec.rb
+++ b/spec/unit/knife/cookbook_upload_spec.rb
@@ -61,8 +61,9 @@ describe Chef::Knife::CookbookUpload do
test_cookbook = Chef::CookbookVersion.new('test_cookbook', '/tmp/blah')
cookbook_loader.stub(:each).and_yield("test_cookbook", test_cookbook)
cookbook_loader.stub(:cookbook_names).and_return(["test_cookbook"])
- Chef::CookbookUploader.should_receive(:new).with( kind_of(Array), kind_of(Array),
- {:force=>nil, :concurrency => 3}).and_return(double("Chef::CookbookUploader", :upload_cookbooks=> true))
+ Chef::CookbookUploader.should_receive(:new).
+ with( kind_of(Array), { :force => nil, :concurrency => 3}).
+ and_return(double("Chef::CookbookUploader", :upload_cookbooks=> true))
knife.run
end
end
diff --git a/spec/unit/mixin/template_spec.rb b/spec/unit/mixin/template_spec.rb
index 3aa0b9ba22..63fa81782e 100644
--- a/spec/unit/mixin/template_spec.rb
+++ b/spec/unit/mixin/template_spec.rb
@@ -76,7 +76,7 @@ describe Chef::Mixin::Template, "render_template" do
describe "with a template resource" do
before :each do
@cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, @cookbook_repo) }
+ Chef::Cookbook::FileVendor.fetch_from_disk(@cookbook_repo)
@node = Chef::Node.new
cl = Chef::CookbookLoader.new(@cookbook_repo)
diff --git a/spec/unit/platform_spec.rb b/spec/unit/platform_spec.rb
index 3d7aef98a0..029fc29aae 100644
--- a/spec/unit/platform_spec.rb
+++ b/spec/unit/platform_spec.rb
@@ -254,6 +254,16 @@ describe Chef::Platform do
end
+ it "does not overwrite the platform map when using :default platform" do
+ Chef::Platform.set(
+ :resource => :file,
+ :platform => :default,
+ :provider => "new school"
+ )
+ Chef::Platform.platforms[:default][:file].should eql("new school")
+ Chef::Platform.platforms[:default][:cat].should eql("nice")
+ end
+
end
context "while testing the configured platform data" do
diff --git a/spec/unit/provider/deploy_spec.rb b/spec/unit/provider/deploy_spec.rb
index e6e4566011..c6df0d4fdf 100644
--- a/spec/unit/provider/deploy_spec.rb
+++ b/spec/unit/provider/deploy_spec.rb
@@ -192,6 +192,7 @@ describe Chef::Provider::Deploy do
FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/releases/5")
@provider.run_action(:rollback)
@provider.release_path.should eql("/my/deploy/dir/releases/3")
+ @provider.shared_path.should eql("/my/deploy/dir/shared")
end
it "sets the release path to the specified release, symlinks, and rm's any newer releases on rollback" do
@@ -203,6 +204,7 @@ describe Chef::Provider::Deploy do
FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/releases/20040815162342")
@provider.run_action(:rollback)
@provider.release_path.should eql("/my/deploy/dir/releases/20040700000000")
+ @provider.shared_path.should eql("/my/deploy/dir/shared")
end
it "sets the release path to the penultimate release, symlinks, and rm's the last release on rollback" do
@@ -216,6 +218,7 @@ describe Chef::Provider::Deploy do
FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/releases/20040815162342")
@provider.run_action(:rollback)
@provider.release_path.should eql("/my/deploy/dir/releases/20040700000000")
+ @provider.shared_path.should eql("/my/deploy/dir/shared")
end
describe "if there are no releases to fallback to" do
@@ -255,6 +258,7 @@ describe Chef::Provider::Deploy do
FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/releases/20040815162342")
@provider.run_action(:rollback)
@provider.release_path.should eql("/my/deploy/dir/releases/20040700000000")
+ @provider.shared_path.should eql("/my/deploy/dir/shared")
end
end
diff --git a/spec/unit/provider/env_spec.rb b/spec/unit/provider/env_spec.rb
index 0bc5117e48..dc6176d45c 100644
--- a/spec/unit/provider/env_spec.rb
+++ b/spec/unit/provider/env_spec.rb
@@ -229,4 +229,23 @@ describe Chef::Provider::Env do
@provider.compare_value.should be_true
end
end
+
+ describe "modify_env" do
+ before(:each) do
+ @provider.stub(:create_env).and_return(true)
+ @new_resource.delim ";"
+
+ @current_resource = Chef::Resource::Env.new("FOO")
+ @current_resource.value "C:/foo/bin"
+ @provider.current_resource = @current_resource
+ end
+
+ it "should not modify the variable passed to the resource" do
+ new_value = "C:/bar/bin"
+ passed_value = new_value.dup
+ @new_resource.value(passed_value)
+ @provider.modify_env
+ passed_value.should == new_value
+ end
+ end
end
diff --git a/spec/unit/provider/git_spec.rb b/spec/unit/provider/git_spec.rb
index 2179db15ff..ec1e0927b8 100644
--- a/spec/unit/provider/git_spec.rb
+++ b/spec/unit/provider/git_spec.rb
@@ -224,8 +224,8 @@ SHAS
@provider.clone
end
- it "runs a checkout command with default options" do
- expected_cmd = 'git checkout -b deploy d35af14d41ae22b19da05d7d03a0bafc321b244c'
+ it "runs a checkout command with default options and uses -B to reset branches if necessary" do
+ expected_cmd = 'git checkout -B deploy d35af14d41ae22b19da05d7d03a0bafc321b244c'
@provider.should_receive(:shell_out!).with(expected_cmd, :cwd => "/my/deploy/dir",
:log_tag => "git[web2.0 app]")
@provider.checkout
diff --git a/spec/unit/provider/group/dscl_spec.rb b/spec/unit/provider/group/dscl_spec.rb
index 5a02ee8dfb..8848a01bf2 100644
--- a/spec/unit/provider/group/dscl_spec.rb
+++ b/spec/unit/provider/group/dscl_spec.rb
@@ -240,6 +240,7 @@ describe Chef::Provider::Group::Dscl do
@provider.load_current_resource
@provider.define_resource_requirements
end
+
it "raises an error if the required binary /usr/bin/dscl doesn't exist" do
File.should_receive(:exists?).with("/usr/bin/dscl").and_return(false)
@@ -251,7 +252,7 @@ describe Chef::Provider::Group::Dscl do
lambda { @provider.process_resource_requirements }.should_not raise_error
end
end
-
+
describe "when creating the group" do
it "creates the group, password field, gid, and sets group membership" do
@provider.should_receive(:set_gid).and_return(true)
@@ -294,3 +295,39 @@ describe Chef::Provider::Group::Dscl do
end
end
end
+
+describe 'Test DSCL loading' do
+ before do
+ @node = Chef::Node.new
+ @events = Chef::EventDispatch::Dispatcher.new
+ @run_context = Chef::RunContext.new(@node, {}, @events)
+ @new_resource = Chef::Resource::Group.new("aj")
+ @provider = Chef::Provider::Group::Dscl.new(@new_resource, @run_context)
+ @output = <<-EOF
+AppleMetaNodeLocation: /Local/Default
+Comment:
+ Test Group
+GeneratedUID: AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA
+NestedGroups: AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAB
+Password: *
+PrimaryGroupID: 999
+RealName:
+ TestGroup
+RecordName: com.apple.aj
+RecordType: dsRecTypeStandard:Groups
+GroupMembership: waka bar
+EOF
+ @provider.stub(:safe_dscl).with("read /Groups/aj").and_return(@output)
+ @current_resource = @provider.load_current_resource
+
+ end
+
+ it 'should parse gid properly' do
+ File.stub(:exists?).and_return(true)
+ @current_resource.gid.should eq("999")
+ end
+ it 'should parse members properly' do
+ File.stub(:exists?).and_return(true)
+ @current_resource.members.should eq(['waka', 'bar'])
+ end
+end
diff --git a/spec/unit/provider/http_request_spec.rb b/spec/unit/provider/http_request_spec.rb
index 605287fcc3..3077685b97 100644
--- a/spec/unit/provider/http_request_spec.rb
+++ b/spec/unit/provider/http_request_spec.rb
@@ -53,13 +53,13 @@ describe Chef::Provider::HttpRequest do
it "should inflate a message block at runtime" do
@new_resource.message { "return" }
- @http.should_receive(:get).with("http://www.opscode.com/?message=return", {})
+ @http.should_receive(:get).with("http://www.opscode.com/", {})
@provider.run_action(:get)
@new_resource.should be_updated
end
it "should run a GET request" do
- @http.should_receive(:get).with("http://www.opscode.com/?message=is cool", {})
+ @http.should_receive(:get).with("http://www.opscode.com/", {})
@provider.run_action(:get)
@new_resource.should be_updated
end
@@ -112,25 +112,25 @@ describe Chef::Provider::HttpRequest do
it "should inflate a message block at runtime" do
@new_resource.message { "return" }
- @http.should_receive(:head).with("http://www.opscode.com/?message=return", {}).and_return(nil)
+ @http.should_receive(:head).with("http://www.opscode.com/", {}).and_return(nil)
@provider.run_action(:head)
@new_resource.should be_updated
end
it "should run a HEAD request" do
- @http.should_receive(:head).with("http://www.opscode.com/?message=is cool", {}).and_return(nil)
+ @http.should_receive(:head).with("http://www.opscode.com/", {}).and_return(nil)
@provider.run_action(:head)
@new_resource.should be_updated
end
it "should update a HEAD request with empty string response body (CHEF-4762)" do
- @http.should_receive(:head).with("http://www.opscode.com/?message=is cool", {}).and_return("")
+ @http.should_receive(:head).with("http://www.opscode.com/", {}).and_return("")
@provider.run_action(:head)
@new_resource.should be_updated
end
it "should update a HEAD request with nil response body (CHEF-4762)" do
- @http.should_receive(:head).with("http://www.opscode.com/?message=is cool", {}).and_return(nil)
+ @http.should_receive(:head).with("http://www.opscode.com/", {}).and_return(nil)
@provider.run_action(:head)
@new_resource.should be_updated
end
@@ -138,14 +138,14 @@ describe Chef::Provider::HttpRequest do
it "should not update a HEAD request if a not modified response (CHEF-4762)" do
if_modified_since = File.mtime(__FILE__).httpdate
@new_resource.headers "If-Modified-Since" => if_modified_since
- @http.should_receive(:head).with("http://www.opscode.com/?message=is cool", {"If-Modified-Since" => if_modified_since}).and_return(false)
+ @http.should_receive(:head).with("http://www.opscode.com/", {"If-Modified-Since" => if_modified_since}).and_return(false)
@provider.run_action(:head)
@new_resource.should_not be_updated
end
it "should run a HEAD request with If-Modified-Since header" do
@new_resource.headers "If-Modified-Since" => File.mtime(__FILE__).httpdate
- @http.should_receive(:head).with("http://www.opscode.com/?message=is cool", @new_resource.headers)
+ @http.should_receive(:head).with("http://www.opscode.com/", @new_resource.headers)
@provider.run_action(:head)
end
diff --git a/spec/unit/provider/log_spec.rb b/spec/unit/provider/log_spec.rb
index 8f411e461a..a270ee4822 100644
--- a/spec/unit/provider/log_spec.rb
+++ b/spec/unit/provider/log_spec.rb
@@ -20,80 +20,60 @@ require 'spec_helper'
describe Chef::Provider::Log::ChefLog do
- before(:each) do
- @log_str = "this is my test string to log"
- @node = Chef::Node.new
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, {}, @events)
- end
+ let(:log_str) { "this is my test string to log" }
+
+ let(:node) { Chef::Node.new }
+
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
+
+ let(:new_resource) { Chef::Resource::Log.new(log_str) }
+
+ let(:provider) { Chef::Provider::Log::ChefLog.new(new_resource, run_context) }
it "should be registered with the default platform hash" do
- Chef::Platform.platforms[:default][:log].should_not be_nil
+ expect(Chef::Platform.platforms[:default][:log]).not_to be_nil
end
it "should write the string to the Chef::Log object at default level (info)" do
- @new_resource = Chef::Resource::Log.new(@log_str)
- @provider = Chef::Provider::Log::ChefLog.new(@new_resource, @run_context)
- Chef::Log.should_receive(:info).with(@log_str).and_return(true)
- @provider.action_write
+ expect(Chef::Log).to receive(:info).with(log_str).and_return(true)
+ provider.run_action(:write)
end
it "should write the string to the Chef::Log object at debug level" do
- @new_resource = Chef::Resource::Log.new(@log_str)
- @new_resource.level :debug
- @provider = Chef::Provider::Log::ChefLog.new(@new_resource, @run_context)
- Chef::Log.should_receive(:debug).with(@log_str).and_return(true)
- @provider.action_write
+ new_resource.level :debug
+ expect(Chef::Log).to receive(:debug).with(log_str).and_return(true)
+ provider.run_action(:write)
end
it "should write the string to the Chef::Log object at info level" do
- @new_resource = Chef::Resource::Log.new(@log_str)
- @new_resource.level :info
- @provider = Chef::Provider::Log::ChefLog.new(@new_resource, @run_context)
- Chef::Log.should_receive(:info).with(@log_str).and_return(true)
- @provider.action_write
+ new_resource.level :info
+ expect(Chef::Log).to receive(:info).with(log_str).and_return(true)
+ provider.run_action(:write)
end
it "should write the string to the Chef::Log object at warn level" do
- @new_resource = Chef::Resource::Log.new(@log_str)
- @new_resource.level :warn
- @provider = Chef::Provider::Log::ChefLog.new(@new_resource, @run_context)
- Chef::Log.should_receive(:warn).with(@log_str).and_return(true)
- @provider.action_write
+ new_resource.level :warn
+ expect(Chef::Log).to receive(:warn).with(log_str).and_return(true)
+ provider.run_action(:write)
end
it "should write the string to the Chef::Log object at error level" do
- @new_resource = Chef::Resource::Log.new(@log_str)
- @new_resource.level :error
- @provider = Chef::Provider::Log::ChefLog.new(@new_resource, @run_context)
- Chef::Log.should_receive(:error).with(@log_str).and_return(true)
- @provider.action_write
+ new_resource.level :error
+ expect(Chef::Log).to receive(:error).with(log_str).and_return(true)
+ provider.run_action(:write)
end
it "should write the string to the Chef::Log object at fatal level" do
- @new_resource = Chef::Resource::Log.new(@log_str)
- @new_resource.level :fatal
- @provider = Chef::Provider::Log::ChefLog.new(@new_resource, @run_context)
- Chef::Log.should_receive(:fatal).with(@log_str).and_return(true)
- @provider.action_write
- end
-
- it "should not update the resource if the message was not written to the log" do
- Chef::Log.level = :fatal
- @new_resource = Chef::Resource::Log.new(@log_str)
- @new_resource.level :info
- @provider = Chef::Provider::Log::ChefLog.new(@new_resource, @run_context)
- @provider.action_write
- @new_resource.updated.should be_false
+ new_resource.level :fatal
+ expect(Chef::Log).to receive(:fatal).with(log_str).and_return(true)
+ provider.run_action(:write)
end
- it "should update the resource if the message has been written to the log" do
- Chef::Log.level = :debug
- @new_resource = Chef::Resource::Log.new(@log_str)
- @new_resource.level :info
- @provider = Chef::Provider::Log::ChefLog.new(@new_resource, @run_context)
- @provider.action_write
- @new_resource.updated.should be_true
+ it "should print the string in why-run mode" do
+ Chef::Config[:why_run] = true
+ expect(Chef::Log).to receive(:info).with(log_str).and_return(true)
+ provider.run_action(:write)
end
-
end
diff --git a/spec/unit/provider/mount/mount_spec.rb b/spec/unit/provider/mount/mount_spec.rb
index f55a65ab2a..41fa77e756 100644
--- a/spec/unit/provider/mount/mount_spec.rb
+++ b/spec/unit/provider/mount/mount_spec.rb
@@ -125,11 +125,17 @@ describe Chef::Provider::Mount::Mount do
end
it "should set mounted true if the mount point is found in the mounts list" do
- @provider.stub(:shell_out!).and_return(OpenStruct.new(:stdout => '/dev/sdz1 on /tmp/foo'))
+ @provider.stub(:shell_out!).and_return(OpenStruct.new(:stdout => "/dev/sdz1 on /tmp/foo type ext3 (rw)\n"))
@provider.load_current_resource()
@provider.current_resource.mounted.should be_true
end
+ it "should set mounted false if another mount point beginning with the same path is found in the mounts list" do
+ @provider.stub(:shell_out!).and_return(OpenStruct.new(:stdout => "/dev/sdz1 on /tmp/foobar type ext3 (rw)\n"))
+ @provider.load_current_resource()
+ @provider.current_resource.mounted.should be_false
+ end
+
it "should set mounted true if the symlink target of the device is found in the mounts list" do
# expand the target path to correct specs on Windows
target = ::File.expand_path('/dev/mapper/target')
@@ -437,14 +443,17 @@ describe Chef::Provider::Mount::Mount do
@current_resource.stub(:enabled).and_return(true)
fstab_read = ["/dev/sdz1 /tmp/foo ext3 defaults 1 2\n",
"/dev/sdy1 /tmp/foo ext3 defaults 1 2\n",
- "/dev/sdz1 /tmp/foo ext3 defaults 1 2\n"]
+ "/dev/sdz1 /tmp/foo ext3 defaults 1 2\n",
+ "/dev/sdz1 /tmp/foobar ext3 defaults 1 2\n"]
fstab_write = StringIO.new
::File.stub(:readlines).with("/etc/fstab").and_return(fstab_read)
::File.stub(:open).with("/etc/fstab", "w").and_yield(fstab_write)
@provider.disable_fs
- fstab_write.string.should == "/dev/sdz1 /tmp/foo ext3 defaults 1 2\n/dev/sdy1 /tmp/foo ext3 defaults 1 2\n"
+ fstab_write.string.should == "/dev/sdz1 /tmp/foo ext3 defaults 1 2\n" +
+ "/dev/sdy1 /tmp/foo ext3 defaults 1 2\n" +
+ "/dev/sdz1 /tmp/foobar ext3 defaults 1 2\n"
end
it "should not disable if enabled is false" do
diff --git a/spec/unit/provider/package/paludis_spec.rb b/spec/unit/provider/package/paludis_spec.rb
index bf93ecb2a4..c99600e535 100644
--- a/spec/unit/provider/package/paludis_spec.rb
+++ b/spec/unit/provider/package/paludis_spec.rb
@@ -59,7 +59,7 @@ PKG_STATUS
end
it "should run pkg info with the package name" do
- @provider.should_receive(:shell_out!).with("cave -L warning print-ids -m \"*/#{@new_resource.package_name.split('/').last}\" -f \"%c/%p %v %r\n\"").and_return(@shell_out)
+ @provider.should_receive(:shell_out!).with("cave -L warning print-ids -M none -m \"*/#{@new_resource.package_name.split('/').last}\" -f \"%c/%p %v %r\n\"").and_return(@shell_out)
@provider.load_current_resource
end
@@ -86,13 +86,13 @@ INSTALLED
context "when installing a package" do
it "should run pkg install with the package name and version" do
- @provider.should_receive(:shell_out!).with("cave -L warning resolve -x \"=net/ntp-4.2.6_p5-r2\"")
+ @provider.should_receive(:shell_out!).with("cave -L warning resolve -x \"=net/ntp-4.2.6_p5-r2\"", {:timeout=>@new_resource.timeout})
@provider.install_package("net/ntp", "4.2.6_p5-r2")
end
it "should run pkg install with the package name and version and options if specified" do
- @provider.should_receive(:shell_out!).with("cave -L warning resolve -x --preserve-world \"=net/ntp-4.2.6_p5-r2\"")
+ @provider.should_receive(:shell_out!).with("cave -L warning resolve -x --preserve-world \"=net/ntp-4.2.6_p5-r2\"", {:timeout=>@new_resource.timeout})
@new_resource.stub(:options).and_return("--preserve-world")
@provider.install_package("net/ntp", "4.2.6_p5-r2")
end
@@ -102,7 +102,7 @@ INSTALLED
sys-process/lsof 4.87 arbor
sys-process/lsof 4.87 x86_64
PKG_STATUS
- @provider.should_receive(:shell_out!).with("cave -L warning resolve -x \"=sys-process/lsof-4.87\"")
+ @provider.should_receive(:shell_out!).with("cave -L warning resolve -x \"=sys-process/lsof-4.87\"", {:timeout=>@new_resource.timeout})
@provider.install_package("sys-process/lsof", "4.87")
end
@@ -120,7 +120,7 @@ PKG_STATUS
context "when upgrading a package" do
it "should run pkg install with the package name and version" do
- @provider.should_receive(:shell_out!).with("cave -L warning resolve -x \"=net/ntp-4.2.6_p5-r2\"")
+ @provider.should_receive(:shell_out!).with("cave -L warning resolve -x \"=net/ntp-4.2.6_p5-r2\"", {:timeout=>@new_resource.timeout})
@provider.upgrade_package("net/ntp", "4.2.6_p5-r2")
end
end
diff --git a/spec/unit/provider/package/rpm_spec.rb b/spec/unit/provider/package/rpm_spec.rb
index 50e6528317..6e46cf5e98 100644
--- a/spec/unit/provider/package/rpm_spec.rb
+++ b/spec/unit/provider/package/rpm_spec.rb
@@ -80,6 +80,18 @@ describe Chef::Provider::Package::Rpm do
@provider.stub(:popen4).and_return(status)
lambda { @provider.run_action(:any) }.should raise_error(Chef::Exceptions::Package)
end
+
+ it "should not detect the package name as version when not installed" do
+ @status = double("Status", :exitstatus => -1)
+ @stdout = StringIO.new("package openssh-askpass is not installed")
+ @new_resource = Chef::Resource::Package.new("openssh-askpass")
+ @new_resource.source 'openssh-askpass'
+ @provider = Chef::Provider::Package::Rpm.new(@new_resource, @run_context)
+ @provider.should_receive(:popen4).with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' openssh-askpass").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
+ @provider.should_receive(:popen4).with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' openssh-askpass").and_return(@status)
+ @provider.load_current_resource
+ @provider.current_resource.version.should be_nil
+ end
end
describe "after the current resource is loaded" do
diff --git a/spec/unit/provider/package/zypper_spec.rb b/spec/unit/provider/package/zypper_spec.rb
index c437631309..87f02d7794 100644
--- a/spec/unit/provider/package/zypper_spec.rb
+++ b/spec/unit/provider/package/zypper_spec.rb
@@ -146,25 +146,37 @@ describe Chef::Provider::Package::Zypper do
end
describe "remove_package" do
- it "should run zypper remove with the package name" do
- Chef::Config.stub(:[]).with(:zypper_check_gpg).and_return(true)
- @provider.should_receive(:shell_out!).with(
- "zypper --non-interactive remove emacs=1.0")
- @provider.remove_package("emacs", "1.0")
+
+ context "when package version is not explicitly specified" do
+ it "should run zypper remove with the package name" do
+ Chef::Config.stub(:[]).with(:zypper_check_gpg).and_return(true)
+ @provider.should_receive(:shell_out!).with(
+ "zypper --non-interactive remove emacs")
+ @provider.remove_package("emacs", nil)
+ end
end
- it "should run zypper remove without gpg checks" do
- Chef::Config.stub(:[]).with(:zypper_check_gpg).and_return(false)
- @provider.should_receive(:shell_out!).with(
+
+ context "when package version is explicitly specified" do
+ it "should run zypper remove with the package name" do
+ Chef::Config.stub(:[]).with(:zypper_check_gpg).and_return(true)
+ @provider.should_receive(:shell_out!).with(
+ "zypper --non-interactive remove emacs=1.0")
+ @provider.remove_package("emacs", "1.0")
+ end
+ it "should run zypper remove without gpg checks" do
+ Chef::Config.stub(:[]).with(:zypper_check_gpg).and_return(false)
+ @provider.should_receive(:shell_out!).with(
+ "zypper --non-interactive --no-gpg-checks remove emacs=1.0")
+ @provider.remove_package("emacs", "1.0")
+ end
+ it "should warn about gpg checks on zypper remove" do
+ Chef::Log.should_receive(:warn).with(
+ /All packages will be installed without gpg signature checks/)
+ @provider.should_receive(:shell_out!).with(
"zypper --non-interactive --no-gpg-checks remove emacs=1.0")
- @provider.remove_package("emacs", "1.0")
- end
- it "should warn about gpg checks on zypper remove" do
- Chef::Log.should_receive(:warn).with(
- /All packages will be installed without gpg signature checks/)
- @provider.should_receive(:shell_out!).with(
- "zypper --non-interactive --no-gpg-checks remove emacs=1.0")
- @provider.remove_package("emacs", "1.0")
+ @provider.remove_package("emacs", "1.0")
+ end
end
end
diff --git a/spec/unit/provider/package_spec.rb b/spec/unit/provider/package_spec.rb
index 33b4f8186a..375a0d0646 100644
--- a/spec/unit/provider/package_spec.rb
+++ b/spec/unit/provider/package_spec.rb
@@ -339,7 +339,7 @@ describe Chef::Provider::Package do
describe "when given a response file" do
before(:each) do
@cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, @cookbook_repo) }
+ Chef::Cookbook::FileVendor.fetch_from_disk(@cookbook_repo)
@node = Chef::Node.new
cl = Chef::CookbookLoader.new(@cookbook_repo)
diff --git a/spec/unit/provider/remote_directory_spec.rb b/spec/unit/provider/remote_directory_spec.rb
index d3f1438f0f..b986e2c8ad 100644
--- a/spec/unit/provider/remote_directory_spec.rb
+++ b/spec/unit/provider/remote_directory_spec.rb
@@ -35,7 +35,7 @@ describe Chef::Provider::RemoteDirectory do
@resource.cookbook('openldap')
@cookbook_repo = ::File.expand_path(::File.join(CHEF_SPEC_DATA, "cookbooks"))
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, @cookbook_repo) }
+ Chef::Cookbook::FileVendor.fetch_from_disk(@cookbook_repo)
@node = Chef::Node.new
cl = Chef::CookbookLoader.new(@cookbook_repo)
diff --git a/spec/unit/provider/template/content_spec.rb b/spec/unit/provider/template/content_spec.rb
index dfc5d21c2a..b419e70519 100644
--- a/spec/unit/provider/template/content_spec.rb
+++ b/spec/unit/provider/template/content_spec.rb
@@ -36,7 +36,7 @@ describe Chef::Provider::Template::Content do
let(:run_context) do
cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, cookbook_repo) }
+ Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_repo)
cl = Chef::CookbookLoader.new(cookbook_repo)
cl.load_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cl)
diff --git a/spec/unit/provider_spec.rb b/spec/unit/provider_spec.rb
index 363649ec46..9b89fc1888 100644
--- a/spec/unit/provider_spec.rb
+++ b/spec/unit/provider_spec.rb
@@ -61,6 +61,18 @@ describe Chef::Provider do
@provider = Chef::Provider.new(@resource, @run_context)
end
+ it "should mixin shell_out" do
+ expect(@provider.respond_to?(:shell_out)).to be true
+ end
+
+ it "should mixin shell_out!" do
+ expect(@provider.respond_to?(:shell_out!)).to be true
+ end
+
+ it "should mixin shell_out_with_systems_locale" do
+ expect(@provider.respond_to?(:shell_out_with_systems_locale)).to be true
+ end
+
it "should store the resource passed to new as new_resource" do
@provider.new_resource.should eql(@resource)
end
diff --git a/spec/unit/resource/user_spec.rb b/spec/unit/resource/user_spec.rb
index 9972ddbba1..70b866202b 100644
--- a/spec/unit/resource/user_spec.rb
+++ b/spec/unit/resource/user_spec.rb
@@ -54,6 +54,10 @@ describe Chef::Resource::User, "initialize" do
@resource.supports[:non_unique].should eql(false)
end
+ it "should set force to false" do
+ @resource.force.should eql(false)
+ end
+
%w{create remove modify manage lock unlock}.each do |action|
it "should allow action #{action}" do
@resource.allowed_actions.detect { |a| a == action.to_sym }.should eql(action.to_sym)
diff --git a/spec/unit/resource_reporter_spec.rb b/spec/unit/resource_reporter_spec.rb
index a7ec665495..fe6a895b5a 100644
--- a/spec/unit/resource_reporter_spec.rb
+++ b/spec/unit/resource_reporter_spec.rb
@@ -21,6 +21,7 @@
require File.expand_path("../../spec_helper", __FILE__)
require 'chef/resource_reporter'
+require 'socket'
describe Chef::ResourceReporter do
before(:all) do
@@ -707,5 +708,52 @@ describe Chef::ResourceReporter do
@resource_reporter.run_completed(@node)
end
end
+
+ context "when data report post is enabled and the server response fails" do
+ before do
+ @enable_reporting_url_fatals = Chef::Config[:enable_reporting_url_fatals]
+ Chef::Config[:enable_reporting_url_fatals] = true
+ # this call doesn't matter for this context
+ @rest_client.stub(:create_url)
+ end
+
+ after do
+ Chef::Config[:enable_reporting_url_fatals] = @enable_reporting_url_fatals
+ end
+
+ it "should log 4xx errors" do
+ response = Net::HTTPClientError.new("forbidden", "403", "Forbidden")
+ error = Net::HTTPServerException.new("403 message", response)
+ @rest_client.stub(:raw_http_request).and_raise(error)
+ Chef::Log.should_receive(:error).with(/403/)
+
+ @resource_reporter.post_reporting_data
+ end
+
+ it "should log error 5xx errors" do
+ response = Net::HTTPServerError.new("internal error", "500", "Internal Server Error")
+ error = Net::HTTPFatalError.new("500 message", response)
+ @rest_client.stub(:raw_http_request).and_raise(error)
+ Chef::Log.should_receive(:error).with(/500/)
+
+ @resource_reporter.post_reporting_data
+ end
+
+ it "should log if a socket error happens" do
+ @rest_client.stub(:raw_http_request).and_raise(SocketError.new("test socket error"))
+ Chef::Log.should_receive(:error).with(/test socket error/)
+
+ @resource_reporter.post_reporting_data
+
+ end
+
+ it "should raise if an unkwown error happens" do
+ @rest_client.stub(:raw_http_request).and_raise(Exception.new)
+
+ lambda {
+ @resource_reporter.post_reporting_data
+ }.should raise_error(Exception)
+ end
+ end
end
end
diff --git a/spec/unit/role_spec.rb b/spec/unit/role_spec.rb
index 9ff75566b4..05ebf282db 100644
--- a/spec/unit/role_spec.rb
+++ b/spec/unit/role_spec.rb
@@ -296,6 +296,12 @@ EOR
File.should_not_receive(:exists?)
lambda {@role.class.from_disk("lolcat")}.should raise_error(Chef::Exceptions::DuplicateRole)
end
+
+ it "should not raise an exception if two files exist with a similar name" do
+ Dir.should_receive(:glob).and_return(["#{Chef::Config[:role_path]}/memes/lolcat.rb", "#{Chef::Config[:role_path]}/super_lolcat.rb"])
+ File.should_not_receive(:exists?)
+ lambda {@role.class.from_disk("lolcat")}.should_not raise_error(Chef::Exceptions::DuplicateRole)
+ end
end
describe "when loading from disk and role_path is an array" do
diff --git a/spec/unit/shell/shell_session_spec.rb b/spec/unit/shell/shell_session_spec.rb
index 92a2e5d538..f49c9fc805 100644
--- a/spec/unit/shell/shell_session_spec.rb
+++ b/spec/unit/shell/shell_session_spec.rb
@@ -50,6 +50,7 @@ end
describe Shell::ClientSession do
before do
Chef::Config[:shell_config] = { :override_runlist => [Chef::RunList::RunListItem.new('shell::override')] }
+ @chef_rest = double("Chef::REST")
@session = Shell::ClientSession.instance
@node = Chef::Node.build("foo")
@session.node = @node
@@ -66,6 +67,7 @@ describe Shell::ClientSession do
@expansion = Chef::RunList::RunListExpansion.new(@node.chef_environment, [])
@node.run_list.should_receive(:expand).with(@node.chef_environment).and_return(@expansion)
+ Chef::REST.should_receive(:new).with(Chef::Config[:chef_server_url]).and_return(@chef_rest)
@session.rebuild_context
end
diff --git a/spec/unit/version_constraint_spec.rb b/spec/unit/version_constraint_spec.rb
index 4184689e2b..dfa4740d51 100644
--- a/spec/unit/version_constraint_spec.rb
+++ b/spec/unit/version_constraint_spec.rb
@@ -148,4 +148,32 @@ describe Chef::VersionConstraint do
vc.should_not include "0.3.0"
end
end
+
+ describe 'to_s' do
+ it 'shows a patch-level if one is given' do
+ vc = Chef::VersionConstraint.new '~> 1.2.0'
+
+ vc.to_s.should == '~> 1.2.0'
+ end
+
+ it 'shows no patch-level if one is not given' do
+ vc = Chef::VersionConstraint.new '~> 1.2'
+
+ vc.to_s.should == '~> 1.2'
+ end
+ end
+
+ describe 'inspect' do
+ it 'shows a patch-level if one is given' do
+ vc = Chef::VersionConstraint.new '~> 1.2.0'
+
+ vc.inspect.should == '(~> 1.2.0)'
+ end
+
+ it 'shows no patch-level if one is not given' do
+ vc = Chef::VersionConstraint.new '~> 1.2'
+
+ vc.inspect.should == '(~> 1.2)'
+ end
+ end
end