summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsawanoboly <sawanoboriyu@higanworks.com>2015-04-21 13:36:03 +0900
committersawanoboly <sawanoboriyu@higanworks.com>2015-04-21 13:36:03 +0900
commit9a26ba99476563b3be7e1ca5f8e8ebbf87a8fc6c (patch)
treeb2a6613acd20b6142f0e4dcd327feaf066a855e7
parent9117b3b7d326948fcbe4da0ea13b0698e1449b9d (diff)
parent4ef31e1c63f02d695fa6f7c8ec3f6cdef0502e1a (diff)
downloadchef-9a26ba99476563b3be7e1ca5f8e8ebbf87a8fc6c.tar.gz
Merge branch 'master' into show_chef_version_on_shell
-rw-r--r--CHANGELOG.md11
-rw-r--r--CHEF_MVPS.md158
-rw-r--r--MAINTAINERS11
-rw-r--r--RELEASE_NOTES.md25
-rw-r--r--lib/chef.rb1
-rw-r--r--lib/chef/chef_class.rb130
-rw-r--r--lib/chef/client.rb19
-rw-r--r--lib/chef/event_loggers/windows_eventlog.rb16
-rw-r--r--lib/chef/exceptions.rb3
-rw-r--r--lib/chef/key.rb251
-rw-r--r--lib/chef/knife/bootstrap/templates/chef-full.erb189
-rw-r--r--lib/chef/mixin/provides.rb32
-rw-r--r--lib/chef/platform/provider_priority_map.rb23
-rw-r--r--lib/chef/platform/resource_priority_map.rb37
-rw-r--r--lib/chef/policy_builder/expand_node_object.rb14
-rw-r--r--lib/chef/policy_builder/policyfile.rb1
-rw-r--r--lib/chef/provider.rb25
-rw-r--r--lib/chef/provider_resolver.rb15
-rw-r--r--lib/chef/resource.rb44
-rw-r--r--lib/chef/resource_resolver.rb101
-rw-r--r--lib/chef/search/query.rb2
-rw-r--r--spec/data/big_json_plus_one.json2
-rw-r--r--spec/data/lwrp/providers/buck_passer.rb3
-rw-r--r--spec/data/lwrp/resources/bar.rb2
-rw-r--r--spec/data/nested.json (renamed from spec/data/big_json.json)4
-rw-r--r--spec/functional/event_loggers/windows_eventlog_spec.rb14
-rw-r--r--spec/functional/resource/execute_spec.rb2
-rw-r--r--spec/unit/chef_class_spec.rb91
-rw-r--r--spec/unit/json_compat_spec.rb27
-rw-r--r--spec/unit/key_spec.rb577
-rw-r--r--spec/unit/provider_resolver_spec.rb1
-rw-r--r--spec/unit/recipe_spec.rb39
-rw-r--r--spec/unit/resource_spec.rb12
-rw-r--r--spec/unit/search/query_spec.rb24
-rw-r--r--spec/unit/shell_spec.rb4
35 files changed, 1695 insertions, 215 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0acc5ba8d2..f56d662d85 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,14 +9,19 @@
Reset $HOME to user running chef-client when running via sudo
* [**Torben Knerr**](https://github.com/tknerr):
Allow for the chef gem installation to succeed without elevated privileges #3126
+* [**Mike Dodge**](https://github.com/mikedodge04)
+ MacOSX services: Load LaunchAgents as console user, adding plist and
+ session_type options.
+
* [pr#3162](https://github.com/chef/chef/pull/3162): Add
`--minimal-ohai` flag to client/solo/apply; restricts ohai to only the
bare minimum of plugins.
* Ensure link's path attribute works with delayed #3130
* gem_package, chef_gem should not shell out to using https://rubygems.org #2867
-* [**Mike Dodge**](https://github.com/mikedodge04)
- MacOSX services: Load LaunchAgents as console user, adding plist and
- session_type options.
+* Add dynamic resource resolution similar to dynamic provider resolution
+* Add Chef class fascade to internal structures
+* Convert bootstrap template to use sh #2877
+* Fix nil pointer for windows event logger #3200
## 12.2.1
* [Issue 3153](https://github.com/chef/chef/issues/3153): Fix bug where unset HOME would cause chef to crash
diff --git a/CHEF_MVPS.md b/CHEF_MVPS.md
index 28dbe3c8e8..dd46ea9174 100644
--- a/CHEF_MVPS.md
+++ b/CHEF_MVPS.md
@@ -2,9 +2,11 @@
Every release of Chef we pick someone from the community to name as the Most Valuable Player for that release. It could be someone who provided a big feature, reported a security vulnerability, or someone doing great things in the community that we want to highlight.
+In addition to the Hall of Fame and MVP recipients, three individuals are awarded the distinction of "Awesome Community Chef" each year at ChefConf.
+
#### Hall of Fame
-After receiving three MVP awards, we add someone to the hall of fame. We want to express our gratitude to their continuing participation and give newer community members the opportunity to be reconignized.
+After receiving three MVP awards, we add someone to the hall of fame. We want to express our gratitude to their continuing participation and give newer community members the opportunity to be recognized.
* Matthew Kent
* Doug MacEachern
@@ -18,71 +20,89 @@ After receiving three MVP awards, we add someone to the hall of fame. We want to
| Release | Date | MVP |
|---------|------|-----|
-| [Client 11.16.0](http://www.getchef.com/blog/2014/09/08/release-chef-client-11-16-0-ohai-7-4-0/) | 2014-09-08 | Jesse Hu |
-| [Client 11.14.2](http://www.getchef.com/blog/2014/08/01/release-chef-client-11-14-2/) | 2014-08-01 | Nikhil Benesch |
-| [Client 11.12.0](http://www.getchef.com/blog/2014/04/08/release-chef-client-11-12-0-10-32-2/) | 2014-04-08 | Chris Bandy |
-| [Client 11.10.4](http://www.getchef.com/blog/2014/02/20/chef-client-patch-release-11-10-4/) | 2014-02-20 | Jon Cowie |
-| [Client 11.10.2](http://www.getchef.com/blog/2014/02/18/chef-client-release-11-10-2-10-30-4/) | 2014-02-18 | Eric Tucker |
-| [Client 11.10.0](http://www.getchef.com/blog/2014/02/06/chef-client-11-10-0-release/) | 2014-02-06 | Nikhil Benesch |
-| [Client 11.8.2](http://www.getchef.com/blog/2013/12/06/release-chef-client-10-30-2-11-8-2-mixlib-shellout-1-3-0/) | 2013-12-06 | James Ogden |
-| [Client 11.8.0](http://www.opscode.com/blog/2013/10/31/release-chef-client-11-8-0-ohai-6-20-0/) | 2013-10-31 | Eric Saxby |
-| [Client 11.6.2](http://www.getchef.com/blog/2013/10/08/release-chef-client-11-6-2-10-28-2/) | 2013-10-08 | Jeff Blaine |
-| [Client 11.6.0](http://www.opscode.com/blog/2013/07/23/chef-client-11-6-0-ohai-6-18-0-and-more/) | 2013-07-23 | Jesse Campbell |
-| [Client 11.4.0](http://www.opscode.com/blog/2013/02/13/chef-client-11-4-0-10-22-0-released/) | 2013-02-13 | Vaidas Jablonskis |
-| [Client 11.2.0](http://www.opscode.com/blog/2013/02/07/chef-client-11-2-0-10-20-0-released/) | 2013-02-06 | Mike Javorski |
-| [Chef 11.0.0](http://www.opscode.com/blog/2013/02/04/chef-11-released/) | 2013-02-04 | Andrea Campi, Bryan Berry |
-| [Chef 10.32.2](http://www.getchef.com/blog/2014/04/08/release-chef-client-11-12-0-10-32-2/) | 2014-04-08 | Phil Dibowitz |
-| [Chef 10.30.4](http://www.getchef.com/blog/2014/02/18/chef-client-release-11-10-2-10-30-4/) | 2014-02-18 | Christopher Laco |
-| [Chef 10.30.2](http://www.getchef.com/blog/2013/12/06/release-chef-client-10-30-2-11-8-2-mixlib-shellout-1-3-0/) | 2013-12-06 | Phil Dibowitz |
-| [Chef 10.28.2](http://www.getchef.com/blog/2013/10/08/release-chef-client-11-6-2-10-28-2/) | 2013-10-08 | Jeff Blaine |
-| [Chef 10.28.0](http://www.opscode.com/blog/2013/09/03/chef-10-28-0-released/) | 2013-09-03 | Jeff Blaine |
-| [Chef 10.26.0](http://www.opscode.com/blog/2013/05/08/chef-10-26-0-released/) | 2013-05-08 | Ranjib Dey |
-| [Chef 10.24.0](http://www.opscode.com/blog/2013/02/15/chef-server-11-0-6-and-10-24-0-released/) | 2013-02-15 | Anthony Goddard |
-| [Chef 10.22.0](http://www.opscode.com/blog/2013/02/13/chef-client-11-4-0-10-22-0-released/) | 2013-02-13 | Brian Bianco |
-| [Chef 10.20.0](http://www.opscode.com/blog/2013/02/07/chef-client-11-2-0-10-20-0-released/) | 2013-02-06 | Chris Roberts |
-| [Chef 10.18.2](http://www.opscode.com/blog/2013/01/18/chef-10-18-2-bugfix-release/) | 2013-01-18 | Fletcher Nichol |
-| [Chef 10.18.0](http://www.opscode.com/blog/2013/01/16/chef-10-18-0-released/) | 2013-01-16 | Xabier de Zuazo |
-| [Chef 10.16.6](http://www.opscode.com/blog/2013/01/11/chef-10-16-6-security-release/) | 2013-01-11 | Dan Kubb |
-| [Chef 10.16.4](http://www.opscode.com/blog/2012/12/26/chef-10-16-4-released/) | 2012-12-26 | Avishai Ish-Shalom |
-| [Chef 10.16.2](http://www.opscode.com/blog/2012/10/26/chef-10-16-2-released/) | 2012-10-26 | Jamie Winsor |
-| [Chef 10.16.0](http://www.opscode.com/blog/2012/10/22/chef-10-16-0-released/) | 2012-10-22 | John Dewey |
-| [Chef 10.14.4](http://www.opscode.com/blog/2012/09/28/chef-10-14-4-released/) | 2012-09-27 | Kendrick Martin |
-| [Chef 10.14.2](http://www.opscode.com/blog/2012/09/11/chef-10-14-2-released/) | 2012-09-10 | Phil Dibowitz, Tim Smith |
-| [Chef 10.14.0](http://www.opscode.com/blog/2012/09/07/chef-10-14-0-released/) | 2012-09-07 | Xabier de Zuazo |
-| [Chef 10.12.0](http://www.opscode.com/blog/2012/06/19/chef-10-12-0-released/) | 2012-06-18 | Chris Roberts |
-| [Chef 0.10.10](http://www.opscode.com/blog/2012/05/11/chef-0-10-10-released/) | 2012-05-11 | Juanje Ojeda, Igor Afonov |
-| [Chef 0.10.8](http://www.opscode.com/blog/2011/12/15/chef-0-10-8-released/) | 2011-12-15 | Bryan Berry |
-| [Chef 0.10.6](http://www.opscode.com/blog/2011/12/14/chef-0-10-6-released/) | 2011-12-13 | Andrea Campi |
-| [Chef 0.10.4](http://www.opscode.com/blog/2011/08/11/chef-0-10-4-released/) | 2011-08-11 | Matthew Kent |
-| [Chef 0.10.2](http://www.opscode.com/blog/2011/06/29/chef-0-10-2-and-0-9-18-released/) | 2011-06-29 | Daniel Oliver |
-| [Chef 0.10.0](http://www.opscode.com/blog/2011/05/02/chef-0-10-0-released/) | 2011-05-02 | Grace Mollison, Darrin Eden |
-| [Chef 0.9.18](http://www.opscode.com/blog/2011/06/29/chef-0-10-2-and-0-9-18-released/) | 2011-06-29 | Jesai Langenbach |
-| [Chef 0.9.16](http://www.opscode.com/blog/2011/04/15/chef-0-9-16-released/) | 2011-04-15 | Michael Leinartas |
-| [Chef 0.9.14](http://www.opscode.com/blog/2011/03/04/chef-0-9-14-released/) | 2011-03-04 | Gilles Devaux |
-| [Chef 0.9.12](http://www.opscode.com/blog/2010/10/22/chef-0-9-12-released/) | 2010-10-22 | Laurent Désarmes |
-| [Chef 0.9.10](http://www.opscode.com/blog/2010/10/19/chef-0-9-10-ohai-0-5-8-and-mixliblog-1-2-0-released/) | 2010-10-19 | Toomas Pelberg, Tommy Bishop |
-| [Chef 0.9.8](http://www.opscode.com/blog/2010/08/05/chef-0-9-8-and-mixlib-authentication-1-1-4-released/) | 2010-08-05 | Joe Williams |
-| [Chef 0.9.6](http://www.opscode.com/blog/2010/07/03/chef-0-9-6-released/) | 2010-07-03 | Caleb Tennis |
-| [Chef 0.9.4](http://www.opscode.com/blog/2010/06/30/chef-0-9-4-released/) | 2010-06-30 | Ian Meyer |
-| [Chef 0.9.0](http://www.opscode.com/blog/2010/06/21/chef-0-9-0-and-ohai-0-5-6-released/) | 2010-06-21 | Doug MacEachern |
-| [Chef 0.8.16](http://www.opscode.com/blog/2010/05/11/chef-0-8-16-and-ohai-0-5-4-release/) | 2010-05-11 | Akzhan Abdulin |
-| [Chef 0.8.14](http://www.opscode.com/blog/2010/05/07/chef-0-8-14-release/) | 2010-05-07 | Renaud Chaput |
-| [Chef 0.8.10](http://www.opscode.com/blog/2010/04/02/chef-0-8-10-release/) | 2010-04-02 | Thom May, Tollef Fog Heen |
-| [Chef 0.8.8](http://www.opscode.com/blog/2010/03/18/chef-0-8-8-release/) | 2010-03-18 | Eric Hankins |
-| [Chef 0.8.6](http://www.opscode.com/blog/2010/03/05/chef-0-8-6-release/) | 2010-03-05 | Ian Meyer |
-| [Chef 0.8.4](http://www.opscode.com/blog/2010/03/02/chef-0-8-4-release/) | 2010-03-02 | Tollef Fog Heen |
-| [Chef 0.8.2](http://www.opscode.com/blog/2010/03/01/chef-0-8-2-release/) | 2010-03-01 | Scott M. Likens |
-| [Chef 0.7.16](http://www.opscode.com/blog/2009/12/22/chef-0-7-16-release/) | 2009-12-22 | Bryan McLellan |
-| [Chef 0.7.14](http://www.opscode.com/blog/2009/10/26/chef-0-7-14-ohai-0-3-6-releases/) | 2009-10-16 | Thom May |
-| [Chef 0.7.12](http://www.opscode.com/blog/2009/10/06/chef-0-7-12rc0-ohai-0-3-4rc0-releases/) | 2009-10-06 | Diego Algorta |
-| [Chef 0.7.10](http://www.opscode.com/blog/2009/09/04/chef-0-7-10-release/) | 2009-09-04 | Dan DeLeo |
-| [Chef 0.7.8](http://www.opscode.com/blog/2009/08/13/chef-0-7-8-release/) | 2009-08-13 | Jeppe Nejsum Madsen |
-| [Chef 0.7.6](http://www.opscode.com/blog/2009/08/08/chef-0-7-6-release/) | 2009-08-08 | Grant Zanetti |
-| [Chef 0.7.4](http://www.opscode.com/blog/2009/06/26/back-to-back-chef-0-7-2-and-chef-0-7-4-released/) | 2009-06-26 | Hongli Lai |
-| [Chef 0.7.2](http://www.opscode.com/blog/2009/06/26/back-to-back-chef-0-7-2-and-chef-0-7-4-released/) | 2009-06-26 | Joshua Sierles |
-| [Chef 0.7.0](http://www.opscode.com/blog/2009/06/10/chef-0-7-0-release/) | 2009-06-10 | Matthew Kent |
-| [Chef 0.6.2](http://www.opscode.com/blog/2009/04/29/chef-0-6-2-release/) | 2009-04-29 | David Balatero |
-| [Chef 0.6.0](http://www.opscode.com/blog/2009/04/29/chef-0-6-0-release/) | 2009-04-29 | Matthew Kent |
-| [Chef 0.5.6](http://www.opscode.com/blog/2009/03/06/chef-0-5-6/) | 2009-03-06 | Sean Cribbs |
-| [Chef 0.5.4](http://www.opscode.com/blog/2009/02/13/chef-0-5-4/) | 2009-02-13 | Arjuna Christensen |
-| [Chef 0.5.2](http://www.opscode.com/blog/2009/02/01/chef-0-5-2-and-ohai-0-1-4/) | 2009-02-01 | Bryan McLellan |
+| [Client 11.16.0](https://www.chef.io/blog/2014/09/08/release-chef-client-11-16-0-ohai-7-4-0/) | 2014-09-08 | Jesse Hu |
+| [Client 11.14.2](https://www.chef.io/blog/2014/08/01/release-chef-client-11-14-2/) | 2014-08-01 | Nikhil Benesch |
+| [Client 11.12.0](https://www.chef.io/blog/2014/04/08/release-chef-client-11-12-0-10-32-2/) | 2014-04-08 | Chris Bandy |
+| [Client 11.10.4](https://www.chef.io/blog/2014/02/20/chef-client-patch-release-11-10-4/) | 2014-02-20 | Jon Cowie |
+| [Client 11.10.2](https://www.chef.io/blog/2014/02/18/chef-client-release-11-10-2-10-30-4/) | 2014-02-18 | Eric Tucker |
+| [Client 11.10.0](https://www.chef.io/blog/2014/02/06/chef-client-11-10-0-release/) | 2014-02-06 | Nikhil Benesch |
+| [Client 11.8.2](https://www.chef.io/blog/2013/12/06/release-chef-client-10-30-2-11-8-2-mixlib-shellout-1-3-0/) | 2013-12-06 | James Ogden |
+| [Client 11.8.0](https://www.chef.io/blog/2013/10/31/release-chef-client-11-8-0-ohai-6-20-0/) | 2013-10-31 | Eric Saxby |
+| [Client 11.6.2](https://www.chef.io/blog/2013/10/08/release-chef-client-11-6-2-10-28-2/) | 2013-10-08 | Jeff Blaine |
+| [Client 11.6.0](https://www.chef.io/blog/2013/07/23/chef-client-11-6-0-ohai-6-18-0-and-more/) | 2013-07-23 | Jesse Campbell |
+| [Client 11.4.0](https://www.chef.io/blog/2013/02/13/chef-client-11-4-0-10-22-0-released/) | 2013-02-13 | Vaidas Jablonskis |
+| [Client 11.2.0](https://www.chef.io/blog/2013/02/07/chef-client-11-2-0-10-20-0-released/) | 2013-02-06 | Mike Javorski |
+| [Chef 11.0.0](https://www.chef.io/blog/2013/02/04/chef-11-released/) | 2013-02-04 | Andrea Campi, Bryan Berry |
+| [Chef 10.32.2](https://www.chef.io/blog/2014/04/08/release-chef-client-11-12-0-10-32-2/) | 2014-04-08 | Phil Dibowitz |
+| [Chef 10.30.4](https://www.chef.io/blog/2014/02/18/chef-client-release-11-10-2-10-30-4/) | 2014-02-18 | Christopher Laco |
+| [Chef 10.30.2](https://www.chef.io/blog/2013/12/06/release-chef-client-10-30-2-11-8-2-mixlib-shellout-1-3-0/) | 2013-12-06 | Phil Dibowitz |
+| [Chef 10.28.2](https://www.chef.io/blog/2013/10/08/release-chef-client-11-6-2-10-28-2/) | 2013-10-08 | Jeff Blaine |
+| [Chef 10.28.0](https://www.chef.io/blog/2013/09/03/chef-10-28-0-released/) | 2013-09-03 | Jeff Blaine |
+| [Chef 10.26.0](https://www.chef.io/blog/2013/05/08/chef-10-26-0-released/) | 2013-05-08 | Ranjib Dey |
+| [Chef 10.24.0](https://www.chef.io/blog/2013/02/15/chef-server-11-0-6-and-10-24-0-released/) | 2013-02-15 | Anthony Goddard |
+| [Chef 10.22.0](https://www.chef.io/blog/2013/02/13/chef-client-11-4-0-10-22-0-released/) | 2013-02-13 | Brian Bianco |
+| [Chef 10.20.0](https://www.chef.io/blog/2013/02/07/chef-client-11-2-0-10-20-0-released/) | 2013-02-06 | Chris Roberts |
+| [Chef 10.18.2](https://www.chef.io/blog/2013/01/18/chef-10-18-2-bugfix-release/) | 2013-01-18 | Fletcher Nichol |
+| [Chef 10.18.0](https://www.chef.io/blog/2013/01/16/chef-10-18-0-released/) | 2013-01-16 | Xabier de Zuazo |
+| [Chef 10.16.6](https://www.chef.io/blog/2013/01/11/chef-10-16-6-security-release/) | 2013-01-11 | Dan Kubb |
+| [Chef 10.16.4](https://www.chef.io/blog/2012/12/26/chef-10-16-4-released/) | 2012-12-26 | Avishai Ish-Shalom |
+| [Chef 10.16.2](https://www.chef.io/blog/2012/10/26/chef-10-16-2-released/) | 2012-10-26 | Jamie Winsor |
+| [Chef 10.16.0](https://www.chef.io/blog/2012/10/22/chef-10-16-0-released/) | 2012-10-22 | John Dewey |
+| [Chef 10.14.4](https://www.chef.io/blog/2012/09/28/chef-10-14-4-released/) | 2012-09-27 | Kendrick Martin |
+| [Chef 10.14.2](https://www.chef.io/blog/2012/09/11/chef-10-14-2-released/) | 2012-09-10 | Phil Dibowitz, Tim Smith |
+| [Chef 10.14.0](https://www.chef.io/blog/2012/09/07/chef-10-14-0-released/) | 2012-09-07 | Xabier de Zuazo |
+| [Chef 10.12.0](https://www.chef.io/blog/2012/06/19/chef-10-12-0-released/) | 2012-06-18 | Chris Roberts |
+| [Chef 0.10.10](https://www.chef.io/blog/2012/05/11/chef-0-10-10-released/) | 2012-05-11 | Juanje Ojeda, Igor Afonov |
+| [Chef 0.10.8](https://www.chef.io/blog/2011/12/15/chef-0-10-8-released/) | 2011-12-15 | Bryan Berry |
+| [Chef 0.10.6](https://www.chef.io/blog/2011/12/14/chef-0-10-6-released/) | 2011-12-13 | Andrea Campi |
+| [Chef 0.10.4](https://www.chef.io/blog/2011/08/11/chef-0-10-4-released/) | 2011-08-11 | Matthew Kent |
+| [Chef 0.10.2](https://www.chef.io/blog/2011/06/29/chef-0-10-2-and-0-9-18-released/) | 2011-06-29 | Daniel Oliver |
+| [Chef 0.10.0](https://www.chef.io/blog/2011/05/02/chef-0-10-0-released/) | 2011-05-02 | Grace Mollison, Darrin Eden |
+| [Chef 0.9.18](https://www.chef.io/blog/2011/06/29/chef-0-10-2-and-0-9-18-released/) | 2011-06-29 | Jesai Langenbach |
+| [Chef 0.9.16](https://www.chef.io/blog/2011/04/15/chef-0-9-16-released/) | 2011-04-15 | Michael Leinartas |
+| [Chef 0.9.14](https://www.chef.io/blog/2011/03/04/chef-0-9-14-released/) | 2011-03-04 | Gilles Devaux |
+| [Chef 0.9.12](https://www.chef.io/blog/2010/10/22/chef-0-9-12-released/) | 2010-10-22 | Laurent Désarmes |
+| [Chef 0.9.10](https://www.chef.io/blog/2010/10/19/chef-0-9-10-ohai-0-5-8-and-mixliblog-1-2-0-released/) | 2010-10-19 | Toomas Pelberg, Tommy Bishop |
+| [Chef 0.9.8](https://www.chef.io/blog/2010/08/05/chef-0-9-8-and-mixlib-authentication-1-1-4-released/) | 2010-08-05 | Joe Williams |
+| [Chef 0.9.6](https://www.chef.io/blog/2010/07/03/chef-0-9-6-released/) | 2010-07-03 | Caleb Tennis |
+| [Chef 0.9.4](https://www.chef.io/blog/2010/06/30/chef-0-9-4-released/) | 2010-06-30 | Ian Meyer |
+| [Chef 0.9.0](https://www.chef.io/blog/2010/06/21/chef-0-9-0-and-ohai-0-5-6-released/) | 2010-06-21 | Doug MacEachern |
+| [Chef 0.8.16](https://www.chef.io/blog/2010/05/11/chef-0-8-16-and-ohai-0-5-4-release/) | 2010-05-11 | Akzhan Abdulin |
+| [Chef 0.8.14](https://www.chef.io/blog/2010/05/07/chef-0-8-14-release/) | 2010-05-07 | Renaud Chaput |
+| [Chef 0.8.10](https://www.chef.io/blog/2010/04/02/chef-0-8-10-release/) | 2010-04-02 | Thom May, Tollef Fog Heen |
+| [Chef 0.8.8](https://www.chef.io/blog/2010/03/18/chef-0-8-8-release/) | 2010-03-18 | Eric Hankins |
+| [Chef 0.8.6](https://www.chef.io/blog/2010/03/05/chef-0-8-6-release/) | 2010-03-05 | Ian Meyer |
+| [Chef 0.8.4](https://www.chef.io/blog/2010/03/02/chef-0-8-4-release/) | 2010-03-02 | Tollef Fog Heen |
+| [Chef 0.8.2](https://www.chef.io/blog/2010/03/01/chef-0-8-2-release/) | 2010-03-01 | Scott M. Likens |
+| [Chef 0.7.16](https://www.chef.io/blog/2009/12/22/chef-0-7-16-release/) | 2009-12-22 | Bryan McLellan |
+| [Chef 0.7.14](https://www.chef.io/blog/2009/10/26/chef-0-7-14-ohai-0-3-6-releases/) | 2009-10-16 | Thom May |
+| [Chef 0.7.12](https://www.chef.io/blog/2009/10/06/chef-0-7-12rc0-ohai-0-3-4rc0-releases/) | 2009-10-06 | Diego Algorta |
+| [Chef 0.7.10](https://www.chef.io/blog/2009/09/04/chef-0-7-10-release/) | 2009-09-04 | Dan DeLeo |
+| [Chef 0.7.8](https://www.chef.io/blog/2009/08/13/chef-0-7-8-release/) | 2009-08-13 | Jeppe Nejsum Madsen |
+| [Chef 0.7.6](https://www.chef.io/blog/2009/08/08/chef-0-7-6-release/) | 2009-08-08 | Grant Zanetti |
+| [Chef 0.7.4](https://www.chef.io/blog/2009/06/26/back-to-back-chef-0-7-2-and-chef-0-7-4-released/) | 2009-06-26 | Hongli Lai |
+| [Chef 0.7.2](https://www.chef.io/blog/2009/06/26/back-to-back-chef-0-7-2-and-chef-0-7-4-released/) | 2009-06-26 | Joshua Sierles |
+| [Chef 0.7.0](https://www.chef.io/blog/2009/06/10/chef-0-7-0-release/) | 2009-06-10 | Matthew Kent |
+| [Chef 0.6.2](https://www.chef.io/blog/2009/04/29/chef-0-6-2-release/) | 2009-04-29 | David Balatero |
+| [Chef 0.6.0](https://www.chef.io/blog/2009/04/29/chef-0-6-0-release/) | 2009-04-29 | Matthew Kent |
+| [Chef 0.5.6](https://www.chef.io/blog/2009/03/06/chef-0-5-6/) | 2009-03-06 | Sean Cribbs |
+| [Chef 0.5.4](https://www.chef.io/blog/2009/02/13/chef-0-5-4/) | 2009-02-13 | Arjuna Christensen |
+| [Chef 0.5.2](https://www.chef.io/blog/2009/02/01/chef-0-5-2-and-ohai-0-1-4/) | 2009-02-01 | Bryan McLellan |
+
+#### Awesome Community Chefs
+
+Each year at ChefConf, three individuals are awarded the Awesome Community Chef award. The Awesome Community Chef awards are a way for the community to recognize a few of the individuals who have made a dramatic impact and have helped further the cause.
+
+* 2013
+ * [Bryan Berry](https://github.com/bryanwb)
+ * [Fletcher Nichol](https://github.com/fnichol)
+ * [Jamie Winsor](https://github.com/reset)
+* 2014
+ * [Ranjib Dey](https://github.com/ranjib)
+ * [Miah Johnson](https://github.com/miah)
+ * [Seth Vargo](https://github.com/sethvargo)
+ * [Eric Wolfe](https://github.com/atomic-penguin)
+* 2015
+ * [Jon Cowie](https://github.com/jonlives)
+ * [Noah Kantrowitz](https://github.com/coderanger)
+ * [Matt Wrock](https://github.com/mwrock) \ No newline at end of file
diff --git a/MAINTAINERS b/MAINTAINERS
index 6ab4a64a80..00268f3624 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -137,7 +137,8 @@ The specific components of Chef related to a given platform - including (but not
lieutenant = "martinisoft"
maintainers = [
- "Aevin1387"
+ "Aevin1387",
+ "tBunnyMan"
]
@@ -205,7 +206,13 @@ The specific components of Chef related to a given platform - including (but not
[people.stevendanna]
Name = Steven Danna
GitHub = stevendanna
-
+
+ [people.tBunnyMan]
+ Name = David Aronsohn
+ GitHub = tbunnyman
+ IRC = tBunnyMan
+ Twitter = OnlyHaveCans
+
[people.thommay]
Name = Thom May
GitHub = thommay
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 510e457b33..8a7b537670 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -18,3 +18,28 @@ however advanced users may find it useful in certain use cases. Any
cookbook that relies on other ohai data will absolutely not work in this
mode unless the user implements workarounds such as running the ohai
resource during the compile phase.
+
+## Dynamic Resource Resolution and Chef Class Fascade
+
+Resolution of Resources is now dynamic and similar to Providers and handles
+multiple resources having the same provides line on a given platform. When
+the user types a resource like 'package' into the DSL that is resolved via
+the provides lines, and if multiple classes provide the same resource (like
+Homebrew and MacPorts package resources on Mac) then which one is selected
+is governed by the Chef::Platform::ResourcePriorityMap.
+
+In order to change the priorities in both the ResourcePriorityMap and
+ProviderPriorityMap a helper API has been constructed off of the Chef class:
+
+* `Chef.get_provider_priority_array(resource_name)`
+* `Chef.get_resource_priority_array(resource_name)`
+* `Chef.set_provider_priority_array(resource_name, Array<Class>, *filter)`
+* `Chef.set_resoruce_priority_array(resource_name, Array<Class>, *filter)`
+
+In order to change the `package` resource globally on MacOSX to the MacPorts provider:
+
+`Chef.set_resource_priority_array(:package, [ Chef::Resource::MacportsPackage ], os: 'darwin')`
+
+That line can be placed into a library file in a cookbook so that it is applied before
+any recipes are compiled.
+
diff --git a/lib/chef.rb b/lib/chef.rb
index 7f54b91f14..6bce976439 100644
--- a/lib/chef.rb
+++ b/lib/chef.rb
@@ -32,3 +32,4 @@ require 'chef/run_status'
require 'chef/handler'
require 'chef/handler/json_file'
+require 'chef/chef_class'
diff --git a/lib/chef/chef_class.rb b/lib/chef/chef_class.rb
new file mode 100644
index 0000000000..d3f7ee55c7
--- /dev/null
+++ b/lib/chef/chef_class.rb
@@ -0,0 +1,130 @@
+#
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# NOTE: This class is not intended for internal use by the chef-client code. Classes in
+# chef-client should still have objects like the node and run_context injected into them
+# via their initializers. This class is still global state and will complicate writing
+# unit tests for internal Chef objects. It is intended to be used only by recipe code.
+
+# NOTE: When adding require lines here you are creating tight coupling on a global that may be
+# included in many different situations and ultimately that ends in tears with circular requires.
+# Note the way that the run_context, provider_priority_map and resource_priority_map are "dependency
+# injected" into this class by other objects and do not reference the class symbols in those files
+# directly and we do not need to require those files here.
+
+class Chef
+ class << self
+
+ #
+ # Public API
+ #
+
+ # Get the node object
+ #
+ # @return [Chef::Node] node object of the chef-client run
+ attr_reader :node
+
+ # Get the run context
+ #
+ # @return [Chef::RunContext] run_context of the chef-client run
+ attr_reader :run_context
+
+ # Get the array of providers associated with a resource_name for the current node
+ #
+ # @param resource_name [Symbol] name of the resource as a symbol
+ # @return [Array<Class>] Priority Array of Provider Classes to use for the resource_name on the node
+ def get_provider_priority_array(resource_name)
+ @provider_priority_map.get_priority_array(node, resource_name).dup
+ end
+
+ # Get the array of resources associated with a resource_name for the current node
+ #
+ # @param resource_name [Symbol] name of the resource as a symbol
+ # @return [Array<Class>] Priority Array of Resource Classes to use for the resource_name on the node
+ def get_resource_priority_array(resource_name)
+ @resource_priority_map.get_priority_array(node, resource_name).dup
+ end
+
+ # Set the array of providers associated with a resource_name for the current node
+ #
+ # @param resource_name [Symbol] name of the resource as a symbol
+ # @param priority_array [Array<Class>] Array of Classes to set as the priority for resource_name on the node
+ # @param filter [Hash] Chef::Nodearray-style filter
+ # @return [Array<Class>] Modified Priority Array of Provider Classes to use for the resource_name on the node
+ def set_provider_priority_array(resource_name, priority_array, *filter)
+ @provider_priority_map.set_priority_array(resource_name, priority_array, *filter).dup
+ end
+
+ # Get the array of resources associated with a resource_name for the current node
+ #
+ # @param resource_name [Symbol] name of the resource as a symbol
+ # @param priority_array [Array<Class>] Array of Classes to set as the priority for resource_name on the node
+ # @param filter [Hash] Chef::Nodearray-style filter
+ # @return [Array<Class>] Modified Priority Array of Resource Classes to use for the resource_name on the node
+ def set_resource_priority_array(resource_name, priority_array, *filter)
+ @resource_priority_map.set_priority_array(resource_name, priority_array, *filter).dup
+ end
+
+ #
+ # Dependency Injection API (Private not Public)
+ # [ in the ruby sense these have to be public methods, but they are
+ # *NOT* for public consumption ]
+ #
+
+ # Sets the resource_priority_map
+ #
+ # @api private
+ # @param resource_priority_map [Chef::Platform::ResourcePriorityMap]
+ def set_resource_priority_map(resource_priority_map)
+ @resource_priority_map = resource_priority_map
+ end
+
+ # Sets the provider_priority_map
+ #
+ # @api private
+ # @param provider_priority_map [Chef::Platform::providerPriorityMap]
+ def set_provider_priority_map(provider_priority_map)
+ @provider_priority_map = provider_priority_map
+ end
+
+ # Sets the node object
+ #
+ # @api private
+ # @param node [Chef::Node]
+ def set_node(node)
+ @node = node
+ end
+
+ # Sets the run_context object
+ #
+ # @api private
+ # @param run_context [Chef::RunContext]
+ def set_run_context(run_context)
+ @run_context = run_context
+ end
+
+ # Resets the internal state
+ #
+ # @api private
+ def reset!
+ @run_context = nil
+ @node = nil
+ @provider_priority_map = nil
+ @resource_priority_map = nil
+ end
+ end
+end
diff --git a/lib/chef/client.rb b/lib/chef/client.rb
index a4f15c271f..d04a3dbbd5 100644
--- a/lib/chef/client.rb
+++ b/lib/chef/client.rb
@@ -166,6 +166,13 @@ class Chef
if new_runlist = args.delete(:runlist)
@json_attribs["run_list"] = new_runlist
end
+
+ # these slurp in the resource+provider world, so be exceedingly lazy about requiring them
+ require 'chef/platform/provider_priority_map' unless defined? Chef::Platform::ProviderPriorityMap
+ require 'chef/platform/resource_priority_map' unless defined? Chef::Platform::ResourcePriorityMap
+
+ Chef.set_provider_priority_map(Chef::Platform::ProviderPriorityMap.instance)
+ Chef.set_resource_priority_map(Chef::Platform::ResourcePriorityMap.instance)
end
def configure_formatters
@@ -224,21 +231,21 @@ class Chef
end
# Instantiates a Chef::Node object, possibly loading the node's prior state
- # when using chef-client. Delegates to policy_builder
- #
+ # when using chef-client. Delegates to policy_builder. Injects the built node
+ # into the Chef class.
#
- # === Returns
- # Chef::Node:: The node object for this chef run
+ # @return [Chef::Node] The node object for this Chef run
def load_node
policy_builder.load_node
@node = policy_builder.node
+ Chef.set_node(@node)
+ node
end
# Mutates the `node` object to prepare it for the chef run. Delegates to
# policy_builder
#
- # === Returns
- # Chef::Node:: The updated node object
+ # @return [Chef::Node] The updated node object
def build_node
policy_builder.build_node
@run_status = Chef::RunStatus.new(node, events)
diff --git a/lib/chef/event_loggers/windows_eventlog.rb b/lib/chef/event_loggers/windows_eventlog.rb
index 6f5ef627fb..37dcdc8693 100644
--- a/lib/chef/event_loggers/windows_eventlog.rb
+++ b/lib/chef/event_loggers/windows_eventlog.rb
@@ -88,15 +88,21 @@ class Chef
#Exception message: %4
#Exception backtrace: %5
def run_failed(e)
+ data =
+ if @run_status
+ [@run_status.run_id,
+ @run_status.elapsed_time.to_s]
+ else
+ ["UNKNOWN", "UNKNOWN"]
+ end
+
@eventlog.report_event(
:event_type => ::Win32::EventLog::ERROR_TYPE,
:source => SOURCE,
:event_id => RUN_FAILED_EVENT_ID,
- :data => [@run_status.run_id,
- @run_status.elapsed_time.to_s,
- e.class.name,
- e.message,
- e.backtrace.join("\n")]
+ :data => data + [e.class.name,
+ e.message,
+ e.backtrace.join("\n")]
)
end
diff --git a/lib/chef/exceptions.rb b/lib/chef/exceptions.rb
index eea6a2f239..cfedbfd0d9 100644
--- a/lib/chef/exceptions.rb
+++ b/lib/chef/exceptions.rb
@@ -69,6 +69,9 @@ class Chef
class ValidationFailed < ArgumentError; end
class InvalidPrivateKey < ArgumentError; end
class ConfigurationError < ArgumentError; end
+ class MissingKeyAttribute < ArgumentError; end
+ class InvalidKeyArgument < ArgumentError; end
+ class InvalidKeyAttribute < ArgumentError; end
class RedirectLimitExceeded < RuntimeError; end
class AmbiguousRunlistSpecification < ArgumentError; end
class CookbookFrozen < ArgumentError; end
diff --git a/lib/chef/key.rb b/lib/chef/key.rb
new file mode 100644
index 0000000000..1828713386
--- /dev/null
+++ b/lib/chef/key.rb
@@ -0,0 +1,251 @@
+#
+# Author:: Tyler Cloke (tyler@chef.io)
+# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/json_compat'
+require 'chef/mixin/params_validate'
+require 'chef/exceptions'
+
+class Chef
+ # Class for interacting with a chef key object. Can be used to create new keys,
+ # save to server, load keys from server, list keys, delete keys, etc.
+ #
+ # @author Tyler Cloke
+ #
+ # @attr [String] actor the name of the client or user that this key is for
+ # @attr [String] name the name of the key
+ # @attr [String] public_key the RSA string of this key
+ # @attr [String] private_key the RSA string of the private key if returned via a POST or PUT
+ # @attr [String] expiration_date the ISO formatted string YYYY-MM-DDTHH:MM:SSZ, i.e. 2020-12-24T21:00:00Z
+ # @attr [String] rest Chef::REST object, initialized and cached via chef_rest method
+ # @attr [string] api_base either "users" or "clients", initialized and cached via api_base method
+ #
+ # @attr_reader [String] actor_field_name must be either 'client' or 'user'
+ class Key
+
+ include Chef::Mixin::ParamsValidate
+
+ attr_reader :actor_field_name
+
+ def initialize(actor, actor_field_name)
+ # Actor that the key is for, either a client or a user.
+ @actor = actor
+
+ unless actor_field_name == "user" || actor_field_name == "client"
+ raise Chef::Exceptions::InvalidKeyArgument, "the second argument to initialize must be either 'user' or 'client'"
+ end
+
+ @actor_field_name = actor_field_name
+
+ @name = nil
+ @public_key = nil
+ @private_key = nil
+ @expiration_date = nil
+ @create_key = nil
+ end
+
+ def chef_rest
+ @rest ||= if @actor_field_name == "user"
+ Chef::REST.new(Chef::Config[:chef_server_root])
+ else
+ Chef::REST.new(Chef::Config[:chef_server_url])
+ end
+ end
+
+ def api_base
+ @api_base ||= if @actor_field_name == "user"
+ "users"
+ else
+ "clients"
+ end
+ end
+
+ def actor(arg=nil)
+ set_or_return(:actor, arg,
+ :regex => /^[a-z0-9\-_]+$/)
+ end
+
+ def name(arg=nil)
+ set_or_return(:name, arg,
+ :kind_of => String)
+ end
+
+ def public_key(arg=nil)
+ raise Chef::Exceptions::InvalidKeyAttribute, "you cannot set the public_key if create_key is true" if !arg.nil? && @create_key
+ set_or_return(:public_key, arg,
+ :kind_of => String)
+ end
+
+ def private_key(arg=nil)
+ set_or_return(:private_key, arg,
+ :kind_of => String)
+ end
+
+ def delete_public_key
+ @public_key = nil
+ end
+
+ def create_key(arg=nil)
+ raise Chef::Exceptions::InvalidKeyAttribute, "you cannot set create_key to true if the public_key field exists" if arg == true && !@public_key.nil?
+ set_or_return(:create_key, arg,
+ :kind_of => [TrueClass, FalseClass])
+ end
+
+ def expiration_date(arg=nil)
+ set_or_return(:expiration_date, arg,
+ :regex => /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z|infinity)$/)
+ end
+
+ def to_hash
+ result = {
+ @actor_field_name => @actor
+ }
+ result["name"] = @name if @name
+ result["public_key"] = @public_key if @public_key
+ result["private_key"] = @private_key if @private_key
+ result["expiration_date"] = @expiration_date if @expiration_date
+ result["create_key"] = @create_key if @create_key
+ result
+ end
+
+ def to_json(*a)
+ Chef::JSONCompat.to_json(to_hash, *a)
+ end
+
+ def create
+ # if public_key is undefined and create_key is false, we cannot create
+ if @public_key.nil? && !@create_key
+ raise Chef::Exceptions::MissingKeyAttribute, "either public_key must be defined or create_key must be true"
+ end
+
+ # defaults the key name to the fingerprint of the key
+ if @name.nil?
+ # if they didn't pass a public_key,
+ #then they must supply a name because we can't generate a fingerprint
+ unless @public_key.nil?
+ @name = fingerprint
+ else
+ raise Chef::Exceptions::MissingKeyAttribute, "a name cannot be auto-generated if no public key passed, either pass a public key or supply a name"
+ end
+ end
+
+ payload = {"name" => @name}
+ payload['public_key'] = @public_key unless @public_key.nil?
+ payload['create_key'] = @create_key if @create_key
+ payload['expiration_date'] = @expiration_date unless @expiration_date.nil?
+ new_key = chef_rest.post_rest("#{api_base}/#{@actor}/keys", payload)
+ Chef::Key.from_hash(new_key)
+ end
+
+ def fingerprint
+ self.class.generate_fingerprint(@public_key)
+ end
+
+ def update
+ if @name.nil?
+ raise Chef::Exceptions::MissingKeyAttribute, "the name field must be populated when update is called"
+ end
+
+ new_key = chef_rest.put_rest("#{api_base}/#{@actor}/keys/#{@name}", to_hash)
+ Chef::Key.from_hash(self.to_hash.merge(new_key))
+ end
+
+ def save
+ create
+ rescue Net::HTTPServerException => e
+ if e.response.code == "409"
+ update
+ else
+ raise e
+ end
+ end
+
+ def destroy
+ if @name.nil?
+ raise Chef::Exceptions::MissingKeyAttribute, "the name field must be populated when delete is called"
+ end
+
+ chef_rest.delete_rest("#{api_base}/#{@actor}/keys/#{@name}")
+ end
+
+ # Class methods
+ def self.from_hash(key_hash)
+ if key_hash.has_key?("user")
+ key = Chef::Key.new(key_hash["user"], "user")
+ else
+ key = Chef::Key.new(key_hash["client"], "client")
+ end
+ key.name key_hash['name'] if key_hash.key?('name')
+ key.public_key key_hash['public_key'] if key_hash.key?('public_key')
+ key.private_key key_hash['private_key'] if key_hash.key?('private_key')
+ key.create_key key_hash['create_key'] if key_hash.key?('create_key')
+ key.expiration_date key_hash['expiration_date'] if key_hash.key?('expiration_date')
+ key
+ end
+
+ def self.from_json(json)
+ Chef::Key.from_hash(Chef::JSONCompat.from_json(json))
+ end
+
+ class << self
+ alias_method :json_create, :from_json
+ end
+
+ def self.list_by_user(actor, inflate=false)
+ keys = Chef::REST.new(Chef::Config[:chef_server_root]).get_rest("users/#{actor}/keys")
+ self.list(keys, actor, :load_by_user, inflate)
+ end
+
+ def self.list_by_client(actor, inflate=false)
+ keys = Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("clients/#{actor}/keys")
+ self.list(keys, actor, :load_by_client, inflate)
+ end
+
+ def self.load_by_user(actor, key_name)
+ response = Chef::REST.new(Chef::Config[:chef_server_root]).get_rest("users/#{actor}/keys/#{key_name}")
+ Chef::Key.from_hash(response)
+ end
+
+ def self.load_by_client(actor, key_name)
+ response = Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("clients/#{actor}/keys/#{key_name}")
+ Chef::Key.from_hash(response)
+ end
+
+ def self.generate_fingerprint(public_key)
+ openssl_key_object = OpenSSL::PKey::RSA.new(public_key)
+ data_string = OpenSSL::ASN1::Sequence([
+ OpenSSL::ASN1::Integer.new(openssl_key_object.public_key.n),
+ OpenSSL::ASN1::Integer.new(openssl_key_object.public_key.e)
+ ])
+ OpenSSL::Digest::SHA1.hexdigest(data_string.to_der).scan(/../).join(':')
+ end
+
+ private
+
+ def self.list(keys, actor, load_method_symbol, inflate)
+ if inflate
+ keys.inject({}) do |key_map, result|
+ name = result["name"]
+ key_map[name] = Chef::Key.send(load_method_symbol, actor, name)
+ key_map
+ end
+ else
+ keys
+ end
+ end
+ end
+end
diff --git a/lib/chef/knife/bootstrap/templates/chef-full.erb b/lib/chef/knife/bootstrap/templates/chef-full.erb
index a87ab8e544..335b1f181c 100644
--- a/lib/chef/knife/bootstrap/templates/chef-full.erb
+++ b/lib/chef/knife/bootstrap/templates/chef-full.erb
@@ -1,15 +1,16 @@
-bash -c '
+sh -c '
<%= "export https_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%>
-distro=`uname -s`
-
-if test "x$distro" = "xSunOS"; then
- if test -d "/usr/sfw/bin"; then
- PATH=/usr/sfw/bin:$PATH
- export PATH
- fi
+if test "x$TMPDIR" = "x"; then
+ tmp="/tmp"
+else
+ tmp=$TMPDIR
fi
+# secure-ish temp dir creation without having mktemp available (DDoS-able but not exploitable)
+tmp_dir="$tmp/install.sh.$$"
+(umask 077 && mkdir $tmp_dir) || exit 1
+
exists() {
if command -v $1 &>/dev/null
then
@@ -19,41 +20,183 @@ exists() {
fi
}
+http_404_error() {
+ echo "ERROR 404: Could not retrieve a valid install.sh!"
+ exit 1
+}
+
+capture_tmp_stderr() {
+ # spool up /tmp/stderr from all the commands we called
+ if test -f "$tmp_dir/stderr"; then
+ output=`cat $tmp_dir/stderr`
+ stderr_results="${stderr_results}\nSTDERR from $1:\n\n$output\n"
+ rm $tmp_dir/stderr
+ fi
+}
+
+# do_wget URL FILENAME
+do_wget() {
+ echo "trying wget..."
+ wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %> <%= knife_config[:bootstrap_wget_options] %> -O "$2" "$1" 2>$tmp_dir/stderr
+ rc=$?
+ # check for 404
+ grep "ERROR 404" $tmp_dir/stderr 2>&1 >/dev/null
+ if test $? -eq 0; then
+ http_404_error
+ fi
+
+ # check for bad return status or empty output
+ if test $rc -ne 0 || test ! -s "$2"; then
+ capture_tmp_stderr "wget"
+ return 1
+ fi
+
+ return 0
+}
+
+# do_curl URL FILENAME
+do_curl() {
+ echo "trying curl..."
+ curl -sL <%= "--proxy \"#{knife_config[:bootstrap_proxy]}\" " if knife_config[:bootstrap_proxy] %> <%= knife_config[:bootstrap_curl_options] %> -D $tmp_dir/stderr -o "$2" "$1" 2>$tmp_dir/stderr
+ rc=$?
+ # check for 404
+ grep "404 Not Found" $tmp_dir/stderr 2>&1 >/dev/null
+ if test $? -eq 0; then
+ http_404_error
+ fi
+
+ # check for bad return status or empty output
+ if test $rc -ne 0 || test ! -s "$2"; then
+ capture_tmp_stderr "curl"
+ return 1
+ fi
+
+ return 0
+}
+
+# do_fetch URL FILENAME
+do_fetch() {
+ echo "trying fetch..."
+ fetch -o "$2" "$1" 2>$tmp_dir/stderr
+ # check for bad return status
+ test $? -ne 0 && return 1
+ return 0
+}
+
+# do_perl URL FILENAME
+do_perl() {
+ echo "trying perl..."
+ perl -e "use LWP::Simple; getprint(shift @ARGV);" "$1" > "$2" 2>$tmp_dir/stderr
+ rc=$?
+ # check for 404
+ grep "404 Not Found" $tmp_dir/stderr 2>&1 >/dev/null
+ if test $? -eq 0; then
+ http_404_error
+ fi
+
+ # check for bad return status or empty output
+ if test $rc -ne 0 || test ! -s "$2"; then
+ capture_tmp_stderr "perl"
+ return 1
+ fi
+
+ return 0
+}
+
+# do_python URL FILENAME
+do_python() {
+ echo "trying python..."
+ python -c "import sys,urllib2 ; sys.stdout.write(urllib2.urlopen(sys.argv[1]).read())" "$1" > "$2" 2>$tmp_dir/stderr
+ rc=$?
+ # check for 404
+ grep "HTTP Error 404" $tmp_dir/stderr 2>&1 >/dev/null
+ if test $? -eq 0; then
+ http_404_error
+ fi
+
+ # check for bad return status or empty output
+ if test $rc -ne 0 || test ! -s "$2"; then
+ capture_tmp_stderr "python"
+ return 1
+ fi
+ return 0
+}
+
+# do_download URL FILENAME
+do_download() {
+ PATH=/opt/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sfw/bin:/sbin:/bin:/usr/sbin:/usr/bin
+ export PATH
+
+ echo "downloading $1"
+ echo " to file $2"
+
+ # we try all of these until we get success.
+ # perl, in particular may be present but LWP::Simple may not be installed
+
+ if exists wget; then
+ do_wget $1 $2 && return 0
+ fi
+
+ if exists curl; then
+ do_curl $1 $2 && return 0
+ fi
+
+ if exists fetch; then
+ do_fetch $1 $2 && return 0
+ fi
+
+ if exists perl; then
+ do_perl $1 $2 && return 0
+ fi
+
+ if exists python; then
+ do_python $1 $2 && return 0
+ fi
+
+ echo ">>>>>> wget, curl, fetch, perl, or python not found on this instance."
+
+ if test "x$stderr_results" != "x"; then
+ echo "\nDEBUG OUTPUT FOLLOWS:\n$stderr_results"
+ fi
+
+ return 16
+}
+
<% if knife_config[:bootstrap_install_command] %>
<%= knife_config[:bootstrap_install_command] %>
<% else %>
install_sh="<%= knife_config[:bootstrap_url] ? knife_config[:bootstrap_url] : "https://www.opscode.com/chef/install.sh" %>"
if ! exists /usr/bin/chef-client; then
- echo "Installing Chef Client..."
- if exists wget; then
- bash <(wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %> <%= knife_config[:bootstrap_wget_options] %> ${install_sh} -O -) <%= latest_current_chef_version_string %>
- elif exists curl; then
- bash <(curl -L <%= "--proxy \"#{knife_config[:bootstrap_proxy]}\" " if knife_config[:bootstrap_proxy] %> <%= knife_config[:bootstrap_curl_options] %> ${install_sh}) <%= latest_current_chef_version_string %>
- else
- echo "Neither wget nor curl found. Please install one and try again." >&2
- exit 1
- fi
+ echo "-----> Installing Chef Omnibus (<%= latest_current_chef_version_string %>)"
+ do_download ${install_sh} $tmp_dir/install.sh
+ sh $tmp_dir/install.sh -P chef <%= latest_current_chef_version_string %>
+ else
+ echo "-----> Existing Chef installation detected"
fi
<% end %>
+if test "x$tmp_dir" != "x"; then
+ rm -r "$tmp_dir"
+fi
+
mkdir -p /etc/chef
<% if client_pem -%>
-cat > /etc/chef/client.pem <<'EOP'
+cat > /etc/chef/client.pem <<EOP
<%= ::File.read(::File.expand_path(client_pem)) %>
EOP
chmod 0600 /etc/chef/client.pem
<% end -%>
<% if validation_key -%>
-cat > /etc/chef/validation.pem <<'EOP'
+cat > /etc/chef/validation.pem <<EOP
<%= validation_key %>
EOP
chmod 0600 /etc/chef/validation.pem
<% end -%>
<% if encrypted_data_bag_secret -%>
-cat > /etc/chef/encrypted_data_bag_secret <<'EOP'
+cat > /etc/chef/encrypted_data_bag_secret <<EOP
<%= encrypted_data_bag_secret %>
EOP
chmod 0600 /etc/chef/encrypted_data_bag_secret
@@ -69,17 +212,17 @@ mkdir -p /etc/chef/trusted_certs
mkdir -p /etc/chef/ohai/hints
<% @chef_config[:knife][:hints].each do |name, hash| -%>
-cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP'
+cat > /etc/chef/ohai/hints/<%= name %>.json <<EOP
<%= Chef::JSONCompat.to_json(hash) %>
EOP
<% end -%>
<% end -%>
-cat > /etc/chef/client.rb <<'EOP'
+cat > /etc/chef/client.rb <<EOP
<%= config_content %>
EOP
-cat > /etc/chef/first-boot.json <<'EOP'
+cat > /etc/chef/first-boot.json <<EOP
<%= Chef::JSONCompat.to_json(first_boot) %>
EOP
diff --git a/lib/chef/mixin/provides.rb b/lib/chef/mixin/provides.rb
new file mode 100644
index 0000000000..e5bb2c2005
--- /dev/null
+++ b/lib/chef/mixin/provides.rb
@@ -0,0 +1,32 @@
+
+require 'chef/mixin/descendants_tracker'
+
+class Chef
+ module Mixin
+ module Provides
+ include Chef::Mixin::DescendantsTracker
+
+ def node_map
+ @node_map ||= Chef::NodeMap.new
+ end
+
+ def provides(short_name, opts={}, &block)
+ if !short_name.kind_of?(Symbol)
+ # YAGNI: this is probably completely unnecessary and can be removed?
+ Chef::Log.deprecation "Passing a non-Symbol to Chef::Resource#provides will be removed"
+ if short_name.kind_of?(String)
+ short_name.downcase!
+ short_name.gsub!(/\s/, "_")
+ end
+ short_name = short_name.to_sym
+ end
+ node_map.set(short_name, true, opts, &block)
+ end
+
+ # provides a node on the resource (early binding)
+ def provides?(node, resource_name)
+ node_map.get(node, resource_name)
+ end
+ end
+ end
+end
diff --git a/lib/chef/platform/provider_priority_map.rb b/lib/chef/platform/provider_priority_map.rb
index 2517f46dfd..1539f61900 100644
--- a/lib/chef/platform/provider_priority_map.rb
+++ b/lib/chef/platform/provider_priority_map.rb
@@ -1,6 +1,4 @@
-require 'chef/providers'
-
class Chef
class Platform
class ProviderPriorityMap
@@ -10,7 +8,22 @@ class Chef
load_default_map
end
+ def get_priority_array(node, resource_name)
+ priority_map.get(node, resource_name.to_sym)
+ end
+
+ def set_priority_array(resource_name, priority_array, *filter)
+ priority(resource_name.to_sym, priority_array.to_a, *filter)
+ end
+
+ def priority(*args)
+ priority_map.set(*args)
+ end
+
+ private
+
def load_default_map
+ require 'chef/providers'
#
# Linux
@@ -71,13 +84,9 @@ class Chef
end
def priority_map
+ require 'chef/node_map'
@priority_map ||= Chef::NodeMap.new
end
-
- def priority(*args)
- priority_map.set(*args)
- end
-
end
end
end
diff --git a/lib/chef/platform/resource_priority_map.rb b/lib/chef/platform/resource_priority_map.rb
new file mode 100644
index 0000000000..fc43b3e7db
--- /dev/null
+++ b/lib/chef/platform/resource_priority_map.rb
@@ -0,0 +1,37 @@
+class Chef
+ class Platform
+ class ResourcePriorityMap
+ include Singleton
+
+ def initialize
+ load_default_map
+ end
+
+ def get_priority_array(node, resource_name)
+ priority_map.get(node, resource_name.to_sym)
+ end
+
+ def set_priority_array(resource_name, priority_array, *filter)
+ priority resource_name.to_sym, priority_array.to_a, *filter
+ end
+
+ def priority(*args)
+ priority_map.set(*args)
+ end
+
+ private
+
+ def load_default_map
+ require 'chef/resources'
+
+ # MacOSX
+ priority :package, Chef::Resource::HomebrewPackage, os: "darwin"
+ end
+
+ def priority_map
+ require 'chef/node_map'
+ @priority_map ||= Chef::NodeMap.new
+ end
+ end
+ end
+end
diff --git a/lib/chef/policy_builder/expand_node_object.rb b/lib/chef/policy_builder/expand_node_object.rb
index 2ee8a23258..524bdd95b1 100644
--- a/lib/chef/policy_builder/expand_node_object.rb
+++ b/lib/chef/policy_builder/expand_node_object.rb
@@ -24,6 +24,7 @@ require 'chef/rest'
require 'chef/run_context'
require 'chef/config'
require 'chef/node'
+require 'chef/chef_class'
class Chef
module PolicyBuilder
@@ -54,6 +55,15 @@ class Chef
@run_list_expansion = nil
end
+ # This method injects the run_context and provider and resource priority
+ # maps into the Chef class. The run_context has to be injected here, the provider and
+ # resource maps could be moved if a better place can be found to do this work.
+ #
+ # @param run_context [Chef::RunContext] the run_context to inject
+ def setup_chef_class(run_context)
+ Chef.set_run_context(run_context)
+ end
+
def setup_run_context(specific_recipes=nil)
if Chef::Config[:solo]
Chef::Cookbook::FileVendor.fetch_from_disk(Chef::Config[:cookbook_path])
@@ -68,6 +78,10 @@ class Chef
run_context = Chef::RunContext.new(node, cookbook_collection, @events)
end
+ # TODO: this is really obviously not the place for this
+ # FIXME: need same edits
+ setup_chef_class(run_context)
+
# TODO: this is not the place for this. It should be in Runner or
# CookbookCompiler or something.
run_context.load(@run_list_expansion)
diff --git a/lib/chef/policy_builder/policyfile.rb b/lib/chef/policy_builder/policyfile.rb
index 0c7c07f9f3..ac25b549be 100644
--- a/lib/chef/policy_builder/policyfile.rb
+++ b/lib/chef/policy_builder/policyfile.rb
@@ -385,4 +385,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/provider.rb b/lib/chef/provider.rb
index 680fe9782f..65a56cf726 100644
--- a/lib/chef/provider.rb
+++ b/lib/chef/provider.rb
@@ -22,7 +22,7 @@ require 'chef/mixin/convert_to_class_name'
require 'chef/mixin/enforce_ownership_and_permissions'
require 'chef/mixin/why_run'
require 'chef/mixin/shell_out'
-require 'chef/mixin/descendants_tracker'
+require 'chef/mixin/provides'
require 'chef/platform/service_helpers'
require 'chef/node_map'
@@ -30,26 +30,11 @@ class Chef
class Provider
include Chef::Mixin::WhyRun
include Chef::Mixin::ShellOut
- extend Chef::Mixin::DescendantsTracker
+ extend Chef::Mixin::Provides
- class << self
- def node_map
- @node_map ||= Chef::NodeMap.new
- end
-
- def provides(resource_name, opts={}, &block)
- node_map.set(resource_name.to_sym, true, opts, &block)
- end
-
- # provides a node on the resource (early binding)
- def provides?(node, resource)
- node_map.get(node, resource.resource_name)
- end
-
- # supports the given resource and action (late binding)
- def supports?(resource, action)
- true
- end
+ # supports the given resource and action (late binding)
+ def self.supports?(resource, action)
+ true
end
attr_accessor :new_resource
diff --git a/lib/chef/provider_resolver.rb b/lib/chef/provider_resolver.rb
index d83a3e0468..867c3deca8 100644
--- a/lib/chef/provider_resolver.rb
+++ b/lib/chef/provider_resolver.rb
@@ -47,7 +47,7 @@ class Chef
def enabled_handlers
@enabled_handlers ||=
providers.select do |klass|
- klass.provides?(node, resource)
+ klass.provides?(node, resource.resource_name)
end.sort {|a,b| a.to_s <=> b.to_s }
end
@@ -84,8 +84,13 @@ class Chef
if handlers.count >= 2
# this magic stack ranks the providers by where they appear in the provider_priority_map, it is mostly used
# to pick amongst N different ways to start init scripts on different debian/ubuntu systems.
- priority_list = [ get_provider_priority_map(resource.resource_name, node) ].flatten.compact
+ priority_list = [ get_priority_array(node, resource.resource_name) ].flatten.compact
handlers = handlers.sort_by { |x| i = priority_list.index x; i.nil? ? Float::INFINITY : i }
+ if priority_list.index(handlers.first).nil?
+ # if we had more than one and we picked one with a precidence of infinity that means that the resource_priority_map
+ # entry for this resource is missing -- we should probably raise here and force resolution of the ambiguity.
+ Chef::Log.warn "Ambiguous provider precedence: #{handlers}, please use Chef.set_provider_priority_array to provide determinism"
+ end
handlers = [ handlers.first ]
end
@@ -106,12 +111,12 @@ class Chef
end
# dep injection hooks
- def get_provider_priority_map(resource_name, node)
- provider_priority_map.get(node, resource_name)
+ def get_priority_array(node, resource_name)
+ provider_priority_map.get_priority_array(node, resource_name)
end
def provider_priority_map
- Chef::Platform::ProviderPriorityMap.instance.priority_map
+ Chef::Platform::ProviderPriorityMap.instance
end
end
end
diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb
index ea220b6c70..d934ec8c47 100644
--- a/lib/chef/resource.rb
+++ b/lib/chef/resource.rb
@@ -33,7 +33,7 @@ require 'chef/platform'
require 'chef/resource/resource_notification'
require 'chef/mixin/deprecation'
-require 'chef/mixin/descendants_tracker'
+require 'chef/mixin/provides'
class Chef
class Resource
@@ -46,6 +46,7 @@ class Chef
include Chef::DSL::PlatformIntrospection
include Chef::DSL::RegistryHelper
include Chef::DSL::RebootPending
+ extend Chef::Mixin::Provides
#
# The node the current Chef run is using.
@@ -879,7 +880,6 @@ class Chef
include Chef::Mixin::ConvertToClassName
extend Chef::Mixin::ConvertToClassName
- extend Chef::Mixin::DescendantsTracker
# XXX: this is required for definition params inside of the scope of a
# subresource to work correctly.
@@ -1016,6 +1016,7 @@ class Chef
end
def provider_for_action(action)
+ require 'chef/provider_resolver'
provider = Chef::ProviderResolver.new(node, self, action).resolve.new(self, run_context)
provider.action = action
provider
@@ -1080,33 +1081,6 @@ class Chef
end
end
- # Maps a short_name (and optionally a platform and version) to a
- # Chef::Resource. This allows finer grained per platform resource
- # attributes and the end of overloaded resource definitions
- # (I'm looking at you Chef::Resource::Package)
- # Ex:
- # class WindowsFile < Chef::Resource
- # provides :file, os: "linux", platform_family: "rhel", platform: "redhat"
- # provides :file, os: "!windows
- # provides :file, os: [ "linux", "aix" ]
- # provides :file, os: "solaris2" do |node|
- # node['platform_version'].to_f <= 5.11
- # end
- # # ...other stuff
- # end
- #
- def self.provides(short_name, opts={}, &block)
- short_name_sym = short_name
- if short_name.kind_of?(String)
- # YAGNI: this is probably completely unnecessary and can be removed?
- Chef::Log.warn "[DEPRECATION] Passing a String to Chef::Resource#provides will be removed"
- short_name.downcase!
- short_name.gsub!(/\s/, "_")
- short_name_sym = short_name.to_sym
- end
- node_map.set(short_name_sym, constantize(self.name), opts, &block)
- end
-
# Returns a resource based on a short_name and node
#
# ==== Parameters
@@ -1116,16 +1090,12 @@ class Chef
# === Returns
# <Chef::Resource>:: returns the proper Chef::Resource class
def self.resource_for_node(short_name, node)
- klass = node_map.get(node, short_name) ||
- resource_matching_short_name(short_name)
+ require 'chef/resource_resolver'
+ klass = Chef::ResourceResolver.new(node, short_name).resolve
raise Chef::Exceptions::NoSuchResourceType.new(short_name, node) if klass.nil?
klass
end
- def self.node_map
- @@node_map ||= NodeMap.new
- end
-
# Returns the class of a Chef::Resource based on the short name
# ==== Parameters
# short_name<Symbol>:: short_name of the resource (ie :directory)
@@ -1156,7 +1126,3 @@ class Chef
end
end
end
-
-# We require this at the BOTTOM of this file to avoid circular requires (it is used
-# at runtime but not load time)
-require 'chef/provider_resolver'
diff --git a/lib/chef/resource_resolver.rb b/lib/chef/resource_resolver.rb
new file mode 100644
index 0000000000..ff9d7aeb9f
--- /dev/null
+++ b/lib/chef/resource_resolver.rb
@@ -0,0 +1,101 @@
+#
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/exceptions'
+require 'chef/platform/resource_priority_map'
+
+class Chef
+ class ResourceResolver
+
+ attr_reader :node
+ attr_reader :resource
+ attr_reader :action
+
+ def initialize(node, resource)
+ @node = node
+ @resource = resource
+ end
+
+ # return a deterministically sorted list of Chef::Resource subclasses
+ def resources
+ @resources ||= Chef::Resource.descendants
+ end
+
+ def resolve
+ maybe_dynamic_resource_resolution(resource) ||
+ maybe_chef_platform_lookup(resource)
+ end
+
+ # this cut looks at if the resource can handle the resource type on the node
+ def enabled_handlers
+ @enabled_handlers ||=
+ resources.select do |klass|
+ klass.provides?(node, resource)
+ end.sort {|a,b| a.to_s <=> b.to_s }
+ @enabled_handlers
+ end
+
+ private
+
+ # try dynamically finding a resource based on querying the resources to see what they support
+ def maybe_dynamic_resource_resolution(resource)
+ # log this so we know what resources will work for the generic resource on the node (early cut)
+ Chef::Log.debug "resources for generic #{resource} resource enabled on node include: #{enabled_handlers}"
+
+ # if none of the resources specifically support the resource, we still need to pick one of the resources that are
+ # enabled on the node to handle the why-run use case.
+ handlers = enabled_handlers
+
+ if handlers.count >= 2
+ # this magic stack ranks the resources by where they appear in the resource_priority_map
+ priority_list = [ get_priority_array(node, resource) ].flatten.compact
+ handlers = handlers.sort_by { |x| i = priority_list.index x; i.nil? ? Float::INFINITY : i }
+ if priority_list.index(handlers.first).nil?
+ # if we had more than one and we picked one with a precidence of infinity that means that the resource_priority_map
+ # entry for this resource is missing -- we should probably raise here and force resolution of the ambiguity.
+ Chef::Log.warn "Ambiguous resource precedence: #{handlers}, please use Chef.set_resource_priority_array to provide determinism"
+ end
+ handlers = [ handlers.first ]
+ end
+
+ Chef::Log.debug "resources that survived replacement include: #{handlers}"
+
+ raise Chef::Exceptions::AmbiguousResourceResolution.new(resource, handlers) if handlers.count >= 2
+
+ Chef::Log.debug "dynamic resource resolver FAILED to resolve a resouce" if handlers.empty?
+
+ return nil if handlers.empty?
+
+ handlers[0]
+ end
+
+ # try the old static lookup of resources by mangling name to resource klass
+ def maybe_chef_platform_lookup(resource)
+ Chef::Resource.resource_matching_short_name(resource)
+ end
+
+ # dep injection hooks
+ def get_priority_array(node, resource_name)
+ resource_priority_map.get_priority_array(node, resource_name)
+ end
+
+ def resource_priority_map
+ Chef::Platform::ResourcePriorityMap.instance
+ end
+ end
+end
diff --git a/lib/chef/search/query.rb b/lib/chef/search/query.rb
index 8656e810db..6469a18c49 100644
--- a/lib/chef/search/query.rb
+++ b/lib/chef/search/query.rb
@@ -89,7 +89,7 @@ WARNDEP
if block
response["rows"].each { |row| block.call(row) if row }
unless (response["start"] + response["rows"].length) >= response["total"]
- args_h[:start] = response["start"] + (args_h[:rows] || 0)
+ args_h[:start] = response["start"] + response["rows"].length
search(type, query, args_h, &block)
end
true
diff --git a/spec/data/big_json_plus_one.json b/spec/data/big_json_plus_one.json
deleted file mode 100644
index 8ea4b74644..0000000000
--- a/spec/data/big_json_plus_one.json
+++ /dev/null
@@ -1,2 +0,0 @@
-{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":"test"
-}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
diff --git a/spec/data/lwrp/providers/buck_passer.rb b/spec/data/lwrp/providers/buck_passer.rb
index c56ab94f85..9792e2c824 100644
--- a/spec/data/lwrp/providers/buck_passer.rb
+++ b/spec/data/lwrp/providers/buck_passer.rb
@@ -1,4 +1,5 @@
-provides 'buck_passer'
+provides :buck_passer
+
action :pass_buck do
lwrp_foo :prepared_thumbs do
action :prepare_thumbs
diff --git a/spec/data/lwrp/resources/bar.rb b/spec/data/lwrp/resources/bar.rb
index b6359648db..2ff35efd08 100644
--- a/spec/data/lwrp/resources/bar.rb
+++ b/spec/data/lwrp/resources/bar.rb
@@ -1,2 +1,2 @@
-provides "lwrp_bar" # This makes sure that we cover the case of lwrps using provides
+provides :lwrp_bar # This makes sure that we cover the case of lwrps using provides
actions :pass_buck, :prepare_eyes, :watch_paint_dry
diff --git a/spec/data/big_json.json b/spec/data/nested.json
index 96c2818894..775bb21981 100644
--- a/spec/data/big_json.json
+++ b/spec/data/nested.json
@@ -1,2 +1,2 @@
-{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":"test"
-}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} \ No newline at end of file
+{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":"test"
+}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
diff --git a/spec/functional/event_loggers/windows_eventlog_spec.rb b/spec/functional/event_loggers/windows_eventlog_spec.rb
index 4e383dd429..0723e7b984 100644
--- a/spec/functional/event_loggers/windows_eventlog_spec.rb
+++ b/spec/functional/event_loggers/windows_eventlog_spec.rb
@@ -79,4 +79,18 @@ describe Chef::EventLoggers::WindowsEventLogger, :windows_only, :not_supported_o
end).to be_truthy
end
+ it 'writes run_failed event with event_id 10003 even when run_status is not set' do
+ logger.run_failed(mock_exception)
+
+ expect(event_log.read(flags, offset).any? do |e|
+ e.source == 'Chef' && e.event_id == 10003 &&
+ e.string_inserts[0].include?("UNKNOWN") &&
+ e.string_inserts[1].include?("UNKNOWN") &&
+ e.string_inserts[2].include?(mock_exception.class.name) &&
+ e.string_inserts[3].include?(mock_exception.message) &&
+ e.string_inserts[4].include?(mock_exception.backtrace[0]) &&
+ e.string_inserts[4].include?(mock_exception.backtrace[1])
+ end).to be_truthy
+ end
+
end
diff --git a/spec/functional/resource/execute_spec.rb b/spec/functional/resource/execute_spec.rb
index aaa1c772b7..ffa4628cb2 100644
--- a/spec/functional/resource/execute_spec.rb
+++ b/spec/functional/resource/execute_spec.rb
@@ -62,7 +62,7 @@ describe Chef::Resource::Execute do
end
describe "when parent resource sets :cwd" do
- let(:guard) { %{ruby -e 'exit 1 unless File.exists?("./big_json_plus_one.json")'} }
+ let(:guard) { %{ruby -e 'exit 1 unless File.exists?("./nested.json")'} }
it "guard inherits :cwd from resource and runs" do
resource.cwd CHEF_SPEC_DATA
diff --git a/spec/unit/chef_class_spec.rb b/spec/unit/chef_class_spec.rb
new file mode 100644
index 0000000000..2528246be6
--- /dev/null
+++ b/spec/unit/chef_class_spec.rb
@@ -0,0 +1,91 @@
+#
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright (c) 2015 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+describe "Chef class" do
+ let(:platform) { "debian" }
+
+ let(:node) do
+ node = Chef::Node.new
+ node.automatic['platform'] = platform
+ node
+ end
+
+ let(:run_context) do
+ Chef::RunContext.new(node, nil, nil)
+ end
+
+ let(:resource_priority_map) do
+ double("Chef::Platform::ResourcePriorityMap")
+ end
+
+ let(:provider_priority_map) do
+ double("Chef::Platform::ProviderPriorityMap")
+ end
+
+ before do
+ Chef.set_run_context(run_context)
+ Chef.set_node(node)
+ Chef.set_resource_priority_map(resource_priority_map)
+ Chef.set_provider_priority_map(provider_priority_map)
+ end
+
+ after do
+ Chef.reset!
+ end
+
+ context "priority maps" do
+ context "#get_provider_priority_array" do
+ it "should use the current node to get the right priority_map" do
+ expect(provider_priority_map).to receive(:get_priority_array).with(node, :http_request).and_return("stuff")
+ expect(Chef.get_provider_priority_array(:http_request)).to eql("stuff")
+ end
+ end
+ context "#get_resource_priority_array" do
+ it "should use the current node to get the right priority_map" do
+ expect(resource_priority_map).to receive(:get_priority_array).with(node, :http_request).and_return("stuff")
+ expect(Chef.get_resource_priority_array(:http_request)).to eql("stuff")
+ end
+ end
+ context "#set_provider_priority_array" do
+ it "should delegate to the provider_priority_map" do
+ expect(provider_priority_map).to receive(:set_priority_array).with(:http_request, ["a", "b"], platform: "debian").and_return("stuff")
+ expect(Chef.set_provider_priority_array(:http_request, ["a", "b"], platform: "debian")).to eql("stuff")
+ end
+ end
+ context "#set_priority_map_for_resource" do
+ it "should delegate to the resource_priority_map" do
+ expect(resource_priority_map).to receive(:set_priority_array).with(:http_request, ["a", "b"], platform: "debian").and_return("stuff")
+ expect(Chef.set_resource_priority_array(:http_request, ["a", "b"], platform: "debian")).to eql("stuff")
+ end
+ end
+ end
+
+ context "#run_context" do
+ it "should return the injected RunContext" do
+ expect(Chef.run_context).to eql(run_context)
+ end
+ end
+
+ context "#node" do
+ it "should return the injected Node" do
+ expect(Chef.node).to eql(node)
+ end
+ end
+end
diff --git a/spec/unit/json_compat_spec.rb b/spec/unit/json_compat_spec.rb
index 65d931df70..7482ba8a28 100644
--- a/spec/unit/json_compat_spec.rb
+++ b/spec/unit/json_compat_spec.rb
@@ -72,32 +72,19 @@ describe Chef::JSONCompat do
end
end
- describe "with a file with 300 or less nested entries" do
- let(:json) { IO.read(File.join(CHEF_SPEC_DATA, 'big_json.json')) }
+ # On FreeBSD 10.1 i386 rspec fails with a SystemStackError loading the expect line with more that 252 entries
+ # https://github.com/chef/chef/issues/3101
+ describe "with the file with 252 or less nested entries" do
+ let(:json) { IO.read(File.join(CHEF_SPEC_DATA, 'nested.json')) }
let(:hash) { Chef::JSONCompat.from_json(json) }
- describe "when a big json file is loaded" do
+ describe "when the 252 json file is loaded" do
it "should create a Hash from the file" do
expect(hash).to be_kind_of(Hash)
end
- it "should has 'test' as a 300th nested value" do
- expect(hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']).to eq('test')
- end
- end
- end
-
- describe "with a file with more than 300 nested entries" do
- let(:json) { IO.read(File.join(CHEF_SPEC_DATA, 'big_json_plus_one.json')) }
- let(:hash) { Chef::JSONCompat.from_json(json, {:max_nesting => 301}) }
-
- describe "when a big json file is loaded" do
- it "should create a Hash from the file" do
- expect(hash).to be_kind_of(Hash)
- end
-
- it "should has 'test' as a 301st nested value" do
- expect(hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']).to eq('test')
+ it "should has 'test' as a 252 nested value" do
+ expect(hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']).to eq('test')
end
end
end
diff --git a/spec/unit/key_spec.rb b/spec/unit/key_spec.rb
new file mode 100644
index 0000000000..9f37b8aa12
--- /dev/null
+++ b/spec/unit/key_spec.rb
@@ -0,0 +1,577 @@
+#
+# Author:: Tyler Cloke (tyler@chef.io)
+# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+require 'chef/key'
+
+describe Chef::Key do
+ # whether user or client irrelevent to these tests
+ let(:key) { Chef::Key.new("original_actor", "user") }
+ let(:public_key_string) do
+ <<EOS
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvPo+oNPB7uuNkws0fC02
+KxSwdyqPLu0fhI1pOweNKAZeEIiEz2PkybathHWy8snSXGNxsITkf3eyvIIKa8OZ
+WrlqpI3yv/5DOP8HTMCxnFuMJQtDwMcevlqebX4bCxcByuBpNYDcAHjjfLGSfMjn
+E5lZpgYWwnpic4kSjYcL9ORK9nYvlWV9P/kCYmRhIjB4AhtpWRiOfY/TKi3P2LxT
+IjSmiN/ihHtlhV/VSnBJ5PzT/lRknlrJ4kACoz7Pq9jv+aAx5ft/xE9yDa2DYs0q
+Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
+0wIDAQAB
+-----END PUBLIC KEY-----
+EOS
+ end
+
+ shared_examples_for "fields with username type validation" do
+ context "when invalid input is passed" do
+ # It is not feasible to check all invalid characters. Here are a few
+ # that we probably care about.
+ it "should raise an ArgumentError" do
+ # capital letters
+ expect { key.send(field, "Bar") }.to raise_error(ArgumentError)
+ # slashes
+ expect { key.send(field, "foo/bar") }.to raise_error(ArgumentError)
+ # ?
+ expect { key.send(field, "foo?") }.to raise_error(ArgumentError)
+ # &
+ expect { key.send(field, "foo&") }.to raise_error(ArgumentError)
+ # spaces
+ expect { key.send(field, "foo ") }.to raise_error(ArgumentError)
+ end
+ end
+ end
+
+ shared_examples_for "string fields that are settable" do
+ context "when it is set with valid input" do
+ it "should set the field" do
+ key.send(field, valid_input)
+ expect(key.send(field)).to eq(valid_input)
+ end
+ end
+
+ context "when you feed it anything but a string" do
+ it "should raise an ArgumentError" do
+ expect { key.send(field, Hash.new) }.to raise_error(ArgumentError)
+ end
+ end
+ end
+
+
+ describe "when a new Chef::Key object is initialized with invalid input" do
+ it "should raise an InvalidKeyArgument" do
+ expect { Chef::Key.new("original_actor", "not_a_user_or_client") }.to raise_error(Chef::Exceptions::InvalidKeyArgument)
+ end
+ end
+
+ describe "when a new Chef::Key object is initialized with valid input" do
+ it "should be a Chef::Key" do
+ expect(key).to be_a_kind_of(Chef::Key)
+ end
+
+ it "should properly set the actor" do
+ expect(key.actor).to eq("original_actor")
+ end
+ end
+
+ describe "when actor field is set" do
+ it_should_behave_like "string fields that are settable" do
+ let(:field) { :actor }
+ let(:valid_input) { "new_field_value" }
+ end
+
+ it_should_behave_like "fields with username type validation" do
+ let(:field) { :actor }
+ end
+ end
+
+ describe "when the name field is set" do
+ it_should_behave_like "string fields that are settable" do
+ let(:field) { :name }
+ let(:valid_input) { "new_field_value" }
+ end
+ end
+
+ describe "when the private_key field is set" do
+ it_should_behave_like "string fields that are settable" do
+ let(:field) { :private_key }
+ let(:valid_input) { "new_field_value" }
+ end
+ end
+
+ describe "when the public_key field is set" do
+ it_should_behave_like "string fields that are settable" do
+ let(:field) { :public_key }
+ let(:valid_input) { "new_field_value" }
+ end
+
+ context "when create_key is true" do
+ before do
+ key.create_key true
+ end
+
+ it "should raise an InvalidKeyAttribute" do
+ expect { key.public_key public_key_string }.to raise_error(Chef::Exceptions::InvalidKeyAttribute)
+ end
+ end
+ end
+
+ describe "when the create_key field is set" do
+ context "when it is set to true" do
+ it "should set the field" do
+ key.create_key(true)
+ expect(key.create_key).to eq(true)
+ end
+ end
+
+ context "when it is set to false" do
+ it "should set the field" do
+ key.create_key(false)
+ expect(key.create_key).to eq(false)
+ end
+ end
+
+ context "when anything but a TrueClass or FalseClass is passed" do
+ it "should raise an ArgumentError" do
+ expect { key.create_key "not_a_boolean" }.to raise_error(ArgumentError)
+ end
+ end
+
+ context "when public_key is defined" do
+ before do
+ key.public_key public_key_string
+ end
+
+ it "should raise an InvalidKeyAttribute" do
+ expect { key.create_key true }.to raise_error(Chef::Exceptions::InvalidKeyAttribute)
+ end
+ end
+ end
+
+ describe "when the expiration_date field is set" do
+ context "when a valid date is passed" do
+ it_should_behave_like "string fields that are settable" do
+ let(:field) { :public_key }
+ let(:valid_input) { "2020-12-24T21:00:00Z" }
+ end
+ end
+
+ context "when infinity is passed" do
+ it_should_behave_like "string fields that are settable" do
+ let(:field) { :public_key }
+ let(:valid_input) { "infinity" }
+ end
+ end
+
+ context "when an invalid date is passed" do
+ it "should raise an ArgumentError" do
+ expect { key.expiration_date "invalid_date" }.to raise_error(ArgumentError)
+ # wrong years
+ expect { key.expiration_date "20-12-24T21:00:00Z" }.to raise_error(ArgumentError)
+ end
+
+ context "when it is a valid UTC date missing a Z" do
+ it "should raise an ArgumentError" do
+ expect { key.expiration_date "2020-12-24T21:00:00" }.to raise_error(ArgumentError)
+ end
+ end
+ end
+ end # when the expiration_date field is set
+
+ describe "when serializing to JSON" do
+ shared_examples_for "common json operations" do
+ it "should serializes as a JSON object" do
+ expect(json).to match(/^\{.+\}$/)
+ end
+
+ it "should include the actor value under the key relative to the actor_field_name passed" do
+ expect(json).to include(%Q("#{new_key.actor_field_name}":"original_actor"))
+ end
+
+ it "should include the name field when present" do
+ new_key.name("monkeypants")
+ expect(new_key.to_json).to include(%q{"name":"monkeypants"})
+ end
+
+ it "should not include the name if not present" do
+ expect(json).to_not include("name")
+ end
+
+ it "should include the public_key field when present" do
+ new_key.public_key "this_public_key"
+ expect(new_key.to_json).to include(%q("public_key":"this_public_key"))
+ end
+
+ it "should not include the public_key if not present" do
+ expect(json).to_not include("public_key")
+ end
+
+ it "should include the private_key field when present" do
+ new_key.private_key "this_public_key"
+ expect(new_key.to_json).to include(%q("private_key":"this_public_key"))
+ end
+
+ it "should not include the private_key if not present" do
+ expect(json).to_not include("private_key")
+ end
+
+ it "should include the expiration_date field when present" do
+ new_key.expiration_date "2020-12-24T21:00:00Z"
+ expect(new_key.to_json).to include(%Q("expiration_date":"2020-12-24T21:00:00Z"))
+ end
+
+ it "should not include the expiration_date if not present" do
+ expect(json).to_not include("expiration_date")
+ end
+
+ it "should include the create_key field when present" do
+ new_key.create_key true
+ expect(new_key.to_json).to include(%q("create_key":true))
+ end
+
+ it "should not include the create_key if not present" do
+ expect(json).to_not include("create_key")
+ end
+ end
+
+ context "when key is for a user" do
+ it_should_behave_like "common json operations" do
+ let(:new_key) { Chef::Key.new("original_actor", "user") }
+ let(:json) do
+ new_key.to_json
+ end
+ end
+ end
+
+ context "when key is for a client" do
+ it_should_behave_like "common json operations" do
+ let(:new_key) { Chef::Key.new("original_actor", "client") }
+ let(:json) do
+ new_key.to_json
+ end
+ end
+ end
+
+ end # when serializing to JSON
+
+ describe "when deserializing from JSON" do
+ shared_examples_for "a deserializable object" do
+ it "deserializes to a Chef::Key object" do
+ expect(key).to be_a_kind_of(Chef::Key)
+ end
+
+ it "preserves the actor" do
+ expect(key.actor).to eq("turtle")
+ end
+
+ it "preserves the name" do
+ expect(key.name).to eq("key_name")
+ end
+
+ it "includes the public key if present" do
+ expect(key.public_key).to eq(public_key_string)
+ end
+
+ it "includes the expiration_date if present" do
+ expect(key.expiration_date).to eq("infinity")
+ end
+
+ it "includes the private_key if present" do
+ expect(key.private_key).to eq("some_private_key")
+ end
+
+ it "includes the create_key if present" do
+ expect(key_with_create_key_field.create_key).to eq(true)
+ end
+ end
+
+ context "when deserializing a key for a user" do
+ it_should_behave_like "a deserializable object" do
+ let(:key) do
+ o = { "user" => "turtle",
+ "name" => "key_name",
+ "public_key" => public_key_string,
+ "private_key" => "some_private_key",
+ "expiration_date" => "infinity"}
+ Chef::Key.from_json(o.to_json)
+ end
+ let(:key_with_create_key_field) do
+ o = { "user" => "turtle",
+ "create_key" => true }
+ Chef::Key.from_json(o.to_json)
+ end
+ end
+ end
+
+ context "when deserializing a key for a client" do
+ it_should_behave_like "a deserializable object" do
+ let(:key) do
+ o = { "client" => "turtle",
+ "name" => "key_name",
+ "public_key" => public_key_string,
+ "private_key" => "some_private_key",
+ "expiration_date" => "infinity"}
+ Chef::Key.from_json(o.to_json)
+ end
+ let(:key_with_create_key_field) do
+ o = { "client" => "turtle",
+ "create_key" => true }
+ Chef::Key.from_json(o.to_json)
+ end
+ end
+ end
+ end # when deserializing from JSON
+
+
+ describe "API Interactions" do
+ let(:rest) do
+ Chef::Config[:chef_server_root] = "http://www.example.com"
+ Chef::Config[:chef_server_url] = "http://www.example.com/organizations/test_org"
+ r = double('rest')
+ allow(Chef::REST).to receive(:new).and_return(r)
+ r
+ end
+
+ let(:user_key) do
+ o = Chef::Key.new("foobar", "user")
+ o
+ end
+
+ let(:client_key) do
+ o = Chef::Key.new("foobar", "client")
+ o
+ end
+
+ describe "list" do
+ context "when listing keys for a user" do
+ let(:response) { [{"uri" => "http://www.example.com/users/keys/foobar", "name"=>"foobar", "expired"=>false}] }
+ let(:inflated_response) { {"foobar" => user_key} }
+
+ it "lists all keys" do
+ expect(rest).to receive(:get_rest).with("users/#{user_key.actor}/keys").and_return(response)
+ expect(Chef::Key.list_by_user("foobar")).to eq(response)
+ end
+
+ it "inflate all keys" do
+ allow(Chef::Key).to receive(:load_by_user).with(user_key.actor, "foobar").and_return(user_key)
+ expect(rest).to receive(:get_rest).with("users/#{user_key.actor}/keys").and_return(response)
+ expect(Chef::Key.list_by_user("foobar", true)).to eq(inflated_response)
+ end
+
+ end
+
+ context "when listing keys for a client" do
+ let(:response) { [{"uri" => "http://www.example.com/users/keys/foobar", "name"=>"foobar", "expired"=>false}] }
+ let(:inflated_response) { {"foobar" => client_key} }
+
+ it "lists all keys" do
+ expect(rest).to receive(:get_rest).with("clients/#{client_key.actor}/keys").and_return(response)
+ expect(Chef::Key.list_by_client("foobar")).to eq(response)
+ end
+
+ it "inflate all keys" do
+ allow(Chef::Key).to receive(:load_by_client).with(client_key.actor, "foobar").and_return(client_key)
+ expect(rest).to receive(:get_rest).with("clients/#{user_key.actor}/keys").and_return(response)
+ expect(Chef::Key.list_by_client("foobar", true)).to eq(inflated_response)
+ end
+
+ end
+ end
+
+
+ describe "create" do
+ shared_examples_for "create key" do
+ context "when a field is missing" do
+ it "should raise a MissingKeyAttribute" do
+ expect { key.create }.to raise_error(Chef::Exceptions::MissingKeyAttribute)
+ end
+ end
+
+ context "when the name field is missing" do
+ before do
+ key.public_key public_key_string
+ key.expiration_date "2020-12-24T21:00:00Z"
+ end
+
+ it "creates a new key via the API with the fingerprint as the name" do
+ expect(rest).to receive(:post_rest).with(url,
+ {"name" => "12:3e:33:73:0b:f4:ec:72:dc:f0:4c:51:62:27:08:76:96:24:f4:4a",
+ "public_key" => key.public_key,
+ "expiration_date" => key.expiration_date}).and_return({})
+ key.create
+ end
+ end
+
+ context "when every field is populated" do
+ before do
+ key.name "key_name"
+ key.public_key public_key_string
+ key.expiration_date "2020-12-24T21:00:00Z"
+ key.create_key false
+ end
+
+ context "when create_key is false" do
+ it "creates a new key via the API" do
+ expect(rest).to receive(:post_rest).with(url,
+ {"name" => key.name,
+ "public_key" => key.public_key,
+ "expiration_date" => key.expiration_date}).and_return({})
+ key.create
+ end
+ end
+
+ context "when create_key is true and public_key is nil" do
+ before do
+ key.delete_public_key
+ key.create_key true
+ end
+ it "should create a new key via the API" do
+ expect(rest).to receive(:post_rest).with(url,
+ {"name" => key.name,
+ "create_key" => true,
+ "expiration_date" => key.expiration_date}).and_return({})
+ key.create
+ end
+ end
+
+ context "when create_key is false and public_key is nil" do
+ before do
+ key.delete_public_key
+ key.create_key false
+ end
+ it "should raise an InvalidKeyArgument" do
+ expect { key.create }.to raise_error(Chef::Exceptions::MissingKeyAttribute)
+ end
+ end
+ end
+ end
+
+ context "when creating a user key" do
+ it_should_behave_like "create key" do
+ let(:url) { "users/#{key.actor}/keys" }
+ let(:key) { user_key }
+ end
+ end
+
+ context "when creating a client key" do
+ it_should_behave_like "create key" do
+ let(:url) { "clients/#{client_key.actor}/keys" }
+ let(:key) { client_key }
+ end
+ end
+ end # create
+
+ describe "update" do
+ shared_examples_for "update key" do
+ context "when name is missing" do
+ it "should raise an MissingKeyAttribute" do
+ expect { key.update }.to raise_error(Chef::Exceptions::MissingKeyAttribute)
+ end
+ end
+
+ context "when some fields are populated" do
+ before do
+ key.name "key_name"
+ key.expiration_date "2020-12-24T21:00:00Z"
+ end
+
+ it "should update the key via the API" do
+ expect(rest).to receive(:put_rest).with(url, key.to_hash).and_return({})
+ key.update
+ end
+ end
+ end
+
+ context "when creating a user key" do
+ it_should_behave_like "update key" do
+ let(:url) { "users/#{key.actor}/keys/#{key.name}" }
+ let(:key) { user_key }
+ end
+ end
+
+ context "when creating a client key" do
+ it_should_behave_like "update key" do
+ let(:url) { "clients/#{client_key.actor}/keys/#{key.name}" }
+ let(:key) { client_key }
+ end
+ end
+
+ end #update
+
+ describe "load" do
+ shared_examples_for "load" do
+ it "should load a named key from the API" do
+ expect(rest).to receive(:get_rest).with(url).and_return({"user" => "foobar", "name" => "test_key_name", "public_key" => public_key_string, "expiration_date" => "infinity"})
+ key = Chef::Key.send(load_method, "foobar", "test_key_name")
+ expect(key.actor).to eq("foobar")
+ expect(key.name).to eq("test_key_name")
+ expect(key.public_key).to eq(public_key_string)
+ expect(key.expiration_date).to eq("infinity")
+ end
+ end
+
+ describe "load_by_user" do
+ it_should_behave_like "load" do
+ let(:load_method) { :load_by_user }
+ let(:url) { "users/foobar/keys/test_key_name" }
+ end
+ end
+
+ describe "load_by_client" do
+ it_should_behave_like "load" do
+ let(:load_method) { :load_by_client }
+ let(:url) { "clients/foobar/keys/test_key_name" }
+ end
+ end
+
+ end #load
+
+ describe "destroy" do
+ shared_examples_for "destroy key" do
+ context "when name is missing" do
+ it "should raise an MissingKeyAttribute" do
+ expect { Chef::Key.new("username", "user").destroy }.to raise_error(Chef::Exceptions::MissingKeyAttribute)
+ end
+ end
+
+ before do
+ key.name "key_name"
+ end
+ context "when name is not missing" do
+ it "should delete the key via the API" do
+ expect(rest).to receive(:delete_rest).with(url).and_return({})
+ key.destroy
+ end
+ end
+ end
+
+ context "when destroying a user key" do
+ it_should_behave_like "destroy key" do
+ let(:url) { "users/#{key.actor}/keys/#{key.name}" }
+ let(:key) { user_key }
+ end
+ end
+
+ context "when destroying a client key" do
+ it_should_behave_like "destroy key" do
+ let(:url) { "clients/#{client_key.actor}/keys/#{key.name}" }
+ let(:key) { client_key }
+ end
+ end
+ end
+ end # API Interactions
+end
diff --git a/spec/unit/provider_resolver_spec.rb b/spec/unit/provider_resolver_spec.rb
index 63c381f08e..718eebfdf4 100644
--- a/spec/unit/provider_resolver_spec.rb
+++ b/spec/unit/provider_resolver_spec.rb
@@ -18,6 +18,7 @@
require 'spec_helper'
require 'chef/mixin/convert_to_class_name'
+require 'chef/provider_resolver'
include Chef::Mixin::ConvertToClassName
diff --git a/spec/unit/recipe_spec.rb b/spec/unit/recipe_spec.rb
index b370e12732..7442f4477e 100644
--- a/spec/unit/recipe_spec.rb
+++ b/spec/unit/recipe_spec.rb
@@ -20,6 +20,7 @@
#
require 'spec_helper'
+require 'chef/platform/resource_priority_map'
describe Chef::Recipe do
@@ -136,6 +137,44 @@ describe Chef::Recipe do
res.kind_of?(YourMom)
end
+ describe "when there is more than one resource that resolves on a node" do
+ before do
+ node.automatic[:platform] = "nbc_sports"
+ Sounders = Class.new(Chef::Resource)
+ Sounders.provides :football, platform: "nbc_sports"
+ TottenhamHotspur = Class.new(Chef::Resource)
+ TottenhamHotspur.provides :football, platform: "nbc_sports"
+ end
+
+ after do
+ Object.send(:remove_const, :Sounders)
+ Object.send(:remove_const, :TottenhamHotspur)
+ end
+
+ it "warns if resolution of the two resources is ambiguous" do
+ expect(Chef::Log).to receive(:warn).at_least(:once).with(/Ambiguous resource precedence/)
+ res1 = recipe.football "club world cup"
+ expect(res1.name).to eql("club world cup")
+ # the class of res1 is not defined.
+ end
+
+ it "selects one if it is given priority" do
+ expect(Chef::Log).not_to receive(:warn)
+ Chef::Platform::ResourcePriorityMap.instance.send(:priority, :football, TottenhamHotspur, platform: "nbc_sports")
+ res1 = recipe.football "club world cup"
+ expect(res1.name).to eql("club world cup")
+ expect(res1).to be_a_kind_of(TottenhamHotspur)
+ end
+
+ it "selects the other one if it is given priority" do
+ expect(Chef::Log).not_to receive(:warn)
+ Chef::Platform::ResourcePriorityMap.instance.send(:priority, :football, Sounders, platform: "nbc_sports")
+ res1 = recipe.football "club world cup"
+ expect(res1.name).to eql("club world cup")
+ expect(res1).to be_a_kind_of(Sounders)
+ end
+ end
+
end
end
diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb
index 8214021f65..6b2d6c89d3 100644
--- a/spec/unit/resource_spec.rb
+++ b/spec/unit/resource_spec.rb
@@ -709,22 +709,22 @@ describe Chef::Resource do
end
it 'adds mappings for a single platform' do
- expect(Chef::Resource.node_map).to receive(:set).with(
- :dinobot, Chef::Resource::Klz, { platform: ['autobots'] }
+ expect(Chef::Resource::Klz.node_map).to receive(:set).with(
+ :dinobot, true, { platform: ['autobots'] }
)
klz.provides :dinobot, platform: ['autobots']
end
it 'adds mappings for multiple platforms' do
- expect(Chef::Resource.node_map).to receive(:set).with(
- :energy, Chef::Resource::Klz, { platform: ['autobots', 'decepticons']}
+ expect(Chef::Resource::Klz.node_map).to receive(:set).with(
+ :energy, true, { platform: ['autobots', 'decepticons']}
)
klz.provides :energy, platform: ['autobots', 'decepticons']
end
it 'adds mappings for all platforms' do
- expect(Chef::Resource.node_map).to receive(:set).with(
- :tape_deck, Chef::Resource::Klz, {}
+ expect(Chef::Resource::Klz.node_map).to receive(:set).with(
+ :tape_deck, true, {}
)
klz.provides :tape_deck
end
diff --git a/spec/unit/search/query_spec.rb b/spec/unit/search/query_spec.rb
index 2fb197b183..59ac80f228 100644
--- a/spec/unit/search/query_spec.rb
+++ b/spec/unit/search/query_spec.rb
@@ -81,6 +81,9 @@ describe Chef::Search::Query do
end
describe "search" do
+ let(:query_string) { "search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=0" }
+ let(:query_string_continue) { "search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=4" }
+
let(:response) { {
"rows" => [
{ "name" => "my-name-is-node",
@@ -140,6 +143,19 @@ describe Chef::Search::Query do
"total" => 4
} }
+ let(:big_response) {
+ r = response.dup
+ r["total"] = 8
+ r
+ }
+
+ let(:big_response_end) {
+ r = response.dup
+ r["start"] = 4
+ r["total"] = 8
+ r
+ }
+
it "accepts a type as the first argument" do
expect { query.search("node") }.not_to raise_error
expect { query.search(:node) }.not_to raise_error
@@ -195,6 +211,14 @@ describe Chef::Search::Query do
query.search(:node, "*:*", sort: nil, start: 0, rows: 1) { |r| @call_me.do(r) }
end
+ it "sends multiple API requests when the server indicates there is more data" do
+ expect(rest).to receive(:get_rest).with(query_string).and_return(big_response)
+ expect(rest).to receive(:get_rest).with(query_string_continue).and_return(big_response_end)
+ query.search(:node, "platform:rhel") do |r|
+ nil
+ end
+ end
+
context "when :filter_result is provided as a result" do
include_context "filtered search" do
let(:filter_key) { :filter_result }
diff --git a/spec/unit/shell_spec.rb b/spec/unit/shell_spec.rb
index 4d5581d4d6..e6d11da523 100644
--- a/spec/unit/shell_spec.rb
+++ b/spec/unit/shell_spec.rb
@@ -43,6 +43,8 @@ describe Shell do
before do
Shell.irb_conf = {}
allow(Shell::ShellSession.instance).to receive(:reset!)
+ allow(Chef::Platform).to receive(:windows?).and_return(false)
+ allow(Chef::Util::PathHelper).to receive(:home).and_return('/home/foo')
end
describe "reporting its status" do
@@ -56,7 +58,7 @@ describe Shell do
describe "configuring IRB" do
it "configures irb history" do
Shell.configure_irb
- expect(Shell.irb_conf[:HISTORY_FILE]).to eq("#{ENV['HOME']}/.chef/chef_shell_history")
+ expect(Shell.irb_conf[:HISTORY_FILE]).to eq(Chef::Util::PathHelper.home('.chef', 'chef_shell_history'))
expect(Shell.irb_conf[:SAVE_HISTORY]).to eq(1000)
end