summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNoah Kantrowitz <noah@coderanger.net>2016-08-02 16:36:05 -0700
committerNoah Kantrowitz <noah@coderanger.net>2016-08-02 16:36:05 -0700
commit0368df838c36fd5a54c75007aae3c2e28cbdba1b (patch)
treed89eac235ed3890c4628c59505299627a44508ca
parent16fbf0a9a81daa1e3418eca251e59b4545ae0b88 (diff)
parent767a45530b373bbd4818b93ab1efe5cd3c7da5ed (diff)
downloadchef-0368df838c36fd5a54c75007aae3c2e28cbdba1b.tar.gz
Merge branch 'master' into configoption
-rw-r--r--CHANGELOG.md35
-rw-r--r--Gemfile5
-rw-r--r--Gemfile.lock118
-rw-r--r--RELEASE_NOTES.md64
-rw-r--r--Rakefile5
-rw-r--r--VERSION2
-rw-r--r--acceptance/.gitignore2
-rw-r--r--acceptance/.shared/kitchen_acceptance/.kitchen.ec2.yml13
-rw-r--r--acceptance/.shared/kitchen_acceptance/libraries/kitchen.rb41
-rw-r--r--acceptance/Gemfile9
-rw-r--r--acceptance/Gemfile.lock183
-rw-r--r--acceptance/data-collector/Berksfile.lock6
-rw-r--r--acceptance/data-collector/test/integration/default/serverspec/default_spec.rb43
-rw-r--r--acceptance/top-cookbooks/.acceptance/acceptance-cookbook/libraries/top_cookbooks.rb4
-rw-r--r--acceptance/trivial/.kitchen.yml2
-rw-r--r--acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/destroy.rb2
-rw-r--r--acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/provision.rb2
-rw-r--r--acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/verify.rb2
-rw-r--r--acceptance/windows-service/test/integration/chef-windows-service/inspec/chef_windows_service_spec.rb8
-rw-r--r--chef-config/Rakefile2
-rw-r--r--chef-config/lib/chef-config/config.rb15
-rw-r--r--chef-config/lib/chef-config/package_task.rb56
-rw-r--r--chef-config/lib/chef-config/version.rb2
-rw-r--r--chef-config/spec/unit/config_spec.rb10
-rw-r--r--chef.gemspec7
-rw-r--r--kitchen-tests/.kitchen.travis.yml1
-rw-r--r--kitchen-tests/.kitchen.yml1
-rw-r--r--kitchen-tests/Berksfile2
-rw-r--r--kitchen-tests/Berksfile.lock33
-rw-r--r--kitchen-tests/Gemfile.lock98
-rw-r--r--lib/chef/application.rb4
-rw-r--r--lib/chef/application/client.rb4
-rw-r--r--lib/chef/application/solo.rb11
-rw-r--r--lib/chef/audit/audit_reporter.rb6
-rw-r--r--lib/chef/audit/runner.rb2
-rw-r--r--lib/chef/chef_fs/chef_fs_data_store.rb1
-rw-r--r--lib/chef/chef_fs/file_system/multiplexed_dir.rb2
-rw-r--r--lib/chef/chef_fs/file_system/repository/acls_dir.rb6
-rw-r--r--lib/chef/chef_fs/file_system/repository/base_file.rb3
-rw-r--r--lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_entry.rb1
-rw-r--r--lib/chef/chef_fs/file_system/repository/directory.rb13
-rw-r--r--lib/chef/chef_fs/file_system_cache.rb80
-rw-r--r--lib/chef/data_collector.rb119
-rw-r--r--lib/chef/data_collector/messages.rb37
-rw-r--r--lib/chef/data_collector/messages/helpers.rb4
-rw-r--r--lib/chef/data_collector/resource_report.rb33
-rw-r--r--lib/chef/decorator/unchain.rb59
-rw-r--r--lib/chef/dsl/cheffish.rb1
-rw-r--r--lib/chef/dsl/declare_resource.rb10
-rw-r--r--lib/chef/exceptions.rb5
-rw-r--r--lib/chef/http.rb10
-rw-r--r--lib/chef/knife/bootstrap.rb9
-rw-r--r--lib/chef/knife/cookbook_create.rb4
-rw-r--r--lib/chef/knife/cookbook_site_download.rb9
-rw-r--r--lib/chef/knife/cookbook_site_install.rb21
-rw-r--r--lib/chef/knife/cookbook_site_list.rb9
-rw-r--r--lib/chef/knife/cookbook_site_search.rb9
-rw-r--r--lib/chef/knife/cookbook_site_share.rb29
-rw-r--r--lib/chef/knife/cookbook_site_show.rb17
-rw-r--r--lib/chef/knife/cookbook_site_unshare.rb9
-rw-r--r--lib/chef/knife/core/bootstrap_context.rb12
-rw-r--r--lib/chef/knife/supermarket_download.rb33
-rw-r--r--lib/chef/knife/supermarket_install.rb33
-rw-r--r--lib/chef/knife/supermarket_list.rb33
-rw-r--r--lib/chef/knife/supermarket_search.rb33
-rw-r--r--lib/chef/knife/supermarket_share.rb33
-rw-r--r--lib/chef/knife/supermarket_show.rb33
-rw-r--r--lib/chef/knife/supermarket_unshare.rb33
-rw-r--r--lib/chef/node.rb45
-rw-r--r--lib/chef/node/attribute.rb193
-rw-r--r--lib/chef/node/attribute_collections.rb139
-rw-r--r--lib/chef/node/common_api.rb129
-rw-r--r--lib/chef/node/immutable_collections.rb29
-rw-r--r--lib/chef/property.rb8
-rw-r--r--lib/chef/provider.rb9
-rw-r--r--lib/chef/provider/batch.rb2
-rw-r--r--lib/chef/provider/cron.rb2
-rw-r--r--lib/chef/provider/file.rb8
-rw-r--r--lib/chef/provider/package/aix.rb6
-rw-r--r--lib/chef/provider/package/openbsd.rb2
-rw-r--r--lib/chef/provider/package/rubygems.rb12
-rw-r--r--lib/chef/provider/package/windows/exe.rb7
-rw-r--r--lib/chef/provider/package/zypper.rb14
-rw-r--r--lib/chef/provider/powershell_script.rb2
-rw-r--r--lib/chef/provider/remote_directory.rb2
-rw-r--r--lib/chef/resource.rb53
-rw-r--r--lib/chef/resource_builder.rb13
-rw-r--r--lib/chef/run_context.rb57
-rw-r--r--lib/chef/shell.rb2
-rw-r--r--lib/chef/version.rb2
-rw-r--r--omnibus/.kitchen.yml38
-rw-r--r--omnibus/Gemfile4
-rw-r--r--omnibus/Gemfile.lock107
-rw-r--r--omnibus/config/software/chef-gem-nokogiri.rb1
-rw-r--r--omnibus/config/software/chef-gem-pkg-config.rb9
-rw-r--r--omnibus/config/software/chef.rb7
-rw-r--r--omnibus_overrides.rb6
-rw-r--r--pkg.rb1
-rw-r--r--rubygems-pkg/rubygems-update-2.4.6.gembin451072 -> 0 bytes
-rw-r--r--spec/data/run_context/cookbooks/circular-dep1/attributes/default.rb6
-rw-r--r--spec/data/run_context/cookbooks/circular-dep2/attributes/default.rb5
-rw-r--r--spec/data/run_context/cookbooks/dependency1/attributes/aa_first.rb4
-rw-r--r--spec/data/run_context/cookbooks/dependency1/attributes/default.rb4
-rw-r--r--spec/data/run_context/cookbooks/dependency1/attributes/zz_last.rb5
-rw-r--r--spec/data/run_context/cookbooks/dependency2/attributes/default.rb5
-rw-r--r--spec/data/run_context/cookbooks/no-default-attr/attributes/server.rb5
-rw-r--r--spec/data/run_context/cookbooks/test-with-circular-deps/attributes/default.rb5
-rw-r--r--spec/data/run_context/cookbooks/test-with-deps/attributes/default.rb5
-rw-r--r--spec/functional/assets/chocolatey_feed/test-A.1.0.nupkgbin2667 -> 2678 bytes
-rw-r--r--spec/functional/assets/chocolatey_feed/test-A.1.5.nupkgbin2669 -> 2679 bytes
-rw-r--r--spec/functional/assets/chocolatey_feed/test-A.2.0.nupkgbin2667 -> 2678 bytes
-rw-r--r--spec/functional/assets/chocolatey_feed/test-B.1.0.nupkgbin2667 -> 2678 bytes
-rw-r--r--spec/functional/resource/cron_spec.rb9
-rw-r--r--spec/functional/resource/dsc_script_spec.rb2
-rw-r--r--spec/functional/resource/package_spec.rb2
-rw-r--r--spec/functional/resource/template_spec.rb6
-rw-r--r--spec/functional/shell_spec.rb2
-rw-r--r--spec/integration/knife/client_bulk_delete_spec.rb130
-rw-r--r--spec/integration/knife/client_create_spec.rb69
-rw-r--r--spec/integration/knife/client_delete_spec.rb63
-rw-r--r--spec/integration/knife/client_key_create_spec.rb65
-rw-r--r--spec/integration/knife/client_key_delete_spec.rb42
-rw-r--r--spec/integration/knife/client_key_list_spec.rb60
-rw-r--r--spec/integration/knife/client_key_show_spec.rb44
-rw-r--r--spec/integration/knife/client_list_spec.rb48
-rw-r--r--spec/integration/knife/client_show_spec.rb36
-rw-r--r--spec/integration/knife/cookbook_bulk_delete_spec.rb64
-rw-r--r--spec/integration/knife/cookbook_download_spec.rb95
-rw-r--r--spec/integration/knife/cookbook_list_spec.rb54
-rw-r--r--spec/integration/knife/cookbook_show_spec.rb159
-rw-r--r--spec/integration/knife/cookbook_upload_spec.rb90
-rw-r--r--spec/integration/knife/data_bag_create_spec.rb58
-rw-r--r--spec/integration/knife/data_bag_delete_spec.rb58
-rw-r--r--spec/integration/knife/data_bag_from_file_spec.rb115
-rw-r--r--spec/integration/knife/data_bag_list_spec.rb43
-rw-r--r--spec/integration/knife/data_bag_show_spec.rb53
-rw-r--r--spec/integration/knife/diff_spec.rb4
-rw-r--r--spec/integration/knife/download_spec.rb8
-rw-r--r--spec/integration/knife/environment_compare_spec.rb74
-rw-r--r--spec/integration/knife/environment_create_spec.rb40
-rw-r--r--spec/integration/knife/environment_delete_spec.rb36
-rw-r--r--spec/integration/knife/environment_from_file_spec.rb115
-rw-r--r--spec/integration/knife/environment_list_spec.rb41
-rw-r--r--spec/integration/knife/environment_show_spec.rb56
-rw-r--r--spec/integration/knife/node_bulk_delete_spec.rb51
-rw-r--r--spec/integration/knife/node_create_spec.rb46
-rw-r--r--spec/integration/knife/node_delete_spec.rb47
-rw-r--r--spec/integration/knife/node_environment_set_spec.rb42
-rw-r--r--spec/integration/knife/node_from_file_spec.rb58
-rw-r--r--spec/integration/knife/node_list_spec.rb44
-rw-r--r--spec/integration/knife/node_run_list_add_spec.rb53
-rw-r--r--spec/integration/knife/node_run_list_remove_spec.rb35
-rw-r--r--spec/integration/knife/node_run_list_set_spec.rb40
-rw-r--r--spec/integration/knife/node_show_spec.rb35
-rw-r--r--spec/integration/knife/raw_spec.rb2
-rw-r--r--spec/integration/knife/role_bulk_delete_spec.rb51
-rw-r--r--spec/integration/knife/role_create_spec.rb40
-rw-r--r--spec/integration/knife/role_delete_spec.rb47
-rw-r--r--spec/integration/knife/role_from_file_spec.rb95
-rw-r--r--spec/integration/knife/role_list_spec.rb44
-rw-r--r--spec/integration/knife/role_show_spec.rb50
-rw-r--r--spec/integration/knife/upload_spec.rb6
-rw-r--r--spec/spec_helper.rb6
-rw-r--r--spec/support/platform_helpers.rb4
-rw-r--r--spec/support/shared/integration/knife_support.rb17
-rw-r--r--spec/support/shared/unit/provider/file.rb25
-rw-r--r--spec/unit/application/solo_spec.rb19
-rw-r--r--spec/unit/chef_fs/file_system/repository/directory_spec.rb1
-rw-r--r--spec/unit/cookbook_version_spec.rb8
-rw-r--r--spec/unit/data_collector/messages/helpers_spec.rb10
-rw-r--r--spec/unit/data_collector/messages_spec.rb68
-rw-r--r--spec/unit/data_collector_spec.rb106
-rw-r--r--spec/unit/dsl/declare_resource_spec.rb30
-rw-r--r--spec/unit/knife/cookbook_create_spec.rb1
-rw-r--r--spec/unit/knife/cookbook_site_download_spec.rb1
-rw-r--r--spec/unit/knife/cookbook_site_install_spec.rb2
-rw-r--r--spec/unit/knife/cookbook_site_share_spec.rb8
-rw-r--r--spec/unit/knife/node_environment_set_spec.rb24
-rw-r--r--spec/unit/knife/node_run_list_set_spec.rb25
-rw-r--r--spec/unit/node/attribute_spec.rb16
-rw-r--r--spec/unit/node/immutable_collections_spec.rb4
-rw-r--r--spec/unit/node/vivid_mash_spec.rb377
-rw-r--r--spec/unit/node_spec.rb171
-rw-r--r--spec/unit/provider/cron_spec.rb32
-rw-r--r--spec/unit/provider/package/aix_spec.rb13
-rw-r--r--spec/unit/provider/package/windows/exe_spec.rb23
-rw-r--r--spec/unit/provider/package/zypper_spec.rb20
-rw-r--r--spec/unit/provider/powershell_script_spec.rb8
-rw-r--r--spec/unit/provider/remote_directory_spec.rb15
-rw-r--r--spec/unit/recipe_spec.rb37
-rw-r--r--spec/unit/run_context_spec.rb4
-rw-r--r--spec/unit/shell/shell_session_spec.rb2
-rw-r--r--tasks/dependencies.rb2
-rw-r--r--version_policy.rb4
194 files changed, 4956 insertions, 1150 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 549b63abba..c9b30edba7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,40 @@
# Change Log
+## [v12.12.15](https://github.com/chef/chef/tree/v12.12.15) (2016-07-08)
+[Full Changelog](https://github.com/chef/chef/compare/v12.12.13...v12.12.15)
+
+**Fixed Bugs:**
+
+- Fix for #5094 12.12.13 node.default_unless issue [\#5097](https://github.com/chef/chef/pull/5097) ([lamont-granquist](https://github.com/lamont-granquist))
+
+## [v12.12.13](https://github.com/chef/chef/tree/v12.12.13) (2016-07-01)
+[Full Changelog](https://github.com/chef/chef/compare/v12.11.18...v12.12.13)
+
+**Implemented Enhancements:**
+
+- Tweak 3694 warnings [\#5075](https://github.com/chef/chef/pull/5075) ([lamont-granquist](https://github.com/lamont-granquist))
+- Adding node object to Data collector run\_converge message [\#5065](https://github.com/chef/chef/pull/5065) ([adamleff](https://github.com/adamleff))
+- Attribute API improvements [\#5029](https://github.com/chef/chef/pull/5029) ([lamont-granquist](https://github.com/lamont-granquist))
+- Remove deprecated Thread.exclusive around require call. [\#5068](https://github.com/chef/chef/pull/5068) ([maxlazio](https://github.com/maxlazio))
+- Ensure that chef-solo uses the expected repo dir [\#5059](https://github.com/chef/chef/pull/5059) ([thommay](https://github.com/thommay))
+- Expand data\_collector resource list to include all resources [\#5058](https://github.com/chef/chef/pull/5058) ([adamleff](https://github.com/adamleff))
+- Turn off fips with an empty environment var [\#5048](https://github.com/chef/chef/pull/5048) ([mwrock](https://github.com/mwrock))
+- Deprecate knife-supermarket gem [\#4896](https://github.com/chef/chef/pull/4896) ([thommay](https://github.com/thommay))
+- Update Nokogiri [\#5042](https://github.com/chef/chef/pull/5042) ([mwrock](https://github.com/mwrock))
+- Remote resource should respect sensitive flag [\#5025](https://github.com/chef/chef/pull/5025) ([PrajaktaPurohit](https://github.com/PrajaktaPurohit))
+- Convert the 3694 warning to a deprecation so it will be subject to the usual deprecation formatting \(collected at the bottom, can be made an error, etc\). [\#5022](https://github.com/chef/chef/pull/5022) ([coderanger](https://github.com/coderanger))
+- Deprecate `knife cookbook create` in favor of `chef generate cookbook`. [\#5021](https://github.com/chef/chef/pull/5021) ([tylercloke](https://github.com/tylercloke))
+
+**Fixed Bugs:**
+
+- Fixes windows_package uninstall scenarios by calling uninstall string directly [\#5050](https://github.com/chef/chef/pull/5050) ([mwrock](https://github.com/mwrock))
+- Fix gem_package idempotency [\#5046](https://github.com/chef/chef/pull/5046) ([thommay](https://github.com/thommay))
+- Undefined local variable lookup in multiplexed_dir.rb [\#5027](https://github.com/chef/chef/issues/5027) ([robdimarco](https://github.com/robdimarco))
+- Correctly write out data collector metadata file [\#5019](https://github.com/chef/chef/pull/5019) ([adamleff](https://github.com/adamleff))
+- Eliminate missing constant errors for LWRP class [\#5000](https://github.com/chef/chef/pull/5000) ([PrajaktaPurohit](https://github.com/PrajaktaPurohit))
+- Updated_resource_count to data collector should only include updated resources [\#5006](https://github.com/chef/chef/pull/5006) ([adamleff](https://github.com/adamleff))
+- Don't mask directory deletion errors [\#4991](https://github.com/chef/chef/pull/4991) ([jaymzh](https://github.com/jaymzh))
+
## [v12.11.18](https://github.com/chef/chef/tree/v12.11.18) (2016-06-02)
[Full Changelog](https://github.com/chef/chef/compare/v12.11.17...v12.11.18)
diff --git a/Gemfile b/Gemfile
index 40d608e66b..9327fb539a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -22,6 +22,7 @@ group(:omnibus_package) do
gem "rb-readline"
gem "nokogiri"
end
+
group(:omnibus_package, :pry) do
gem "pry"
gem "pry-byebug"
@@ -65,7 +66,7 @@ end
group(:development, :test) do
gem "simplecov"
- gem "rack"
+ gem "rack", "< 2.0" # 2.0 requires Ruby 2.2+
# for testing new chefstyle rules
# gem 'chefstyle', github: 'chef/chefstyle'
@@ -78,7 +79,7 @@ end
group(:travis) do
# See `bundler-audit` in .travis.yml
- gem "bundler-audit", git: "https://github.com/rubysec/bundler-audit.git", ref: "4e32fca"
+ gem "bundler-audit", git: "https://github.com/rubysec/bundler-audit.git"
end
instance_eval(ENV["GEMFILE_MOD"]) if ENV["GEMFILE_MOD"]
diff --git a/Gemfile.lock b/Gemfile.lock
index 5cd0539227..33bdcfb214 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -8,27 +8,27 @@ GIT
GIT
remote: https://github.com/rubysec/bundler-audit.git
- revision: 4e32fca89d75f0e249671431ff38aadc02bfb28b
- ref: 4e32fca
+ revision: b16b26e0a4eed474f5f1ee38c22030a2f617ffc8
specs:
- bundler-audit (0.4.0)
+ bundler-audit (0.5.0)
bundler (~> 1.2)
thor (~> 0.18)
PATH
remote: .
specs:
- chef (12.12.2)
+ chef (12.13.21)
bundler (>= 1.10)
- chef-config (= 12.12.2)
- chef-zero (~> 4.5)
+ chef-config (= 12.13.21)
+ chef-zero (~> 4.8)
diff-lcs (~> 1.2, >= 1.2.4)
erubis (~> 2.7)
ffi-yajl (~> 2.2)
highline (~> 1.6, >= 1.6.9)
iniparse (~> 1.4)
+ mixlib-archive (>= 0.2.0)
mixlib-authentication (~> 1.4)
- mixlib-cli (~> 1.4)
+ mixlib-cli (~> 1.4, < 1.7)
mixlib-log (~> 1.3)
mixlib-shellout (~> 2.0)
net-sftp (~> 2.1, >= 2.1.2)
@@ -37,26 +37,27 @@ PATH
ohai (>= 8.6.0.alpha.1, < 9)
plist (~> 3.2)
proxifier (~> 1.0)
- rspec-core (~> 3.4)
- rspec-expectations (~> 3.4)
- rspec-mocks (~> 3.4)
+ rspec-core (~> 3.5)
+ rspec-expectations (~> 3.5)
+ rspec-mocks (~> 3.5)
rspec_junit_formatter (~> 0.2.0)
serverspec (~> 2.7)
specinfra (~> 2.10)
syslog-logger (~> 1.6)
uuidtools (~> 2.1.5)
- chef (12.12.2-universal-mingw32)
+ chef (12.13.21-universal-mingw32)
bundler (>= 1.10)
- chef-config (= 12.12.2)
- chef-zero (~> 4.5)
+ chef-config (= 12.13.21)
+ chef-zero (~> 4.8)
diff-lcs (~> 1.2, >= 1.2.4)
erubis (~> 2.7)
ffi (~> 1.9)
ffi-yajl (~> 2.2)
highline (~> 1.6, >= 1.6.9)
iniparse (~> 1.4)
+ mixlib-archive (>= 0.2.0)
mixlib-authentication (~> 1.4)
- mixlib-cli (~> 1.4)
+ mixlib-cli (~> 1.4, < 1.7)
mixlib-log (~> 1.3)
mixlib-shellout (~> 2.0)
net-sftp (~> 2.1, >= 2.1.2)
@@ -65,9 +66,9 @@ PATH
ohai (>= 8.6.0.alpha.1, < 9)
plist (~> 3.2)
proxifier (~> 1.0)
- rspec-core (~> 3.4)
- rspec-expectations (~> 3.4)
- rspec-mocks (~> 3.4)
+ rspec-core (~> 3.5)
+ rspec-expectations (~> 3.5)
+ rspec-mocks (~> 3.5)
rspec_junit_formatter (~> 0.2.0)
serverspec (~> 2.7)
specinfra (~> 2.10)
@@ -87,7 +88,7 @@ PATH
PATH
remote: chef-config
specs:
- chef-config (12.12.2)
+ chef-config (12.13.21)
fuzzyurl (~> 0.8.0)
mixlib-config (~> 2.0)
mixlib-shellout (~> 2.0)
@@ -98,14 +99,14 @@ GEM
addressable (2.4.0)
appbundler (0.9.0)
mixlib-cli (~> 1.4)
- artifactory (2.3.2)
+ artifactory (2.3.3)
ast (2.3.0)
- aws-sdk (2.3.13)
- aws-sdk-resources (= 2.3.13)
- aws-sdk-core (2.3.13)
+ aws-sdk (2.3.19)
+ aws-sdk-resources (= 2.3.19)
+ aws-sdk-core (2.3.19)
jmespath (~> 1.0)
- aws-sdk-resources (2.3.13)
- aws-sdk-core (= 2.3.13)
+ aws-sdk-resources (2.3.19)
+ aws-sdk-core (= 2.3.19)
aws-sdk-v1 (1.66.0)
json (~> 1.4)
nokogiri (>= 1.4.4)
@@ -116,7 +117,7 @@ GEM
chef-api (0.6.0)
logify (~> 0.1)
mime-types
- chef-provisioning (1.7.1)
+ chef-provisioning (1.8.0)
cheffish (>= 1.3.1, < 3.0)
inifile (>= 2.0.2)
mixlib-install (~> 1.0)
@@ -124,7 +125,7 @@ GEM
net-ssh (>= 2.9, < 4.0)
net-ssh-gateway (~> 1.2.0)
winrm (~> 1.3)
- chef-provisioning-aws (1.9.0)
+ chef-provisioning-aws (1.10.0)
aws-sdk (>= 2.1.26, < 3.0)
aws-sdk-v1 (>= 1.59.0)
chef-provisioning (~> 1.4)
@@ -132,11 +133,11 @@ GEM
ubuntu_ami (~> 0.4, >= 0.4.1)
chef-rewind (0.0.9)
chef-sugar (3.3.0)
- chef-zero (4.6.2)
+ chef-zero (4.8.0)
ffi-yajl (~> 2.2)
hashie (>= 2.0, < 4.0)
mixlib-log (~> 1.3)
- rack
+ rack (< 2)
uuidtools (~> 2.1)
cheffish (2.0.4)
chef-zero (~> 4.3)
@@ -146,7 +147,7 @@ GEM
fauxhai (~> 3.2)
rspec (~> 3.0)
coderay (1.1.1)
- colorize (0.7.7)
+ colorize (0.8.1)
compat_resource (12.10.6)
cucumber-core (1.5.0)
gherkin (~> 4.0)
@@ -158,10 +159,12 @@ GEM
erubis (2.7.0)
faraday (0.9.2)
multipart-post (>= 1.2, < 3)
- fauxhai (3.5.0)
+ fauxhai (3.6.0)
net-ssh
ffi (1.9.10)
ffi (1.9.10-x86-mingw32)
+ ffi-win32-extensions (1.0.2)
+ ffi
ffi-yajl (2.2.3)
libyajl2 (~> 1.2)
foodcritic (6.3.0)
@@ -174,7 +177,7 @@ GEM
yajl-ruby (~> 1.1)
fuzzyurl (0.8.0)
gherkin (4.0.0)
- github_api (0.14.0)
+ github_api (0.14.2)
addressable (~> 2.4.0)
descendants_tracker (~> 0.0.4)
faraday (~> 0.8, < 0.10)
@@ -188,10 +191,10 @@ GEM
ffi (>= 1.0.1)
gyoku (1.3.1)
builder (>= 2.1.2)
- halite (1.2.1)
+ halite (1.3.0)
bundler
chef (~> 12.0)
- stove (~> 3.2, >= 3.2.3)
+ stove (~> 4.0)
thor
hashie (3.4.4)
highline (1.7.8)
@@ -217,11 +220,13 @@ GEM
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
mini_portile2 (2.1.0)
+ mixlib-archive (0.2.0)
+ mixlib-log
mixlib-authentication (1.4.1)
mixlib-log
mixlib-cli (1.6.0)
mixlib-config (2.2.1)
- mixlib-install (1.0.13)
+ mixlib-install (1.1.0)
artifactory
mixlib-shellout
mixlib-versioning
@@ -238,7 +243,7 @@ GEM
net-ssh (>= 2.6.5)
net-sftp (2.1.2)
net-ssh (>= 2.6.5)
- net-ssh (3.1.1)
+ net-ssh (3.2.0)
net-ssh-gateway (1.2.0)
net-ssh (>= 2.6.5)
net-ssh-multi (1.2.1)
@@ -261,7 +266,7 @@ GEM
rack (>= 1.2, < 3)
octokit (4.3.0)
sawyer (~> 0.7.0, >= 0.5.3)
- ohai (8.16.0)
+ ohai (8.17.1)
chef-config (>= 12.5.0.alpha.1, < 13)
ffi (~> 1.9)
ffi-yajl (~> 2.2)
@@ -277,7 +282,7 @@ GEM
ast (~> 2.2)
pkg-config (1.1.7)
plist (3.2.0)
- poise (2.7.0)
+ poise (2.7.1)
halite (~> 1.0)
polyglot (0.3.5)
powerpack (0.1.1)
@@ -297,25 +302,25 @@ GEM
pry (>= 0.9.11)
rack (1.6.4)
rainbow (2.1.0)
- rake (11.1.2)
+ rake (11.2.2)
rb-readline (0.5.3)
retryable (2.0.3)
- rspec (3.4.0)
- rspec-core (~> 3.4.0)
- rspec-expectations (~> 3.4.0)
- rspec-mocks (~> 3.4.0)
- rspec-core (3.4.4)
- rspec-support (~> 3.4.0)
- rspec-expectations (3.4.0)
+ rspec (3.5.0)
+ rspec-core (~> 3.5.0)
+ rspec-expectations (~> 3.5.0)
+ rspec-mocks (~> 3.5.0)
+ rspec-core (3.5.1)
+ rspec-support (~> 3.5.0)
+ rspec-expectations (3.5.0)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.4.0)
+ rspec-support (~> 3.5.0)
rspec-its (1.2.0)
rspec-core (>= 3.0.0)
rspec-expectations (>= 3.0.0)
- rspec-mocks (3.4.1)
+ rspec-mocks (3.5.0)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.4.0)
- rspec-support (3.4.1)
+ rspec-support (~> 3.5.0)
+ rspec-support (3.5.0)
rspec_junit_formatter (0.2.3)
builder (< 4)
rspec-core (>= 2, < 4, != 2.12.0)
@@ -345,23 +350,23 @@ GEM
simplecov-html (~> 0.10.0)
simplecov-html (0.10.0)
slop (3.6.0)
- specinfra (2.59.0)
+ specinfra (2.59.4)
net-scp
net-ssh (>= 2.7, < 4.0)
net-telnet
sfl
- stove (3.2.8)
+ stove (4.1.1)
chef-api (~> 0.5)
logify (~> 0.2)
syslog-logger (1.6.8)
systemu (2.6.5)
thor (0.19.1)
thread_safe (0.3.5)
- tomlrb (1.2.1)
+ tomlrb (1.2.2)
treetop (1.6.5)
polyglot (~> 0.3)
ubuntu_ami (0.4.1)
- unicode-display_width (1.0.5)
+ unicode-display_width (1.1.0)
uuidtools (2.1.5)
win32-api (1.5.3-universal-mingw32)
win32-dir (0.5.1)
@@ -370,7 +375,7 @@ GEM
win32-ipc (>= 0.6.0)
win32-eventlog (0.6.3)
ffi
- win32-ipc (0.6.6)
+ win32-ipc (0.7.0)
ffi
win32-mmap (0.4.2)
ffi
@@ -378,8 +383,9 @@ GEM
win32-ipc (>= 0.6.0)
win32-process (0.8.3)
ffi (>= 1.0.0)
- win32-service (0.8.7)
+ win32-service (0.8.9)
ffi
+ ffi-win32-extensions
windows-api (0.4.4)
win32-api (>= 1.4.5)
winrm (1.8.1)
@@ -423,7 +429,7 @@ DEPENDENCIES
pry-byebug
pry-remote
pry-stack_explorer
- rack
+ rack (< 2.0)
rake
rb-readline
ruby-prof
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 4d99cec89f..b3bba87dc0 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,57 +1,35 @@
*This file holds "in progress" release notes for the current release under development and is intended for consumption by the Chef Documentation team.
Please see `https://docs.chef.io/release/<major>-<minor>/release_notes.html` for the official Chef release notes.*
-# Chef Client Release Notes 12.11:
+# Chef Client Release Notes 12.12:
-## Support for RFC 062-based exit codes
+## Attribute read/write/unlink/exist? APIs
-[Chef RFC 062](https://github.com/chef/chef-rfc/blob/master/rfc062-exit-status.md) identifies standard exit codes for Chef Client. As of this release, When Chef exits with a non-standard exit code, a deprecation warning will be printed.
+On the node object:
-Also introduced is a new configuration setting - `exit_status`.
+- `node.read("foo", "bar", "baz")` equals `node["foo"]["bar"]["baz"] `but with safety (nil instead of exception)
+- `node.read!("foo", "bar", "baz")` equals `node["foo"]["bar"]["baz"]` and does raises NoMethodError
-By default in this release, `exit_status` is `nil` and the default behavior will be to warn on the use of deprecated and non-standard exit codes. `exit_status` can be set to `:enabled`, which will force chef-client to exit with the RFC defined exit codes and any non-standard exit statuses will be converted to `1` or GENERIC_FAILURE. `exit_status` can also be set to `:disabled` which preserves the old behavior of non-standardized exit status and skips the deprecation warnings.
+- `node.write(:default, "foo", "bar", "baz")` equals `node.default["foo"]["bar"] = "baz"` and autovivifies and replaces intermediate non-hash objects (very safe)
+- `node.write!(:default, "foo", "bar", "baz")` equals `node.default["foo"]["bar"] = "baz"` and while it autovivifies it can raise if you hit a non-hash on an intermediate key (NoMethodError)
+- there is still no non-autovivifying writer, and i don't think anyone really wants one.
+- `node.exist?("foo", "bar")` can be used to see if `node["foo"]["bar"]` exists
-## New Data Collector functionality for run statistics
+On node levels:
-The Data Collector feature is new to Chef 12.11 and is detailed in [Chef RFC 077](https://github.com/chef/chef-rfc/blob/master/rfc077-mode-agnostic-data-collection.md). It provides a unified method for sharing statistics about your Chef runs in a webhook-like manner. The Data Collector supports Chef in all its modes: Chef Client, Chef Solo (commonly referred to as "Chef Client Local Mode"), and Chef Solo legacy mode.
+- `node.default.read/read!("foo")` operates similarly to `node.read("foo")` but only on default level
+- `node.default.write/write!("foo", "bar")` is `node.write/write!(:default, "foo", "bar")`
+- `node.default.unlink/unlink!("foo")` is `node.unlink/unlink!(:default, "foo")`
+- `node.default.exist?("foo", "bar")` can be used to see if `node.default["foo"]["bar"]` exists
-To enable the Data Collector, specify the following settings in your client configuration file:
+Deprecations:
- * `data_collector.server_url`: Required. The URL to which the Chef Client will POST the Data Collector messages
- * `data_collector.token`: Optional. An token which will be sent in a `x-data-collector-token` HTTP header which can be used to authenticate the message.
- * `data_collector.mode`: The Chef mode in which the Data Collector should run. For example, this allows you to only enable Data Collector in Chef Solo but not Chef Client. Available options are `:solo`, `:client`, or `:both`. Default is `:both`.
- * `data_collector.raise_on_failure`: If enabled, Chef will raise an exception and fail to run if the Data Collector cannot be reached at the start of the Chef run. Defaults to `false`.
- * `data_collector.organization`: Optional. In Solo mode, the `organization` field in the messages will be set to this value. Default is `chef_solo`. This field does not apply to Chef Client mode.
+- node.set is deprecated
+- node.set_unless is deprecated
-## Replace chef-solo with chef-client local mode
+## `data_collector` enhancements
-The default operation of `chef-solo` is now the equivalent to `chef-client -z`, but allows for the old style `chef-solo` by uttering `chef-solo --legacy-mode`. As part of this effort, environment and role files written in ruby are now fully supported by `knife upload`.
+- Adds `node` to the `data_collector` message
+- `data_collector` reports on all resources and not just those that have been processed
-## Added a `systemd_unit` resource
-
-A new `systemd_unit` resource is now available. This resource supports the following properties:
-
-* `enabled` - boolean
-* `active` - boolean
-* `masked` - boolean
-* `static` - boolean
-* `user` - String
-* `content` - String or Hash
-* `triggers_reload` - boolean
-
-It has these possible actions:
-
-* `:nothing` - default
-* `:create`
-* `:delete`
-* `:enable`
-* `:disable`
-* `:mask`
-* `:unmask`
-* `:start`
-* `:stop`
-* `:restart`
-* `:reload`
-* `:try_restart`
-* `:reload_or_restart`
-* `:reload_or_try_restart`
+## `knife cookbook create` is deprecated. Use the chef-dk's `chef generate cookbook` instead. \ No newline at end of file
diff --git a/Rakefile b/Rakefile
index 7a9ff83cb9..74a30d45b0 100644
--- a/Rakefile
+++ b/Rakefile
@@ -29,12 +29,13 @@ require_relative "tasks/cbgb"
require_relative "tasks/dependencies"
require_relative "tasks/changelog"
-ChefConfig::PackageTask.new(File.expand_path("..", __FILE__), "Chef") do |package|
+ChefConfig::PackageTask.new(File.expand_path("..", __FILE__), "Chef", "chef") do |package|
package.component_paths = ["chef-config"]
package.generate_version_class = true
end
# Add a conservative dependency update to version:bump (which was created by PackageTask)
-task "version:bump" => %w{version:bump_patch version:update bundle:install}
+task "version:bump" => %w{version:bump_patch version:update}
+task "version:bump" => %w{version:bump_patch version:update}
task :pedant, :chef_zero_spec
diff --git a/VERSION b/VERSION
index b6c97aea42..db43bd81fe 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-12.12.2 \ No newline at end of file
+12.13.21 \ No newline at end of file
diff --git a/acceptance/.gitignore b/acceptance/.gitignore
index c2ab70737d..4b0b151d75 100644
--- a/acceptance/.gitignore
+++ b/acceptance/.gitignore
@@ -1 +1,3 @@
.acceptance_logs
+.acceptance_data
+data-collector/Berksfile.lock
diff --git a/acceptance/.shared/kitchen_acceptance/.kitchen.ec2.yml b/acceptance/.shared/kitchen_acceptance/.kitchen.ec2.yml
index 40228829bb..dfe3d888a0 100644
--- a/acceptance/.shared/kitchen_acceptance/.kitchen.ec2.yml
+++ b/acceptance/.shared/kitchen_acceptance/.kitchen.ec2.yml
@@ -213,18 +213,7 @@ platforms:
image-type: machine
user_data: |
<powershell>
- $logfile="C:\\Program Files\\Amazon\\Ec2ConfigService\\Logs\\kitchen-ec2.log"
- #PS Remoting and & winrm.cmd basic config
- Enable-PSRemoting -Force -SkipNetworkProfileCheck
- & winrm.cmd set winrm/config '@{MaxTimeoutms="1800000"}' >> $logfile
- & winrm.cmd set winrm/config/winrs '@{MaxMemoryPerShellMB="1024"}' >> $logfile
- & winrm.cmd set winrm/config/winrs '@{MaxShellsPerUser="50"}' >> $logfile
- #Server settings - support username/password login
- & winrm.cmd set winrm/config/service/auth '@{Basic="true"}' >> $logfile
- & winrm.cmd set winrm/config/service '@{AllowUnencrypted="true"}' >> $logfile
- & winrm.cmd set winrm/config/winrs '@{MaxMemoryPerShellMB="1024"}' >> $logfile
- #Firewall Config
- & netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" profile=public protocol=tcp localport=5985 remoteip=localsubnet new remoteip=any >> $logfile
+ & netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" profile=public protocol=tcp localport=5985 remoteip=localsubnet new remoteip=any
#Set script execution to unrestricted
& Set-ExecutionPolicy Unrestricted -Force
</powershell>
diff --git a/acceptance/.shared/kitchen_acceptance/libraries/kitchen.rb b/acceptance/.shared/kitchen_acceptance/libraries/kitchen.rb
index d36909e8b3..d5d2e1380b 100644
--- a/acceptance/.shared/kitchen_acceptance/libraries/kitchen.rb
+++ b/acceptance/.shared/kitchen_acceptance/libraries/kitchen.rb
@@ -1,3 +1,5 @@
+require 'chef/mixin/shell_out'
+
module KitchenAcceptance
class Kitchen < Chef::Resource
resource_name :kitchen
@@ -33,18 +35,33 @@ module KitchenAcceptance
property :kitchen_options, String, default: lazy { ENV["PROJECT_NAME"] ? "-c -l debug" : "-c" }
action :run do
- execute "bundle exec kitchen #{command}#{instances ? " #{instances}" : ""}#{kitchen_options ? " #{kitchen_options}" : ""}" do
- cwd kitchen_dir
- env({
- "KITCHEN_DRIVER" => driver,
- "KITCHEN_INSTANCES" => instances,
- "KITCHEN_LOCAL_YAML" => ::File.expand_path("../../.kitchen.#{driver}.yml", __FILE__),
- "KITCHEN_CHEF_PRODUCT" => chef_product,
- "KITCHEN_CHEF_CHANNEL" => chef_channel,
- "KITCHEN_CHEF_VERSION" => chef_version,
- "ARTIFACTORY_USERNAME" => artifactory_username,
- "ARTIFACTORY_PASSWORD" => artifactory_password
- }.merge(new_resource.env))
+
+ ruby_block "copy_kitchen_logs_to_data_path" do
+ block do
+ cmd_env = {
+ "KITCHEN_DRIVER" => driver,
+ "KITCHEN_INSTANCES" => instances,
+ "KITCHEN_LOCAL_YAML" => ::File.expand_path("../../.kitchen.#{driver}.yml", __FILE__),
+ "KITCHEN_CHEF_PRODUCT" => chef_product,
+ "KITCHEN_CHEF_CHANNEL" => chef_channel,
+ "KITCHEN_CHEF_VERSION" => chef_version,
+ "ARTIFACTORY_USERNAME" => artifactory_username,
+ "ARTIFACTORY_PASSWORD" => artifactory_password
+ }.merge(new_resource.env)
+ suite = kitchen_dir.split("/").last
+ kitchen_log_path = ENV["WORKSPACE"] ? "#{ENV["WORKSPACE"]}/chef-acceptance-data/logs" : "#{kitchen_dir}/../.acceptance_data/logs/"
+
+ begin
+ shell_out!("bundle exec kitchen #{command}#{instances ? " #{instances}" : ""}#{kitchen_options ? " #{kitchen_options}" : ""}",
+ env: cmd_env,
+ timeout: 60 * 30,
+ live_stream: STDOUT,
+ cwd: kitchen_dir)
+ ensure
+ FileUtils.mkdir_p("#{kitchen_log_path}/#{suite}/#{command}")
+ FileUtils.cp_r("#{kitchen_dir}/.kitchen/logs/.", "#{kitchen_log_path}/#{suite}/#{command}")
+ end
+ end
end
end
end
diff --git a/acceptance/Gemfile b/acceptance/Gemfile
index 185437ed71..b521df8607 100644
--- a/acceptance/Gemfile
+++ b/acceptance/Gemfile
@@ -1,13 +1,16 @@
source "https://rubygems.org"
gem "chef-acceptance", github: "chef/chef-acceptance"
-gem "test-kitchen"
gem "kitchen-ec2"
-gem "kitchen-inspec"
gem "inspec"
# Pinning to github for kitchen-vagrant because 0.19.0 incorrectly
# puts in a box_url for bento when a vagrant box in atlas is specified
gem "kitchen-vagrant"
gem "windows_chef_zero"
-gem "winrm-fs"
+gem "kitchen-inspec", :github => "mwrock/kitchen-inspec", :branch => "winrm-v2"
+gem "test-kitchen", :github => "test-kitchen", :branch => "winrm-v2"
+gem "train", :github => "chef/train", :branch => "winrm-v2"
+gem "winrm", :github => "winrb/winrm", :branch => "winrm-v2"
+gem "winrm-fs", :github => "winrb/winrm-fs", :branch => "winrm-v2"
+gem "winrm-elevated", :github => "winrb/winrm-elevated", :branch => "winrm-v2"
gem "berkshelf"
diff --git a/acceptance/Gemfile.lock b/acceptance/Gemfile.lock
index 840e1a49c4..ff9d439b5b 100644
--- a/acceptance/Gemfile.lock
+++ b/acceptance/Gemfile.lock
@@ -6,18 +6,89 @@ GIT
mixlib-shellout (~> 2.0)
thor (~> 0.19)
+GIT
+ remote: git://github.com/chef/train.git
+ revision: cc92f89267f128ee78bc12da803722268e2f6af2
+ branch: winrm-v2
+ specs:
+ train (0.15.0)
+ docker-api (~> 1.26)
+ json (~> 1.8)
+ mixlib-shellout (~> 2.0)
+ net-scp (~> 1.2)
+ net-ssh (>= 2.9, < 4.0)
+ winrm (~> 2.0)
+ winrm-fs (~> 1.0)
+
+GIT
+ remote: git://github.com/mwrock/kitchen-inspec.git
+ revision: d63240a44667974070298ad4fca20394257c92bd
+ branch: winrm-v2
+ specs:
+ kitchen-inspec (0.14.0)
+ inspec (>= 0.22.0, < 1.0.0)
+ test-kitchen (~> 1.6)
+
+GIT
+ remote: git://github.com/test-kitchen/test-kitchen.git
+ revision: 06d7c0168ed6390c87a821ae8958e7d80c4d1912
+ branch: winrm-v2
+ specs:
+ test-kitchen (1.10.2)
+ mixlib-install (~> 1.0, >= 1.0.4)
+ mixlib-shellout (>= 1.2, < 3.0)
+ net-scp (~> 1.1)
+ net-ssh (>= 2.9, < 4.0)
+ safe_yaml (~> 1.0)
+ thor (~> 0.18)
+
+GIT
+ remote: git://github.com/winrb/winrm-elevated.git
+ revision: 160bf424e018b2539fdde73079443e565ae57260
+ branch: winrm-v2
+ specs:
+ winrm-elevated (1.0.0)
+ winrm (~> 2.0)
+ winrm-fs (~> 1.0)
+
+GIT
+ remote: git://github.com/winrb/winrm-fs.git
+ revision: ceb883b87fb81898e73e9249f287457ccb9d549f
+ branch: winrm-v2
+ specs:
+ winrm-fs (1.0.0)
+ erubis (~> 2.7)
+ logging (>= 1.6.1, < 3.0)
+ rubyzip (~> 1.1)
+ winrm
+
+GIT
+ remote: git://github.com/winrb/winrm.git
+ revision: 0f35bbd963024b32cc8e262f25e6110c6abf5794
+ branch: winrm-v2
+ specs:
+ winrm (2.0.0)
+ builder (>= 2.1.2)
+ erubis (~> 2.7)
+ gssapi (~> 1.2)
+ gyoku (~> 1.0)
+ httpclient (~> 2.2, >= 2.2.0.2)
+ logging (>= 1.6.1, < 3.0)
+ nori (~> 2.0)
+ rubyntlm (~> 0.6.0)
+
GEM
remote: https://rubygems.org/
specs:
addressable (2.4.0)
- artifactory (2.3.2)
- aws-sdk (2.3.9)
- aws-sdk-resources (= 2.3.9)
- aws-sdk-core (2.3.9)
+ artifactory (2.3.3)
+ aws-sdk (2.4.2)
+ aws-sdk-resources (= 2.4.2)
+ aws-sdk-core (2.4.2)
jmespath (~> 1.0)
- aws-sdk-resources (2.3.9)
- aws-sdk-core (= 2.3.9)
- berkshelf (4.3.3)
+ aws-sdk-resources (2.4.2)
+ aws-sdk-core (= 2.4.2)
+ berkshelf (4.3.5)
addressable (~> 2.3, >= 2.3.4)
berkshelf-api-client (~> 2.0, >= 2.0.2)
buff-config (~> 1.0)
@@ -29,6 +100,7 @@ GEM
faraday (~> 0.9)
httpclient (~> 2.7)
minitar (~> 0.5, >= 0.5.4)
+ mixlib-archive (~> 0.1)
octokit (~> 4.0)
retryable (~> 2.0)
ridley (~> 4.5)
@@ -52,21 +124,21 @@ GEM
celluloid-io (0.16.2)
celluloid (>= 0.16.0)
nio4r (>= 1.1.0)
- chef-config (12.10.24)
+ chef-config (12.12.15)
fuzzyurl (~> 0.8.0)
mixlib-config (~> 2.0)
mixlib-shellout (~> 2.0)
cleanroom (1.0.0)
coderay (1.1.1)
diff-lcs (1.2.5)
- docker-api (1.28.0)
+ docker-api (1.29.1)
excon (>= 0.38.0)
json
erubis (2.7.0)
- excon (0.49.0)
+ excon (0.51.0)
faraday (0.9.2)
multipart-post (>= 1.2, < 3)
- ffi (1.9.10)
+ ffi (1.9.14)
fuzzyurl (0.8.0)
gssapi (1.2.0)
ffi (>= 1.0.1)
@@ -75,30 +147,25 @@ GEM
hashie (3.4.4)
hitimes (1.2.4)
httpclient (2.7.2)
- inspec (0.22.1)
+ inspec (0.26.0)
hashie (~> 3.4)
json (~> 1.8)
method_source (~> 0.8)
pry (~> 0)
- r-train (~> 0.12)
rainbow (~> 2)
rspec (~> 3)
rspec-its (~> 1.2)
rubyzip (~> 1.1)
thor (~> 0.19)
- jmespath (1.2.4)
- json_pure (>= 1.8.1)
+ train (~> 0.13)
+ jmespath (1.3.1)
json (1.8.3)
- json_pure (1.8.3)
- kitchen-ec2 (1.0.0)
+ kitchen-ec2 (1.0.1)
aws-sdk (~> 2)
excon
multi_json
retryable (~> 2.0)
test-kitchen (~> 1.4, >= 1.4.1)
- kitchen-inspec (0.14.0)
- inspec (>= 0.22.0, < 1.0.0)
- test-kitchen (~> 1.6)
kitchen-vagrant (0.20.0)
test-kitchen (~> 1.4)
little-plugger (1.1.4)
@@ -107,13 +174,12 @@ GEM
multi_json (~> 1.10)
method_source (0.8.2)
minitar (0.5.4)
- mixlib-authentication (1.4.0)
+ mixlib-archive (0.2.0)
+ mixlib-log
+ mixlib-authentication (1.4.1)
mixlib-log
- rspec-core (~> 3.2)
- rspec-expectations (~> 3.2)
- rspec-mocks (~> 3.2)
mixlib-config (2.2.1)
- mixlib-install (1.0.12)
+ mixlib-install (1.1.0)
artifactory
mixlib-shellout
mixlib-versioning
@@ -125,26 +191,18 @@ GEM
multipart-post (2.0.0)
net-scp (1.2.1)
net-ssh (>= 2.6.5)
- net-ssh (3.1.1)
+ net-ssh (3.2.0)
nio4r (1.2.1)
nori (2.6.0)
octokit (4.3.0)
sawyer (~> 0.7.0, >= 0.5.3)
- pry (0.10.3)
+ pry (0.10.4)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
- r-train (0.12.1)
- docker-api (~> 1.26)
- json (~> 1.8)
- mixlib-shellout (~> 2.0)
- net-scp (~> 1.2)
- net-ssh (>= 2.9, < 4.0)
- winrm (~> 1.6)
- winrm-fs (~> 0.3)
rainbow (2.1.0)
- retryable (2.0.3)
- ridley (4.5.1)
+ retryable (2.0.4)
+ ridley (4.6.0)
addressable
buff-config (~> 1.0)
buff-extensions (~> 1.0)
@@ -162,22 +220,22 @@ GEM
retryable (~> 2.0)
semverse (~> 1.1)
varia_model (~> 0.4.0)
- rspec (3.4.0)
- rspec-core (~> 3.4.0)
- rspec-expectations (~> 3.4.0)
- rspec-mocks (~> 3.4.0)
- rspec-core (3.4.4)
- rspec-support (~> 3.4.0)
- rspec-expectations (3.4.0)
+ rspec (3.5.0)
+ rspec-core (~> 3.5.0)
+ rspec-expectations (~> 3.5.0)
+ rspec-mocks (~> 3.5.0)
+ rspec-core (3.5.1)
+ rspec-support (~> 3.5.0)
+ rspec-expectations (3.5.0)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.4.0)
+ rspec-support (~> 3.5.0)
rspec-its (1.2.0)
rspec-core (>= 3.0.0)
rspec-expectations (>= 3.0.0)
- rspec-mocks (3.4.1)
+ rspec-mocks (3.5.0)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.4.0)
- rspec-support (3.4.1)
+ rspec-support (~> 3.5.0)
+ rspec-support (3.5.0)
rubyntlm (0.6.0)
rubyzip (1.2.0)
safe_yaml (1.0.4)
@@ -189,13 +247,6 @@ GEM
solve (2.0.3)
molinillo (~> 0.4.2)
semverse (~> 1.1)
- test-kitchen (1.9.0)
- mixlib-install (~> 1.0, >= 1.0.4)
- mixlib-shellout (>= 1.2, < 3.0)
- net-scp (~> 1.1)
- net-ssh (>= 2.9, < 4.0)
- safe_yaml (~> 1.0)
- thor (~> 0.18)
thor (0.19.1)
timers (4.0.4)
hitimes
@@ -204,19 +255,6 @@ GEM
hashie (>= 2.0.2, < 4.0.0)
windows_chef_zero (2.0.0)
test-kitchen (>= 1.2.1)
- winrm (1.8.1)
- builder (>= 2.1.2)
- gssapi (~> 1.2)
- gyoku (~> 1.0)
- httpclient (~> 2.2, >= 2.2.0.2)
- logging (>= 1.6.1, < 3.0)
- nori (~> 2.0)
- rubyntlm (~> 0.6.0)
- winrm-fs (0.4.2)
- erubis (~> 2.7)
- logging (>= 1.6.1, < 3.0)
- rubyzip (~> 1.1)
- winrm (~> 1.5)
PLATFORMS
ruby
@@ -226,11 +264,14 @@ DEPENDENCIES
chef-acceptance!
inspec
kitchen-ec2
- kitchen-inspec
+ kitchen-inspec!
kitchen-vagrant
- test-kitchen
+ test-kitchen!
+ train!
windows_chef_zero
- winrm-fs
+ winrm!
+ winrm-elevated!
+ winrm-fs!
BUNDLED WITH
1.12.5
diff --git a/acceptance/data-collector/Berksfile.lock b/acceptance/data-collector/Berksfile.lock
deleted file mode 100644
index 39f4ce30dc..0000000000
--- a/acceptance/data-collector/Berksfile.lock
+++ /dev/null
@@ -1,6 +0,0 @@
-DEPENDENCIES
- data-collector-test
- path: .acceptance/data-collector-test
-
-GRAPH
- data-collector-test (0.1.0)
diff --git a/acceptance/data-collector/test/integration/default/serverspec/default_spec.rb b/acceptance/data-collector/test/integration/default/serverspec/default_spec.rb
index be15b96429..f9d365ac58 100644
--- a/acceptance/data-collector/test/integration/default/serverspec/default_spec.rb
+++ b/acceptance/data-collector/test/integration/default/serverspec/default_spec.rb
@@ -110,6 +110,7 @@ shared_examples_for "run_converge.success payload check" do
expanded_run_list
message_type
message_version
+ node
node_name
organization_name
resources
@@ -150,6 +151,7 @@ shared_examples_for "run_converge.failure payload check" do
expanded_run_list
message_type
message_version
+ node
node_name
organization_name
resources
@@ -178,44 +180,6 @@ shared_examples_for "run_converge.failure payload check" do
end
end
-shared_examples_for "node-update payload check" do
- describe "node update message" do
- let(:required_fields) do
- %w{
- entity_name
- entity_type
- entity_uuid
- id
- message_type
- message_version
- organization_name
- recorded_at
- remote_hostname
- requestor_name
- requestor_type
- run_id
- service_hostname
- source
- task
- user_agent
- }
- end
- let(:optional_fields) { %{data} }
-
- it "is not missing any required fields" do
- payload = JSON.load(command("curl http://localhost:9292/cache/action").stdout)
- missing_fields = required_fields.select { |key| !payload.key?(key) }
- expect(missing_fields).to eq([])
- end
-
- it "does not have any extra fields" do
- payload = JSON.load(command("curl http://localhost:9292/cache/action").stdout)
- extra_fields = payload.keys.select { |key| !required_fields.include?(key) && !optional_fields.include?(key) }
- expect(extra_fields).to eq([])
- end
- end
-end
-
describe "CCR with no data collector URL configured" do
include_examples "successful chef run", "chef-client -z -c /etc/chef/no-endpoint.rb"
include_examples "counter checks", { "run_start" => nil, "run_converge.success" => nil, "run_converge.failure" => nil }
@@ -226,7 +190,6 @@ describe "CCR, local mode, config in solo mode" do
include_examples "counter checks", { "run_start" => 1, "run_converge.success" => 1, "run_converge.failure" => nil }
include_examples "run_start payload check"
include_examples "run_converge.success payload check"
- include_examples "node-update payload check"
end
describe "CCR, local mode, config in client mode" do
@@ -239,7 +202,6 @@ describe "CCR, local mode, config in both mode" do
include_examples "counter checks", { "run_start" => 1, "run_converge.success" => 1, "run_converge.failure" => nil }
include_examples "run_start payload check"
include_examples "run_converge.success payload check"
- include_examples "node-update payload check"
end
describe "CCR, local mode, config in solo mode, failed run" do
@@ -247,5 +209,4 @@ describe "CCR, local mode, config in solo mode, failed run" do
include_examples "counter checks", { "run_start" => 1, "run_converge.success" => nil, "run_converge.failure" => 1 }
include_examples "run_start payload check"
include_examples "run_converge.failure payload check"
- include_examples "node-update payload check"
end
diff --git a/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/libraries/top_cookbooks.rb b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/libraries/top_cookbooks.rb
index 203ea9809a..73f5151bca 100644
--- a/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/libraries/top_cookbooks.rb
+++ b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/libraries/top_cookbooks.rb
@@ -3,6 +3,8 @@ class TopCookbooks < Chef::Resource
property :command, String, name_property: true
+ # Disabling all windows tests until winrm issue is properly settled.
+ #
action :run do
cookbook_kitchen "#{command} docker" do
end
@@ -33,8 +35,6 @@ class TopCookbooks < Chef::Resource
repository "adamedx/winbox"
end
- # Temporarily disabling windows and chocolatey to eliminate
- # transient errors on the builders
# cookbook_kitchen "#{command} windows" do
# end
diff --git a/acceptance/trivial/.kitchen.yml b/acceptance/trivial/.kitchen.yml
index 1e0af03503..0db67c468f 100644
--- a/acceptance/trivial/.kitchen.yml
+++ b/acceptance/trivial/.kitchen.yml
@@ -3,5 +3,5 @@ verifier:
suites:
- name: chef-current-install
- includes: [windows-2012r2]
+ includes: [ubuntu-14.04, windows-server-2012r2]
run_list:
diff --git a/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/destroy.rb b/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/destroy.rb
index e2d663ac2f..e12f938cf3 100644
--- a/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/destroy.rb
+++ b/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/destroy.rb
@@ -1 +1 @@
-kitchen "destroy"
+#kitchen "destroy"
diff --git a/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/provision.rb b/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/provision.rb
index 5726c0e7b5..cec9de4e5d 100644
--- a/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/provision.rb
+++ b/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/provision.rb
@@ -1 +1 @@
-kitchen "converge"
+#kitchen "converge"
diff --git a/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/verify.rb b/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/verify.rb
index 05ac94ce66..52e3560cf6 100644
--- a/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/verify.rb
+++ b/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/verify.rb
@@ -1 +1 @@
-kitchen "verify"
+#kitchen "verify"
diff --git a/acceptance/windows-service/test/integration/chef-windows-service/inspec/chef_windows_service_spec.rb b/acceptance/windows-service/test/integration/chef-windows-service/inspec/chef_windows_service_spec.rb
index a791177362..75383b69bf 100644
--- a/acceptance/windows-service/test/integration/chef-windows-service/inspec/chef_windows_service_spec.rb
+++ b/acceptance/windows-service/test/integration/chef-windows-service/inspec/chef_windows_service_spec.rb
@@ -13,7 +13,7 @@ describe service("chef-client") do
it { should_not be_running }
end
-describe command("chef-service-manager -a install") do
+describe command("/opscode/chef/bin/chef-service-manager.bat -a install") do
its("exit_status") { should eq 0 }
its(:stdout) { should match /Service 'chef-client' has successfully been installed./ }
end
@@ -24,7 +24,7 @@ describe service("chef-client") do
it { should_not be_running }
end
-describe command("chef-service-manager -a start") do
+describe command("/opscode/chef/bin/chef-service-manager.bat -a start") do
its("exit_status") { should eq 0 }
its(:stdout) { should match /Service 'chef-client' is now 'running'/ }
end
@@ -35,7 +35,7 @@ describe service("chef-client") do
it { should be_running }
end
-describe command("chef-service-manager -a stop") do
+describe command("/opscode/chef/bin/chef-service-manager.bat -a stop") do
its("exit_status") { should eq 0 }
its(:stdout) { should match /Service 'chef-client' is now 'stopped'/ }
end
@@ -46,7 +46,7 @@ describe service("chef-client") do
it { should_not be_running }
end
-describe command("chef-service-manager -a uninstall") do
+describe command("/opscode/chef/bin/chef-service-manager.bat -a uninstall") do
its("exit_status") { should eq 0 }
its(:stdout) { should match /Service chef-client deleted/ }
end
diff --git a/chef-config/Rakefile b/chef-config/Rakefile
index 46f87c96c9..fd6497a287 100644
--- a/chef-config/Rakefile
+++ b/chef-config/Rakefile
@@ -1,6 +1,6 @@
require "chef-config/package_task"
-ChefConfig::PackageTask.new(File.expand_path("..", __FILE__), "ChefConfig") do |package|
+ChefConfig::PackageTask.new(File.expand_path("..", __FILE__), "ChefConfig", "chef-config") do |package|
package.module_path = "chef-config"
end
diff --git a/chef-config/lib/chef-config/config.rb b/chef-config/lib/chef-config/config.rb
index 568467456f..a194edc80e 100644
--- a/chef-config/lib/chef-config/config.rb
+++ b/chef-config/lib/chef-config/config.rb
@@ -132,8 +132,8 @@ module ChefConfig
until File.directory?(PathHelper.join(path, "cookbooks")) || File.directory?(PathHelper.join(path, "cookbook_artifacts"))
new_path = File.expand_path("..", path)
if new_path == path
- ChefConfig.logger.warn("No cookbooks directory found at or above current directory. Assuming #{Dir.pwd}.")
- return Dir.pwd
+ ChefConfig.logger.warn("No cookbooks directory found at or above current directory. Assuming #{cwd}.")
+ return cwd
end
path = new_path
end
@@ -519,7 +519,16 @@ module ChefConfig
# Set to true if Chef is to set OpenSSL to run in FIPS mode
default(:fips) do
- !ENV["CHEF_FIPS"].nil? || ChefConfig.fips?
+ # CHEF_FIPS is used in testing to override checking for system level
+ # enablement. There are 3 possible values that this variable may have:
+ # nil - no override and the system will be checked
+ # empty - FIPS is NOT enabled
+ # a non empty value - FIPS is enabled
+ if ENV["CHEF_FIPS"] == ""
+ false
+ else
+ !ENV["CHEF_FIPS"].nil? || ChefConfig.fips?
+ end
end
# Initialize openssl
diff --git a/chef-config/lib/chef-config/package_task.rb b/chef-config/lib/chef-config/package_task.rb
index b984f60f9f..eb257ff4b5 100644
--- a/chef-config/lib/chef-config/package_task.rb
+++ b/chef-config/lib/chef-config/package_task.rb
@@ -31,6 +31,10 @@ module ChefConfig
# the top level module which contains VERSION and MODULE_ROOT.
attr_accessor :module_name
+ # Name of the gem being built. This is used to find the lines to fix in
+ # Gemfile.lock.
+ attr_accessor :gem_name
+
# Should the generated version.rb be in a class or module? Default is false (module).
attr_accessor :generate_version_class
@@ -55,15 +59,16 @@ module ChefConfig
# Name of git remote used to push tags during a release. Default is origin.
attr_accessor :git_remote
- def initialize(root_path = nil, module_name = nil)
- init(root_path, module_name)
+ def initialize(root_path = nil, module_name = nil, gem_name = nil)
+ init(root_path, module_name, gem_name)
yield self if block_given?
define unless root_path.nil? || module_name.nil?
end
- def init(root_path, module_name)
+ def init(root_path, module_name, gem_name)
@root_path = root_path
@module_name = module_name
+ @gem_name = gem_name
@component_paths = []
@module_path = nil
@package_dir = "pkg"
@@ -87,6 +92,10 @@ module ChefConfig
File.join(chef_root_path, "VERSION")
end
+ def gemfile_lock_path
+ File.join(root_path, "Gemfile.lock")
+ end
+
def version
IO.read(version_file_path).strip
end
@@ -155,6 +164,26 @@ module ChefConfig
namespace :version do
desc 'Regenerate lib/#{@module_path}/version.rb from VERSION file'
task :update => :update_components_versions do
+ update_version_rb
+ update_gemfile_lock
+ end
+
+ task :bump => %w{version:bump_patch version:update}
+
+ task :show do
+ puts version
+ end
+
+ # Add 1 to the current patch version in the VERSION file, and write it back out.
+ task :bump_patch do
+ current_version = version
+ new_version = current_version.sub(/^(\d+\.\d+\.)(\d+)/) { "#{$1}#{$2.to_i + 1}" }
+ puts "Updating version in #{version_rb_path} from #{current_version.chomp} to #{new_version.chomp}"
+ IO.write(version_file_path, new_version)
+ end
+
+ def update_version_rb
+ puts "Updating #{version_rb_path} to include version #{version} ..."
contents = <<-VERSION_RB
# Copyright:: Copyright 2010-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
@@ -194,18 +223,15 @@ end
IO.write(version_rb_path, contents)
end
- task :bump => %w{version:bump_patch version:update}
-
- task :show do
- puts version
- end
-
- # Add 1 to the current patch version in the VERSION file, and write it back out.
- task :bump_patch do
- current_version = version
- new_version = current_version.sub(/^(\d+\.\d+\.)(\d+)/) { "#{$1}#{$2.to_i + 1}" }
- puts "Updating version in #{version_rb_path} from #{current_version.chomp} to #{new_version.chomp}"
- IO.write(version_file_path, new_version)
+ def update_gemfile_lock
+ if File.exist?(gemfile_lock_path)
+ puts "Updating #{gemfile_lock_path} to include version #{version} ..."
+ contents = IO.read(gemfile_lock_path)
+ contents.gsub!(/^\s*(chef|chef-config)\s*\((= )?\S+\)\s*$/) do |line|
+ line.gsub(/\((= )?\d+(\.\d+)+/) { "(#{$1}#{version}" }
+ end
+ IO.write(gemfile_lock_path, contents)
+ end
end
end
diff --git a/chef-config/lib/chef-config/version.rb b/chef-config/lib/chef-config/version.rb
index 3b1cf7aa51..d428427cbe 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.12.2"
+ VERSION = "12.13.21"
end
#
diff --git a/chef-config/spec/unit/config_spec.rb b/chef-config/spec/unit/config_spec.rb
index f09dbb517a..0ddb56cf0d 100644
--- a/chef-config/spec/unit/config_spec.rb
+++ b/chef-config/spec/unit/config_spec.rb
@@ -186,6 +186,16 @@ RSpec.describe ChefConfig::Config do
expect(ChefConfig::Config[:fips]).to eq(false)
end
+ context "when ENV['CHEF_FIPS'] is empty" do
+ before do
+ ENV["CHEF_FIPS"] = ""
+ end
+
+ it "returns false" do
+ expect(ChefConfig::Config[:fips]).to eq(false)
+ end
+ end
+
context "when ENV['CHEF_FIPS'] is set" do
before do
ENV["CHEF_FIPS"] = "1"
diff --git a/chef.gemspec b/chef.gemspec
index b88c899d5c..14b31ca23e 100644
--- a/chef.gemspec
+++ b/chef.gemspec
@@ -17,10 +17,11 @@ Gem::Specification.new do |s|
s.add_dependency "chef-config", "= #{Chef::VERSION}"
- s.add_dependency "mixlib-cli", "~> 1.4"
+ s.add_dependency "mixlib-cli", "~> 1.4", "< 1.7"
s.add_dependency "mixlib-log", "~> 1.3"
s.add_dependency "mixlib-authentication", "~> 1.4"
s.add_dependency "mixlib-shellout", "~> 2.0"
+ s.add_dependency "mixlib-archive", ">= 0.2.0"
s.add_dependency "ohai", ">= 8.6.0.alpha.1", "< 9"
s.add_dependency "ffi-yajl", "~> 2.2"
@@ -31,13 +32,13 @@ Gem::Specification.new do |s|
s.add_dependency "erubis", "~> 2.7"
s.add_dependency "diff-lcs", "~> 1.2", ">= 1.2.4"
- s.add_dependency "chef-zero", "~> 4.5"
+ s.add_dependency "chef-zero", "~> 4.8"
s.add_dependency "plist", "~> 3.2"
s.add_dependency "iniparse", "~> 1.4"
# Audit mode requires these, so they are non-developmental dependencies now
- %w{rspec-core rspec-expectations rspec-mocks}.each { |gem| s.add_dependency gem, "~> 3.4" }
+ %w{rspec-core rspec-expectations rspec-mocks}.each { |gem| s.add_dependency gem, "~> 3.5" }
s.add_dependency "rspec_junit_formatter", "~> 0.2.0"
s.add_dependency "serverspec", "~> 2.7"
s.add_dependency "specinfra", "~> 2.10"
diff --git a/kitchen-tests/.kitchen.travis.yml b/kitchen-tests/.kitchen.travis.yml
index 99486928de..dd92b832dc 100644
--- a/kitchen-tests/.kitchen.travis.yml
+++ b/kitchen-tests/.kitchen.travis.yml
@@ -24,6 +24,7 @@ provisioner:
verifier:
name: inspec
+ format: progress
platforms:
- name: debian-7
diff --git a/kitchen-tests/.kitchen.yml b/kitchen-tests/.kitchen.yml
index c02ea55a02..314857663e 100644
--- a/kitchen-tests/.kitchen.yml
+++ b/kitchen-tests/.kitchen.yml
@@ -7,6 +7,7 @@ driver:
verifier:
name: inspec
+ format: progress
provisioner:
name: chef_github
diff --git a/kitchen-tests/Berksfile b/kitchen-tests/Berksfile
index 31e49b3e18..407b685236 100644
--- a/kitchen-tests/Berksfile
+++ b/kitchen-tests/Berksfile
@@ -5,4 +5,4 @@ cookbook "base", path: "cookbooks/base"
cookbook "php", "~> 1.5.0"
-cookbook "resolver", github: "chef-cookbooks/resolver", branch: "lcg/docker"
+cookbook "resolver", github: "chef-cookbooks/resolver"
diff --git a/kitchen-tests/Berksfile.lock b/kitchen-tests/Berksfile.lock
index f4a9de89e2..eeecf4954f 100644
--- a/kitchen-tests/Berksfile.lock
+++ b/kitchen-tests/Berksfile.lock
@@ -4,15 +4,15 @@ DEPENDENCIES
php (~> 1.5.0)
resolver
git: git://github.com/chef-cookbooks/resolver.git
- revision: dd65ab8e2346cc0739c13682c74868f5b939b06a
- branch: lcg/docker
+ revision: 8bf9034dabc47d29a07870e4059c32114f2c820a
webapp
path: cookbooks/webapp
GRAPH
apache2 (3.2.2)
- apt (3.0.0)
- aws (3.3.3)
+ apt (4.0.1)
+ compat_resource (>= 12.10)
+ aws (3.4.0)
ohai (>= 2.1.0)
base (0.1.0)
apt (>= 0.0.0)
@@ -30,18 +30,19 @@ GRAPH
ubuntu (>= 0.0.0)
users (>= 0.0.0)
yum-epel (>= 0.0.0)
- build-essential (4.0.0)
- mingw (>= 0.0.0)
+ build-essential (6.0.0)
+ compat_resource (>= 12.10)
+ mingw (>= 1.1)
seven_zip (>= 0.0.0)
- chef-client (4.5.2)
+ chef-client (4.6.0)
cron (>= 1.7.0)
logrotate (>= 1.9.0)
- windows (>= 1.39.0)
+ windows (>= 1.42.0)
chef-sugar (3.3.0)
chef_handler (1.4.0)
chef_hostname (0.4.1)
compat_resource (>= 0.0.0)
- compat_resource (12.10.4)
+ compat_resource (12.10.6)
cron (1.7.6)
database (2.3.1)
aws (>= 0.0.0)
@@ -49,11 +50,11 @@ GRAPH
mysql-chef_gem (~> 0.0)
postgresql (>= 1.0.0)
xfs (>= 0.0.0)
- iis (4.1.7)
+ iis (4.1.10)
windows (>= 1.34.6)
iptables (2.2.0)
logrotate (1.9.2)
- mingw (1.0.0)
+ mingw (1.2.2)
compat_resource (>= 0.0.0)
seven_zip (>= 0.0.0)
multipackage (3.0.28)
@@ -63,12 +64,12 @@ GRAPH
mysql-chef_gem (0.0.5)
build-essential (>= 0.0.0)
mysql (>= 0.0.0)
- nscd (4.0.0)
+ nscd (4.1.0)
compat_resource (>= 0.0.0)
ntp (2.0.0)
windows (>= 1.38.0)
- ohai (4.0.2)
- compat_resource (>= 12.9.0)
+ ohai (4.1.1)
+ compat_resource (>= 12.10)
openssh (2.0.0)
iptables (>= 1.0)
openssl (4.4.0)
@@ -97,13 +98,13 @@ GRAPH
database (~> 2.3.1)
mysql (~> 5.6.3)
php (~> 1.5.0)
- windows (1.41.0)
+ windows (1.44.1)
chef_handler (>= 0.0.0)
xfs (2.0.1)
xml (2.0.0)
build-essential (>= 0.0.0)
chef-sugar (>= 0.0.0)
- yum (3.10.0)
+ yum (3.11.0)
yum-epel (0.7.0)
yum (>= 3.6.3)
yum-mysql-community (0.2.0)
diff --git a/kitchen-tests/Gemfile.lock b/kitchen-tests/Gemfile.lock
index 8ab7fbe707..edc91cc8b2 100644
--- a/kitchen-tests/Gemfile.lock
+++ b/kitchen-tests/Gemfile.lock
@@ -2,14 +2,14 @@ GEM
remote: https://rubygems.org/
specs:
addressable (2.4.0)
- artifactory (2.3.2)
- aws-sdk (2.3.9)
- aws-sdk-resources (= 2.3.9)
- aws-sdk-core (2.3.9)
+ artifactory (2.3.3)
+ aws-sdk (2.3.21)
+ aws-sdk-resources (= 2.3.21)
+ aws-sdk-core (2.3.21)
jmespath (~> 1.0)
- aws-sdk-resources (2.3.9)
- aws-sdk-core (= 2.3.9)
- berkshelf (4.3.3)
+ aws-sdk-resources (2.3.21)
+ aws-sdk-core (= 2.3.21)
+ berkshelf (4.3.5)
addressable (~> 2.3, >= 2.3.4)
berkshelf-api-client (~> 2.0, >= 2.0.2)
buff-config (~> 1.0)
@@ -21,6 +21,7 @@ GEM
faraday (~> 0.9)
httpclient (~> 2.7)
minitar (~> 0.5, >= 0.5.4)
+ mixlib-archive (~> 0.1)
octokit (~> 4.0)
retryable (~> 2.0)
ridley (~> 4.5)
@@ -44,21 +45,21 @@ GEM
celluloid-io (0.16.2)
celluloid (>= 0.16.0)
nio4r (>= 1.1.0)
- chef-config (12.10.24)
+ chef-config (12.12.15)
fuzzyurl (~> 0.8.0)
mixlib-config (~> 2.0)
mixlib-shellout (~> 2.0)
cleanroom (1.0.0)
coderay (1.1.1)
diff-lcs (1.2.5)
- docker-api (1.26.2)
+ docker-api (1.29.0)
excon (>= 0.38.0)
json
erubis (2.7.0)
- excon (0.49.0)
+ excon (0.51.0)
faraday (0.9.2)
multipart-post (>= 1.2, < 3)
- ffi (1.9.10)
+ ffi (1.9.14)
fuzzyurl (0.8.0)
gssapi (1.2.0)
ffi (>= 1.0.1)
@@ -66,26 +67,23 @@ GEM
builder (>= 2.1.2)
hashie (3.4.4)
hitimes (1.2.4)
- hitimes (1.2.4-x86-mingw32)
httpclient (2.7.2)
- inspec (0.22.1)
+ inspec (0.27.0)
hashie (~> 3.4)
json (~> 1.8)
method_source (~> 0.8)
pry (~> 0)
- r-train (~> 0.12)
rainbow (~> 2)
rspec (~> 3)
rspec-its (~> 1.2)
rubyzip (~> 1.1)
thor (~> 0.19)
- jmespath (1.2.4)
- json_pure (>= 1.8.1)
+ train (>= 0.15.1, < 1.0)
+ jmespath (1.3.0)
json (1.8.3)
- json_pure (1.8.3)
kitchen-appbundle-updater (0.1.2)
- kitchen-dokken (0.0.29)
- docker-api (~> 1.26.2)
+ kitchen-dokken (0.0.31)
+ docker-api (~> 1.29)
test-kitchen (~> 1.5)
kitchen-ec2 (1.0.0)
aws-sdk (~> 2)
@@ -104,44 +102,32 @@ GEM
multi_json (~> 1.10)
method_source (0.8.2)
minitar (0.5.4)
- mixlib-authentication (1.4.0)
+ mixlib-archive (0.2.0)
+ mixlib-log
+ mixlib-authentication (1.4.1)
mixlib-log
- rspec-core (~> 3.2)
- rspec-expectations (~> 3.2)
- rspec-mocks (~> 3.2)
mixlib-config (2.2.1)
- mixlib-install (1.0.12)
+ mixlib-install (1.1.0)
artifactory
mixlib-shellout
mixlib-versioning
mixlib-log (1.6.0)
mixlib-shellout (2.2.6)
- mixlib-shellout (2.2.6-universal-mingw32)
- win32-process (~> 0.8.2)
- wmi-lite (~> 1.0)
mixlib-versioning (1.1.0)
molinillo (0.4.5)
multi_json (1.12.1)
multipart-post (2.0.0)
net-scp (1.2.1)
net-ssh (>= 2.6.5)
- net-ssh (3.1.1)
+ net-ssh (3.2.0)
nio4r (1.2.1)
nori (2.6.0)
octokit (4.3.0)
sawyer (~> 0.7.0, >= 0.5.3)
- pry (0.10.3)
+ pry (0.10.4)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
- r-train (0.12.1)
- docker-api (~> 1.26)
- json (~> 1.8)
- mixlib-shellout (~> 2.0)
- net-scp (~> 1.2)
- net-ssh (>= 2.9, < 4.0)
- winrm (~> 1.6)
- winrm-fs (~> 0.3)
rainbow (2.1.0)
retryable (2.0.3)
ridley (4.5.1)
@@ -162,22 +148,22 @@ GEM
retryable (~> 2.0)
semverse (~> 1.1)
varia_model (~> 0.4.0)
- rspec (3.4.0)
- rspec-core (~> 3.4.0)
- rspec-expectations (~> 3.4.0)
- rspec-mocks (~> 3.4.0)
- rspec-core (3.4.4)
- rspec-support (~> 3.4.0)
- rspec-expectations (3.4.0)
+ rspec (3.5.0)
+ rspec-core (~> 3.5.0)
+ rspec-expectations (~> 3.5.0)
+ rspec-mocks (~> 3.5.0)
+ rspec-core (3.5.1)
+ rspec-support (~> 3.5.0)
+ rspec-expectations (3.5.0)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.4.0)
+ rspec-support (~> 3.5.0)
rspec-its (1.2.0)
rspec-core (>= 3.0.0)
rspec-expectations (>= 3.0.0)
- rspec-mocks (3.4.1)
+ rspec-mocks (3.5.0)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.4.0)
- rspec-support (3.4.1)
+ rspec-support (~> 3.5.0)
+ rspec-support (3.5.0)
rubyntlm (0.6.0)
rubyzip (1.2.0)
safe_yaml (1.0.4)
@@ -189,7 +175,7 @@ GEM
solve (2.0.3)
molinillo (~> 0.4.2)
semverse (~> 1.1)
- test-kitchen (1.9.0)
+ test-kitchen (1.10.2)
mixlib-install (~> 1.0, >= 1.0.4)
mixlib-shellout (>= 1.2, < 3.0)
net-scp (~> 1.1)
@@ -199,12 +185,18 @@ GEM
thor (0.19.1)
timers (4.0.4)
hitimes
+ train (0.15.1)
+ docker-api (~> 1.26)
+ json (~> 1.8)
+ mixlib-shellout (~> 2.0)
+ net-scp (~> 1.2)
+ net-ssh (>= 2.9, < 4.0)
+ winrm (~> 1.6)
+ winrm-fs (~> 0.3)
vagrant-wrapper (2.0.3)
varia_model (0.4.1)
buff-extensions (~> 1.0)
hashie (>= 2.0.2, < 4.0.0)
- win32-process (0.8.3)
- ffi (>= 1.0.0)
winrm (1.8.1)
builder (>= 2.1.2)
gssapi (~> 1.2)
@@ -213,16 +205,14 @@ GEM
logging (>= 1.6.1, < 3.0)
nori (~> 2.0)
rubyntlm (~> 0.6.0)
- winrm-fs (0.4.2)
+ winrm-fs (0.4.3)
erubis (~> 2.7)
logging (>= 1.6.1, < 3.0)
rubyzip (~> 1.1)
winrm (~> 1.5)
- wmi-lite (1.0.0)
PLATFORMS
ruby
- x86-mingw32
DEPENDENCIES
berkshelf
diff --git a/lib/chef/application.rb b/lib/chef/application.rb
index fa740e068a..c377ffdb36 100644
--- a/lib/chef/application.rb
+++ b/lib/chef/application.rb
@@ -29,6 +29,10 @@ require "tmpdir"
require "rbconfig"
require "chef/application/exit_code"
require "yaml"
+require "resolv"
+# on linux, we replace the glibc resolver with the ruby resolv library, which
+# supports reloading.
+require "resolv-replace" if RbConfig::CONFIG["host_os"] =~ /linux/
class Chef
class Application
diff --git a/lib/chef/application/client.rb b/lib/chef/application/client.rb
index cec47ac071..71bb300971 100644
--- a/lib/chef/application/client.rb
+++ b/lib/chef/application/client.rb
@@ -27,6 +27,7 @@ require "chef/handler/error_report"
require "chef/workstation_config_loader"
require "chef/mixin/shell_out"
require "chef-config/mixin/dot_d"
+require "mixlib/archive"
class Chef::Application::Client < Chef::Application
include Chef::Mixin::ShellOut
@@ -342,8 +343,7 @@ class Chef::Application::Client < Chef::Application
FileUtils.mkdir_p(Chef::Config.chef_repo_path)
tarball_path = File.join(Chef::Config.chef_repo_path, "recipes.tgz")
fetch_recipe_tarball(Chef::Config[:recipe_url], tarball_path)
- result = shell_out!("tar zxvf #{tarball_path} -C #{Chef::Config.chef_repo_path}")
- Chef::Log.debug "#{result.stdout}"
+ Mixlib::Archive.new(tarball_path).extract(Chef::Config.chef_repo_path, perms: false, ignore: /^\.$/)
end
end
diff --git a/lib/chef/application/solo.rb b/lib/chef/application/solo.rb
index d38e97e82b..8bf381a975 100644
--- a/lib/chef/application/solo.rb
+++ b/lib/chef/application/solo.rb
@@ -29,6 +29,7 @@ require "fileutils"
require "chef/mixin/shell_out"
require "pathname"
require "chef-config/mixin/dot_d"
+require "mixlib/archive"
class Chef::Application::Solo < Chef::Application
include Chef::Mixin::ShellOut
@@ -249,6 +250,13 @@ class Chef::Application::Solo < Chef::Application
ARGV[dash_r] = "--recipe-url"
end
+ # For back compat reasons, we need to ensure that we try and use the cache_path as a repo first
+ Chef::Log.debug "Current chef_repo_path is #{Chef::Config.chef_repo_path}"
+
+ if !Chef::Config.has_key?(:cookbook_path) && !Chef::Config.has_key?(:chef_repo_path)
+ Chef::Config.chef_repo_path = Chef::Config.find_chef_repo_path(Chef::Config[:cache_path])
+ end
+
Chef::Config[:local_mode] = true
else
configure_legacy_mode!
@@ -274,8 +282,7 @@ class Chef::Application::Solo < Chef::Application
FileUtils.mkdir_p(recipes_path)
tarball_path = File.join(recipes_path, "recipes.tgz")
fetch_recipe_tarball(Chef::Config[:recipe_url], tarball_path)
- result = shell_out!("tar zxvf #{tarball_path} -C #{recipes_path}")
- Chef::Log.debug "#{result.stdout}"
+ Mixlib::Archive.new(tarball_path).extract(Chef::Config.chef_repo_path, perms: false, ignore: /^\.$/)
end
# json_attribs shuld be fetched after recipe_url tarball is unpacked.
diff --git a/lib/chef/audit/audit_reporter.rb b/lib/chef/audit/audit_reporter.rb
index a40cae93dd..8546a21bb4 100644
--- a/lib/chef/audit/audit_reporter.rb
+++ b/lib/chef/audit/audit_reporter.rb
@@ -140,7 +140,11 @@ class Chef
# Save the audit report to local disk
error_file = "failed-audit-data.json"
Chef::FileCache.store(error_file, Chef::JSONCompat.to_json_pretty(run_data), 0640)
- Chef::Log.error("Failed to post audit report to server. Saving report to #{Chef::FileCache.load(error_file, false)}")
+ if Chef::Config.chef_zero.enabled
+ Chef::Log.debug("Saving audit report to #{Chef::FileCache.load(error_file, false)}")
+ else
+ Chef::Log.error("Failed to post audit report to server. Saving report to #{Chef::FileCache.load(error_file, false)}")
+ end
end
else
Chef::Log.error("Failed to post audit report to server (#{e})")
diff --git a/lib/chef/audit/runner.rb b/lib/chef/audit/runner.rb
index 100a72d2e1..837346381c 100644
--- a/lib/chef/audit/runner.rb
+++ b/lib/chef/audit/runner.rb
@@ -165,7 +165,7 @@ class Chef
add_example_group_methods
run_context.audits.each do |name, group|
ctl_grp = RSpec::Core::ExampleGroup.__control_group__(*group.args, &group.block)
- RSpec.world.register(ctl_grp)
+ RSpec.world.record(ctl_grp)
end
end
diff --git a/lib/chef/chef_fs/chef_fs_data_store.rb b/lib/chef/chef_fs/chef_fs_data_store.rb
index aa5a6d5a69..6b3e830f8d 100644
--- a/lib/chef/chef_fs/chef_fs_data_store.rb
+++ b/lib/chef/chef_fs/chef_fs_data_store.rb
@@ -458,6 +458,7 @@ class Chef
# We want to delete just the ones that == POLICY
next unless policy.name.rpartition("-")[0] == path[1]
policy.delete(false)
+ FileSystemCache.instance.delete!(policy.file_path)
found_policy = true
end
raise ChefZero::DataStore::DataNotFoundError.new(path) if !found_policy
diff --git a/lib/chef/chef_fs/file_system/multiplexed_dir.rb b/lib/chef/chef_fs/file_system/multiplexed_dir.rb
index d3951edd51..21abc012f8 100644
--- a/lib/chef/chef_fs/file_system/multiplexed_dir.rb
+++ b/lib/chef/chef_fs/file_system/multiplexed_dir.rb
@@ -41,7 +41,7 @@ class Chef
child_entry = dir.child(name)
if child_entry.exists?
if result
- Chef::Log.debug("Child with name '#{child_entry.name}' found in multiple directories: #{result.parent.path_for_printing} and #{child_entry.parent.path_for_printing}") unless seen[child.name].path_for_printing == child.path_for_printing
+ Chef::Log.debug("Child with name '#{child_entry.name}' found in multiple directories: #{result.parent.path_for_printing} and #{child_entry.parent.path_for_printing}")
else
result = child_entry
end
diff --git a/lib/chef/chef_fs/file_system/repository/acls_dir.rb b/lib/chef/chef_fs/file_system/repository/acls_dir.rb
index 619031aa70..110befdf22 100644
--- a/lib/chef/chef_fs/file_system/repository/acls_dir.rb
+++ b/lib/chef/chef_fs/file_system/repository/acls_dir.rb
@@ -28,14 +28,16 @@ class Chef
module Repository
class AclsDir < Repository::Directory
+ BARE_FILES = %w{ organization.json root }
+
def can_have_child?(name, is_dir)
- is_dir ? Chef::ChefFS::FileSystem::ChefServer::AclsDir::ENTITY_TYPES.include?(name) : name == "organization.json"
+ is_dir ? Chef::ChefFS::FileSystem::ChefServer::AclsDir::ENTITY_TYPES.include?(name) : BARE_FILES.include?(name)
end
protected
def make_child_entry(child_name)
- if child_name == "organization.json"
+ if BARE_FILES.include? child_name
Acl.new(child_name, self)
else
AclsSubDir.new(child_name, self)
diff --git a/lib/chef/chef_fs/file_system/repository/base_file.rb b/lib/chef/chef_fs/file_system/repository/base_file.rb
index a768bcf971..3e1edc8d62 100644
--- a/lib/chef/chef_fs/file_system/repository/base_file.rb
+++ b/lib/chef/chef_fs/file_system/repository/base_file.rb
@@ -16,6 +16,8 @@
# limitations under the License.
#
+require "chef/chef_fs/file_system_cache"
+
class Chef
module ChefFS
module FileSystem
@@ -99,6 +101,7 @@ class Chef
end
def delete(_)
+ FileSystemCache.instance.delete!(file_path)
File.delete(file_path)
rescue Errno::ENOENT
raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_entry.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_entry.rb
index 9d1538e46e..4019c6985b 100644
--- a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_entry.rb
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_entry.rb
@@ -120,6 +120,7 @@ class Chef
end
def delete(recurse)
+ FileSystemCache.instance.delete!(file_path)
begin
if dir?
if !recurse
diff --git a/lib/chef/chef_fs/file_system/repository/directory.rb b/lib/chef/chef_fs/file_system/repository/directory.rb
index dae467993a..328cf92b03 100644
--- a/lib/chef/chef_fs/file_system/repository/directory.rb
+++ b/lib/chef/chef_fs/file_system/repository/directory.rb
@@ -16,6 +16,8 @@
# limitations under the License.
#
+require "chef/chef_fs/file_system_cache"
+
class Chef
module ChefFS
module FileSystem
@@ -68,9 +70,11 @@ class Chef
end
def children
- dir_ls.sort.
+ return FileSystemCache.instance.children(file_path) if FileSystemCache.instance.exist?(file_path)
+ children = dir_ls.sort.
map { |child_name| make_child_entry(child_name) }.
select { |new_child| new_child.fs_entry_valid? && can_have_child?(new_child.name, new_child.dir?) }
+ FileSystemCache.instance.set_children(file_path, children)
rescue Errno::ENOENT => e
raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
end
@@ -80,6 +84,7 @@ class Chef
if child.exists?
raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, child)
end
+ FileSystemCache.instance.delete!(child.file_path)
if file_contents
child.write(file_contents)
else
@@ -118,6 +123,7 @@ class Chef
raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self)
end
begin
+ FileSystemCache.instance.delete!(file_path)
Dir.mkdir(file_path)
rescue Errno::EEXIST
raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self)
@@ -134,6 +140,7 @@ class Chef
raise MustDeleteRecursivelyError.new(self, $!)
end
FileUtils.rm_r(file_path)
+ FileSystemCache.instance.delete!(file_path)
else
raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
end
@@ -145,6 +152,10 @@ class Chef
protected
+ def write(data)
+ raise FileSystemError.new(self, nil, "attempted to write to a directory entry")
+ end
+
def make_child_entry(child_name)
raise "Not Implemented"
end
diff --git a/lib/chef/chef_fs/file_system_cache.rb b/lib/chef/chef_fs/file_system_cache.rb
new file mode 100644
index 0000000000..a9d8d8bfe4
--- /dev/null
+++ b/lib/chef/chef_fs/file_system_cache.rb
@@ -0,0 +1,80 @@
+#
+# 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 "singleton"
+require "chef/client"
+
+class Chef
+ module ChefFS
+ class FileSystemCache
+ include Singleton
+
+ def initialize
+ @cache = {}
+
+ Chef::Client.when_run_starts do
+ FileSystemCache.instance.reset!
+ end
+ end
+
+ def reset!
+ @cache = {}
+ end
+
+ def exist?(path)
+ @cache.key?(path)
+ end
+
+ def children(path)
+ @cache[path]["children"]
+ end
+
+ def set_children(path, val)
+ @cache[path] ||= { "children" => [] }
+ @cache[path]["children"] = val
+ val
+ end
+
+ def delete!(path)
+ parent = _get_parent(path)
+ Chef::Log.debug("Deleting parent #{parent} and #{path} from FileSystemCache")
+ if @cache.key?(path)
+ @cache.delete(path)
+ end
+ if !parent.nil? && @cache.key?(parent)
+ @cache.delete(parent)
+ end
+ end
+
+ def fetch(path)
+ if @cache.key?(path)
+ @cache[path]
+ else
+ false
+ end
+ end
+
+ private
+
+ def _get_parent(path)
+ parts = ChefFS::PathUtils.split(path)
+ return nil if parts.nil? || parts.length < 2
+ ChefFS::PathUtils.join(*parts[0..-2])
+ end
+ end
+ end
+end
diff --git a/lib/chef/data_collector.rb b/lib/chef/data_collector.rb
index c8dd354f60..dbb0b3771a 100644
--- a/lib/chef/data_collector.rb
+++ b/lib/chef/data_collector.rb
@@ -22,6 +22,7 @@ require "uri"
require "chef/event_dispatch/base"
require "chef/data_collector/messages"
require "chef/data_collector/resource_report"
+require "ostruct"
class Chef
@@ -51,12 +52,14 @@ class Chef
# and exports its data through a webhook-like mechanism to a configured
# endpoint.
class Reporter < EventDispatch::Base
- attr_reader :completed_resources, :status, :exception, :error_descriptions,
- :expanded_run_list, :run_status, :http,
+ attr_reader :all_resource_reports, :status, :exception, :error_descriptions,
+ :expanded_run_list, :run_context, :run_status, :http,
:current_resource_report, :enabled
def initialize
- @completed_resources = []
+ validate_data_collector_server_url!
+
+ @all_resource_reports = []
@current_resource_loaded = nil
@error_descriptions = {}
@expanded_run_list = {}
@@ -93,6 +96,29 @@ class Chef
send_run_completion(status: "failure")
end
+ # see EventDispatch::Base#converge_start
+ # Upon receipt, we stash the run_context for use at the
+ # end of the run in order to determine what resource+action
+ # combinations have not yet fired so we can report on
+ # unprocessed resources.
+ def converge_start(run_context)
+ @run_context = run_context
+ end
+
+ # see EventDispatch::Base#converge_complete
+ # At the end of the converge, we add any unprocessed resources
+ # to our report list.
+ def converge_complete
+ detect_unprocessed_resources
+ end
+
+ # see EventDispatch::Base#converge_failed
+ # At the end of the converge, we add any unprocessed resources
+ # to our report list
+ def converge_failed(exception)
+ detect_unprocessed_resources
+ end
+
# see EventDispatch::Base#resource_current_state_loaded
# Create a new ResourceReport instance that we'll use to track
# the state of this resource during the run. Nested resources are
@@ -100,13 +126,7 @@ class Chef
# resource, and we only care about tracking top-level resources.
def resource_current_state_loaded(new_resource, action, current_resource)
return if nested_resource?(new_resource)
- update_current_resource_report(
- Chef::DataCollector::ResourceReport.new(
- new_resource,
- action,
- current_resource
- )
- )
+ update_current_resource_report(create_resource_report(new_resource, action, current_resource))
end
# see EventDispatch::Base#resource_up_to_date
@@ -116,19 +136,15 @@ class Chef
end
# see EventDispatch::Base#resource_skipped
- # If this is a top-level resource, we create a ResourceReport instance
- # (because a skipped resource does not trigger the
+ # If this is a top-level resource, we create a ResourceReport
+ # instance (because a skipped resource does not trigger the
# resource_current_state_loaded event), and flag it as skipped.
def resource_skipped(new_resource, action, conditional)
return if nested_resource?(new_resource)
- update_current_resource_report(
- Chef::DataCollector::ResourceReport.new(
- new_resource,
- action
- )
- )
- current_resource_report.skipped(conditional)
+ resource_report = create_resource_report(new_resource, action)
+ resource_report.skipped(conditional)
+ update_current_resource_report(resource_report)
end
# see EventDispatch::Base#resource_updated
@@ -154,13 +170,12 @@ class Chef
end
# see EventDispatch::Base#resource_completed
- # Mark the ResourceReport instance as finished (for timing details)
- # and add it to the list of resources encountered during this run.
+ # Mark the ResourceReport instance as finished (for timing details).
# This marks the end of this resource during this run.
def resource_completed(new_resource)
if current_resource_report && !nested_resource?(new_resource)
current_resource_report.finish
- add_completed_resource(current_resource_report)
+ add_resource_report(current_resource_report)
update_current_resource_report(nil)
end
end
@@ -223,7 +238,8 @@ class Chef
yield
rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
Errno::ECONNREFUSED, EOFError, Net::HTTPBadResponse,
- Net::HTTPHeaderSyntaxError, Net::ProtocolError, OpenSSL::SSL::SSLError => e
+ Net::HTTPHeaderSyntaxError, Net::ProtocolError, OpenSSL::SSL::SSLError,
+ Errno::EHOSTDOWN => e
disable_data_collector_reporter
code = if e.respond_to?(:response) && e.response.code
e.response.code.to_s
@@ -266,12 +282,11 @@ class Chef
# we have nothing to report.
return unless run_status
- send_to_data_collector(Chef::DataCollector::Messages.node_update_message(run_status).to_json)
send_to_data_collector(
Chef::DataCollector::Messages.run_end_message(
run_status: run_status,
expanded_run_list: expanded_run_list,
- completed_resources: completed_resources,
+ resources: all_resource_reports,
status: opts[:status],
error_descriptions: error_descriptions
).to_json
@@ -297,8 +312,12 @@ class Chef
Chef::Config[:data_collector][:token]
end
- def add_completed_resource(resource_report)
- @completed_resources << resource_report
+ def add_resource_report(resource_report)
+ @all_resource_reports << OpenStruct.new(
+ resource: resource_report.new_resource,
+ action: resource_report.action,
+ report_data: resource_report.to_hash
+ )
end
def disable_data_collector_reporter
@@ -321,6 +340,38 @@ class Chef
@error_descriptions = discription_hash
end
+ def create_resource_report(new_resource, action, current_resource = nil)
+ Chef::DataCollector::ResourceReport.new(
+ new_resource,
+ action,
+ current_resource
+ )
+ end
+
+ def detect_unprocessed_resources
+ # create a Set containing all resource+action combinations from
+ # the Resource Collection
+ collection_resources = Set.new
+ run_context.resource_collection.all_resources.each do |resource|
+ Array(resource.action).each do |action|
+ collection_resources.add([resource, action])
+ end
+ end
+
+ # Delete from the Set any resource+action combination we have
+ # already processed.
+ all_resource_reports.each do |report|
+ collection_resources.delete([report.resource, report.action])
+ end
+
+ # The items remaining in the Set are unprocessed resource+actions,
+ # so we'll create new resource reports for them which default to
+ # a state of "unprocessed".
+ collection_resources.each do |resource, action|
+ add_resource_report(create_resource_report(resource, action))
+ end
+ end
+
# If we are getting messages about a resource while we are in the middle of
# another resource's update, we assume that the nested resource is just the
# implementation of a provider, and we want to hide it from the reporting
@@ -328,6 +379,20 @@ class Chef
def nested_resource?(new_resource)
@current_resource_report && @current_resource_report.new_resource != new_resource
end
+
+ def validate_data_collector_server_url!
+ raise Chef::Exceptions::ConfigurationError,
+ "Chef::Config[:data_collector][:server_url] is empty. Please supply a valid URL." if data_collector_server_url.empty?
+
+ begin
+ uri = URI(data_collector_server_url)
+ rescue URI::InvalidURIError
+ raise Chef::Exceptions::ConfigurationError, "Chef::Config[:data_collector][:server_url] (#{data_collector_server_url}) is not a valid URI."
+ end
+
+ raise Chef::Exceptions::ConfigurationError,
+ "Chef::Config[:data_collector][:server_url] (#{data_collector_server_url}) is a URI with no host. Please supply a valid URL." if uri.host.nil?
+ end
end
end
end
diff --git a/lib/chef/data_collector/messages.rb b/lib/chef/data_collector/messages.rb
index e23262c9e4..8c2a84b580 100644
--- a/lib/chef/data_collector/messages.rb
+++ b/lib/chef/data_collector/messages.rb
@@ -68,17 +68,18 @@ class Chef
"id" => run_status.run_id,
"message_version" => "1.0.0",
"message_type" => "run_converge",
+ "node" => run_status.node,
"node_name" => run_status.node.name,
"organization_name" => organization,
- "resources" => reporter_data[:completed_resources].map(&:for_json),
+ "resources" => reporter_data[:resources].map(&:report_data),
"run_id" => run_status.run_id,
"run_list" => run_status.node.run_list.for_json,
"start_time" => run_status.start_time.utc.iso8601,
"end_time" => run_status.end_time.utc.iso8601,
"source" => collector_source,
"status" => reporter_data[:status],
- "total_resource_count" => reporter_data[:completed_resources].count,
- "updated_resource_count" => reporter_data[:completed_resources].select { |r| r.status == "updated" }.count,
+ "total_resource_count" => reporter_data[:resources].count,
+ "updated_resource_count" => reporter_data[:resources].select { |r| r.report_data["status"] == "updated" }.count,
}
message["error"] = {
@@ -90,36 +91,6 @@ class Chef
message
end
-
- #
- # Message payload that is sent to the DataCollector server at the
- # end of a Chef run.
- #
- # @param run_status [Chef::RunStatus] The RunStatus instance for this node/run.
- #
- # @return [Hash] A hash containing the node object and related metadata.
- #
- def self.node_update_message(run_status)
- {
- "entity_name" => run_status.node.name,
- "entity_type" => "node",
- "entity_uuid" => node_uuid,
- "id" => SecureRandom.uuid,
- "message_version" => "1.1.0",
- "message_type" => "action",
- "organization_name" => organization,
- "recorded_at" => Time.now.utc.iso8601,
- "remote_hostname" => run_status.node["fqdn"],
- "requestor_name" => run_status.node.name,
- "requestor_type" => "client",
- "run_id" => run_status.run_id,
- "service_hostname" => chef_server_fqdn(run_status),
- "source" => collector_source,
- "task" => "update",
- "user_agent" => Chef::HTTP::HTTPRequest::DEFAULT_UA,
- "data" => run_status.node,
- }
- end
end
end
end
diff --git a/lib/chef/data_collector/messages/helpers.rb b/lib/chef/data_collector/messages/helpers.rb
index 3e52f80047..c0c700f847 100644
--- a/lib/chef/data_collector/messages/helpers.rb
+++ b/lib/chef/data_collector/messages/helpers.rb
@@ -148,8 +148,8 @@ class Chef
end
def update_metadata(key, value)
- metadata[key] = value
- Chef::FileCache.store(metadata_filename, metadata.to_json, 0644)
+ updated_metadata = metadata.tap { |x| x[key] = value }
+ Chef::FileCache.store(metadata_filename, updated_metadata.to_json, 0644)
end
def metadata_filename
diff --git a/lib/chef/data_collector/resource_report.rb b/lib/chef/data_collector/resource_report.rb
index 1793fe2c9d..dcaf9c8e44 100644
--- a/lib/chef/data_collector/resource_report.rb
+++ b/lib/chef/data_collector/resource_report.rb
@@ -22,13 +22,14 @@ class Chef
class DataCollector
class ResourceReport
- attr_reader :action, :current_resource, :elapsed_time, :new_resource, :status
- attr_accessor :conditional, :exception
+ attr_reader :action, :elapsed_time, :new_resource, :status
+ attr_accessor :conditional, :current_resource, :exception
def initialize(new_resource, action, current_resource = nil)
@new_resource = new_resource
@action = action
@current_resource = current_resource
+ @status = "unprocessed"
end
def skipped(conditional)
@@ -54,22 +55,32 @@ class Chef
@elapsed_time = new_resource.elapsed_time
end
+ def elapsed_time_in_milliseconds
+ elapsed_time.nil? ? nil : (elapsed_time * 1000).to_i
+ end
+
+ def potentially_changed?
+ %w{updated failed}.include?(status)
+ end
+
def to_hash
hash = {
- "type" => new_resource.resource_name.to_sym,
- "name" => new_resource.name.to_s,
- "id" => new_resource.identity.to_s,
- "after" => new_resource.state_for_resource_reporter,
- "before" => current_resource ? current_resource.state_for_resource_reporter : {},
- "duration" => (elapsed_time * 1000).to_i.to_s,
- "delta" => new_resource.respond_to?(:diff) ? new_resource.diff : "",
- "result" => action.to_s,
- "status" => status,
+ "type" => new_resource.resource_name.to_sym,
+ "name" => new_resource.name.to_s,
+ "id" => new_resource.identity.to_s,
+ "after" => new_resource.state_for_resource_reporter,
+ "before" => current_resource ? current_resource.state_for_resource_reporter : {},
+ "duration" => elapsed_time_in_milliseconds.to_s,
+ "delta" => new_resource.respond_to?(:diff) && potentially_changed? ? new_resource.diff : "",
+ "ignore_failure" => new_resource.ignore_failure,
+ "result" => action.to_s,
+ "status" => status,
}
if new_resource.cookbook_name
hash["cookbook_name"] = new_resource.cookbook_name
hash["cookbook_version"] = new_resource.cookbook_version.version
+ hash["recipe_name"] = new_resource.recipe_name
end
hash["conditional"] = conditional.to_text if status == "skipped"
diff --git a/lib/chef/decorator/unchain.rb b/lib/chef/decorator/unchain.rb
new file mode 100644
index 0000000000..8093c70f4c
--- /dev/null
+++ b/lib/chef/decorator/unchain.rb
@@ -0,0 +1,59 @@
+class Chef
+ class Decorator < SimpleDelegator
+ #
+ # This decorator unchains method call chains and turns them into method calls
+ # with variable args. So this:
+ #
+ # node.set_unless["foo"]["bar"] = "baz"
+ #
+ # Can become:
+ #
+ # node.set_unless("foo", "bar", "baz")
+ #
+ # While this is a decorator it is not a Decorator and does not inherit because
+ # it deliberately does not need or want the method_missing magic. It is not legal
+ # to call anything on the intermediate values and only supports method chaining with
+ # #[] until the chain comes to an end with #[]=, so does not behave like a hash or
+ # array... e.g.
+ #
+ # node.default['foo'].keys is legal
+ # node.set_unless['foo'].keys is not legal now or ever
+ #
+ class Unchain
+ attr_accessor :__path__
+ attr_accessor :__method__
+
+ def initialize(obj, method)
+ @__path__ = []
+ @__method__ = method
+ @delegate_sd_obj = obj
+ end
+
+ def [](key)
+ __path__.push(key)
+ self
+ end
+
+ def []=(key, value)
+ __path__.push(key)
+ @delegate_sd_obj.public_send(__method__, *__path__, value)
+ end
+
+ # unfortunately we have to support method_missing for node.set_unless.foo.bar = 'baz' notation
+ def method_missing(symbol, *args)
+ if symbol == :to_ary
+ merged_attributes.send(symbol, *args)
+ elsif args.empty?
+ Chef.log_deprecation %q{method access to node attributes (node.foo.bar) is deprecated and will be removed in Chef 13, please use bracket syntax (node["foo"]["bar"])}
+ self[symbol]
+ elsif symbol.to_s =~ /=$/
+ Chef.log_deprecation %q{method setting of node attributes (node.foo="bar") is deprecated and will be removed in Chef 13, please use bracket syntax (node["foo"]="bar")}
+ key_to_set = symbol.to_s[/^(.+)=$/, 1]
+ self[key_to_set] = (args.length == 1 ? args[0] : args)
+ else
+ raise NoMethodError, "Undefined node attribute or method `#{symbol}' on `node'"
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/dsl/cheffish.rb b/lib/chef/dsl/cheffish.rb
index de052bbe5c..03290b3674 100644
--- a/lib/chef/dsl/cheffish.rb
+++ b/lib/chef/dsl/cheffish.rb
@@ -27,6 +27,7 @@ class Chef
chef_acl
chef_client
chef_container
+ chef_data_bag_item
chef_data_bag
chef_environment
chef_group
diff --git a/lib/chef/dsl/declare_resource.rb b/lib/chef/dsl/declare_resource.rb
index 8d76ddfb31..86227a0f9d 100644
--- a/lib/chef/dsl/declare_resource.rb
+++ b/lib/chef/dsl/declare_resource.rb
@@ -71,7 +71,15 @@ class Chef
# delete_resource!(:template, '/x/y.txy')
#
def delete_resource!(type, name, run_context: self.run_context)
- run_context.resource_collection.delete("#{type}[#{name}]")
+ run_context.resource_collection.delete("#{type}[#{name}]").tap do |resource|
+ # Purge any pending notifications too. This will not raise an exception
+ # if there are no notifications.
+ if resource
+ run_context.before_notification_collection.delete(resource.declared_key)
+ run_context.immediate_notification_collection.delete(resource.declared_key)
+ run_context.delayed_notification_collection.delete(resource.declared_key)
+ end
+ end
end
# Lookup a resource in the resource collection by name and delete it. Returns
diff --git a/lib/chef/exceptions.rb b/lib/chef/exceptions.rb
index ea90d80cd8..43759568a7 100644
--- a/lib/chef/exceptions.rb
+++ b/lib/chef/exceptions.rb
@@ -106,7 +106,12 @@ class Chef
# for back compat, need to raise an error that inherits from ArgumentError
class CookbookNotFoundInRepo < ArgumentError; end
class RecipeNotFound < ArgumentError; end
+ # AttributeNotFound really means the attribute file could not be found
class AttributeNotFound < RuntimeError; end
+ # NoSuchAttribute is raised on access by node.read!("foo", "bar") when node["foo"]["bar"] does not exist.
+ class NoSuchAttribute < RuntimeError; end
+ # AttributeTypeMismatch is raised by node.write!("foo", "bar", "baz") when e.g. node["foo"] = "bar" (overwriting String with Hash)
+ class AttributeTypeMismatch < RuntimeError; end
class MissingCookbookDependency < StandardError; end # CHEF-5120
class InvalidCommandOption < RuntimeError; end
class CommandTimeout < RuntimeError; end
diff --git a/lib/chef/http.rb b/lib/chef/http.rb
index c6afa97d23..3e69f58383 100644
--- a/lib/chef/http.rb
+++ b/lib/chef/http.rb
@@ -232,11 +232,11 @@ class Chef
# PERFORMANCE CRITICAL: *MUST* lazy require here otherwise we load up webrick
# via chef-zero and that hits DNS (at *require* time) which may timeout,
# when for most knife/chef-client work we never need/want this loaded.
- Thread.exclusive {
- unless defined?(SocketlessChefZeroClient)
- require "chef/http/socketless_chef_zero_client"
- end
- }
+
+ unless defined?(SocketlessChefZeroClient)
+ require "chef/http/socketless_chef_zero_client"
+ end
+
SocketlessChefZeroClient.new(base_url)
else
BasicClient.new(base_url, :ssl_policy => Chef::HTTP::APISSLPolicy)
diff --git a/lib/chef/knife/bootstrap.rb b/lib/chef/knife/bootstrap.rb
index f5dc29371f..ee4d9ce7af 100644
--- a/lib/chef/knife/bootstrap.rb
+++ b/lib/chef/knife/bootstrap.rb
@@ -101,6 +101,14 @@ class Chef
:description => "The proxy server for the node being bootstrapped",
:proc => Proc.new { |p| Chef::Config[:knife][:bootstrap_proxy] = p }
+ option :bootstrap_proxy_user,
+ :long => "--bootstrap-proxy-user PROXY_USER",
+ :description => "The proxy authentication username for the node being bootstrapped"
+
+ option :bootstrap_proxy_pass,
+ :long => "--bootstrap-proxy-pass PROXY_PASS",
+ :description => "The proxy authentication password for the node being bootstrapped"
+
option :bootstrap_no_proxy,
:long => "--bootstrap-no-proxy [NO_PROXY_URL|NO_PROXY_IP]",
:description => "Do not proxy locations for the node being bootstrapped; this option is used internally by Opscode",
@@ -224,6 +232,7 @@ class Chef
unless valid_values.include?(v)
raise "Invalid value '#{v}' for --node-ssl-verify-mode. Valid values are: #{valid_values.join(", ")}"
end
+ v
}
option :node_verify_api_cert,
diff --git a/lib/chef/knife/cookbook_create.rb b/lib/chef/knife/cookbook_create.rb
index 950de380f8..ccb78bb7a6 100644
--- a/lib/chef/knife/cookbook_create.rb
+++ b/lib/chef/knife/cookbook_create.rb
@@ -56,6 +56,10 @@ class Chef
:description => "Email address of cookbook maintainer"
def run
+ Chef::Log.deprecation <<EOF
+This command is being deprecated in favor of `chef generate cookbook` and will soon return an error.
+Please use `chef generate cookbook` instead of this command.
+EOF
self.config = Chef::Config.merge!(config)
if @name_args.length < 1
show_usage
diff --git a/lib/chef/knife/cookbook_site_download.rb b/lib/chef/knife/cookbook_site_download.rb
index 7d0e21791d..43677cfa78 100644
--- a/lib/chef/knife/cookbook_site_download.rb
+++ b/lib/chef/knife/cookbook_site_download.rb
@@ -37,6 +37,13 @@ class Chef
:long => "--force",
:description => "Force download deprecated version"
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
def run
if current_cookbook_deprecated?
message = "DEPRECATION: This cookbook has been deprecated. "
@@ -59,7 +66,7 @@ class Chef
private
def cookbooks_api_url
- "https://supermarket.chef.io/api/v1/cookbooks"
+ "#{config[:supermarket_site]}/api/v1/cookbooks"
end
def current_cookbook_data
diff --git a/lib/chef/knife/cookbook_site_install.rb b/lib/chef/knife/cookbook_site_install.rb
index 45f3061d87..43d015dcc4 100644
--- a/lib/chef/knife/cookbook_site_install.rb
+++ b/lib/chef/knife/cookbook_site_install.rb
@@ -19,6 +19,7 @@
require "chef/knife"
require "chef/exceptions"
require "shellwords"
+require "mixlib/archive"
class Chef
class Knife
@@ -59,6 +60,13 @@ class Chef
:boolean => true,
:default => false
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
attr_reader :cookbook_name
attr_reader :vendor_path
@@ -134,6 +142,7 @@ class Chef
def download_cookbook_to(download_path)
downloader = Chef::Knife::CookbookSiteDownload.new
downloader.config[:file] = download_path
+ downloader.config[:supermarket_site] = config[:supermarket_site]
downloader.name_args = name_args
downloader.run
downloader
@@ -141,17 +150,7 @@ class Chef
def extract_cookbook(upstream_file, version)
ui.info("Uncompressing #{@cookbook_name} version #{version}.")
- extract_command = "tar zxvf \"#{convert_path upstream_file}\""
- if Chef::Platform.windows?
- tar_version = shell_out("tar --version").stdout.tr("\n", " ")
- if tar_version =~ /GNU tar/
- Chef::Log.debug("GNU tar detected, adding --force-local")
- extract_command << " --force-local"
- else
- Chef::Log.debug("non-GNU tar detected, not adding --force-local")
- end
- end
- shell_out!(extract_command, :cwd => @install_path)
+ Mixlib::Archive.new(convert_path(upstream_file)).extract(@install_path, perms: false)
end
def clear_existing_files(cookbook_path)
diff --git a/lib/chef/knife/cookbook_site_list.rb b/lib/chef/knife/cookbook_site_list.rb
index abe48bf340..3bdef8abe5 100644
--- a/lib/chef/knife/cookbook_site_list.rb
+++ b/lib/chef/knife/cookbook_site_list.rb
@@ -30,6 +30,13 @@ class Chef
:long => "--with-uri",
:description => "Show corresponding URIs"
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
def run
if config[:with_uri]
cookbooks = Hash.new
@@ -41,7 +48,7 @@ class Chef
end
def get_cookbook_list(items = 10, start = 0, cookbook_collection = {})
- cookbooks_url = "https://supermarket.chef.io/api/v1/cookbooks?items=#{items}&start=#{start}"
+ cookbooks_url = "#{config[:supermarket_site]}/api/v1/cookbooks?items=#{items}&start=#{start}"
cr = noauth_rest.get(cookbooks_url)
cr["items"].each do |cookbook|
cookbook_collection[cookbook["cookbook_name"]] = cookbook
diff --git a/lib/chef/knife/cookbook_site_search.rb b/lib/chef/knife/cookbook_site_search.rb
index ba4b873efc..d401844217 100644
--- a/lib/chef/knife/cookbook_site_search.rb
+++ b/lib/chef/knife/cookbook_site_search.rb
@@ -24,12 +24,19 @@ class Chef
banner "knife cookbook site search QUERY (options)"
category "cookbook site"
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
def run
output(search_cookbook(name_args[0]))
end
def search_cookbook(query, items = 10, start = 0, cookbook_collection = {})
- cookbooks_url = "https://supermarket.chef.io/api/v1/search?q=#{query}&items=#{items}&start=#{start}"
+ cookbooks_url = "#{config[:supermarket_site]}/api/v1/search?q=#{query}&items=#{items}&start=#{start}"
cr = noauth_rest.get(cookbooks_url)
cr["items"].each do |cookbook|
cookbook_collection[cookbook["cookbook_name"]] = cookbook
diff --git a/lib/chef/knife/cookbook_site_share.rb b/lib/chef/knife/cookbook_site_share.rb
index 6f37568f5f..d55d6c123a 100644
--- a/lib/chef/knife/cookbook_site_share.rb
+++ b/lib/chef/knife/cookbook_site_share.rb
@@ -50,6 +50,13 @@ class Chef
:default => false,
:description => "Don't take action, only print what files will be uploaded to Supermarket."
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
def run
config[:cookbook_path] ||= Chef::Config[:cookbook_path]
@@ -106,23 +113,17 @@ class Chef
end
def get_category(cookbook_name)
- begin
- data = noauth_rest.get("https://supermarket.chef.io/api/v1/cookbooks/#{@name_args[0]}")
- if !data["category"] && data["error_code"]
- ui.fatal("Received an error from Supermarket: #{data["error_code"]}. On the first time you upload it, you are required to specify the category you want to share this cookbook to.")
- exit(1)
- else
- data["category"]
- end
- rescue => e
- ui.fatal("Unable to reach Supermarket: #{e.message}. Increase log verbosity (-VV) for more information.")
- Chef::Log.debug("\n#{e.backtrace.join("\n")}")
- exit(1)
- end
+ data = noauth_rest.get("#{config[:supermarket_site]}/api/v1/cookbooks/#{@name_args[0]}")
+ data["category"]
+ rescue => e
+ return "Other" if e.kind_of?(Net::HTTPServerException) && e.response.code == "404"
+ ui.fatal("Unable to reach Supermarket: #{e.message}. Increase log verbosity (-VV) for more information.")
+ Chef::Log.debug("\n#{e.backtrace.join("\n")}")
+ exit(1)
end
def do_upload(cookbook_filename, cookbook_category, user_id, user_secret_filename)
- uri = "https://supermarket.chef.io/api/v1/cookbooks"
+ uri = "#{config[:supermarket_site]}/api/v1/cookbooks"
category_string = Chef::JSONCompat.to_json({ "category" => cookbook_category })
diff --git a/lib/chef/knife/cookbook_site_show.rb b/lib/chef/knife/cookbook_site_show.rb
index c0280cb318..ce153ca5a1 100644
--- a/lib/chef/knife/cookbook_site_show.rb
+++ b/lib/chef/knife/cookbook_site_show.rb
@@ -24,21 +24,32 @@ class Chef
banner "knife cookbook site show COOKBOOK [VERSION] (options)"
category "cookbook site"
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
def run
output(format_for_display(get_cookbook_data))
end
+ def supermarket_uri
+ "#{config[:supermarket_site]}/api/v1"
+ end
+
def get_cookbook_data
case @name_args.length
when 1
- noauth_rest.get("https://supermarket.chef.io/api/v1/cookbooks/#{@name_args[0]}")
+ noauth_rest.get("#{supermarket_uri}/cookbooks/#{@name_args[0]}")
when 2
- noauth_rest.get("https://supermarket.chef.io/api/v1/cookbooks/#{@name_args[0]}/versions/#{name_args[1].tr('.', '_')}")
+ noauth_rest.get("#{supermarket_uri}/cookbooks/#{@name_args[0]}/versions/#{name_args[1].tr('.', '_')}")
end
end
def get_cookbook_list(items = 10, start = 0, cookbook_collection = {})
- cookbooks_url = "https://supermarket.chef.io/api/v1/cookbooks?items=#{items}&start=#{start}"
+ cookbooks_url = "#{supermarket_uri}/cookbooks?items=#{items}&start=#{start}"
cr = noauth_rest.get(cookbooks_url)
cr["items"].each do |cookbook|
cookbook_collection[cookbook["cookbook_name"]] = cookbook
diff --git a/lib/chef/knife/cookbook_site_unshare.rb b/lib/chef/knife/cookbook_site_unshare.rb
index 310f6ac41d..bdabff0b94 100644
--- a/lib/chef/knife/cookbook_site_unshare.rb
+++ b/lib/chef/knife/cookbook_site_unshare.rb
@@ -30,6 +30,13 @@ class Chef
banner "knife cookbook site unshare COOKBOOK"
category "cookbook site"
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
def run
@cookbook_name = @name_args[0]
if @cookbook_name.nil?
@@ -41,7 +48,7 @@ class Chef
confirm "Do you really want to unshare all versions of the cookbook #{@cookbook_name}"
begin
- rest.delete "https://supermarket.chef.io/api/v1/cookbooks/#{@name_args[0]}"
+ rest.delete "#{config[:supermarket_site]}/api/v1/cookbooks/#{@name_args[0]}"
rescue Net::HTTPServerException => e
raise e unless e.message =~ /Forbidden/
ui.error "Forbidden: You must be the maintainer of #{@cookbook_name} to unshare it."
diff --git a/lib/chef/knife/core/bootstrap_context.rb b/lib/chef/knife/core/bootstrap_context.rb
index 48d2cb9e77..b2670f196b 100644
--- a/lib/chef/knife/core/bootstrap_context.rb
+++ b/lib/chef/knife/core/bootstrap_context.rb
@@ -54,7 +54,7 @@ class Chef
end
def client_d
- @cliend_d ||= client_d_content
+ @client_d ||= client_d_content
end
def encrypted_data_bag_secret
@@ -114,6 +114,16 @@ validation_client_name "#{@chef_config[:validation_client_name]}"
client_rb << %Q{https_proxy "#{knife_config[:bootstrap_proxy]}"\n}
end
+ if knife_config[:bootstrap_proxy_user]
+ client_rb << %Q{http_proxy_user "#{knife_config[:bootstrap_proxy_user]}"\n}
+ client_rb << %Q{https_proxy_user "#{knife_config[:bootstrap_proxy_user]}"\n}
+ end
+
+ if knife_config[:bootstrap_proxy_pass]
+ client_rb << %Q{http_proxy_pass "#{knife_config[:bootstrap_proxy_pass]}"\n}
+ client_rb << %Q{https_proxy_pass "#{knife_config[:bootstrap_proxy_pass]}"\n}
+ end
+
if knife_config[:bootstrap_no_proxy]
client_rb << %Q{no_proxy "#{knife_config[:bootstrap_no_proxy]}"\n}
end
diff --git a/lib/chef/knife/supermarket_download.rb b/lib/chef/knife/supermarket_download.rb
new file mode 100644
index 0000000000..5657558591
--- /dev/null
+++ b/lib/chef/knife/supermarket_download.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/cookbook_site_download"
+
+class Chef
+ class Knife
+ class SupermarketDownload < Knife::CookbookSiteDownload
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
+
+ banner "knife supermarket download COOKBOOK [VERSION] (options)"
+ category "supermarket"
+ end
+ end
+end
diff --git a/lib/chef/knife/supermarket_install.rb b/lib/chef/knife/supermarket_install.rb
new file mode 100644
index 0000000000..7642e68181
--- /dev/null
+++ b/lib/chef/knife/supermarket_install.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/cookbook_site_install"
+
+class Chef
+ class Knife
+ class SupermarketInstall < Knife::CookbookSiteInstall
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
+
+ banner "knife supermarket install COOKBOOK [VERSION] (options)"
+ category "supermarket"
+ end
+ end
+end
diff --git a/lib/chef/knife/supermarket_list.rb b/lib/chef/knife/supermarket_list.rb
new file mode 100644
index 0000000000..f2bc98bd0e
--- /dev/null
+++ b/lib/chef/knife/supermarket_list.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/cookbook_site_list"
+
+class Chef
+ class Knife
+ class SupermarketList < Knife::CookbookSiteList
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
+
+ banner "knife supermarket list (options)"
+ category "supermarket"
+ end
+ end
+end
diff --git a/lib/chef/knife/supermarket_search.rb b/lib/chef/knife/supermarket_search.rb
new file mode 100644
index 0000000000..3206b0cb80
--- /dev/null
+++ b/lib/chef/knife/supermarket_search.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/cookbook_site_search"
+
+class Chef
+ class Knife
+ class SupermarketSearch < Knife::CookbookSiteSearch
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
+
+ banner "knife supermarket search QUERY (options)"
+ category "supermarket"
+ end
+ end
+end
diff --git a/lib/chef/knife/supermarket_share.rb b/lib/chef/knife/supermarket_share.rb
new file mode 100644
index 0000000000..3109b9e794
--- /dev/null
+++ b/lib/chef/knife/supermarket_share.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/cookbook_site_share"
+
+class Chef
+ class Knife
+ class SupermarketShare < Knife::CookbookSiteShare
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
+
+ banner "knife supermarket share COOKBOOK [CATEGORY] (options)"
+ category "supermarket"
+ end
+ end
+end
diff --git a/lib/chef/knife/supermarket_show.rb b/lib/chef/knife/supermarket_show.rb
new file mode 100644
index 0000000000..2ad122143f
--- /dev/null
+++ b/lib/chef/knife/supermarket_show.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/cookbook_site_show"
+
+class Chef
+ class Knife
+ class SupermarketShow < Knife::CookbookSiteShow
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
+
+ banner "knife supermarket show COOKBOOK [VERSION] (options)"
+ category "supermarket"
+ end
+ end
+end
diff --git a/lib/chef/knife/supermarket_unshare.rb b/lib/chef/knife/supermarket_unshare.rb
new file mode 100644
index 0000000000..fd48e172ce
--- /dev/null
+++ b/lib/chef/knife/supermarket_unshare.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/cookbook_site_unshare"
+
+class Chef
+ class Knife
+ class SupermarketUnshare < Knife::CookbookSiteUnshare
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
+
+ banner "knife supermarket unshare COOKBOOK (options)"
+ category "supermarket"
+ end
+ end
+end
diff --git a/lib/chef/node.rb b/lib/chef/node.rb
index 8d77becbf0..54faab6d3e 100644
--- a/lib/chef/node.rb
+++ b/lib/chef/node.rb
@@ -43,6 +43,8 @@ class Chef
def_delegators :attributes, :keys, :each_key, :each_value, :key?, :has_key?
def_delegators :attributes, :rm, :rm_default, :rm_normal, :rm_override
def_delegators :attributes, :default!, :normal!, :override!, :force_default!, :force_override!
+ def_delegators :attributes, :default_unless, :normal_unless, :override_unless, :set_unless
+ def_delegators :attributes, :read, :read!, :write, :write!, :unlink, :unlink!
attr_accessor :recipe_list, :run_state, :override_runlist
@@ -196,35 +198,18 @@ class Chef
# might be missing
def normal
attributes.top_level_breadcrumb = nil
- attributes.set_unless_value_present = false
attributes.normal
end
- alias_method :set, :normal
-
- # Set a normal attribute of this node, auto-vivifying any mashes that are
- # missing, but if the final value already exists, don't set it
- def normal_unless
- attributes.top_level_breadcrumb = nil
- attributes.set_unless_value_present = true
- attributes.normal
+ def set
+ Chef.log_deprecation("node.set is deprecated and will be removed in Chef 14, please use node.default/node.override (or node.normal only if you really need persistence)")
+ normal
end
- alias_method :set_unless, :normal_unless
-
# Set a default of this node, but auto-vivify any Mashes that might
# be missing
def default
attributes.top_level_breadcrumb = nil
- attributes.set_unless_value_present = false
- attributes.default
- end
-
- # Set a default attribute of this node, auto-vivifying any mashes that are
- # missing, but if the final value already exists, don't set it
- def default_unless
- attributes.top_level_breadcrumb = nil
- attributes.set_unless_value_present = true
attributes.default
end
@@ -232,15 +217,6 @@ class Chef
# might be missing
def override
attributes.top_level_breadcrumb = nil
- attributes.set_unless_value_present = false
- attributes.override
- end
-
- # Set an override attribute of this node, auto-vivifying any mashes that
- # are missing, but if the final value already exists, don't set it
- def override_unless
- attributes.top_level_breadcrumb = nil
- attributes.set_unless_value_present = true
attributes.override
end
@@ -262,7 +238,6 @@ class Chef
def automatic_attrs
attributes.top_level_breadcrumb = nil
- attributes.set_unless_value_present = false
attributes.automatic
end
@@ -290,8 +265,14 @@ class Chef
end
# Only works for attribute fetches, setting is no longer supported
- def method_missing(symbol, *args)
- attributes.send(symbol, *args)
+ # XXX: this should be deprecated
+ def method_missing(method, *args, &block)
+ attributes.public_send(method, *args, &block)
+ end
+
+ # Fix respond_to + method so that it works with method_missing delegation
+ def respond_to_missing?(method, include_private = false)
+ attributes.respond_to?(method, false)
end
# Returns true if this Node expects a given recipe, false if not.
diff --git a/lib/chef/node/attribute.rb b/lib/chef/node/attribute.rb
index ab97cf99bf..f5fe89251d 100644
--- a/lib/chef/node/attribute.rb
+++ b/lib/chef/node/attribute.rb
@@ -19,6 +19,7 @@
require "chef/node/immutable_collections"
require "chef/node/attribute_collections"
+require "chef/decorator/unchain"
require "chef/mixin/deep_merge"
require "chef/log"
@@ -132,6 +133,7 @@ class Chef
:take,
:take_while,
:to_a,
+ :to_h,
:to_hash,
:to_set,
:value?,
@@ -187,8 +189,6 @@ class Chef
attr_accessor :deep_merge_cache
def initialize(normal, default, override, automatic)
- @set_unless_present = false
-
@default = VividMash.new(self, default)
@env_default = VividMash.new(self, {})
@role_default = VividMash.new(self, {})
@@ -214,15 +214,13 @@ class Chef
# attribute you're interested in. For example, to debug where the value
# of `node[:network][:default_interface]` is coming from, use:
# debug_value(:network, :default_interface).
- # The return value is an Array of Arrays. The first element is
- # `["set_unless_enabled?", Boolean]`, which describes whether the
- # attribute collection is in "set_unless" mode. The rest of the Arrays
+ # The return value is an Array of Arrays. The Arrays
# are pairs of `["precedence_level", value]`, where precedence level is
# the component, such as role default, normal, etc. and value is the
# attribute value set at that precedence level. If there is no value at
# that precedence level, +value+ will be the symbol +:not_present+.
def debug_value(*args)
- components = COMPONENTS.map do |component|
+ COMPONENTS.map do |component|
ivar = instance_variable_get(component)
value = args.inject(ivar) do |so_far, key|
if so_far == :not_present
@@ -235,12 +233,6 @@ class Chef
end
[component.to_s.sub(/^@/, ""), value]
end
- [["set_unless_enabled?", @set_unless_present]] + components
- end
-
- # Enables or disables `||=`-like attribute setting. See, e.g., Node#set_unless
- def set_unless_value_present=(setting)
- @set_unless_present = setting
end
# Invalidate a key in the deep_merge_cache. If called with nil, or no arg, this will invalidate
@@ -321,94 +313,134 @@ class Chef
# clears attributes from all precedence levels
def rm(*args)
- reset(args[0])
- # just easier to compute our retval, rather than collect+merge sub-retvals
- ret = args.inject(merged_attributes) do |attr, arg|
- if attr.nil? || !attr.respond_to?(:[])
- nil
- else
- begin
- attr[arg]
- rescue TypeError
- raise TypeError, "Wrong type in index of attribute (did you use a Hash index on an Array?)"
- end
- end
+ with_deep_merged_return_value(self, *args) do
+ rm_default(*args)
+ rm_normal(*args)
+ rm_override(*args)
end
- rm_default(*args)
- rm_normal(*args)
- rm_override(*args)
- ret
end
- # does <level>['foo']['bar'].delete('baz')
- def remove_from_precedence_level(level, *args, key)
- multimash = level.element(*args)
- multimash.nil? ? nil : multimash.delete(key)
- end
-
- private :remove_from_precedence_level
-
# clears attributes from all default precedence levels
#
- # equivalent to: force_default!['foo']['bar'].delete('baz')
+ # similar to: force_default!['foo']['bar'].delete('baz')
+ # - does not autovivify
+ # - does not trainwreck if interior keys do not exist
def rm_default(*args)
- reset(args[0])
- remove_from_precedence_level(force_default!(autovivify: false), *args)
+ with_deep_merged_return_value(combined_default, *args) do
+ default.unlink(*args)
+ role_default.unlink(*args)
+ env_default.unlink(*args)
+ force_default.unlink(*args)
+ end
end
# clears attributes from normal precedence
#
# equivalent to: normal!['foo']['bar'].delete('baz')
+ # - does not autovivify
+ # - does not trainwreck if interior keys do not exist
def rm_normal(*args)
- reset(args[0])
- remove_from_precedence_level(normal!(autovivify: false), *args)
+ normal.unlink(*args)
end
# clears attributes from all override precedence levels
#
# equivalent to: force_override!['foo']['bar'].delete('baz')
+ # - does not autovivify
+ # - does not trainwreck if interior keys do not exist
def rm_override(*args)
- reset(args[0])
- remove_from_precedence_level(force_override!(autovivify: false), *args)
+ with_deep_merged_return_value(combined_override, *args) do
+ override.unlink(*args)
+ role_override.unlink(*args)
+ env_override.unlink(*args)
+ force_override.unlink(*args)
+ end
+ end
+
+ def with_deep_merged_return_value(obj, *path, last)
+ hash = obj.read(*path)
+ return nil unless hash.is_a?(Hash)
+ ret = hash[last]
+ yield
+ ret
end
+ private :with_deep_merged_return_value
+
#
# Replacing attributes without merging
#
# sets default attributes without merging
- def default!(opts = {})
- # FIXME: do not flush whole cache
- reset
- MultiMash.new(self, @default, [], opts)
+ #
+ # - this API autovivifies (and cannot trainwreck)
+ def default!(*args)
+ return Decorator::Unchain.new(self, :default!) unless args.length > 0
+ write(:default, *args)
end
# sets normal attributes without merging
- def normal!(opts = {})
- # FIXME: do not flush whole cache
- reset
- MultiMash.new(self, @normal, [], opts)
+ #
+ # - this API autovivifies (and cannot trainwreck)
+ def normal!(*args)
+ return Decorator::Unchain.new(self, :normal!) unless args.length > 0
+ write(:normal, *args)
end
# sets override attributes without merging
- def override!(opts = {})
- # FIXME: do not flush whole cache
- reset
- MultiMash.new(self, @override, [], opts)
+ #
+ # - this API autovivifies (and cannot trainwreck)
+ def override!(*args)
+ return Decorator::Unchain.new(self, :override!) unless args.length > 0
+ write(:override, *args)
end
# clears from all default precedence levels and then sets force_default
- def force_default!(opts = {})
- # FIXME: do not flush whole cache
- reset
- MultiMash.new(self, @force_default, [@default, @env_default, @role_default], opts)
+ #
+ # - this API autovivifies (and cannot trainwreck)
+ def force_default!(*args)
+ return Decorator::Unchain.new(self, :force_default!) unless args.length > 0
+ value = args.pop
+ rm_default(*args)
+ write(:force_default, *args, value)
end
# clears from all override precedence levels and then sets force_override
- def force_override!(opts = {})
- # FIXME: do not flush whole cache
- reset
- MultiMash.new(self, @force_override, [@override, @env_override, @role_override], opts)
+ def force_override!(*args)
+ return Decorator::Unchain.new(self, :force_override!) unless args.length > 0
+ value = args.pop
+ rm_override(*args)
+ 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
#
@@ -420,9 +452,9 @@ class Chef
#
def merged_attributes(*path)
- # immutablize(
+ # immutablize(
merge_all(path)
- # )
+ # )
end
def combined_override(*path)
@@ -433,6 +465,27 @@ class Chef
immutablize(merge_defaults(path))
end
+ def normal_unless(*args)
+ return Decorator::Unchain.new(self, :normal_unless) unless args.length > 0
+ write(:normal, *args) if read(*args[0...-1]).nil?
+ end
+
+ def default_unless(*args)
+ return Decorator::Unchain.new(self, :default_unless) unless args.length > 0
+ write(:default, *args) if read(*args[0...-1]).nil?
+ end
+
+ def override_unless(*args)
+ return Decorator::Unchain.new(self, :override_unless) unless args.length > 0
+ write(:override, *args) if read(*args[0...-1]).nil?
+ end
+
+ def set_unless(*args)
+ Chef.log_deprecation("node.set_unless is deprecated and will be removed in Chef 14, please use node.default_unless/node.override_unless (or node.normal_unless if you really need persistence)")
+ return Decorator::Unchain.new(self, :default_unless) unless args.length > 0
+ 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
@@ -461,13 +514,17 @@ class Chef
alias :each_attribute :each
def method_missing(symbol, *args)
- if args.empty?
+ if symbol == :to_ary
+ merged_attributes.send(symbol, *args)
+ elsif args.empty?
+ Chef.log_deprecation %q{method access to node attributes (node.foo.bar) is deprecated and will be removed in Chef 13, please use bracket syntax (node["foo"]["bar"])}
if key?(symbol)
self[symbol]
else
raise NoMethodError, "Undefined method or attribute `#{symbol}' on `node'"
end
elsif symbol.to_s =~ /=$/
+ Chef.log_deprecation %q{method setting of node attributes (node.foo="bar") is deprecated and will be removed in Chef 13, please use bracket syntax (node["foo"]="bar")}
key_to_set = symbol.to_s[/^(.+)=$/, 1]
self[key_to_set] = (args.length == 1 ? args[0] : args)
else
@@ -485,10 +542,6 @@ class Chef
}.join(", ") << ">"
end
- def set_unless?
- @set_unless_present
- end
-
private
# Helper method for merge_all/merge_defaults/merge_overrides.
diff --git a/lib/chef/node/attribute_collections.rb b/lib/chef/node/attribute_collections.rb
index 68f3a69756..b739ea8490 100644
--- a/lib/chef/node/attribute_collections.rb
+++ b/lib/chef/node/attribute_collections.rb
@@ -16,15 +16,15 @@
# limitations under the License.
#
+require "chef/node/common_api"
+
class Chef
class Node
-
# == AttrArray
# AttrArray is identical to Array, except that it keeps a reference to the
# "root" (Chef::Node::Attribute) object, and will trigger a cache
# invalidation on that object when mutated.
class AttrArray < Array
-
MUTATOR_METHODS = [
:<<,
:[]=,
@@ -62,8 +62,9 @@ class Chef
# Node::Attribute object.
MUTATOR_METHODS.each do |mutator|
define_method(mutator) do |*args, &block|
+ ret = super(*args, &block)
root.reset_cache(root.top_level_breadcrumb)
- super(*args, &block)
+ ret
end
end
@@ -96,14 +97,12 @@ class Chef
# in the creation of a new VividMash for that key. (This only works when
# using the element reference method, `[]` -- other methods, such as
# #fetch, work as normal).
- # * It supports a set_unless flag (via the root Attribute object) which
- # allows `||=` style behavior (`||=` does not work with
- # auto-vivification). This is only implemented for #[]=; methods such as
- # #store 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
# also invalidates the cached merged_attributes on the root Attribute
# object.
@@ -148,12 +147,9 @@ class Chef
def []=(key, value)
root.top_level_breadcrumb ||= key
- if set_unless? && key?(key) && !self[key].nil?
- self[key]
- else
- root.reset_cache(root.top_level_breadcrumb)
- super
- end
+ ret = super
+ root.reset_cache(root.top_level_breadcrumb)
+ ret
end
alias :attribute? :has_key?
@@ -176,10 +172,6 @@ class Chef
end
end
- def set_unless?
- @root.set_unless?
- end
-
def convert_key(key)
super
end
@@ -206,118 +198,5 @@ class Chef
end
end
-
- # == MultiMash
- # This is a Hash-like object that contains multiple VividMashes in it. Its
- # purpose is so that the user can descend into the mash and delete a subtree
- # from all of the Mash objects (used to delete all values in a subtree from
- # default, force_default, role_default and env_default at the same time). The
- # assignment operator strictly does assignment (does no merging) and works
- # by deleting the subtree and then assigning to the last mash which passed in
- # the initializer.
- #
- # A lot of the complexity of this class comes from the fact that at any key
- # value some or all of the mashes may walk off their ends and become nil or
- # true or something. The schema may change so that one precidence leve may
- # be 'true' object and another may be a VividMash. It is also possible that
- # one or many of them may transition from VividMashes to Hashes or Arrays.
- #
- # It also supports the case where you may be deleting a key using node.rm
- # in which case if intermediate keys all walk off into nil then you don't want
- # to be autovivifying keys as you go. On the other hand you may be using
- # node.force_default! in which case you'll wind up with a []= operator at the
- # end and you want autovivification, so we conditionally have to support either
- # operation.
- #
- # @todo: can we have an autovivify class that decorates a class that doesn't
- # autovivify or something so that the code is less awful?
- #
- class MultiMash
- attr_reader :root
- attr_reader :mashes
- attr_reader :opts
- attr_reader :primary_mash
-
- # Initialize with an array of mashes. For the delete return value to work
- # properly the mashes must come from the same attribute level (i.e. all
- # override or all default, but not a mix of both).
- def initialize(root, primary_mash, mashes, opts = {})
- @root = root
- @primary_mash = primary_mash
- @mashes = mashes
- @opts = opts
- @opts[:autovivify] = true if @opts[:autovivify].nil?
- end
-
- def [](key)
- # handle the secondary mashes
- new_mashes = []
- mashes.each do |mash|
- new_mash = safe_evalute_key(mash, key)
- # secondary mashes never autovivify so once they fall into nil, we just stop tracking them
- new_mashes.push(new_mash) unless new_mash.nil?
- end
-
- new_primary_mash = safe_evalute_key(primary_mash, key)
-
- if new_primary_mash.nil? && @opts[:autovivify]
- primary_mash[key] = VividMash.new(root)
- new_primary_mash = primary_mash[key]
- end
-
- MultiMash.new(root, new_primary_mash, new_mashes, opts)
- end
-
- def []=(key, value)
- if primary_mash.nil?
- # This theoretically should never happen since node#force_default! setter methods will autovivify and
- # node#rm methods do not end in #[]= operators.
- raise TypeError, "No autovivification was specified initially on a method chain ending in assignment"
- end
- ret = delete(key)
- primary_mash[key] = value
- ret
- end
-
- # mash.element('foo', 'bar') is the same as mash['foo']['bar']
- def element(key = nil, *subkeys)
- return self if key.nil?
- submash = self[key]
- subkeys.empty? ? submash : submash.element(*subkeys)
- end
-
- def delete(key)
- # the return value is a deep merge which is correct semantics when
- # merging between attributes on the same level (this would be incorrect
- # if passed both override and default attributes which would need hash_only
- # merging).
- ret = mashes.inject(Mash.new) do |merged, mash|
- Chef::Mixin::DeepMerge.merge(merged, mash)
- end
- ret = Chef::Mixin::DeepMerge.merge(ret, primary_mash)
- mashes.each do |mash|
- mash.delete(key) if mash.respond_to?(:delete)
- end
- primary_mash.delete(key) if primary_mash.respond_to?(:delete)
- ret[key]
- end
-
- private
-
- def safe_evalute_key(mash, key)
- if mash.respond_to?(:[])
- if mash.respond_to?(:has_key?)
- if mash.has_key?(key)
- return mash[key] if mash[key].respond_to?(:[])
- end
- elsif !mash[key].nil?
- return mash[key] if mash[key].respond_to?(:[])
- end
- end
- return nil
- end
-
- end
-
end
end
diff --git a/lib/chef/node/common_api.rb b/lib/chef/node/common_api.rb
new file mode 100644
index 0000000000..ce2c6b6878
--- /dev/null
+++ b/lib/chef/node/common_api.rb
@@ -0,0 +1,129 @@
+#--
+# 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
+ # shared API between VividMash and ImmutableMash, writer code can be
+ # 'shared' to keep it logically in this file by adding them to the
+ # block list in ImmutableMash.
+ module CommonAPI
+ # method-style access to attributes
+
+ def valid_container?(obj, key)
+ return obj.is_a?(Hash) || (obj.is_a?(Array) && key.is_a?(Fixnum))
+ end
+
+ private :valid_container?
+
+ # - 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
+ chain = args.inject(self) do |memo, key|
+ if !valid_container?(memo, key)
+ prev_memo[prev_key] = {}
+ memo = prev_memo[prev_key]
+ end
+ prev_memo = memo
+ prev_key = key
+ memo[key]
+ end
+ if !valid_container?(chain, last)
+ prev_memo[prev_key] = {}
+ chain = prev_memo[prev_key]
+ end
+ chain[last] = value
+ end
+
+ # this autovivifies, but can throw NoSuchAttribute when trying to access #[] on
+ # 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|
+ raise Chef::Exceptions::AttributeTypeMismatch unless valid_container?(memo, key)
+ memo[key]
+ end
+ raise Chef::Exceptions::AttributeTypeMismatch unless valid_container?(obj, last)
+ obj[last] = value
+ end
+
+ # FIXME:(?) does anyone need a non-autovivifying writer for attributes that throws exceptions?
+
+ # 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)
+ if memo.key?(key)
+ memo[key]
+ else
+ return false
+ end
+ elsif memo.is_a?(Array)
+ if memo.length > key
+ memo[key]
+ else
+ return false
+ end
+ end
+ end
+ return true
+ end
+
+ # this is a safe non-autovivifying reader that returns nil if the attribute does not exist
+ def read(*path)
+ begin
+ read!(*path)
+ rescue Chef::Exceptions::NoSuchAttribute
+ nil
+ end
+ end
+
+ # 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
+ end
+
+ # 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
+
+ def unlink!(*path)
+ raise Chef::Exceptions::NoSuchAttribute unless exist?(*path)
+ unlink(*path)
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/node/immutable_collections.rb b/lib/chef/node/immutable_collections.rb
index b5fd86fa72..d4623ace2a 100644
--- a/lib/chef/node/immutable_collections.rb
+++ b/lib/chef/node/immutable_collections.rb
@@ -1,3 +1,21 @@
+#--
+# Copyright:: Copyright 2012-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 "chef/node/common_api"
class Chef
class Node
@@ -124,6 +142,7 @@ class Chef
class ImmutableMash < Mash
include Immutablize
+ include CommonAPI
alias :internal_set :[]=
private :internal_set
@@ -144,6 +163,10 @@ class Chef
:replace,
:select!,
:shift,
+ :write,
+ :write!,
+ :unlink,
+ :unlink!,
]
def initialize(mash_data)
@@ -167,13 +190,15 @@ class Chef
end
def method_missing(symbol, *args)
- if args.empty?
+ if symbol == :to_ary
+ super
+ elsif args.empty?
if key?(symbol)
self[symbol]
else
raise NoMethodError, "Undefined method or attribute `#{symbol}' on `node'"
end
- # This will raise a ImmutableAttributeModification error:
+ # This will raise a ImmutableAttributeModification error:
elsif symbol.to_s =~ /=$/
key_to_set = symbol.to_s[/^(.+)=$/, 1]
self[key_to_set] = (args.length == 1 ? args[0] : args)
diff --git a/lib/chef/property.rb b/lib/chef/property.rb
index 45ab4dd522..0589cb4c54 100644
--- a/lib/chef/property.rb
+++ b/lib/chef/property.rb
@@ -531,8 +531,6 @@ class Chef
end
end
- protected
-
#
# The options this Property will use for get/set behavior and validation.
#
@@ -583,6 +581,7 @@ class Chef
(options.has_key?(:is) && resource.send(:_pv_is, { name => nil }, name, options[:is], raise_error: false))
end
+ # @api private
def get_value(resource)
if instance_variable_name
resource.instance_variable_get(instance_variable_name)
@@ -591,6 +590,7 @@ class Chef
end
end
+ # @api private
def set_value(resource, value)
if instance_variable_name
resource.instance_variable_set(instance_variable_name, value)
@@ -599,6 +599,7 @@ class Chef
end
end
+ # @api private
def value_is_set?(resource)
if instance_variable_name
resource.instance_variable_defined?(instance_variable_name)
@@ -607,6 +608,7 @@ class Chef
end
end
+ # @api private
def reset_value(resource)
if instance_variable_name
if value_is_set?(resource)
@@ -617,6 +619,8 @@ class Chef
end
end
+ private
+
def exec_in_resource(resource, proc, *args)
if resource
if proc.arity > args.size
diff --git a/lib/chef/provider.rb b/lib/chef/provider.rb
index 03b546c09d..7cfddba0cb 100644
--- a/lib/chef/provider.rb
+++ b/lib/chef/provider.rb
@@ -423,9 +423,9 @@ class Chef
module DeprecatedLWRPClass
def const_missing(class_name)
- if deprecated_constants[class_name.to_sym]
+ if Chef::Provider.deprecated_constants[class_name.to_sym]
Chef.log_deprecation("Using an LWRP provider by its name (#{class_name}) directly is no longer supported in Chef 12 and will be removed. Use Chef::ProviderResolver.new(node, resource, action) instead.")
- deprecated_constants[class_name.to_sym]
+ Chef::Provider.deprecated_constants[class_name.to_sym]
else
raise NameError, "uninitialized constant Chef::Provider::#{class_name}"
end
@@ -438,13 +438,12 @@ class Chef
if Chef::Provider.const_defined?(class_name, false)
Chef::Log.warn "Chef::Provider::#{class_name} already exists! Cannot create deprecation class for #{provider_class}"
else
- deprecated_constants[class_name.to_sym] = provider_class
+ Chef::Provider.deprecated_constants[class_name.to_sym] = provider_class
end
end
- private
-
def deprecated_constants
+ raise "Deprecated constants should be called only on Chef::Provider" unless self == Chef::Provider
@deprecated_constants ||= {}
end
end
diff --git a/lib/chef/provider/batch.rb b/lib/chef/provider/batch.rb
index bb294afd3f..0d857aaa79 100644
--- a/lib/chef/provider/batch.rb
+++ b/lib/chef/provider/batch.rb
@@ -29,7 +29,7 @@ class Chef
end
def command
- basepath = is_forced_32bit ? wow64_directory : run_context.node.kernel.os_info.system_directory
+ basepath = is_forced_32bit ? wow64_directory : run_context.node["kernel"]["os_info"]["system_directory"]
interpreter_path = Chef::Util::PathHelper.join(basepath, interpreter)
diff --git a/lib/chef/provider/cron.rb b/lib/chef/provider/cron.rb
index 36b67ab6a5..c7487cf42f 100644
--- a/lib/chef/provider/cron.rb
+++ b/lib/chef/provider/cron.rb
@@ -237,7 +237,7 @@ class Chef
newcron = ""
newcron << "# Chef Name: #{new_resource.name}\n"
[ :mailto, :path, :shell, :home ].each do |v|
- newcron << "#{v.to_s.upcase}=#{@new_resource.send(v)}\n" if @new_resource.send(v)
+ newcron << "#{v.to_s.upcase}=\"#{@new_resource.send(v)}\"\n" if @new_resource.send(v)
end
@new_resource.environment.each do |name, value|
newcron << "#{name}=#{value}\n"
diff --git a/lib/chef/provider/file.rb b/lib/chef/provider/file.rb
index 7f85085eeb..bb0762ceb7 100644
--- a/lib/chef/provider/file.rb
+++ b/lib/chef/provider/file.rb
@@ -154,6 +154,7 @@ class Chef
do_contents_changes
do_acl_changes
do_selinux
+ do_resolv_conf_fixup
load_resource_attributes_from_file(@new_resource)
end
@@ -445,6 +446,13 @@ class Chef
end
end
+ def do_resolv_conf_fixup
+ # reload /etc/resolv.conf after we edit it -- only on linux -- and see lib/chef/application.rb
+ if new_resource.path == "/etc/resolv.conf" && RbConfig::CONFIG["host_os"] =~ /linux/
+ Resolv::DefaultResolver.replace_resolvers [Resolv::DNS.new("/etc/resolv.conf")]
+ end
+ end
+
def do_acl_changes
if access_controls.requires_changes?
converge_by(access_controls.describe_changes) do
diff --git a/lib/chef/provider/package/aix.rb b/lib/chef/provider/package/aix.rb
index a1709c4af7..728f181055 100644
--- a/lib/chef/provider/package/aix.rb
+++ b/lib/chef/provider/package/aix.rb
@@ -55,7 +55,11 @@ class Chef
ret = shell_out_with_timeout("installp -L -d #{@new_resource.source}")
ret.stdout.each_line do |line|
case line
- when /#{@new_resource.package_name}:/
+ when /:#{@new_resource.package_name}:/
+ fields = line.split(":")
+ @new_resource.version(fields[2])
+ when /^#{@new_resource.package_name}:/
+ Chef::Log.warn("You are installing a bff package by product name. For idempotent installs, please install individual filesets")
fields = line.split(":")
@new_resource.version(fields[2])
end
diff --git a/lib/chef/provider/package/openbsd.rb b/lib/chef/provider/package/openbsd.rb
index 2120b9aa48..8043c01693 100644
--- a/lib/chef/provider/package/openbsd.rb
+++ b/lib/chef/provider/package/openbsd.rb
@@ -127,7 +127,7 @@ class Chef
end
def pkg_path
- ENV["PKG_PATH"] || "http://ftp.OpenBSD.org/pub/#{node.kernel.name}/#{node.kernel.release}/packages/#{node.kernel.machine}/"
+ ENV["PKG_PATH"] || "http://ftp.OpenBSD.org/pub/#{node["kernel"]["name"]}/#{node["kernel"]["release"]}/packages/#{node["kernel"]["machine"]}/"
end
end
diff --git a/lib/chef/provider/package/rubygems.rb b/lib/chef/provider/package/rubygems.rb
index eb5a87099f..0aeec951b1 100644
--- a/lib/chef/provider/package/rubygems.rb
+++ b/lib/chef/provider/package/rubygems.rb
@@ -431,17 +431,23 @@ class Chef
end
def current_version
- #raise 'todo'
+ # rubygems 2.6.3 ensures that gem lists are sorted newest first
+ pos = if Gem::Version.new(Gem::VERSION) >= Gem::Version.new("2.6.3")
+ :first
+ else
+ :last
+ end
+
# If one or more matching versions are installed, the newest of them
# is the current version
if !matching_installed_versions.empty?
- gemspec = matching_installed_versions.last
+ gemspec = matching_installed_versions.send(pos)
logger.debug { "#{@new_resource} found installed gem #{gemspec.name} version #{gemspec.version} matching #{gem_dependency}" }
gemspec
# If no version matching the requirements exists, the latest installed
# version is the current version.
elsif !all_installed_versions.empty?
- gemspec = all_installed_versions.last
+ gemspec = all_installed_versions.send(pos)
logger.debug { "#{@new_resource} newest installed version of gem #{gemspec.name} is #{gemspec.version}" }
gemspec
else
diff --git a/lib/chef/provider/package/windows/exe.rb b/lib/chef/provider/package/windows/exe.rb
index 70c9879845..211845c073 100644
--- a/lib/chef/provider/package/windows/exe.rb
+++ b/lib/chef/provider/package/windows/exe.rb
@@ -78,12 +78,9 @@ class Chef
private
def uninstall_command(uninstall_string)
- uninstall_string.delete!('"')
+ uninstall_string = "\"#{uninstall_string}\"" if ::File.exist?(uninstall_string)
uninstall_string = [
- %q{/d"},
- ::File.dirname(uninstall_string),
- %q{" },
- ::File.basename(uninstall_string),
+ uninstall_string,
expand_options(new_resource.options),
" ",
unattended_flags,
diff --git a/lib/chef/provider/package/zypper.rb b/lib/chef/provider/package/zypper.rb
index 5ee1dbea8e..e20a7332f7 100644
--- a/lib/chef/provider/package/zypper.rb
+++ b/lib/chef/provider/package/zypper.rb
@@ -38,15 +38,15 @@ class Chef
status = shell_out_with_timeout!("zypper --non-interactive info #{package_name}")
status.stdout.each_line do |line|
case line
- when /^Version: (.+)$/
- candidate_version = $1
- Chef::Log.debug("#{new_resource} version #{$1}")
- when /^Installed: Yes$/
+ when /^Version *: (.+) *$/
+ candidate_version = $1.strip
+ Chef::Log.debug("#{new_resource} version #{candidate_version}")
+ when /^Installed *: Yes *$/
is_installed = true
Chef::Log.debug("#{new_resource} is installed")
- when /^Status: out-of-date \(version (.+) installed\)$/
- current_version = $1
- Chef::Log.debug("#{new_resource} out of date version #{$1}")
+ when /^Status *: out-of-date \(version (.+) installed\) *$/
+ current_version = $1.strip
+ Chef::Log.debug("#{new_resource} out of date version #{current_version}")
end
end
current_version = candidate_version if is_installed
diff --git a/lib/chef/provider/powershell_script.rb b/lib/chef/provider/powershell_script.rb
index 6365f6a171..ab85ec35ac 100644
--- a/lib/chef/provider/powershell_script.rb
+++ b/lib/chef/provider/powershell_script.rb
@@ -36,7 +36,7 @@ class Chef
end
def command
- basepath = is_forced_32bit ? wow64_directory : run_context.node.kernel.os_info.system_directory
+ basepath = is_forced_32bit ? wow64_directory : run_context.node["kernel"]["os_info"]["system_directory"]
# Powershell.exe is always in "v1.0" folder (for backwards compatibility)
interpreter_path = Chef::Util::PathHelper.join(basepath, "WindowsPowerShell", "v1.0", interpreter)
diff --git a/lib/chef/provider/remote_directory.rb b/lib/chef/provider/remote_directory.rb
index e3bc579107..15b71c43bd 100644
--- a/lib/chef/provider/remote_directory.rb
+++ b/lib/chef/provider/remote_directory.rb
@@ -209,6 +209,8 @@ class Chef
def cookbook_file_resource(target_path, relative_source_path)
res = Chef::Resource::CookbookFile.new(target_path, run_context)
res.cookbook_name = resource_cookbook
+ # Set the sensitivity level
+ res.sensitive(new_resource.sensitive)
res.source(::File.join(source, relative_source_path))
if Chef::Platform.windows? && files_rights
files_rights.each_pair do |permission, *args|
diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb
index 2633187690..479eb0a7e2 100644
--- a/lib/chef/resource.rb
+++ b/lib/chef/resource.rb
@@ -260,6 +260,18 @@ class Chef
end
#
+ # Token class to hold an unresolved subscribes call with an associated
+ # run context.
+ #
+ # @api private
+ # @see Resource#subscribes
+ class UnresolvedSubscribes < self
+ # The full key ise given as the name in {Resource#subscribes}
+ alias_method :to_s, :name
+ alias_method :declared_key, :name
+ end
+
+ #
# Subscribes to updates from other resources, causing a particular action to
# run on *this* resource when the other resource is updated.
#
@@ -326,7 +338,7 @@ class Chef
resources = [resources].flatten
resources.each do |resource|
if resource.is_a?(String)
- resource = Chef::Resource.new(resource, run_context)
+ resource = UnresolvedSubscribes.new(resource, run_context)
end
if resource.run_context.nil?
resource.run_context = run_context
@@ -1530,23 +1542,6 @@ class Chef
end
# @api private
- def self.register_deprecated_lwrp_class(resource_class, class_name)
- if Chef::Resource.const_defined?(class_name, false)
- Chef::Log.warn "#{class_name} already exists! Deprecation class overwrites #{resource_class}"
- Chef::Resource.send(:remove_const, class_name)
- end
-
- if !Chef::Config[:treat_deprecation_warnings_as_errors]
- Chef::Resource.const_set(class_name, resource_class)
- deprecated_constants[class_name.to_sym] = resource_class
- end
- end
-
- def self.deprecated_constants
- @deprecated_constants ||= {}
- end
-
- # @api private
def lookup_provider_constant(name, action = :nothing)
begin
self.class.provider_base.const_get(convert_to_class_name(name.to_s))
@@ -1559,6 +1554,27 @@ class Chef
end
end
+ module DeprecatedLWRPClass
+
+ # @api private
+ def register_deprecated_lwrp_class(resource_class, class_name)
+ if Chef::Resource.const_defined?(class_name, false)
+ Chef::Log.warn "#{class_name} already exists! Deprecation class overwrites #{resource_class}"
+ Chef::Resource.send(:remove_const, class_name)
+ end
+
+ if !Chef::Config[:treat_deprecation_warnings_as_errors]
+ Chef::Resource.const_set(class_name, resource_class)
+ Chef::Resource.deprecated_constants[class_name.to_sym] = resource_class
+ end
+ end
+
+ def deprecated_constants
+ raise "Deprecated constants should be called only on Chef::Resource" unless self == Chef::Resource
+ @deprecated_constants ||= {}
+ end
+ end
+
private
def self.remove_canonical_dsl
@@ -1569,6 +1585,7 @@ class Chef
end
end
end
+ extend DeprecatedLWRPClass
end
end
diff --git a/lib/chef/resource_builder.rb b/lib/chef/resource_builder.rb
index 138e401d5c..1641fe60f2 100644
--- a/lib/chef/resource_builder.rb
+++ b/lib/chef/resource_builder.rb
@@ -104,7 +104,11 @@ class Chef
end
def is_trivial_resource?(resource)
- identicalish_resources?(resource_class.new(name, run_context), resource)
+ trivial_resource = resource_class.new(name, run_context)
+ # force un-lazy the name property on the created trivial resource
+ name_property = resource_class.properties.find { |sym, p| p.name_property? }
+ trivial_resource.send(name_property[0]) unless name_property.nil?
+ identicalish_resources?(trivial_resource, resource)
end
# this is an equality test specific to checking for 3694 cloning warnings
@@ -124,9 +128,10 @@ class Chef
end
def emit_cloned_resource_warning
- Chef::Log.warn("Cloning resource attributes for #{resource} from prior resource (CHEF-3694)")
- Chef::Log.warn("Previous #{prior_resource}: #{prior_resource.source_line}") if prior_resource.source_line
- Chef::Log.warn("Current #{resource}: #{resource.source_line}") if resource.source_line
+ message = "Cloning resource attributes for #{resource} from prior resource (CHEF-3694)"
+ message << "\nPrevious #{prior_resource}: #{prior_resource.source_line}" if prior_resource.source_line
+ message << "\nCurrent #{resource}: #{resource.source_line}" if resource.source_line
+ Chef.log_deprecation(message)
end
def emit_harmless_cloning_debug
diff --git a/lib/chef/run_context.rb b/lib/chef/run_context.rb
index 29c936a932..7ef476c44b 100644
--- a/lib/chef/run_context.rb
+++ b/lib/chef/run_context.rb
@@ -194,12 +194,10 @@ class Chef
# @param [Chef::Resource::Notification] The notification to add.
#
def notifies_before(notification)
- nr = notification.notifying_resource
- if nr.instance_of?(Chef::Resource)
- before_notification_collection[nr.name] << notification
- else
- before_notification_collection[nr.declared_key] << notification
- end
+ # Note for the future, notification.notifying_resource may be an instance
+ # of Chef::Resource::UnresolvedSubscribes when calling {Resource#subscribes}
+ # with a string value.
+ before_notification_collection[notification.notifying_resource.declared_key] << notification
end
#
@@ -208,12 +206,10 @@ class Chef
# @param [Chef::Resource::Notification] The notification to add.
#
def notifies_immediately(notification)
- nr = notification.notifying_resource
- if nr.instance_of?(Chef::Resource)
- immediate_notification_collection[nr.name] << notification
- else
- immediate_notification_collection[nr.declared_key] << notification
- end
+ # Note for the future, notification.notifying_resource may be an instance
+ # of Chef::Resource::UnresolvedSubscribes when calling {Resource#subscribes}
+ # with a string value.
+ immediate_notification_collection[notification.notifying_resource.declared_key] << notification
end
#
@@ -222,12 +218,10 @@ class Chef
# @param [Chef::Resource::Notification] The notification to add.
#
def notifies_delayed(notification)
- nr = notification.notifying_resource
- if nr.instance_of?(Chef::Resource)
- delayed_notification_collection[nr.name] << notification
- else
- delayed_notification_collection[nr.declared_key] << notification
- end
+ # Note for the future, notification.notifying_resource may be an instance
+ # of Chef::Resource::UnresolvedSubscribes when calling {Resource#subscribes}
+ # with a string value.
+ delayed_notification_collection[notification.notifying_resource.declared_key] << notification
end
#
@@ -245,50 +239,29 @@ class Chef
#
# Get the list of before notifications sent by the given resource.
#
- # TODO seriously, this is actually wrong. resource.name is not unique,
- # you need the type as well.
- #
# @return [Array[Notification]]
#
def before_notifications(resource)
- if resource.instance_of?(Chef::Resource)
- return before_notification_collection[resource.name]
- else
- return before_notification_collection[resource.declared_key]
- end
+ return before_notification_collection[resource.declared_key]
end
#
# Get the list of immediate notifications sent by the given resource.
#
- # TODO seriously, this is actually wrong. resource.name is not unique,
- # you need the type as well.
- #
# @return [Array[Notification]]
#
def immediate_notifications(resource)
- if resource.instance_of?(Chef::Resource)
- return immediate_notification_collection[resource.name]
- else
- return immediate_notification_collection[resource.declared_key]
- end
+ return immediate_notification_collection[resource.declared_key]
end
#
# Get the list of delayed (end of run) notifications sent by the given
# resource.
#
- # TODO seriously, this is actually wrong. resource.name is not unique,
- # you need the type as well.
- #
# @return [Array[Notification]]
#
def delayed_notifications(resource)
- if resource.instance_of?(Chef::Resource)
- return delayed_notification_collection[resource.name]
- else
- return delayed_notification_collection[resource.declared_key]
- end
+ return delayed_notification_collection[resource.declared_key]
end
#
diff --git a/lib/chef/shell.rb b/lib/chef/shell.rb
index aad5c49d00..26683cc25d 100644
--- a/lib/chef/shell.rb
+++ b/lib/chef/shell.rb
@@ -148,7 +148,7 @@ module Shell
end
def self.greeting
- " #{Etc.getlogin}@#{Shell.session.node.fqdn}"
+ " #{Etc.getlogin}@#{Shell.session.node["fqdn"]}"
rescue NameError, ArgumentError
""
end
diff --git a/lib/chef/version.rb b/lib/chef/version.rb
index 7c38be31b3..cc29ef1740 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.12.2"
+ VERSION = "12.13.21"
end
#
diff --git a/omnibus/.kitchen.yml b/omnibus/.kitchen.yml
index 90283f8afb..a14d3498de 100644
--- a/omnibus/.kitchen.yml
+++ b/omnibus/.kitchen.yml
@@ -11,7 +11,7 @@ driver:
cpus: 4
memory: 4096
synced_folders:
- - ['..', '/home/vagrant/chef']
+ - ['../..', '/vagrant/code']
- ['../../omnibus', '/home/vagrant/omnibus']
- ['../../omnibus-software', '/home/vagrant/omnibus-software']
@@ -24,7 +24,12 @@ provisioner:
attributes:
vagrant:
this_key_exists_so_we_have_a_vagrant_key: true
- chef_omnibus_install_options: -P angrychef
+ omnibus:
+ build_user: vagrant
+ build_user_group: vagrant
+ build_user_password: vagrant
+ product_name: angrychef
+ product_version: latest
chef_omnibus_root: /opt/angrychef
platforms:
@@ -91,12 +96,30 @@ platforms:
# at `C:\vagrant\code\chef`
- ['../..', '/vagrant/code']
provisioner:
+ attributes:
+ omnibus:
+ build_user: vagrant
+ build_user_group: Administrators
+ build_user_password: vagrant
+ chef_omnibus_root: /opscode/angrychef
+ # By adding an `i386` to the name the Omnibus cookbook's `load-omnibus-toolchain.bat`
+ # will load the 32-bit version of the MinGW toolchain.
+ - name: windows-2012r2-standard-i386
+ driver:
+ box: chef/windows-server-2012r2-standard # private
+ synced_folders:
+ # We have to mount this repos enclosing folder as the Omnibus build
+ # gets cranky if the mounted ChefDK source folder is a symlink. This
+ # mounts at `C:\vagrant\code` and the ChefDK source folder is available
+ # at `C:\vagrant\code\chef-dk`
+ - ['../..', '/vagrant/code']
+ provisioner:
+ attributes:
+ omnibus:
+ build_user: vagrant
+ build_user_group: Administrators
+ build_user_password: vagrant
chef_omnibus_root: /opscode/angrychef
-
-attribute_defaults: &attribute_defaults
- build_user: vagrant
- build_user_group: vagrant
- build_user_password: vagrant
suites:
# - name: angrychef
@@ -109,7 +132,6 @@ suites:
- name: chef
attributes:
omnibus:
- <<: *attribute_defaults
install_dir: /opt/chef
run_list:
- omnibus::default
diff --git a/omnibus/Gemfile b/omnibus/Gemfile
index ef1dec354d..3e19adfb39 100644
--- a/omnibus/Gemfile
+++ b/omnibus/Gemfile
@@ -13,10 +13,10 @@ gem "pedump", git: "https://github.com/ksubrama/pedump.git", branch: "patch-1"
# by running `bundle install --without development` to speed up build times.
group :development do
# Use Berkshelf for resolving cookbook dependencies
- gem "berkshelf", "~> 3.0"
+ gem "berkshelf", "~> 4.0"
# Use Test Kitchen with Vagrant for converging the build environment
- gem "test-kitchen", "~> 1.7.1"
+ gem "test-kitchen", "~> 1.9"
gem "kitchen-vagrant", "~> 0.19.0"
gem "winrm-fs", "~> 0.4.0"
gem "pry"
diff --git a/omnibus/Gemfile.lock b/omnibus/Gemfile.lock
index f165fa5d12..f8cfeec014 100644
--- a/omnibus/Gemfile.lock
+++ b/omnibus/Gemfile.lock
@@ -1,13 +1,13 @@
GIT
remote: https://github.com/chef/omnibus-software.git
- revision: 2f04eff7dbec575cb2985d846dacd02a422cd36f
+ revision: 5e767a6d220f024256439b0a8415eefe923967dc
specs:
omnibus-software (4.0.0)
omnibus (>= 5.2.0)
GIT
remote: https://github.com/chef/omnibus.git
- revision: a36e70caedceadfcf0d85e2adef44ba0218a60a6
+ revision: 29d390ec93709ceec2667038aed6769ee29a0646
specs:
omnibus (5.4.0)
aws-sdk (~> 2)
@@ -35,35 +35,36 @@ GIT
GEM
remote: https://rubygems.org/
specs:
- addressable (2.3.8)
+ addressable (2.4.0)
artifactory (2.3.2)
- awesome_print (1.6.1)
- aws-sdk (2.3.9)
- aws-sdk-resources (= 2.3.9)
- aws-sdk-core (2.3.9)
+ awesome_print (1.7.0)
+ aws-sdk (2.4.2)
+ aws-sdk-resources (= 2.4.2)
+ aws-sdk-core (2.4.2)
jmespath (~> 1.0)
- aws-sdk-resources (2.3.9)
- aws-sdk-core (= 2.3.9)
- berkshelf (3.3.0)
- addressable (~> 2.3.4)
- berkshelf-api-client (~> 1.2)
+ aws-sdk-resources (2.4.2)
+ aws-sdk-core (= 2.4.2)
+ berkshelf (4.3.3)
+ addressable (~> 2.3, >= 2.3.4)
+ berkshelf-api-client (~> 2.0, >= 2.0.2)
buff-config (~> 1.0)
buff-extensions (~> 1.0)
buff-shell_out (~> 0.1)
- celluloid (~> 0.16.0)
+ celluloid (= 0.16.0)
celluloid-io (~> 0.16.1)
cleanroom (~> 1.0)
- faraday (~> 0.9.0)
- httpclient (~> 2.6.0)
- minitar (~> 0.5.4)
- octokit (~> 3.0)
+ faraday (~> 0.9)
+ httpclient (~> 2.7)
+ minitar (~> 0.5, >= 0.5.4)
+ octokit (~> 4.0)
retryable (~> 2.0)
- ridley (~> 4.0)
- solve (~> 1.1)
+ ridley (~> 4.5)
+ solve (~> 2.0)
thor (~> 0.19)
- berkshelf-api-client (1.3.1)
+ berkshelf-api-client (2.0.2)
faraday (~> 0.9.1)
- httpclient (~> 2.6.0)
+ httpclient (~> 2.7.0)
+ ridley (~> 4.5)
binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1)
buff-config (1.0.1)
@@ -75,31 +76,26 @@ GEM
buff-shell_out (0.2.0)
buff-ruby_engine (~> 0.1.0)
builder (3.2.2)
- byebug (9.0.4)
+ byebug (9.0.5)
celluloid (0.16.0)
timers (~> 4.0.0)
celluloid-io (0.16.2)
celluloid (>= 0.16.0)
nio4r (>= 1.1.0)
- chef-config (12.10.24)
+ chef-config (12.12.15)
fuzzyurl (~> 0.8.0)
mixlib-config (~> 2.0)
mixlib-shellout (~> 2.0)
- chef-sugar (3.3.0)
+ chef-sugar (3.4.0)
cleanroom (1.0.0)
coderay (1.1.1)
debug_inspector (0.0.2)
- dep-selector-libgecode (1.2.0)
- dep_selector (1.0.3)
- dep-selector-libgecode (~> 1.0)
- ffi (~> 1.9)
- diff-lcs (1.2.5)
erubis (2.7.0)
faraday (0.9.2)
multipart-post (>= 1.2, < 3)
- ffi (1.9.10)
- ffi (1.9.10-x86-mingw32)
- ffi-yajl (2.2.3)
+ ffi (1.9.14)
+ ffi (1.9.14-x86-mingw32)
+ ffi-yajl (2.3.0)
libyajl2 (~> 1.2)
fuzzyurl (0.8.0)
gssapi (1.2.0)
@@ -109,13 +105,11 @@ GEM
hashie (3.4.4)
hitimes (1.2.4)
hitimes (1.2.4-x86-mingw32)
- httpclient (2.6.0.1)
+ httpclient (2.7.2)
iostruct (0.0.4)
ipaddress (0.8.3)
- jmespath (1.2.4)
- json_pure (>= 1.8.1)
+ jmespath (1.3.1)
json (1.8.3)
- json_pure (1.8.3)
kitchen-vagrant (0.19.0)
test-kitchen (~> 1.4)
libyajl2 (1.2.0)
@@ -125,11 +119,8 @@ GEM
multi_json (~> 1.10)
method_source (0.8.2)
minitar (0.5.4)
- mixlib-authentication (1.4.0)
+ mixlib-authentication (1.4.1)
mixlib-log
- rspec-core (~> 3.2)
- rspec-expectations (~> 3.2)
- rspec-mocks (~> 3.2)
mixlib-cli (1.6.0)
mixlib-config (2.2.1)
mixlib-install (1.0.12)
@@ -142,6 +133,7 @@ GEM
win32-process (~> 0.8.2)
wmi-lite (~> 1.0)
mixlib-versioning (1.1.0)
+ molinillo (0.4.5)
multi_json (1.12.1)
multipart-post (1.2.0)
net-scp (1.2.1)
@@ -149,9 +141,9 @@ GEM
net-ssh (3.1.1)
nio4r (1.2.1)
nori (2.6.0)
- octokit (3.8.0)
- sawyer (~> 0.6.0, >= 0.5.3)
- ohai (8.16.0)
+ octokit (4.3.0)
+ sawyer (~> 0.7.0, >= 0.5.3)
+ ohai (8.17.1)
chef-config (>= 12.5.0.alpha.1, < 13)
ffi (~> 1.9)
ffi-yajl (~> 2.2)
@@ -176,7 +168,7 @@ GEM
binding_of_caller (>= 0.7)
pry (>= 0.9.11)
retryable (2.0.3)
- ridley (4.4.2)
+ ridley (4.5.1)
addressable
buff-config (~> 1.0)
buff-extensions (~> 1.0)
@@ -184,39 +176,30 @@ GEM
buff-shell_out (~> 0.1)
celluloid (~> 0.16.0)
celluloid-io (~> 0.16.1)
- chef-config
+ chef-config (>= 12.5.0)
erubis
faraday (~> 0.9.0)
hashie (>= 2.0.2, < 4.0.0)
- httpclient (~> 2.6)
+ httpclient (~> 2.7)
json (>= 1.7.7)
mixlib-authentication (>= 1.3.0)
retryable (~> 2.0)
semverse (~> 1.1)
varia_model (~> 0.4.0)
- rspec-core (3.4.4)
- rspec-support (~> 3.4.0)
- rspec-expectations (3.4.0)
- diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.4.0)
- rspec-mocks (3.4.1)
- diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.4.0)
- rspec-support (3.4.1)
ruby-progressbar (1.8.1)
rubyntlm (0.6.0)
rubyzip (1.2.0)
safe_yaml (1.0.4)
- sawyer (0.6.0)
- addressable (~> 2.3.5)
+ sawyer (0.7.0)
+ addressable (>= 2.3.5, < 2.5)
faraday (~> 0.8, < 0.10)
semverse (1.2.1)
slop (3.6.0)
- solve (1.2.1)
- dep_selector (~> 1.0)
+ solve (2.0.3)
+ molinillo (~> 0.4.2)
semverse (~> 1.1)
systemu (2.6.5)
- test-kitchen (1.7.3)
+ test-kitchen (1.9.2)
mixlib-install (~> 1.0, >= 1.0.4)
mixlib-shellout (>= 1.2, < 3.0)
net-scp (~> 1.1)
@@ -252,7 +235,7 @@ PLATFORMS
x86-mingw32
DEPENDENCIES
- berkshelf (~> 3.0)
+ berkshelf (~> 4.0)
kitchen-vagrant (~> 0.19.0)
omnibus!
omnibus-software!
@@ -260,7 +243,7 @@ DEPENDENCIES
pry
pry-byebug
pry-stack_explorer
- test-kitchen (~> 1.7.1)
+ test-kitchen (~> 1.9)
winrm-fs (~> 0.4.0)
BUNDLED WITH
diff --git a/omnibus/config/software/chef-gem-nokogiri.rb b/omnibus/config/software/chef-gem-nokogiri.rb
index 8bf7100d5b..a25a47d341 100644
--- a/omnibus/config/software/chef-gem-nokogiri.rb
+++ b/omnibus/config/software/chef-gem-nokogiri.rb
@@ -8,4 +8,5 @@ BuildChefGem::GemInstallSoftwareDef.define(self, __FILE__)
license "MIT"
license_file "https://github.com/ruby-prof/ruby-prof/blob/master/LICENSE"
+dependency "chef-gem-pkg-config"
dependency "chef-gem-mini_portile2"
diff --git a/omnibus/config/software/chef-gem-pkg-config.rb b/omnibus/config/software/chef-gem-pkg-config.rb
new file mode 100644
index 0000000000..9c6e6fa695
--- /dev/null
+++ b/omnibus/config/software/chef-gem-pkg-config.rb
@@ -0,0 +1,9 @@
+# gem installs this gem from the version specified in chef's Gemfile.lock
+# so we can take advantage of omnibus's caching. Just duplicate this file and
+# add the new software def to chef software def if you want to separate
+# another gem's installation.
+require_relative "../../files/chef-gem/build-chef-gem/gem-install-software-def"
+BuildChefGem::GemInstallSoftwareDef.define(self, __FILE__)
+
+license "LGPL-2.1"
+license_file "https://github.com/ruby-gnome2/pkg-config/blob/master/LGPL-2.1"
diff --git a/omnibus/config/software/chef.rb b/omnibus/config/software/chef.rb
index 49db136e94..c6ced7e566 100644
--- a/omnibus/config/software/chef.rb
+++ b/omnibus/config/software/chef.rb
@@ -69,13 +69,6 @@ build do
block { log.info(log_key) { "" } }
bundle "install --verbose", env: project_env
- # For whatever reason, nokogiri software def deletes this (rather small) directory
- block { log.info(log_key) { "" } }
- block "Remove mini_portile test dir" do
- mini_portile = shellout!("#{bundle_bin} show mini_portile").stdout.chomp
- remove_directory File.join(mini_portile, "test")
- end
-
# Check that it worked
block { log.info(log_key) { "" } }
bundle "check", env: project_env
diff --git a/omnibus_overrides.rb b/omnibus_overrides.rb
index d971dd99fa..7771e805e3 100644
--- a/omnibus_overrides.rb
+++ b/omnibus_overrides.rb
@@ -1,12 +1,12 @@
# DO NOT EDIT. Generated by "rake dependencies". Edit version_policy.rb instead.
override :rubygems, version: "2.6.4"
-override :bundler, version: "1.11.2"
+override :bundler, version: "1.12.5"
override "libffi", version: "3.2.1"
override "libiconv", version: "1.14"
override "liblzma", version: "5.2.2"
override "libtool", version: "2.4.2"
-override "libxml2", version: "2.9.3"
-override "libxslt", version: "1.1.28"
+override "libxml2", version: "2.9.4"
+override "libxslt", version: "1.1.29"
override "libyaml", version: "0.1.6"
override "makedepend", version: "1.0.5"
override "ncurses", version: "5.9"
diff --git a/pkg.rb b/pkg.rb
deleted file mode 100644
index bb26f257d0..0000000000
--- a/pkg.rb
+++ /dev/null
@@ -1 +0,0 @@
-package "chef-12.9.38-1.powerpc"
diff --git a/rubygems-pkg/rubygems-update-2.4.6.gem b/rubygems-pkg/rubygems-update-2.4.6.gem
deleted file mode 100644
index 97ebec693a..0000000000
--- a/rubygems-pkg/rubygems-update-2.4.6.gem
+++ /dev/null
Binary files differ
diff --git a/spec/data/run_context/cookbooks/circular-dep1/attributes/default.rb b/spec/data/run_context/cookbooks/circular-dep1/attributes/default.rb
index ef0967a4d2..e45e7d9f68 100644
--- a/spec/data/run_context/cookbooks/circular-dep1/attributes/default.rb
+++ b/spec/data/run_context/cookbooks/circular-dep1/attributes/default.rb
@@ -1,4 +1,2 @@
-set_unless[:attr_load_order] = []
-set[:attr_load_order] << "circular-dep1::default"
-
-
+normal_unless[:attr_load_order] = []
+normal[:attr_load_order] << "circular-dep1::default"
diff --git a/spec/data/run_context/cookbooks/circular-dep2/attributes/default.rb b/spec/data/run_context/cookbooks/circular-dep2/attributes/default.rb
index f2ef012aa1..37f396b1f9 100644
--- a/spec/data/run_context/cookbooks/circular-dep2/attributes/default.rb
+++ b/spec/data/run_context/cookbooks/circular-dep2/attributes/default.rb
@@ -1,3 +1,2 @@
-set_unless[:attr_load_order] = []
-set[:attr_load_order] << "circular-dep2::default"
-
+normal_unless[:attr_load_order] = []
+normal[:attr_load_order] << "circular-dep2::default"
diff --git a/spec/data/run_context/cookbooks/dependency1/attributes/aa_first.rb b/spec/data/run_context/cookbooks/dependency1/attributes/aa_first.rb
index e818d36a9e..3059494198 100644
--- a/spec/data/run_context/cookbooks/dependency1/attributes/aa_first.rb
+++ b/spec/data/run_context/cookbooks/dependency1/attributes/aa_first.rb
@@ -1,2 +1,2 @@
-set_unless[:attr_load_order] = []
-set[:attr_load_order] << "dependency1::aa_first"
+normal_unless[:attr_load_order] = []
+normal[:attr_load_order] << "dependency1::aa_first"
diff --git a/spec/data/run_context/cookbooks/dependency1/attributes/default.rb b/spec/data/run_context/cookbooks/dependency1/attributes/default.rb
index 6875274e3f..a65a3345bc 100644
--- a/spec/data/run_context/cookbooks/dependency1/attributes/default.rb
+++ b/spec/data/run_context/cookbooks/dependency1/attributes/default.rb
@@ -1,2 +1,2 @@
-set_unless[:attr_load_order] = []
-set[:attr_load_order] << "dependency1::default"
+normal_unless[:attr_load_order] = []
+normal[:attr_load_order] << "dependency1::default"
diff --git a/spec/data/run_context/cookbooks/dependency1/attributes/zz_last.rb b/spec/data/run_context/cookbooks/dependency1/attributes/zz_last.rb
index 1a513b03d4..94ffb30133 100644
--- a/spec/data/run_context/cookbooks/dependency1/attributes/zz_last.rb
+++ b/spec/data/run_context/cookbooks/dependency1/attributes/zz_last.rb
@@ -1,3 +1,2 @@
-set_unless[:attr_load_order] = []
-set[:attr_load_order] << "dependency1::zz_last"
-
+normal_unless[:attr_load_order] = []
+normal[:attr_load_order] << "dependency1::zz_last"
diff --git a/spec/data/run_context/cookbooks/dependency2/attributes/default.rb b/spec/data/run_context/cookbooks/dependency2/attributes/default.rb
index 526751f422..8917bf9730 100644
--- a/spec/data/run_context/cookbooks/dependency2/attributes/default.rb
+++ b/spec/data/run_context/cookbooks/dependency2/attributes/default.rb
@@ -1,3 +1,2 @@
-set_unless[:attr_load_order] = []
-set[:attr_load_order] << "dependency2::default"
-
+normal_unless[:attr_load_order] = []
+normal[:attr_load_order] << "dependency2::default"
diff --git a/spec/data/run_context/cookbooks/no-default-attr/attributes/server.rb b/spec/data/run_context/cookbooks/no-default-attr/attributes/server.rb
index 3ad2b925aa..07294665b2 100644
--- a/spec/data/run_context/cookbooks/no-default-attr/attributes/server.rb
+++ b/spec/data/run_context/cookbooks/no-default-attr/attributes/server.rb
@@ -1,3 +1,2 @@
-set_unless[:attr_load_order] = []
-set[:attr_load_order] << "no-default-attr::server"
-
+normal_unless[:attr_load_order] = []
+normal[:attr_load_order] << "no-default-attr::server"
diff --git a/spec/data/run_context/cookbooks/test-with-circular-deps/attributes/default.rb b/spec/data/run_context/cookbooks/test-with-circular-deps/attributes/default.rb
index cca56bc61f..77309462b1 100644
--- a/spec/data/run_context/cookbooks/test-with-circular-deps/attributes/default.rb
+++ b/spec/data/run_context/cookbooks/test-with-circular-deps/attributes/default.rb
@@ -1,3 +1,2 @@
-set_unless[:attr_load_order] = []
-set[:attr_load_order] << "test-with-circular-deps::default"
-
+normal_unless[:attr_load_order] = []
+normal[:attr_load_order] << "test-with-circular-deps::default"
diff --git a/spec/data/run_context/cookbooks/test-with-deps/attributes/default.rb b/spec/data/run_context/cookbooks/test-with-deps/attributes/default.rb
index 4d71cc3cfe..c4cc8151a4 100644
--- a/spec/data/run_context/cookbooks/test-with-deps/attributes/default.rb
+++ b/spec/data/run_context/cookbooks/test-with-deps/attributes/default.rb
@@ -1,3 +1,2 @@
-set_unless[:attr_load_order] = []
-set[:attr_load_order] << "test-with-deps::default"
-
+normal_unless[:attr_load_order] = []
+normal[:attr_load_order] << "test-with-deps::default"
diff --git a/spec/functional/assets/chocolatey_feed/test-A.1.0.nupkg b/spec/functional/assets/chocolatey_feed/test-A.1.0.nupkg
index a2d3e7bb4e..0295507373 100644
--- a/spec/functional/assets/chocolatey_feed/test-A.1.0.nupkg
+++ b/spec/functional/assets/chocolatey_feed/test-A.1.0.nupkg
Binary files differ
diff --git a/spec/functional/assets/chocolatey_feed/test-A.1.5.nupkg b/spec/functional/assets/chocolatey_feed/test-A.1.5.nupkg
index 9ce9445689..19782211e3 100644
--- a/spec/functional/assets/chocolatey_feed/test-A.1.5.nupkg
+++ b/spec/functional/assets/chocolatey_feed/test-A.1.5.nupkg
Binary files differ
diff --git a/spec/functional/assets/chocolatey_feed/test-A.2.0.nupkg b/spec/functional/assets/chocolatey_feed/test-A.2.0.nupkg
index 250084d3ce..360c0843e2 100644
--- a/spec/functional/assets/chocolatey_feed/test-A.2.0.nupkg
+++ b/spec/functional/assets/chocolatey_feed/test-A.2.0.nupkg
Binary files differ
diff --git a/spec/functional/assets/chocolatey_feed/test-B.1.0.nupkg b/spec/functional/assets/chocolatey_feed/test-B.1.0.nupkg
index f275c78dc6..d82b0d09bc 100644
--- a/spec/functional/assets/chocolatey_feed/test-B.1.0.nupkg
+++ b/spec/functional/assets/chocolatey_feed/test-B.1.0.nupkg
Binary files differ
diff --git a/spec/functional/resource/cron_spec.rb b/spec/functional/resource/cron_spec.rb
index 3380eccb0d..f5948191c5 100644
--- a/spec/functional/resource/cron_spec.rb
+++ b/spec/functional/resource/cron_spec.rb
@@ -120,7 +120,7 @@ describe Chef::Resource::Cron, :requires_root, :unix_only do
return if %w{aix solaris}.include?(ohai[:platform])
# Test if the attribute exists on newly created cron
cron_should_exists(cron_name, "")
- expect(shell_out("crontab -l -u #{new_resource.user} | grep \"#{attribute.upcase}=#{value}\"").exitstatus).to eq(0)
+ expect(shell_out("crontab -l -u #{new_resource.user} | grep '#{attribute.upcase}=\"#{value}\"'").exitstatus).to eq(0)
end
after do
@@ -146,6 +146,13 @@ describe Chef::Resource::Cron, :requires_root, :unix_only do
new_resource.home "/home/opscode"
create_and_validate_with_attribute(new_resource, "home", "/home/opscode")
end
+
+ %i{ home mailto path shell }.each do |attr|
+ it "supports an empty string for #{attr} attribute" do
+ new_resource.send(attr, "")
+ create_and_validate_with_attribute(new_resource, attr.to_s, "")
+ end
+ end
end
describe "negative tests for create action" do
diff --git a/spec/functional/resource/dsc_script_spec.rb b/spec/functional/resource/dsc_script_spec.rb
index dc687ec074..5ee97f04a3 100644
--- a/spec/functional/resource/dsc_script_spec.rb
+++ b/spec/functional/resource/dsc_script_spec.rb
@@ -469,7 +469,7 @@ EOF
end
it "allows the use of ps_credential" do
- pending("Pended until we can adjust the test cert to meet the WMF 5 cert requirements.")
+ skip("Skipped until we can adjust the test cert to meet the WMF 5 cert requirements.")
expect(user_exists?(dsc_user)).to eq(false)
powershell_script_resource.run_action(:run)
expect(File).to exist(configuration_data_path)
diff --git a/spec/functional/resource/package_spec.rb b/spec/functional/resource/package_spec.rb
index 6dc55f7f01..0f01a751ec 100644
--- a/spec/functional/resource/package_spec.rb
+++ b/spec/functional/resource/package_spec.rb
@@ -260,7 +260,7 @@ describe Chef::Resource::Package, metadata do
end
before do
- node.set[:preseed_value] = "FROM TEMPLATE"
+ node.normal[:preseed_value] = "FROM TEMPLATE"
end
it "preseeds the package, then installs it" do
diff --git a/spec/functional/resource/template_spec.rb b/spec/functional/resource/template_spec.rb
index f270043f2c..32529fbb0c 100644
--- a/spec/functional/resource/template_spec.rb
+++ b/spec/functional/resource/template_spec.rb
@@ -110,7 +110,7 @@ describe Chef::Resource::Template do
context "using single helper syntax referencing @node" do
before do
- node.set[:helper_test_attr] = "value from helper method"
+ node.normal[:helper_test_attr] = "value from helper method"
resource.helper(:helper_method) { "#{@node[:helper_test_attr]}" }
end
@@ -131,7 +131,7 @@ describe Chef::Resource::Template do
context "using an inline block referencing @node" do
before do
- node.set[:helper_test_attr] = "value from helper method"
+ node.normal[:helper_test_attr] = "value from helper method"
resource.helpers do
def helper_method
@@ -168,7 +168,7 @@ describe Chef::Resource::Template do
end
before do
- node.set[:helper_test_attr] = "value from helper method"
+ node.normal[:helper_test_attr] = "value from helper method"
resource.helpers(ExampleModuleReferencingATNode)
end
diff --git a/spec/functional/shell_spec.rb b/spec/functional/shell_spec.rb
index fe2abdb12a..636162fb16 100644
--- a/spec/functional/shell_spec.rb
+++ b/spec/functional/shell_spec.rb
@@ -137,7 +137,7 @@ describe Shell do
it "sets the override_runlist from the command line" do
output, exitstatus = run_chef_shell_with("-o 'override::foo,override::bar'") do |out, keyboard|
- show_recipes_code = %q[puts "#{node.recipes.inspect}"]
+ show_recipes_code = %q[puts "#{node["recipes"].inspect}"]
keyboard.puts(show_recipes_code)
read_until(out, show_recipes_code)
end
diff --git a/spec/integration/knife/client_bulk_delete_spec.rb b/spec/integration/knife/client_bulk_delete_spec.rb
new file mode 100644
index 0000000000..a422401af6
--- /dev/null
+++ b/spec/integration/knife/client_bulk_delete_spec.rb
@@ -0,0 +1,130 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife client bulk delete", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some clients" do
+ before do
+ client "concat", {}
+ client "cons", {}
+ client "car", {}
+ client "cdr", {}
+ client "cat", {}
+ end
+
+ it "deletes all matching clients" do
+ knife("client bulk delete ^ca.*", input: "Y").should_succeed <<EOM
+The following clients will be deleted:
+
+car cat
+
+Are you sure you want to delete these clients? (Y/N) Deleted client car
+Deleted client cat
+EOM
+
+ knife("client list").should_succeed <<EOM
+cdr
+chef-validator
+chef-webui
+concat
+cons
+EOM
+ end
+
+ it "deletes all matching clients when unanchored" do
+ knife("client bulk delete ca.*", input: "Y").should_succeed <<EOM
+The following clients will be deleted:
+
+car cat concat
+
+Are you sure you want to delete these clients? (Y/N) Deleted client car
+Deleted client cat
+Deleted client concat
+EOM
+
+ knife("client list").should_succeed <<EOM
+cdr
+chef-validator
+chef-webui
+cons
+EOM
+ end
+ end
+
+ when_the_chef_server "has a validator client" do
+ before do
+ client "cons", {}
+ client "car", {}
+ client "car-validator", { validator: true }
+ client "cdr", {}
+ client "cat", {}
+ end
+
+ it "refuses to delete a validator normally" do
+ knife("client bulk delete ^ca.*", input: "Y").should_succeed <<EOM
+The following clients are validators and will not be deleted:
+
+car-validator
+
+You must specify --delete-validators to delete the validator clients
+The following clients will be deleted:
+
+car cat
+
+Are you sure you want to delete these clients? (Y/N) Deleted client car
+Deleted client cat
+EOM
+
+ knife("client list").should_succeed <<EOM
+car-validator
+cdr
+chef-validator
+chef-webui
+cons
+EOM
+ end
+
+ it "deletes a validator when told to" do
+ knife("client bulk delete ^ca.* -D", input: "Y\nY").should_succeed <<EOM
+The following validators will be deleted:
+
+car-validator
+
+Are you sure you want to delete these validators? (Y/N) Deleted client car-validator
+The following clients will be deleted:
+
+car cat
+
+Are you sure you want to delete these clients? (Y/N) Deleted client car
+Deleted client cat
+EOM
+
+ knife("client list").should_succeed <<EOM
+cdr
+chef-validator
+chef-webui
+cons
+EOM
+ end
+ end
+end
diff --git a/spec/integration/knife/client_create_spec.rb b/spec/integration/knife/client_create_spec.rb
new file mode 100644
index 0000000000..10172833c8
--- /dev/null
+++ b/spec/integration/knife/client_create_spec.rb
@@ -0,0 +1,69 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "openssl"
+
+describe "knife client create", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let(:out) { "Created client[bah]\n" }
+
+ when_the_chef_server "is empty" do
+ it "creates a new client" do
+ knife("client create -k bah").should_succeed stderr: out
+ end
+
+ it "creates a new validator client" do
+ knife("client create -k --validator bah").should_succeed stderr: out
+ knife("client show bah").should_succeed <<EOM
+admin: false
+chef_type: client
+name: bah
+validator: true
+EOM
+ end
+
+ it "refuses to add an existing client" do
+ pending "Knife client create must not blindly overwrite an existing client"
+ knife("client create -k bah").should_succeed stderr: out
+ expect { knife("client create -k bah") }.to raise_error(Net::HTTPServerException)
+ end
+
+ it "saves the private key to a file" do
+ Dir.mktmpdir do |tgt|
+ knife("client create -f #{tgt}/bah.pem bah").should_succeed stderr: out
+ expect(File).to exist("#{tgt}/bah.pem")
+ end
+ end
+
+ it "reads the public key from a file" do
+ Dir.mktmpdir do |tgt|
+ key = OpenSSL::PKey::RSA.generate(1024)
+ File.open("#{tgt}/public.pem", "w") { |pub| pub.write(key.public_key.to_pem) }
+ knife("client create -p #{tgt}/public.pem bah").should_succeed stderr: out
+ end
+ end
+
+ it "refuses to run if conflicting options are passed" do
+ knife("client create -p public.pem --prevent-keygen blah").should_fail stderr: "FATAL: You cannot pass --public-key and --prevent-keygen\n", stdout: /^USAGE.*/
+ end
+ end
+end
diff --git a/spec/integration/knife/client_delete_spec.rb b/spec/integration/knife/client_delete_spec.rb
new file mode 100644
index 0000000000..d135dd0a5b
--- /dev/null
+++ b/spec/integration/knife/client_delete_spec.rb
@@ -0,0 +1,63 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife client delete", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some clients" do
+ before do
+ client "cons", {}
+ client "car", {}
+ client "car-validator", { validator: true }
+ client "cdr", {}
+ client "cat", {}
+ end
+
+ it "deletes a client" do
+ knife("client delete car", input: "Y").should_succeed <<EOM
+Do you really want to delete car? (Y/N) Deleted client[car]
+EOM
+
+ knife("client list").should_succeed <<EOM
+car-validator
+cat
+cdr
+chef-validator
+chef-webui
+cons
+EOM
+ end
+
+ it "refuses to delete a validator normally" do
+ knife("client delete car-validator", input: "Y").should_fail exit_code: 2, stdout: "Do you really want to delete car-validator? (Y/N) ", stderr: <<EOM
+FATAL: You must specify --delete-validators to delete the validator client car-validator
+EOM
+ end
+
+ it "deletes a validator correctly" do
+ knife("client delete car-validator -D", input: "Y").should_succeed <<EOM
+Do you really want to delete car-validator? (Y/N) Deleted client[car-validator]
+EOM
+ end
+
+ end
+end
diff --git a/spec/integration/knife/client_key_create_spec.rb b/spec/integration/knife/client_key_create_spec.rb
new file mode 100644
index 0000000000..b588afbe50
--- /dev/null
+++ b/spec/integration/knife/client_key_create_spec.rb
@@ -0,0 +1,65 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "openssl"
+
+describe "knife client key create", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let(:out) { "Created key: new" }
+
+ when_the_chef_server "has a client" do
+ before do
+ client "bah", {}
+ end
+
+ it "creates a new client key" do
+ knife("client key create -k new bah").should_succeed stderr: /^#{out}/, stdout: /.*BEGIN RSA PRIVATE KEY/
+ end
+
+ it "creates a new client key with an expiration date" do
+ date = "2017-12-31T23:59:59Z"
+ knife("client key create -k new -e #{date} bah").should_succeed stderr: /^#{out}/, stdout: /.*BEGIN RSA PRIVATE KEY/
+ knife("client key show bah new").should_succeed /expiration_date:.*#{date}/
+ end
+
+ it "refuses to add an already existing key" do
+ knife("client key create -k new bah")
+ expect { knife("client key create -k new bah") }.to raise_error(Net::HTTPServerException)
+ end
+
+ it "saves the private key to a file" do
+ Dir.mktmpdir do |tgt|
+ knife("client key create -f #{tgt}/bah.pem -k new bah").should_succeed stderr: /^#{out}/
+ expect(File).to exist("#{tgt}/bah.pem")
+ end
+ end
+
+ it "reads the public key from a file" do
+ Dir.mktmpdir do |tgt|
+ key = OpenSSL::PKey::RSA.generate(1024)
+ File.open("#{tgt}/public.pem", "w") { |pub| pub.write(key.public_key.to_pem) }
+ knife("client key create -p #{tgt}/public.pem -k new bah").should_succeed stderr: /^#{out}/
+ end
+ end
+
+ end
+end
diff --git a/spec/integration/knife/client_key_delete_spec.rb b/spec/integration/knife/client_key_delete_spec.rb
new file mode 100644
index 0000000000..d5827aa545
--- /dev/null
+++ b/spec/integration/knife/client_key_delete_spec.rb
@@ -0,0 +1,42 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife client key delete", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has a client" do
+ before do
+ client "car", {}
+ end
+
+ it "deletes a client" do
+ out = "Do you really want to delete the key named new for the client named car? (Y/N) "
+ knife("client key create -k new car")
+ knife("client key delete car new", input: "Y").should_succeed stdout: out, stderr: <<EOM
+Deleted key named new for the client named car
+EOM
+
+ knife("client key list car").should_succeed ""
+ end
+
+ end
+end
diff --git a/spec/integration/knife/client_key_list_spec.rb b/spec/integration/knife/client_key_list_spec.rb
new file mode 100644
index 0000000000..de9894622e
--- /dev/null
+++ b/spec/integration/knife/client_key_list_spec.rb
@@ -0,0 +1,60 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "date"
+
+describe "knife client key list", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let(:now) { DateTime.now }
+ let(:last_month) { (now << 1).strftime("%FT%TZ") }
+ let(:next_month) { (now >> 1).strftime("%FT%TZ") }
+
+ when_the_chef_server "has a client" do
+ before do
+ client "cons", {}
+ knife("client key create cons -k new")
+ knife("client key create cons -k next_month -e #{next_month}")
+ knife("client key create cons -k expired -e #{last_month}")
+ end
+
+ it "lists the keys for a client" do
+ knife("client key list cons").should_succeed "expired\nnew\nnext_month\n"
+ end
+
+ it "shows detailed output" do
+ knife("client key list -w cons").should_succeed <<EOM
+expired: http://127.0.0.1:8900/clients/cons/keys/expired (expired)
+new: http://127.0.0.1:8900/clients/cons/keys/new
+next_month: http://127.0.0.1:8900/clients/cons/keys/next_month
+EOM
+ end
+
+ it "lists the expired keys for a client" do
+ knife("client key list -e cons").should_succeed "expired\n"
+ end
+
+ it "lists the unexpired keys for a client" do
+ knife("client key list -n cons").should_succeed "new\nnext_month\n"
+ end
+
+ end
+end
diff --git a/spec/integration/knife/client_key_show_spec.rb b/spec/integration/knife/client_key_show_spec.rb
new file mode 100644
index 0000000000..e96ff3b6fe
--- /dev/null
+++ b/spec/integration/knife/client_key_show_spec.rb
@@ -0,0 +1,44 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "date"
+
+describe "knife client key show", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let(:now) { DateTime.now }
+ let(:last_month) { (now << 1).strftime("%FT%TZ") }
+ let(:next_month) { (now >> 1).strftime("%FT%TZ") }
+
+ when_the_chef_server "has a client" do
+ before do
+ client "cons", {}
+ knife("client key create cons -k new")
+ knife("client key create cons -k next_month -e #{next_month}")
+ knife("client key create cons -k expired -e #{last_month}")
+ end
+
+ it "shows a key for a client" do
+ knife("client key show cons new").should_succeed stdout: /.*name:.*new/
+ end
+
+ end
+end
diff --git a/spec/integration/knife/client_list_spec.rb b/spec/integration/knife/client_list_spec.rb
new file mode 100644
index 0000000000..4159df73f1
--- /dev/null
+++ b/spec/integration/knife/client_list_spec.rb
@@ -0,0 +1,48 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife client list", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some clients" do
+ before do
+ client "cons", {}
+ client "car", {}
+ client "car-validator", { validator: true }
+ client "cdr", {}
+ client "cat", {}
+ end
+
+ it "lists the clients" do
+ knife("client list").should_succeed <<EOM
+car
+car-validator
+cat
+cdr
+chef-validator
+chef-webui
+cons
+EOM
+ end
+
+ end
+end
diff --git a/spec/integration/knife/client_show_spec.rb b/spec/integration/knife/client_show_spec.rb
new file mode 100644
index 0000000000..23ac204d77
--- /dev/null
+++ b/spec/integration/knife/client_show_spec.rb
@@ -0,0 +1,36 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife client show", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has a client" do
+ before do
+ client "cons", {}
+ end
+
+ it "shows a client" do
+ knife("client show cons").should_succeed stdout: /.*name:.*cons/
+ end
+
+ end
+end
diff --git a/spec/integration/knife/cookbook_bulk_delete_spec.rb b/spec/integration/knife/cookbook_bulk_delete_spec.rb
new file mode 100644
index 0000000000..4740813ce1
--- /dev/null
+++ b/spec/integration/knife/cookbook_bulk_delete_spec.rb
@@ -0,0 +1,64 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/cookbook_bulk_delete"
+
+describe "knife cookbook bulk delete", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has a cookbook" do
+ before do
+ cookbook "foo", "1.0.0"
+ cookbook "foo", "0.6.5"
+ cookbook "fox", "0.6.0"
+ cookbook "fox", "0.6.5"
+ cookbook "fax", "0.6.0"
+ cookbook "zfa", "0.6.5"
+ end
+
+ # rubocop:disable Style/TrailingWhitespace
+ it "knife cookbook bulk delete deletes all matching cookbooks" do
+ stdout = <<EOM
+All versions of the following cookbooks will be deleted:
+
+foo fox
+
+Do you really want to delete these cookbooks? (Y/N)
+EOM
+
+ stderr = <<EOM
+Deleted cookbook foo [1.0.0]
+Deleted cookbook foo [0.6.5]
+Deleted cookbook fox [0.6.5]
+Deleted cookbook fox [0.6.0]
+EOM
+
+ knife("cookbook bulk delete ^fo.*", input: "Y").should_succeed(stderr: stderr, stdout: stdout)
+
+ knife("cookbook list -a").should_succeed <<EOM
+fax 0.6.0
+zfa 0.6.5
+EOM
+ end
+ # rubocop:enable Style/TrailingWhitespace
+
+ end
+end
diff --git a/spec/integration/knife/cookbook_download_spec.rb b/spec/integration/knife/cookbook_download_spec.rb
new file mode 100644
index 0000000000..2fbffb9dea
--- /dev/null
+++ b/spec/integration/knife/cookbook_download_spec.rb
@@ -0,0 +1,95 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/cookbook_download"
+require "tmpdir"
+
+describe "knife cookbook download", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let(:tmpdir) { Dir.mktmpdir }
+
+ when_the_chef_server "has only one cookbook" do
+ before do
+ cookbook "x", "1.0.1"
+ end
+
+ it "knife cookbook download downloads the latest version" do
+ knife("cookbook download -d #{tmpdir} x").should_succeed stderr: <<EOM
+Downloading x cookbook version 1.0.1
+Downloading resources
+Downloading providers
+Downloading recipes
+Downloading definitions
+Downloading libraries
+Downloading attributes
+Downloading files
+Downloading templates
+Downloading root_files
+Cookbook downloaded to #{tmpdir}/x-1.0.1
+EOM
+ end
+
+ it "knife cookbook download with a version downloads the specified version" do
+ knife("cookbook download -d #{tmpdir} x 1.0.1").should_succeed stderr: <<EOM
+Downloading x cookbook version 1.0.1
+Downloading resources
+Downloading providers
+Downloading recipes
+Downloading definitions
+Downloading libraries
+Downloading attributes
+Downloading files
+Downloading templates
+Downloading root_files
+Cookbook downloaded to #{tmpdir}/x-1.0.1
+EOM
+ end
+
+ it "knife cookbook download with an unknown version raises an error" do
+ expect { knife("cookbook download -d #{tmpdir} x 1.0.0") }.to raise_error(Net::HTTPServerException)
+ end
+ end
+
+ when_the_chef_server "has multiple cookbook versions" do
+ before do
+ cookbook "x", "1.0.1"
+ cookbook "x", "1.0.0"
+ end
+
+ it "knife cookbook download with no version prompts" do
+ knife("cookbook download -d #{tmpdir} x", input: "2\n").should_succeed(stderr: <<EOM, stdout: "Which version do you want to download?\n1. x 1.0.0\n2. x 1.0.1\n\n"
+Downloading x cookbook version 1.0.1
+Downloading resources
+Downloading providers
+Downloading recipes
+Downloading definitions
+Downloading libraries
+Downloading attributes
+Downloading files
+Downloading templates
+Downloading root_files
+Cookbook downloaded to #{tmpdir}/x-1.0.1
+EOM
+)
+ end
+ end
+end
diff --git a/spec/integration/knife/cookbook_list_spec.rb b/spec/integration/knife/cookbook_list_spec.rb
new file mode 100644
index 0000000000..65578696f2
--- /dev/null
+++ b/spec/integration/knife/cookbook_list_spec.rb
@@ -0,0 +1,54 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/cookbook_list"
+
+describe "knife cookbook list", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has a cookbook" do
+ before do
+ cookbook "x", "1.0.0"
+ cookbook "x", "0.6.5"
+ cookbook "x", "0.6.0"
+ cookbook "y", "0.6.5"
+ cookbook "y", "0.6.0"
+ cookbook "z", "0.6.5"
+ end
+
+ it "knife cookbook list shows all the cookbooks" do
+ knife("cookbook list").should_succeed <<EOM
+x 1.0.0
+y 0.6.5
+z 0.6.5
+EOM
+ end
+
+ it "knife cookbook list -a shows all the versions of all the cookbooks" do
+ knife("cookbook list -a").should_succeed <<EOM
+x 1.0.0 0.6.5 0.6.0
+y 0.6.5 0.6.0
+z 0.6.5
+EOM
+ end
+
+ end
+end
diff --git a/spec/integration/knife/cookbook_show_spec.rb b/spec/integration/knife/cookbook_show_spec.rb
new file mode 100644
index 0000000000..c001d66b97
--- /dev/null
+++ b/spec/integration/knife/cookbook_show_spec.rb
@@ -0,0 +1,159 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/cookbook_show"
+
+describe "knife cookbook show", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has a cookbook" do
+ before do
+ cookbook "x", "1.0.0", { "recipes" => { "default.rb" => "file 'n'", "x.rb" => "" } }
+ cookbook "x", "0.6.5"
+ end
+
+ it "knife cookbook show x shows all the versions" do
+ knife("cookbook show x").should_succeed "x 1.0.0 0.6.5\n"
+ end
+
+ # rubocop:disable Style/TrailingWhitespace
+ it "knife cookbook show x 1.0.0 shows the correct version" do
+ knife("cookbook show x 1.0.0").should_succeed <<EOM
+attributes:
+chef_type: cookbook_version
+cookbook_name: x
+definitions:
+files:
+frozen?: false
+json_class: Chef::CookbookVersion
+libraries:
+metadata:
+ attributes:
+ chef_versions:
+ conflicting:
+ dependencies:
+ description:
+ gems:
+ groupings:
+ issues_url:
+ license: All rights reserved
+ long_description:
+ maintainer:
+ maintainer_email:
+ name: x
+ ohai_versions:
+ platforms:
+ privacy: false
+ providing:
+ recipes:
+ recommendations:
+ replacing:
+ source_url:
+ suggestions:
+ version: 1.0.0
+name: x-1.0.0
+providers:
+recipes:
+ checksum: 4631b34cf58de10c5ef1304889941b2e
+ name: default.rb
+ path: recipes/default.rb
+ specificity: default
+ url: http://127.0.0.1:8900/file_store/checksums/4631b34cf58de10c5ef1304889941b2e
+
+ checksum: d41d8cd98f00b204e9800998ecf8427e
+ name: x.rb
+ path: recipes/x.rb
+ specificity: default
+ url: http://127.0.0.1:8900/file_store/checksums/d41d8cd98f00b204e9800998ecf8427e
+resources:
+root_files:
+ checksum: 8226671f751ba102dea6a6b6bd32fa8d
+ name: metadata.rb
+ path: metadata.rb
+ specificity: default
+ url: http://127.0.0.1:8900/file_store/checksums/8226671f751ba102dea6a6b6bd32fa8d
+templates:
+version: 1.0.0
+EOM
+ end
+
+ it "knife cookbook show x 1.0.0 metadata shows the metadata" do
+ knife("cookbook show x 1.0.0 metadata").should_succeed <<EOM
+attributes:
+chef_versions:
+conflicting:
+dependencies:
+description:
+gems:
+groupings:
+issues_url:
+license: All rights reserved
+long_description:
+maintainer:
+maintainer_email:
+name: x
+ohai_versions:
+platforms:
+privacy: false
+providing:
+recipes:
+recommendations:
+replacing:
+source_url:
+suggestions:
+version: 1.0.0
+EOM
+ end
+
+ it "knife cookbook show x 1.0.0 recipes shows all the recipes" do
+ knife("cookbook show x 1.0.0 recipes").should_succeed <<EOM
+checksum: 4631b34cf58de10c5ef1304889941b2e
+name: default.rb
+path: recipes/default.rb
+specificity: default
+url: http://127.0.0.1:8900/file_store/checksums/4631b34cf58de10c5ef1304889941b2e
+
+checksum: d41d8cd98f00b204e9800998ecf8427e
+name: x.rb
+path: recipes/x.rb
+specificity: default
+url: http://127.0.0.1:8900/file_store/checksums/d41d8cd98f00b204e9800998ecf8427e
+EOM
+ end
+ # rubocop:enable Style/TrailingWhitespace
+
+ it "knife cookbook show x 1.0.0 recipes default.rb shows the default recipe" do
+ knife("cookbook show x 1.0.0 recipes default.rb").should_succeed "file 'n'\n"
+ end
+
+ it "knife cookbook show with a non-existent file displays an error" do
+ expect { knife("cookbook show x 1.0.0 recipes moose.rb") }.to raise_error(Chef::Exceptions::FileNotFound)
+ end
+
+ it "knife cookbook show with a non-existent version displays an error" do
+ expect { knife("cookbook show x 1.0.1") }.to raise_error(Net::HTTPServerException)
+ end
+
+ it "knife cookbook show with a non-existent cookbook displays an error" do
+ expect { knife("cookbook show y") }.to raise_error(Net::HTTPServerException)
+ end
+ end
+end
diff --git a/spec/integration/knife/cookbook_upload_spec.rb b/spec/integration/knife/cookbook_upload_spec.rb
new file mode 100644
index 0000000000..a0de725603
--- /dev/null
+++ b/spec/integration/knife/cookbook_upload_spec.rb
@@ -0,0 +1,90 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/cookbook_upload"
+
+describe "knife cookbook upload", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let (:cb_dir) { "#{@repository_dir}/cookbooks" }
+
+ when_the_chef_server "is empty" do
+ when_the_repository "has a cookbook" do
+ before do
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+ end
+
+ it "knife cookbook upload uploads the cookbook" do
+ knife("cookbook upload x -o #{cb_dir}").should_succeed stderr: <<EOM
+Uploading x [1.0.0]
+Uploaded 1 cookbook.
+EOM
+ end
+
+ it "knife cookbook upload --freeze uploads and freezes the cookbook" do
+ knife("cookbook upload x -o #{cb_dir} --freeze").should_succeed stderr: <<EOM
+Uploading x [1.0.0]
+Uploaded 1 cookbook.
+EOM
+ # Modify the file, attempt to reupload
+ file "cookbooks/x/metadata.rb", 'name "x"; version "1.0.0"#different'
+ knife("cookbook upload x -o #{cb_dir} --freeze").should_fail stderr: <<EOM
+Uploading x [1.0.0]
+ERROR: Version 1.0.0 of cookbook x is frozen. Use --force to override.
+WARNING: Not updating version constraints for x in the environment as the cookbook is frozen.
+ERROR: Failed to upload 1 cookbook.
+EOM
+ end
+ end
+
+ when_the_repository "has a cookbook that depends on another cookbook" do
+ before do
+ file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0", "\ndepends 'y'")
+ file "cookbooks/y/metadata.rb", cb_metadata("y", "1.0.0")
+ end
+
+ it "knife cookbook upload --include-dependencies uploads both cookbooks" do
+ knife("cookbook upload --include-dependencies x -o #{cb_dir}").should_succeed stderr: <<EOM
+Uploading x [1.0.0]
+Uploading y [1.0.0]
+Uploaded 2 cookbooks.
+EOM
+ end
+
+ it "knife cookbook upload fails due to missing dependencies" do
+ knife("cookbook upload x -o #{cb_dir}").should_fail stderr: <<EOM
+Uploading x [1.0.0]
+ERROR: Cookbook x depends on cookbooks which are not currently
+ERROR: being uploaded and cannot be found on the server.
+ERROR: The missing cookbook(s) are: 'y' version '>= 0.0.0'
+EOM
+ end
+
+ it "knife cookbook upload -a uploads both cookbooks" do
+ knife("cookbook upload -a -o #{cb_dir}").should_succeed stderr: <<EOM
+Uploading x [1.0.0]
+Uploading y [1.0.0]
+Uploaded all cookbooks.
+EOM
+ end
+ end
+ end
+end
diff --git a/spec/integration/knife/data_bag_create_spec.rb b/spec/integration/knife/data_bag_create_spec.rb
new file mode 100644
index 0000000000..0a07792dbc
--- /dev/null
+++ b/spec/integration/knife/data_bag_create_spec.rb
@@ -0,0 +1,58 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/data_bag_create"
+
+describe "knife data bag create", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let(:err) { "Created data_bag[foo]\n" }
+ let(:out) { "Created data_bag_item[bar]\n" }
+ let(:exists) { "Data bag foo already exists\n" }
+
+ when_the_chef_server "is empty" do
+ it "creates a new data bag" do
+ knife("data bag create foo").should_succeed stderr: err
+ 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
+
+ it "refuses to add an existing data bag" do
+ knife("data bag create foo").should_succeed stderr: err
+ knife("data bag create foo").should_succeed stderr: exists
+ 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
+ end
+end
diff --git a/spec/integration/knife/data_bag_delete_spec.rb b/spec/integration/knife/data_bag_delete_spec.rb
new file mode 100644
index 0000000000..96345b0d2b
--- /dev/null
+++ b/spec/integration/knife/data_bag_delete_spec.rb
@@ -0,0 +1,58 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/data_bag_delete"
+
+describe "knife data bag delete", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some data bags" do
+ before do
+ data_bag "x", {}
+ data_bag "canteloupe", {}
+ data_bag "rocket", { "falcon9" => { heavy: "true" }, "atlas" => {}, "ariane" => {} }
+ end
+
+ it "with an empty data bag" do
+ knife("data bag delete canteloupe", input: "y").should_succeed <<EOM
+Do you really want to delete canteloupe? (Y/N) Deleted data_bag[canteloupe]
+EOM
+ end
+
+ it "with a bag with some items" do
+ knife("data bag delete rocket", input: "y").should_succeed <<EOM
+Do you really want to delete rocket? (Y/N) Deleted data_bag[rocket]
+EOM
+ end
+
+ it "with a single item" do
+ knife("data bag delete rocket falcon9", input: "y").should_succeed <<EOM
+Do you really want to delete falcon9? (Y/N) Deleted data_bag_item[falcon9]
+EOM
+ end
+
+ it "choosing not to delete" do
+ knife("data bag delete rocket falcon9", input: "n").should_succeed <<EOM, exit_code: 3
+Do you really want to delete falcon9? (Y/N) You said no, so I'm done here.
+EOM
+ end
+ end
+end
diff --git a/spec/integration/knife/data_bag_from_file_spec.rb b/spec/integration/knife/data_bag_from_file_spec.rb
new file mode 100644
index 0000000000..ca8f743487
--- /dev/null
+++ b/spec/integration/knife/data_bag_from_file_spec.rb
@@ -0,0 +1,115 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife data bag from file", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let (:db_dir) { "#{@repository_dir}/data_bags" }
+
+ when_the_chef_server "has an empty data bag" do
+ before do
+ data_bag "foo", {}
+ data_bag "bar", {}
+ end
+
+ when_the_repository "has some data bag items" do
+ before do
+ file "data_bags/foo/bar.json", { "id" => "bar", "foo" => "bar " }
+ file "data_bags/foo/bzr.json", { "id" => "bzr", "foo" => "bar " }
+ file "data_bags/foo/cat.json", { "id" => "cat", "foo" => "bar " }
+ file "data_bags/foo/dog.json", { "id" => "dog", "foo" => "bar " }
+ file "data_bags/foo/encrypted.json", <<EOM
+{
+ "id": "encrypted",
+ "password": {
+ "encrypted_data": "H6ab5RY9a9JAkS8A0RCMspXtOJh0ai8cNeA4Q3gLO8s=\\n",
+ "iv": "uWKKKxrJgtELlGMCOLJdkA==\\n",
+ "version": 1,
+ "cipher": "aes-256-cbc"
+ }
+}
+EOM
+ file "data_bags/bar/round_trip.json", <<EOM
+{
+ "name": "data_bag_item_bar_round_trip",
+ "json_class": "Chef::DataBagItem",
+ "chef_type": "data_bag_item",
+ "data_bag": "bar",
+ "raw_data": {
+ "id": "round_trip",
+ "root_password": {
+ "encrypted_data": "noDOsTpsTAZlTU5sprhmYZzUDfr8du7hH/zRDOjRAmoTJHTZyfYoR221EOOW\\nXJ1D\\n",
+ "iv": "Bnqhfy6n0Hx1wCe9pxHLoA==\\n",
+ "version": 1,
+ "cipher": "aes-256-cbc"
+ },
+ "admin_password": {
+ "encrypted_data": "TcC7dU1gx6OnE5Ab4i/k42UEf0Nnr7cAyuTHId/LNjNOwpNf7XZc27DQSjuy\\nHPlt\\n",
+ "iv": "+TAWJuPWCI2+WB8lGJAyvw==\\n",
+ "version": 1,
+ "cipher": "aes-256-cbc"
+ }
+ }
+}
+EOM
+ end
+
+ it "uploads a single file" do
+ knife("data bag from file foo #{db_dir}/foo/bar.json").should_succeed stderr: <<EOM
+Updated data_bag_item[foo::bar]
+EOM
+ end
+
+ it "uploads a single encrypted file" do
+ knife("data bag from file foo #{db_dir}/foo/encrypted.json").should_succeed stderr: <<EOM
+Updated data_bag_item[foo::encrypted]
+EOM
+ end
+
+ it "uploads a file in chef's internal format" do
+ pending "chef/chef#4815"
+ knife("data bag from file bar #{db_dir}/bar/round_trip.json").should_succeed stderr: <<EOM
+Updated data_bag_item[bar::round_trip]
+EOM
+ end
+
+ it "uploads many files" do
+ knife("data bag from file foo #{db_dir}/foo/bar.json #{db_dir}/foo/bzr.json").should_succeed stderr: <<EOM
+Updated data_bag_item[foo::bar]
+Updated data_bag_item[foo::bzr]
+EOM
+ end
+
+ it "uploads a whole directory" do
+ knife("data bag from file foo #{db_dir}/foo")
+ knife("data bag show foo").should_succeed <<EOM
+bar
+bzr
+cat
+dog
+encrypted
+EOM
+ end
+
+ end
+ end
+end
diff --git a/spec/integration/knife/data_bag_list_spec.rb b/spec/integration/knife/data_bag_list_spec.rb
new file mode 100644
index 0000000000..7db9638660
--- /dev/null
+++ b/spec/integration/knife/data_bag_list_spec.rb
@@ -0,0 +1,43 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/data_bag_list"
+
+describe "knife data bag list", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some data bags" do
+ before do
+ data_bag "x", {}
+ data_bag "canteloupe", {}
+ data_bag "rocket", {}
+ end
+
+ it "knife data bag list shows all the cookbooks" do
+ knife("data bag list").should_succeed <<EOM
+canteloupe
+rocket
+x
+EOM
+ end
+
+ end
+end
diff --git a/spec/integration/knife/data_bag_show_spec.rb b/spec/integration/knife/data_bag_show_spec.rb
new file mode 100644
index 0000000000..22381adb9e
--- /dev/null
+++ b/spec/integration/knife/data_bag_show_spec.rb
@@ -0,0 +1,53 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/data_bag_show"
+
+describe "knife data bag show", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some data bags" do
+ before do
+ data_bag "x", {}
+ data_bag "canteloupe", {}
+ data_bag "rocket", { "falcon9" => { heavy: "true" }, "atlas" => {}, "ariane" => {} }
+ end
+
+ it "with an empty data bag" do
+ knife("data bag show canteloupe").should_succeed "\n"
+ end
+
+ it "with a bag with some items" do
+ knife("data bag show rocket").should_succeed <<EOM
+ariane
+atlas
+falcon9
+EOM
+ end
+
+ it "with a single item" do
+ knife("data bag show rocket falcon9").should_succeed <<EOM, stderr: "WARNING: Unencrypted data bag detected, ignoring any provided secret options.\n"
+heavy: true
+id: falcon9
+EOM
+ end
+ end
+end
diff --git a/spec/integration/knife/diff_spec.rb b/spec/integration/knife/diff_spec.rb
index b7d2f4d1c3..b3bd23f48e 100644
--- a/spec/integration/knife/diff_spec.rb
+++ b/spec/integration/knife/diff_spec.rb
@@ -72,7 +72,7 @@ EOM
file "data_bags/x/y.json", {}
file "environments/_default.json", { "description" => "The default Chef environment" }
file "environments/x.json", {}
- file "nodes/x.json", {}
+ file "nodes/x.json", { "normal" => { "tags" => [] } }
file "roles/x.json", {}
file "users/admin.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
file "users/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
@@ -366,7 +366,7 @@ EOM
file "data_bags/x/y.json", {}
file "environments/_default.json", { "description" => "The default Chef environment" }
file "environments/x.json", {}
- file "nodes/x.json", {}
+ file "nodes/x.json", { "normal" => { "tags" => [] } }
file "roles/x.json", {}
file "users/admin.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
file "users/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
diff --git a/spec/integration/knife/download_spec.rb b/spec/integration/knife/download_spec.rb
index a924226ea2..be0fc9d708 100644
--- a/spec/integration/knife/download_spec.rb
+++ b/spec/integration/knife/download_spec.rb
@@ -76,7 +76,7 @@ EOM
file "data_bags/x/y.json", {}
file "environments/_default.json", { "description" => "The default Chef environment" }
file "environments/x.json", {}
- file "nodes/x.json", {}
+ file "nodes/x.json", { "normal" => { "tags" => [] } }
file "roles/x.json", {}
file "users/admin.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
file "users/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
@@ -645,7 +645,7 @@ EOM
file "data_bags/x/y.json", {}
file "environments/_default.json", { "description" => "The default Chef environment" }
file "environments/x.json", {}
- file "nodes/x.json", {}
+ file "nodes/x.json", { "normal" => { "tags" => [] } }
file "roles/x.json", {}
file "users/admin.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
file "users/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
@@ -1271,7 +1271,7 @@ EOM
file "groups/x.json", {}
file "invitations.json", [ "foo" ]
file "members.json", [ "bar" ]
- file "nodes/x.json", {}
+ file "nodes/x.json", { "normal" => { "tags" => [] } }
file "org.json", { "full_name" => "Something" }
file "policies/x-1.0.0.json", {}
file "policies/blah-1.0.0.json", {}
@@ -1295,7 +1295,7 @@ EOM
file "environments/x.json", { "description" => "foo" }
file "groups/x.json", { "description" => "foo" }
file "groups/x.json", { "groups" => [ "admin" ] }
- file "nodes/x.json", { "run_list" => [ "blah" ] }
+ file "nodes/x.json", { "normal" => { "tags" => [] }, "run_list" => [ "blah" ] }
file "org.json", { "full_name" => "Something Else " }
file "policies/x-1.0.0.json", { "run_list" => [ "blah" ] }
file "policy_groups/x.json", {
diff --git a/spec/integration/knife/environment_compare_spec.rb b/spec/integration/knife/environment_compare_spec.rb
new file mode 100644
index 0000000000..3259b27d1b
--- /dev/null
+++ b/spec/integration/knife/environment_compare_spec.rb
@@ -0,0 +1,74 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife environment compare", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some environments" do
+ before do
+ cookbook "blah", "1.0.1"
+ cookbook "blah", "1.1.1"
+ cookbook "krad", "1.1.1"
+ environment "x", {
+ "cookbook_versions" => {
+ "blah" => "= 1.0.0",
+ "krad" => ">= 1.0.0",
+ },
+ }
+ environment "y", {
+ "cookbook_versions" => {
+ "blah" => "= 1.1.0",
+ "krad" => ">= 1.0.0",
+ },
+ }
+ end
+
+ # rubocop:disable Style/TrailingWhitespace
+ it "displays the cookbooks for a single environment" do
+ knife("environment compare x").should_succeed <<EOM
+ x
+blah = 1.0.0
+krad >= 1.0.0
+
+EOM
+ end
+
+ it "compares the cookbooks for two environments" do
+ knife("environment compare x y").should_succeed <<EOM
+ x y
+blah = 1.0.0 = 1.1.0
+krad >= 1.0.0 >= 1.0.0
+
+EOM
+ end
+
+ it "compares the cookbooks for all environments" do
+ knife("environment compare --all").should_succeed <<EOM
+ x y
+blah = 1.0.0 = 1.1.0
+krad >= 1.0.0 >= 1.0.0
+
+EOM
+ end
+ # rubocop:enable Style/TrailingWhitespace
+ end
+end
diff --git a/spec/integration/knife/environment_create_spec.rb b/spec/integration/knife/environment_create_spec.rb
new file mode 100644
index 0000000000..03fd4e63f7
--- /dev/null
+++ b/spec/integration/knife/environment_create_spec.rb
@@ -0,0 +1,40 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife environment create", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let(:out) { "Created bah\n" }
+
+ when_the_chef_server "is empty" do
+ it "creates a new environment" do
+ knife("environment create bah").should_succeed out
+ end
+
+ it "refuses to add an existing environment" do
+ pending "Knife environment create must not blindly overwrite an existing environment"
+ knife("environment create bah").should_succeed out
+ expect { knife("environment create bah") }.to raise_error(Net::HTTPServerException)
+ end
+
+ end
+end
diff --git a/spec/integration/knife/environment_delete_spec.rb b/spec/integration/knife/environment_delete_spec.rb
new file mode 100644
index 0000000000..0f1fe5c4a8
--- /dev/null
+++ b/spec/integration/knife/environment_delete_spec.rb
@@ -0,0 +1,36 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife environment delete", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has an environment" do
+ before do
+ environment "y", {}
+ end
+
+ it "deletes an environment" do
+ knife("environment delete y", input: "y").should_succeed "Do you really want to delete y? (Y/N) Deleted y\n"
+ end
+
+ end
+end
diff --git a/spec/integration/knife/environment_from_file_spec.rb b/spec/integration/knife/environment_from_file_spec.rb
new file mode 100644
index 0000000000..67d4373939
--- /dev/null
+++ b/spec/integration/knife/environment_from_file_spec.rb
@@ -0,0 +1,115 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife environment from file", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ # include_context "default config options"
+
+ let (:env_dir) { "#{@repository_dir}/environments" }
+
+ when_the_chef_server "is empty" do
+ when_the_repository "has some environments" do
+ before do
+
+ file "environments/cons.json", <<EOM
+{
+ "name": "cons",
+ "description": "An environment",
+ "cookbook_versions": {
+
+ },
+ "json_class": "Chef::Environment",
+ "chef_type": "environment",
+ "default_attributes": {
+ "hola": "Amigos!"
+ },
+ "override_attributes": {
+
+ }
+}
+EOM
+
+ file "environments/car.json", <<EOM
+{
+ "name": "car",
+ "description": "An environment for list nodes",
+ "cookbook_versions": {
+
+ },
+ "json_class": "Chef::Environment",
+ "chef_type": "environment",
+ "default_attributes": {
+ "hola": "Amigos!"
+ },
+ "override_attributes": {
+
+ }
+}
+EOM
+
+ file "environments/cdr.json", <<EOM
+{
+ "name": "cdr",
+ "description": "An environment for last nodes",
+ "cookbook_versions": {
+
+ },
+ "json_class": "Chef::Environment",
+ "chef_type": "environment",
+ "default_attributes": {
+ "hola": "Amigos!"
+ },
+ "override_attributes": {
+
+ }
+}
+EOM
+
+ end
+
+ it "uploads a single file" do
+ knife("environment from file #{env_dir}/cons.json").should_succeed stderr: <<EOM
+Updated Environment cons
+EOM
+ end
+
+ it "uploads many files" do
+ knife("environment from file #{env_dir}/cons.json #{env_dir}/car.json #{env_dir}/cdr.json").should_succeed stderr: <<EOM
+Updated Environment cons
+Updated Environment car
+Updated Environment cdr
+EOM
+ end
+
+ it "uploads all environments in the repository" do
+ cwd(".")
+ knife("environment from file --all")
+ knife("environment list").should_succeed <<EOM
+_default
+car
+cdr
+cons
+EOM
+ end
+
+ end
+ end
+end
diff --git a/spec/integration/knife/environment_list_spec.rb b/spec/integration/knife/environment_list_spec.rb
new file mode 100644
index 0000000000..5e74453d1f
--- /dev/null
+++ b/spec/integration/knife/environment_list_spec.rb
@@ -0,0 +1,41 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife environment list", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some environments" do
+ before do
+ environment "b", {}
+ environment "y", {}
+ end
+
+ it "lists all the environments" do
+ knife("environment list").should_succeed <<EOM
+_default
+b
+y
+EOM
+ end
+
+ end
+end
diff --git a/spec/integration/knife/environment_show_spec.rb b/spec/integration/knife/environment_show_spec.rb
new file mode 100644
index 0000000000..e74bf6d05d
--- /dev/null
+++ b/spec/integration/knife/environment_show_spec.rb
@@ -0,0 +1,56 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife environment show", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some environments" do
+ before do
+ environment "b", {
+ "default_attributes" => { "foo" => "bar" },
+ }
+ end
+
+ # rubocop:disable Style/TrailingWhitespace
+ it "shows an environment" do
+ knife("environment show b").should_succeed <<EOM
+chef_type: environment
+cookbook_versions:
+default_attributes:
+ foo: bar
+description:
+json_class: Chef::Environment
+name: b
+override_attributes:
+EOM
+ end
+ # rubocop:enable Style/TrailingWhitespace
+
+ it "shows the requested attribute of an environment" do
+ pending "KnifeSupport doesn't appear to pass this through correctly"
+ knife("environment show b -a foo").should_succeed <<EOM
+b:
+ foo: bar
+EOM
+ end
+ end
+end
diff --git a/spec/integration/knife/node_bulk_delete_spec.rb b/spec/integration/knife/node_bulk_delete_spec.rb
new file mode 100644
index 0000000000..fa706cbd2b
--- /dev/null
+++ b/spec/integration/knife/node_bulk_delete_spec.rb
@@ -0,0 +1,51 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife node bulk delete", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some nodes" do
+ before do
+ node "cons", {}
+ node "car", {}
+ node "cdr", {}
+ node "cat", {}
+ end
+
+ it "deletes all matching nodes" do
+ knife("node bulk delete ^ca.*", input: "Y").should_succeed <<EOM
+The following nodes will be deleted:
+
+car cat
+
+Are you sure you want to delete these nodes? (Y/N) Deleted node car
+Deleted node cat
+EOM
+
+ knife("node list").should_succeed <<EOM
+cdr
+cons
+EOM
+ end
+ end
+
+end
diff --git a/spec/integration/knife/node_create_spec.rb b/spec/integration/knife/node_create_spec.rb
new file mode 100644
index 0000000000..93a2f9ce6f
--- /dev/null
+++ b/spec/integration/knife/node_create_spec.rb
@@ -0,0 +1,46 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "openssl"
+
+describe "knife node create", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let(:out) { "Created node[bah]\n" }
+
+ when_the_chef_server "is empty" do
+ it "creates a new node" do
+ knife("node create bah").should_succeed out
+ end
+
+ it "creates a new validator node" do
+ knife("node create bah").should_succeed out
+ knife("node show bah").should_succeed /Node Name: bah/
+ end
+
+ it "refuses to add an existing node" do
+ pending "Knife node create must not blindly overwrite an existing node"
+ knife("node create bah").should_succeed out
+ expect { knife("node create bah") }.to raise_error(Net::HTTPServerException)
+ end
+
+ end
+end
diff --git a/spec/integration/knife/node_delete_spec.rb b/spec/integration/knife/node_delete_spec.rb
new file mode 100644
index 0000000000..5d88af6d4f
--- /dev/null
+++ b/spec/integration/knife/node_delete_spec.rb
@@ -0,0 +1,47 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife node delete", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some nodes" do
+ before do
+ node "cons", {}
+ node "car", {}
+ node "cdr", {}
+ node "cat", {}
+ end
+
+ it "deletes a node" do
+ knife("node delete car", input: "Y").should_succeed <<EOM
+Do you really want to delete car? (Y/N) Deleted node[car]
+EOM
+
+ knife("node list").should_succeed <<EOM
+cat
+cdr
+cons
+EOM
+ end
+
+ end
+end
diff --git a/spec/integration/knife/node_environment_set_spec.rb b/spec/integration/knife/node_environment_set_spec.rb
new file mode 100644
index 0000000000..6dadecf76a
--- /dev/null
+++ b/spec/integration/knife/node_environment_set_spec.rb
@@ -0,0 +1,42 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife node environment set", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has a node and an environment" do
+ before do
+ node "cons", {}
+ environment "lisp", {}
+ end
+
+ it "sets an environment on a node" do
+ knife("node environment set cons lisp").should_succeed /chef_environment:.*lisp/
+ knife("node show cons -a chef_environment").should_succeed /Environment:.*lisp/
+ end
+
+ it "with no environment" do
+ knife("node environment set adam").should_fail stderr: "FATAL: You must specify a node name and an environment.\n",
+ stdout: /^USAGE: knife node environment set NODE ENVIRONMENT\n/
+ end
+ end
+end
diff --git a/spec/integration/knife/node_from_file_spec.rb b/spec/integration/knife/node_from_file_spec.rb
new file mode 100644
index 0000000000..3430967a21
--- /dev/null
+++ b/spec/integration/knife/node_from_file_spec.rb
@@ -0,0 +1,58 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife node from file", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ # include_context "default config options"
+
+ let (:node_dir) { "#{@repository_dir}/nodes" }
+
+ when_the_chef_server "is empty" do
+ when_the_repository "has some nodes" do
+ before do
+
+ file "nodes/cons.json", <<EOM
+{
+ "name": "cons",
+ "chef_environment": "_default",
+ "run_list": [
+ "recipe[cons]"
+]
+,
+ "normal": {
+ "tags": [
+
+ ]
+ }
+}
+EOM
+
+ end
+
+ it "uploads a single file" do
+ knife("node from file #{node_dir}/cons.json").should_succeed stderr: <<EOM
+Updated Node cons
+EOM
+ end
+
+ end
+ end
+end
diff --git a/spec/integration/knife/node_list_spec.rb b/spec/integration/knife/node_list_spec.rb
new file mode 100644
index 0000000000..76f5861e03
--- /dev/null
+++ b/spec/integration/knife/node_list_spec.rb
@@ -0,0 +1,44 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife node list", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some nodes" do
+ before do
+ node "cons", {}
+ node "car", {}
+ node "cdr", {}
+ node "cat", {}
+ end
+
+ it "lists all cookbooks" do
+ knife("node list").should_succeed <<EOM
+car
+cat
+cdr
+cons
+EOM
+ end
+
+ end
+end
diff --git a/spec/integration/knife/node_run_list_add_spec.rb b/spec/integration/knife/node_run_list_add_spec.rb
new file mode 100644
index 0000000000..87d08e1975
--- /dev/null
+++ b/spec/integration/knife/node_run_list_add_spec.rb
@@ -0,0 +1,53 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife node run list add", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has a node with no run_list" do
+ before do
+ node "cons", {}
+ end
+
+ it "sets the run list" do
+ knife("node run list add cons recipe[foo]").should_succeed /run_list:\s*recipe\[foo\]\n/
+ end
+ end
+
+ when_the_chef_server "has a node with a run_list" do
+ before do
+ node "cons", { run_list: ["recipe[bar]"] }
+ end
+
+ it "appends to the run list" do
+ knife("node run list add cons recipe[foo]").should_succeed /run_list:\n\s*recipe\[bar\]\n\s*recipe\[foo\]\n/m
+ end
+
+ it "adds to the run list before the specified item" do
+ knife("node run list add cons -b recipe[bar] recipe[foo]").should_succeed /run_list:\n\s*recipe\[foo\]\n\s*recipe\[bar\]\n/m
+ end
+
+ it "adds to the run list after the specified item" do
+ knife("node run list add cons -a recipe[bar] recipe[foo]").should_succeed /run_list:\n\s*recipe\[bar\]\n\s*recipe\[foo\]\n/m
+ end
+ end
+end
diff --git a/spec/integration/knife/node_run_list_remove_spec.rb b/spec/integration/knife/node_run_list_remove_spec.rb
new file mode 100644
index 0000000000..e85e3ed8e8
--- /dev/null
+++ b/spec/integration/knife/node_run_list_remove_spec.rb
@@ -0,0 +1,35 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife node run list remove", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has a node with a run_list" do
+ before do
+ node "cons", { run_list: ["recipe[bar]", "recipe[foo]"] }
+ end
+
+ it "removes the item from the run list" do
+ knife("node run list remove cons recipe[bar]").should_succeed /run_list:\s*recipe\[foo\]\n/m
+ end
+ end
+end
diff --git a/spec/integration/knife/node_run_list_set_spec.rb b/spec/integration/knife/node_run_list_set_spec.rb
new file mode 100644
index 0000000000..ec6b08fb97
--- /dev/null
+++ b/spec/integration/knife/node_run_list_set_spec.rb
@@ -0,0 +1,40 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife node run list set", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has a node with a run_list" do
+ before do
+ node "cons", { run_list: ["recipe[bar]", "recipe[foo]"] }
+ end
+
+ it "sets the run list" do
+ knife("node run list set cons recipe[bar]").should_succeed /run_list:\s*recipe\[bar\]\n/m
+ end
+
+ it "with no role or recipe" do
+ knife("node run list set cons").should_fail stderr: "FATAL: You must supply both a node name and a run list.\n",
+ stdout: /^USAGE: knife node run_list set NODE ENTRIES \(options\)/m
+ end
+ end
+end
diff --git a/spec/integration/knife/node_show_spec.rb b/spec/integration/knife/node_show_spec.rb
new file mode 100644
index 0000000000..dd890aed59
--- /dev/null
+++ b/spec/integration/knife/node_show_spec.rb
@@ -0,0 +1,35 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife node show", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has a node with a run_list" do
+ before do
+ node "cons", { run_list: ["recipe[bar]", "recipe[foo]"] }
+ end
+
+ it "shows the node" do
+ knife("node show cons").should_succeed /Run List:\s*recipe\[bar\], recipe\[foo\]\n/m
+ end
+ end
+end
diff --git a/spec/integration/knife/raw_spec.rb b/spec/integration/knife/raw_spec.rb
index 9078bf09a1..5e0d3a3d11 100644
--- a/spec/integration/knife/raw_spec.rb
+++ b/spec/integration/knife/raw_spec.rb
@@ -49,7 +49,9 @@ describe "knife raw", :workstation do
},
"normal": {
+ "tags": [
+ ]
},
"default": {
diff --git a/spec/integration/knife/role_bulk_delete_spec.rb b/spec/integration/knife/role_bulk_delete_spec.rb
new file mode 100644
index 0000000000..0e7ff941e2
--- /dev/null
+++ b/spec/integration/knife/role_bulk_delete_spec.rb
@@ -0,0 +1,51 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife role bulk delete", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some roles" do
+ before do
+ role "cons", {}
+ role "car", {}
+ role "cdr", {}
+ role "cat", {}
+ end
+
+ it "deletes all matching roles" do
+ knife("role bulk delete ^ca.*", input: "Y").should_succeed <<EOM
+The following roles will be deleted:
+
+car cat
+
+Are you sure you want to delete these roles? (Y/N) Deleted role car
+Deleted role cat
+EOM
+
+ knife("role list").should_succeed <<EOM
+cdr
+cons
+EOM
+ end
+
+ end
+end
diff --git a/spec/integration/knife/role_create_spec.rb b/spec/integration/knife/role_create_spec.rb
new file mode 100644
index 0000000000..941eaf5cb6
--- /dev/null
+++ b/spec/integration/knife/role_create_spec.rb
@@ -0,0 +1,40 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife role create", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ let(:out) { "Created role[bah]\n" }
+
+ when_the_chef_server "is empty" do
+ it "creates a new role" do
+ knife("role create bah").should_succeed out
+ end
+
+ it "refuses to add an existing role" do
+ pending "Knife role create must not blindly overwrite an existing role"
+ knife("role create bah").should_succeed out
+ expect { knife("role create bah") }.to raise_error(Net::HTTPServerException)
+ end
+
+ end
+end
diff --git a/spec/integration/knife/role_delete_spec.rb b/spec/integration/knife/role_delete_spec.rb
new file mode 100644
index 0000000000..9fbd3758b9
--- /dev/null
+++ b/spec/integration/knife/role_delete_spec.rb
@@ -0,0 +1,47 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife role delete", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some roles" do
+ before do
+ role "cons", {}
+ role "car", {}
+ role "cdr", {}
+ role "cat", {}
+ end
+
+ it "deletes a role" do
+ knife("role delete car", input: "Y").should_succeed <<EOM
+Do you really want to delete car? (Y/N) Deleted role[car]
+EOM
+
+ knife("role list").should_succeed <<EOM
+cat
+cdr
+cons
+EOM
+ end
+
+ end
+end
diff --git a/spec/integration/knife/role_from_file_spec.rb b/spec/integration/knife/role_from_file_spec.rb
new file mode 100644
index 0000000000..60caa3fa88
--- /dev/null
+++ b/spec/integration/knife/role_from_file_spec.rb
@@ -0,0 +1,95 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife role from file", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ # include_context "default config options"
+
+ let (:role_dir) { "#{@repository_dir}/roles" }
+
+ when_the_chef_server "is empty" do
+ when_the_repository "has some roles" do
+ before do
+
+ file "roles/cons.json", <<EOM
+{
+ "name": "cons",
+ "description": "An role",
+ "json_class": "Chef::role",
+ "chef_type": "role",
+ "default_attributes": {
+ "hola": "Amigos!"
+ },
+ "override_attributes": {
+
+ }
+}
+EOM
+
+ file "roles/car.json", <<EOM
+{
+ "name": "car",
+ "description": "A role for list nodes",
+ "json_class": "Chef::Role",
+ "chef_type": "role",
+ "default_attributes": {
+ "hola": "Amigos!"
+ },
+ "override_attributes": {
+
+ }
+}
+EOM
+
+ file "roles/cdr.json", <<EOM
+{
+ "name": "cdr",
+ "description": "A role for last nodes",
+ "json_class": "Chef::Role",
+ "chef_type": "role",
+ "default_attributes": {
+ "hola": "Amigos!"
+ },
+ "override_attributes": {
+
+ }
+}
+EOM
+
+ end
+
+ it "uploads a single file" do
+ knife("role from file #{role_dir}/cons.json").should_succeed stderr: <<EOM
+Updated Role cons
+EOM
+ end
+
+ it "uploads many files" do
+ knife("role from file #{role_dir}/cons.json #{role_dir}/car.json #{role_dir}/cdr.json").should_succeed stderr: <<EOM
+Updated Role cons
+Updated Role car
+Updated Role cdr
+EOM
+ end
+
+ end
+ end
+end
diff --git a/spec/integration/knife/role_list_spec.rb b/spec/integration/knife/role_list_spec.rb
new file mode 100644
index 0000000000..36dc76be4c
--- /dev/null
+++ b/spec/integration/knife/role_list_spec.rb
@@ -0,0 +1,44 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife role list", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some roles" do
+ before do
+ role "cons", {}
+ role "car", {}
+ role "cdr", {}
+ role "cat", {}
+ end
+
+ it "lists all cookbooks" do
+ knife("role list").should_succeed <<EOM
+car
+cat
+cdr
+cons
+EOM
+ end
+
+ end
+end
diff --git a/spec/integration/knife/role_show_spec.rb b/spec/integration/knife/role_show_spec.rb
new file mode 100644
index 0000000000..df2572447c
--- /dev/null
+++ b/spec/integration/knife/role_show_spec.rb
@@ -0,0 +1,50 @@
+#
+# Copyright:: Copyright 2013-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 "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+
+describe "knife role show", :workstation do
+ include IntegrationSupport
+ include KnifeSupport
+
+ include_context "default config options"
+
+ when_the_chef_server "has some roles" do
+ before do
+ role "cons", {}
+ role "car", {}
+ role "cdr", {}
+ role "cat", {}
+ end
+
+ # rubocop:disable Style/TrailingWhitespace
+ it "shows a cookbook" do
+ knife("role show cons").should_succeed <<EOM
+chef_type: role
+default_attributes:
+description:
+env_run_lists:
+json_class: Chef::Role
+name: cons
+override_attributes:
+run_list:
+EOM
+ end
+ # rubocop:enable Style/TrailingWhitespace
+
+ end
+end
diff --git a/spec/integration/knife/upload_spec.rb b/spec/integration/knife/upload_spec.rb
index 55c95b59b7..1db0ea8726 100644
--- a/spec/integration/knife/upload_spec.rb
+++ b/spec/integration/knife/upload_spec.rb
@@ -96,7 +96,7 @@ EOM
file "data_bags/x/y.json", {}
file "environments/_default.json", { "description" => "The default Chef environment" }
file "environments/x.json", {}
- file "nodes/x.json", {}
+ file "nodes/x.json", { "normal" => { "tags" => [] } }
file "roles/x.json", {}
file "users/admin.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
file "users/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
@@ -802,7 +802,7 @@ EOM
file "data_bags/x/y.json", {}
file "environments/_default.json", { "description" => "The default Chef environment" }
file "environments/x.json", {}
- file "nodes/x.json", {}
+ file "nodes/x.json", { "normal" => { "tags" => [] } }
file "roles/x.json", {}
file "users/admin.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
file "users/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
@@ -1313,7 +1313,7 @@ EOM
file "invitations.json", [ "foo" ]
file "members.json", [ "bar" ]
file "org.json", { "full_name" => "wootles" }
- file "nodes/x.json", {}
+ file "nodes/x.json", { "normal" => { "tags" => [] } }
file "policies/x-1.0.0.json", {}
file "policies/blah-1.0.0.json", {}
file "policy_groups/x.json", { "policies" => { "x" => { "revision_id" => "1.0.0" }, "blah" => { "revision_id" => "1.0.0" } } }
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 2f6747c9af..dcbc34a157 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -66,6 +66,8 @@ require "chef/util/file_edit"
require "chef/config"
+require "chef/chef_fs/file_system_cache"
+
if ENV["CHEF_FIPS"] == "1"
Chef::Config.init_openssl
end
@@ -152,6 +154,8 @@ RSpec.configure do |config|
config.filter_run_excluding :unix_only => true unless unix?
config.filter_run_excluding :aix_only => true unless aix?
config.filter_run_excluding :debian_family_only => true unless debian_family?
+ config.filter_run_excluding :linux_only => true unless linux?
+ config.filter_run_excluding :non_linux_only => true if linux?
config.filter_run_excluding :supports_cloexec => true unless supports_cloexec?
config.filter_run_excluding :selinux_only => true unless selinux_enabled?
config.filter_run_excluding :requires_root => true unless root?
@@ -200,6 +204,8 @@ RSpec.configure do |config|
config.before(:each) do
Chef.reset!
+ Chef::ChefFS::FileSystemCache.instance.reset!
+
Chef::Config.reset
# By default, treat deprecation warnings as errors in tests.
diff --git a/spec/support/platform_helpers.rb b/spec/support/platform_helpers.rb
index 9ba56a15e3..783429161a 100644
--- a/spec/support/platform_helpers.rb
+++ b/spec/support/platform_helpers.rb
@@ -138,6 +138,10 @@ def freebsd?
!!(RUBY_PLATFORM =~ /freebsd/)
end
+def linux?
+ !!(RUBY_PLATFORM =~ /linux/)
+end
+
def debian_family?
!!(ohai[:platform_family] == "debian")
end
diff --git a/spec/support/shared/integration/knife_support.rb b/spec/support/shared/integration/knife_support.rb
index 1e81cd115c..01df9ab1a7 100644
--- a/spec/support/shared/integration/knife_support.rb
+++ b/spec/support/shared/integration/knife_support.rb
@@ -20,10 +20,11 @@ require "chef/knife"
require "chef/application/knife"
require "logger"
require "chef/log"
+require "chef/chef_fs/file_system_cache"
module KnifeSupport
DEBUG = ENV["DEBUG"]
- def knife(*args)
+ def knife(*args, input: nil)
# Allow knife('role from file roles/blah.json') rather than requiring the
# arguments to be split like knife('role', 'from', 'file', 'roles/blah.json')
# If any argument will have actual spaces in it, the long form is required.
@@ -37,7 +38,7 @@ module KnifeSupport
Chef::Config[:concurrency] = 1
# Work on machines where we can't access /var
- checksums_cache_dir = Dir.mktmpdir("checksums") do |checksums_cache_dir|
+ Dir.mktmpdir("checksums") do |checksums_cache_dir|
Chef::Config[:cache_options] = {
:path => checksums_cache_dir,
:skip_expires => true,
@@ -47,6 +48,13 @@ module KnifeSupport
# ourselves, thank you very much
stdout = StringIO.new
stderr = StringIO.new
+
+ stdin = if input
+ StringIO.new(input)
+ else
+ STDIN
+ end
+
old_loggers = Chef::Log.loggers
old_log_level = Chef::Log.level
begin
@@ -57,12 +65,15 @@ module KnifeSupport
instance = subcommand_class.new(args)
# Capture stdout/stderr
- instance.ui = Chef::Knife::UI.new(stdout, stderr, STDIN, {})
+ instance.ui = Chef::Knife::UI.new(stdout, stderr, stdin, disable_editing: true)
# Don't print stuff
Chef::Config[:verbosity] = ( DEBUG ? 2 : 0 )
instance.config[:config_file] = File.join(CHEF_SPEC_DATA, "null_config.rb")
+ # Ensure the ChefFS cache is empty
+ Chef::ChefFS::FileSystemCache.instance.reset!
+
# Configure chef with a (mostly) blank knife.rb
# We set a global and then mutate it in our stub knife.rb so we can be
# extra sure that we're not loading someone's real knife.rb and then
diff --git a/spec/support/shared/unit/provider/file.rb b/spec/support/shared/unit/provider/file.rb
index cb539ffbc3..ee3438da70 100644
--- a/spec/support/shared/unit/provider/file.rb
+++ b/spec/support/shared/unit/provider/file.rb
@@ -683,6 +683,31 @@ shared_examples_for Chef::Provider::File do
end
end
+ context "do_resolv_conf_fixup" do
+ %w{/resolv.conf /etc/resolv.con /etc/foo/resolv.conf /c/resolv.conf}.each do |path|
+ context "when managing #{path}" do
+ let(:resource_path) { path }
+ it "does not reload the nameservers" do
+ expect(Resolv::DefaultResolver).not_to receive(:replace_resolvers)
+ provider.send(:do_resolv_conf_fixup)
+ end
+ end
+ end
+ context "when managing /etc/resolv.conf", linux_only: true do
+ let(:resource_path) { "/etc/resolv.conf" }
+ it "reloads the nameservers on linux" do
+ expect(Resolv::DefaultResolver).to receive(:replace_resolvers)
+ provider.send(:do_resolv_conf_fixup)
+ end
+ end
+ context "when managing /etc/resolv.conf", non_linux_only: true do
+ let(:resource_path) { "/etc/resolv.conf" }
+ it "does not reload the nameservers on non-linux" do
+ expect(Resolv::DefaultResolver).not_to receive(:replace_resolvers)
+ provider.send(:do_resolv_conf_fixup)
+ end
+ end
+ end
end
context "action delete" do
diff --git a/spec/unit/application/solo_spec.rb b/spec/unit/application/solo_spec.rb
index bb29261f5a..686ae745d8 100644
--- a/spec/unit/application/solo_spec.rb
+++ b/spec/unit/application/solo_spec.rb
@@ -120,9 +120,10 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config
expect(app).to receive(:open).with("http://junglist.gen.nz/recipes.tgz").and_yield(tarfile)
expect(File).to receive(:open).with("#{Dir.tmpdir}/chef-solo/recipes.tgz", "wb").and_yield(target_file)
- shellout = instance_double("Mixlib::ShellOut", run_command: nil, error!: nil, stdout: "")
+ archive = double(Mixlib::Archive)
- expect(app).to receive(:shell_out!).with("tar zxvf #{Dir.tmpdir}/chef-solo/recipes.tgz -C #{Dir.tmpdir}/chef-solo").and_return(shellout)
+ expect(Mixlib::Archive).to receive(:new).with("#{Dir.tmpdir}/chef-solo/recipes.tgz").and_return(archive)
+ expect(archive).to receive(:extract).with("#{Dir.tmpdir}/chef-solo", { perms: false, ignore: /^\.$/ })
app.reconfigure
expect(target_file.string).to eq("remote_tarball_content")
end
@@ -136,11 +137,10 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config
Chef::Config[:cookbook_path] = "#{Dir.tmpdir}/chef-solo/cookbooks"
expect(FileUtils).to receive(:mkdir_p).with("#{Dir.tmpdir}/chef-solo").and_return(true)
- allow(Chef::Mixin::Command).to receive(:run_command).and_return(true)
+ archive = double(Mixlib::Archive)
- shellout = instance_double("Mixlib::ShellOut", run_command: nil, error!: nil, stdout: "")
-
- expect(app).to receive(:shell_out!).with("tar zxvf #{Dir.tmpdir}/chef-solo/recipes.tgz -C #{Dir.tmpdir}/chef-solo").and_return(shellout)
+ expect(Mixlib::Archive).to receive(:new).with("#{Dir.tmpdir}/chef-solo/recipes.tgz").and_return(archive)
+ expect(archive).to receive(:extract).with("#{Dir.tmpdir}/chef-solo", { perms: false, ignore: /^\.$/ })
expect(app).to receive(:fetch_recipe_tarball).ordered
expect(Chef::ConfigFetcher).to receive(:new).ordered.and_return(config_fetcher)
app.reconfigure
@@ -212,6 +212,13 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config
end
end
+ it "sets the repo path" do
+ expect(Chef::Config).to receive(:find_chef_repo_path).and_return("/var/chef")
+ app.reconfigure
+ expect(Chef::Config.has_key?(:chef_repo_path)).to be_truthy
+ expect(Chef::Config[:chef_repo_path]).to eq ("/var/chef")
+ end
+
it "runs chef-client in local mode" do
allow(app).to receive(:setup_application).and_return(true)
allow(app).to receive(:run_application).and_return(true)
diff --git a/spec/unit/chef_fs/file_system/repository/directory_spec.rb b/spec/unit/chef_fs/file_system/repository/directory_spec.rb
index e050181be9..6e53e52966 100644
--- a/spec/unit/chef_fs/file_system/repository/directory_spec.rb
+++ b/spec/unit/chef_fs/file_system/repository/directory_spec.rb
@@ -76,6 +76,7 @@ describe Chef::ChefFS::FileSystem::Repository::Directory do
context "#create_child" do
it "creates a new TestFile" do
expect(TestFile).to receive(:new).with("test_child", test_directory).and_return(file_double)
+ allow(file_double).to receive(:file_path).and_return("#{test_directory}/test_child")
expect(file_double).to receive(:write).with("test")
test_directory.create_child("test_child", "test")
end
diff --git a/spec/unit/cookbook_version_spec.rb b/spec/unit/cookbook_version_spec.rb
index 7def2f5749..81ea161bfe 100644
--- a/spec/unit/cookbook_version_spec.rb
+++ b/spec/unit/cookbook_version_spec.rb
@@ -120,8 +120,8 @@ describe Chef::CookbookVersion do
# Used to test file-specificity related file lookups
let(:node) do
Chef::Node.new.tap do |n|
- n.set[:platform] = "ubuntu"
- n.set[:platform_version] = "13.04"
+ n.normal[:platform] = "ubuntu"
+ n.normal[:platform_version] = "13.04"
n.name("testing")
end
end
@@ -203,8 +203,8 @@ describe Chef::CookbookVersion do
# Used to test file-specificity related file lookups
let(:node) do
Chef::Node.new.tap do |n|
- n.set[:platform] = "ubuntu"
- n.set[:platform_version] = "13.04"
+ n.normal[:platform] = "ubuntu"
+ n.normal[:platform_version] = "13.04"
n.name("testing")
end
end
diff --git a/spec/unit/data_collector/messages/helpers_spec.rb b/spec/unit/data_collector/messages/helpers_spec.rb
index 0ed0f6c921..26f7dbacfa 100644
--- a/spec/unit/data_collector/messages/helpers_spec.rb
+++ b/spec/unit/data_collector/messages/helpers_spec.rb
@@ -171,20 +171,16 @@ describe Chef::DataCollector::Messages::Helpers do
end
describe '#update_metadata' do
- let(:metadata) { double("metadata") }
-
it "updates the file" do
allow(TestMessage).to receive(:metadata_filename).and_return("fake_metadata_file.json")
- allow(TestMessage).to receive(:metadata).and_return(metadata)
- expect(metadata).to receive(:[]=).with("new_key", "new_value")
- expect(metadata).to receive(:to_json).and_return("metadata_json")
+ allow(TestMessage).to receive(:metadata).and_return({ "key" => "current_value" })
expect(Chef::FileCache).to receive(:store).with(
"fake_metadata_file.json",
- "metadata_json",
+ '{"key":"updated_value"}',
0644
)
- TestMessage.update_metadata("new_key", "new_value")
+ TestMessage.update_metadata("key", "updated_value")
end
end
end
diff --git a/spec/unit/data_collector/messages_spec.rb b/spec/unit/data_collector/messages_spec.rb
index dee86a3907..b0c7e692d2 100644
--- a/spec/unit/data_collector/messages_spec.rb
+++ b/spec/unit/data_collector/messages_spec.rb
@@ -18,6 +18,7 @@
#
require "spec_helper"
+require "ffi_yajl"
require "chef/data_collector/messages/helpers"
describe Chef::DataCollector::Messages do
@@ -61,13 +62,14 @@ describe Chef::DataCollector::Messages do
end
describe '#run_end_message' do
- let(:run_status) { Chef::RunStatus.new(Chef::Node.new, Chef::EventDispatch::Dispatcher.new) }
- let(:resource1) { double("resource1", for_json: "resource_data", status: "updated") }
- let(:resource2) { double("resource2", for_json: "resource_data", status: "skipped") }
+ let(:node) { Chef::Node.new }
+ let(:run_status) { Chef::RunStatus.new(node, Chef::EventDispatch::Dispatcher.new) }
+ let(:report1) { double("report1", report_data: { "status" => "updated" }) }
+ let(:report2) { double("report2", report_data: { "status" => "skipped" }) }
let(:reporter_data) do
{
run_status: run_status,
- completed_resources: [resource1, resource2],
+ resources: [report1, report2],
}
end
@@ -76,6 +78,20 @@ describe Chef::DataCollector::Messages do
allow(run_status).to receive(:end_time).and_return(Time.now)
end
+ it "includes a valid node object in the payload" do
+ message = Chef::DataCollector::Messages.run_end_message(reporter_data)
+ expect(message["node"]).to be_an_instance_of(Chef::Node)
+ end
+
+ it "returns a sane JSON representation of the node object" do
+ node.chef_environment = "my_test_environment"
+ node.run_list.add("recipe[my_test_cookbook::default]")
+ message = FFI_Yajl::Parser.parse(Chef::DataCollector::Messages.run_end_message(reporter_data).to_json)
+
+ expect(message["node"]["chef_environment"]).to eq("my_test_environment")
+ expect(message["node"]["run_list"]).to eq(["recipe[my_test_cookbook::default]"])
+ end
+
context "when the run was successful" do
let(:required_fields) do
%w{
@@ -86,6 +102,7 @@ describe Chef::DataCollector::Messages do
expanded_run_list
message_type
message_version
+ node
node_name
organization_name
resources
@@ -136,6 +153,7 @@ describe Chef::DataCollector::Messages do
expanded_run_list
message_type
message_version
+ node
node_name
organization_name
resources
@@ -169,46 +187,4 @@ describe Chef::DataCollector::Messages do
end
end
end
-
- describe '#node_update_message' do
- let(:run_status) { Chef::RunStatus.new(Chef::Node.new, Chef::EventDispatch::Dispatcher.new) }
-
- let(:required_fields) do
- %w{
- entity_name
- entity_type
- entity_uuid
- id
- message_type
- message_version
- organization_name
- recorded_at
- remote_hostname
- requestor_name
- requestor_type
- run_id
- service_hostname
- source
- task
- user_agent
- }
- end
- let(:optional_fields) { %w{data} }
-
- it "is not missing any required fields" do
- missing_fields = required_fields.select do |key|
- !Chef::DataCollector::Messages.node_update_message(run_status).key?(key)
- end
-
- expect(missing_fields).to eq([])
- end
-
- it "does not have any extra fields" do
- extra_fields = Chef::DataCollector::Messages.node_update_message(run_status).keys.select do |key|
- !required_fields.include?(key) && !optional_fields.include?(key)
- end
-
- expect(extra_fields).to eq([])
- end
- end
end
diff --git a/spec/unit/data_collector_spec.rb b/spec/unit/data_collector_spec.rb
index 78b0aaf97d..131d6b8df9 100644
--- a/spec/unit/data_collector_spec.rb
+++ b/spec/unit/data_collector_spec.rb
@@ -20,6 +20,7 @@
require "spec_helper"
require "chef/data_collector"
+require "chef/resource_builder"
describe Chef::DataCollector do
describe ".register_reporter?" do
@@ -155,6 +156,10 @@ describe Chef::DataCollector::Reporter do
let(:reporter) { described_class.new }
let(:run_status) { Chef::RunStatus.new(Chef::Node.new, Chef::EventDispatch::Dispatcher.new) }
+ before do
+ Chef::Config[:data_collector][:server_url] = "http://my-data-collector-server.mycompany.com"
+ end
+
describe '#run_started' do
before do
allow(reporter).to receive(:update_run_status)
@@ -193,10 +198,32 @@ describe Chef::DataCollector::Reporter do
end
end
+ describe '#converge_start' do
+ it "stashes the run_context for later use" do
+ reporter.converge_start("test_context")
+ expect(reporter.run_context).to eq("test_context")
+ end
+ end
+
+ describe '#converge_complete' do
+ it "detects and processes any unprocessed resources" do
+ expect(reporter).to receive(:detect_unprocessed_resources)
+ reporter.converge_complete
+ end
+ end
+
+ describe '#converge_failed' do
+ it "detects and processes any unprocessed resources" do
+ expect(reporter).to receive(:detect_unprocessed_resources)
+ reporter.converge_failed("exception")
+ end
+ end
+
describe '#resource_current_state_loaded' do
let(:new_resource) { double("new_resource") }
let(:action) { double("action") }
let(:current_resource) { double("current_resource") }
+ let(:resource_report) { double("resource_report") }
context "when resource is a nested resource" do
it "does not update the resource report" do
@@ -207,14 +234,12 @@ describe Chef::DataCollector::Reporter do
end
context "when resource is not a nested resource" do
- it "updates the resource report" do
+ it "creates the resource report and stores it as the current one" do
allow(reporter).to receive(:nested_resource?).and_return(false)
- expect(Chef::DataCollector::ResourceReport).to receive(:new).with(
- new_resource,
- action,
- current_resource)
- .and_return("resource_report")
- expect(reporter).to receive(:update_current_resource_report).with("resource_report")
+ expect(reporter).to receive(:create_resource_report)
+ .with(new_resource, action, current_resource)
+ .and_return(resource_report)
+ expect(reporter).to receive(:update_current_resource_report).with(resource_report)
reporter.resource_current_state_loaded(new_resource, action, current_resource)
end
end
@@ -256,7 +281,7 @@ describe Chef::DataCollector::Reporter do
before do
allow(reporter).to receive(:nested_resource?)
- allow(reporter).to receive(:current_resource_report).and_return(resource_report)
+ allow(reporter).to receive(:create_resource_report).and_return(resource_report)
allow(resource_report).to receive(:skipped)
end
@@ -269,13 +294,12 @@ describe Chef::DataCollector::Reporter do
end
context "when the resource is not a nested resource" do
- it "updates the resource report" do
+ it "creates the resource report and stores it as the current one" do
allow(reporter).to receive(:nested_resource?).and_return(false)
- expect(Chef::DataCollector::ResourceReport).to receive(:new).with(
- new_resource,
- action)
- .and_return("resource_report")
- expect(reporter).to receive(:update_current_resource_report).with("resource_report")
+ expect(reporter).to receive(:create_resource_report)
+ .with(new_resource, action)
+ .and_return(resource_report)
+ expect(reporter).to receive(:update_current_resource_report).with(resource_report)
reporter.resource_skipped(new_resource, action, conditional)
end
@@ -349,15 +373,16 @@ describe Chef::DataCollector::Reporter do
let(:resource_report) { double("resource_report") }
before do
- allow(reporter).to receive(:add_completed_resource)
allow(reporter).to receive(:update_current_resource_report)
+ allow(reporter).to receive(:add_resource_report)
+ allow(reporter).to receive(:current_resource_report)
allow(resource_report).to receive(:finish)
end
context "when there is no current resource report" do
- it "does not add the updated resource" do
+ it "does not touch the current resource report" do
allow(reporter).to receive(:current_resource_report).and_return(nil)
- expect(reporter).not_to receive(:add_completed_resource)
+ expect(reporter).not_to receive(:update_current_resource_report)
reporter.resource_completed(new_resource)
end
end
@@ -368,9 +393,9 @@ describe Chef::DataCollector::Reporter do
end
context "when the resource is a nested resource" do
- it "does not add the updated resource" do
+ it "does not mark the resource as finished" do
allow(reporter).to receive(:nested_resource?).with(new_resource).and_return(true)
- expect(reporter).not_to receive(:add_completed_resource)
+ expect(resource_report).not_to receive(:finish)
reporter.resource_completed(new_resource)
end
end
@@ -385,11 +410,6 @@ describe Chef::DataCollector::Reporter do
reporter.resource_completed(new_resource)
end
- it "adds the resource to the updated resource list" do
- expect(reporter).to receive(:add_completed_resource).with(resource_report)
- reporter.resource_completed(new_resource)
- end
-
it "nils out the current resource report" do
expect(reporter).to receive(:update_current_resource_report).with(nil)
reporter.resource_completed(new_resource)
@@ -474,7 +494,8 @@ describe Chef::DataCollector::Reporter do
[ Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
Errno::ECONNREFUSED, EOFError, Net::HTTPBadResponse,
- Net::HTTPHeaderSyntaxError, Net::ProtocolError, OpenSSL::SSL::SSLError ].each do |exception_class|
+ Net::HTTPHeaderSyntaxError, Net::ProtocolError, OpenSSL::SSL::SSLError,
+ Errno::EHOSTDOWN ].each do |exception_class|
context "when the block raises a #{exception_class} exception" do
it "disables the reporter" do
expect(reporter).to receive(:disable_data_collector_reporter)
@@ -499,4 +520,39 @@ describe Chef::DataCollector::Reporter do
end
end
end
+
+ describe '#validate_data_collector_server_url!' do
+ context "when server_url is empty" do
+ it "raises an exception" do
+ Chef::Config[:data_collector][:server_url] = ""
+ expect { reporter.send(:validate_data_collector_server_url!) }.to raise_error(Chef::Exceptions::ConfigurationError)
+ end
+ end
+
+ context "when server_url is not empty" do
+ context "when server_url is an invalid URI" do
+ it "raises an exception" do
+ Chef::Config[:data_collector][:server_url] = "this is not a URI"
+ expect { reporter.send(:validate_data_collector_server_url!) }.to raise_error(Chef::Exceptions::ConfigurationError)
+ end
+ end
+
+ context "when server_url is a valid URI" do
+ context "when server_url is a URI with no host" do
+ it "raises an exception" do
+ Chef::Config[:data_collector][:server_url] = "/file/uri.txt"
+ expect { reporter.send(:validate_data_collector_server_url!) }.to raise_error(Chef::Exceptions::ConfigurationError)
+ end
+
+ end
+
+ context "when server_url is a URI with a valid host" do
+ it "does not an exception" do
+ Chef::Config[:data_collector][:server_url] = "http://www.google.com/data-collector"
+ expect { reporter.send(:validate_data_collector_server_url!) }.not_to raise_error
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/unit/dsl/declare_resource_spec.rb b/spec/unit/dsl/declare_resource_spec.rb
index 6dd9317c21..692e57d2e1 100644
--- a/spec/unit/dsl/declare_resource_spec.rb
+++ b/spec/unit/dsl/declare_resource_spec.rb
@@ -235,6 +235,36 @@ describe Chef::ResourceCollection do
).to eql(resource)
expect(run_context.resource_collection.all_resources.size).to eql(0)
end
+
+ it "removes pending delayed notifications" do
+ recipe.declare_resource(:zen_master, "one")
+ recipe.declare_resource(:zen_master, "two") do
+ notifies :win, "zen_master[one]"
+ end
+ recipe.delete_resource(:zen_master, "two")
+ resource = recipe.declare_resource(:zen_master, "two")
+ expect(resource.delayed_notifications).to eql([])
+ end
+
+ it "removes pending immediate notifications" do
+ recipe.declare_resource(:zen_master, "one")
+ recipe.declare_resource(:zen_master, "two") do
+ notifies :win, "zen_master[one]", :immediate
+ end
+ recipe.delete_resource(:zen_master, "two")
+ resource = recipe.declare_resource(:zen_master, "two")
+ expect(resource.immediate_notifications).to eql([])
+ end
+
+ it "removes pending before notifications" do
+ recipe.declare_resource(:zen_master, "one")
+ recipe.declare_resource(:zen_master, "two") do
+ notifies :win, "zen_master[one]", :before
+ end
+ recipe.delete_resource(:zen_master, "two")
+ resource = recipe.declare_resource(:zen_master, "two")
+ expect(resource.before_notifications).to eql([])
+ end
end
describe "run_context helpers" do
diff --git a/spec/unit/knife/cookbook_create_spec.rb b/spec/unit/knife/cookbook_create_spec.rb
index 5e343f3db1..f860a8bce8 100644
--- a/spec/unit/knife/cookbook_create_spec.rb
+++ b/spec/unit/knife/cookbook_create_spec.rb
@@ -22,6 +22,7 @@ require "tmpdir"
describe Chef::Knife::CookbookCreate do
before(:each) do
Chef::Config[:node_name] = "webmonkey.example.com"
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
@knife = Chef::Knife::CookbookCreate.new
@knife.config = {}
@knife.name_args = ["foobar"]
diff --git a/spec/unit/knife/cookbook_site_download_spec.rb b/spec/unit/knife/cookbook_site_download_spec.rb
index d283bd417f..0ab6a8a9b4 100644
--- a/spec/unit/knife/cookbook_site_download_spec.rb
+++ b/spec/unit/knife/cookbook_site_download_spec.rb
@@ -38,6 +38,7 @@ describe Chef::Knife::CookbookSiteDownload do
expect(@noauth_rest).to receive(:get).
with("#{@cookbook_api_url}/apache2").
and_return(@current_data)
+ @knife.configure_chef
end
context "when the cookbook is deprecated and not forced" do
diff --git a/spec/unit/knife/cookbook_site_install_spec.rb b/spec/unit/knife/cookbook_site_install_spec.rb
index d60443d779..1549245ea3 100644
--- a/spec/unit/knife/cookbook_site_install_spec.rb
+++ b/spec/unit/knife/cookbook_site_install_spec.rb
@@ -23,6 +23,7 @@ describe Chef::Knife::CookbookSiteInstall do
let(:stdout) { StringIO.new }
let(:stderr) { StringIO.new }
let(:downloader) { Hash.new }
+ let(:archive) { double(Mixlib::Archive, extract: true) }
let(:repo) { double(:sanity_check => true, :reset_to_default_state => true,
:prepare_to_import => true, :finalize_updates_to => true,
:merge_updates_from => true) }
@@ -48,6 +49,7 @@ describe Chef::Knife::CookbookSiteInstall do
allow(File).to receive(:unlink)
allow(File).to receive(:rmtree)
allow(knife).to receive(:shell_out!).and_return(true)
+ allow(Mixlib::Archive).to receive(:new).and_return(archive)
# CookbookSiteDownload Stup
allow(knife).to receive(:download_cookbook_to).and_return(downloader)
diff --git a/spec/unit/knife/cookbook_site_share_spec.rb b/spec/unit/knife/cookbook_site_share_spec.rb
index 9339114d2a..5ac48539e4 100644
--- a/spec/unit/knife/cookbook_site_share_spec.rb
+++ b/spec/unit/knife/cookbook_site_share_spec.rb
@@ -83,11 +83,11 @@ describe Chef::Knife::CookbookSiteShare do
@knife.run
end
- it "should print error and exit when given only 1 argument and cannot determine category" do
+ it "should use a default category when given only 1 argument and cannot determine category" do
@knife.name_args = ["cookbook_name"]
- expect(@noauth_rest).to receive(:get).with("https://supermarket.chef.io/api/v1/cookbooks/cookbook_name").and_return(@bad_category_response)
- expect(@knife.ui).to receive(:fatal)
- expect { @knife.run }.to raise_error(SystemExit)
+ expect(@noauth_rest).to receive(:get).with("https://supermarket.chef.io/api/v1/cookbooks/cookbook_name") { raise Net::HTTPServerException.new("404 Not Found", OpenStruct.new(code: "404")) }
+ expect(@knife).to receive(:do_upload)
+ expect { @knife.run }.to_not raise_error
end
it "should print error and exit when given only 1 argument and Chef::ServerAPI throws an exception" do
diff --git a/spec/unit/knife/node_environment_set_spec.rb b/spec/unit/knife/node_environment_set_spec.rb
index 03fc764fd8..7ceafdad78 100644
--- a/spec/unit/knife/node_environment_set_spec.rb
+++ b/spec/unit/knife/node_environment_set_spec.rb
@@ -52,29 +52,5 @@ describe Chef::Knife::NodeEnvironmentSet do
@knife.run
end
- describe "with no environment" do
- # Set up outputs for inspection later
- before(:each) do
- @stdout = StringIO.new
- @stderr = StringIO.new
-
- allow(@knife.ui).to receive(:stdout).and_return(@stdout)
- allow(@knife.ui).to receive(:stderr).and_return(@stderr)
- end
-
- it "should exit" do
- @knife.name_args = [ "adam" ]
- expect { @knife.run }.to raise_error SystemExit
- end
-
- it "should show the user the usage and an error" do
- @knife.name_args = [ "adam" ]
-
- begin ; @knife.run ; rescue SystemExit ; end
-
- expect(@stdout.string).to eq "USAGE: knife node environment set NODE ENVIRONMENT\n"
- expect(@stderr.string).to eq "FATAL: You must specify a node name and an environment.\n"
- end
- end
end
end
diff --git a/spec/unit/knife/node_run_list_set_spec.rb b/spec/unit/knife/node_run_list_set_spec.rb
index 1bbaa7d9a5..bd55edb997 100644
--- a/spec/unit/knife/node_run_list_set_spec.rb
+++ b/spec/unit/knife/node_run_list_set_spec.rb
@@ -111,30 +111,5 @@ describe Chef::Knife::NodeRunListSet do
end
end
- describe "with no role or recipe" do
- # Set up outputs for inspection later
- before(:each) do
- @stdout = StringIO.new
- @stderr = StringIO.new
-
- allow(@knife.ui).to receive(:stdout).and_return(@stdout)
- allow(@knife.ui).to receive(:stderr).and_return(@stderr)
- end
-
- it "should exit" do
- @knife.name_args = [ "adam" ]
- expect { @knife.run }.to raise_error SystemExit
- end
-
- it "should show the user" do
- @knife.name_args = [ "adam" ]
-
- begin ; @knife.run ; rescue SystemExit ; end
-
- expect(@stdout.string).to eq "USAGE: knife node run_list set NODE ENTRIES (options)\n"
- expect(@stderr.string).to eq "FATAL: You must supply both a node name and a run list.\n"
- end
- end
-
end
end
diff --git a/spec/unit/node/attribute_spec.rb b/spec/unit/node/attribute_spec.rb
index 57ad3c0c25..e40f454c0b 100644
--- a/spec/unit/node/attribute_spec.rb
+++ b/spec/unit/node/attribute_spec.rb
@@ -218,7 +218,7 @@ describe Chef::Node::Attribute do
end
it "gives the value at each level of precedence for a path spec" do
- expected = [["set_unless_enabled?", false],
+ expected = [
%w{default default},
%w{env_default env_default},
%w{role_default role_default},
@@ -417,12 +417,6 @@ describe Chef::Node::Attribute do
expect(@attributes.normal["foo"]["bar"]).to eq(:baz)
end
- it "should optionally skip setting the value if one already exists" do
- @attributes.set_unless_value_present = true
- @attributes.normal["hostname"] = "bar"
- expect(@attributes["hostname"]).to eq("latte")
- end
-
it "does not support ||= when setting" do
# This is a limitation of auto-vivification.
# Users who need this behavior can use set_unless and friends
@@ -493,6 +487,7 @@ describe Chef::Node::Attribute do
end
it "should return true if an attribute exists but is set to nil using dot notation" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
expect(@attributes.music.deeper.has_key?("gates_of_ishtar")).to eq(true)
end
@@ -533,10 +528,12 @@ describe Chef::Node::Attribute do
describe "method_missing" do
it "should behave like a [] lookup" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
expect(@attributes.music.mastodon).to eq("rocks")
end
it "should allow the last method to set a value if it has an = sign on the end" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
@attributes.normal.music.mastodon = %w{dream still shining}
expect(@attributes.normal.music.mastodon).to eq(%w{dream still shining})
end
@@ -577,7 +574,7 @@ describe Chef::Node::Attribute do
it "should yield lower if we go deeper" do
collect = Array.new
- @attributes.one.keys.each do |k|
+ @attributes["one"].keys.each do |k|
collect << k
end
expect(collect.include?("two")).to eq(true)
@@ -587,7 +584,7 @@ describe Chef::Node::Attribute do
end
it "should not raise an exception if one of the hashes has a nil value on a deep lookup" do
- expect { @attributes.place.keys { |k| } }.not_to raise_error
+ expect { @attributes["place"].keys { |k| } }.not_to raise_error
end
end
@@ -1171,6 +1168,7 @@ describe Chef::Node::Attribute do
end
it "raises an error when using `attr=value`" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
expect { @attributes.new_key = "new value" }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
end
diff --git a/spec/unit/node/immutable_collections_spec.rb b/spec/unit/node/immutable_collections_spec.rb
index f57ed459cd..fe4e50d1bd 100644
--- a/spec/unit/node/immutable_collections_spec.rb
+++ b/spec/unit/node/immutable_collections_spec.rb
@@ -95,6 +95,10 @@ describe Chef::Node::ImmutableMash do
:replace,
:select!,
:shift,
+ :write,
+ :write!,
+ :unlink,
+ :unlink!,
].each do |mutator|
it "doesn't allow mutation via `#{mutator}'" do
expect { @immutable_mash.send(mutator) }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
diff --git a/spec/unit/node/vivid_mash_spec.rb b/spec/unit/node/vivid_mash_spec.rb
new file mode 100644
index 0000000000..5319ba4a35
--- /dev/null
+++ b/spec/unit/node/vivid_mash_spec.rb
@@ -0,0 +1,377 @@
+#
+# 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"
+require "chef/node/attribute_collections"
+
+describe Chef::Node::VividMash do
+ class Root
+ attr_accessor :top_level_breadcrumb
+ end
+
+ let(:root) { Root.new }
+
+ 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 }
+ )
+ 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
+ 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 "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")
+ 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).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")
+ end
+ 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 })
+ end
+ 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 })
+ end
+ end
+end
diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb
index 923b488f72..72731c927f 100644
--- a/spec/unit/node_spec.rb
+++ b/spec/unit/node_spec.rb
@@ -233,60 +233,69 @@ describe Chef::Node do
end
it "should let you go deep with attribute?" do
- node.set["battles"]["people"]["wonkey"] = true
+ node.normal["battles"]["people"]["wonkey"] = true
expect(node["battles"]["people"].attribute?("wonkey")).to eq(true)
expect(node["battles"]["people"].attribute?("snozzberry")).to eq(false)
end
it "does not allow you to set an attribute via method_missing" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
expect { node.sunshine = "is bright" }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
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"
expect(node.sunshine).to eql("is bright")
end
describe "normal attributes" do
it "should allow you to set an attribute with set, without pre-declaring a hash" do
- node.set[:snoopy][:is_a_puppy] = true
+ node.normal[:snoopy][:is_a_puppy] = true
expect(node[:snoopy][:is_a_puppy]).to eq(true)
end
+ it "should allow you to set an attribute with set_unless with method_missing but emit a deprecation warning" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ node.normal_unless.snoopy.is_a_puppy = false
+ expect(node[:snoopy][:is_a_puppy]).to eq(false)
+ end
+
it "should allow you to set an attribute with set_unless" do
- node.set_unless[:snoopy][:is_a_puppy] = false
+ node.normal_unless[:snoopy][:is_a_puppy] = false
expect(node[:snoopy][:is_a_puppy]).to eq(false)
end
it "should not allow you to set an attribute with set_unless if it already exists" do
- node.set[:snoopy][:is_a_puppy] = true
- node.set_unless[:snoopy][:is_a_puppy] = false
+ node.normal[:snoopy][:is_a_puppy] = true
+ node.normal_unless[:snoopy][:is_a_puppy] = false
expect(node[:snoopy][:is_a_puppy]).to eq(true)
end
it "should allow you to set an attribute with set_unless if is a nil value" do
node.attributes.normal = { snoopy: { is_a_puppy: nil } }
- node.set_unless[:snoopy][:is_a_puppy] = false
+ node.normal_unless[:snoopy][:is_a_puppy] = false
expect(node[:snoopy][:is_a_puppy]).to eq(false)
end
it "should allow you to set a value after a set_unless" do
# this tests for set_unless_present state bleeding between statements CHEF-3806
- node.set_unless[:snoopy][:is_a_puppy] = false
- node.set[:snoopy][:is_a_puppy] = true
+ node.normal_unless[:snoopy][:is_a_puppy] = false
+ node.normal[:snoopy][:is_a_puppy] = true
expect(node[:snoopy][:is_a_puppy]).to eq(true)
end
it "should let you set a value after a 'dangling' set_unless" do
# this tests for set_unless_present state bleeding between statements CHEF-3806
- node.set[:snoopy][:is_a_puppy] = "what"
- node.set_unless[:snoopy][:is_a_puppy]
- node.set[:snoopy][:is_a_puppy] = true
+ node.normal[:snoopy][:is_a_puppy] = "what"
+ node.normal_unless[:snoopy][:is_a_puppy]
+ node.normal[:snoopy][:is_a_puppy] = true
expect(node[:snoopy][:is_a_puppy]).to eq(true)
end
it "auto-vivifies attributes created via method syntax" do
- node.set.fuu.bahrr.baz = "qux"
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ node.normal.fuu.bahrr.baz = "qux"
expect(node.fuu.bahrr.baz).to eq("qux")
end
@@ -295,6 +304,20 @@ describe Chef::Node do
node.tag("three", "four")
expect(node["tags"]).to eq(%w{one two three four})
end
+
+ it "set is a deprecated alias for normal" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ expect(Chef).to receive(:log_deprecation).with(/set is deprecated/)
+ node.set[:snoopy][:is_a_puppy] = true
+ expect(node[:snoopy][:is_a_puppy]).to eq(true)
+ end
+
+ it "set_unless is a deprecated alias for normal_unless" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ expect(Chef).to receive(:log_deprecation).with(/set_unless is deprecated/)
+ node.set_unless[:snoopy][:is_a_puppy] = false
+ expect(node[:snoopy][:is_a_puppy]).to eq(false)
+ end
end
describe "default attributes" do
@@ -329,10 +352,41 @@ describe Chef::Node do
expect(node[:snoopy][:is_a_puppy]).to eq(true)
end
+ it "does not exhibit chef/chef/issues/5005 bug" do
+ node.env_default["a"]["r1"]["g"]["u"] = "u1"
+ node.default_unless["a"]["r1"]["g"]["r"] = "r"
+ expect(node["a"]["r1"]["g"]["u"]).to eql("u1")
+ end
+
it "auto-vivifies attributes created via method syntax" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
node.default.fuu.bahrr.baz = "qux"
expect(node.fuu.bahrr.baz).to eq("qux")
end
+
+ it "default_unless correctly resets the deep merge cache" do
+ node.normal["tags"] = [] # this sets our top-level breadcrumb
+ node.default_unless["foo"]["bar"] = "NK-19V"
+ expect(node["foo"]["bar"]).to eql("NK-19V")
+ node.default_unless["foo"]["baz"] = "NK-33"
+ expect(node["foo"]["baz"]).to eql("NK-33")
+ end
+
+ it "normal_unless correctly resets the deep merge cache" do
+ node.normal["tags"] = [] # this sets our top-level breadcrumb
+ node.normal_unless["foo"]["bar"] = "NK-19V"
+ expect(node["foo"]["bar"]).to eql("NK-19V")
+ node.normal_unless["foo"]["baz"] = "NK-33"
+ expect(node["foo"]["baz"]).to eql("NK-33")
+ end
+
+ it "override_unless correctly resets the deep merge cache" do
+ node.normal["tags"] = [] # this sets our top-level breadcrumb
+ node.override_unless["foo"]["bar"] = "NK-19V"
+ expect(node["foo"]["bar"]).to eql("NK-19V")
+ node.override_unless["foo"]["baz"] = "NK-33"
+ expect(node["foo"]["baz"]).to eql("NK-33")
+ end
end
describe "override attributes" do
@@ -368,6 +422,7 @@ describe Chef::Node do
end
it "auto-vivifies attributes created via method syntax" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
node.override.fuu.bahrr.baz = "qux"
expect(node.fuu.bahrr.baz).to eq("qux")
end
@@ -453,8 +508,9 @@ describe Chef::Node do
expect( node["mysql"]["server"][0]["port"] ).to be_nil
end
- it "does not have a horrible error message when mistaking arrays for hashes" do
- expect { node.rm("mysql", "server", "port") }.to raise_error(TypeError, "Wrong type in index of attribute (did you use a Hash index on an Array?)")
+ it "when mistaking arrays for hashes, it considers the value removed and does nothing" do
+ node.rm("mysql", "server", "port")
+ expect(node["mysql"]["server"][0]["port"]).to eql(3456)
end
end
end
@@ -706,6 +762,7 @@ describe Chef::Node do
#
describe "deep merge attribute cache edge conditions" do
it "does not error with complicated attribute substitution" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
node.default["chef_attribute_hell"]["attr1"] = "attribute1"
node.default["chef_attribute_hell"]["attr2"] = "#{node.chef_attribute_hell.attr1}/attr2"
expect { node.default["chef_attribute_hell"]["attr3"] = "#{node.chef_attribute_hell.attr2}/attr3" }.not_to raise_error
@@ -720,6 +777,7 @@ describe Chef::Node do
end
it "method interpolation syntax also works" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
node.default["passenger"]["version"] = "4.0.57"
node.default["passenger"]["root_path"] = "passenger-#{node['passenger']['version']}"
node.default["passenger"]["root_path_2"] = "passenger-#{node.passenger['version']}"
@@ -729,6 +787,7 @@ describe Chef::Node do
end
it "should raise an ArgumentError if you ask for an attribute that doesn't exist via method_missing" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
expect { node.sunshine }.to raise_error(NoMethodError)
end
@@ -744,6 +803,51 @@ describe Chef::Node do
expect(seen_attributes["sunshine"]).to eq("is bright")
expect(seen_attributes["canada"]).to eq("is a nice place")
end
+
+ describe "functional attribute API" do
+ # deeper functional testing of this API is in the VividMash spec tests
+ it "should have an exist? function" do
+ node.default["foo"]["bar"] = "baz"
+ expect(node.exist?("foo", "bar")).to be true
+ expect(node.exist?("bar", "foo")).to be false
+ end
+
+ it "should have a read function" do
+ node.override["foo"]["bar"] = "baz"
+ expect(node.read("foo", "bar")).to eql("baz")
+ expect(node.read("bar", "foo")).to eql(nil)
+ end
+
+ it "should have a read! function" do
+ node.override["foo"]["bar"] = "baz"
+ expect(node.read!("foo", "bar")).to eql("baz")
+ expect { node.read!("bar", "foo") }.to raise_error(Chef::Exceptions::NoSuchAttribute)
+ end
+
+ it "delegates write(:level) to node.level.write()" do
+ node.write(:default, "foo", "bar", "baz")
+ expect(node.default["foo"]["bar"]).to eql("baz")
+ end
+
+ it "delegates write!(:level) to node.level.write!()" do
+ node.write!(:default, "foo", "bar", "baz")
+ expect(node.default["foo"]["bar"]).to eql("baz")
+ node.default["bar"] = true
+ expect { node.write!(:default, "bar", "foo", "baz") }.to raise_error(Chef::Exceptions::AttributeTypeMismatch)
+ end
+
+ it "delegates unlink(:level) to node.level.unlink()" do
+ node.default["foo"]["bar"] = "baz"
+ expect(node.unlink(:default, "foo", "bar")).to eql("baz")
+ expect(node.unlink(:default, "bar", "foo")).to eql(nil)
+ end
+
+ it "delegates unlink!(:level) to node.level.unlink!()" do
+ node.default["foo"]["bar"] = "baz"
+ expect(node.unlink!(:default, "foo", "bar")).to eql("baz")
+ expect { node.unlink!(:default, "bar", "foo") }.to raise_error(Chef::Exceptions::NoSuchAttribute)
+ end
+ end
end
describe "consuming json" do
@@ -789,8 +893,8 @@ describe Chef::Node do
it "should add json attributes to the node" do
node.consume_external_attrs(@ohai_data, { "one" => "two", "three" => "four" })
- expect(node.one).to eql("two")
- expect(node.three).to eql("four")
+ expect(node["one"]).to eql("two")
+ expect(node["three"]).to eql("four")
end
it "should set the tags attribute to an empty array if it is not already defined" do
@@ -824,17 +928,17 @@ describe Chef::Node do
it "deep merges attributes instead of overwriting them" do
node.consume_external_attrs(@ohai_data, "one" => { "two" => { "three" => "four" } })
- expect(node.one.to_hash).to eq({ "two" => { "three" => "four" } })
+ expect(node["one"].to_hash).to eq({ "two" => { "three" => "four" } })
node.consume_external_attrs(@ohai_data, "one" => { "abc" => "123" })
node.consume_external_attrs(@ohai_data, "one" => { "two" => { "foo" => "bar" } })
- expect(node.one.to_hash).to eq({ "two" => { "three" => "four", "foo" => "bar" }, "abc" => "123" })
+ expect(node["one"].to_hash).to eq({ "two" => { "three" => "four", "foo" => "bar" }, "abc" => "123" })
end
it "gives attributes from JSON priority when deep merging" do
node.consume_external_attrs(@ohai_data, "one" => { "two" => { "three" => "four" } })
- expect(node.one.to_hash).to eq({ "two" => { "three" => "four" } })
+ expect(node["one"].to_hash).to eq({ "two" => { "three" => "four" } })
node.consume_external_attrs(@ohai_data, "one" => { "two" => { "three" => "forty-two" } })
- expect(node.one.to_hash).to eq({ "two" => { "three" => "forty-two" } })
+ expect(node["one"].to_hash).to eq({ "two" => { "three" => "forty-two" } })
end
end
@@ -1036,10 +1140,10 @@ describe Chef::Node do
end
it "sets attributes from the files" do
- expect(node.ldap_server).to eql("ops1prod")
- expect(node.ldap_basedn).to eql("dc=hjksolutions,dc=com")
- expect(node.ldap_replication_password).to eql("forsure")
- expect(node.smokey).to eql("robinson")
+ expect(node["ldap_server"]).to eql("ops1prod")
+ expect(node["ldap_basedn"]).to eql("dc=hjksolutions,dc=com")
+ expect(node["ldap_replication_password"]).to eql("forsure")
+ expect(node["smokey"]).to eql("robinson")
end
it "gives a sensible error when attempting to load a missing attributes file" do
@@ -1083,8 +1187,8 @@ describe Chef::Node do
it "should load a node from a ruby file" do
node.from_file(File.expand_path(File.join(CHEF_SPEC_DATA, "nodes", "test.rb")))
expect(node.name).to eql("test.example.com-short")
- expect(node.sunshine).to eql("in")
- expect(node.something).to eql("else")
+ expect(node["sunshine"]).to eql("in")
+ expect(node["something"]).to eql("else")
expect(node.run_list).to eq(["operations-master", "operations-monitoring"])
end
@@ -1562,4 +1666,19 @@ describe Chef::Node do
end
end
+ describe "method_missing handling" do
+ it "should have an #empty? method via Chef::Node::Attribute" do
+ node.default["foo"] = "bar"
+ expect(node.empty?).to be false
+ end
+
+ it "it should correctly implement #respond_to?" do
+ expect(node.respond_to?(:empty?)).to be true
+ end
+
+ it "it should correctly retrieve the method with #method" do
+ expect(node.method(:empty?)).to be_kind_of(Method)
+ end
+ end
+
end
diff --git a/spec/unit/provider/cron_spec.rb b/spec/unit/provider/cron_spec.rb
index 010b1b09f3..9e849743e7 100644
--- a/spec/unit/provider/cron_spec.rb
+++ b/spec/unit/provider/cron_spec.rb
@@ -462,10 +462,10 @@ CRONTAB
@new_resource.environment "TEST" => "LOL"
expect(@provider).to receive(:write_crontab).with(<<-ENDCRON)
# Chef Name: cronhole some stuff
-MAILTO=foo@example.com
-PATH=/usr/bin:/my/custom/path
-SHELL=/bin/foosh
-HOME=/home/foo
+MAILTO="foo@example.com"
+PATH="/usr/bin:/my/custom/path"
+SHELL="/bin/foosh"
+HOME="/home/foo"
TEST=LOL
30 * * * * /bin/true
ENDCRON
@@ -524,10 +524,10 @@ TEST=LOL
# Another comment
# Chef Name: cronhole some stuff
-MAILTO=foo@example.com
-PATH=/usr/bin:/my/custom/path
-SHELL=/bin/foosh
-HOME=/home/foo
+MAILTO="foo@example.com"
+PATH="/usr/bin:/my/custom/path"
+SHELL="/bin/foosh"
+HOME="/home/foo"
TEST=LOL
30 * * * * /bin/true
ENDCRON
@@ -585,10 +585,10 @@ TEST=LOL
0 2 * * * /some/other/command
# Chef Name: cronhole some stuff
-MAILTO=foo@example.com
-PATH=/usr/bin:/my/custom/path
-SHELL=/bin/foosh
-HOME=/home/foo
+MAILTO="foo@example.com"
+PATH="/usr/bin:/my/custom/path"
+SHELL="/bin/foosh"
+HOME="/home/foo"
TEST=LOL
30 * * * * /bin/true
# Chef Name: something else
@@ -679,10 +679,10 @@ HOME=/home/foo
0 2 * * * /some/other/command
# Chef Name: cronhole some stuff
-MAILTO=foo@example.com
-PATH=/usr/bin:/my/custom/path
-SHELL=/bin/foosh
-HOME=/home/foo
+MAILTO="foo@example.com"
+PATH="/usr/bin:/my/custom/path"
+SHELL="/bin/foosh"
+HOME="/home/foo"
30 * * * * /bin/true
# Chef Name: something else
diff --git a/spec/unit/provider/package/aix_spec.rb b/spec/unit/provider/package/aix_spec.rb
index 6940874a43..2b574bb7df 100644
--- a/spec/unit/provider/package/aix_spec.rb
+++ b/spec/unit/provider/package/aix_spec.rb
@@ -73,6 +73,19 @@ describe Chef::Provider::Package::Aix do
expect(@new_resource.version).to eq("3.3.12.0")
end
+ it "should warn if the package is not a fileset" do
+ info = "samba.base:samba.base.samples:3.3.12.0::COMMITTED:I:Samba for AIX:
+ /etc/objrepos:samba.base:3.3.12.0::COMMITTED:I:Samba for AIX:"
+ status = double("Status", :stdout => info, :exitstatus => 0)
+ expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base", timeout: 900).and_return(status)
+ expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base", timeout: 900).and_return(@empty_status)
+ expect(Chef::Log).to receive(:warn).once.with(%r{bff package by product name})
+ @provider.load_current_resource
+
+ expect(@provider.current_resource.package_name).to eq("samba.base")
+ expect(@new_resource.version).to eq("3.3.12.0")
+ end
+
it "should return the current version installed if found by lslpp" do
status = double("Status", :stdout => @bffinfo, :exitstatus => 0)
@stdout = StringIO.new(@bffinfo)
diff --git a/spec/unit/provider/package/windows/exe_spec.rb b/spec/unit/provider/package/windows/exe_spec.rb
index 23a54601c2..b514f80a35 100644
--- a/spec/unit/provider/package/windows/exe_spec.rb
+++ b/spec/unit/provider/package/windows/exe_spec.rb
@@ -110,23 +110,28 @@ describe Chef::Provider::Package::Windows::Exe do
end
describe "remove_package" do
- context "no version given and one package installed" do
- it "removes installed package" do
- expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \/d\"uninst_dir\" uninst_file \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
+ before do
+ allow(::File).to receive(:exist?).and_return(false)
+ end
+
+ context "no version given and one package installed with unquoted uninstall string" do
+ it "removes installed package and quotes uninstall string" do
+ allow(::File).to receive(:exist?).with("uninst_dir/uninst_file").and_return(true)
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"uninst_dir\/uninst_file\" \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
provider.remove_package
end
end
- context "several packages installed" do
+ context "several packages installed with quoted uninstall strings" do
let(:uninstall_hash) do
[
{
"DisplayVersion" => "v1",
- "UninstallString" => File.join("uninst_dir1", "uninst_file1"),
+ "UninstallString" => "\"#{File.join("uninst_dir1", "uninst_file1")}\"",
},
{
"DisplayVersion" => "v2",
- "UninstallString" => File.join("uninst_dir2", "uninst_file2"),
+ "UninstallString" => "\"#{File.join("uninst_dir2", "uninst_file2")}\"",
},
]
end
@@ -134,15 +139,15 @@ describe Chef::Provider::Package::Windows::Exe do
context "version given and installed" do
it "removes given version" do
new_resource.version("v2")
- expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \/d\"uninst_dir2\" uninst_file2 \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"uninst_dir2\/uninst_file2\" \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
provider.remove_package
end
end
context "no version given" do
it "removes both versions" do
- expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \/d\"uninst_dir1\" uninst_file1 \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
- expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \/d\"uninst_dir2\" uninst_file2 \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"uninst_dir1\/uninst_file1\" \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"uninst_dir2\/uninst_file2\" \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
provider.remove_package
end
end
diff --git a/spec/unit/provider/package/zypper_spec.rb b/spec/unit/provider/package/zypper_spec.rb
index df0a1da9a2..8838c26b71 100644
--- a/spec/unit/provider/package/zypper_spec.rb
+++ b/spec/unit/provider/package/zypper_spec.rb
@@ -72,7 +72,7 @@ describe Chef::Provider::Package::Zypper do
provider.load_current_resource
end
- it "should set the installed version if zypper info has one" do
+ it "should set the installed version if zypper info has one (zypper version < 1.13.0)" do
status = double(:stdout => "Version: 1.0\nInstalled: Yes\n", :exitstatus => 0)
allow(provider).to receive(:shell_out!).and_return(status)
@@ -80,7 +80,15 @@ describe Chef::Provider::Package::Zypper do
provider.load_current_resource
end
- it "should set the candidate version if zypper info has one" do
+ it "should set the installed version if zypper info has one (zypper version >= 1.13.0)" do
+ status = double(:stdout => "Version : 1.0 \nInstalled : Yes \n", :exitstatus => 0)
+
+ allow(provider).to receive(:shell_out!).and_return(status)
+ expect(current_resource).to receive(:version).with(["1.0"]).and_return(true)
+ provider.load_current_resource
+ end
+
+ it "should set the candidate version if zypper info has one (zypper version < 1.13.0)" do
status = double(:stdout => "Version: 1.0\nInstalled: No\nStatus: out-of-date (version 0.9 installed)", :exitstatus => 0)
allow(provider).to receive(:shell_out!).and_return(status)
@@ -88,6 +96,14 @@ describe Chef::Provider::Package::Zypper do
expect(provider.candidate_version).to eql(["1.0"])
end
+ it "should set the candidate version if zypper info has one (zypper version >= 1.13.0)" do
+ status = double(:stdout => "Version : 1.0 \nInstalled : No \nStatus : out-of-date (version 0.9 installed)", :exitstatus => 0)
+
+ allow(provider).to receive(:shell_out!).and_return(status)
+ provider.load_current_resource
+ expect(provider.candidate_version).to eql(["1.0"])
+ end
+
it "should return the current resouce" do
expect(provider.load_current_resource).to eql(current_resource)
end
diff --git a/spec/unit/provider/powershell_script_spec.rb b/spec/unit/provider/powershell_script_spec.rb
index 5b5c783986..96869ff31c 100644
--- a/spec/unit/provider/powershell_script_spec.rb
+++ b/spec/unit/provider/powershell_script_spec.rb
@@ -43,8 +43,8 @@ describe Chef::Provider::PowershellScript, "action_run" do
allow(Chef::Platform).to receive(:windows_nano_server?).and_return(true)
allow(provider).to receive(:is_forced_32bit).and_return(false)
os_info_double = double("os_info")
- allow(provider.run_context.node.kernel).to receive(:os_info).and_return(os_info_double)
- allow(os_info_double).to receive(:system_directory).and_return("C:\\Windows\\system32")
+ allow(provider.run_context.node["kernel"]).to receive(:[]).with("os_info").and_return(os_info_double)
+ allow(os_info_double).to receive(:[]).with("system_directory").and_return("C:\\Windows\\system32")
end
it "sets the -Command flag as the last flag" do
@@ -58,8 +58,8 @@ describe Chef::Provider::PowershellScript, "action_run" do
allow(Chef::Platform).to receive(:windows_nano_server?).and_return(false)
allow(provider).to receive(:is_forced_32bit).and_return(false)
os_info_double = double("os_info")
- allow(provider.run_context.node.kernel).to receive(:os_info).and_return(os_info_double)
- allow(os_info_double).to receive(:system_directory).and_return("C:\\Windows\\system32")
+ allow(provider.run_context.node["kernel"]).to receive(:[]).with("os_info").and_return(os_info_double)
+ allow(os_info_double).to receive(:[]).with("system_directory").and_return("C:\\Windows\\system32")
end
it "sets the -File flag as the last flag" do
diff --git a/spec/unit/provider/remote_directory_spec.rb b/spec/unit/provider/remote_directory_spec.rb
index 710d6613fc..b6fd4cfc8e 100644
--- a/spec/unit/provider/remote_directory_spec.rb
+++ b/spec/unit/provider/remote_directory_spec.rb
@@ -99,6 +99,21 @@ describe Chef::Provider::RemoteDirectory do
expect(cookbook_file.owner).to eq("toor")
expect(cookbook_file.backup).to eq(23)
end
+
+ it "respects sensitive flag" do
+ @resource.cookbook "gondola_rides"
+ @resource.sensitive true
+ cookbook_file = @provider.send(:cookbook_file_resource,
+ "/target/destination/path.txt",
+ "relative/source/path.txt")
+ expect(cookbook_file.sensitive).to eq(true)
+
+ @resource.sensitive false
+ cookbook_file = @provider.send(:cookbook_file_resource,
+ "/target/destination/path.txt",
+ "relative/source/path.txt")
+ expect(cookbook_file.sensitive).to eq(false)
+ end
end
describe "when creating the remote directory" do
diff --git a/spec/unit/recipe_spec.rb b/spec/unit/recipe_spec.rb
index e5dbd42f70..3c30f96b20 100644
--- a/spec/unit/recipe_spec.rb
+++ b/spec/unit/recipe_spec.rb
@@ -195,9 +195,7 @@ describe Chef::Recipe do
describe "when cloning resources" do
def expect_warning
- expect(Chef::Log).to receive(:warn).with(/3694/)
- expect(Chef::Log).to receive(:warn).with(/Previous/)
- expect(Chef::Log).to receive(:warn).with(/Current/)
+ expect(Chef).to receive(:log_deprecation).with(/^Cloning resource attributes for zen_master\[klopp\]/)
end
it "should emit a 3694 warning when attributes change" do
@@ -244,7 +242,7 @@ describe Chef::Recipe do
it "should not emit a 3694 warning for completely trivial resource cloning" do
recipe.zen_master "klopp"
- expect(Chef::Log).to_not receive(:warn)
+ expect(Chef).to_not receive(:log_deprecation)
recipe.zen_master "klopp"
end
@@ -252,7 +250,7 @@ describe Chef::Recipe do
recipe.zen_master "klopp" do
action :nothing
end
- expect(Chef::Log).to_not receive(:warn)
+ expect(Chef).to_not receive(:log_deprecation)
recipe.zen_master "klopp" do
action :score
end
@@ -262,12 +260,33 @@ describe Chef::Recipe do
recipe.zen_master "klopp" do
action :score
end
- expect(Chef::Log).to_not receive(:warn)
+ expect(Chef).to_not receive(:log_deprecation)
recipe.zen_master "klopp" do
action :nothing
end
end
+ class Coerced < Chef::Resource
+ resource_name :coerced
+ provides :coerced
+ default_action :whatever
+ property :package_name, [String, Array], coerce: proc { |x| [x].flatten }, name_property: true
+ def after_created
+ Array(action).each do |action|
+ run_action(action)
+ end
+ end
+ action :whatever do
+ package_name # unlazy the package_name
+ end
+ end
+
+ it "does not emit 3694 when the name_property is unlazied by running it at compile_time" do
+ recipe.coerced "string"
+ expect(Chef).to_not receive(:log_deprecation)
+ recipe.coerced "string"
+ end
+
it "validating resources via build_resource" do
expect {recipe.build_resource(:remote_file, "klopp") do
source Chef::DelayedEvaluator.new { "http://chef.io" }
@@ -299,6 +318,7 @@ describe Chef::Recipe do
end
it "will insert another resource if create_if_missing is not set (cloned resource as of Chef-12)" do
+ expect(Chef).to receive(:log_deprecation).with(/^Cloning resource attributes for zen_master\[klopp\]/)
zm_resource
recipe.declare_resource(:zen_master, "klopp")
expect(run_context.resource_collection.count).to eql(2)
@@ -421,15 +441,18 @@ describe Chef::Recipe do
end
it "copies attributes from the first resource" do
+ expect(Chef).to receive(:log_deprecation).with(/^Cloning resource attributes for zen_master\[klopp\]/)
expect(duplicated_resource.something).to eq("bvb09")
end
it "does not copy the action from the first resource" do
+ expect(Chef).to receive(:log_deprecation).with(/^Cloning resource attributes for zen_master\[klopp\]/)
expect(original_resource.action).to eq([:score])
expect(duplicated_resource.action).to eq([:nothing])
end
it "does not copy the source location of the first resource" do
+ expect(Chef).to receive(:log_deprecation).with(/^Cloning resource attributes for zen_master\[klopp\]/)
# sanity check source location:
expect(original_resource.source_line).to include(__FILE__)
expect(duplicated_resource.source_line).to include(__FILE__)
@@ -438,10 +461,12 @@ describe Chef::Recipe do
end
it "sets the cookbook name on the cloned resource to that resource's cookbook" do
+ expect(Chef).to receive(:log_deprecation).with(/^Cloning resource attributes for zen_master\[klopp\]/)
expect(duplicated_resource.cookbook_name).to eq("second_cb")
end
it "sets the recipe name on the cloned resource to that resoure's recipe" do
+ expect(Chef).to receive(:log_deprecation).with(/^Cloning resource attributes for zen_master\[klopp\]/)
expect(duplicated_resource.recipe_name).to eq("second_recipe")
end
diff --git a/spec/unit/run_context_spec.rb b/spec/unit/run_context_spec.rb
index 7b2a27e9f6..234cd3c9e1 100644
--- a/spec/unit/run_context_spec.rb
+++ b/spec/unit/run_context_spec.rb
@@ -153,8 +153,8 @@ describe Chef::RunContext do
let(:chef_repo_path) { File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) }
let(:node) {
node = Chef::Node.new
- node.set[:platform] = "ubuntu"
- node.set[:platform_version] = "13.04"
+ node.normal[:platform] = "ubuntu"
+ node.normal[:platform_version] = "13.04"
node.name("testing")
node
}
diff --git a/spec/unit/shell/shell_session_spec.rb b/spec/unit/shell/shell_session_spec.rb
index 22f3dc6f0c..259e6096a4 100644
--- a/spec/unit/shell/shell_session_spec.rb
+++ b/spec/unit/shell/shell_session_spec.rb
@@ -158,7 +158,7 @@ describe Shell::SoloSession do
it "keeps json attribs and passes them to the node for consumption" do
@session.node_attributes = { "besnard_lakes" => "are_the_dark_horse" }
- expect(@session.node.besnard_lakes).to eq("are_the_dark_horse")
+ expect(@session.node["besnard_lakes"]).to eq("are_the_dark_horse")
#pending "1) keep attribs in an ivar 2) pass them to the node 3) feed them to the node on reset"
end
diff --git a/tasks/dependencies.rb b/tasks/dependencies.rb
index eb4bb1f44f..0b216f8e52 100644
--- a/tasks/dependencies.rb
+++ b/tasks/dependencies.rb
@@ -85,13 +85,11 @@ namespace :dependencies do
other_platforms: false, leave_frozen: false
gemfile_lock_task :update_kitchen_tests_gemfile_lock, dirs: %w{
kitchen-tests
- kitchen-tests/test/integration/webapp/serverspec
}
berksfile_lock_task :update_kitchen_tests_berksfile_lock, dirs: %w{
kitchen-tests
kitchen-tests/cookbooks/audit_test
}
- # kitchen-tests/cookbooks/webapp isn't solving right now ....
desc "Update omnibus overrides, including versions in version_policy.rb and latest version of gems: #{OMNIBUS_RUBYGEMS_AT_LATEST_VERSION.keys}."
task :update_omnibus_overrides do |t, rake_args|
diff --git a/version_policy.rb b/version_policy.rb
index 8d450010d3..b8bead7bef 100644
--- a/version_policy.rb
+++ b/version_policy.rb
@@ -26,8 +26,8 @@ OMNIBUS_OVERRIDES = {
## according to comment in omnibus-sw, the very latest versions don't work on solaris
# https://github.com/chef/omnibus-software/blob/aefb7e79d29ca746c3f843673ef5e317fa3cba54/config/software/libtool.rb#L23
"libtool" => "2.4.2",
- "libxml2" => "2.9.3",
- "libxslt" => "1.1.28",
+ "libxml2" => "2.9.4",
+ "libxslt" => "1.1.29",
"libyaml" => "0.1.6",
"makedepend" => "1.0.5",
"ncurses" => "5.9",