summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md3
-rw-r--r--CHANGELOG.md42
-rw-r--r--Gemfile.lock50
-rw-r--r--VERSION2
-rw-r--r--acceptance/.shared/kitchen_acceptance/.kitchen.ec2.yml4
-rw-r--r--acceptance/Gemfile.lock18
-rw-r--r--chef-config/lib/chef-config/config.rb22
-rw-r--r--chef-config/lib/chef-config/exceptions.rb1
-rw-r--r--chef-config/lib/chef-config/version.rb2
-rw-r--r--chef-config/spec/unit/config_spec.rb85
-rw-r--r--distro/common/html/knife_bootstrap.html2
-rw-r--r--distro/common/man/man1/README.md4
-rw-r--r--distro/common/man/man1/knife-client.12
-rw-r--r--kitchen-tests/Berksfile.lock15
-rw-r--r--kitchen-tests/Gemfile.lock23
-rw-r--r--lib/chef/application.rb22
-rw-r--r--lib/chef/application/client.rb4
-rw-r--r--lib/chef/application/solo.rb2
-rw-r--r--lib/chef/chef_class.rb1
-rw-r--r--lib/chef/chef_fs/file_system/chef_server/versioned_cookbook_dir.rb2
-rw-r--r--lib/chef/dsl/core.rb2
-rw-r--r--lib/chef/dsl/declare_resource.rb4
-rw-r--r--lib/chef/dsl/method_missing.rb2
-rw-r--r--lib/chef/dsl/recipe.rb2
-rw-r--r--lib/chef/dsl/universal.rb2
-rw-r--r--lib/chef/http.rb7
-rw-r--r--lib/chef/knife.rb22
-rw-r--r--lib/chef/mixin/powershell_out.rb2
-rw-r--r--lib/chef/mixin/shell_out.rb2
-rw-r--r--lib/chef/node.rb4
-rw-r--r--lib/chef/node/attribute.rb166
-rw-r--r--lib/chef/node/attribute_collections.rb43
-rw-r--r--lib/chef/node/common_api.rb6
-rw-r--r--lib/chef/node/immutable_collections.rb95
-rw-r--r--lib/chef/node/mixin/deep_merge_cache.rb61
-rw-r--r--lib/chef/node/mixin/immutablize_array.rb67
-rw-r--r--lib/chef/node/mixin/immutablize_hash.rb54
-rw-r--r--lib/chef/node/mixin/state_tracking.rb71
-rw-r--r--lib/chef/provider/cron.rb2
-rw-r--r--lib/chef/provider/group/suse.rb27
-rw-r--r--lib/chef/provider/package.rb12
-rw-r--r--lib/chef/provider/package/windows/exe.rb7
-rw-r--r--lib/chef/provider/package/windows/msi.rb2
-rw-r--r--lib/chef/provider/ruby_block.rb2
-rw-r--r--lib/chef/provider/user.rb10
-rw-r--r--lib/chef/resource.rb24
-rw-r--r--lib/chef/resource/file.rb2
-rw-r--r--lib/chef/resource/scm.rb8
-rw-r--r--lib/chef/resource/yum_repository.rb2
-rw-r--r--lib/chef/run_context.rb12
-rw-r--r--lib/chef/version.rb2
-rw-r--r--omnibus/Gemfile.lock25
-rw-r--r--omnibus/README.md2
-rw-r--r--omnibus_overrides.rb2
-rw-r--r--spec/functional/resource/group_spec.rb1
-rw-r--r--spec/functional/resource/user/useradd_spec.rb6
-rw-r--r--spec/integration/knife/data_bag_create_spec.rb3
-rw-r--r--spec/spec_helper.rb4
-rw-r--r--spec/support/shared/integration/app_server_support.rb2
-rw-r--r--spec/unit/http_spec.rb2
-rw-r--r--spec/unit/knife/core/gem_glob_loader_spec.rb2
-rw-r--r--spec/unit/knife_spec.rb31
-rw-r--r--spec/unit/mixin/powershell_out_spec.rb26
-rw-r--r--spec/unit/node/vivid_mash_spec.rb116
-rw-r--r--spec/unit/node_spec.rb137
-rw-r--r--spec/unit/provider/deploy_spec.rb2
-rw-r--r--spec/unit/provider/group/suse_spec.rb90
-rw-r--r--spec/unit/provider/package/windows_spec.rb6
-rw-r--r--spec/unit/provider/remote_file/content_spec.rb2
-rw-r--r--spec/unit/provider/user_spec.rb6
-rw-r--r--spec/unit/resource/apt_repository_spec.rb2
-rw-r--r--version_policy.rb2
72 files changed, 1007 insertions, 492 deletions
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index a15e5747cc..aca7c10237 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -11,6 +11,5 @@ StackOverflow discussion that's relevant]
- [ ] New functionality includes tests
- [ ] All tests pass
-- [ ] Documentation, especially RELEASE\_NOTES.md, has been updated if
- required
+- [ ] RELEASE\_NOTES.md, has been updated if required (not required for bugfixes, required for API changes)
- [ ] All commits have been signed-off for the Developer Certificate of Origin. See <https://github.com/chef/chef/blob/master/CONTRIBUTING.md#developer-certification-of-origin-dco>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d940293470..d414d611e8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -726,7 +726,7 @@ of partial templates.
Typo fixes
* [**Tim Smith**](https://github.com/tas50)
Typo fixes
-* [Pull 2505](https://github.com/opscode/chef/pull/2505) Make Chef handle URIs in a case-insensitive manner
+* [Pull 2505](https://github.com/chef/chef/pull/2505) Make Chef handle URIs in a case-insensitive manner
* [**Phil Dibowitz**](https://github.com/jaymzh):
Drop SSL warnings now that we have a safe default
* [Pull 2684](https://github.com/chef/chef/pull/2684) Remove ole_initialize/uninitialize which cause problems with Ruby >= 2
@@ -812,32 +812,32 @@ of partial templates.
## 12.0.3
* [**Phil Dibowitz**](https://github.com/jaymzh):
-[Issue 2594](https://github.com/opscode/chef/issues/2594) Restore missing require in `digester`.
+[Issue 2594](https://github.com/chef/chef/issues/2594) Restore missing require in `digester`.
## 12.0.2
-* [Issue 2578](https://github.com/opscode/chef/issues/2578) Check that `installed` is not empty for `keg_only` formula in Homebrew provider
-* [Issue 2609](https://github.com/opscode/chef/issues/2609) Resolve the circular dependency between ProviderResolver and Resource.
-* [Issue 2596](https://github.com/opscode/chef/issues/2596) Fix nodes not writing to disk
-* [Issue 2580](https://github.com/opscode/chef/issues/2580) Make sure the relative paths are preserved when using link resource.
-* [Pull 2630](https://github.com/opscode/chef/pull/2630) Improve knife's SSL error messaging
-* [Issue 2606](https://github.com/opscode/chef/issues/2606) chef 12 ignores default_release for apt_package
-* [Issue 2602](https://github.com/opscode/chef/issues/2602) Fix `subscribes` resource notifications.
-* [Issue 2578](https://github.com/opscode/chef/issues/2578) Check that `installed` is not empty for `keg_only` formula in Homebrew provider.
+* [Issue 2578](https://github.com/chef/chef/issues/2578) Check that `installed` is not empty for `keg_only` formula in Homebrew provider
+* [Issue 2609](https://github.com/chef/chef/issues/2609) Resolve the circular dependency between ProviderResolver and Resource.
+* [Issue 2596](https://github.com/chef/chef/issues/2596) Fix nodes not writing to disk
+* [Issue 2580](https://github.com/chef/chef/issues/2580) Make sure the relative paths are preserved when using link resource.
+* [Pull 2630](https://github.com/chef/chef/pull/2630) Improve knife's SSL error messaging
+* [Issue 2606](https://github.com/chef/chef/issues/2606) chef 12 ignores default_release for apt_package
+* [Issue 2602](https://github.com/chef/chef/issues/2602) Fix `subscribes` resource notifications.
+* [Issue 2578](https://github.com/chef/chef/issues/2578) Check that `installed` is not empty for `keg_only` formula in Homebrew provider.
* [**gh2k**](https://github.com/gh2k):
- [Issue 2625](https://github.com/opscode/chef/issues/2625) Fix missing `shell_out!` for `windows_package` resource
+ [Issue 2625](https://github.com/chef/chef/issues/2625) Fix missing `shell_out!` for `windows_package` resource
* [**BackSlasher**](https://github.com/BackSlasher):
- [Issue 2634](https://github.com/opscode/chef/issues/2634) Fix `option ':command' is not a valid option` error in subversion provider.
+ [Issue 2634](https://github.com/chef/chef/issues/2634) Fix `option ':command' is not a valid option` error in subversion provider.
* [**Seth Vargo**](https://github.com/sethvargo):
- [Issue 2345](https://github.com/opscode/chef/issues/2345) Allow knife to install cookbooks with metadata.json.
+ [Issue 2345](https://github.com/chef/chef/issues/2345) Allow knife to install cookbooks with metadata.json.
## 12.0.1
-* [Issue 2552](https://github.com/opscode/chef/issues/2552) Create constant for LWRP before calling `provides`
-* [Issue 2545](https://github.com/opscode/chef/issues/2545) `path` attribute of `execute` resource is restored to provide backwards compatibility with Chef 11.
-* [Issue 2565](https://github.com/opscode/chef/issues/2565) Fix `Chef::Knife::Core::BootstrapContext` constructor for knife-windows compat.
-* [Issue 2566](https://github.com/opscode/chef/issues/2566) Make sure Client doesn't raise error when interval is set on Windows.
-* [Issue 2560](https://github.com/opscode/chef/issues/2560) Fix `uninitialized constant Windows::Constants` in `windows_eventlog`.
-* [Issue 2563](https://github.com/opscode/chef/issues/2563) Make sure the Chef Client rpm packages are signed with GPG keys correctly.
+* [Issue 2552](https://github.com/chef/chef/issues/2552) Create constant for LWRP before calling `provides`
+* [Issue 2545](https://github.com/chef/chef/issues/2545) `path` attribute of `execute` resource is restored to provide backwards compatibility with Chef 11.
+* [Issue 2565](https://github.com/chef/chef/issues/2565) Fix `Chef::Knife::Core::BootstrapContext` constructor for knife-windows compat.
+* [Issue 2566](https://github.com/chef/chef/issues/2566) Make sure Client doesn't raise error when interval is set on Windows.
+* [Issue 2560](https://github.com/chef/chef/issues/2560) Fix `uninitialized constant Windows::Constants` in `windows_eventlog`.
+* [Issue 2563](https://github.com/chef/chef/issues/2563) Make sure the Chef Client rpm packages are signed with GPG keys correctly.
## 12.0.0
@@ -950,7 +950,7 @@ of partial templates.
* [**Ionuț Arțăriși**](https://github.com/mapleoin):
Changed the default group provider to gpasswd on SLES versions 12 and higher.
* [**Noah Kantrowitz**](https://github.com/coderanger):
- Implemented [RFC017 - File Specificity Overhaul](https://github.com/opscode/chef-rfc/blob/master/rfc017-file-specificity.md).
+ Implemented [RFC017 - File Specificity Overhaul](https://github.com/chef/chef-rfc/blob/master/rfc017-file-specificity.md).
* [**James Bence**](https://github.com/jbence):
Improved the reliability of Git provider by making it to be more specific when selecting tags.
* [**Jean Mertz**](https://github.com/JeanMertz):
@@ -988,7 +988,7 @@ of partial templates.
### Chef Contributions
* ruby 1.9.3 support is dropped
-* Added RFC-023 Chef 12 Attribute Changes (https://github.com/opscode/chef-rfc/blob/master/rfc023-chef-12-attributes-changes.md)
+* Added RFC-023 Chef 12 Attribute Changes (https://github.com/chef/chef-rfc/blob/master/rfc023-chef-12-attributes-changes.md)
* Added os/platform_family options to provides syntax on the Chef::Resource DSL
* Added provides methods to the Chef::Provider DSL
* Added supported?(resource, action) class method to all Providers for late-evaluation if a provider can handle a
diff --git a/Gemfile.lock b/Gemfile.lock
index 9effc84d42..2fd38c1bc1 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,6 +1,6 @@
GIT
remote: https://github.com/chef/chef-server
- revision: 6fde9680c6efdcd0792bec840b7fe7f6fbee790f
+ revision: 77a662df32c79865b2195cc398d7e121c7048ff3
specs:
oc-chef-pedant (2.2.0)
activesupport (>= 4.2.7.1, < 6.0)
@@ -16,7 +16,7 @@ GIT
GIT
remote: https://github.com/chef/chefstyle.git
- revision: c36dcbd6c2c21d2e19db77d9fbdf2402d0bacccf
+ revision: 6d24969bd7c5471e089bd47f45e4832d03e9f8a2
branch: master
specs:
chefstyle (0.4.0)
@@ -33,10 +33,10 @@ GIT
PATH
remote: .
specs:
- chef (12.15.26)
+ chef (12.16.23)
addressable
bundler (>= 1.10)
- chef-config (= 12.15.26)
+ chef-config (= 12.16.23)
chef-zero (>= 4.8)
diff-lcs (~> 1.2, >= 1.2.4)
erubis (~> 2.7)
@@ -62,10 +62,10 @@ PATH
specinfra (~> 2.10)
syslog-logger (~> 1.6)
uuidtools (~> 2.1.5)
- chef (12.15.26-universal-mingw32)
+ chef (12.16.23-universal-mingw32)
addressable
bundler (>= 1.10)
- chef-config (= 12.15.26)
+ chef-config (= 12.16.23)
chef-zero (>= 4.8)
diff-lcs (~> 1.2, >= 1.2.4)
erubis (~> 2.7)
@@ -106,7 +106,7 @@ PATH
PATH
remote: chef-config
specs:
- chef-config (12.15.26)
+ chef-config (12.16.23)
addressable
fuzzyurl
mixlib-config (~> 2.0)
@@ -125,12 +125,12 @@ GEM
mixlib-cli (~> 1.4)
artifactory (2.5.0)
ast (2.3.0)
- aws-sdk (2.6.5)
- aws-sdk-resources (= 2.6.5)
- aws-sdk-core (2.6.5)
+ aws-sdk (2.6.9)
+ aws-sdk-resources (= 2.6.9)
+ aws-sdk-core (2.6.9)
jmespath (~> 1.0)
- aws-sdk-resources (2.6.5)
- aws-sdk-core (= 2.6.5)
+ aws-sdk-resources (2.6.9)
+ aws-sdk-core (= 2.6.9)
aws-sdk-v1 (1.66.0)
json (~> 1.4)
nokogiri (>= 1.4.4)
@@ -178,6 +178,7 @@ GEM
url
coderay (1.1.1)
concurrent-ruby (1.0.2)
+ connection_pool (2.2.0)
cucumber (2.4.0)
builder (>= 2.1.2)
cucumber-core (~> 1.5.0)
@@ -299,10 +300,11 @@ GEM
mixlib-log
mixlib-cli (1.7.0)
mixlib-config (2.2.4)
- mixlib-install (2.0.3)
+ mixlib-install (2.1.1)
artifactory
mixlib-shellout
mixlib-versioning
+ thor
mixlib-log (1.7.1)
mixlib-shellout (2.2.7)
mixlib-shellout (2.2.7-universal-mingw32)
@@ -313,7 +315,8 @@ GEM
multi_test (0.1.2)
multi_xml (0.5.5)
multipart-post (2.0.0)
- net-http-persistent (2.9.4)
+ net-http-persistent (3.0.0)
+ connection_pool (~> 2.2)
net-http-pipeline (1.0.1)
net-http-spy (0.2.1)
net-scp (1.2.1)
@@ -328,12 +331,10 @@ GEM
net-ssh-gateway (>= 1.2.0)
net-telnet (0.1.1)
netrc (0.11.0)
- nokogiri (1.6.8)
+ nokogiri (1.6.8.1)
mini_portile2 (~> 2.1.0)
- pkg-config (~> 1.1.7)
- nokogiri (1.6.8-x86-mingw32)
+ nokogiri (1.6.8.1-x86-mingw32)
mini_portile2 (~> 2.1.0)
- pkg-config (~> 1.1.7)
nori (2.6.0)
oauth2 (1.2.0)
faraday (>= 0.8, < 0.10)
@@ -357,16 +358,15 @@ GEM
wmi-lite (~> 1.0)
parser (2.3.1.4)
ast (~> 2.2)
- pkg-config (1.1.7)
plist (3.2.0)
poise (2.7.1)
halite (~> 1.0)
- poise-boiler (1.13.0)
+ poise-boiler (1.13.1)
bundler
chefspec (~> 5.0)
codeclimate-test-reporter (~> 0.4)
codecov (~> 0.0, >= 0.0.2)
- foodcritic (~> 8.0)
+ foodcritic (>= 7, < 9)
fuubar (~> 2.0)
git (~> 1.2)
halite (~> 1.2)
@@ -461,19 +461,19 @@ GEM
sawyer (0.7.0)
addressable (>= 2.3.5, < 2.5)
faraday (~> 0.8, < 0.10)
- serverspec (2.36.1)
+ serverspec (2.37.1)
multi_json
rspec (~> 3.0)
rspec-its
specinfra (~> 2.53)
- sfl (2.2)
+ sfl (2.3)
simplecov (0.12.0)
docile (~> 1.1.0)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.0)
slop (3.6.0)
- specinfra (2.63.1)
+ specinfra (2.63.3)
net-scp
net-ssh (>= 2.7, < 4.0)
net-telnet
@@ -539,7 +539,7 @@ GEM
ffi-win32-extensions
windows-api (0.4.4)
win32-api (>= 1.4.5)
- winrm (2.0.3)
+ winrm (2.1.0)
builder (>= 2.1.2)
erubis (~> 2.7)
gssapi (~> 1.2)
diff --git a/VERSION b/VERSION
index be30b82b5e..4e601d4e44 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-12.15.26 \ No newline at end of file
+12.16.23 \ No newline at end of file
diff --git a/acceptance/.shared/kitchen_acceptance/.kitchen.ec2.yml b/acceptance/.shared/kitchen_acceptance/.kitchen.ec2.yml
index 209b7fa979..caefef49ea 100644
--- a/acceptance/.shared/kitchen_acceptance/.kitchen.ec2.yml
+++ b/acceptance/.shared/kitchen_acceptance/.kitchen.ec2.yml
@@ -10,7 +10,9 @@ end
driver:
name: ec2
tags:
- X-Project: chef-ci-acceptance
+ X-Dept: Eng
+ X-Contact: product-team
+ X-Application: chef-ci-acceptance
aws_ssh_key_id: <%= ENV['AWS_SSH_KEY_ID'] || ENV['USER'] || ENV['USERNAME'] %>
# test-specific stuff
region: us-west-2
diff --git a/acceptance/Gemfile.lock b/acceptance/Gemfile.lock
index 55da7b77a8..8fc49431b7 100644
--- a/acceptance/Gemfile.lock
+++ b/acceptance/Gemfile.lock
@@ -11,12 +11,12 @@ GEM
specs:
addressable (2.4.0)
artifactory (2.5.0)
- aws-sdk (2.6.5)
- aws-sdk-resources (= 2.6.5)
- aws-sdk-core (2.6.5)
+ aws-sdk (2.6.9)
+ aws-sdk-resources (= 2.6.9)
+ aws-sdk-core (2.6.9)
jmespath (~> 1.0)
- aws-sdk-resources (2.6.5)
- aws-sdk-core (= 2.6.5)
+ aws-sdk-resources (2.6.9)
+ aws-sdk-core (= 2.6.9)
berkshelf (4.3.5)
addressable (~> 2.3, >= 2.3.4)
berkshelf-api-client (~> 2.0, >= 2.0.2)
@@ -53,7 +53,7 @@ GEM
celluloid-io (0.16.2)
celluloid (>= 0.16.0)
nio4r (>= 1.1.0)
- chef-config (12.14.89)
+ chef-config (12.15.19)
addressable
fuzzyurl
mixlib-config (~> 2.0)
@@ -61,7 +61,7 @@ GEM
cleanroom (1.0.0)
coderay (1.1.1)
diff-lcs (1.2.5)
- docker-api (1.32.0)
+ docker-api (1.32.1)
excon (>= 0.38.0)
json
erubis (2.7.0)
@@ -77,7 +77,7 @@ GEM
hashie (3.4.6)
hitimes (1.2.4)
httpclient (2.7.2)
- inspec (1.0.0)
+ inspec (1.2.0)
hashie (~> 3.4)
json (>= 1.8, < 3.0)
method_source (~> 0.8)
@@ -211,7 +211,7 @@ GEM
hashie (>= 2.0.2, < 4.0.0)
windows_chef_zero (2.0.0)
test-kitchen (>= 1.2.1)
- winrm (2.0.3)
+ winrm (2.1.0)
builder (>= 2.1.2)
erubis (~> 2.7)
gssapi (~> 1.2)
diff --git a/chef-config/lib/chef-config/config.rb b/chef-config/lib/chef-config/config.rb
index f2db54aa17..2fe59c8350 100644
--- a/chef-config/lib/chef-config/config.rb
+++ b/chef-config/lib/chef-config/config.rb
@@ -32,6 +32,7 @@ require "mixlib/shellout"
require "uri"
require "addressable/uri"
require "openssl"
+require "yaml"
module ChefConfig
@@ -70,6 +71,25 @@ module ChefConfig
event_handlers << logger
end
+ def self.apply_extra_config_options(extra_config_options)
+ if extra_config_options
+ extra_parsed_options = extra_config_options.inject({}) do |memo, option|
+ # Sanity check value.
+ if option.empty? || !option.include?("=")
+ raise UnparsableConfigOption, "Unparsable config option #{option.inspect}"
+ end
+ # Split including whitespace if someone does truly odd like
+ # --config-option "foo = bar"
+ key, value = option.split(/\s*=\s*/, 2)
+ # Call to_sym because Chef::Config expects only symbol keys. Also
+ # runs a simple parse on the string for some common types.
+ memo[key.to_sym] = YAML.safe_load(value)
+ memo
+ end
+ merge!(extra_parsed_options)
+ end
+ end
+
# Config file to load (client.rb, knife.rb, etc. defaults set differently in knife, chef-client, etc.)
configurable(:config_file)
@@ -966,7 +986,7 @@ module ChefConfig
# If there is no 'locale -a' then we return 'en_US.UTF-8' since that is the most commonly
# available English UTF-8 locale. However, all modern POSIXen should support 'locale -a'.
def self.guess_internal_locale
- # https://github.com/opscode/chef/issues/2181
+ # https://github.com/chef/chef/issues/2181
# Some systems have the `locale -a` command, but the result has
# invalid characters for the default encoding.
#
diff --git a/chef-config/lib/chef-config/exceptions.rb b/chef-config/lib/chef-config/exceptions.rb
index db10a5f364..23fd28f9c8 100644
--- a/chef-config/lib/chef-config/exceptions.rb
+++ b/chef-config/lib/chef-config/exceptions.rb
@@ -22,5 +22,6 @@ module ChefConfig
class ConfigurationError < ArgumentError; end
class InvalidPath < StandardError; end
+ class UnparsableConfigOption < StandardError; end
end
diff --git a/chef-config/lib/chef-config/version.rb b/chef-config/lib/chef-config/version.rb
index acbf48ea49..ebc1c76739 100644
--- a/chef-config/lib/chef-config/version.rb
+++ b/chef-config/lib/chef-config/version.rb
@@ -21,7 +21,7 @@
module ChefConfig
CHEFCONFIG_ROOT = File.expand_path("../..", __FILE__)
- VERSION = "12.15.26"
+ VERSION = "12.16.23"
end
#
diff --git a/chef-config/spec/unit/config_spec.rb b/chef-config/spec/unit/config_spec.rb
index 0ddb56cf0d..2cdf9af78f 100644
--- a/chef-config/spec/unit/config_spec.rb
+++ b/chef-config/spec/unit/config_spec.rb
@@ -68,6 +68,91 @@ RSpec.describe ChefConfig::Config do
end
end
+ describe "parsing arbitrary config from the CLI" do
+
+ def apply_config
+ described_class.apply_extra_config_options(extra_config_options)
+ end
+
+ context "when no arbitrary config is given" do
+
+ let(:extra_config_options) { nil }
+
+ it "succeeds" do
+ expect { apply_config }.to_not raise_error
+ end
+
+ end
+
+ context "when given a simple string option" do
+
+ let(:extra_config_options) { [ "node_name=bobotclown" ] }
+
+ it "applies the string option" do
+ apply_config
+ expect(described_class[:node_name]).to eq("bobotclown")
+ end
+
+ end
+
+ context "when given a blank value" do
+
+ let(:extra_config_options) { [ "http_retries=" ] }
+
+ it "sets the value to nil" do
+ # ensure the value is actually changed in the test
+ described_class[:http_retries] = 55
+ apply_config
+ expect(described_class[:http_retries]).to eq(nil)
+ end
+ end
+
+ context "when given spaces between `key = value`" do
+
+ let(:extra_config_options) { [ "node_name = bobo" ] }
+
+ it "handles the extra spaces and applies the config option" do
+ apply_config
+ expect(described_class[:node_name]).to eq("bobo")
+ end
+
+ end
+
+ context "when given an integer value" do
+
+ let(:extra_config_options) { [ "http_retries=9000" ] }
+
+ it "converts to a numeric type and applies the config option" do
+ apply_config
+ expect(described_class[:http_retries]).to eq(9000)
+ end
+
+ end
+
+ context "when given a boolean" do
+
+ let(:extra_config_options) { [ "boolean_thing=true" ] }
+
+ it "converts to a boolean type and applies the config option" do
+ apply_config
+ expect(described_class[:boolean_thing]).to eq(true)
+ end
+
+ end
+
+ context "when given input that is not in key=value form" do
+
+ let(:extra_config_options) { [ "http_retries:9000" ] }
+
+ it "raises UnparsableConfigOption" do
+ message = 'Unparsable config option "http_retries:9000"'
+ expect { apply_config }.to raise_error(ChefConfig::UnparsableConfigOption, message)
+ end
+
+ end
+
+ end
+
describe "when configuring formatters" do
# if TTY and not(force-logger)
# formatter = configured formatter or default formatter
diff --git a/distro/common/html/knife_bootstrap.html b/distro/common/html/knife_bootstrap.html
index 5e3d70404f..7589dfbaba 100644
--- a/distro/common/html/knife_bootstrap.html
+++ b/distro/common/html/knife_bootstrap.html
@@ -173,7 +173,7 @@
<div class="highlight-bash"><div class="highlight"><pre><span class="nv">$ </span>knife bootstrap 192.168.1.100 -r <span class="s1">&#39;role[webserver]&#39;</span> -d ubuntu12.04-gems-mine
</pre></div>
</div>
-<p>Alternatively, an example bootstrap template can be found in the git source for the chef-repo: <a class="reference external" href="https://github.com/opscode/chef/tree/master/lib/chef/knife/bootstrap">https://github.com/opscode/chef/tree/master/lib/chef/knife/bootstrap</a>. Copy the template to <tt class="docutils literal"><span class="pre">~/.chef-repo/.chef/bootstrap/ubuntu12.04-apt.erb</span></tt> and modify the template appropriately.</p>
+<p>Alternatively, an example bootstrap template can be found in the git source for the chef-repo: <a class="reference external" href="https://github.com/chef/chef/tree/master/lib/chef/knife/bootstrap">https://github.com/chef/chef/tree/master/lib/chef/knife/bootstrap</a>. Copy the template to <tt class="docutils literal"><span class="pre">~/.chef-repo/.chef/bootstrap/ubuntu12.04-apt.erb</span></tt> and modify the template appropriately.</p>
</div>
<div class="section" id="debian-and-apt">
<h3>Debian and Apt<a class="headerlink" href="#debian-and-apt" title="Permalink to this headline">¶</a></h3>
diff --git a/distro/common/man/man1/README.md b/distro/common/man/man1/README.md
index 9a915fb4cc..7af6aa8948 100644
--- a/distro/common/man/man1/README.md
+++ b/distro/common/man/man1/README.md
@@ -9,7 +9,7 @@ that are built into the chef-client are managed.
## Source Files
The source files are located in the chef-docs repository:
-https://github.com/opscode/chef-docs
+https://github.com/chef/chef-docs
Each Knife subcommand has its own source folder. The folder naming
pattern begins with man_.
@@ -55,4 +55,4 @@ at docs.opscode.com/knife_foo.html.
## Questions?
-Open an [Issue](https://github.com/opscode/chef-docs/issues) and ask.
+Open an [Issue](https://github.com/chef/chef-docs/issues) and ask.
diff --git a/distro/common/man/man1/knife-client.1 b/distro/common/man/man1/knife-client.1
index 9dbd174c71..24bd999d65 100644
--- a/distro/common/man/man1/knife-client.1
+++ b/distro/common/man/man1/knife-client.1
@@ -37,7 +37,7 @@ However, during the first chef\-client run, this private key does not exist. Ins
.sp
During the initial chef\-client run, the chef\-client will register with the Chef server using the private key assigned to the chef\-validator, after which the chef\-client will obtain a \fBclient.pem\fP private key for all future authentication requests to the Chef server\&.
.sp
-After the initial chef\-client run has completed successfully, the chef\-validator is no longer required and may be deleted from the node. Use the \fBdelete_validation\fP recipe found in the \fBchef\-client\fP cookbook (\fI\%https://github.com/opscode\-cookbooks/chef\-client\fP) to remove the chef\-validator\&.
+After the initial chef\-client run has completed successfully, the chef\-validator is no longer required and may be deleted from the node. Use the \fBdelete_validation\fP recipe found in the \fBchef\-client\fP cookbook (\fI\%https://github.com/chef\-cookbooks/chef\-client\fP) to remove the chef\-validator\&.
.sp
The \fBknife client\fP subcommand is used to manage an API client list and their associated RSA public key\-pairs. This allows authentication requests to be made to the Chef server by any entity that uses the Chef server API, such as the chef\-client and knife\&.
.SH COMMON OPTIONS
diff --git a/kitchen-tests/Berksfile.lock b/kitchen-tests/Berksfile.lock
index f08e94dc94..9261f6f481 100644
--- a/kitchen-tests/Berksfile.lock
+++ b/kitchen-tests/Berksfile.lock
@@ -52,7 +52,7 @@ GRAPH
sudo (>= 0.0.0)
ubuntu (>= 0.0.0)
users (>= 0.0.0)
- build-essential (7.0.0)
+ build-essential (7.0.1)
compat_resource (>= 12.14)
mingw (>= 1.1)
seven_zip (>= 0.0.0)
@@ -64,16 +64,16 @@ GRAPH
chef_hostname (0.4.2)
compat_resource (>= 0.0.0)
compat_resource (12.14.7)
- cron (2.0.0)
+ cron (3.0.0)
database (6.0.0)
postgresql (>= 1.0.0)
firewall (2.5.2)
chef-sugar (>= 0.0.0)
httpd (0.4.4)
compat_resource (>= 12.14.6)
- iis (5.0.1)
+ iis (5.0.4)
windows (>= 1.34.6)
- iptables (3.0.0)
+ iptables (3.0.1)
compat_resource (>= 12.14.3)
logrotate (2.1.0)
compat_resource (>= 0.0.0)
@@ -98,7 +98,8 @@ GRAPH
ntp (3.2.0)
openssh (2.1.0)
iptables (>= 1.0)
- openssl (6.0.0)
+ openssl (4.4.0)
+ chef-sugar (>= 3.1.1)
php (1.5.0)
build-essential (>= 0.0.0)
iis (>= 0.0.0)
@@ -106,10 +107,10 @@ GRAPH
windows (>= 0.0.0)
xml (>= 0.0.0)
yum-epel (>= 0.0.0)
- postgresql (3.4.16)
+ postgresql (4.0.6)
apt (>= 1.9.0)
build-essential (>= 0.0.0)
- openssl (>= 0.0.0)
+ openssl (~> 4.0)
rbac (1.0.3)
resolver (1.3.1)
selinux (0.9.0)
diff --git a/kitchen-tests/Gemfile.lock b/kitchen-tests/Gemfile.lock
index f1e544cc08..7498483862 100644
--- a/kitchen-tests/Gemfile.lock
+++ b/kitchen-tests/Gemfile.lock
@@ -3,12 +3,12 @@ GEM
specs:
addressable (2.4.0)
artifactory (2.5.0)
- aws-sdk (2.6.5)
- aws-sdk-resources (= 2.6.5)
- aws-sdk-core (2.6.5)
+ aws-sdk (2.6.9)
+ aws-sdk-resources (= 2.6.9)
+ aws-sdk-core (2.6.9)
jmespath (~> 1.0)
- aws-sdk-resources (2.6.5)
- aws-sdk-core (= 2.6.5)
+ aws-sdk-resources (2.6.9)
+ aws-sdk-core (= 2.6.9)
berkshelf (5.1.0)
addressable (~> 2.3, >= 2.3.4)
berkshelf-api-client (>= 2.0.2, < 4.0)
@@ -43,7 +43,7 @@ GEM
celluloid-io (0.16.2)
celluloid (>= 0.16.0)
nio4r (>= 1.1.0)
- chef-config (12.14.89)
+ chef-config (12.15.19)
addressable
fuzzyurl
mixlib-config (~> 2.0)
@@ -51,7 +51,7 @@ GEM
cleanroom (1.0.0)
coderay (1.1.1)
diff-lcs (1.2.5)
- docker-api (1.32.0)
+ docker-api (1.32.1)
excon (>= 0.38.0)
json
erubis (2.7.0)
@@ -69,7 +69,7 @@ GEM
hitimes (1.2.4)
hitimes (1.2.4-x86-mingw32)
httpclient (2.8.2.4)
- inspec (1.0.0)
+ inspec (1.2.0)
hashie (~> 3.4)
json (>= 1.8, < 3.0)
method_source (~> 0.8)
@@ -86,7 +86,7 @@ GEM
jmespath (1.3.1)
json (2.0.2)
kitchen-appbundle-updater (0.1.2)
- kitchen-dokken (1.0.0)
+ kitchen-dokken (1.0.3)
docker-api (~> 1.29)
test-kitchen (~> 1.5)
kitchen-ec2 (1.2.0)
@@ -111,10 +111,11 @@ GEM
mixlib-authentication (1.4.1)
mixlib-log
mixlib-config (2.2.4)
- mixlib-install (2.0.3)
+ mixlib-install (2.1.1)
artifactory
mixlib-shellout
mixlib-versioning
+ thor
mixlib-log (1.7.1)
mixlib-shellout (2.2.7)
mixlib-shellout (2.2.7-universal-mingw32)
@@ -211,7 +212,7 @@ GEM
hashie (>= 2.0.2, < 4.0.0)
win32-process (0.8.3)
ffi (>= 1.0.0)
- winrm (2.0.3)
+ winrm (2.1.0)
builder (>= 2.1.2)
erubis (~> 2.7)
gssapi (~> 1.2)
diff --git a/lib/chef/application.rb b/lib/chef/application.rb
index f9735a3769..7f15859c8f 100644
--- a/lib/chef/application.rb
+++ b/lib/chef/application.rb
@@ -28,7 +28,6 @@ require "mixlib/cli"
require "tmpdir"
require "rbconfig"
require "chef/application/exit_code"
-require "yaml"
class Chef
class Application
@@ -111,20 +110,13 @@ class Chef
end
extra_config_options = config.delete(:config_option)
Chef::Config.merge!(config)
- if extra_config_options
- extra_parsed_options = extra_config_options.inject({}) do |memo, option|
- # Sanity check value.
- Chef::Application.fatal!("Unparsable config option #{option.inspect}") if option.empty? || !option.include?("=")
- # Split including whitespace if someone does truly odd like
- # --config-option "foo = bar"
- key, value = option.split(/\s*=\s*/, 2)
- # Call to_sym because Chef::Config expects only symbol keys. Also
- # runs a simple parse on the string for some common types.
- memo[key.to_sym] = YAML.safe_load(value)
- memo
- end
- Chef::Config.merge!(extra_parsed_options)
- end
+ apply_extra_config_options(extra_config_options)
+ end
+
+ def apply_extra_config_options(extra_config_options)
+ Chef::Config.apply_extra_config_options(extra_config_options)
+ rescue ChefConfig::UnparsableConfigOption => e
+ Chef::Application.fatal!(e.message)
end
def set_specific_recipes
diff --git a/lib/chef/application/client.rb b/lib/chef/application/client.rb
index cbaa494b71..000aff905b 100644
--- a/lib/chef/application/client.rb
+++ b/lib/chef/application/client.rb
@@ -202,7 +202,7 @@ class Chef::Application::Client < Chef::Application
:short => "-o RunlistItem,RunlistItem...",
:long => "--override-runlist RunlistItem,RunlistItem...",
:description => "Replace current run list with specified items for a single run",
- :proc => lambda {|items|
+ :proc => lambda { |items|
items = items.split(",")
items.compact.map do |item|
Chef::RunList::RunListItem.new(item)
@@ -213,7 +213,7 @@ class Chef::Application::Client < Chef::Application
:short => "-r RunlistItem,RunlistItem...",
:long => "--runlist RunlistItem,RunlistItem...",
:description => "Permanently replace current run list with specified items",
- :proc => lambda {|items|
+ :proc => lambda { |items|
items = items.split(",")
items.compact.map do |item|
Chef::RunList::RunListItem.new(item)
diff --git a/lib/chef/application/solo.rb b/lib/chef/application/solo.rb
index 446a0f007d..1481338a9c 100644
--- a/lib/chef/application/solo.rb
+++ b/lib/chef/application/solo.rb
@@ -166,7 +166,7 @@ class Chef::Application::Solo < Chef::Application
:short => "-o RunlistItem,RunlistItem...",
:long => "--override-runlist RunlistItem,RunlistItem...",
:description => "Replace current run list with specified items",
- :proc => lambda {|items|
+ :proc => lambda { |items|
items = items.split(",")
items.compact.map do |item|
Chef::RunList::RunListItem.new(item)
diff --git a/lib/chef/chef_class.rb b/lib/chef/chef_class.rb
index f019448bd8..0bb15c03ca 100644
--- a/lib/chef/chef_class.rb
+++ b/lib/chef/chef_class.rb
@@ -30,6 +30,7 @@ require "chef/platform/provider_priority_map"
require "chef/platform/resource_priority_map"
require "chef/platform/provider_handler_map"
require "chef/platform/resource_handler_map"
+require "chef/event_dispatch/dsl"
class Chef
class << self
diff --git a/lib/chef/chef_fs/file_system/chef_server/versioned_cookbook_dir.rb b/lib/chef/chef_fs/file_system/chef_server/versioned_cookbook_dir.rb
index 269e160d43..b7c96c42e1 100644
--- a/lib/chef/chef_fs/file_system/chef_server/versioned_cookbook_dir.rb
+++ b/lib/chef/chef_fs/file_system/chef_server/versioned_cookbook_dir.rb
@@ -24,7 +24,7 @@ class Chef
module ChefServer
class VersionedCookbookDir < CookbookDir
# See Erchef code
- # https://github.com/opscode/chef_objects/blob/968a63344d38fd507f6ace05f73d53e9cd7fb043/src/chef_regex.erl#L94
+ # https://github.com/chef/chef_objects/blob/968a63344d38fd507f6ace05f73d53e9cd7fb043/src/chef_regex.erl#L94
VALID_VERSIONED_COOKBOOK_NAME = /^([.a-zA-Z0-9_-]+)-(\d+\.\d+\.\d+)$/
def initialize(name, parent, options = {})
diff --git a/lib/chef/dsl/core.rb b/lib/chef/dsl/core.rb
index 11507857cf..d7c5b6a006 100644
--- a/lib/chef/dsl/core.rb
+++ b/lib/chef/dsl/core.rb
@@ -1,7 +1,7 @@
#--
# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Christopher Walters (<cw@chef.io>)
-# Copyright:: Copyright 2008-2016, 2009-2015 Chef Software, Inc.
+# Copyright:: Copyright 2008-2016 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/dsl/declare_resource.rb b/lib/chef/dsl/declare_resource.rb
index ed3083e1ca..5bd1f7fb8e 100644
--- a/lib/chef/dsl/declare_resource.rb
+++ b/lib/chef/dsl/declare_resource.rb
@@ -1,7 +1,7 @@
#--
# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Christopher Walters
-# Copyright:: Copyright 2008-2016, 2009-2015 Chef Software, Inc.
+# Copyright:: Copyright 2008-2016 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -47,7 +47,7 @@ class Chef
when Chef::RunContext
rc
when :root
- Chef.run_context
+ run_context.root_run_context
when :parent
run_context.parent_run_context
else
diff --git a/lib/chef/dsl/method_missing.rb b/lib/chef/dsl/method_missing.rb
index 0d7ded30f3..51c3eac606 100644
--- a/lib/chef/dsl/method_missing.rb
+++ b/lib/chef/dsl/method_missing.rb
@@ -1,5 +1,5 @@
#--
-# Copyright:: Copyright 2008-2016, 2009-2015 Chef Software, Inc.
+# Copyright:: Copyright 2008-2016 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/dsl/recipe.rb b/lib/chef/dsl/recipe.rb
index 1bb8f130af..e2bd070179 100644
--- a/lib/chef/dsl/recipe.rb
+++ b/lib/chef/dsl/recipe.rb
@@ -1,7 +1,7 @@
#--
# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Christopher Walters (<cw@chef.io>)
-# Copyright:: Copyright 2008-2016, 2009-2015 Chef Software, Inc.
+# Copyright:: Copyright 2008-2016 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/dsl/universal.rb b/lib/chef/dsl/universal.rb
index 810792f542..6e3d162b6f 100644
--- a/lib/chef/dsl/universal.rb
+++ b/lib/chef/dsl/universal.rb
@@ -1,7 +1,7 @@
#--
# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Christopher Walters (<cw@chef.io>)
-# Copyright:: Copyright 2008-2016, 2009-2015 Chef Software, Inc.
+# Copyright:: Copyright 2008-2016 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/http.rb b/lib/chef/http.rb
index 924081bc6b..12acae953c 100644
--- a/lib/chef/http.rb
+++ b/lib/chef/http.rb
@@ -5,7 +5,7 @@
# Author:: Christopher Brown (<cb@chef.io>)
# Author:: Christopher Walters (<cw@chef.io>)
# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright 2009-2016, 2013-2015 Chef Software, Inc.
+# Copyright:: Copyright 2009-2016 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -329,10 +329,9 @@ class Chef
# Runs a synchronous HTTP request, with no middleware applied (use #request
# to have the middleware applied). The entire response will be loaded into memory.
# @api private
- def send_http_request(method, url, headers, body, &response_handler)
- headers = build_headers(method, url, headers, body)
-
+ def send_http_request(method, url, base_headers, body, &response_handler)
retrying_http_errors(url) do
+ headers = build_headers(method, url, base_headers, body)
client = http_client(url)
return_value = nil
if block_given?
diff --git a/lib/chef/knife.rb b/lib/chef/knife.rb
index 0dbd02ceb4..8d40e06a43 100644
--- a/lib/chef/knife.rb
+++ b/lib/chef/knife.rb
@@ -408,11 +408,25 @@ class Chef
config_loader = self.class.load_config(config[:config_file])
config[:config_file] = config_loader.config_location
+ # For CLI options like `--config-option key=value`. These have to get
+ # parsed and applied separately.
+ extra_config_options = config.delete(:config_option)
+
merge_configs
apply_computed_config
- Chef::Config.export_proxies
+
# This has to be after apply_computed_config so that Mixlib::Log is configured
Chef::Log.info("Using configuration from #{config[:config_file]}") if config[:config_file]
+
+ begin
+ Chef::Config.apply_extra_config_options(extra_config_options)
+ rescue ChefConfig::UnparsableConfigOption => e
+ ui.error e.message
+ show_usage
+ exit(1)
+ end
+
+ Chef::Config.export_proxies
end
def show_usage
@@ -525,7 +539,11 @@ class Chef
# FIXME: yard with @yield
def create_object(object, pretty_name = nil, object_class: nil)
- output = edit_data(object, object_class: object_class)
+ output = if object_class
+ edit_data(object, object_class: object_class)
+ else
+ edit_hash(object)
+ end
if Kernel.block_given?
output = yield(output)
diff --git a/lib/chef/mixin/powershell_out.rb b/lib/chef/mixin/powershell_out.rb
index 74de85f86f..ab7cf00a72 100644
--- a/lib/chef/mixin/powershell_out.rb
+++ b/lib/chef/mixin/powershell_out.rb
@@ -91,7 +91,7 @@ class Chef
"-InputFormat None",
]
- "powershell.exe #{flags.join(' ')} -Command \"#{script}\""
+ "powershell.exe #{flags.join(' ')} -Command \"#{script.gsub('"', '\"')}\""
end
end
end
diff --git a/lib/chef/mixin/shell_out.rb b/lib/chef/mixin/shell_out.rb
index a258a91075..d8607c8de7 100644
--- a/lib/chef/mixin/shell_out.rb
+++ b/lib/chef/mixin/shell_out.rb
@@ -61,7 +61,7 @@ class Chef
[:command_log_prepend, :log_tag] ]
# CHEF-3090: Deprecate command_log_level and command_log_prepend
- # Patterned after https://github.com/opscode/chef/commit/e1509990b559984b43e428d4d801c394e970f432
+ # Patterned after https://github.com/chef/chef/commit/e1509990b559984b43e428d4d801c394e970f432
def run_command_compatible_options(command_args)
return command_args unless command_args.last.is_a?(Hash)
diff --git a/lib/chef/node.rb b/lib/chef/node.rb
index 212b1ced14..34a92d325b 100644
--- a/lib/chef/node.rb
+++ b/lib/chef/node.rb
@@ -197,7 +197,6 @@ class Chef
# Set a normal attribute of this node, but auto-vivify any Mashes that
# might be missing
def normal
- attributes.top_level_breadcrumb = nil
attributes.normal
end
@@ -209,14 +208,12 @@ class Chef
# Set a default of this node, but auto-vivify any Mashes that might
# be missing
def default
- attributes.top_level_breadcrumb = nil
attributes.default
end
# Set an override attribute of this node, but auto-vivify any Mashes that
# might be missing
def override
- attributes.top_level_breadcrumb = nil
attributes.override
end
@@ -237,7 +234,6 @@ class Chef
end
def automatic_attrs
- attributes.top_level_breadcrumb = nil
attributes.automatic
end
diff --git a/lib/chef/node/attribute.rb b/lib/chef/node/attribute.rb
index a4a07275c0..2d6aff0b21 100644
--- a/lib/chef/node/attribute.rb
+++ b/lib/chef/node/attribute.rb
@@ -17,6 +17,9 @@
# limitations under the License.
#
+require "chef/node/mixin/deep_merge_cache"
+require "chef/node/mixin/immutablize_hash"
+require "chef/node/mixin/state_tracking"
require "chef/node/immutable_collections"
require "chef/node/attribute_collections"
require "chef/decorator/unchain"
@@ -34,9 +37,18 @@ class Chef
class Attribute < Mash
include Immutablize
-
+ # FIXME: what is include Enumerable doing up here, when down below we delegate
+ # most of the Enumerable/Hash things to the underlying merged ImmutableHash. That
+ # is, in fact, the correct, thing to do, while including Enumerable to try to create
+ # a hash-like API gets lots of things wrong because of the difference between the
+ # Hash `each do |key, value|` vs the Array-like `each do |value|` API that Enumerable
+ # expects. This include should probably be deleted?
include Enumerable
+ include Chef::Node::Mixin::DeepMergeCache
+ include Chef::Node::Mixin::StateTracking
+ include Chef::Node::Mixin::ImmutablizeHash
+
# List of the component attribute hashes, in order of precedence, low to
# high.
COMPONENTS = [
@@ -175,39 +187,21 @@ class Chef
# return the automatic level attribute component
attr_reader :automatic
- # This is used to track the top level key as we descend through method chaining into
- # a precedence level (e.g. node.default['foo']['bar']['baz']= results in 'foo' here). We
- # need this so that when we hit the end of a method chain which results in a mutator method
- # that we can invalidate the whole top-level deep merge cache for the top-level key. It is
- # the responsibility of the accessor on the Chef::Node object to reset this to nil, and then
- # the first VividMash#[] call can ||= and set this to the first key we encounter.
- attr_accessor :top_level_breadcrumb
-
- # Cache of deep merged values by top-level key. This is a simple hash which has keys that are the
- # top-level keys of the node object, and we save the computed deep-merge for that key here. There is
- # no cache of subtrees.
- attr_accessor :deep_merge_cache
-
def initialize(normal, default, override, automatic)
- @default = VividMash.new(self, default)
- @env_default = VividMash.new(self, {})
- @role_default = VividMash.new(self, {})
- @force_default = VividMash.new(self, {})
-
- @normal = VividMash.new(self, normal)
+ @default = VividMash.new(default, self)
+ @env_default = VividMash.new({}, self)
+ @role_default = VividMash.new({}, self)
+ @force_default = VividMash.new({}, self)
- @override = VividMash.new(self, override)
- @role_override = VividMash.new(self, {})
- @env_override = VividMash.new(self, {})
- @force_override = VividMash.new(self, {})
+ @normal = VividMash.new(normal, self)
- @automatic = VividMash.new(self, automatic)
+ @override = VividMash.new(override, self)
+ @role_override = VividMash.new({}, self)
+ @env_override = VividMash.new({}, self)
+ @force_override = VividMash.new({}, self)
- @merged_attributes = nil
- @combined_override = nil
- @combined_default = nil
- @top_level_breadcrumb = nil
- @deep_merge_cache = {}
+ @automatic = VividMash.new(automatic, self)
+ super()
end
# Debug what's going on with an attribute. +args+ is a path spec to the
@@ -235,76 +229,62 @@ class Chef
end
end
- # Invalidate a key in the deep_merge_cache. If called with nil, or no arg, this will invalidate
- # the entire deep_merge cache. In the case of the user doing node.default['foo']['bar']['baz']=
- # that eventually results in a call to reset_cache('foo') here. A node.default=hash_thing call
- # must invalidate the entire cache and re-deep-merge the entire node object.
- def reset_cache(path = nil)
- if path.nil?
- @deep_merge_cache = {}
- else
- deep_merge_cache.delete(path.to_s)
- end
- end
-
- alias :reset :reset_cache
-
# Set the cookbook level default attribute component to +new_data+.
def default=(new_data)
reset
- @default = VividMash.new(self, new_data)
+ @default = VividMash.new(new_data, self)
end
# Set the role level default attribute component to +new_data+
def role_default=(new_data)
reset
- @role_default = VividMash.new(self, new_data)
+ @role_default = VividMash.new(new_data, self)
end
# Set the environment level default attribute component to +new_data+
def env_default=(new_data)
reset
- @env_default = VividMash.new(self, new_data)
+ @env_default = VividMash.new(new_data, self)
end
# Set the force_default (+default!+) level attributes to +new_data+
def force_default=(new_data)
reset
- @force_default = VividMash.new(self, new_data)
+ @force_default = VividMash.new(new_data, self)
end
# Set the normal level attribute component to +new_data+
def normal=(new_data)
reset
- @normal = VividMash.new(self, new_data)
+ @normal = VividMash.new(new_data, self)
end
# Set the cookbook level override attribute component to +new_data+
def override=(new_data)
reset
- @override = VividMash.new(self, new_data)
+ @override = VividMash.new(new_data, self)
end
# Set the role level override attribute component to +new_data+
def role_override=(new_data)
reset
- @role_override = VividMash.new(self, new_data)
+ @role_override = VividMash.new(new_data, self)
end
# Set the environment level override attribute component to +new_data+
def env_override=(new_data)
reset
- @env_override = VividMash.new(self, new_data)
+ @env_override = VividMash.new(new_data, self)
end
def force_override=(new_data)
reset
- @force_override = VividMash.new(self, new_data)
+ @force_override = VividMash.new(new_data, self)
end
def automatic=(new_data)
reset
- @automatic = VividMash.new(self, new_data)
+ @automatic = VividMash.new(new_data, self)
end
#
@@ -413,36 +393,6 @@ class Chef
write(:force_override, *args, value)
end
- # method-style access to attributes
-
- def read(*path)
- merged_attributes.read(*path)
- end
-
- def read!(*path)
- merged_attributes.read!(*path)
- end
-
- def exist?(*path)
- merged_attributes.exist?(*path)
- end
-
- def write(level, *args, &block)
- self.send(level).write(*args, &block)
- end
-
- def write!(level, *args, &block)
- self.send(level).write!(*args, &block)
- end
-
- def unlink(level, *path)
- self.send(level).unlink(*path)
- end
-
- def unlink!(level, *path)
- self.send(level).unlink!(*path)
- end
-
#
# Accessing merged attributes.
#
@@ -484,24 +434,39 @@ class Chef
write(:normal, *args) if read(*args[0...-1]).nil?
end
- def [](key)
- if deep_merge_cache.has_key?(key.to_s)
- # return the cache of the deep merged values by top-level key
- deep_merge_cache[key.to_s]
- else
- # save all the work of computing node[key]
- deep_merge_cache[key.to_s] = merged_attributes(key)
+ def has_key?(key)
+ COMPONENTS.any? do |component_ivar|
+ instance_variable_get(component_ivar).has_key?(key)
end
end
+ # method-style access to attributes (has to come after the prepended ImmutablizeHash)
- def []=(key, value)
- raise Exceptions::ImmutableAttributeModification
+ def read(*path)
+ merged_attributes.read(*path)
end
- def has_key?(key)
- COMPONENTS.any? do |component_ivar|
- instance_variable_get(component_ivar).has_key?(key)
- end
+ def read!(*path)
+ merged_attributes.read!(*path)
+ end
+
+ def exist?(*path)
+ merged_attributes.exist?(*path)
+ end
+
+ def write(level, *args, &block)
+ self.send(level).write(*args, &block)
+ end
+
+ def write!(level, *args, &block)
+ self.send(level).write!(*args, &block)
+ end
+
+ def unlink(level, *path)
+ self.send(level).unlink(*path)
+ end
+
+ def unlink!(level, *path)
+ self.send(level).unlink!(*path)
end
alias :attribute? :has_key?
@@ -600,7 +565,7 @@ class Chef
return nil if components.compact.empty?
- components.inject(ImmutableMash.new({})) do |merged, component|
+ components.inject(ImmutableMash.new({}, self)) do |merged, component|
Chef::Mixin::DeepMerge.hash_only_merge!(merged, component)
end
end
@@ -631,6 +596,11 @@ class Chef
end
end
+ # needed for __path__
+ def convert_key(key)
+ key.kind_of?(Symbol) ? key.to_s : key
+ end
+
end
end
diff --git a/lib/chef/node/attribute_collections.rb b/lib/chef/node/attribute_collections.rb
index 1bd31bceb0..b01b447978 100644
--- a/lib/chef/node/attribute_collections.rb
+++ b/lib/chef/node/attribute_collections.rb
@@ -17,6 +17,7 @@
#
require "chef/node/common_api"
+require "chef/node/mixin/state_tracking"
class Chef
class Node
@@ -63,15 +64,12 @@ class Chef
MUTATOR_METHODS.each do |mutator|
define_method(mutator) do |*args, &block|
ret = super(*args, &block)
- root.reset_cache(root.top_level_breadcrumb)
+ send_reset_cache
ret
end
end
- attr_reader :root
-
- def initialize(root, data)
- @root = root
+ def initialize(data = [])
super(data)
map! { |e| convert_value(e) }
end
@@ -96,14 +94,20 @@ class Chef
when AttrArray
value
when Hash
- VividMash.new(root, value)
+ VividMash.new(value, __root__)
when Array
- AttrArray.new(root, value)
+ AttrArray.new(value, __root__)
else
value
end
end
+ # needed for __path__
+ def convert_key(key)
+ key
+ end
+
+ prepend Chef::Node::Mixin::StateTracking
end
# == VividMash
@@ -117,8 +121,6 @@ class Chef
# #fetch, work as normal).
# * attr_accessor style element set and get are supported via method_missing
class VividMash < Mash
- attr_reader :root
-
include CommonAPI
# Methods that mutate a VividMash. Each of them is overridden so that it
@@ -126,7 +128,6 @@ class Chef
# object.
MUTATOR_METHODS = [
:clear,
- :delete,
:delete_if,
:keep_if,
:merge!,
@@ -140,23 +141,27 @@ class Chef
# For all of the mutating methods on Mash, override them so that they
# also invalidate the cached `merged_attributes` on the root Attribute
# object.
+
+ def delete(key, &block)
+ send_reset_cache(__path__ + [ key ])
+ super
+ end
+
MUTATOR_METHODS.each do |mutator|
define_method(mutator) do |*args, &block|
- root.reset_cache(root.top_level_breadcrumb)
+ send_reset_cache
super(*args, &block)
end
end
- def initialize(root, data = {})
- @root = root
+ def initialize(data = {})
super(data)
end
def [](key)
- root.top_level_breadcrumb ||= key
value = super
if !key?(key)
- value = self.class.new(root)
+ value = self.class.new({}, __root__)
self[key] = value
else
value
@@ -164,9 +169,8 @@ class Chef
end
def []=(key, value)
- root.top_level_breadcrumb ||= key
ret = super
- root.reset_cache(root.top_level_breadcrumb)
+ send_reset_cache(__path__ + [ key ])
ret
end
@@ -205,9 +209,9 @@ class Chef
when AttrArray
value
when Hash
- VividMash.new(root, value)
+ VividMash.new(value, __root__)
when Array
- AttrArray.new(root, value)
+ AttrArray.new(value, __root__)
else
value
end
@@ -217,6 +221,7 @@ class Chef
Mash.new(self)
end
+ prepend Chef::Node::Mixin::StateTracking
end
end
end
diff --git a/lib/chef/node/common_api.rb b/lib/chef/node/common_api.rb
index ce2c6b6878..9bb83a5178 100644
--- a/lib/chef/node/common_api.rb
+++ b/lib/chef/node/common_api.rb
@@ -32,7 +32,6 @@ class Chef
# - autovivifying / autoreplacing writer
# - non-container-ey intermediate objects are replaced with hashes
def write(*args, &block)
- root.top_level_breadcrumb = nil if respond_to?(:root)
value = block_given? ? yield : args.pop
last = args.pop
prev_memo = prev_key = nil
@@ -56,7 +55,6 @@ class Chef
# something that is not a container ("schema violation" issues).
#
def write!(*args, &block)
- root.top_level_breadcrumb = nil if respond_to?(:root)
value = block_given? ? yield : args.pop
last = args.pop
obj = args.inject(self) do |memo, key|
@@ -71,7 +69,6 @@ class Chef
# return true or false based on if the attribute exists
def exist?(*path)
- root.top_level_breadcrumb = nil if respond_to?(:root)
path.inject(self) do |memo, key|
return false unless valid_container?(memo, key)
if memo.is_a?(Hash)
@@ -103,7 +100,6 @@ class Chef
# non-autovivifying reader that throws an exception if the attribute does not exist
def read!(*path)
raise Chef::Exceptions::NoSuchAttribute unless exist?(*path)
- root.top_level_breadcrumb = nil if respond_to?(:root)
path.inject(self) do |memo, key|
memo[key]
end
@@ -112,10 +108,8 @@ class Chef
# FIXME:(?) does anyone really like the autovivifying reader that we have and wants the same behavior? readers that write? ugh...
def unlink(*path, last)
- root.top_level_breadcrumb = nil if respond_to?(:root)
hash = path.empty? ? self : read(*path)
return nil unless hash.is_a?(Hash) || hash.is_a?(Array)
- root.top_level_breadcrumb ||= last
hash.delete(last)
end
diff --git a/lib/chef/node/immutable_collections.rb b/lib/chef/node/immutable_collections.rb
index d4623ace2a..938135cbee 100644
--- a/lib/chef/node/immutable_collections.rb
+++ b/lib/chef/node/immutable_collections.rb
@@ -16,6 +16,9 @@
#
require "chef/node/common_api"
+require "chef/node/mixin/state_tracking"
+require "chef/node/mixin/immutablize_array"
+require "chef/node/mixin/immutablize_hash"
class Chef
class Node
@@ -24,9 +27,9 @@ class Chef
def immutablize(value)
case value
when Hash
- ImmutableMash.new(value)
+ ImmutableMash.new(value, __root__)
when Array
- ImmutableArray.new(value)
+ ImmutableArray.new(value, __root__)
else
value
end
@@ -49,55 +52,12 @@ class Chef
alias :internal_push :<<
private :internal_push
- # A list of methods that mutate Array. Each of these is overridden to
- # raise an error, making this instances of this class more or less
- # immutable.
- DISALLOWED_MUTATOR_METHODS = [
- :<<,
- :[]=,
- :clear,
- :collect!,
- :compact!,
- :default=,
- :default_proc=,
- :delete,
- :delete_at,
- :delete_if,
- :fill,
- :flatten!,
- :insert,
- :keep_if,
- :map!,
- :merge!,
- :pop,
- :push,
- :update,
- :reject!,
- :reverse!,
- :replace,
- :select!,
- :shift,
- :slice!,
- :sort!,
- :sort_by!,
- :uniq!,
- :unshift,
- ]
-
- def initialize(array_data)
+ def initialize(array_data = [])
array_data.each do |value|
internal_push(immutablize(value))
end
end
- # Redefine all of the methods that mutate a Hash to raise an error when called.
- # This is the magic that makes this object "Immutable"
- DISALLOWED_MUTATOR_METHODS.each do |mutator_method_name|
- define_method(mutator_method_name) do |*args, &block|
- raise Exceptions::ImmutableAttributeModification
- end
- end
-
# For elements like Fixnums, true, nil...
def safe_dup(e)
e.dup
@@ -125,6 +85,13 @@ class Chef
a
end
+ # for consistency's sake -- integers 'converted' to integers
+ def convert_key(key)
+ key
+ end
+
+ prepend Chef::Node::Mixin::StateTracking
+ prepend Chef::Node::Mixin::ImmutablizeArray
end
# == ImmutableMash
@@ -140,36 +107,13 @@ class Chef
# it is stale.
# * Values can be accessed in attr_reader-like fashion via method_missing.
class ImmutableMash < Mash
-
include Immutablize
include CommonAPI
alias :internal_set :[]=
private :internal_set
- DISALLOWED_MUTATOR_METHODS = [
- :[]=,
- :clear,
- :collect!,
- :default=,
- :default_proc=,
- :delete,
- :delete_if,
- :keep_if,
- :map!,
- :merge!,
- :update,
- :reject!,
- :replace,
- :select!,
- :shift,
- :write,
- :write!,
- :unlink,
- :unlink!,
- ]
-
- def initialize(mash_data)
+ def initialize(mash_data = {})
mash_data.each do |key, value|
internal_set(key, immutablize(value))
end
@@ -181,14 +125,6 @@ class Chef
alias :attribute? :has_key?
- # Redefine all of the methods that mutate a Hash to raise an error when called.
- # This is the magic that makes this object "Immutable"
- DISALLOWED_MUTATOR_METHODS.each do |mutator_method_name|
- define_method(mutator_method_name) do |*args, &block|
- raise Exceptions::ImmutableAttributeModification
- end
- end
-
def method_missing(symbol, *args)
if symbol == :to_ary
super
@@ -238,7 +174,8 @@ class Chef
h
end
+ prepend Chef::Node::Mixin::StateTracking
+ prepend Chef::Node::Mixin::ImmutablizeHash
end
-
end
end
diff --git a/lib/chef/node/mixin/deep_merge_cache.rb b/lib/chef/node/mixin/deep_merge_cache.rb
new file mode 100644
index 0000000000..b18d6b10cb
--- /dev/null
+++ b/lib/chef/node/mixin/deep_merge_cache.rb
@@ -0,0 +1,61 @@
+#--
+# Copyright:: Copyright 2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ class Node
+ module Mixin
+ module DeepMergeCache
+ # Cache of deep merged values by top-level key. This is a simple hash which has keys that are the
+ # top-level keys of the node object, and we save the computed deep-merge for that key here. There is
+ # no cache of subtrees.
+ attr_accessor :deep_merge_cache
+
+ def initialize
+ @merged_attributes = nil
+ @combined_override = nil
+ @combined_default = nil
+ @deep_merge_cache = {}
+ end
+
+ # Invalidate a key in the deep_merge_cache. If called with nil, or no arg, this will invalidate
+ # the entire deep_merge cache. In the case of the user doing node.default['foo']['bar']['baz']=
+ # that eventually results in a call to reset_cache('foo') here. A node.default=hash_thing call
+ # must invalidate the entire cache and re-deep-merge the entire node object.
+ def reset_cache(path = nil)
+ if path.nil?
+ deep_merge_cache.clear
+ else
+ deep_merge_cache.delete(path.to_s)
+ end
+ end
+
+ alias :reset :reset_cache
+
+ def [](key)
+ if deep_merge_cache.has_key?(key.to_s)
+ # return the cache of the deep merged values by top-level key
+ deep_merge_cache[key.to_s]
+ else
+ # save all the work of computing node[key]
+ deep_merge_cache[key.to_s] = merged_attributes(key)
+ end
+ end
+
+ end
+ end
+ end
+end
diff --git a/lib/chef/node/mixin/immutablize_array.rb b/lib/chef/node/mixin/immutablize_array.rb
new file mode 100644
index 0000000000..cfa7266b9a
--- /dev/null
+++ b/lib/chef/node/mixin/immutablize_array.rb
@@ -0,0 +1,67 @@
+#--
+# Copyright:: Copyright 2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ class Node
+ module Mixin
+ module ImmutablizeArray
+ # A list of methods that mutate Array. Each of these is overridden to
+ # raise an error, making this instances of this class more or less
+ # immutable.
+ DISALLOWED_MUTATOR_METHODS = [
+ :<<,
+ :[]=,
+ :clear,
+ :collect!,
+ :compact!,
+ :default=,
+ :default_proc=,
+ :delete,
+ :delete_at,
+ :delete_if,
+ :fill,
+ :flatten!,
+ :insert,
+ :keep_if,
+ :map!,
+ :merge!,
+ :pop,
+ :push,
+ :update,
+ :reject!,
+ :reverse!,
+ :replace,
+ :select!,
+ :shift,
+ :slice!,
+ :sort!,
+ :sort_by!,
+ :uniq!,
+ :unshift,
+ ]
+
+ # Redefine all of the methods that mutate a Hash to raise an error when called.
+ # This is the magic that makes this object "Immutable"
+ DISALLOWED_MUTATOR_METHODS.each do |mutator_method_name|
+ define_method(mutator_method_name) do |*args, &block|
+ raise Exceptions::ImmutableAttributeModification
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/node/mixin/immutablize_hash.rb b/lib/chef/node/mixin/immutablize_hash.rb
new file mode 100644
index 0000000000..f09e6944fc
--- /dev/null
+++ b/lib/chef/node/mixin/immutablize_hash.rb
@@ -0,0 +1,54 @@
+#--
+# Copyright:: Copyright 2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ class Node
+ module Mixin
+ module ImmutablizeHash
+ DISALLOWED_MUTATOR_METHODS = [
+ :[]=,
+ :clear,
+ :collect!,
+ :default=,
+ :default_proc=,
+ :delete,
+ :delete_if,
+ :keep_if,
+ :map!,
+ :merge!,
+ :update,
+ :reject!,
+ :replace,
+ :select!,
+ :shift,
+ :write,
+ :write!,
+ :unlink,
+ :unlink!,
+ ]
+
+ # Redefine all of the methods that mutate a Hash to raise an error when called.
+ # This is the magic that makes this object "Immutable"
+ DISALLOWED_MUTATOR_METHODS.each do |mutator_method_name|
+ define_method(mutator_method_name) do |*args, &block|
+ raise Exceptions::ImmutableAttributeModification
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/node/mixin/state_tracking.rb b/lib/chef/node/mixin/state_tracking.rb
new file mode 100644
index 0000000000..9be102eeeb
--- /dev/null
+++ b/lib/chef/node/mixin/state_tracking.rb
@@ -0,0 +1,71 @@
+#--
+# Copyright:: Copyright 2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ class Node
+ module Mixin
+ module StateTracking
+ attr_reader :__path__
+ attr_reader :__root__
+
+ NULL = Object.new
+
+ def initialize(data = NULL, root = self)
+ # __path__ and __root__ must be nil when we call super so it knows
+ # to avoid resetting the cache on construction
+ data == NULL ? super() : super(data)
+ @__path__ = []
+ @__root__ = root
+ end
+
+ def [](key)
+ ret = super
+ if ret.is_a?(StateTracking)
+ ret.__path__ = __path__ + [ convert_key(key) ]
+ ret.__root__ = __root__
+ end
+ ret
+ end
+
+ def []=(key, value)
+ ret = super
+ if ret.is_a?(StateTracking)
+ ret.__path__ = __path__ + [ convert_key(key) ]
+ ret.__root__ = __root__
+ end
+ ret
+ end
+
+ protected
+
+ def __path__=(path)
+ @__path__ = path
+ end
+
+ def __root__=(root)
+ @__root__ = root
+ end
+
+ private
+
+ def send_reset_cache(path = __path__)
+ __root__.reset_cache(path.first) if !__root__.nil? && __root__.respond_to?(:reset_cache) && !path.nil?
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/cron.rb b/lib/chef/provider/cron.rb
index 7baaeec0c5..35e5bb874c 100644
--- a/lib/chef/provider/cron.rb
+++ b/lib/chef/provider/cron.rb
@@ -199,7 +199,7 @@ class Chef
def set_environment_var(attr_name, attr_value)
if %w{MAILTO PATH SHELL HOME}.include?(attr_name)
- @current_resource.send(attr_name.downcase.to_sym, attr_value)
+ @current_resource.send(attr_name.downcase.to_sym, attr_value.gsub(/^"|"$/, ""))
else
@current_resource.environment(@current_resource.environment.merge(attr_name => attr_value))
end
diff --git a/lib/chef/provider/group/suse.rb b/lib/chef/provider/group/suse.rb
index a79038e25e..71336f9311 100644
--- a/lib/chef/provider/group/suse.rb
+++ b/lib/chef/provider/group/suse.rb
@@ -17,6 +17,7 @@
#
require "chef/provider/group/groupadd"
+require "etc"
class Chef
class Provider
@@ -36,24 +37,42 @@ class Chef
a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/sbin/groupmod for #{@new_resource.name}"
# No whyrun alternative: this component should be available in the base install of any given system that uses it
end
+
+ requirements.assert(:create, :manage, :modify) do |a|
+ a.assertion do
+ begin
+ to_add(@new_resource.members).all? { |member| Etc.getpwnam(member) }
+ rescue
+ false
+ end
+ end
+ a.failure_message Chef::Exceptions::Group, "Could not add users #{to_add(@new_resource.members).join(", ")} to #{@new_resource.group_name}: one of these users does not exist"
+ a.whyrun "Could not find one of these users: #{to_add(@new_resource.members).join(", ")}. Assuming it will be created by a prior step"
+ end
end
def set_members(members)
- to_delete = @current_resource.members - members
- to_delete.each do |member|
+ to_remove(members).each do |member|
remove_member(member)
end
- to_add = members - @current_resource.members
- to_add.each do |member|
+ to_add(members).each do |member|
add_member(member)
end
end
+ def to_add(members)
+ members - @current_resource.members
+ end
+
def add_member(member)
shell_out!("groupmod -A #{member} #{@new_resource.group_name}")
end
+ def to_remove(members)
+ @current_resource.members - members
+ end
+
def remove_member(member)
shell_out!("groupmod -R #{member} #{@new_resource.group_name}")
end
diff --git a/lib/chef/provider/package.rb b/lib/chef/provider/package.rb
index 3f641145e6..3fed63c914 100644
--- a/lib/chef/provider/package.rb
+++ b/lib/chef/provider/package.rb
@@ -31,6 +31,8 @@ class Chef
include Chef::Mixin::ShellOut
extend Chef::Mixin::SubclassDirective
+ use_inline_resources
+
# subclasses declare this if they want all their arguments as arrays of packages and names
subclass_directive :use_multipackage_api
# subclasses declare this if they want sources (filenames) pulled from their package names
@@ -81,7 +83,7 @@ class Chef
end
end
- def action_install
+ action :install do
unless target_version_array.any?
Chef::Log.debug("#{@new_resource} is already installed - nothing to do")
return
@@ -116,7 +118,7 @@ class Chef
private :install_description
- def action_upgrade
+ action :upgrade do
if !target_version_array.any?
Chef::Log.debug("#{@new_resource} no versions to upgrade - nothing to do")
return
@@ -146,7 +148,7 @@ class Chef
private :upgrade_description
- def action_remove
+ action :remove do
if removing_package?
description = @new_resource.version ? "version #{@new_resource.version} of " : ""
converge_by("remove #{description}package #{@current_resource.package_name}") do
@@ -181,7 +183,7 @@ class Chef
end
end
- def action_purge
+ action :purge do
if removing_package?
description = @new_resource.version ? "version #{@new_resource.version} of" : ""
converge_by("purge #{description} package #{@current_resource.package_name}") do
@@ -193,7 +195,7 @@ class Chef
end
end
- def action_reconfig
+ action :reconfig do
if @current_resource.version == nil
Chef::Log.debug("#{@new_resource} is NOT installed - nothing to do")
return
diff --git a/lib/chef/provider/package/windows/exe.rb b/lib/chef/provider/package/windows/exe.rb
index 44a2f19d1e..60065d9019 100644
--- a/lib/chef/provider/package/windows/exe.rb
+++ b/lib/chef/provider/package/windows/exe.rb
@@ -89,9 +89,10 @@ class Chef
end
def current_installed_version
- @current_installed_version ||= uninstall_entries.count == 0 ? nil : begin
- uninstall_entries.map { |entry| entry.display_version }.uniq
- end
+ @current_installed_version ||=
+ if uninstall_entries.count != 0
+ uninstall_entries.map { |entry| entry.display_version }.uniq
+ end
end
# http://unattended.sourceforge.net/installers.php
diff --git a/lib/chef/provider/package/windows/msi.rb b/lib/chef/provider/package/windows/msi.rb
index 301baa4ed5..ee3b2f7e8e 100644
--- a/lib/chef/provider/package/windows/msi.rb
+++ b/lib/chef/provider/package/windows/msi.rb
@@ -50,7 +50,7 @@ class Chef
Chef::Log.debug("#{new_resource} checking package status and version for #{product_code}")
get_installed_version(product_code)
else
- uninstall_entries.count == 0 ? nil : begin
+ if uninstall_entries.count != 0
uninstall_entries.map { |entry| entry.display_version }.uniq
end
end
diff --git a/lib/chef/provider/ruby_block.rb b/lib/chef/provider/ruby_block.rb
index 0817b14044..18ee9cecc5 100644
--- a/lib/chef/provider/ruby_block.rb
+++ b/lib/chef/provider/ruby_block.rb
@@ -1,7 +1,7 @@
#
# Author:: Adam Jacob (<adam@chef.io>)
# Author:: AJ Christensen (<aj@chef.io>)
-# Copyright:: Copyright 2009-2016, Opscode
+# Copyright:: Copyright 2009-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/provider/user.rb b/lib/chef/provider/user.rb
index f6b088d333..4b05ac8f5e 100644
--- a/lib/chef/provider/user.rb
+++ b/lib/chef/provider/user.rb
@@ -113,15 +113,13 @@ class Chef
# <true>:: If a change is required
# <false>:: If the users are identical
def compare_user
- changed = [ :comment, :home, :shell, :password ].select do |user_attrib|
- !@new_resource.send(user_attrib).nil? && @new_resource.send(user_attrib) != @current_resource.send(user_attrib)
- end
+ return true if !@new_resource.home.nil? && Pathname.new(@new_resource.home).cleanpath != Pathname.new(@current_resource.home).cleanpath
- changed += [ :uid, :gid ].select do |user_attrib|
- !@new_resource.send(user_attrib).nil? && @new_resource.send(user_attrib).to_s != @current_resource.send(user_attrib).to_s
+ [ :comment, :shell, :password, :uid, :gid ].each do |user_attrib|
+ return true if !@new_resource.send(user_attrib).nil? && @new_resource.send(user_attrib).to_s != @current_resource.send(user_attrib).to_s
end
- changed.any?
+ false
end
def action_create
diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb
index 8048330ce1..074ab772a1 100644
--- a/lib/chef/resource.rb
+++ b/lib/chef/resource.rb
@@ -186,22 +186,16 @@ class Chef
# This should most likely be paired with action :nothing
#
# @param arg [Array[Symbol], Symbol] A list of actions (e.g. `:create`)
- # @return [Array[Symbol]] the list of actions.
#
- def delayed_action(arg = nil)
- if arg
- arg = Array(arg).map(&:to_sym)
- arg.each do |action|
- validate(
- { action: action },
- { action: { kind_of: Symbol, equal_to: allowed_actions } }
- )
- # the resource effectively sends a delayed notification to itself
- run_context.add_delayed_action(Notification.new(self, action, self))
- end
- @delayed_action = arg
- else
- @delayed_action
+ def delayed_action(arg)
+ arg = Array(arg).map(&:to_sym)
+ arg.map do |action|
+ validate(
+ { action: action },
+ { action: { kind_of: Symbol, equal_to: allowed_actions } }
+ )
+ # the resource effectively sends a delayed notification to itself
+ run_context.add_delayed_action(Notification.new(self, action, self))
end
end
diff --git a/lib/chef/resource/file.rb b/lib/chef/resource/file.rb
index 207de63778..5c275a574f 100644
--- a/lib/chef/resource/file.rb
+++ b/lib/chef/resource/file.rb
@@ -1,7 +1,7 @@
#
# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Seth Chisamore (<schisamo@chef.io>)
-# Copyright:: Copyright 2008-2016, 2011-2015 Chef Software, Inc.
+# Copyright:: Copyright 2008-2016 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/resource/scm.rb b/lib/chef/resource/scm.rb
index 1e8c71e59d..533723c2c4 100644
--- a/lib/chef/resource/scm.rb
+++ b/lib/chef/resource/scm.rb
@@ -89,13 +89,7 @@ class Chef
)
end
- def svn_password(arg = nil)
- set_or_return(
- :svn_password,
- arg,
- :kind_of => String
- )
- end
+ property :svn_password, String, sensitive: true, desired_state: false
def svn_arguments(arg = nil)
@svn_arguments, arg = nil, nil if arg == false
diff --git a/lib/chef/resource/yum_repository.rb b/lib/chef/resource/yum_repository.rb
index b1859361b1..1c215b51ff 100644
--- a/lib/chef/resource/yum_repository.rb
+++ b/lib/chef/resource/yum_repository.rb
@@ -57,7 +57,7 @@ class Chef
property :password, String, regex: /.*/
property :repo_gpgcheck, [TrueClass, FalseClass]
property :report_instanceid, [TrueClass, FalseClass]
- property :repositoryid, String, regex: /.*/, name_attribute: true
+ property :repositoryid, String, regex: /.*/, name_property: true
property :sensitive, [TrueClass, FalseClass], default: false
property :skip_if_unavailable, [TrueClass, FalseClass]
property :source, String, regex: /.*/
diff --git a/lib/chef/run_context.rb b/lib/chef/run_context.rb
index 5d29f766c9..626977b09f 100644
--- a/lib/chef/run_context.rb
+++ b/lib/chef/run_context.rb
@@ -85,6 +85,17 @@ class Chef
attr_reader :parent_run_context
#
+ # The root run context.
+ #
+ # @return [Chef::RunContext] The root run context.
+ #
+ def root_run_context
+ rc = self
+ rc = rc.parent_run_context until rc.parent_run_context.nil?
+ rc
+ end
+
+ #
# The collection of resources intended to be converged (and able to be
# notified).
#
@@ -653,6 +664,7 @@ ERROR_MESSAGE
notifies_immediately
notifies_delayed
parent_run_context
+ root_run_context
resource_collection
resource_collection=
}.map { |x| x.to_sym }
diff --git a/lib/chef/version.rb b/lib/chef/version.rb
index 078d42c305..3413b702c4 100644
--- a/lib/chef/version.rb
+++ b/lib/chef/version.rb
@@ -21,7 +21,7 @@
class Chef
CHEF_ROOT = File.expand_path("../..", __FILE__)
- VERSION = "12.15.26"
+ VERSION = "12.16.23"
end
#
diff --git a/omnibus/Gemfile.lock b/omnibus/Gemfile.lock
index a54921cb4b..182b723d22 100644
--- a/omnibus/Gemfile.lock
+++ b/omnibus/Gemfile.lock
@@ -1,6 +1,6 @@
GIT
remote: git://github.com/chef/license_scout.git
- revision: 4fd26d99d0617d6336ae372f026c190617800e6b
+ revision: ed2fe16bff7b1b337c3ae23fee8d63cce018303c
specs:
license_scout (0.1.2)
ffi-yajl (~> 2.2)
@@ -8,7 +8,7 @@ GIT
GIT
remote: git://github.com/chef/omnibus-software.git
- revision: 4ce91af05b8be7d46feac765d0fc24eb28e62c68
+ revision: cd69f8563fa8875c82a4e44652ffbfdac7ef201d
branch: shain/ruby_windows_monster
specs:
omnibus-software (4.0.0)
@@ -17,7 +17,7 @@ GIT
GIT
remote: git://github.com/chef/omnibus.git
- revision: 1b5c7a20da006403d5aac2ddc754e43fb97cb540
+ revision: d8a531fd4b95fc73c5c279ba0a53cedd6b2a1196
branch: rhass/COOL-502_with_gcc_investigate
specs:
omnibus (5.5.0)
@@ -38,12 +38,12 @@ GEM
addressable (2.4.0)
artifactory (2.5.0)
awesome_print (1.7.0)
- aws-sdk (2.6.5)
- aws-sdk-resources (= 2.6.5)
- aws-sdk-core (2.6.5)
+ aws-sdk (2.6.11)
+ aws-sdk-resources (= 2.6.11)
+ aws-sdk-core (2.6.11)
jmespath (~> 1.0)
- aws-sdk-resources (2.6.5)
- aws-sdk-core (= 2.6.5)
+ aws-sdk-resources (2.6.11)
+ aws-sdk-core (= 2.6.11)
berkshelf (4.3.5)
addressable (~> 2.3, >= 2.3.4)
berkshelf-api-client (~> 2.0, >= 2.0.2)
@@ -83,7 +83,7 @@ GEM
celluloid-io (0.16.2)
celluloid (>= 0.16.0)
nio4r (>= 1.1.0)
- chef-config (12.14.89)
+ chef-config (12.15.19)
addressable
fuzzyurl
mixlib-config (~> 2.0)
@@ -127,10 +127,11 @@ GEM
mixlib-log
mixlib-cli (1.7.0)
mixlib-config (2.2.4)
- mixlib-install (2.0.3)
+ mixlib-install (2.1.1)
artifactory
mixlib-shellout
mixlib-versioning
+ thor
mixlib-log (1.7.1)
mixlib-shellout (2.2.7)
mixlib-shellout (2.2.7-universal-mingw32)
@@ -149,7 +150,7 @@ GEM
nori (2.6.0)
octokit (4.3.0)
sawyer (~> 0.7.0, >= 0.5.3)
- ohai (8.20.0)
+ ohai (8.21.0)
chef-config (>= 12.5.0.alpha.1, < 13)
ffi (~> 1.9)
ffi-yajl (~> 2.2)
@@ -227,7 +228,7 @@ GEM
hashie (>= 2.0.2, < 4.0.0)
win32-process (0.8.3)
ffi (>= 1.0.0)
- winrm (2.0.3)
+ winrm (2.1.0)
builder (>= 2.1.2)
erubis (~> 2.7)
gssapi (~> 1.2)
diff --git a/omnibus/README.md b/omnibus/README.md
index 98a9094325..5f325aa164 100644
--- a/omnibus/README.md
+++ b/omnibus/README.md
@@ -75,7 +75,7 @@ changing the list found in the `.kitchen.yml` `platforms` YAML stanza.
This build environment is designed to get you up-and-running quickly. However,
there is nothing that restricts you to building on other platforms. Simply use
-the [omnibus cookbook](https://github.com/opscode-cookbooks/omnibus) to setup
+the [omnibus cookbook](https://github.com/chef-cookbooks/omnibus) to setup
your desired platform and execute the build steps listed above.
The default build environment requires Test Kitchen and VirtualBox for local
diff --git a/omnibus_overrides.rb b/omnibus_overrides.rb
index 53946131cd..24084dd6ba 100644
--- a/omnibus_overrides.rb
+++ b/omnibus_overrides.rb
@@ -16,4 +16,4 @@ override "ruby-windows-devkit-bash", version: "3.1.23-4-msys-1.0.18"
override "util-macros", version: "1.19.0"
override "xproto", version: "7.0.28"
override "zlib", version: "1.2.8"
-override "openssl", version: "1.0.2h"
+override "openssl", version: "1.0.2j"
diff --git a/spec/functional/resource/group_spec.rb b/spec/functional/resource/group_spec.rb
index 31f9933546..7effd386a4 100644
--- a/spec/functional/resource/group_spec.rb
+++ b/spec/functional/resource/group_spec.rb
@@ -425,6 +425,7 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" end
end
it "does not raise an error on manage" do
+ allow(Etc).to receive(:getpwnam).and_return(double("User"))
expect { group_resource.run_action(:manage) }.not_to raise_error
end
end
diff --git a/spec/functional/resource/user/useradd_spec.rb b/spec/functional/resource/user/useradd_spec.rb
index 79d62436f5..874155c107 100644
--- a/spec/functional/resource/user/useradd_spec.rb
+++ b/spec/functional/resource/user/useradd_spec.rb
@@ -637,8 +637,10 @@ describe Chef::Provider::User::Useradd, metadata do
context "and has no password" do
# TODO: platform_family should be setup in spec_helper w/ tags
- if %w{suse opensuse}.include?(OHAI_SYSTEM["platform_family"])
- # suse gets this right:
+ if %w{opensuse}.include?(OHAI_SYSTEM["platform_family"]) ||
+ (%w{suse}.include?(OHAI_SYSTEM["platform_family"]) &&
+ OHAI_SYSTEM["platform_version"].to_f < 12.1)
+ # suse 11.x gets this right:
it "errors out trying to unlock the user" do
expect(@error).to be_a(Mixlib::ShellOut::ShellCommandFailed)
expect(@error.message).to include("Cannot unlock the password")
diff --git a/spec/integration/knife/data_bag_create_spec.rb b/spec/integration/knife/data_bag_create_spec.rb
index 0a07792dbc..dc61d55fd5 100644
--- a/spec/integration/knife/data_bag_create_spec.rb
+++ b/spec/integration/knife/data_bag_create_spec.rb
@@ -34,12 +34,10 @@ describe "knife data bag create", :workstation do
end
it "creates a new data bag and item" do
- pending "Deprecation warning must get fixed"
knife("data bag create foo bar").should_succeed stdout: out, stderr: err
end
it "adds a new item to an existing bag" do
- pending "Deprecation warning must get fixed"
knife("data bag create foo").should_succeed stderr: err
knife("data bag create foo bar").should_succeed stdout: out, stderr: exists
end
@@ -50,7 +48,6 @@ describe "knife data bag create", :workstation do
end
it "fails to add an existing item" do
- pending "Deprecation warning must get fixed"
knife("data bag create foo bar").should_succeed stdout: out, stderr: err
expect { knife("data bag create foo bar") }.to raise_error(Net::HTTPServerException)
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 47a5ec7f9f..7559e797bc 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -174,13 +174,13 @@ RSpec.configure do |config|
running_platform_arch = `uname -m`.strip unless windows?
- config.filter_run_excluding :arch => lambda {|target_arch|
+ config.filter_run_excluding :arch => lambda { |target_arch|
running_platform_arch != target_arch
}
# Functional Resource tests that are provider-specific:
# context "on platforms that use useradd", :provider => {:user => Chef::Provider::User::Useradd}} do #...
- config.filter_run_excluding :provider => lambda {|criteria|
+ config.filter_run_excluding :provider => lambda { |criteria|
type, target_provider = criteria.first
node = TEST_NODE.dup
diff --git a/spec/support/shared/integration/app_server_support.rb b/spec/support/shared/integration/app_server_support.rb
index 4dfa3fa155..e2bb3812ea 100644
--- a/spec/support/shared/integration/app_server_support.rb
+++ b/spec/support/shared/integration/app_server_support.rb
@@ -1,7 +1,7 @@
#
# Author:: John Keiser (<jkeiser@chef.io>)
# Author:: Ho-Sheng Hsiao (<hosh@chef.io>)
-# Copyright:: Copyright 2012-2016, 2013-2015 Chef Software, Inc.
+# Copyright:: Copyright 2012-2016 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/spec/unit/http_spec.rb b/spec/unit/http_spec.rb
index d99f03aac9..d58f07c417 100644
--- a/spec/unit/http_spec.rb
+++ b/spec/unit/http_spec.rb
@@ -74,7 +74,7 @@ describe Chef::HTTP do
expect(http.create_url("///api/endpoint?url=http://foo.bar")).to eql(URI.parse("http://www.getchef.com/organization/org/api/endpoint?url=http://foo.bar"))
end
- # As per: https://github.com/opscode/chef/issues/2500
+ # As per: https://github.com/chef/chef/issues/2500
it "should treat scheme part of the URI in a case-insensitive manner" do
http = Chef::HTTP.allocate # Calling Chef::HTTP::new sets @url, don't want that.
expect { http.create_url("HTTP://www1.chef.io/") }.not_to raise_error
diff --git a/spec/unit/knife/core/gem_glob_loader_spec.rb b/spec/unit/knife/core/gem_glob_loader_spec.rb
index 69a40ebaed..2f9e04769e 100644
--- a/spec/unit/knife/core/gem_glob_loader_spec.rb
+++ b/spec/unit/knife/core/gem_glob_loader_spec.rb
@@ -78,7 +78,7 @@ describe Chef::Knife::SubcommandLoader::GemGlobLoader do
expect(loader.site_subcommands).to include(expected_command)
end
- # https://github.com/opscode/chef-dk/issues/227
+ # https://github.com/chef/chef-dk/issues/227
#
# `knife` in ChefDK isn't from a gem install, it's directly run from a clone
# of the source, but there can be one or more versions of chef also installed
diff --git a/spec/unit/knife_spec.rb b/spec/unit/knife_spec.rb
index f0ec45d59a..9569526b2a 100644
--- a/spec/unit/knife_spec.rb
+++ b/spec/unit/knife_spec.rb
@@ -349,6 +349,37 @@ describe Chef::Knife do
expect { knife.run_with_pretty_exceptions }.to raise_error(Exception)
end
end
+
+ describe "setting arbitrary configuration with --config-option" do
+
+ let(:stdout) { StringIO.new }
+
+ let(:stderr) { StringIO.new }
+
+ let(:stdin) { StringIO.new }
+
+ let(:ui) { Chef::Knife::UI.new(stdout, stderr, stdin, disable_editing: true) }
+
+ let(:subcommand) do
+ KnifeSpecs::TestYourself.options = Chef::Application::Knife.options.merge(KnifeSpecs::TestYourself.options)
+ KnifeSpecs::TestYourself.new(%w{--config-option badly_formatted_arg}).tap do |cmd|
+ cmd.ui = ui
+ end
+ end
+
+ it "sets arbitrary configuration via --config-option" do
+ Chef::Knife.run(%w{test yourself --config-option arbitrary_config_thing=hello}, Chef::Application::Knife.options)
+ expect(Chef::Config[:arbitrary_config_thing]).to eq("hello")
+ end
+
+ it "handles errors in arbitrary configuration" do
+ expect(subcommand).to receive(:exit).with(1)
+ subcommand.configure_chef
+ expect(stderr.string).to include("ERROR: Unparsable config option \"badly_formatted_arg\"")
+ expect(stdout.string).to include(subcommand.opt_parser.to_s)
+ end
+ end
+
end
describe "when first created" do
diff --git a/spec/unit/mixin/powershell_out_spec.rb b/spec/unit/mixin/powershell_out_spec.rb
index 8e5f3588ce..4ecdcb8325 100644
--- a/spec/unit/mixin/powershell_out_spec.rb
+++ b/spec/unit/mixin/powershell_out_spec.rb
@@ -18,7 +18,7 @@
require "spec_helper"
require "chef/mixin/powershell_out"
-describe Chef::Mixin::PowershellOut do
+describe Chef::Mixin::PowershellOut, :windows_only do
let(:shell_out_class) { Class.new { include Chef::Mixin::PowershellOut } }
subject(:object) { shell_out_class.new }
let(:architecture) { "something" }
@@ -44,6 +44,18 @@ describe Chef::Mixin::PowershellOut do
).and_return(ret)
expect(object.powershell_out("Get-Process", timeout: 600)).to eql(ret)
end
+
+ context "when double quote is passed in the powershell command" do
+ it "passes if double quote is appended with single escape" do
+ result = object.powershell_out("Write-Verbose \"Some String\" -Verbose")
+ expect(result.stderr).to be == ""
+ expect(result.stdout).to be == "VERBOSE: Some String\n"
+ end
+
+ it "suppresses error if double quote is passed with double escape characters" do
+ expect { object.powershell_out("Write-Verbose \\\"Some String\\\" -Verbose") }.not_to raise_error
+ end
+ end
end
describe "#powershell_out!" do
@@ -66,5 +78,17 @@ describe Chef::Mixin::PowershellOut do
expect(mixlib_shellout).to receive(:error!)
expect(object.powershell_out!("Get-Process", timeout: 600)).to eql(mixlib_shellout)
end
+
+ context "when double quote is passed in the powershell command" do
+ it "passes if double quote is appended with single escape" do
+ result = object.powershell_out!("Write-Verbose \"Some String\" -Verbose")
+ expect(result.stderr).to be == ""
+ expect(result.stdout).to be == "VERBOSE: Some String\n"
+ end
+
+ it "raises error if double quote is passed with double escape characters" do
+ expect { object.powershell_out!("Write-Verbose \\\"Some String\\\" -Verbose") }.to raise_error(Mixlib::ShellOut::ShellCommandFailed)
+ end
+ end
end
end
diff --git a/spec/unit/node/vivid_mash_spec.rb b/spec/unit/node/vivid_mash_spec.rb
index 206b15ef6c..017e6206fc 100644
--- a/spec/unit/node/vivid_mash_spec.rb
+++ b/spec/unit/node/vivid_mash_spec.rb
@@ -19,36 +19,46 @@ require "spec_helper"
require "chef/node/attribute_collections"
describe Chef::Node::VividMash do
- class Root
- attr_accessor :top_level_breadcrumb
- end
-
- let(:root) { Root.new }
+ let(:root) { instance_double(Chef::Node::Attribute) }
let(:vivid) do
- expect(root).to receive(:reset_cache).at_least(:once).with(nil)
- Chef::Node::VividMash.new(root,
- { "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil }
+ Chef::Node::VividMash.new(
+ { "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil },
+ root
)
end
- def with_breadcrumb(key)
- expect(root).to receive(:top_level_breadcrumb=).with(nil).at_least(:once).and_call_original
- expect(root).to receive(:top_level_breadcrumb=).with(key).at_least(:once).and_call_original
+ context "without a root node" do
+ let(:vivid) do
+ Chef::Node::VividMash.new(
+ { "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil }
+ )
+ end
+
+ it "sets the root to the root object" do
+ expect(vivid["one"]["two"].__root__).to eql(vivid)
+ end
+
+ it "does not send reset cache" do
+ # if we setup the expectation here then the object winds up responding to :reset_cache and then it fails...
+ # expect(vivid).not_to receive(:reset_cache)
+ # but even so we expect to blow up here with NoMethodError if we screw up and send :reset_cache to a root VividMash
+ vivid["one"]["foo"] = "bar"
+ end
end
context "#[]=" do
it "deep converts values through arrays" do
- allow(root).to receive(:reset_cache)
- vivid[:foo] = [ { :bar => true } ]
+ expect(root).to receive(:reset_cache).with("foo")
+ vivid["foo"] = [ { :bar => true } ]
expect(vivid["foo"].class).to eql(Chef::Node::AttrArray)
expect(vivid["foo"][0].class).to eql(Chef::Node::VividMash)
expect(vivid["foo"][0]["bar"]).to be true
end
it "deep converts values through nested arrays" do
- allow(root).to receive(:reset_cache)
- vivid[:foo] = [ [ { :bar => true } ] ]
+ expect(root).to receive(:reset_cache).with("foo")
+ vivid["foo"] = [ [ { :bar => true } ] ]
expect(vivid["foo"].class).to eql(Chef::Node::AttrArray)
expect(vivid["foo"][0].class).to eql(Chef::Node::AttrArray)
expect(vivid["foo"][0][0].class).to eql(Chef::Node::VividMash)
@@ -56,8 +66,8 @@ describe Chef::Node::VividMash do
end
it "deep converts values through hashes" do
- allow(root).to receive(:reset_cache)
- vivid[:foo] = { baz: { :bar => true } }
+ expect(root).to receive(:reset_cache).with("foo")
+ vivid["foo"] = { baz: { :bar => true } }
expect(vivid["foo"]).to be_an_instance_of(Chef::Node::VividMash)
expect(vivid["foo"]["baz"]).to be_an_instance_of(Chef::Node::VividMash)
expect(vivid["foo"]["baz"]["bar"]).to be true
@@ -66,182 +76,144 @@ describe Chef::Node::VividMash do
context "#read" do
before do
- # vivify the vividmash, then we're read-only so the cache should never be cleared afterwards
- vivid
expect(root).not_to receive(:reset_cache)
end
it "reads hashes deeply" do
- with_breadcrumb("one")
expect(vivid.read("one", "two", "three")).to eql("four")
end
it "does not trainwreck when hitting hash keys that do not exist" do
- with_breadcrumb("one")
expect(vivid.read("one", "five", "six")).to eql(nil)
end
it "does not trainwreck when hitting an array with an out of bounds index" do
- with_breadcrumb("array")
expect(vivid.read("array", 5, "one")).to eql(nil)
end
it "does not trainwreck when hitting an array with a string key" do
- with_breadcrumb("array")
expect(vivid.read("array", "one", "two")).to eql(nil)
end
it "does not trainwreck when traversing a nil" do
- with_breadcrumb("nil")
expect(vivid.read("nil", "one", "two")).to eql(nil)
end
end
context "#exist?" do
before do
- # vivify the vividmash, then we're read-only so the cache should never be cleared afterwards
- vivid
expect(root).not_to receive(:reset_cache)
end
it "true if there's a hash key there" do
- with_breadcrumb("one")
expect(vivid.exist?("one", "two", "three")).to be true
end
it "true for intermediate hashes" do
- with_breadcrumb("one")
expect(vivid.exist?("one")).to be true
end
it "true for arrays that exist" do
- with_breadcrumb("array")
expect(vivid.exist?("array", 1)).to be true
end
it "true when the value of the key is nil" do
- with_breadcrumb("nil")
expect(vivid.exist?("nil")).to be true
end
it "false when attributes don't exist" do
- with_breadcrumb("one")
expect(vivid.exist?("one", "five", "six")).to be false
end
it "false when traversing a non-container" do
- with_breadcrumb("one")
expect(vivid.exist?("one", "two", "three", "four")).to be false
end
it "false when an array index does not exist" do
- with_breadcrumb("array")
expect(vivid.exist?("array", 3)).to be false
end
it "false when traversing a nil" do
- with_breadcrumb("nil")
expect(vivid.exist?("nil", "foo", "bar")).to be false
end
end
context "#read!" do
before do
- # vivify the vividmash, then we're read-only so the cache should never be cleared afterwards
- vivid
expect(root).not_to receive(:reset_cache)
end
it "reads hashes deeply" do
- with_breadcrumb("one")
expect(vivid.read!("one", "two", "three")).to eql("four")
end
it "reads arrays deeply" do
- with_breadcrumb("array")
expect(vivid.read!("array", 1)).to eql(1)
end
it "throws an exception when attributes do not exist" do
- with_breadcrumb("one")
expect { vivid.read!("one", "five", "six") }.to raise_error(Chef::Exceptions::NoSuchAttribute)
end
it "throws an exception when traversing a non-container" do
- with_breadcrumb("one")
expect { vivid.read!("one", "two", "three", "four") }.to raise_error(Chef::Exceptions::NoSuchAttribute)
end
it "throws an exception when an array element does not exist" do
- with_breadcrumb("array")
expect { vivid.read!("array", 3) }.to raise_error(Chef::Exceptions::NoSuchAttribute)
end
end
context "#write" do
- before do
- vivid
- expect(root).not_to receive(:reset_cache).with(nil)
- end
-
it "should write into hashes" do
- with_breadcrumb("one")
expect(root).to receive(:reset_cache).at_least(:once).with("one")
vivid.write("one", "five", "six")
expect(vivid["one"]["five"]).to eql("six")
end
it "should deeply autovivify" do
- with_breadcrumb("one")
expect(root).to receive(:reset_cache).at_least(:once).with("one")
vivid.write("one", "five", "six", "seven", "eight", "nine", "ten")
expect(vivid["one"]["five"]["six"]["seven"]["eight"]["nine"]).to eql("ten")
end
it "should raise an exception if you overwrite an array with a hash" do
- with_breadcrumb("array")
expect(root).to receive(:reset_cache).at_least(:once).with("array")
vivid.write("array", "five", "six")
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => { "five" => "six" }, "nil" => nil })
end
it "should raise an exception if you traverse through an array with a hash" do
- with_breadcrumb("array")
expect(root).to receive(:reset_cache).at_least(:once).with("array")
vivid.write("array", "five", "six", "seven")
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => { "five" => { "six" => "seven" } }, "nil" => nil })
end
it "should raise an exception if you overwrite a string with a hash" do
- with_breadcrumb("one")
expect(root).to receive(:reset_cache).at_least(:once).with("one")
vivid.write("one", "two", "three", "four", "five")
expect(vivid).to eql({ "one" => { "two" => { "three" => { "four" => "five" } } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should raise an exception if you traverse through a string with a hash" do
- with_breadcrumb("one")
expect(root).to receive(:reset_cache).at_least(:once).with("one")
vivid.write("one", "two", "three", "four", "five", "six")
expect(vivid).to eql({ "one" => { "two" => { "three" => { "four" => { "five" => "six" } } } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should raise an exception if you overwrite a nil with a hash" do
- with_breadcrumb("nil")
expect(root).to receive(:reset_cache).at_least(:once).with("nil")
vivid.write("nil", "one", "two")
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => { "one" => "two" } })
end
it "should raise an exception if you traverse through a nil with a hash" do
- with_breadcrumb("nil")
expect(root).to receive(:reset_cache).at_least(:once).with("nil")
vivid.write("nil", "one", "two", "three")
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => { "one" => { "two" => "three" } } })
end
it "writes with a block" do
- with_breadcrumb("one")
expect(root).to receive(:reset_cache).at_least(:once).with("one")
vivid.write("one", "five") { "six" }
expect(vivid["one"]["five"]).to eql("six")
@@ -249,69 +221,55 @@ describe Chef::Node::VividMash do
end
context "#write!" do
- before do
- vivid
- expect(root).not_to receive(:reset_cache).with(nil)
- end
-
it "should write into hashes" do
- with_breadcrumb("one")
expect(root).to receive(:reset_cache).at_least(:once).with("one")
vivid.write!("one", "five", "six")
expect(vivid["one"]["five"]).to eql("six")
end
it "should deeply autovivify" do
- with_breadcrumb("one")
expect(root).to receive(:reset_cache).at_least(:once).with("one")
vivid.write!("one", "five", "six", "seven", "eight", "nine", "ten")
expect(vivid["one"]["five"]["six"]["seven"]["eight"]["nine"]).to eql("ten")
end
it "should raise an exception if you overwrite an array with a hash" do
- with_breadcrumb("array")
expect(root).not_to receive(:reset_cache)
expect { vivid.write!("array", "five", "six") }.to raise_error(Chef::Exceptions::AttributeTypeMismatch)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should raise an exception if you traverse through an array with a hash" do
- with_breadcrumb("array")
expect(root).not_to receive(:reset_cache)
expect { vivid.write!("array", "five", "six", "seven") }.to raise_error(Chef::Exceptions::AttributeTypeMismatch)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should raise an exception if you overwrite a string with a hash" do
- with_breadcrumb("one")
expect(root).not_to receive(:reset_cache)
expect { vivid.write!("one", "two", "three", "four", "five") }.to raise_error(Chef::Exceptions::AttributeTypeMismatch)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should raise an exception if you traverse through a string with a hash" do
- with_breadcrumb("one")
expect(root).not_to receive(:reset_cache)
expect { vivid.write!("one", "two", "three", "four", "five", "six") }.to raise_error(Chef::Exceptions::AttributeTypeMismatch)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should raise an exception if you overwrite a nil with a hash" do
- with_breadcrumb("nil")
expect(root).not_to receive(:reset_cache)
expect { vivid.write!("nil", "one", "two") }.to raise_error(Chef::Exceptions::AttributeTypeMismatch)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should raise an exception if you traverse through a nil with a hash" do
- with_breadcrumb("nil")
expect(root).not_to receive(:reset_cache)
expect { vivid.write!("nil", "one", "two", "three") }.to raise_error(Chef::Exceptions::AttributeTypeMismatch)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "writes with a block" do
- with_breadcrumb("one")
expect(root).to receive(:reset_cache).at_least(:once).with("one")
vivid.write!("one", "five") { "six" }
expect(vivid["one"]["five"]).to eql("six")
@@ -319,41 +277,31 @@ describe Chef::Node::VividMash do
end
context "#unlink" do
- before do
- vivid
- expect(root).not_to receive(:reset_cache).with(nil)
- end
-
it "should return nil if the keys don't already exist" do
- expect(root).to receive(:top_level_breadcrumb=).with(nil).at_least(:once).and_call_original
expect(root).not_to receive(:reset_cache)
expect(vivid.unlink("five", "six", "seven", "eight")).to eql(nil)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should unlink hashes" do
- with_breadcrumb("one")
expect(root).to receive(:reset_cache).at_least(:once).with("one")
expect( vivid.unlink("one") ).to eql({ "two" => { "three" => "four" } })
expect(vivid).to eql({ "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should unlink array elements" do
- with_breadcrumb("array")
expect(root).to receive(:reset_cache).at_least(:once).with("array")
expect(vivid.unlink("array", 2)).to eql(2)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1 ], "nil" => nil })
end
it "should unlink nil" do
- with_breadcrumb("nil")
expect(root).to receive(:reset_cache).at_least(:once).with("nil")
expect(vivid.unlink("nil")).to eql(nil)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ] })
end
it "should traverse a nil and safely do nothing" do
- with_breadcrumb("nil")
expect(root).not_to receive(:reset_cache)
expect(vivid.unlink("nil", "foo")).to eql(nil)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
@@ -361,41 +309,31 @@ describe Chef::Node::VividMash do
end
context "#unlink!" do
- before do
- vivid
- expect(root).not_to receive(:reset_cache).with(nil)
- end
-
it "should raise an exception if the keys don't already exist" do
- expect(root).to receive(:top_level_breadcrumb=).with(nil).at_least(:once).and_call_original
expect(root).not_to receive(:reset_cache)
expect { vivid.unlink!("five", "six", "seven", "eight") }.to raise_error(Chef::Exceptions::NoSuchAttribute)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should unlink! hashes" do
- with_breadcrumb("one")
expect(root).to receive(:reset_cache).at_least(:once).with("one")
expect( vivid.unlink!("one") ).to eql({ "two" => { "three" => "four" } })
expect(vivid).to eql({ "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should unlink! array elements" do
- with_breadcrumb("array")
expect(root).to receive(:reset_cache).at_least(:once).with("array")
expect(vivid.unlink!("array", 2)).to eql(2)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1 ], "nil" => nil })
end
it "should unlink! nil" do
- with_breadcrumb("nil")
expect(root).to receive(:reset_cache).at_least(:once).with("nil")
expect(vivid.unlink!("nil")).to eql(nil)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ] })
end
it "should raise an exception if it traverses a nil" do
- with_breadcrumb("nil")
expect(root).not_to receive(:reset_cache)
expect { vivid.unlink!("nil", "foo") }.to raise_error(Chef::Exceptions::NoSuchAttribute)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb
index 2c8fc4408b..cfc19db480 100644
--- a/spec/unit/node_spec.rb
+++ b/spec/unit/node_spec.rb
@@ -243,6 +243,34 @@ describe Chef::Node do
expect { node.sunshine = "is bright" }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
end
+ it "does not allow modification of node attributes via hash methods" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ node.default["h4sh"] = { foo: "bar" }
+ expect { node["h4sh"].delete("foo") }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
+ expect { node.h4sh.delete("foo") }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
+ end
+
+ it "does not allow modification of node attributes via array methods" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ node.default["array"] = []
+ expect { node["array"] << "boom" }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
+ expect { node.array << "boom" }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
+ end
+
+ it "returns merged immutable attributes for arrays" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ node.default["array"] = []
+ expect( node["array"].class ).to eql(Chef::Node::ImmutableArray)
+ expect( node.array.class ).to eql(Chef::Node::ImmutableArray)
+ end
+
+ it "returns merged immutable attributes for hashes" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ node.default["h4sh"] = {}
+ expect( node["h4sh"].class ).to eql(Chef::Node::ImmutableMash)
+ expect( node.h4sh.class ).to eql(Chef::Node::ImmutableMash)
+ end
+
it "should allow you get get an attribute via method_missing" do
Chef::Config[:treat_deprecation_warnings_as_errors] = false
node.default.sunshine = "is bright"
@@ -756,9 +784,9 @@ describe Chef::Node do
# In Chef-12.0 there is a deep_merge cache on the top level attribute which had a bug
# where it cached node[:foo] separate from node['foo']. These tests exercise those edge conditions.
#
- # https://github.com/opscode/chef/issues/2700
- # https://github.com/opscode/chef/issues/2712
- # https://github.com/opscode/chef/issues/2745
+ # https://github.com/chef/chef/issues/2700
+ # https://github.com/chef/chef/issues/2712
+ # https://github.com/chef/chef/issues/2745
#
describe "deep merge attribute cache edge conditions" do
it "does not error with complicated attribute substitution" do
@@ -1681,4 +1709,107 @@ describe Chef::Node do
end
end
+ describe "path tracking via __path__" do
+ it "works through hash keys" do
+ node.default["foo"] = { "bar" => { "baz" => "qux" } }
+ expect(node["foo"]["bar"].__path__).to eql(%w{foo bar})
+ end
+
+ it "works through the default level" do
+ node.default["foo"] = { "bar" => { "baz" => "qux" } }
+ expect(node.default["foo"]["bar"].__path__).to eql(%w{foo bar})
+ end
+
+ it "works through arrays" do
+ node.default["foo"] = [ { "bar" => { "baz" => "qux" } } ]
+ expect(node["foo"][0].__path__).to eql(["foo", 0])
+ expect(node["foo"][0]["bar"].__path__).to eql(["foo", 0, "bar"])
+ end
+
+ it "works through arrays at the default level" do
+ node.default["foo"] = [ { "bar" => { "baz" => "qux" } } ]
+ expect(node.default["foo"][0].__path__).to eql(["foo", 0])
+ expect(node.default["foo"][0]["bar"].__path__).to eql(["foo", 0, "bar"])
+ end
+
+ # if we set __path__ in the initializer we'd get this wrong, this is why we
+ # update the path on every #[] or #[]= operator
+ it "works on access when the node has been rearranged" do
+ node.default["foo"] = { "bar" => { "baz" => "qux" } }
+ a = node.default["foo"]
+ node.default["fizz"] = a
+ expect(node["fizz"]["bar"].__path__).to eql(%w{fizz bar})
+ expect(node["foo"]["bar"].__path__).to eql(%w{foo bar})
+ end
+
+ # We have a problem because the __path__ is stored on in each node, but the
+ # node can be wired up at multiple locations in the tree via pointers. One
+ # solution would be to deep-dup the value in `#[]=(key, value)` and fix the
+ # __path__ on all the dup'd nodes. The problem is that this would create an
+ # unusual situation where after assignment, you couldn't mutate the thing you
+ # hand a handle on. I'm not entirely positive this behavior is the correct
+ # thing to support, but it is more hash-like (although if we start with a hash
+ # then convert_value does its thing and we *do* get dup'd on assignment). This
+ # behavior likely makes any implementation of a deep merge cache built over the
+ # top of __path__ tracking have edge conditions where it will fail.
+ #
+ # Removing this support would be a breaking change. The test is included here
+ # because it seems most likely that someone would break this behavior while trying
+ # to fix __path__ behavior.
+ it "does not dup in the background when a node is assigned" do
+ # get a handle on a vividmash (can't be a hash or else we convert_value it)
+ node.default["foo"] = { "bar" => { "baz" => "qux" } }
+ a = node.default["foo"]
+ # assign that somewhere else in the tree
+ node.default["fizz"] = a
+ # now upate the source
+ a["duptest"] = true
+ # the tree should have been updated
+ expect(node.default["fizz"]["duptest"]).to be true
+ expect(node["fizz"]["duptest"]).to be true
+ end
+ end
+
+ describe "root tracking via __root__" do
+ it "works through hash keys" do
+ node.default["foo"] = { "bar" => { "baz" => "qux" } }
+ expect(node["foo"]["bar"].__root__).to eql(node.attributes)
+ end
+
+ it "works through the default level" do
+ node.default["foo"] = { "bar" => { "baz" => "qux" } }
+ expect(node.default["foo"]["bar"].__root__).to eql(node.attributes)
+ end
+
+ it "works through arrays" do
+ node.default["foo"] = [ { "bar" => { "baz" => "qux" } } ]
+ expect(node["foo"][0].__root__).to eql(node.attributes)
+ expect(node["foo"][0]["bar"].__root__).to eql(node.attributes)
+ end
+
+ it "works through arrays at the default level" do
+ node.default["foo"] = [ { "bar" => { "baz" => "qux" } } ]
+ expect(node.default["foo"][0].__root__).to eql(node.attributes)
+ expect(node.default["foo"][0]["bar"].__root__).to eql(node.attributes)
+ end
+ end
+
+ describe "ways of abusing Chef 12 node state" do
+ # these tests abuse the top_level_breadcrumb state in Chef 12
+ it "derived attributes work correctly" do
+ node.default["v1"] = 1
+ expect(node["a"]).to eql(nil)
+ node.default["a"] = node["v1"]
+ expect(node["a"]).to eql(1)
+ end
+
+ it "works when saving nodes to variables" do
+ a = node.default["a"]
+ expect(node["a"]).to eql({})
+ node.default["b"] = 0
+ a["key"] = 1
+
+ expect(node["a"]["key"]).to eql(1)
+ end
+ end
end
diff --git a/spec/unit/provider/deploy_spec.rb b/spec/unit/provider/deploy_spec.rb
index e69714280c..b30ddb736a 100644
--- a/spec/unit/provider/deploy_spec.rb
+++ b/spec/unit/provider/deploy_spec.rb
@@ -556,7 +556,7 @@ describe Chef::Provider::Deploy do
@resource.deploy_to("/my/app")
expect(mock_execution).to receive(:user).with("notCoolMan")
expect(mock_execution).to receive(:group).with("Ggroup")
- expect(mock_execution).to receive(:cwd) {|*args|
+ expect(mock_execution).to receive(:cwd) { |*args|
if args.empty?
nil
else
diff --git a/spec/unit/provider/group/suse_spec.rb b/spec/unit/provider/group/suse_spec.rb
new file mode 100644
index 0000000000..da4e8e9155
--- /dev/null
+++ b/spec/unit/provider/group/suse_spec.rb
@@ -0,0 +1,90 @@
+#
+# Author:: Tom Duffield (<tom@chef.io>)
+# Copyright:: Copyright 2016 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::Provider::Group::Suse do
+ let(:node) { Chef::Node.new }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
+ let(:new_members) { %w{root new_user} }
+ let(:new_resource) do
+ Chef::Resource::Group.new("new_group").tap do |r|
+ r.gid 50
+ r.members new_members
+ r.system false
+ r.non_unique false
+ end
+ end
+ let(:current_resource) do
+ Chef::Resource::Group.new("new_group").tap do |r|
+ r.gid 50
+ r.members %w{root}
+ r.system false
+ r.non_unique false
+ end
+ end
+ let(:provider) do
+ described_class.new(new_resource, run_context).tap do |p|
+ p.current_resource = current_resource
+ end
+ end
+
+ describe "when determining the current group state" do
+ before(:each) do
+ allow(File).to receive(:exists?).and_return(true)
+ provider.action = :create
+ provider.define_resource_requirements
+ end
+
+ # Checking for required binaries is already done in the spec
+ # for Chef::Provider::Group - no need to repeat it here. We'll
+ # include only what's specific to this provider.
+ it "should raise an error if the required binary /usr/sbin/groupmod doesn't exist" do
+ expect(File).to receive(:exists?).with("/usr/sbin/groupmod").and_return(false)
+ expect { provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Group)
+ end
+
+ it "should raise error if one of the member users does not exist" do
+ expect(Etc).to receive(:getpwnam).with("new_user").and_raise ArgumentError
+ expect { provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Group)
+ end
+ end
+
+ describe "#set_members" do
+ it "should add missing members and remove deleted members" do
+ expect(provider).not_to receive(:remove_member)
+ expect(provider).to receive(:add_member).with("new_user")
+ provider.set_members(new_members)
+ end
+ end
+
+ describe "#add_member" do
+ it "should call out to groupmod to add user" do
+ expect(provider).to receive(:shell_out!).with("groupmod -A new_user new_group")
+ provider.add_member("new_user")
+ end
+ end
+
+ describe "#remove_member" do
+ it "should call out to groupmod to remove user" do
+ expect(provider).to receive(:shell_out!).with("groupmod -R new_user new_group")
+ provider.remove_member("new_user")
+ end
+ end
+end
diff --git a/spec/unit/provider/package/windows_spec.rb b/spec/unit/provider/package/windows_spec.rb
index d1d717bdbe..53cbbc1da1 100644
--- a/spec/unit/provider/package/windows_spec.rb
+++ b/spec/unit/provider/package/windows_spec.rb
@@ -26,9 +26,9 @@ describe Chef::Provider::Package::Windows, :windows_only do
allow(Chef::FileCache).to receive(:create_cache_path).with("package/").and_return(cache_path)
end
- let(:node) { double("Chef::Node") }
- let(:events) { double("Chef::Events").as_null_object } # mock all the methods
- let(:run_context) { double("Chef::RunContext", :node => node, :events => events) }
+ let(:node) { Chef::Node.new }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
let(:resource_source) { "calculator.msi" }
let(:resource_name) { "calculator" }
let(:installer_type) { nil }
diff --git a/spec/unit/provider/remote_file/content_spec.rb b/spec/unit/provider/remote_file/content_spec.rb
index db9a75458d..307eb98187 100644
--- a/spec/unit/provider/remote_file/content_spec.rb
+++ b/spec/unit/provider/remote_file/content_spec.rb
@@ -159,7 +159,7 @@ describe Chef::Provider::RemoteFile::Content do
describe "when there is an array of sources and the first fails" do
- # https://github.com/opscode/chef/pull/1358#issuecomment-40853299
+ # https://github.com/chef/chef/pull/1358#issuecomment-40853299
def create_exception(exception_class)
if [ Net::HTTPServerException, Net::HTTPFatalError ].include? exception_class
exception_class.new("message", { "something" => 1 })
diff --git a/spec/unit/provider/user_spec.rb b/spec/unit/provider/user_spec.rb
index 1a8ad6ad1b..719dc8d492 100644
--- a/spec/unit/provider/user_spec.rb
+++ b/spec/unit/provider/user_spec.rb
@@ -221,6 +221,12 @@ describe Chef::Provider::User do
it "should return false if the objects are identical" do
expect(@provider.compare_user).to eql(false)
end
+
+ it "should ignore differences in trailing slash in home paths" do
+ @new_resource.home "/home/adam"
+ @current_resource.home "/home/adam/"
+ expect(@provider.compare_user).to eql(false)
+ end
end
describe "action_create" do
diff --git a/spec/unit/resource/apt_repository_spec.rb b/spec/unit/resource/apt_repository_spec.rb
index 0b0c0c5d26..69cf94ae56 100644
--- a/spec/unit/resource/apt_repository_spec.rb
+++ b/spec/unit/resource/apt_repository_spec.rb
@@ -24,7 +24,7 @@ describe Chef::Resource::AptRepository do
let(:run_context) { Chef::RunContext.new(node, {}, events) }
let(:resource) { Chef::Resource::AptRepository.new("multiverse", run_context) }
- it "should create a new Chef::Resource::AptUpdate" do
+ it "should create a new Chef::Resource::AptRepository" do
expect(resource).to be_a_kind_of(Chef::Resource)
expect(resource).to be_a_kind_of(Chef::Resource::AptRepository)
end
diff --git a/version_policy.rb b/version_policy.rb
index bfe08e91e4..5621ea43ff 100644
--- a/version_policy.rb
+++ b/version_policy.rb
@@ -45,7 +45,7 @@ OMNIBUS_OVERRIDES = {
## These can float as they are frequently updated in a way that works for us
#override "cacerts" =>"???",
- "openssl" => "1.0.2h",
+ "openssl" => "1.0.2j",
}
#