summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml4
-rw-r--r--CHANGELOG.md77
-rw-r--r--DOC_CHANGES.md22
-rw-r--r--Gemfile2
-rw-r--r--README.md2
-rw-r--r--RELEASE_NOTES.md150
-rw-r--r--Rakefile12
-rwxr-xr-xbin/chef-service-manager2
-rw-r--r--bin/chef-windows-service35
-rw-r--r--chef-x86-mingw32.gemspec3
-rw-r--r--chef.gemspec4
-rw-r--r--ext/win32-eventlog/Rakefile50
-rw-r--r--ext/win32-eventlog/chef-log.man26
-rw-r--r--lib/chef/application/apply.rb18
-rw-r--r--lib/chef/application/client.rb5
-rw-r--r--lib/chef/client.rb22
-rw-r--r--lib/chef/config.rb41
-rw-r--r--lib/chef/cookbook/cookbook_version_loader.rb2
-rw-r--r--lib/chef/cookbook/metadata.rb119
-rw-r--r--lib/chef/cookbook/syntax_check.rb15
-rw-r--r--lib/chef/cookbook_version.rb83
-rw-r--r--lib/chef/dsl/recipe.rb30
-rw-r--r--lib/chef/encrypted_data_bag_item/assertions.rb2
-rw-r--r--lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb2
-rw-r--r--lib/chef/event_loggers/base.rb62
-rw-r--r--lib/chef/event_loggers/windows_eventlog.rb104
-rw-r--r--lib/chef/exceptions.rb13
-rw-r--r--lib/chef/guard_interpreter/resource_guard_interpreter.rb21
-rw-r--r--lib/chef/http.rb2
-rw-r--r--lib/chef/json_compat.rb8
-rw-r--r--lib/chef/knife.rb3
-rw-r--r--lib/chef/knife/cookbook_create.rb2
-rw-r--r--lib/chef/knife/cookbook_site_share.rb51
-rw-r--r--lib/chef/knife/core/status_presenter.rb156
-rw-r--r--lib/chef/knife/core/ui.rb8
-rw-r--r--lib/chef/knife/node_from_file.rb17
-rw-r--r--lib/chef/knife/ssh.rb7
-rw-r--r--lib/chef/knife/status.rb69
-rw-r--r--lib/chef/mixin/command/unix.rb4
-rw-r--r--lib/chef/mixin/convert_to_class_name.rb54
-rw-r--r--lib/chef/mixin/descendants_tracker.rb82
-rw-r--r--lib/chef/mixin/homebrew_user.rb2
-rw-r--r--lib/chef/mixin/shell_out.rb4
-rw-r--r--lib/chef/node.rb4
-rw-r--r--lib/chef/node_map.rb146
-rw-r--r--lib/chef/platform/provider_mapping.rb44
-rw-r--r--lib/chef/platform/provider_priority_map.rb80
-rw-r--r--lib/chef/platform/service_helpers.rb113
-rw-r--r--lib/chef/provider.rb24
-rw-r--r--lib/chef/provider/breakpoint.rb2
-rw-r--r--lib/chef/provider/cookbook_file.rb2
-rw-r--r--lib/chef/provider/cron.rb2
-rw-r--r--lib/chef/provider/cron/unix.rb22
-rw-r--r--lib/chef/provider/deploy.rb2
-rw-r--r--lib/chef/provider/deploy/revision.rb2
-rw-r--r--lib/chef/provider/deploy/timestamped.rb2
-rw-r--r--lib/chef/provider/directory.rb2
-rw-r--r--lib/chef/provider/dsc_script.rb8
-rw-r--r--lib/chef/provider/env.rb35
-rw-r--r--lib/chef/provider/env/windows.rb6
-rw-r--r--lib/chef/provider/erl_call.rb2
-rw-r--r--lib/chef/provider/execute.rb7
-rw-r--r--lib/chef/provider/file.rb2
-rw-r--r--lib/chef/provider/git.rb66
-rw-r--r--lib/chef/provider/http_request.rb2
-rw-r--r--lib/chef/provider/link.rb2
-rw-r--r--lib/chef/provider/log.rb2
-rw-r--r--lib/chef/provider/lwrp_base.rb20
-rw-r--r--lib/chef/provider/mount/mount.rb2
-rw-r--r--lib/chef/provider/package/aix.rb2
-rw-r--r--lib/chef/provider/package/apt.rb2
-rw-r--r--lib/chef/provider/package/dpkg.rb2
-rw-r--r--lib/chef/provider/package/easy_install.rb2
-rw-r--r--lib/chef/provider/package/freebsd/port.rb10
-rw-r--r--lib/chef/provider/package/homebrew.rb6
-rw-r--r--lib/chef/provider/package/ips.rb2
-rw-r--r--lib/chef/provider/package/macports.rb3
-rw-r--r--lib/chef/provider/package/pacman.rb9
-rw-r--r--lib/chef/provider/package/paludis.rb6
-rw-r--r--lib/chef/provider/package/rpm.rb2
-rw-r--r--lib/chef/provider/package/rubygems.rb4
-rw-r--r--lib/chef/provider/package/smartos.rb2
-rw-r--r--lib/chef/provider/package/solaris.rb2
-rw-r--r--lib/chef/provider/package/yum.rb2
-rw-r--r--lib/chef/provider/powershell_script.rb4
-rw-r--r--lib/chef/provider/remote_directory.rb4
-rw-r--r--lib/chef/provider/route.rb2
-rw-r--r--lib/chef/provider/ruby_block.rb2
-rw-r--r--lib/chef/provider/script.rb6
-rw-r--r--lib/chef/provider/service/aix.rb126
-rw-r--r--lib/chef/provider/service/aixinit.rb117
-rw-r--r--lib/chef/provider/service/arch.rb6
-rw-r--r--lib/chef/provider/service/debian.rb64
-rw-r--r--lib/chef/provider/service/freebsd.rb4
-rw-r--r--lib/chef/provider/service/gentoo.rb3
-rw-r--r--lib/chef/provider/service/init.rb2
-rw-r--r--lib/chef/provider/service/insserv.rb22
-rw-r--r--lib/chef/provider/service/invokercd.rb6
-rw-r--r--lib/chef/provider/service/macosx.rb2
-rw-r--r--lib/chef/provider/service/redhat.rb12
-rw-r--r--lib/chef/provider/service/simple.rb2
-rw-r--r--lib/chef/provider/service/solaris.rb2
-rw-r--r--lib/chef/provider/service/systemd.rb7
-rw-r--r--lib/chef/provider/service/upstart.rb7
-rw-r--r--lib/chef/provider/service/windows.rb4
-rw-r--r--lib/chef/provider/subversion.rb2
-rw-r--r--lib/chef/provider/template.rb1
-rw-r--r--lib/chef/provider/whyrun_safe_ruby_block.rb2
-rw-r--r--lib/chef/provider_resolver.rb103
-rw-r--r--lib/chef/providers.rb6
-rw-r--r--lib/chef/recipe.rb2
-rw-r--r--lib/chef/resource.rb147
-rw-r--r--lib/chef/resource/apt_package.rb4
-rw-r--r--lib/chef/resource/bash.rb1
-rw-r--r--lib/chef/resource/bff_package.rb1
-rw-r--r--lib/chef/resource/breakpoint.rb2
-rw-r--r--lib/chef/resource/chef_gem.rb3
-rw-r--r--lib/chef/resource/conditional.rb6
-rw-r--r--lib/chef/resource/cookbook_file.rb5
-rw-r--r--lib/chef/resource/csh.rb1
-rw-r--r--lib/chef/resource/deploy.rb1
-rw-r--r--lib/chef/resource/deploy_revision.rb7
-rw-r--r--lib/chef/resource/directory.rb3
-rw-r--r--lib/chef/resource/dpkg_package.rb3
-rw-r--r--lib/chef/resource/dsc_script.rb3
-rw-r--r--lib/chef/resource/easy_install_package.rb3
-rw-r--r--lib/chef/resource/erl_call.rb1
-rw-r--r--lib/chef/resource/execute.rb35
-rw-r--r--lib/chef/resource/file.rb4
-rw-r--r--lib/chef/resource/freebsd_package.rb33
-rw-r--r--lib/chef/resource/gem_package.rb3
-rw-r--r--lib/chef/resource/git.rb3
-rw-r--r--lib/chef/resource/homebrew_package.rb3
-rw-r--r--lib/chef/resource/http_request.rb1
-rw-r--r--lib/chef/resource/ips_package.rb4
-rw-r--r--lib/chef/resource/link.rb3
-rw-r--r--lib/chef/resource/log.rb4
-rw-r--r--lib/chef/resource/lwrp_base.rb39
-rw-r--r--lib/chef/resource/macports_package.rb4
-rw-r--r--lib/chef/resource/pacman_package.rb3
-rw-r--r--lib/chef/resource/paludis_package.rb4
-rw-r--r--lib/chef/resource/perl.rb1
-rw-r--r--lib/chef/resource/powershell_script.rb2
-rw-r--r--lib/chef/resource/python.rb2
-rw-r--r--lib/chef/resource/remote_directory.rb3
-rw-r--r--lib/chef/resource/remote_file.rb2
-rw-r--r--lib/chef/resource/rpm_package.rb3
-rw-r--r--lib/chef/resource/ruby.rb1
-rw-r--r--lib/chef/resource/ruby_block.rb3
-rw-r--r--lib/chef/resource/script.rb27
-rw-r--r--lib/chef/resource/service.rb4
-rw-r--r--lib/chef/resource/smartos_package.rb7
-rw-r--r--lib/chef/resource/solaris_package.rb8
-rw-r--r--lib/chef/resource/subversion.rb1
-rw-r--r--lib/chef/resource/template.rb5
-rw-r--r--lib/chef/resource/timestamped_deploy.rb3
-rw-r--r--lib/chef/resource/whyrun_safe_ruby_block.rb1
-rw-r--r--lib/chef/resource/windows_package.rb4
-rw-r--r--lib/chef/resource/windows_script.rb3
-rw-r--r--lib/chef/resource/windows_service.rb3
-rw-r--r--lib/chef/resource/yum_package.rb4
-rw-r--r--lib/chef/resource_collection.rb279
-rw-r--r--lib/chef/resource_collection/resource_collection_serialization.rb59
-rw-r--r--lib/chef/resource_collection/resource_list.rb89
-rw-r--r--lib/chef/resource_collection/resource_set.rb170
-rw-r--r--lib/chef/resource_platform_map.rb151
-rw-r--r--lib/chef/run_context.rb6
-rw-r--r--lib/chef/shell/ext.rb2
-rw-r--r--lib/chef/util/dsc/local_configuration_manager.rb26
-rw-r--r--lib/chef/win32/version.rb2
-rw-r--r--spec/data/cb_version_cookbooks/cookbook2/files/test.txt0
-rw-r--r--spec/data/cb_version_cookbooks/cookbook2/templates/test.erb0
-rw-r--r--spec/data/cookbooks/ignorken/files/default/not_me.rb2
-rw-r--r--spec/data/cookbooks/ignorken/templates/ubuntu-12.10/not_me.rb2
-rw-r--r--spec/data/cookbooks/openldap/libraries/openldap.rb4
-rw-r--r--spec/data/cookbooks/openldap/libraries/openldap/version.rb3
-rw-r--r--spec/data/lwrp/providers/buck_passer.rb11
-rw-r--r--spec/data/lwrp/resources/foo.rb5
-rw-r--r--spec/data/lwrp_override/providers/buck_passer.rb15
-rw-r--r--spec/data/lwrp_override/resources/foo.rb7
-rwxr-xr-xspec/functional/assets/chefinittest34
-rwxr-xr-xspec/functional/assets/testchefsubsys11
-rw-r--r--spec/functional/event_loggers/windows_eventlog_spec.rb82
-rwxr-xr-xspec/functional/resource/aix_service_spec.rb136
-rwxr-xr-xspec/functional/resource/aixinit_service_spec.rb211
-rw-r--r--spec/functional/resource/batch_spec.rb15
-rw-r--r--spec/functional/resource/cron_spec.rb8
-rw-r--r--spec/functional/resource/dsc_script_spec.rb139
-rwxr-xr-xspec/functional/resource/env_spec.rb16
-rw-r--r--spec/functional/resource/execute_spec.rb113
-rw-r--r--spec/functional/resource/file_spec.rb2
-rw-r--r--spec/functional/resource/powershell_spec.rb50
-rw-r--r--spec/functional/resource/rpm_spec.rb9
-rw-r--r--spec/spec_helper.rb6
-rw-r--r--spec/support/chef_helpers.rb1
-rw-r--r--spec/support/lib/chef/provider/snakeoil.rb1
-rw-r--r--spec/support/lib/chef/resource/zen_follower.rb8
-rw-r--r--spec/support/platform_helpers.rb4
-rw-r--r--spec/support/shared/functional/windows_script.rb118
-rw-r--r--spec/support/shared/unit/execute_resource.rb7
-rw-r--r--spec/support/shared/unit/resource/static_provider_resolution.rb71
-rw-r--r--spec/support/shared/unit/script_resource.rb2
-rw-r--r--spec/support/shared/unit/windows_script_resource.rb37
-rw-r--r--spec/unit/application/apply_spec.rb (renamed from spec/unit/application/apply.rb)18
-rw-r--r--spec/unit/client_spec.rb2
-rw-r--r--spec/unit/config_spec.rb89
-rw-r--r--spec/unit/cookbook/cookbook_version_loader_spec.rb5
-rw-r--r--spec/unit/cookbook/metadata_spec.rb41
-rw-r--r--spec/unit/cookbook/syntax_check_spec.rb7
-rw-r--r--spec/unit/cookbook_version_spec.rb81
-rw-r--r--spec/unit/encrypted_data_bag_item/check_encrypted_spec.rb2
-rw-r--r--spec/unit/encrypted_data_bag_item_spec.rb4
-rw-r--r--spec/unit/knife/cookbook_site_share_spec.rb57
-rw-r--r--spec/unit/knife/core/ui_spec.rb28
-rw-r--r--spec/unit/knife/status_spec.rb3
-rw-r--r--spec/unit/knife_spec.rb19
-rw-r--r--spec/unit/lwrp_spec.rb37
-rw-r--r--spec/unit/node_map_spec.rb155
-rw-r--r--spec/unit/node_spec.rb4
-rw-r--r--spec/unit/platform_spec.rb23
-rw-r--r--spec/unit/provider/cron/unix_spec.rb138
-rw-r--r--spec/unit/provider/env/windows_spec.rb4
-rw-r--r--spec/unit/provider/env_spec.rb68
-rw-r--r--spec/unit/provider/execute_spec.rb28
-rw-r--r--spec/unit/provider/git_spec.rb46
-rw-r--r--spec/unit/provider/log_spec.rb4
-rw-r--r--spec/unit/provider/mount/mount_spec.rb16
-rw-r--r--spec/unit/provider/package/apt_spec.rb2
-rw-r--r--spec/unit/provider/package/freebsd/port_spec.rb22
-rw-r--r--spec/unit/provider/package/homebrew_spec.rb9
-rw-r--r--spec/unit/provider/package/pacman_spec.rb8
-rw-r--r--spec/unit/provider/package/paludis_spec.rb2
-rw-r--r--spec/unit/provider/package/rubygems_spec.rb420
-rw-r--r--spec/unit/provider/service/aix_service_spec.rb181
-rw-r--r--spec/unit/provider/service/aixinit_service_spec.rb269
-rw-r--r--spec/unit/provider_resolver_spec.rb387
-rw-r--r--spec/unit/recipe_spec.rb45
-rw-r--r--spec/unit/resource/apt_package_spec.rb21
-rw-r--r--spec/unit/resource/breakpoint_spec.rb12
-rw-r--r--spec/unit/resource/chef_gem_spec.rb21
-rw-r--r--spec/unit/resource/deploy_revision_spec.rb31
-rw-r--r--spec/unit/resource/deploy_spec.rb13
-rw-r--r--spec/unit/resource/dpkg_package_spec.rb22
-rw-r--r--spec/unit/resource/easy_install_package_spec.rb25
-rw-r--r--spec/unit/resource/execute_spec.rb5
-rw-r--r--spec/unit/resource/freebsd_package_spec.rb5
-rw-r--r--spec/unit/resource/gem_package_spec.rb21
-rw-r--r--spec/unit/resource/git_spec.rb12
-rw-r--r--spec/unit/resource/homebrew_package_spec.rb25
-rw-r--r--spec/unit/resource/ips_package_spec.rb21
-rw-r--r--spec/unit/resource/macports_package_spec.rb21
-rw-r--r--spec/unit/resource/pacman_package_spec.rb22
-rw-r--r--spec/unit/resource/rpm_package_spec.rb22
-rw-r--r--spec/unit/resource/service_spec.rb12
-rw-r--r--spec/unit/resource/smartos_package_spec.rb25
-rw-r--r--spec/unit/resource/solaris_package_spec.rb39
-rw-r--r--spec/unit/resource/subversion_spec.rb12
-rw-r--r--spec/unit/resource/timestamped_deploy_spec.rb34
-rw-r--r--spec/unit/resource/yum_package_spec.rb23
-rw-r--r--spec/unit/resource_collection/resource_list_spec.rb137
-rw-r--r--spec/unit/resource_collection/resource_set_spec.rb199
-rw-r--r--spec/unit/resource_collection_spec.rb159
-rw-r--r--spec/unit/resource_definition_spec.rb78
-rw-r--r--spec/unit/resource_platform_map_spec.rb164
-rw-r--r--spec/unit/resource_spec.rb89
-rw-r--r--spec/unit/rest_spec.rb154
-rw-r--r--spec/unit/runner_spec.rb483
-rw-r--r--spec/unit/shell/shell_ext_spec.rb2
-rw-r--r--spec/unit/util/dsc/local_configuration_manager_spec.rb25
269 files changed, 6693 insertions, 2374 deletions
diff --git a/.travis.yml b/.travis.yml
index ec05a9f002..65d28d0f68 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -19,6 +19,10 @@ branches:
script: bundle exec rspec --color --format progress
+env:
+ global:
+ - FORCE_FFI_YAJL=ext
+
matrix:
include:
- rvm: 1.9.3
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2daf841499..e22cb2f150 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -74,11 +74,74 @@
Improve the regex for /etc/rc.conf for the FreeBSD service provider
* [**Stanislav Bogatyrev**](https://github.com/realloc):
Fetch recipe_url before loading json_attribs in chef-solo (CHEF-5075)
-* [**Mal Graty**](https://github.com/mal): Workaround for a breaking change in git's shallow-clone behavior. (Issue 1563)
-* [**Dave Eddy**](https://github.com/bahamas10): Fix version detection in FreeBSD pkgng provider. (PR 1980)
+* [**Mal Graty**](https://github.com/mal):
+ Workaround for a breaking change in git's shallow-clone behavior. (Issue 1563)
+* [**Dave Eddy**](https://github.com/bahamas10):
+ Fix version detection in FreeBSD pkgng provider. (PR 1980)
+* [**Dan Rathbone**](https://github.com/rathers):
+ Fixed gem_package resource to be able to upgrade gems when version is not set.
+* [**Jean Mertz**](https://github.com/JeanMertz):
+ Made Chef Client load library folder recursively.
+* [**Eric Saxby**](https://github.com/sax):
+ Made Chef Client read the non-root crontab entries as the user specified in the resource.
+* [**sawanoboly**](https://github.com/sawanoboly):
+ Added `--dry-run` option to `knife cookbook site share` which displays the files that are to be uploaded to Supermarket.
+* [**Sander van Harmelen**](https://github.com/svanharmelen):
+ Fixed `Chef::HTTP` to be able to follow relative redirects.
+* [**Cory Stephenson**](https://github.com/Aevin1387):
+ Fixed FreeBSD port package provider to interpret FreeBSD version 10 correctly.
+* [**Brett Chalupa**](https://github.com/brettchalupa):
+ Added `source_url` and `issues_url` options to metadata to be used by Supermarket.
+* [**Anshul Sharma**](https://github.com/justanshulsharma):
+ Fixed Chef Client to use the `:client_name` instead of `:node_name` during initial client registration.
+* [**tbe**](https://github.com/tbe):
+ Fixed Paludis package provider to be able to interpret the package category.
+* [**David Workman**](https://github.com/workmad3):
+ Added a more clear error message to chef-apply when no recipe is given.
+* [**Joe Nuspl**](https://github.com/nvwls):
+ Added support for `sensitive` property to the execute resource.
+* [**Nolan Davidson**](https://github.com/nsdavidson):
+ Added an error message to prevent unintentional running of `exec()` in recipes.
+* [**wacky612**](https://github.com/wacky612):
+ Fixed a bug in pacman package provider that was preventing the installation of `bind` package.
+* [**Ionuț Arțăriși**](https://github.com/mapleoin):
+ Changed the default service provider to systemd on SLES versions 12 and higher.
+* [**Ionuț Arțăriși**](https://github.com/mapleoin):
+ Changed the default group provider to gpasswd on SLES versions 12 and higher.
+* [**Noah Kantrowitz**](https://github.com/coderanger):
+ Implemented [RFC017 - File Specificity Overhaul](https://github.com/opscode/chef-rfc/blob/master/rfc017-file-specificity.md).
+* [**James Bence**](https://github.com/jbence):
+ Improved the reliability of Git provider by making it to be more specific when selecting tags.
+* [**Jean Mertz**](https://github.com/JeanMertz):
+ Changed knife upload not to validate the ruby files under files & templates directories.
+* [**Alex Pop**](https://github.com/alexpop):
+ Made `knife cookbook create` to display the directory of the cookbook that is being created.
+* [**Alex Pop**](https://github.com/alexpop):
+ Fixed the information debug output for the configuration file being used when running knife.
+* [**Martin Smith**](https://github.com/martinb3):
+ Changed `knife cookbook site share` to make category an optional parameter when uploading cookbooks.
+ It is still required when the cookbook is being uploaded for the first time but on the consequent
+ uploads existing category of the cookbook will be used.
+* [**Nicolas DUPEUX**](https://github.com/vaxvms):
+ Added JSON output to `knife status` command. `--medium` and `--long` output formatting parameters are now supported in knife status.
+* [**Trevor North**](https://github.com/trvrnrth):
+ Removed dead code from `knife ssh`.
+* [**Nicolas Szalay**](https://github.com/rottenbytes):
+ Fixed a bug preventing mounting of cgroup type devices in the mount provider.
+* [**Anshul Sharma**](https://github.com/justanshulsharma):
+ Fixed inconsistent globbing in `knife from file` command.
+* [**Nicolas Szalay**](https://github.com/rottenbytes):
+ Made user prompts in knife more beautiful by adding a space after Y/N prompts.
+* [**Ivan Larionov**](https://github.com/xeron):
+ Made empty run_list to produce an empty array when using node.to_hash.
+
### Chef Contributions
+* Default `guard_interpreter` for `powershell_script` resource set to `:powershell_script`, for `batch` to `:batch`
+* Recipe definition now returns the retval of the definition
+* Add support for Windows 10 to version helper.
+* `dsc_script` resource should honor configuration parameters when `configuration_data_script` is not set (Issue #2209)
* Ruby has been updated to 2.1.3 along with rubygems update to 2.4.2
* Removed shelling out to erubis/ruby for syntax checks (>= 1.9 has been able
to do this in the ruby vm itself for awhile now and we've dropped 1.8.7 which
@@ -147,6 +210,16 @@
* Verify x509 properties of certificates in the :trusted_certs_dir during knife ssl check.
* Disable unforked interval chef-client runs.
* Removed dependencies on the 'json' gem, replaced with ffi-yajl. Use Chef::JSONCompat library for parsing and printing.
+* Restore the deprecation logic of #valid_actions in LWRPs until Chef 13.
+* Now that we don't allow unforked chef-client interval runs, remove the reloading of previously defined LWRPs.
+* Use shell_out to determine Chef::Config[:internal_locale], fix CentOS locale detection bug.
+* `only_if` and `not_if` attributes of `execute` resource now inherits the parent resource's
+ attributes when set to a `String`.
+* Retain the original value of `retries` for resources and display the original value when the run fails.
+* Added service provider for AIX.
+* The Windows env provider will delete elements even if they are only in ENV (and not in the registry)
+* Allow events to be logged to Windows Event Log
+* Fixed bug in env resource where a value containing the delimiter could never correctly match the existing values
## Last Release: 11.14.2
diff --git a/DOC_CHANGES.md b/DOC_CHANGES.md
index 08c343809a..7eb85eb894 100644
--- a/DOC_CHANGES.md
+++ b/DOC_CHANGES.md
@@ -521,3 +521,25 @@ end
Chef will then execute the Homebrew command as that user. The `homebrew_user` attribute can only be provided to the
`homebrew_package` resource, not the `package` resource.
+
+### Default `guard_interpreter` attribute for `powershell_script` resource
+
+For the `powershell_script` resource, the `guard_interpreter` attribute is set to `:powershell_script` by default. This means
+that if a string is supplied to an `only_if` or `not_if` attribute of a `powersell_script` resource, the PowerShell command
+interpreter (the 64-bit version) will be used to evaluate the guard. It also means that other features available to the guard
+when `guard_interpreter` is set to something other than `:default`, such as inheritance of attributes and the specification of
+process architectur of the guard process (i.e. 32-bit or 64-bit process) are available by default.
+
+In versions of Chef prior to Chef 12, the value of the attribute was `:default` by default, which uses the 32-bit version of the
+`cmd.exe` (batch script language) shell to evaluate strings supplied to guards.
+
+### Default `guard_interpreter` attribute for `batch` resource
+
+For the`batch` resource, the `guard_interpreter` attribute it is set to `:batch` by default. This means
+that if a string is supplied to an `only_if` or `not_if` attribute of a `batch` resource, the 64-bit version of the Windows
+default command interpreter, `cmd.exe`, will be used to evaluate the guard. It also means that other features available to the guard
+when `guard_interpreter` is set to something other than `:default`, such as inheritance of attributes and the specification of
+process architectur of the guard process (i.e. 32-bit or 64-bit process) are available by default.
+
+In versions of Chef prior to Chef 12, the value of the attribute was `:default` by default, which means the 32-bit version of the
+`cmd.exe` (batch script language) shell would be used to evaluate strings supplied to guards.
diff --git a/Gemfile b/Gemfile
index b298b396e0..1418235ebc 100644
--- a/Gemfile
+++ b/Gemfile
@@ -2,8 +2,6 @@ source "https://rubygems.org"
gemspec :name => "chef"
gem "activesupport", "< 4.0.0", :group => :compat_testing, :platform => "ruby"
-# TODO remove this when next version of ffi-yajl is released including this change
-gem "ffi-yajl", :github => 'tyler-ball/ffi-yajl', :branch => 'tball/remove_to_json'
group(:docgen) do
gem "yard"
diff --git a/README.md b/README.md
index 585199f00b..306baba163 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,7 @@ emerge, etc.):
* git
* C compiler, header files, etc. On Ubuntu/debian, use the
`build-essential` package.
-* ruby 1.8.7 or later (1.9.3+ recommended)
+* ruby 1.9.3 or later
* rubygems
* bundler
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index a6d1a65f51..ca1f504ba5 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,26 @@
# Chef Client Release Notes 12.0.0:
+# Internal API Changes in this Release
+
+These changes do not impact any cookbook code, but may impact tools that
+use the code base as a library. Authors of tools that rely on Chef
+internals should review these changes carefully and update their
+applications.
+
+## Changes to CookbookUpload
+
+`Chef::CookbookUpload.new` previously took a path as the second
+argument, but due to internal changes, this parameter was not used, and
+it has been removed. See: https://github.com/opscode/chef/commit/12c9bed3a5a7ab86ff78cb660d96f8b77ad6395d
+
+## Changes to FileVendor
+
+`Chef::Cookbook::FileVendor` was previously configured by passing a
+block to the `on_create` method; it is now configured by calling either
+`fetch_from_remote` or `fetch_from_disk`. See: https://github.com/opscode/chef/commit/3b2b4de8e7f0d55524f2a0ccaf3e1aa9f2d371eb
+
+# End-User Changes
+
## Knife Prefers `config.rb` to `knife.rb`.
Knife will now look for `config.rb` in preference to `knife.rb` for its
@@ -118,7 +139,7 @@ homebrew_package 'vim' do
end
```
-Chef will then execute the Homebrew command as that user. The `homebrew_user` attribute can only be provided to the
+Chef will then execute the Homebrew command as that user. The `homebrew_user` attribute can only be provided to the
`homebrew_package` resource, not the `package` resource.
## DSCL user provider now supports Mac OS X 10.7 and above.
@@ -249,25 +270,6 @@ Informational messages from knife are now sent to stderr, allowing you to pipe t
The `data_bag_item` dsl method can be used to load encrypted data bag items when an additional `secret` String parameter is included.
If no `secret` is provided but the data bag item is encrypted, `Chef::Config[:encrypted_data_bag_secret]` will be checked.
-# Internal API Changes in this Release
-
-These changes do not impact any cookbook code, but may impact tools that
-use the code base as a library. Authors of tools that rely on Chef
-internals should review these changes carefully and update their
-applications.
-
-## Changes to CookbookUpload
-
-`Chef::CookbookUpload.new` previously took a path as the second
-argument, but due to internal changes, this parameter was not used, and
-it has been removed. See: https://github.com/opscode/chef/commit/12c9bed3a5a7ab86ff78cb660d96f8b77ad6395d
-
-## Changes to FileVendor
-
-`Chef::Cookbook::FileVendor` was previously configured by passing a
-block to the `on_create` method; it is now configured by calling either
-`fetch_from_remote` or `fetch_from_disk`. See: https://github.com/opscode/chef/commit/3b2b4de8e7f0d55524f2a0ccaf3e1aa9f2d371eb
-
## 'group' provider on OSX properly uses 'dscl' to determine existing groups
On OSX, the 'group' provider would use 'etc' to determine existing groups,
@@ -315,3 +317,111 @@ error when `client_fork false` is set.
## Interval sleep occurs before converge
When running chef-client or chef-solo at intervals, the application will perform splay and interval sleep
before converging chef. (In previous releases, splay sleep occurred first, then convergance, then interval sleep).
+
+## `--dry-run` option for knife cookbook site share
+"knife cookbook site share" command now accepts a new command line option `--dry-run`. When this option is specified, command
+ will display the files that are about to be uploaded to the Supermarket.
+
+## New cookbook metadata attributes for Supermarket
+Cookbook metadata now accepts `source_url` and `issues_url` that should point to the source code of the cookbook and
+ the issue tracker of the cookbook. These attributes are being used by Supermarket.
+
+## CHEF RFC-017 - File Specificity Overhaul
+RFC-017 has two great advantages:
+1. It makes it easy to create cookbooks by removing the need for `default/` folder when adding templates and cookbook files.
+2. It enables the configuring a custom lookup logic when Chef is attempting to find cookbook files.
+
+You can read more about this RFC [here](https://github.com/opscode/chef-rfc/blob/master/rfc017-file-specificity.md).
+
+## JSON output for `knife status`
+`knife status` command now supports two additional output formats:
+
+1. `--medium`: Includes normal attributes in the output and presents the output as JSON.
+1. `--long`: Includes all attributes in the output and presents the output as JSON.
+
+## AIX Service Provider Support
+
+Chef 12 now supports managing services on AIX, using both the SRC (Subsystem Resource Controller) as well as the BSD-style init system. SRC is the default; the BSD-style provider can be selected using `Chef::Provider::Service::AixInit`.
+
+The SRC service provider will manage services as well as service groups. However, because SRC has no standard mechanism for starting services on system boot, `action :enable` and `action :disable` are not supported for SRC services. You may use the `execute` resource to invoke `mkitab`, for example, to add lines to `/etc/inittab` with the right parameters.
+
+## `guard_interpreter` attribute for `powershell_script` defaults to `:powershell_script`
+The default `guard_interpreter` attribute for the `powershell_script` resource is `:powershell_script`. This means that the
+64-bit version of the PowerShell shell will be used to evaluate strings supplied to the `not_if` or `only_if` attributes of the
+resource. Prior to this release, the default value was `:default`, which used the 32-bit version of the `cmd.exe` shell to evaluate the guard.
+
+If you are using guard expressions with the `powershell_script` resource in your recipes, you should override the
+`guard_interpreter` attribute to restore the behavior of guards for this resource in Chef 11:
+
+```ruby
+# The not_if will be evaluated with 64-bit PowerShell by default,
+# So override it to :default if your guard assumes 32-bit cmd.exe
+powershell_script 'make_safe_backup' do
+ guard_interpreter :default # Chef 11 behavior
+ code 'cp ~/data/nodes.json $env:systemroot/system32/data/nodes.bak'
+
+ # cmd.exe (batch) guard below behaves differently in 32-bit vs. 64-bit processes
+ not_if 'if NOT EXIST %SYSTEMROOT%\\system32\\data\\nodes.bak exit /b 1'
+end
+```
+
+If the code in your guard expression does not rely on the `cmd.exe` interpreter, e.g. it simply executes a process that should
+return an exit code such as `findstr datafile sentinelvalue`, and does not rely on being executed from a 32-bit process, then it
+should function identically when executed from the PowerShell shell and it is not necessary to override the attribute
+to`:default` to restore Chef 11 behavior.
+
+Note that with this change guards for the `powershell_script` resource will also inherit some attributes like `:architecture`, `:cwd`,
+`:environment`, and `:path`.
+
+## `guard_interpreter` attribute for `batch` resource defaults to `:batch`
+
+The default `guard_interpreter` attribute for the `batch` resource is now `:batch`. This means that the
+64-bit version of the `cmd.exe` shell will be used to evaluate strings supplied to the `not_if` or `only_if` attributes of the
+resource. Prior to this release, the default value was `:default`, which used the 32-bit version of the `cmd.exe` shell to evaluate the guard.
+
+Note that with this change guards for the `batch` resource will also inherit some attributes like `:architecture`, `:cwd`,
+`:environment`, and `:path`.
+
+Unless the code you supply to guard attributes (`only_if` and `not_if`) has logic that requires that the 32-bit version of
+`cmd.exe` be used to evaluate the guard or you need to avoid the inheritance behavior of guard options, that code should function identically in this release of Chef and Chef 11 releases.
+
+If an assumption of a 32-bit process for guard evaluation exists in your code, you can obtain the equivalent of Chef 11's 32-bit
+process behavior by supplying an architecture attribute to the guard as follows:
+
+```ruby
+# The not_if will be evaluated with 64-bit cmd.exe by default,
+# so you can verride it with the :architecture guard option to
+# make it 32-bit as it is in Chef 11
+batch 'make_safe_backup' do
+ code 'copy %USERPROFILE%\\data\\nodes.json %SYSTEMROOT%\\system32\\data\\nodes.bak'
+
+ # cmd.exe (batch) guard code below behaves differently in 32-bit vs. 64-bit processes
+ not_if 'if NOT EXIST %SYSTEMROOT%\\system32\\data\\nodes.bak exit /b 1', :architecture => :i386
+end
+```
+
+If in addition to the 32-bit process assumption you also need to avoid the inheritance behavior, you can revert completely to
+the Chef 11's 32-bit process, no inheritance behavior by supplying `:default` for the `guard_interpreter` as follows:
+
+```ruby
+# The not_if will be evaluated with 64-bit cmd.exe by default,
+# so override it to :default if your guard assumes 32-bit cmd.exe
+batch 'make_safe_backup' do
+ guard_interpreter :default # Revert to Chef 11 behavior
+ code 'copy %USERPROFILE%\\data\\nodes.json %SYSTEMROOT%\\system32\\data\\nodes.bak'
+
+ # cmd.exe (batch) guard code below behaves differently in 32-bit vs. 64-bit processes
+ not_if 'if NOT EXIST %SYSTEMROOT%\\system32\\data\\nodes.bak exit /b 1'
+end
+```
+
+## Chef Client logs events to Windows Event Log on Windows
+
+Chef 12 will log a small set of events to Windows Event Log. This feature is enabled by default, and can be disabled by the new config option `disable_event_logger`.
+
+Events by default will be logged to the "Application" event log on Windows. Chef will log event when:
+* Run starts
+* Run completes
+* Run fails
+
+Information about these events can be found in `Chef::EventDispatch::Base`.
diff --git a/Rakefile b/Rakefile
index b55ed8321b..70a45d94c0 100644
--- a/Rakefile
+++ b/Rakefile
@@ -52,6 +52,18 @@ task :pedant do
require File.expand_path('spec/support/pedant/run_pedant')
end
+task :build_eventlog do
+ Dir.chdir 'ext/win32-eventlog/' do
+ system 'rake build'
+ end
+end
+
+task :register_eventlog do
+ Dir.chdir 'ext/win32-eventlog/' do
+ system 'rake register'
+ end
+end
+
begin
require 'yard'
DOC_FILES = [ "README.rdoc", "LICENSE", "spec/tiny_server.rb", "lib/**/*.rb" ]
diff --git a/bin/chef-service-manager b/bin/chef-service-manager
index aaf91c7568..7cef10f506 100755
--- a/bin/chef-service-manager
+++ b/bin/chef-service-manager
@@ -28,7 +28,7 @@ if Chef::Platform.windows?
:service_name => "chef-client",
:service_display_name => "Chef Client Service",
:service_description => "Runs Chef Client on regular, configurable intervals.",
- :service_file_path => File.expand_path(File.join(File.dirname(__FILE__), '../lib/chef/application/windows_service.rb'))
+ :service_file_path => File.expand_path(File.join(File.dirname(__FILE__), '../../../../bin/chef-windows-service'))
}
Chef::Application::WindowsServiceManager.new(chef_client_service).run
else
diff --git a/bin/chef-windows-service b/bin/chef-windows-service
new file mode 100644
index 0000000000..292d5651fc
--- /dev/null
+++ b/bin/chef-windows-service
@@ -0,0 +1,35 @@
+#!/usr/bin/env ruby
+#
+# Author:: Jay Mundrawala (<jdm@getchef.com>)
+#
+# Copyright:: 2014, Chef Software, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Note:
+# The file is used by appbundler to generate a ruby file that
+# we can execute using the correct gems. The batch file we
+# generate will call that file, and will be registered as
+# a windows service.
+
+require 'rubygems'
+$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
+require 'chef'
+require 'chef/application/windows_service'
+
+if Chef::Platform.windows?
+ Chef::Application::WindowsService.mainloop
+else
+ puts "chef-windows-service is only available on Windows platforms."
+end
diff --git a/chef-x86-mingw32.gemspec b/chef-x86-mingw32.gemspec
index 6d69c4e7e6..a35ec5d63c 100644
--- a/chef-x86-mingw32.gemspec
+++ b/chef-x86-mingw32.gemspec
@@ -14,5 +14,8 @@ gemspec.add_dependency "win32-process", "0.7.3"
gemspec.add_dependency "win32-service", "0.8.2"
gemspec.add_dependency "win32-mmap", "0.4.0"
gemspec.add_dependency "wmi-lite", "~> 1.0"
+gemspec.add_dependency "win32-eventlog", "0.6.1"
+gemspec.extensions << "ext/win32-eventlog/Rakefile"
+gemspec.files += %w(ext/win32-eventlog/Rakefile ext/win32-eventlog/chef-log.man)
gemspec
diff --git a/chef.gemspec b/chef.gemspec
index f970bb32f9..427657f678 100644
--- a/chef.gemspec
+++ b/chef.gemspec
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
s.add_dependency "mixlib-shellout", ">= 2.0.0.rc.0", "< 3.0"
s.add_dependency "ohai", ">= 7.6.0.rc.0"
- s.add_dependency "ffi-yajl", "~> 1.1"
+ s.add_dependency "ffi-yajl", "~> 1.2"
s.add_dependency "net-ssh", "~> 2.6"
s.add_dependency "net-ssh-multi", "~> 1.1"
# CHEF-3027: The knife-cloud plugins require newer features from highline, core chef should not.
@@ -49,7 +49,7 @@ Gem::Specification.new do |s|
# chef-service-manager is a windows only executable.
# However gemspec doesn't give us a way to have this executable only
# on windows. So we're including this in all platforms.
- s.executables = %w( chef-client chef-solo knife chef-shell shef chef-apply chef-service-manager )
+ s.executables = %w( chef-client chef-solo knife chef-shell shef chef-apply chef-service-manager chef-windows-service )
s.require_path = 'lib'
s.files = %w(Rakefile LICENSE README.md CONTRIBUTING.md) + Dir.glob("{distro,lib,tasks,spec}/**/*", File::FNM_DOTMATCH).reject {|f| File.directory?(f) }
diff --git a/ext/win32-eventlog/Rakefile b/ext/win32-eventlog/Rakefile
new file mode 100644
index 0000000000..3112c27e8e
--- /dev/null
+++ b/ext/win32-eventlog/Rakefile
@@ -0,0 +1,50 @@
+require 'rubygems'
+require 'rake'
+require 'mkmf'
+
+desc "Building event log dll"
+
+def ensure_present(commands)
+ commands.each do |c|
+ unless find_executable c
+ warn "Could not find #{c}. Windows Event Logging will not correctly function."
+ end
+ end
+end
+
+
+EVT_MC_FILE = 'chef-log.man'
+EVT_RC_FILE = 'chef-log.rc'
+EVT_RESOURCE_OBJECT = 'resource.o'
+EVT_SHARED_OBJECT = 'chef-log.dll'
+MC = 'windmc'
+RC = 'windres'
+CC = 'gcc'
+
+ensure_present [MC, RC, CC]
+
+task :build => [EVT_RESOURCE_OBJECT, EVT_SHARED_OBJECT]
+task :default => [:build, :register]
+
+file EVT_RC_FILE=> EVT_MC_FILE do
+ sh "#{MC} #{EVT_MC_FILE}"
+end
+
+file EVT_RESOURCE_OBJECT => EVT_RC_FILE do
+ sh "#{RC} -i #{EVT_RC_FILE} -o #{EVT_RESOURCE_OBJECT}"
+end
+
+file EVT_SHARED_OBJECT => EVT_RESOURCE_OBJECT do
+ sh "#{CC} -o #{EVT_SHARED_OBJECT} -shared #{EVT_RESOURCE_OBJECT}"
+end
+
+task :register => EVT_SHARED_OBJECT do
+ require 'win32/eventlog'
+ dll_file = File.expand_path(EVT_SHARED_OBJECT)
+ Win32::EventLog.add_event_source(
+ :source => "Application",
+ :key_name => "Chef",
+ :event_message_file => dll_file,
+ :category_message_file => dll_file
+ )
+end
diff --git a/ext/win32-eventlog/chef-log.man b/ext/win32-eventlog/chef-log.man
new file mode 100644
index 0000000000..4b4a022d7f
--- /dev/null
+++ b/ext/win32-eventlog/chef-log.man
@@ -0,0 +1,26 @@
+MessageId=10000
+SymbolicName=RUN_START
+Language=English
+Starting Chef Client run v%1
+.
+
+MessageId=10001
+SymbolicName=RUN_STARTED
+Language=English
+Started Chef Client run %1
+.
+
+MessageId=10002
+SymbolicName=RUN_COMPLETED
+Language=English
+Completed Chef Client run %1 in %2 seconds
+.
+
+MessageId=10003
+SymbolicName=RUN_FAILED
+Language=English
+Failed Chef Client run %1 in %2 seconds.%n
+Exception type: %3%n
+Exception message: %4%n
+Exception backtrace: %5%n
+.
diff --git a/lib/chef/application/apply.rb b/lib/chef/application/apply.rb
index ea9154c6f2..22d835e876 100644
--- a/lib/chef/application/apply.rb
+++ b/lib/chef/application/apply.rb
@@ -31,7 +31,6 @@ class Chef::Application::Apply < Chef::Application
banner "Usage: chef-apply [RECIPE_FILE] [-e RECIPE_TEXT] [-s]"
-
option :execute,
:short => "-e RECIPE_TEXT",
:long => "--execute RECIPE_TEXT",
@@ -92,14 +91,17 @@ class Chef::Application::Apply < Chef::Application
end
def read_recipe_file(file_name)
- recipe_path = file_name
- unless File.exist?(recipe_path)
- Chef::Application.fatal!("No file exists at #{recipe_path}", 1)
+ if file_name.nil?
+ Chef::Application.fatal!("No recipe file was provided", 1)
+ else
+ recipe_path = File.expand_path(file_name)
+ unless File.exist?(recipe_path)
+ Chef::Application.fatal!("No file exists at #{recipe_path}", 1)
+ end
+ recipe_fh = open(recipe_path)
+ recipe_text = recipe_fh.read
+ [recipe_text, recipe_fh]
end
- recipe_path = File.expand_path(recipe_path)
- recipe_fh = open(recipe_path)
- recipe_text = recipe_fh.read
- [recipe_text, recipe_fh]
end
def get_recipe_and_run_context
diff --git a/lib/chef/application/client.rb b/lib/chef/application/client.rb
index 7f0a39782a..5463f504bc 100644
--- a/lib/chef/application/client.rb
+++ b/lib/chef/application/client.rb
@@ -238,6 +238,11 @@ class Chef::Application::Client < Chef::Application
:boolean => true
end
+ option :audit_mode,
+ :long => "--[no-]audit-mode",
+ :description => "If not specified, run converge and audit phase. If true, run only audit phase. If false, run only converge phase.",
+ :boolean => true
+
IMMEDIATE_RUN_SIGNAL = "1".freeze
attr_reader :chef_client_json
diff --git a/lib/chef/client.rb b/lib/chef/client.rb
index e531da5768..4f37bd0ee3 100644
--- a/lib/chef/client.rb
+++ b/lib/chef/client.rb
@@ -36,6 +36,8 @@ require 'chef/cookbook/file_vendor'
require 'chef/cookbook/file_system_file_vendor'
require 'chef/cookbook/remote_file_vendor'
require 'chef/event_dispatch/dispatcher'
+require 'chef/event_loggers/base'
+require 'chef/event_loggers/windows_eventlog'
require 'chef/formatters/base'
require 'chef/formatters/doc'
require 'chef/formatters/minimal'
@@ -151,7 +153,7 @@ class Chef
@runner = nil
@ohai = Ohai::System.new
- event_handlers = configure_formatters
+ event_handlers = configure_formatters + configure_event_loggers
event_handlers += Array(Chef::Config[:event_handlers])
@events = EventDispatch::Dispatcher.new(*event_handlers)
@@ -191,6 +193,22 @@ class Chef
end
end
+ def configure_event_loggers
+ if Chef::Config.disable_event_logger
+ []
+ else
+ Chef::Config.event_loggers.map do |evt_logger|
+ case evt_logger
+ when Symbol
+ Chef::EventLoggers.new(evt_logger)
+ when Class
+ evt_logger.new
+ else
+ end
+ end
+ end
+ end
+
# Instantiates a Chef::Node object, possibly loading the node's prior state
# when using chef-client. Delegates to policy_builder
#
@@ -282,7 +300,7 @@ class Chef
rescue Exception => e
# TODO: munge exception so a semantic failure message can be given to the
# user
- @events.registration_failed(node_name, e, config)
+ @events.registration_failed(client_name, e, config)
raise
end
diff --git a/lib/chef/config.rb b/lib/chef/config.rb
index 107b50ee85..d033a2981b 100644
--- a/lib/chef/config.rb
+++ b/lib/chef/config.rb
@@ -25,11 +25,13 @@ require 'mixlib/config'
require 'chef/util/selinux'
require 'chef/util/path_helper'
require 'pathname'
+require 'chef/mixin/shell_out'
class Chef
class Config
extend Mixlib::Config
+ extend Chef::Mixin::ShellOut
PathHelper = Chef::Util::PathHelper
@@ -76,6 +78,10 @@ class Chef
formatters << [name, file_path]
end
+ def self.add_event_logger(logger)
+ event_handlers << logger
+ end
+
# Config file to load (client.rb, knife.rb, etc. defaults set differently in knife, chef-client, etc.)
configurable(:config_file)
@@ -449,6 +455,15 @@ class Chef
# Event Handlers
default :event_handlers, []
+ default :disable_event_loggers, false
+ default :event_loggers do
+ evt_loggers = []
+ if Chef::Platform::windows?
+ evt_loggers << :win_evt
+ end
+ evt_loggers
+ end
+
# Exception Handlers
default :exception_handlers, []
@@ -604,25 +619,37 @@ class Chef
# available English UTF-8 locale. However, all modern POSIXen should support 'locale -a'.
default :internal_locale do
begin
- locales = `locale -a`.split
+ # https://github.com/opscode/chef/issues/2181
+ # Some systems have the `locale -a` command, but the result has
+ # invalid characters for the default encoding.
+ #
+ # For example, on CentOS 6 with ENV['LANG'] = "en_US.UTF-8",
+ # `locale -a`.split fails with ArgumentError invalid UTF-8 encoding.
+ locales = shell_out_with_systems_locale("locale -a").stdout.split
case
when locales.include?('C.UTF-8')
'C.UTF-8'
- when locales.include?('en_US.UTF-8')
+ when locales.include?('en_US.UTF-8'), locales.include?('en_US.utf8')
'en_US.UTF-8'
when locales.include?('en.UTF-8')
'en.UTF-8'
- when guesses = locales.select { |l| l =~ /^en_.*UTF-8$'/ }
- guesses.first
else
- Chef::Log.warn "Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support."
- 'C'
+ # Will match en_ZZ.UTF-8, en_ZZ.utf-8, en_ZZ.UTF8, en_ZZ.utf8
+ guesses = locales.select { |l| l =~ /^en_.*UTF-?8$/i }
+ unless guesses.empty?
+ guessed_locale = guesses.first
+ # Transform into the form en_ZZ.UTF-8
+ guessed_locale.gsub(/UTF-?8$/i, "UTF-8")
+ else
+ Chef::Log.warn "Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support."
+ 'C'
+ end
end
rescue
if Chef::Platform.windows?
Chef::Log.debug "Defaulting to locale en_US.UTF-8 on Windows, until it matters that we do something else."
else
- Chef::Log.warn "No usable locale -a command found, assuming you have en_US.UTF-8 installed."
+ Chef::Log.debug "No usable locale -a command found, assuming you have en_US.UTF-8 installed."
end
'en_US.UTF-8'
end
diff --git a/lib/chef/cookbook/cookbook_version_loader.rb b/lib/chef/cookbook/cookbook_version_loader.rb
index 5481ba7ddc..bcbfcbeec8 100644
--- a/lib/chef/cookbook/cookbook_version_loader.rb
+++ b/lib/chef/cookbook/cookbook_version_loader.rb
@@ -81,7 +81,7 @@ class Chef
load_as(:attribute_filenames, 'attributes', '*.rb')
load_as(:definition_filenames, 'definitions', '*.rb')
load_as(:recipe_filenames, 'recipes', '*.rb')
- load_as(:library_filenames, 'libraries', '*.rb')
+ load_recursively_as(:library_filenames, 'libraries', '*.rb')
load_recursively_as(:template_filenames, "templates", "*")
load_recursively_as(:file_filenames, "files", "*")
load_recursively_as(:resource_filenames, "resources", "*.rb")
diff --git a/lib/chef/cookbook/metadata.rb b/lib/chef/cookbook/metadata.rb
index 3964354d50..54e930135d 100644
--- a/lib/chef/cookbook/metadata.rb
+++ b/lib/chef/cookbook/metadata.rb
@@ -35,28 +35,31 @@ class Chef
# about Chef Cookbooks.
class Metadata
- NAME = 'name'.freeze
- DESCRIPTION = 'description'.freeze
- LONG_DESCRIPTION = 'long_description'.freeze
- MAINTAINER = 'maintainer'.freeze
- MAINTAINER_EMAIL = 'maintainer_email'.freeze
- LICENSE = 'license'.freeze
- PLATFORMS = 'platforms'.freeze
- DEPENDENCIES = 'dependencies'.freeze
- RECOMMENDATIONS = 'recommendations'.freeze
- SUGGESTIONS = 'suggestions'.freeze
- CONFLICTING = 'conflicting'.freeze
- PROVIDING = 'providing'.freeze
- REPLACING = 'replacing'.freeze
- ATTRIBUTES = 'attributes'.freeze
- GROUPINGS = 'groupings'.freeze
- RECIPES = 'recipes'.freeze
- VERSION = 'version'.freeze
+ NAME = 'name'.freeze
+ DESCRIPTION = 'description'.freeze
+ LONG_DESCRIPTION = 'long_description'.freeze
+ MAINTAINER = 'maintainer'.freeze
+ MAINTAINER_EMAIL = 'maintainer_email'.freeze
+ LICENSE = 'license'.freeze
+ PLATFORMS = 'platforms'.freeze
+ DEPENDENCIES = 'dependencies'.freeze
+ RECOMMENDATIONS = 'recommendations'.freeze
+ SUGGESTIONS = 'suggestions'.freeze
+ CONFLICTING = 'conflicting'.freeze
+ PROVIDING = 'providing'.freeze
+ REPLACING = 'replacing'.freeze
+ ATTRIBUTES = 'attributes'.freeze
+ GROUPINGS = 'groupings'.freeze
+ RECIPES = 'recipes'.freeze
+ VERSION = 'version'.freeze
+ SOURCE_URL = 'source_url'.freeze
+ ISSUES_URL = 'issues_url'.freeze
COMPARISON_FIELDS = [ :name, :description, :long_description, :maintainer,
:maintainer_email, :license, :platforms, :dependencies,
:recommendations, :suggestions, :conflicting, :providing,
- :replacing, :attributes, :groupings, :recipes, :version]
+ :replacing, :attributes, :groupings, :recipes, :version,
+ :source_url, :issues_url ]
VERSION_CONSTRAINTS = {:depends => DEPENDENCIES,
:recommends => RECOMMENDATIONS,
@@ -111,6 +114,8 @@ class Chef
@groupings = Mash.new
@recipes = Mash.new
@version = Version.new("0.0.0")
+ @source_url = ''
+ @issues_url = ''
@errors = []
end
@@ -413,7 +418,7 @@ class Chef
end
end
- # Adds an attribute )hat a user needs to configure for this cookbook. Takes
+ # Adds an attribute that a user needs to configure for this cookbook. Takes
# a name (with the / notation for a nested attribute), followed by any of
# these options
#
@@ -443,7 +448,9 @@ class Chef
:type => { :equal_to => [ "string", "array", "hash", "symbol", "boolean", "numeric" ], :default => "string" },
:required => { :equal_to => [ "required", "recommended", "optional", true, false ], :default => "optional" },
:recipes => { :kind_of => [ Array ], :default => [] },
- :default => { :kind_of => [ String, Array, Hash, Symbol, Numeric, TrueClass, FalseClass ] }
+ :default => { :kind_of => [ String, Array, Hash, Symbol, Numeric, TrueClass, FalseClass ] },
+ :source_url => { :kind_of => String },
+ :issues_url => { :kind_of => String }
}
)
options[:required] = remap_required_attribute(options[:required]) unless options[:required].nil?
@@ -469,23 +476,25 @@ class Chef
def to_hash
{
- NAME => self.name,
- DESCRIPTION => self.description,
- LONG_DESCRIPTION => self.long_description,
- MAINTAINER => self.maintainer,
- MAINTAINER_EMAIL => self.maintainer_email,
- LICENSE => self.license,
- PLATFORMS => self.platforms,
- DEPENDENCIES => self.dependencies,
- RECOMMENDATIONS => self.recommendations,
- SUGGESTIONS => self.suggestions,
- CONFLICTING => self.conflicting,
- PROVIDING => self.providing,
- REPLACING => self.replacing,
- ATTRIBUTES => self.attributes,
- GROUPINGS => self.groupings,
- RECIPES => self.recipes,
- VERSION => self.version
+ NAME => self.name,
+ DESCRIPTION => self.description,
+ LONG_DESCRIPTION => self.long_description,
+ MAINTAINER => self.maintainer,
+ MAINTAINER_EMAIL => self.maintainer_email,
+ LICENSE => self.license,
+ PLATFORMS => self.platforms,
+ DEPENDENCIES => self.dependencies,
+ RECOMMENDATIONS => self.recommendations,
+ SUGGESTIONS => self.suggestions,
+ CONFLICTING => self.conflicting,
+ PROVIDING => self.providing,
+ REPLACING => self.replacing,
+ ATTRIBUTES => self.attributes,
+ GROUPINGS => self.groupings,
+ RECIPES => self.recipes,
+ VERSION => self.version,
+ SOURCE_URL => self.source_url,
+ ISSUES_URL => self.issues_url
}
end
@@ -517,6 +526,8 @@ class Chef
@groupings = o[GROUPINGS] if o.has_key?(GROUPINGS)
@recipes = o[RECIPES] if o.has_key?(RECIPES)
@version = o[VERSION] if o.has_key?(VERSION)
+ @source_url = o[SOURCE_URL] if o.has_key?(SOURCE_URL)
+ @issues_url = o[ISSUES_URL] if o.has_key?(ISSUES_URL)
self
end
@@ -531,7 +542,9 @@ class Chef
VERSION_CONSTRAINTS.each do |dependency_type, hash_key|
if dependency_group = o[hash_key]
dependency_group.each do |cb_name, constraints|
- metadata.send(method_name, cb_name, *Array(constraints))
+ if metadata.respond_to?(method_name)
+ metadata.public_send(method_name, cb_name, *Array(constraints))
+ end
end
end
end
@@ -543,6 +556,36 @@ class Chef
from_hash(o)
end
+ # Sets the cookbook's source URL, or returns it.
+ #
+ # === Parameters
+ # maintainer<String>:: The source URL
+ #
+ # === Returns
+ # source_url<String>:: Returns the current source URL.
+ def source_url(arg=nil)
+ set_or_return(
+ :source_url,
+ arg,
+ :kind_of => [ String ]
+ )
+ end
+
+ # Sets the cookbook's issues URL, or returns it.
+ #
+ # === Parameters
+ # issues_url<String>:: The issues URL
+ #
+ # === Returns
+ # issues_url<String>:: Returns the current issues URL.
+ def issues_url(arg=nil)
+ set_or_return(
+ :issues_url,
+ arg,
+ :kind_of => [ String ]
+ )
+ end
+
private
def run_validation
diff --git a/lib/chef/cookbook/syntax_check.rb b/lib/chef/cookbook/syntax_check.rb
index 1437785259..96fc7e7b84 100644
--- a/lib/chef/cookbook/syntax_check.rb
+++ b/lib/chef/cookbook/syntax_check.rb
@@ -101,15 +101,24 @@ class Chef
end
def remove_ignored_files(file_list)
- return file_list unless chefignore.ignores.length > 0
+ return file_list if chefignore.ignores.empty?
+
file_list.reject do |full_path|
relative_pn = Chef::Util::PathHelper.relative_path_from(cookbook_path, full_path)
- chefignore.ignored? relative_pn.to_s
+ chefignore.ignored?(relative_pn.to_s)
end
end
+ def remove_uninteresting_ruby_files(file_list)
+ file_list.reject { |f| f =~ %r{#{cookbook_path}/(files|templates)/} }
+ end
+
def ruby_files
- remove_ignored_files Dir[File.join(Chef::Util::PathHelper.escape_glob(cookbook_path), '**', '*.rb')]
+ path = Chef::Util::PathHelper.escape_glob(cookbook_path)
+ files = Dir[File.join(path, '**', '*.rb')]
+ files = remove_ignored_files(files)
+ files = remove_uninteresting_ruby_files(files)
+ files
end
def untested_ruby_files
diff --git a/lib/chef/cookbook_version.rb b/lib/chef/cookbook_version.rb
index 95af94bdf7..505b403e65 100644
--- a/lib/chef/cookbook_version.rb
+++ b/lib/chef/cookbook_version.rb
@@ -315,13 +315,20 @@ class Chef
else
if segment == :files || segment == :templates
error_message = "Cookbook '#{name}' (#{version}) does not contain a file at any of these locations:\n"
- error_locations = [
- " #{segment}/#{node[:platform]}-#{node[:platform_version]}/#{filename}",
- " #{segment}/#{node[:platform]}/#{filename}",
- " #{segment}/default/#{filename}",
- ]
+ error_locations = if filename.is_a?(Array)
+ filename.map{|name| " #{File.join(segment.to_s, name)}"}
+ else
+ [
+ " #{segment}/#{node[:platform]}-#{node[:platform_version]}/#{filename}",
+ " #{segment}/#{node[:platform]}/#{filename}",
+ " #{segment}/default/#{filename}",
+ " #{segment}/#{filename}",
+ ]
+ end
error_message << error_locations.join("\n")
existing_files = segment_filenames(segment)
+ # Strip the root_dir prefix off all files for readability
+ existing_files.map!{|path| path[root_dir.length+1..-1]} if root_dir
# Show the files that the cookbook does have. If the user made a typo,
# hopefully they'll see it here.
unless existing_files.empty?
@@ -421,38 +428,44 @@ class Chef
def preferences_for_path(node, segment, path)
# only files and templates can be platform-specific
if segment.to_sym == :files || segment.to_sym == :templates
- begin
- platform, version = Chef::Platform.find_platform_and_version(node)
- rescue ArgumentError => e
- # Skip platform/version if they were not found by find_platform_and_version
- if e.message =~ /Cannot find a (?:platform|version)/
- platform = "/unknown_platform/"
- version = "/unknown_platform_version/"
- else
- raise
+ relative_search_path = if path.is_a?(Array)
+ path
+ else
+ begin
+ platform, version = Chef::Platform.find_platform_and_version(node)
+ rescue ArgumentError => e
+ # Skip platform/version if they were not found by find_platform_and_version
+ if e.message =~ /Cannot find a (?:platform|version)/
+ platform = "/unknown_platform/"
+ version = "/unknown_platform_version/"
+ else
+ raise
+ end
end
- end
- fqdn = node[:fqdn]
+ fqdn = node[:fqdn]
- # Break version into components, eg: "5.7.1" => [ "5.7.1", "5.7", "5" ]
- search_versions = []
- parts = version.to_s.split('.')
+ # Break version into components, eg: "5.7.1" => [ "5.7.1", "5.7", "5" ]
+ search_versions = []
+ parts = version.to_s.split('.')
- parts.size.times do
- search_versions << parts.join('.')
- parts.pop
- end
+ parts.size.times do
+ search_versions << parts.join('.')
+ parts.pop
+ end
- # Most specific to least specific places to find the path
- search_path = [ File.join(segment.to_s, "host-#{fqdn}", path) ]
- search_versions.each do |v|
- search_path << File.join(segment.to_s, "#{platform}-#{v}", path)
- end
- search_path << File.join(segment.to_s, platform.to_s, path)
- search_path << File.join(segment.to_s, "default", path)
+ # Most specific to least specific places to find the path
+ search_path = [ File.join("host-#{fqdn}", path) ]
+ search_versions.each do |v|
+ search_path << File.join("#{platform}-#{v}", path)
+ end
+ search_path << File.join(platform.to_s, path)
+ search_path << File.join("default", path)
+ search_path << path
- search_path
+ search_path
+ end
+ relative_search_path.map {|relative_path| File.join(segment.to_s, relative_path)}
else
[File.join(segment, path)]
end
@@ -666,7 +679,13 @@ class Chef
# Check if path is actually under root_path
next if parts[0] == '..'
if segment == :templates || segment == :files
- return [ pathname.to_s, parts[1] ]
+ # Check if pathname looks like files/foo or templates/foo (unscoped)
+ if pathname.each_filename.to_a.length == 2
+ # Use root_default in case the same path exists at root_default and default
+ return [ pathname.to_s, 'root_default' ]
+ else
+ return [ pathname.to_s, parts[1] ]
+ end
else
return [ pathname.to_s, 'default' ]
end
diff --git a/lib/chef/dsl/recipe.rb b/lib/chef/dsl/recipe.rb
index 3282320b8c..120497d56e 100644
--- a/lib/chef/dsl/recipe.rb
+++ b/lib/chef/dsl/recipe.rb
@@ -17,8 +17,8 @@
# limitations under the License.
#
-require 'chef/resource_platform_map'
require 'chef/mixin/convert_to_class_name'
+require 'chef/exceptions'
class Chef
module DSL
@@ -52,9 +52,7 @@ class Chef
end
def has_resource_definition?(name)
- yes_or_no = run_context.definitions.has_key?(name)
-
- yes_or_no
+ run_context.definitions.has_key?(name)
end
# Processes the arguments and block as a resource definition.
@@ -68,12 +66,10 @@ class Chef
# This sets up the parameter overrides
new_def.instance_eval(&block) if block
-
new_recipe = Chef::Recipe.new(cookbook_name, recipe_name, run_context)
new_recipe.params = new_def.params
new_recipe.params[:name] = args[0]
new_recipe.instance_eval(&new_def.recipe)
- new_recipe
end
# Instantiates a resource (via #build_resource), then adds it to the
@@ -85,21 +81,7 @@ class Chef
resource = build_resource(type, name, created_at, &resource_attrs_block)
- # Some resources (freebsd_package) can be invoked with multiple names
- # (package || freebsd_package).
- # https://github.com/opscode/chef/issues/1773
- # For these resources we want to make sure
- # their key in resource collection is same as the name they are declared
- # as. Since this might be a breaking change for resources that define
- # customer to_s methods, we are working around the issue by letting
- # resources know of their created_as_type until this issue is fixed in
- # Chef 12:
- # https://github.com/opscode/chef/issues/1817
- if resource.respond_to?(:created_as_type=)
- resource.created_as_type = type
- end
-
- run_context.resource_collection.insert(resource)
+ run_context.resource_collection.insert(resource, resource_type:type, instance_name:name)
resource
end
@@ -123,7 +105,7 @@ class Chef
# This behavior is very counter-intuitive and should be removed.
# See CHEF-3694, https://tickets.opscode.com/browse/CHEF-3694
# Moved to this location to resolve CHEF-5052, https://tickets.opscode.com/browse/CHEF-5052
- resource.load_prior_resource
+ resource.load_prior_resource(type, name)
resource.cookbook_name = cookbook_name
resource.recipe_name = recipe_name
# Determine whether this resource is being created in the context of an enclosing Provider
@@ -162,6 +144,10 @@ class Chef
end
end
+ def exec(args)
+ raise Chef::Exceptions::ResourceNotFound, "exec was called, but you probably meant to use an execute resource. If not, please call Kernel#exec explicitly. The exec block called was \"#{args}\""
+ end
+
end
end
end
diff --git a/lib/chef/encrypted_data_bag_item/assertions.rb b/lib/chef/encrypted_data_bag_item/assertions.rb
index e9acebbd29..0f9416e7b6 100644
--- a/lib/chef/encrypted_data_bag_item/assertions.rb
+++ b/lib/chef/encrypted_data_bag_item/assertions.rb
@@ -45,7 +45,7 @@ class Chef::EncryptedDataBagItem
def assert_aead_requirements_met!(algorithm)
unless OpenSSL::Cipher.method_defined?(:auth_data=)
- raise EncryptedDataBagRequirementsFailure, "The used Encrypted Data Bags version requires Ruby >= 1.9"
+ raise EncryptedDataBagRequirementsFailure, "The used Encrypted Data Bags version requires Ruby >= 2.0"
end
unless OpenSSL::Cipher.ciphers.include?(algorithm)
raise EncryptedDataBagRequirementsFailure, "The used Encrypted Data Bags version requires an OpenSSL version with \"#{algorithm}\" algorithm support"
diff --git a/lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb b/lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb
index 3567925844..9a54396174 100644
--- a/lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb
+++ b/lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb
@@ -25,7 +25,7 @@ class Chef::EncryptedDataBagItem
def assert_requirements_met!
unless OpenSSL::Cipher.method_defined?(:auth_data=)
- raise EncryptedDataBagRequirementsFailure, "The used Encrypted Data Bags version requires Ruby >= 1.9"
+ raise EncryptedDataBagRequirementsFailure, "The used Encrypted Data Bags version requires Ruby >= 2.0"
end
unless OpenSSL::Cipher.ciphers.include?(algorithm)
raise EncryptedDataBagRequirementsFailure, "The used Encrypted Data Bags version requires an OpenSSL version with \"#{algorithm}\" algorithm support"
diff --git a/lib/chef/event_loggers/base.rb b/lib/chef/event_loggers/base.rb
new file mode 100644
index 0000000000..1f676dd516
--- /dev/null
+++ b/lib/chef/event_loggers/base.rb
@@ -0,0 +1,62 @@
+#
+# Author:: Jay Mundrawala (<jdm@getchef.com>)
+#
+# Copyright:: 2014, Chef Software, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/event_dispatch/base'
+
+class Chef
+ module EventLoggers
+ class UnknownEventLogger < StandardError; end
+ class UnavailableEventLogger < StandardError; end
+
+ def self.event_loggers_by_name
+ @event_loggers_by_name ||= {}
+ end
+
+ def self.register(name, logger)
+ event_loggers_by_name[name.to_s] = logger
+ end
+
+ def self.by_name(name)
+ event_loggers_by_name[name]
+ end
+
+ def self.available_event_loggers
+ event_loggers_by_name.select do |key, val|
+ val.available?
+ end.keys
+ end
+
+ def self.new(name)
+ event_logger_class = by_name(name.to_s) or
+ raise UnknownEventLogger, "No event logger found for #{name} (available: #{available_event_loggers.join(', ')})"
+ raise UnavailableEventLogger unless available_event_loggers.include? name.to_s
+ event_logger_class.new
+ end
+
+ class Base < EventDispatch::Base
+ def self.short_name(name)
+ Chef::EventLoggers.register(name, self)
+ end
+
+ # Returns true if this implementation of EventLoggers can be used
+ def self.available?
+ false
+ end
+ end
+ end
+end
diff --git a/lib/chef/event_loggers/windows_eventlog.rb b/lib/chef/event_loggers/windows_eventlog.rb
new file mode 100644
index 0000000000..e3bbbfa1e6
--- /dev/null
+++ b/lib/chef/event_loggers/windows_eventlog.rb
@@ -0,0 +1,104 @@
+#
+# Author:: Jay Mundrawala (<jdm@getchef.com>)
+#
+# Copyright:: 2014, Chef Software, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/event_loggers/base'
+require 'chef/platform/query_helpers'
+
+if Chef::Platform::windows?
+ [:INFINITE, :WAIT_FAILED, :FORMAT_MESSAGE_IGNORE_INSERTS, :ERROR_INSUFFICIENT_BUFFER].each do |c|
+ # These are redefined in 'win32/eventlog'
+ Windows::Constants.send(:remove_const, c)
+ end
+
+ require 'win32/eventlog'
+ include Win32
+end
+
+class Chef
+ module EventLoggers
+ class WindowsEventLogger < EventLoggers::Base
+ short_name(:win_evt)
+
+ # These must match those that are defined in the manifest file
+ RUN_START_EVENT_ID = 10000
+ RUN_STARTED_EVENT_ID = 10001
+ RUN_COMPLETED_EVENT_ID = 10002
+ RUN_FAILED_EVENT_ID = 10003
+
+ EVENT_CATEGORY_ID = 11000
+ LOG_CATEGORY_ID = 11001
+
+ # Since we must install the event logger, this is not really configurable
+ SOURCE = 'Chef'
+
+ def self.available?
+ return Chef::Platform::windows?
+ end
+
+ def initialize
+ @eventlog = EventLog::open('Application')
+ end
+
+ def run_start(version)
+ @eventlog.report_event(
+ :event_type => EventLog::INFO_TYPE,
+ :source => SOURCE,
+ :event_id => RUN_START_EVENT_ID,
+ :data => [version]
+ )
+ end
+
+ def run_started(run_status)
+ @run_status = run_status
+ @eventlog.report_event(
+ :event_type => EventLog::INFO_TYPE,
+ :source => SOURCE,
+ :event_id => RUN_STARTED_EVENT_ID,
+ :data => [run_status.run_id]
+ )
+ end
+
+ def run_completed(node)
+ @eventlog.report_event(
+ :event_type => EventLog::INFO_TYPE,
+ :source => SOURCE,
+ :event_id => RUN_COMPLETED_EVENT_ID,
+ :data => [@run_status.run_id, @run_status.elapsed_time.to_s]
+ )
+ end
+
+ #Failed chef-client run %1 in %2 seconds.
+ #Exception type: %3
+ #Exception message: %4
+ #Exception backtrace: %5
+ def run_failed(e)
+ @eventlog.report_event(
+ :event_type => 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")]
+ )
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/exceptions.rb b/lib/chef/exceptions.rb
index 67429ac5a2..25f08455fc 100644
--- a/lib/chef/exceptions.rb
+++ b/lib/chef/exceptions.rb
@@ -91,7 +91,11 @@ class Chef
class ResourceNotFound < RuntimeError; end
# Can't find a Resource of this type that is valid on this platform.
- class NoSuchResourceType < NameError; end
+ class NoSuchResourceType < NameError
+ def initialize(short_name, node)
+ super "Cannot find a resource for #{short_name} on #{node[:platform]} version #{node[:platform_version]}"
+ end
+ end
class InvalidResourceSpecification < ArgumentError; end
class SolrConnectionError < RuntimeError; end
@@ -355,5 +359,12 @@ class Chef
end
class InvalidSearchQuery < ArgumentError; end
+
+ # Raised by Chef::ProviderResolver
+ class AmbiguousProviderResolution < RuntimeError
+ def initialize(resource, classes)
+ super "Found more than one provider for #{resource.resource_name} resource: #{classes}"
+ end
+ end
end
end
diff --git a/lib/chef/guard_interpreter/resource_guard_interpreter.rb b/lib/chef/guard_interpreter/resource_guard_interpreter.rb
index 229a8502c7..346b585d8c 100644
--- a/lib/chef/guard_interpreter/resource_guard_interpreter.rb
+++ b/lib/chef/guard_interpreter/resource_guard_interpreter.rb
@@ -33,10 +33,19 @@ class Chef
# to the resource
merge_inherited_attributes
- # Script resources have a code attribute, which is
- # what is used to execute the command, so include
- # that with attributes specified by caller in opts
- block_attributes = @command_opts.merge({:code => @command})
+ # Only execute and script resources and use guard attributes.
+ # The command to be executed on them are passed via different attributes.
+ # Script resources use code attribute and execute resources use
+ # command attribute. Moreover script resources are also execute
+ # resources. Here we make sure @command is assigned to the right
+ # attribute by checking the type of the resources.
+ # We need to make sure we check for Script first because any resource
+ # that can get to here is an Execute resource.
+ if @parent_resource.is_a? Chef::Resource::Script
+ block_attributes = @command_opts.merge({:code => @command})
+ else
+ block_attributes = @command_opts.merge({:command => @command})
+ end
# Handles cases like powershell_script where default
# attributes are different when used in a guard vs. not. For
@@ -79,8 +88,8 @@ class Chef
raise ArgumentError, "Specified guard_interpreter resource #{parent_resource.guard_interpreter.to_s} unknown for this platform"
end
- if ! resource_class.ancestors.include?(Chef::Resource::Script)
- raise ArgumentError, "Specified guard interpreter class #{resource_class} must be a kind of Chef::Resource::Script resource"
+ if ! resource_class.ancestors.include?(Chef::Resource::Execute)
+ raise ArgumentError, "Specified guard interpreter class #{resource_class} must be a kind of Chef::Resource::Execute resource"
end
empty_events = Chef::EventDispatch::Dispatcher.new
diff --git a/lib/chef/http.rb b/lib/chef/http.rb
index 7f2d00157b..ee951bd675 100644
--- a/lib/chef/http.rb
+++ b/lib/chef/http.rb
@@ -271,7 +271,7 @@ class Chef
elsif redirect_location = redirected_to(response)
if [:GET, :HEAD].include?(method)
follow_redirect do
- send_http_request(method, create_url(redirect_location), headers, body, &response_handler)
+ send_http_request(method, url+redirect_location, headers, body, &response_handler)
end
else
raise Exceptions::InvalidRedirect, "#{method} request was redirected from #{url} to #{redirect_location}. Only GET and HEAD support redirects."
diff --git a/lib/chef/json_compat.rb b/lib/chef/json_compat.rb
index 3350da0c13..d0b3b4c7f8 100644
--- a/lib/chef/json_compat.rb
+++ b/lib/chef/json_compat.rb
@@ -39,6 +39,8 @@ class Chef
CHEF_SANDBOX = "Chef::Sandbox".freeze
CHEF_RESOURCE = "Chef::Resource".freeze
CHEF_RESOURCECOLLECTION = "Chef::ResourceCollection".freeze
+ CHEF_RESOURCESET = "Chef::ResourceCollection::ResourceSet".freeze
+ CHEF_RESOURCELIST = "Chef::ResourceCollection::ResourceList".freeze
class <<self
@@ -145,8 +147,12 @@ class Chef
Chef::Resource
when CHEF_RESOURCECOLLECTION
Chef::ResourceCollection
+ when CHEF_RESOURCESET
+ Chef::ResourceCollection::ResourceSet
+ when CHEF_RESOURCELIST
+ Chef::ResourceCollection::ResourceList
when /^Chef::Resource/
- Chef::Resource.find_subclass_by_name(json_class)
+ Chef::Resource.find_descendants_by_name(json_class)
else
raise Chef::Exceptions::JSON::ParseError, "Unsupported `json_class` type '#{json_class}'"
end
diff --git a/lib/chef/knife.rb b/lib/chef/knife.rb
index 6421384f01..0c079792a4 100644
--- a/lib/chef/knife.rb
+++ b/lib/chef/knife.rb
@@ -164,7 +164,6 @@ class Chef
def self.load_config(explicit_config_file)
config_loader = WorkstationConfigLoader.new(explicit_config_file, Chef::Log)
- Chef::Log.debug("Using configuration from #{config_loader.config_location}")
config_loader.load
ui.warn("No knife configuration file found") if config_loader.no_config_found?
@@ -393,6 +392,8 @@ class Chef
merge_configs
apply_computed_config
+ # This has to be after apply_computed_config so that Mixlib::Log is configured
+ Chef::Log.info("Using configuration from #{config[:config_file]}") if config[:config_file]
end
def show_usage
diff --git a/lib/chef/knife/cookbook_create.rb b/lib/chef/knife/cookbook_create.rb
index f4183a7245..e17a54079f 100644
--- a/lib/chef/knife/cookbook_create.rb
+++ b/lib/chef/knife/cookbook_create.rb
@@ -80,7 +80,7 @@ class Chef
end
def create_cookbook(dir, cookbook_name, copyright, license)
- msg("** Creating cookbook #{cookbook_name}")
+ msg("** Creating cookbook #{cookbook_name} in #{dir}")
FileUtils.mkdir_p "#{File.join(dir, cookbook_name, "attributes")}"
FileUtils.mkdir_p "#{File.join(dir, cookbook_name, "recipes")}"
FileUtils.mkdir_p "#{File.join(dir, cookbook_name, "definitions")}"
diff --git a/lib/chef/knife/cookbook_site_share.rb b/lib/chef/knife/cookbook_site_share.rb
index 7204ccdb1c..b4a7873c71 100644
--- a/lib/chef/knife/cookbook_site_share.rb
+++ b/lib/chef/knife/cookbook_site_share.rb
@@ -31,7 +31,7 @@ class Chef
require 'chef/cookbook_site_streaming_uploader'
end
- banner "knife cookbook site share COOKBOOK CATEGORY (options)"
+ banner "knife cookbook site share COOKBOOK [CATEGORY] (options)"
category "cookbook site"
option :cookbook_path,
@@ -40,17 +40,28 @@ class Chef
:description => "A colon-separated path to look for cookbooks in",
:proc => lambda { |o| Chef::Config.cookbook_path = o.split(":") }
+ option :dry_run,
+ :long => '--dry-run',
+ :short => '-n',
+ :boolean => true,
+ :default => false,
+ :description => "Don't take action, only print what files will be upload to SuperMarket."
+
def run
- if @name_args.length < 2
+ config[:cookbook_path] ||= Chef::Config[:cookbook_path]
+
+ if @name_args.length < 1
show_usage
- ui.fatal("You must specify the cookbook name and the category you want to share this cookbook to.")
- exit 1
+ ui.fatal("You must specify the cookbook name.")
+ exit(1)
+ elsif @name_args.length < 2
+ cookbook_name = @name_args[0]
+ category = get_category(cookbook_name)
+ else
+ cookbook_name = @name_args[0]
+ category = @name_args[1]
end
- config[:cookbook_path] ||= Chef::Config[:cookbook_path]
-
- cookbook_name = @name_args[0]
- category = @name_args[1]
cl = Chef::CookbookLoader.new(config[:cookbook_path])
if cl.cookbook_exists?(cookbook_name)
cookbook = cl[cookbook_name]
@@ -66,6 +77,14 @@ class Chef
exit(1)
end
+ if config[:dry_run]
+ ui.info("Not uploading #{cookbook_name}.tgz due to --dry-run flag.")
+ result = shell_out!("tar -tzf #{cookbook_name}.tgz", :cwd => tmp_cookbook_dir)
+ ui.info(result.stdout)
+ FileUtils.rm_rf tmp_cookbook_dir
+ return
+ end
+
begin
do_upload("#{tmp_cookbook_dir}/#{cookbook_name}.tgz", category, Chef::Config[:node_name], Chef::Config[:client_key])
ui.info("Upload complete!")
@@ -84,6 +103,22 @@ class Chef
end
+ def get_category(cookbook_name)
+ begin
+ data = noauth_rest.get_rest("http://cookbooks.opscode.com/api/v1/cookbooks/#{@name_args[0]}")
+ if !data["category"] && data["error_code"]
+ ui.fatal("Received an error from the Opscode Cookbook site: #{data["error_code"]}. On the first time you upload it, you are required to specify the category you want to share this cookbook to.")
+ exit(1)
+ else
+ data['category']
+ end
+ rescue => e
+ ui.fatal("Unable to reach Opscode Cookbook Site: #{e.message}. Increase log verbosity (-VV) for more information.")
+ Chef::Log.debug("\n#{e.backtrace.join("\n")}")
+ exit(1)
+ end
+ end
+
def do_upload(cookbook_filename, cookbook_category, user_id, user_secret_filename)
uri = "https://supermarket.getchef.com/api/v1/cookbooks"
diff --git a/lib/chef/knife/core/status_presenter.rb b/lib/chef/knife/core/status_presenter.rb
new file mode 100644
index 0000000000..3298d5e4ac
--- /dev/null
+++ b/lib/chef/knife/core/status_presenter.rb
@@ -0,0 +1,156 @@
+#
+# Author:: Nicolas DUPEUX (<nicolas.dupeux@arkea.com>)
+# Copyright:: Copyright (c) 2011 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 'chef/knife/core/text_formatter'
+require 'chef/knife/core/generic_presenter'
+
+class Chef
+ class Knife
+ module Core
+
+ # This module may be included into a knife subcommand class to automatically
+ # add configuration options used by the StatusPresenter
+ module StatusFormattingOptions
+ # :nodoc:
+ # Would prefer to do this in a rational way, but can't be done b/c of
+ # Mixlib::CLI's design :(
+ def self.included(includer)
+ includer.class_eval do
+ option :medium_output,
+ :short => '-m',
+ :long => '--medium',
+ :boolean => true,
+ :default => false,
+ :description => 'Include normal attributes in the output'
+
+ option :long_output,
+ :short => '-l',
+ :long => '--long',
+ :boolean => true,
+ :default => false,
+ :description => 'Include all attributes in the output'
+ end
+ end
+ end
+
+ #==Chef::Knife::Core::StatusPresenter
+ # A customized presenter for Chef::Node objects. Supports variable-length
+ # output formats for displaying node data
+ class StatusPresenter < GenericPresenter
+
+ def format(data)
+ if parse_format_option == :json
+ summarize_json(data)
+ else
+ super
+ end
+ end
+
+ def summarize_json(list)
+ result_list = []
+ list.each do |node|
+ result = {}
+
+ result["name"] = node.name
+ result["chef_environment"] = node.chef_environment
+ ip = (node[:ec2] && node[:ec2][:public_ipv4]) || node[:ipaddress]
+ fqdn = (node[:ec2] && node[:ec2][:public_hostname]) || node[:fqdn]
+ result["ip"] = ip if ip
+ result["fqdn"] = fqdn if fqdn
+ result["run_list"] = node.run_list if config[:run_list]
+ result["ohai_time"] = node[:ohai_time]
+ result["platform"] = node[:platform] if node[:platform]
+ result["platform_version"] = node[:platform_version] if node[:platform_version]
+
+ if config[:long_output]
+ result["default"] = node.default_attrs
+ result["override"] = node.override_attrs
+ result["automatic"] = node.automatic_attrs
+ end
+ result_list << result
+ end
+
+ Chef::JSONCompat.to_json_pretty(result_list)
+ end
+
+ # Converts a Chef::Node object to a string suitable for output to a
+ # terminal. If config[:medium_output] or config[:long_output] are set
+ # the volume of output is adjusted accordingly. Uses colors if enabled
+ # in the ui object.
+ def summarize(list)
+ summarized=''
+ list.each do |data|
+ node = data
+ # special case ec2 with their split horizon whatsis.
+ ip = (node[:ec2] && node[:ec2][:public_ipv4]) || node[:ipaddress]
+ fqdn = (node[:ec2] && node[:ec2][:public_hostname]) || node[:fqdn]
+
+ hours, minutes, seconds = time_difference_in_hms(node["ohai_time"])
+ hours_text = "#{hours} hour#{hours == 1 ? ' ' : 's'}"
+ minutes_text = "#{minutes} minute#{minutes == 1 ? ' ' : 's'}"
+ run_list = "#{node.run_list}" if config[:run_list]
+ if hours > 24
+ color = :red
+ text = hours_text
+ elsif hours >= 1
+ color = :yellow
+ text = hours_text
+ else
+ color = :green
+ text = minutes_text
+ end
+
+ line_parts = Array.new
+ line_parts << @ui.color(text, color) + ' ago' << node.name
+ line_parts << fqdn if fqdn
+ line_parts << ip if ip
+ line_parts << run_list if run_list
+
+ if node['platform']
+ platform = node['platform']
+ if node['platform_version']
+ platform << " #{node['platform_version']}"
+ end
+ line_parts << platform
+ end
+
+ summarized=summarized + line_parts.join(', ') + ".\n"
+ end
+ summarized
+ end
+
+ def key(key_text)
+ ui.color(key_text, :cyan)
+ end
+
+ # :nodoc:
+ # TODO: this is duplicated from StatusHelper in the Webui. dedup.
+ def time_difference_in_hms(unix_time)
+ now = Time.now.to_i
+ difference = now - unix_time.to_i
+ hours = (difference / 3600).to_i
+ difference = difference % 3600
+ minutes = (difference / 60).to_i
+ seconds = (difference % 60)
+ return [hours, minutes, seconds]
+ end
+
+ end
+ end
+ end
+end
diff --git a/lib/chef/knife/core/ui.rb b/lib/chef/knife/core/ui.rb
index 0007480ea2..00a4834638 100644
--- a/lib/chef/knife/core/ui.rb
+++ b/lib/chef/knife/core/ui.rb
@@ -113,7 +113,7 @@ class Chef
# determined by the value of `config[:color]`. When output is not to a
# terminal, colored output is never used
def color?
- Chef::Config[:color] && stdout.tty? && !Chef::Platform.windows?
+ Chef::Config[:color] && stdout.tty?
end
def ask(*args, &block)
@@ -209,11 +209,11 @@ class Chef
def confirmation_instructions(default_choice)
case default_choice
when true
- '? (Y/n)'
+ '? (Y/n) '
when false
- '? (y/N)'
+ '? (y/N) '
else
- '? (Y/N)'
+ '? (Y/N) '
end
end
diff --git a/lib/chef/knife/node_from_file.rb b/lib/chef/knife/node_from_file.rb
index d69392a8db..66f2a466fd 100644
--- a/lib/chef/knife/node_from_file.rb
+++ b/lib/chef/knife/node_from_file.rb
@@ -35,16 +35,17 @@ class Chef
end
def run
- updated = loader.load_from('nodes', @name_args[0])
-
- updated.save
-
- output(format_for_display(updated)) if config[:print_after]
-
- ui.info("Updated Node #{updated.name}!")
+ @name_args.each do |arg|
+ updated = loader.load_from('nodes', arg)
+
+ updated.save
+
+ output(format_for_display(updated)) if config[:print_after]
+
+ ui.info("Updated Node #{updated.name}!")
+ end
end
end
end
end
-
diff --git a/lib/chef/knife/ssh.rb b/lib/chef/knife/ssh.rb
index accca39aa2..de4c60d998 100644
--- a/lib/chef/knife/ssh.rb
+++ b/lib/chef/knife/ssh.rb
@@ -106,13 +106,6 @@ class Chef
def session
config[:on_error] ||= :skip
ssh_error_handler = Proc.new do |server|
- if config[:manual]
- node_name = server.host
- else
- @action_nodes.each do |n|
- node_name = n if format_for_display(n)[config[:attribute]] == server.host
- end
- end
case config[:on_error]
when :skip
ui.warn "Failed to connect to #{server.host} -- #{$!.class.name}: #{$!.message}"
diff --git a/lib/chef/knife/status.rb b/lib/chef/knife/status.rb
index 5906a4a624..93e81f8f03 100644
--- a/lib/chef/knife/status.rb
+++ b/lib/chef/knife/status.rb
@@ -17,13 +17,13 @@
#
require 'chef/knife'
+require 'chef/knife/core/status_presenter'
class Chef
class Knife
class Status < Knife
deps do
- require 'highline'
require 'chef/search/query'
end
@@ -44,74 +44,27 @@ class Chef
:long => "--hide-healthy",
:description => "Hide nodes that have run chef in the last hour"
- def highline
- @h ||= HighLine.new
- end
-
def run
+ ui.use_presenter Knife::Core::StatusPresenter
all_nodes = []
q = Chef::Search::Query.new
- query = @name_args[0] || "*:*"
+ query = @name_args[0] ? @name_args[0].dup : '*:*'
+ if config[:hide_healthy]
+ time = Time.now.to_i
+ query_unhealthy = "NOT ohai_time:[" << (time - 60*60).to_s << " TO " << time.to_s << "]"
+ query << ' AND ' << query_unhealthy << @name_args[0] if @name_args[0]
+ query = query_unhealthy unless @name_args[0]
+ end
q.search(:node, query) do |node|
all_nodes << node
end
- all_nodes.sort { |n1, n2|
+ output(all_nodes.sort { |n1, n2|
if (config[:sort_reverse] || Chef::Config[:knife][:sort_status_reverse])
(n2["ohai_time"] or 0) <=> (n1["ohai_time"] or 0)
else
(n1["ohai_time"] or 0) <=> (n2["ohai_time"] or 0)
end
- }.each do |node|
- if node.has_key?("ec2")
- fqdn = node['ec2']['public_hostname']
- ipaddress = node['ec2']['public_ipv4']
- else
- fqdn = node['fqdn']
- ipaddress = node['ipaddress']
- end
- hours, minutes, seconds = time_difference_in_hms(node["ohai_time"])
- hours_text = "#{hours} hour#{hours == 1 ? ' ' : 's'}"
- minutes_text = "#{minutes} minute#{minutes == 1 ? ' ' : 's'}"
- run_list = "#{node.run_list}" if config[:run_list]
- if hours > 24
- color = :red
- text = hours_text
- elsif hours >= 1
- color = :yellow
- text = hours_text
- else
- color = :green
- text = minutes_text
- end
-
- line_parts = Array.new
- line_parts << @ui.color(text, color) + " ago" << node.name
- line_parts << fqdn if fqdn
- line_parts << ipaddress if ipaddress
- line_parts << run_list if run_list
-
- if node['platform']
- platform = node['platform']
- if node['platform_version']
- platform << " #{node['platform_version']}"
- end
- line_parts << platform
- end
- highline.say(line_parts.join(', ') + '.') unless (config[:hide_healthy] && hours < 1)
- end
-
- end
-
- # :nodoc:
- # TODO: this is duplicated from StatusHelper in the Webui. dedup.
- def time_difference_in_hms(unix_time)
- now = Time.now.to_i
- difference = now - unix_time.to_i
- hours = (difference / 3600).to_i
- difference = difference % 3600
- minutes = (difference / 60).to_i
- seconds = (difference % 60)
- return [hours, minutes, seconds]
+ })
end
end
diff --git a/lib/chef/mixin/command/unix.rb b/lib/chef/mixin/command/unix.rb
index b63a02663b..2bad4e6bcf 100644
--- a/lib/chef/mixin/command/unix.rb
+++ b/lib/chef/mixin/command/unix.rb
@@ -100,9 +100,9 @@ class Chef
begin
if cmd.kind_of?(Array)
- exec(*cmd)
+ Kernel.exec(*cmd)
else
- exec(cmd)
+ Kernel.exec(cmd)
end
raise 'forty-two'
rescue Exception => e
diff --git a/lib/chef/mixin/convert_to_class_name.rb b/lib/chef/mixin/convert_to_class_name.rb
index f849b8de6a..19f229fdd3 100644
--- a/lib/chef/mixin/convert_to_class_name.rb
+++ b/lib/chef/mixin/convert_to_class_name.rb
@@ -61,6 +61,60 @@ class Chef
base.to_s + (file_base == 'default' ? '' : "_#{file_base}")
end
+ # Copied from rails activesupport. In ruby >= 2.0 const_get will just do this, so this can
+ # be deprecated and removed.
+ #
+ # MIT LICENSE is here: https://github.com/rails/rails/blob/master/activesupport/MIT-LICENSE
+
+ # Tries to find a constant with the name specified in the argument string.
+ #
+ # 'Module'.constantize # => Module
+ # 'Test::Unit'.constantize # => Test::Unit
+ #
+ # The name is assumed to be the one of a top-level constant, no matter
+ # whether it starts with "::" or not. No lexical context is taken into
+ # account:
+ #
+ # C = 'outside'
+ # module M
+ # C = 'inside'
+ # C # => 'inside'
+ # 'C'.constantize # => 'outside', same as ::C
+ # end
+ #
+ # NameError is raised when the name is not in CamelCase or the constant is
+ # unknown.
+ def constantize(camel_cased_word)
+ names = camel_cased_word.split('::')
+
+ # Trigger a built-in NameError exception including the ill-formed constant in the message.
+ Object.const_get(camel_cased_word) if names.empty?
+
+ # Remove the first blank element in case of '::ClassName' notation.
+ names.shift if names.size > 1 && names.first.empty?
+
+ names.inject(Object) do |constant, name|
+ if constant == Object
+ constant.const_get(name)
+ else
+ candidate = constant.const_get(name)
+ next candidate if constant.const_defined?(name, false)
+ next candidate unless Object.const_defined?(name)
+
+ # Go down the ancestors to check if it is owned directly. The check
+ # stops when we reach Object or the end of ancestors tree.
+ constant = constant.ancestors.inject do |const, ancestor|
+ break const if ancestor == Object
+ break ancestor if ancestor.const_defined?(name, false)
+ const
+ end
+
+ # owner is in Object, so raise
+ constant.const_get(name, false)
+ end
+ end
+ end
+
end
end
end
diff --git a/lib/chef/mixin/descendants_tracker.rb b/lib/chef/mixin/descendants_tracker.rb
new file mode 100644
index 0000000000..75d1f620d4
--- /dev/null
+++ b/lib/chef/mixin/descendants_tracker.rb
@@ -0,0 +1,82 @@
+#
+# Copyright (c) 2005-2012 David Heinemeier Hansson
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+
+# This is lifted from rails activesupport (note the copyright above):
+# https://github.com/rails/rails/blob/9f84e60ac9d7bf07d6ae1bc94f3941f5b8f1a228/activesupport/lib/active_support/descendants_tracker.rb
+
+class Chef
+ module Mixin
+ module DescendantsTracker
+ @@direct_descendants = {}
+
+ class << self
+ def direct_descendants(klass)
+ @@direct_descendants[klass] || []
+ end
+
+ def descendants(klass)
+ arr = []
+ accumulate_descendants(klass, arr)
+ arr
+ end
+
+ def find_descendants_by_name(klass, name)
+ descendants(klass).first {|c| c.name == name }
+ end
+
+ # This is the only method that is not thread safe, but is only ever called
+ # during the eager loading phase.
+ def store_inherited(klass, descendant)
+ (@@direct_descendants[klass] ||= []) << descendant
+ end
+
+ private
+
+ def accumulate_descendants(klass, acc)
+ if direct_descendants = @@direct_descendants[klass]
+ acc.concat(direct_descendants)
+ direct_descendants.each { |direct_descendant| accumulate_descendants(direct_descendant, acc) }
+ end
+ end
+ end
+
+ def inherited(base)
+ DescendantsTracker.store_inherited(self, base)
+ super
+ end
+
+ def direct_descendants
+ DescendantsTracker.direct_descendants(self)
+ end
+
+ def find_descendants_by_name(name)
+ DescendantsTracker.find_descendants_by_name(self, name)
+ end
+
+ def descendants
+ DescendantsTracker.descendants(self)
+ end
+ end
+ end
+end
diff --git a/lib/chef/mixin/homebrew_user.rb b/lib/chef/mixin/homebrew_user.rb
index 854a954a90..ab6fb19563 100644
--- a/lib/chef/mixin/homebrew_user.rb
+++ b/lib/chef/mixin/homebrew_user.rb
@@ -36,7 +36,7 @@ class Chef
# the brew executable.
def find_homebrew_uid(provided_user = nil)
# They could provide us a user name or a UID
- unless provided_user.nil?
+ if provided_user
return provided_user if provided_user.is_a? Integer
return Etc.getpwnam(provided_user).uid
end
diff --git a/lib/chef/mixin/shell_out.rb b/lib/chef/mixin/shell_out.rb
index 82772b584a..5b05e788db 100644
--- a/lib/chef/mixin/shell_out.rb
+++ b/lib/chef/mixin/shell_out.rb
@@ -15,10 +15,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# chef/shell_out has been deprecated in favor of mixlib/shellout
-# chef/shell_out is still required here to ensure backward compatibility
-require 'chef/shell_out'
-
require 'mixlib/shellout'
class Chef
diff --git a/lib/chef/node.rb b/lib/chef/node.rb
index 327da67b1c..5f788af4d4 100644
--- a/lib/chef/node.rb
+++ b/lib/chef/node.rb
@@ -397,7 +397,7 @@ class Chef
end
index_hash["recipe"] = run_list.recipe_names if run_list.recipe_names.length > 0
index_hash["role"] = run_list.role_names if run_list.role_names.length > 0
- index_hash["run_list"] = run_list.run_list if run_list.run_list.length > 0
+ index_hash["run_list"] = run_list.run_list_items
index_hash
end
@@ -409,7 +409,7 @@ class Chef
display["normal"] = normal_attrs
display["default"] = attributes.combined_default
display["override"] = attributes.combined_override
- display["run_list"] = run_list.run_list
+ display["run_list"] = run_list.run_list_items
display
end
diff --git a/lib/chef/node_map.rb b/lib/chef/node_map.rb
new file mode 100644
index 0000000000..2ca6d9ba17
--- /dev/null
+++ b/lib/chef/node_map.rb
@@ -0,0 +1,146 @@
+#
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+ class NodeMap
+
+ VALID_OPTS = [
+ :on_platform,
+ :on_platforms,
+ :platform,
+ :os,
+ :platform_family,
+ ]
+
+ DEPRECATED_OPTS = [
+ :on_platform,
+ :on_platforms,
+ ]
+
+ # Create a new NodeMap
+ #
+ def initialize
+ @map = {}
+ end
+
+ # Set a key/value pair on the map with a filter. The filter must be true
+ # when applied to the node in order to retrieve the value.
+ #
+ # @param key [Object] Key to store
+ # @param value [Object] Value associated with the key
+ # @param filters [Hash] Node filter options to apply to key retrieval
+ # @yield [node] Arbitrary node filter as a block which takes a node argument
+ # @return [NodeMap] Returns self for possible chaining
+ #
+ def set(key, value, filters = {}, &block)
+ validate_filter!(filters)
+ deprecate_filter!(filters)
+ @map[key] ||= []
+ # we match on the first value we find, so we want to unshift so that the
+ # last setter wins
+ # FIXME: need a test for this behavior
+ @map[key].unshift({ filters: filters, block: block, value: value })
+ self
+ end
+
+ # Get a value from the NodeMap via applying the node to the filters that
+ # were set on the key.
+ #
+ # @param node [Chef::Node] The Chef::Node object for the run
+ # @param key [Object] Key to look up
+ # @return [Object] Value
+ #
+ def get(node, key)
+ # FIXME: real exception
+ raise "first argument must be a Chef::Node" unless node.is_a?(Chef::Node)
+ return nil unless @map.has_key?(key)
+ @map[key].each do |matcher|
+ if filters_match?(node, matcher[:filters]) &&
+ block_matches?(node, matcher[:block])
+ return matcher[:value]
+ end
+ end
+ nil
+ end
+
+ private
+
+ # only allow valid filter options
+ def validate_filter!(filters)
+ filters.each_key do |key|
+ # FIXME: real exception
+ raise "Bad key #{key} in Chef::NodeMap filter expression" unless VALID_OPTS.include?(key)
+ end
+ end
+
+ # warn on deprecated filter options
+ def deprecate_filter!(filters)
+ filters.each_key do |key|
+ Chef::Log.warn "The #{key} option to node_map has been deprecated" if DEPRECATED_OPTS.include?(key)
+ end
+ end
+
+ # @todo: this works fine, but is probably hard to understand
+ def negative_match(filter, param)
+ # We support strings prefaced by '!' to mean 'not'. In particular, this is most useful
+ # for os matching on '!windows'.
+ negative_matches = filter.select { |f| f[0] == '!' }
+ return true if !negative_matches.empty? && negative_matches.include?('!' + param)
+
+ # We support the symbol :all to match everything, for backcompat, but this can and should
+ # simply be ommitted.
+ positive_matches = filter.reject { |f| f[0] == '!' || f == :all }
+ return true if !positive_matches.empty? && !positive_matches.include?(param)
+
+ # sorry double-negative: this means we pass this filter.
+ false
+ end
+
+ def filters_match?(node, filters)
+ return true if filters.empty?
+
+ # each filter is applied in turn. if any fail, then it shortcuts and returns false.
+ # if it passes or does not exist it succeeds and continues on. so multiple filters are
+ # effectively joined by 'and'. all filters can be single strings, or arrays which are
+ # effectively joined by 'or'.
+
+ os_filter = [ filters[:os] ].flatten.compact
+ unless os_filter.empty?
+ return false if negative_match(os_filter, node[:os])
+ end
+
+ platform_family_filter = [ filters[:platform_family] ].flatten.compact
+ unless platform_family_filter.empty?
+ return false if negative_match(platform_family_filter, node[:platform_family])
+ end
+
+ # :on_platform and :on_platforms here are synonyms which are deprecated
+ platform_filter = [ filters[:platform] || filters[:on_platform] || filters[:on_platforms] ].flatten.compact
+ unless platform_filter.empty?
+ return false if negative_match(platform_filter, node[:platform])
+ end
+
+ return true
+ end
+
+ def block_matches?(node, block)
+ return true if block.nil?
+ block.call node
+ end
+ end
+end
diff --git a/lib/chef/platform/provider_mapping.rb b/lib/chef/platform/provider_mapping.rb
index 0766ccffa7..382df342f5 100644
--- a/lib/chef/platform/provider_mapping.rb
+++ b/lib/chef/platform/provider_mapping.rb
@@ -41,7 +41,6 @@ class Chef
:mac_os_x => {
:default => {
:package => Chef::Provider::Package::Homebrew,
- :service => Chef::Provider::Service::Macosx,
:user => Chef::Provider::User::Dscl,
:group => Chef::Provider::Group::Dscl
}
@@ -49,7 +48,6 @@ class Chef
:mac_os_x_server => {
:default => {
:package => Chef::Provider::Package::Homebrew,
- :service => Chef::Provider::Service::Macosx,
:user => Chef::Provider::User::Dscl,
:group => Chef::Provider::Group::Dscl
}
@@ -57,7 +55,6 @@ class Chef
:freebsd => {
:default => {
:group => Chef::Provider::Group::Pw,
- :service => Chef::Provider::Service::Freebsd,
:user => Chef::Provider::User::Pw,
:cron => Chef::Provider::Cron
}
@@ -197,10 +194,14 @@ class Chef
},
:suse => {
:default => {
- :service => Chef::Provider::Service::Redhat,
+ :service => Chef::Provider::Service::Systemd,
:cron => Chef::Provider::Cron,
:package => Chef::Provider::Package::Zypper,
- :group => Chef::Provider::Group::Suse
+ :group => Chef::Provider::Group::Gpasswd
+ },
+ "< 12.0" => {
+ :group => Chef::Provider::Group::Suse,
+ :service => Chef::Provider::Service::Redhat
}
},
:oracle => {
@@ -272,7 +273,6 @@ class Chef
:mswin => {
:default => {
:env => Chef::Provider::Env::Windows,
- :service => Chef::Provider::Service::Windows,
:user => Chef::Provider::User::Windows,
:group => Chef::Provider::Group::Windows,
:mount => Chef::Provider::Mount::Windows,
@@ -283,7 +283,6 @@ class Chef
:mingw32 => {
:default => {
:env => Chef::Provider::Env::Windows,
- :service => Chef::Provider::Service::Windows,
:user => Chef::Provider::User::Windows,
:group => Chef::Provider::Group::Windows,
:mount => Chef::Provider::Mount::Windows,
@@ -294,7 +293,6 @@ class Chef
:windows => {
:default => {
:env => Chef::Provider::Env::Windows,
- :service => Chef::Provider::Service::Windows,
:user => Chef::Provider::User::Windows,
:group => Chef::Provider::Group::Windows,
:mount => Chef::Provider::Mount::Windows,
@@ -306,7 +304,6 @@ class Chef
:openindiana => {
:default => {
:mount => Chef::Provider::Mount::Solaris,
- :service => Chef::Provider::Service::Solaris,
:package => Chef::Provider::Package::Ips,
:cron => Chef::Provider::Cron::Solaris,
:group => Chef::Provider::Group::Usermod
@@ -315,7 +312,6 @@ class Chef
:opensolaris => {
:default => {
:mount => Chef::Provider::Mount::Solaris,
- :service => Chef::Provider::Service::Solaris,
:package => Chef::Provider::Package::Ips,
:cron => Chef::Provider::Cron::Solaris,
:group => Chef::Provider::Group::Usermod
@@ -324,7 +320,6 @@ class Chef
:nexentacore => {
:default => {
:mount => Chef::Provider::Mount::Solaris,
- :service => Chef::Provider::Service::Solaris,
:package => Chef::Provider::Package::Solaris,
:cron => Chef::Provider::Cron::Solaris,
:group => Chef::Provider::Group::Usermod
@@ -333,7 +328,6 @@ class Chef
:omnios => {
:default => {
:mount => Chef::Provider::Mount::Solaris,
- :service => Chef::Provider::Service::Solaris,
:package => Chef::Provider::Package::Ips,
:cron => Chef::Provider::Cron::Solaris,
:group => Chef::Provider::Group::Usermod,
@@ -343,7 +337,6 @@ class Chef
:solaris2 => {
:default => {
:mount => Chef::Provider::Mount::Solaris,
- :service => Chef::Provider::Service::Solaris,
:package => Chef::Provider::Package::Ips,
:cron => Chef::Provider::Cron::Solaris,
:group => Chef::Provider::Group::Usermod,
@@ -351,7 +344,6 @@ class Chef
},
"< 5.11" => {
:mount => Chef::Provider::Mount::Solaris,
- :service => Chef::Provider::Service::Solaris,
:package => Chef::Provider::Package::Solaris,
:cron => Chef::Provider::Cron::Solaris,
:group => Chef::Provider::Group::Usermod,
@@ -361,7 +353,6 @@ class Chef
:smartos => {
:default => {
:mount => Chef::Provider::Mount::Solaris,
- :service => Chef::Provider::Service::Solaris,
:package => Chef::Provider::Package::SmartOS,
:cron => Chef::Provider::Cron::Solaris,
:group => Chef::Provider::Group::Usermod
@@ -369,7 +360,6 @@ class Chef
},
:netbsd => {
:default => {
- :service => Chef::Provider::Service::Freebsd,
:group => Chef::Provider::Group::Groupmod
}
},
@@ -390,7 +380,8 @@ class Chef
:ifconfig => Chef::Provider::Ifconfig::Aix,
:cron => Chef::Provider::Cron::Aix,
:package => Chef::Provider::Package::Aix,
- :user => Chef::Provider::User::Aix
+ :user => Chef::Provider::User::Aix,
+ :service => Chef::Provider::Service::Aix
}
},
:exherbo => {
@@ -402,29 +393,10 @@ class Chef
}
},
:default => {
- :file => Chef::Provider::File,
- :directory => Chef::Provider::Directory,
- :link => Chef::Provider::Link,
- :template => Chef::Provider::Template,
- :remote_directory => Chef::Provider::RemoteDirectory,
- :execute => Chef::Provider::Execute,
:mount => Chef::Provider::Mount::Mount,
- :script => Chef::Provider::Script,
- :service => Chef::Provider::Service::Init,
- :perl => Chef::Provider::Script,
- :python => Chef::Provider::Script,
- :ruby => Chef::Provider::Script,
- :bash => Chef::Provider::Script,
- :csh => Chef::Provider::Script,
:user => Chef::Provider::User::Useradd,
:group => Chef::Provider::Group::Gpasswd,
- :http_request => Chef::Provider::HttpRequest,
- :route => Chef::Provider::Route,
:ifconfig => Chef::Provider::Ifconfig,
- :ruby_block => Chef::Provider::RubyBlock,
- :whyrun_safe_ruby_block => Chef::Provider::WhyrunSafeRubyBlock,
- :erl_call => Chef::Provider::ErlCall,
- :log => Chef::Provider::Log::ChefLog
}
}
end
diff --git a/lib/chef/platform/provider_priority_map.rb b/lib/chef/platform/provider_priority_map.rb
new file mode 100644
index 0000000000..ccf6ef0bbe
--- /dev/null
+++ b/lib/chef/platform/provider_priority_map.rb
@@ -0,0 +1,80 @@
+
+require 'chef/providers'
+
+class Chef
+ class Platform
+ class ProviderPriorityMap
+ include Singleton
+
+ def initialize
+ load_default_map
+ end
+
+ def load_default_map
+
+ #
+ # Linux
+ #
+
+ # default block for linux O/Sen must come before platform_family exceptions
+ priority :service, [
+ Chef::Provider::Service::Systemd,
+ Chef::Provider::Service::Insserv,
+ Chef::Provider::Service::Redhat,
+ ], os: "linux"
+
+ priority :service, [
+ Chef::Provider::Service::Systemd,
+ Chef::Provider::Service::Arch,
+ ], platform_family: "arch"
+
+ priority :service, [
+ Chef::Provider::Service::Systemd,
+ Chef::Provider::Service::Gentoo,
+ ], platform_family: "gentoo"
+
+ priority :service, [
+ # on debian-ish system if an upstart script exists that always wins
+ Chef::Provider::Service::Upstart,
+ Chef::Provider::Service::Systemd,
+ Chef::Provider::Service::Insserv,
+ Chef::Provider::Service::Debian,
+ Chef::Provider::Service::Invokercd,
+ ], platform_family: "debian"
+
+ priority :service, [
+ Chef::Provider::Service::Systemd,
+ Chef::Provider::Service::Insserv,
+ Chef::Provider::Service::Redhat,
+ ], platform_family: [ "rhel", "fedora", "suse" ]
+
+ #
+ # BSDen
+ #
+
+ priority :service, Chef::Provider::Service::Freebsd, os: [ "freebsd", "netbsd" ]
+
+ #
+ # Solaris-en
+ #
+
+ priority :service, Chef::Provider::Service::Solaris, os: "solaris2"
+
+ #
+ # Mac
+ #
+
+ priority :service, Chef::Provider::Service::Macosx, os: "darwin"
+ end
+
+ def priority_map
+ @priority_map ||= Chef::NodeMap.new
+ end
+
+ def priority(*args)
+ priority_map.set(*args)
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/platform/service_helpers.rb b/lib/chef/platform/service_helpers.rb
new file mode 100644
index 0000000000..440391843e
--- /dev/null
+++ b/lib/chef/platform/service_helpers.rb
@@ -0,0 +1,113 @@
+#
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# XXX: mixing shellout into a mixin into classes has to be code smell
+require 'chef/mixin/shell_out'
+
+class Chef
+ class Platform
+ class ServiceHelpers
+ class << self
+
+ include Chef::Mixin::ShellOut
+
+ # This helper is mostly used to sort out the mess of different
+ # linux mechanisms that can be used to start services. It does
+ # not necessarily need to linux-specific, but currently all our
+ # other service providers are narrowly platform-specific with no
+ # alternatives.
+ def service_resource_providers
+ service_resource_providers = []
+
+ if ::File.exist?("/usr/sbin/update-rc.d")
+ service_resource_providers << :debian
+ end
+
+ if ::File.exist?("/usr/sbin/invoke-rc.d")
+ service_resource_providers << :invokercd
+ end
+
+ if ::File.exist?("/sbin/insserv")
+ service_resource_providers << :insserv
+ end
+
+ # debian >= 6.0 has /etc/init but does not have upstart
+ if ::File.exist?("/etc/init") && ::File.exist?("/sbin/start")
+ service_resource_providers << :upstart
+ end
+
+ if ::File.exist?("/sbin/chkconfig")
+ service_resource_providers << :redhat
+ end
+
+ if ::File.exist?("/bin/systemctl")
+ # FIXME: look for systemd as init provider
+ service_resource_providers << :systemd
+ end
+
+ service_resource_providers
+ end
+
+ def config_for_service(service_name)
+ configs = []
+
+ if ::File.exist?("/etc/init.d/#{service_name}")
+ configs << :initd
+ end
+
+ if ::File.exist?("/etc/init/#{service_name}.conf")
+ configs << :upstart
+ end
+
+ if ::File.exist?("/etc/xinetd.d/#{service_name}")
+ configs << :xinetd
+ end
+
+ if ::File.exist?("/etc/rc.d/#{service_name}")
+ configs << :etc_rcd
+ end
+
+ if ::File.exist?("/usr/local/etc/rc.d/#{service_name}")
+ configs << :usr_local_etc_rcd
+ end
+
+ if ::File.exist?("/bin/systemctl") && platform_has_systemd_unit?(service_name)
+ configs << :systemd
+ end
+
+ configs
+ end
+
+ private
+
+ def extract_systemd_services(output)
+ # first line finds e.g. "sshd.service"
+ services = output.lines.split.map { |l| l.split[0] }
+ # this splits off the suffix after the last dot to return "sshd"
+ services += services.map { |s| s.sub(/(.*)\..*/, '\1') }
+ end
+
+ def platform_has_systemd_unit?(service_name)
+ services = extract_systemd_services(shell_out!("systemctl --all").stdout) +
+ extract_systemd_services(shell_out!("systemctl --list-unit-files").stdout)
+ services.include?(service_name)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider.rb b/lib/chef/provider.rb
index bdfe826944..680fe9782f 100644
--- a/lib/chef/provider.rb
+++ b/lib/chef/provider.rb
@@ -22,11 +22,35 @@ 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/platform/service_helpers'
+require 'chef/node_map'
class Chef
class Provider
include Chef::Mixin::WhyRun
include Chef::Mixin::ShellOut
+ extend Chef::Mixin::DescendantsTracker
+
+ 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
+ end
attr_accessor :new_resource
attr_accessor :current_resource
diff --git a/lib/chef/provider/breakpoint.rb b/lib/chef/provider/breakpoint.rb
index 224e2758eb..663d558f66 100644
--- a/lib/chef/provider/breakpoint.rb
+++ b/lib/chef/provider/breakpoint.rb
@@ -20,6 +20,8 @@ class Chef
class Provider
class Breakpoint < Chef::Provider
+ provides :breakpoint
+
def load_current_resource
end
diff --git a/lib/chef/provider/cookbook_file.rb b/lib/chef/provider/cookbook_file.rb
index 26d6ebf1d9..b501a9b41d 100644
--- a/lib/chef/provider/cookbook_file.rb
+++ b/lib/chef/provider/cookbook_file.rb
@@ -24,6 +24,8 @@ class Chef
class Provider
class CookbookFile < Chef::Provider::File
+ provides :cookbook_file
+
extend Chef::Deprecation::Warnings
include Chef::Deprecation::Provider::CookbookFile
add_deprecation_warnings_for(Chef::Deprecation::Provider::CookbookFile.instance_methods)
diff --git a/lib/chef/provider/cron.rb b/lib/chef/provider/cron.rb
index c3be9746df..1590c624f6 100644
--- a/lib/chef/provider/cron.rb
+++ b/lib/chef/provider/cron.rb
@@ -28,7 +28,7 @@ class Chef
SPECIAL_TIME_VALUES = [:reboot, :yearly, :annually, :monthly, :weekly, :daily, :midnight, :hourly]
CRON_ATTRIBUTES = [:minute, :hour, :day, :month, :weekday, :time, :command, :mailto, :path, :shell, :home, :environment]
WEEKDAY_SYMBOLS = [:sunday, :monday, :tuesday, :wednesday, :thursday, :friday, :saturday]
-
+
CRON_PATTERN = /\A([-0-9*,\/]+)\s([-0-9*,\/]+)\s([-0-9*,\/]+)\s([-0-9*,\/]+|[a-zA-Z]{3})\s([-0-9*,\/]+|[a-zA-Z]{3})\s(.*)/
SPECIAL_PATTERN = /\A(@(#{SPECIAL_TIME_VALUES.join('|')}))\s(.*)/
ENV_PATTERN = /\A(\S+)=(\S*)/
diff --git a/lib/chef/provider/cron/unix.rb b/lib/chef/provider/cron/unix.rb
index 5cb1bcda41..350f8bda18 100644
--- a/lib/chef/provider/cron/unix.rb
+++ b/lib/chef/provider/cron/unix.rb
@@ -25,18 +25,21 @@ class Chef
class Provider
class Cron
class Unix < Chef::Provider::Cron
+ include Chef::Mixin::ShellOut
private
def read_crontab
- crontab = nil
- status = popen4("crontab -l #{@new_resource.user}") do |pid, stdin, stdout, stderr|
- crontab = stdout.read
- end
- if status.exitstatus > 1
- raise Chef::Exceptions::Cron, "Error determining state of #{@new_resource.name}, exit: #{status.exitstatus}"
+ crontab = shell_out('/usr/bin/crontab -l', :user => @new_resource.user)
+ status = crontab.status.exitstatus
+
+ Chef::Log.debug crontab.format_for_exception if status > 0
+
+ if status > 1
+ raise Chef::Exceptions::Cron, "Error determining state of #{@new_resource.name}, exit: #{status}"
end
- crontab
+ return nil if status > 0
+ crontab.stdout.chomp << "\n"
end
def write_crontab(crontab)
@@ -47,8 +50,9 @@ class Chef
exit_status = 0
error_message = ""
begin
- status, stdout, stderr = run_command_and_return_stdout_stderr(:command => "/usr/bin/crontab #{tempcron.path}",:user => @new_resource.user)
- exit_status = status.exitstatus
+ crontab_write = shell_out("/usr/bin/crontab #{tempcron.path}", :user => @new_resource.user)
+ stderr = crontab_write.stderr
+ exit_status = crontab_write.status.exitstatus
# solaris9, 10 on some failures for example invalid 'mins' in crontab fails with exit code of zero :(
if stderr && stderr.include?("errors detected in input, no crontab file generated")
error_message = stderr
diff --git a/lib/chef/provider/deploy.rb b/lib/chef/provider/deploy.rb
index db147278c2..b30f7ed17e 100644
--- a/lib/chef/provider/deploy.rb
+++ b/lib/chef/provider/deploy.rb
@@ -375,7 +375,7 @@ class Chef
def gem_resource_collection_runner
gems_collection = Chef::ResourceCollection.new
- gem_packages.each { |rbgem| gems_collection << rbgem }
+ gem_packages.each { |rbgem| gems_collection.insert(rbgem) }
gems_run_context = run_context.dup
gems_run_context.resource_collection = gems_collection
Chef::Runner.new(gems_run_context)
diff --git a/lib/chef/provider/deploy/revision.rb b/lib/chef/provider/deploy/revision.rb
index c98c1e5c75..62aa0e87f6 100644
--- a/lib/chef/provider/deploy/revision.rb
+++ b/lib/chef/provider/deploy/revision.rb
@@ -27,6 +27,8 @@ class Chef
class Provider
class Deploy
class Revision < Chef::Provider::Deploy
+ provides :deploy_revision
+ provides :deploy_branch
def all_releases
sorted_releases
diff --git a/lib/chef/provider/deploy/timestamped.rb b/lib/chef/provider/deploy/timestamped.rb
index ce921161e0..ba3f6683f0 100644
--- a/lib/chef/provider/deploy/timestamped.rb
+++ b/lib/chef/provider/deploy/timestamped.rb
@@ -20,6 +20,8 @@ class Chef
class Provider
class Deploy
class Timestamped < Chef::Provider::Deploy
+ provides :timestamped_deploy
+ provides :deploy
protected
diff --git a/lib/chef/provider/directory.rb b/lib/chef/provider/directory.rb
index 067737b9d4..c9c3d466b9 100644
--- a/lib/chef/provider/directory.rb
+++ b/lib/chef/provider/directory.rb
@@ -27,6 +27,8 @@ class Chef
class Provider
class Directory < Chef::Provider::File
+ provides :directory
+
def whyrun_supported?
true
end
diff --git a/lib/chef/provider/dsc_script.rb b/lib/chef/provider/dsc_script.rb
index b8ca54f1b8..5db50e74b3 100644
--- a/lib/chef/provider/dsc_script.rb
+++ b/lib/chef/provider/dsc_script.rb
@@ -24,6 +24,9 @@ require 'chef/util/path_helper'
class Chef
class Provider
class DscScript < Chef::Provider
+
+ provides :dsc_script, os: "windows"
+
def initialize(dsc_resource, run_context)
super(dsc_resource, run_context)
@dsc_resource = dsc_resource
@@ -62,7 +65,7 @@ class Chef
def define_resource_requirements
requirements.assert(:run) do |a|
err = [
- 'Could not find Dsc on the system',
+ 'Could not find PowerShell DSC support on the system',
powershell_info_str,
"Powershell 4.0 or higher was not detected on your system and is required to use the dsc_script resource.",
]
@@ -98,9 +101,8 @@ class Chef
end
def get_augmented_configuration_flags(configuration_data_path)
- updated_flags = nil
+ updated_flags = @dsc_resource.flags.nil? ? {} : @dsc_resource.flags.dup
if configuration_data_path
- updated_flags = @dsc_resource.flags.nil? ? {} : @dsc_resource.flags.dup
Chef::Util::PathHelper.validate_path(configuration_data_path)
updated_flags[:configurationdata] = configuration_data_path
end
diff --git a/lib/chef/provider/env.rb b/lib/chef/provider/env.rb
index e91b8bbb97..600cac1e6b 100644
--- a/lib/chef/provider/env.rb
+++ b/lib/chef/provider/env.rb
@@ -58,20 +58,22 @@ class Chef
# ==== Returns
# <true>:: If a change is required
# <false>:: If a change is not required
- def compare_value
+ def requires_modify_or_create?
if @new_resource.delim
#e.g. check for existing value within PATH
- not @current_resource.value.split(@new_resource.delim).any? do |val|
- val == @new_resource.value
+ not new_values.all? do |val|
+ current_values.include? val
end
else
@new_resource.value != @current_resource.value
end
end
+ alias_method :compare_value, :requires_modify_or_create?
+
def action_create
if @key_exists
- if compare_value
+ if requires_modify_or_create?
modify_env
Chef::Log.info("#{@new_resource} altered")
@new_resource.updated_by_last_action(true)
@@ -91,13 +93,14 @@ class Chef
# after we removed the element.
def delete_element
return false unless @new_resource.delim #no delim: delete the key
- if compare_value
+ needs_delete = new_values.any? { |v| current_values.include?(v) }
+ if !needs_delete
Chef::Log.debug("#{@new_resource} element '#{@new_resource.value}' does not exist")
return true #do not delete the key
else
new_value =
- @current_resource.value.split(@new_resource.delim).select { |item|
- item != @new_resource.value
+ current_values.select { |item|
+ not new_values.include?(item)
}.join(@new_resource.delim)
if new_value.empty?
@@ -122,7 +125,7 @@ class Chef
def action_modify
if @key_exists
- if compare_value
+ if requires_modify_or_create?
modify_env
Chef::Log.info("#{@new_resource} modified")
@new_resource.updated_by_last_action(true)
@@ -142,11 +145,23 @@ class Chef
def modify_env
if @new_resource.delim
- #e.g. add to PATH
- @new_resource.value(@new_resource.value + @new_resource.delim + @current_resource.value)
+ values = new_values.reject do |v|
+ current_values.include?(v)
+ end
+ @new_resource.value((values + [@current_resource.value]).join(@new_resource.delim))
end
create_env
end
+
+ # Returns the current values to split by delimiter
+ def current_values
+ @current_values ||= @current_resource.value.split(@new_resource.delim)
+ end
+
+ # Returns the new values to split by delimiter
+ def new_values
+ @new_values ||= @new_resource.value.split(@new_resource.delim)
+ end
end
end
end
diff --git a/lib/chef/provider/env/windows.rb b/lib/chef/provider/env/windows.rb
index 572ec5c633..dd7cb1bc46 100644
--- a/lib/chef/provider/env/windows.rb
+++ b/lib/chef/provider/env/windows.rb
@@ -43,14 +43,16 @@ class Chef
obj = env_obj(@new_resource.key_name)
if obj
obj.delete_
- ENV.delete(@new_resource.key_name)
broadcast_env_change
end
+ if ENV[@new_resource.key_name]
+ ENV.delete(@new_resource.key_name)
+ end
end
def env_value(key_name)
obj = env_obj(key_name)
- return obj ? obj.variablevalue : nil
+ return obj ? obj.variablevalue : ENV[key_name]
end
def env_obj(key_name)
diff --git a/lib/chef/provider/erl_call.rb b/lib/chef/provider/erl_call.rb
index cdd494a243..f5855bcce6 100644
--- a/lib/chef/provider/erl_call.rb
+++ b/lib/chef/provider/erl_call.rb
@@ -25,6 +25,8 @@ class Chef
class ErlCall < Chef::Provider
include Chef::Mixin::Command
+ provides :erl_call
+
def initialize(node, new_resource)
super(node, new_resource)
end
diff --git a/lib/chef/provider/execute.rb b/lib/chef/provider/execute.rb
index d469bea769..48b2a344d1 100644
--- a/lib/chef/provider/execute.rb
+++ b/lib/chef/provider/execute.rb
@@ -23,6 +23,8 @@ class Chef
class Provider
class Execute < Chef::Provider
+ provides :execute
+
def load_current_resource
true
end
@@ -50,10 +52,11 @@ class Chef
opts[:umask] = @new_resource.umask if @new_resource.umask
opts[:log_level] = :info
opts[:log_tag] = @new_resource.to_s
- if STDOUT.tty? && !Chef::Config[:daemon] && Chef::Log.info?
+ if STDOUT.tty? && !Chef::Config[:daemon] && Chef::Log.info? && !@new_resource.sensitive
opts[:live_stream] = STDOUT
end
- converge_by("execute #{@new_resource.command}") do
+ description = @new_resource.sensitive ? "sensitive resource" : @new_resource.command
+ converge_by("execute #{description}") do
result = shell_out!(@new_resource.command, opts)
Chef::Log.info("#{@new_resource} ran successfully")
end
diff --git a/lib/chef/provider/file.rb b/lib/chef/provider/file.rb
index 256248f240..a9390cc45c 100644
--- a/lib/chef/provider/file.rb
+++ b/lib/chef/provider/file.rb
@@ -54,6 +54,8 @@ class Chef
include Chef::Deprecation::Provider::File
add_deprecation_warnings_for(Chef::Deprecation::Provider::File.instance_methods)
+ provides :file
+
attr_reader :deployment_strategy
attr_accessor :needs_creating
diff --git a/lib/chef/provider/git.rb b/lib/chef/provider/git.rb
index c8e615c1f9..8418f22933 100644
--- a/lib/chef/provider/git.rb
+++ b/lib/chef/provider/git.rb
@@ -25,6 +25,8 @@ class Chef
class Provider
class Git < Chef::Provider
+ provides :git
+
def whyrun_supported?
true
end
@@ -64,7 +66,7 @@ class Chef
a.failure_message Chef::Exceptions::UnresolvableGitReference,
"Unable to parse SHA reference for '#{@new_resource.revision}' in repository '#{@new_resource.repository}'. " +
"Verify your (case-sensitive) repository URL and revision.\n" +
- "`git ls-remote` output: #{@resolved_reference}"
+ "`git ls-remote '#{@new_resource.repository}' '#{rev_search_pattern}'` output: #{@resolved_reference}"
end
end
@@ -240,35 +242,55 @@ class Chef
# annotated tags, we have to search for "revision*" and
# post-process. Special handling for 'HEAD' to ignore a tag
# named 'HEAD'.
- rev_pattern = case @new_resource.revision
- when '', 'HEAD'
- 'HEAD'
- else
- @new_resource.revision + '*'
- end
- command = git("ls-remote \"#{@new_resource.repository}\" \"#{rev_pattern}\"")
- @resolved_reference = shell_out!(command, run_options).stdout
- ref_lines = @resolved_reference.split("\n")
- refs = ref_lines.map { |line| line.split("\t") }
- # first try for ^{} indicating the commit pointed to by an
- # annotated tag
- tagged_commit = refs.find { |m| m[1].end_with?("#{@new_resource.revision}^{}") }
+ @resolved_reference = git_ls_remote(rev_search_pattern)
+ refs = @resolved_reference.split("\n").map { |line| line.split("\t") }
+ # First try for ^{} indicating the commit pointed to by an
+ # annotated tag.
# It is possible for a user to create a tag named 'HEAD'.
# Using such a degenerate annotated tag would be very
# confusing. We avoid the issue by disallowing the use of
# annotated tags named 'HEAD'.
- if tagged_commit && rev_pattern != 'HEAD'
- tagged_commit[0]
+ if rev_search_pattern != 'HEAD'
+ found = find_revision(refs, @new_resource.revision, '^{}')
else
- found = refs.find { |m| m[1].end_with?(@new_resource.revision) }
- if found
- found[0]
- else
- nil
- end
+ found = refs_search(refs, 'HEAD')
+ end
+ found = find_revision(refs, @new_resource.revision) if found.empty?
+ found.size == 1 ? found.first[0] : nil
+ end
+
+ def find_revision(refs, revision, suffix="")
+ found = refs_search(refs, rev_match_pattern('refs/tags/', revision) + suffix)
+ found = refs_search(refs, rev_match_pattern('refs/heads/', revision) + suffix) if found.empty?
+ found = refs_search(refs, revision + suffix) if found.empty?
+ found
+ end
+
+ def rev_match_pattern(prefix, revision)
+ if revision.start_with?(prefix)
+ revision
+ else
+ prefix + revision
end
end
+ def rev_search_pattern
+ if ['', 'HEAD'].include? @new_resource.revision
+ 'HEAD'
+ else
+ @new_resource.revision + '*'
+ end
+ end
+
+ def git_ls_remote(rev_pattern)
+ command = git(%Q(ls-remote "#{@new_resource.repository}" "#{rev_pattern}"))
+ shell_out!(command, run_options).stdout
+ end
+
+ def refs_search(refs, pattern)
+ refs.find_all { |m| m[1] == pattern }
+ end
+
private
def run_options(run_opts={})
diff --git a/lib/chef/provider/http_request.rb b/lib/chef/provider/http_request.rb
index ba54b10195..61aff434ed 100644
--- a/lib/chef/provider/http_request.rb
+++ b/lib/chef/provider/http_request.rb
@@ -23,6 +23,8 @@ class Chef
class Provider
class HttpRequest < Chef::Provider
+ provides :http_request
+
attr_accessor :http
def whyrun_supported?
diff --git a/lib/chef/provider/link.rb b/lib/chef/provider/link.rb
index 639dc4f3ff..417d6a21b0 100644
--- a/lib/chef/provider/link.rb
+++ b/lib/chef/provider/link.rb
@@ -28,6 +28,8 @@ class Chef
class Provider
class Link < Chef::Provider
+ provides :link
+
include Chef::Mixin::EnforceOwnershipAndPermissions
include Chef::Mixin::FileClass
diff --git a/lib/chef/provider/log.rb b/lib/chef/provider/log.rb
index 9379ceeefa..40eaf0aa28 100644
--- a/lib/chef/provider/log.rb
+++ b/lib/chef/provider/log.rb
@@ -25,6 +25,8 @@ class Chef
# Chef log provider, allows logging to chef's logs from recipes
class ChefLog < Chef::Provider
+ provides :log
+
def whyrun_supported?
true
end
diff --git a/lib/chef/provider/lwrp_base.rb b/lib/chef/provider/lwrp_base.rb
index 90ce70ae61..135a3f6b7c 100644
--- a/lib/chef/provider/lwrp_base.rb
+++ b/lib/chef/provider/lwrp_base.rb
@@ -81,22 +81,24 @@ class Chef
include Chef::DSL::DataQuery
def self.build_from_file(cookbook_name, filename, run_context)
+ provider_class = nil
provider_name = filename_to_qualified_string(cookbook_name, filename)
- # Add log entry if we override an existing light-weight provider.
class_name = convert_to_class_name(provider_name)
if Chef::Provider.const_defined?(class_name)
- Chef::Log.info("#{class_name} light-weight provider already initialized -- overriding!")
+ Chef::Log.info("#{class_name} light-weight provider is already initialized -- Skipping loading #{filename}!")
+ Chef::Log.debug("Overriding already defined LWRPs is not supported anymore starting with Chef 12.")
+ provider_class = Chef::Provider.const_get(class_name)
+ else
+ provider_class = Class.new(self)
+ provider_class.class_from_file(filename)
+
+ class_name = convert_to_class_name(provider_name)
+ Chef::Provider.const_set(class_name, provider_class)
+ Chef::Log.debug("Loaded contents of #{filename} into a provider named #{provider_name} defined in Chef::Provider::#{class_name}")
end
- provider_class = Class.new(self)
- provider_class.class_from_file(filename)
-
- class_name = convert_to_class_name(provider_name)
- Chef::Provider.const_set(class_name, provider_class)
- Chef::Log.debug("Loaded contents of #{filename} into a provider named #{provider_name} defined in Chef::Provider::#{class_name}")
-
provider_class
end
diff --git a/lib/chef/provider/mount/mount.rb b/lib/chef/provider/mount/mount.rb
index 2d4a5aadef..c1d4fb2223 100644
--- a/lib/chef/provider/mount/mount.rb
+++ b/lib/chef/provider/mount/mount.rb
@@ -191,7 +191,7 @@ class Chef
def device_should_exist?
( @new_resource.device != "none" ) &&
( not network_device? ) &&
- ( not %w[ tmpfs fuse ].include? @new_resource.fstype )
+ ( not %w[ cgroup tmpfs fuse ].include? @new_resource.fstype )
end
private
diff --git a/lib/chef/provider/package/aix.rb b/lib/chef/provider/package/aix.rb
index da3e6d1684..88de4679ba 100644
--- a/lib/chef/provider/package/aix.rb
+++ b/lib/chef/provider/package/aix.rb
@@ -26,6 +26,8 @@ class Chef
class Package
class Aix < Chef::Provider::Package
+ provides :bff_package, os: "aix"
+
include Chef::Mixin::GetSourceFromPackage
def define_resource_requirements
diff --git a/lib/chef/provider/package/apt.rb b/lib/chef/provider/package/apt.rb
index 0d91d0d1f0..eb2c038eaa 100644
--- a/lib/chef/provider/package/apt.rb
+++ b/lib/chef/provider/package/apt.rb
@@ -25,6 +25,8 @@ class Chef
class Package
class Apt < Chef::Provider::Package
+ provides :apt_package, os: "linux"
+
attr_accessor :is_virtual_package
def load_current_resource
diff --git a/lib/chef/provider/package/dpkg.rb b/lib/chef/provider/package/dpkg.rb
index a1f1c797b1..3a9cecc660 100644
--- a/lib/chef/provider/package/dpkg.rb
+++ b/lib/chef/provider/package/dpkg.rb
@@ -30,6 +30,8 @@ class Chef
DPKG_INSTALLED = /^Status: install ok installed/
DPKG_VERSION = /^Version: (.+)$/
+ provides :dpkg_package, os: "linux"
+
include Chef::Mixin::GetSourceFromPackage
def define_resource_requirements
diff --git a/lib/chef/provider/package/easy_install.rb b/lib/chef/provider/package/easy_install.rb
index 2af8a72e61..90727b738d 100644
--- a/lib/chef/provider/package/easy_install.rb
+++ b/lib/chef/provider/package/easy_install.rb
@@ -25,6 +25,8 @@ class Chef
class Package
class EasyInstall < Chef::Provider::Package
+ provides :easy_install_package
+
def install_check(name)
check = false
diff --git a/lib/chef/provider/package/freebsd/port.rb b/lib/chef/provider/package/freebsd/port.rb
index 4b3510f0e9..8b191179f0 100644
--- a/lib/chef/provider/package/freebsd/port.rb
+++ b/lib/chef/provider/package/freebsd/port.rb
@@ -34,7 +34,7 @@ class Chef
end
def current_installed_version
- pkg_info = if supports_pkgng?
+ pkg_info = if @new_resource.supports_pkgng?
shell_out!("pkg info \"#{@new_resource.package_name}\"", :env => nil, :returns => [0,70])
else
shell_out!("pkg_info -E \"#{@new_resource.package_name}*\"", :env => nil, :returns => [0,1])
@@ -53,14 +53,6 @@ class Chef
def port_dir
super(@new_resource.package_name)
end
-
- private
-
- def supports_pkgng?
- with_pkgng = makefile_variable_value('WITH_PKGNG')
- with_pkgng && with_pkgng =~ /yes/i
- end
-
end
end
end
diff --git a/lib/chef/provider/package/homebrew.rb b/lib/chef/provider/package/homebrew.rb
index 202e4d2533..822f4c8a42 100644
--- a/lib/chef/provider/package/homebrew.rb
+++ b/lib/chef/provider/package/homebrew.rb
@@ -25,7 +25,11 @@ class Chef
class Provider
class Package
class Homebrew < Chef::Provider::Package
+
+ provides :homebrew_package, os: "mac_os_x"
+
include Chef::Mixin::HomebrewUser
+
def load_current_resource
self.current_resource = Chef::Resource::Package.new(new_resource.name)
current_resource.package_name(new_resource.package_name)
@@ -109,7 +113,7 @@ class Chef
private
def get_response_from_command(command)
- homebrew_uid = find_homebrew_uid(new_resource.homebrew_user)
+ homebrew_uid = find_homebrew_uid(new_resource.respond_to?(:homebrew_user) && new_resource.homebrew_user)
homebrew_user = Etc.getpwuid(homebrew_uid)
Chef::Log.debug "Executing '#{command}' as user '#{homebrew_user.name}'"
diff --git a/lib/chef/provider/package/ips.rb b/lib/chef/provider/package/ips.rb
index 4090507303..87022d770a 100644
--- a/lib/chef/provider/package/ips.rb
+++ b/lib/chef/provider/package/ips.rb
@@ -27,6 +27,8 @@ class Chef
class Package
class Ips < Chef::Provider::Package
+ provides :ips_package, os: "solaris2"
+
attr_accessor :virtual
def define_resource_requirements
diff --git a/lib/chef/provider/package/macports.rb b/lib/chef/provider/package/macports.rb
index 05247e6d31..cd142eca42 100644
--- a/lib/chef/provider/package/macports.rb
+++ b/lib/chef/provider/package/macports.rb
@@ -2,6 +2,9 @@ class Chef
class Provider
class Package
class Macports < Chef::Provider::Package
+
+ provides :macports_package, os: "mac_os_x"
+
def load_current_resource
@current_resource = Chef::Resource::Package.new(@new_resource.name)
@current_resource.package_name(@new_resource.package_name)
diff --git a/lib/chef/provider/package/pacman.rb b/lib/chef/provider/package/pacman.rb
index 1014ebcaa5..45edda5c5d 100644
--- a/lib/chef/provider/package/pacman.rb
+++ b/lib/chef/provider/package/pacman.rb
@@ -25,6 +25,8 @@ class Chef
class Package
class Pacman < Chef::Provider::Package
+ provides :pacman_package, os: "linux"
+
def load_current_resource
@current_resource = Chef::Resource::Package.new(@new_resource.name)
@current_resource.package_name(@new_resource.package_name)
@@ -34,7 +36,6 @@ class Chef
Chef::Log.debug("#{@new_resource} checking pacman for #{@new_resource.package_name}")
status = popen4("pacman -Qi #{@new_resource.package_name}") do |pid, stdin, stdout, stderr|
stdout.each do |line|
- line.force_encoding(Encoding::UTF_8) if line.respond_to?(:force_encoding)
case line
when /^Version(\s?)*: (.+)$/
Chef::Log.debug("#{@new_resource} current version is #{$2}")
@@ -62,11 +63,11 @@ class Chef
package_repos = repos.map {|r| Regexp.escape(r) }.join('|')
- status = popen4("pacman -Ss #{@new_resource.package_name}") do |pid, stdin, stdout, stderr|
+ status = popen4("pacman -Sl") do |pid, stdin, stdout, stderr|
stdout.each do |line|
case line
- when /^(#{package_repos})\/#{Regexp.escape(@new_resource.package_name)} (.+)$/
- # $2 contains a string like "4.4.0-1 (kde kdenetwork)" or "3.10-4 (base)"
+ when /^(#{package_repos}) #{Regexp.escape(@new_resource.package_name)} (.+)$/
+ # $2 contains a string like "4.4.0-1" or "3.10-4 [installed]"
# simply split by space and use first token
@candidate_version = $2.split(" ").first
end
diff --git a/lib/chef/provider/package/paludis.rb b/lib/chef/provider/package/paludis.rb
index 7c5245fc97..407e0d0110 100644
--- a/lib/chef/provider/package/paludis.rb
+++ b/lib/chef/provider/package/paludis.rb
@@ -24,6 +24,8 @@ class Chef
class Package
class Paludis < Chef::Provider::Package
+ provides :paludis_package, os: "linux"
+
def load_current_resource
@current_resource = Chef::Resource::Package.new(@new_resource.package_name)
@current_resource.package_name(@new_resource.package_name)
@@ -34,7 +36,7 @@ class Chef
installed = false
re = Regexp.new('(.*)[[:blank:]](.*)[[:blank:]](.*)$')
- shell_out!("cave -L warning print-ids -M none -m \"*/#{@new_resource.package_name.split('/').last}\" -f \"%c/%p %v %r\n\"").stdout.each_line do |line|
+ shell_out!("cave -L warning print-ids -M none -m \"#{@new_resource.package_name}\" -f \"%c/%p %v %r\n\"").stdout.each_line do |line|
res = re.match(line)
unless res.nil?
case res[3]
@@ -45,7 +47,7 @@ class Chef
@current_resource.version(res[2])
else
@candidate_version = res[2]
- @current_resource.version(nil)
+ @current_resource.version(nil)
end
end
end
diff --git a/lib/chef/provider/package/rpm.rb b/lib/chef/provider/package/rpm.rb
index c0a6444252..131587e066 100644
--- a/lib/chef/provider/package/rpm.rb
+++ b/lib/chef/provider/package/rpm.rb
@@ -25,6 +25,8 @@ class Chef
class Package
class Rpm < Chef::Provider::Package
+ provides :rpm_package, os: [ "linux", "aix" ]
+
include Chef::Mixin::GetSourceFromPackage
def define_resource_requirements
diff --git a/lib/chef/provider/package/rubygems.rb b/lib/chef/provider/package/rubygems.rb
index be0022f4aa..3c0ca40693 100644
--- a/lib/chef/provider/package/rubygems.rb
+++ b/lib/chef/provider/package/rubygems.rb
@@ -359,6 +359,9 @@ class Chef
Chef::Log.logger
end
+ provides :chef_gem
+ provides :gem_package
+
include Chef::Mixin::GetSourceFromPackage
def initialize(new_resource, run_context=nil)
@@ -493,6 +496,7 @@ class Chef
def target_version_already_installed?
return false unless @current_resource && @current_resource.version
return false if @current_resource.version.nil?
+ return false if @new_resource.version.nil?
Gem::Requirement.new(@new_resource.version).satisfied_by?(Gem::Version.new(@current_resource.version))
end
diff --git a/lib/chef/provider/package/smartos.rb b/lib/chef/provider/package/smartos.rb
index 19a6b9efef..7cef91953a 100644
--- a/lib/chef/provider/package/smartos.rb
+++ b/lib/chef/provider/package/smartos.rb
@@ -29,6 +29,8 @@ class Chef
class SmartOS < Chef::Provider::Package
attr_accessor :is_virtual_package
+ provides :smartos_package, os: "solaris2", platform_family: "smartos"
+
def load_current_resource
Chef::Log.debug("#{@new_resource} loading current resource")
@current_resource = Chef::Resource::Package.new(@new_resource.name)
diff --git a/lib/chef/provider/package/solaris.rb b/lib/chef/provider/package/solaris.rb
index 19f844b66a..53dd00dd07 100644
--- a/lib/chef/provider/package/solaris.rb
+++ b/lib/chef/provider/package/solaris.rb
@@ -27,6 +27,8 @@ class Chef
include Chef::Mixin::GetSourceFromPackage
+ provides :solaris_package, os: "solaris2"
+
# def initialize(*args)
# super
# @current_resource = Chef::Resource::Package.new(@new_resource.name)
diff --git a/lib/chef/provider/package/yum.rb b/lib/chef/provider/package/yum.rb
index e77319c254..505f5fd6a3 100644
--- a/lib/chef/provider/package/yum.rb
+++ b/lib/chef/provider/package/yum.rb
@@ -29,6 +29,8 @@ class Chef
class Package
class Yum < Chef::Provider::Package
+ provides :yum_package, os: "linux"
+
class RPMUtils
class << self
diff --git a/lib/chef/provider/powershell_script.rb b/lib/chef/provider/powershell_script.rb
index 967b2d822b..0e76cd1656 100644
--- a/lib/chef/provider/powershell_script.rb
+++ b/lib/chef/provider/powershell_script.rb
@@ -51,6 +51,8 @@ $chefscriptresult = {
}.invokereturnasis()
if ($interpolatedexitcode -and $chefscriptresult.gettype().name -eq 'boolean') { exit [int32](!$chefscriptresult) } else { exit 0 }
EOH
+ Chef::Log.debug("powershell_script provider called with script code:\n\n#{code}\n")
+ Chef::Log.debug("powershell_script provider will execute transformed code:\n\n#{@code}\n")
end
public
@@ -65,7 +67,7 @@ EOH
"-NoLogo",
"-NonInteractive",
"-NoProfile",
- "-ExecutionPolicy RemoteSigned",
+ "-ExecutionPolicy Unrestricted",
# Powershell will hang if STDIN is redirected
# http://connect.microsoft.com/PowerShell/feedback/details/572313/powershell-exe-can-hang-if-stdin-is-redirected
"-InputFormat None",
diff --git a/lib/chef/provider/remote_directory.rb b/lib/chef/provider/remote_directory.rb
index 5bd1cb5493..9a7416e318 100644
--- a/lib/chef/provider/remote_directory.rb
+++ b/lib/chef/provider/remote_directory.rb
@@ -32,6 +32,8 @@ class Chef
class Provider
class RemoteDirectory < Chef::Provider::Directory
+ provides :remote_directory
+
include Chef::Mixin::FileClass
def action_create
@@ -63,7 +65,7 @@ class Chef
def ls(path)
files = Dir.glob(::File.join(Chef::Util::PathHelper.escape_glob(path), '**', '*'),
::File::FNM_DOTMATCH)
-
+
# Remove current directory and previous directory
files.reject! do |name|
basename = Pathname.new(name).basename().to_s
diff --git a/lib/chef/provider/route.rb b/lib/chef/provider/route.rb
index 208a4f4139..72a5029a94 100644
--- a/lib/chef/provider/route.rb
+++ b/lib/chef/provider/route.rb
@@ -24,6 +24,8 @@ require 'ipaddr'
class Chef::Provider::Route < Chef::Provider
include Chef::Mixin::Command
+ provides :route
+
attr_accessor :is_running
MASK = {'0.0.0.0' => '0',
diff --git a/lib/chef/provider/ruby_block.rb b/lib/chef/provider/ruby_block.rb
index b0d94a3f8d..eb93fd5708 100644
--- a/lib/chef/provider/ruby_block.rb
+++ b/lib/chef/provider/ruby_block.rb
@@ -20,6 +20,8 @@
class Chef
class Provider
class RubyBlock < Chef::Provider
+ provides :ruby_block
+
def whyrun_supported?
true
end
diff --git a/lib/chef/provider/script.rb b/lib/chef/provider/script.rb
index 4aacf4f524..1615517553 100644
--- a/lib/chef/provider/script.rb
+++ b/lib/chef/provider/script.rb
@@ -22,6 +22,12 @@ require 'chef/provider/execute'
class Chef
class Provider
class Script < Chef::Provider::Execute
+ provides :bash
+ provides :csh
+ provides :perl
+ provides :python
+ provides :ruby
+ provides :script
def initialize(new_resource, run_context)
super
diff --git a/lib/chef/provider/service/aix.rb b/lib/chef/provider/service/aix.rb
new file mode 100644
index 0000000000..6f70f797b9
--- /dev/null
+++ b/lib/chef/provider/service/aix.rb
@@ -0,0 +1,126 @@
+#
+# Author:: kaustubh (<kaustubh@clogeny.com>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/provider/service'
+
+class Chef
+ class Provider
+ class Service
+ class Aix < Chef::Provider::Service
+ attr_reader :status_load_success
+
+ def initialize(new_resource, run_context)
+ super
+ end
+
+ def load_current_resource
+ @current_resource = Chef::Resource::Service.new(@new_resource.name)
+ @current_resource.service_name(@new_resource.service_name)
+
+ @status_load_success = true
+ @priority_success = true
+ @is_resource_group = false
+
+ determine_current_status!
+
+ @current_resource
+ end
+
+ def whyrun_supported?
+ true
+ end
+
+ def start_service
+ if @is_resource_group
+ shell_out!("startsrc -g #{@new_resource.service_name}")
+ else
+ shell_out!("startsrc -s #{@new_resource.service_name}")
+ end
+ end
+
+ def stop_service
+ if @is_resource_group
+ shell_out!("stopsrc -g #{@new_resource.service_name}")
+ else
+ shell_out!("stopsrc -s #{@new_resource.service_name}")
+ end
+ end
+
+ def restart_service
+ stop_service
+ start_service
+ end
+
+ def reload_service
+ if @is_resource_group
+ shell_out!("refresh -g #{@new_resource.service_name}")
+ else
+ shell_out!("refresh -s #{@new_resource.service_name}")
+ end
+ end
+
+ def shared_resource_requirements
+ super
+ requirements.assert(:all_actions) do |a|
+ a.assertion { @status_load_success }
+ a.whyrun ["Service status not available. Assuming a prior action would have installed the service.", "Assuming status of not running."]
+ end
+ end
+
+ def define_resource_requirements
+ # FIXME? need reload from service.rb
+ shared_resource_requirements
+ end
+
+ protected
+ def determine_current_status!
+ Chef::Log.debug "#{@new_resource} using lssrc to check the status "
+ begin
+ services = shell_out!("lssrc -a | grep -w #{@new_resource.service_name}").stdout.split("\n")
+ is_resource_group?(services)
+
+ if services.length == 1 && services[0].split(' ').last == "active"
+ @current_resource.running true
+ else
+ @current_resource.running false
+ end
+ Chef::Log.debug "#{@new_resource} running: #{@current_resource.running}"
+ # ShellOut sometimes throws different types of Exceptions than ShellCommandFailed.
+ # Temporarily catching different types of exceptions here until we get Shellout fixed.
+ # TODO: Remove the line before one we get the ShellOut fix.
+ rescue Mixlib::ShellOut::ShellCommandFailed, SystemCallError
+ @status_load_success = false
+ @current_resource.running false
+ nil
+ end
+ end
+
+ def is_resource_group? (services)
+ if services.length > 1
+ Chef::Log.debug("#{@new_resource.service_name} is a group")
+ @is_resource_group = true
+ elsif services[0].split(' ')[1] == @new_resource.service_name
+ Chef::Log.debug("#{@new_resource.service_name} is a group")
+ @is_resource_group = true
+ end
+ end
+ end
+ end
+ end
+end
+
diff --git a/lib/chef/provider/service/aixinit.rb b/lib/chef/provider/service/aixinit.rb
new file mode 100644
index 0000000000..ab4b8e5406
--- /dev/null
+++ b/lib/chef/provider/service/aixinit.rb
@@ -0,0 +1,117 @@
+#
+# Author:: kaustubh (<kaustubh@clogeny.com>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/provider/service/init'
+
+class Chef
+ class Provider
+ class Service
+ class AixInit < Chef::Provider::Service::Init
+ RC_D_SCRIPT_NAME = /\/etc\/rc.d\/rc2.d\/([SK])(\d\d|)/i
+
+ def initialize(new_resource, run_context)
+ super
+ @init_command = "/etc/rc.d/init.d/#{@new_resource.service_name}"
+ end
+
+ def load_current_resource
+ super
+ @priority_success = true
+ @rcd_status = nil
+
+ set_current_resource_attributes
+ @current_resource
+ end
+
+ def action_enable
+ if @new_resource.priority.nil?
+ priority_ok = true
+ else
+ priority_ok = @current_resource.priority == @new_resource.priority
+ end
+ if @current_resource.enabled and priority_ok
+ Chef::Log.debug("#{@new_resource} already enabled - nothing to do")
+ else
+ converge_by("enable service #{@new_resource}") do
+ enable_service
+ Chef::Log.info("#{@new_resource} enabled")
+ end
+ end
+ load_new_resource_state
+ @new_resource.enabled(true)
+ end
+
+ def enable_service
+ Dir.glob(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]#{@new_resource.service_name}"]).each { |f| ::File.delete(f)}
+
+ if @new_resource.priority.is_a? Integer
+ create_symlink(2, 'S', @new_resource.priority)
+
+ elsif @new_resource.priority.is_a? Hash
+ @new_resource.priority.each do |level,o|
+ create_symlink(level,(o[0] == :start ? 'S' : 'K'),o[1])
+ end
+ else
+ create_symlink(2, 'S', '')
+ end
+ end
+
+ def disable_service
+ Dir.glob(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]#{@new_resource.service_name}"]).each { |f| ::File.delete(f) }
+
+ if @new_resource.priority.is_a? Integer
+ create_symlink(2, 'K',100 - @new_resource.priority)
+ elsif @new_resource.priority.is_a? Hash
+ @new_resource.priority.each do |level,o|
+ create_symlink(level, 'K', 100 - o[1]) if o[0] == :stop
+ end
+ else
+ create_symlink(2, 'K', '')
+ end
+ end
+
+ def create_symlink(run_level, status, priority)
+ ::File.symlink("/etc/rc.d/init.d/#{@new_resource.service_name}", "/etc/rc.d/rc#{run_level}.d/#{status}#{priority}#{@new_resource.service_name}")
+ end
+
+ def set_current_resource_attributes
+ # assuming run level 2 for aix
+ is_enabled = false
+ files = Dir.glob(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]#{@new_resource.service_name}"])
+
+ priority = {}
+
+ files.each do |file|
+ if (RC_D_SCRIPT_NAME =~ file)
+ priority[2] = [($1 == "S" ? :start : :stop), ($2.empty? ? '' : $2.to_i)]
+ if $1 == "S"
+ is_enabled = true
+ end
+ end
+ end
+
+ if is_enabled && files.length == 1
+ priority = priority[2][1]
+ end
+ @current_resource.enabled(is_enabled)
+ @current_resource.priority(priority)
+ end
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/lib/chef/provider/service/arch.rb b/lib/chef/provider/service/arch.rb
index 9be5fb6fe3..888fb3fdf5 100644
--- a/lib/chef/provider/service/arch.rb
+++ b/lib/chef/provider/service/arch.rb
@@ -20,6 +20,12 @@ require 'chef/provider/service/init'
class Chef::Provider::Service::Arch < Chef::Provider::Service::Init
+ provides :service, platform_family: "arch"
+
+ def self.supports?(resource, action)
+ ::File.exist?("/etc/rc.d/#{resource.service_name}")
+ end
+
def initialize(new_resource, run_context)
super
@init_command = "/etc/rc.d/#{@new_resource.service_name}"
diff --git a/lib/chef/provider/service/debian.rb b/lib/chef/provider/service/debian.rb
index 1ebef90349..25b1960b26 100644
--- a/lib/chef/provider/service/debian.rb
+++ b/lib/chef/provider/service/debian.rb
@@ -25,13 +25,19 @@ class Chef
UPDATE_RC_D_ENABLED_MATCHES = /\/rc[\dS].d\/S|not installed/i
UPDATE_RC_D_PRIORITIES = /\/rc([\dS]).d\/([SK])(\d\d)/i
+ provides :service, platform_family: "debian"
+
+ def self.supports?(resource, action)
+ Chef::Platform::ServiceHelpers.service_resource_providers.include?(:debian)
+ end
+
def load_current_resource
super
@priority_success = true
@rcd_status = nil
- @current_resource.priority(get_priority)
- @current_resource.enabled(service_currently_enabled?(@current_resource.priority))
- @current_resource
+ current_resource.priority(get_priority)
+ current_resource.enabled(service_currently_enabled?(current_resource.priority))
+ current_resource
end
def define_resource_requirements
@@ -47,7 +53,7 @@ class Chef
requirements.assert(:all_actions) do |a|
a.assertion { @priority_success }
- a.failure_message Chef::Exceptions::Service, "/usr/sbin/update-rc.d -n -f #{@current_resource.service_name} failed - #{@rcd_status.inspect}"
+ a.failure_message Chef::Exceptions::Service, "/usr/sbin/update-rc.d -n -f #{current_resource.service_name} failed - #{@rcd_status.inspect}"
# This can happen if the service is not yet installed,so we'll fake it.
a.whyrun ["Unable to determine priority of service, assuming service would have been correctly installed earlier in the run.",
"Assigning temporary priorities to continue.",
@@ -59,7 +65,7 @@ class Chef
"3"=>[:start, "20"],
"4"=>[:start, "20"],
"5"=>[:start, "20"]}
- @current_resource.priority(temp_priorities)
+ current_resource.priority(temp_priorities)
end
end
end
@@ -67,7 +73,7 @@ class Chef
def get_priority
priority = {}
- @rcd_status = popen4("/usr/sbin/update-rc.d -n -f #{@current_resource.service_name} remove") do |pid, stdin, stdout, stderr|
+ @rcd_status = popen4("/usr/sbin/update-rc.d -n -f #{current_resource.service_name} remove") do |pid, stdin, stdout, stderr|
[stdout, stderr].each do |iop|
iop.each_line do |line|
@@ -99,7 +105,7 @@ class Chef
def service_currently_enabled?(priority)
enabled = false
priority.each { |runlevel, arguments|
- Chef::Log.debug("#{@new_resource} runlevel #{runlevel}, action #{arguments[0]}, priority #{arguments[1]}")
+ Chef::Log.debug("#{new_resource} runlevel #{runlevel}, action #{arguments[0]}, priority #{arguments[1]}")
# if we are in a update-rc.d default startup runlevel && we start in this runlevel
if %w[ 1 2 3 4 5 S ].include?(runlevel) && arguments[0] == :start
enabled = true
@@ -111,63 +117,63 @@ class Chef
# Override method from parent to ensure priority is up-to-date
def action_enable
- if @new_resource.priority.nil?
+ if new_resource.priority.nil?
priority_ok = true
else
- priority_ok = @current_resource.priority == @new_resource.priority
+ priority_ok = @current_resource.priority == new_resource.priority
end
- if @current_resource.enabled and priority_ok
- Chef::Log.debug("#{@new_resource} already enabled - nothing to do")
+ if current_resource.enabled and priority_ok
+ Chef::Log.debug("#{new_resource} already enabled - nothing to do")
else
- converge_by("enable service #{@new_resource}") do
+ converge_by("enable service #{new_resource}") do
enable_service
- Chef::Log.info("#{@new_resource} enabled")
+ Chef::Log.info("#{new_resource} enabled")
end
end
load_new_resource_state
- @new_resource.enabled(true)
+ new_resource.enabled(true)
end
def enable_service
- if @new_resource.priority.is_a? Integer
- shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
- shell_out!("/usr/sbin/update-rc.d #{@new_resource.service_name} defaults #{@new_resource.priority} #{100 - @new_resource.priority}")
- elsif @new_resource.priority.is_a? Hash
+ if new_resource.priority.is_a? Integer
+ shell_out!("/usr/sbin/update-rc.d -f #{new_resource.service_name} remove")
+ shell_out!("/usr/sbin/update-rc.d #{new_resource.service_name} defaults #{new_resource.priority} #{100 - new_resource.priority}")
+ elsif new_resource.priority.is_a? Hash
# we call the same command regardless of we're enabling or disabling
# users passing a Hash are responsible for setting their own start priorities
set_priority
else # No priority, go with update-rc.d defaults
- shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
- shell_out!("/usr/sbin/update-rc.d #{@new_resource.service_name} defaults")
+ shell_out!("/usr/sbin/update-rc.d -f #{new_resource.service_name} remove")
+ shell_out!("/usr/sbin/update-rc.d #{new_resource.service_name} defaults")
end
end
def disable_service
- if @new_resource.priority.is_a? Integer
+ if new_resource.priority.is_a? Integer
# Stop processes in reverse order of start using '100 - start_priority'
- shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
- shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} stop #{100 - @new_resource.priority} 2 3 4 5 .")
- elsif @new_resource.priority.is_a? Hash
+ shell_out!("/usr/sbin/update-rc.d -f #{new_resource.service_name} remove")
+ shell_out!("/usr/sbin/update-rc.d -f #{new_resource.service_name} stop #{100 - new_resource.priority} 2 3 4 5 .")
+ elsif new_resource.priority.is_a? Hash
# we call the same command regardless of we're enabling or disabling
# users passing a Hash are responsible for setting their own stop priorities
set_priority
else
# no priority, using '100 - 20 (update-rc.d default)' to stop in reverse order of start
- shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
- shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} stop 80 2 3 4 5 .")
+ shell_out!("/usr/sbin/update-rc.d -f #{new_resource.service_name} remove")
+ shell_out!("/usr/sbin/update-rc.d -f #{new_resource.service_name} stop 80 2 3 4 5 .")
end
end
def set_priority
args = ""
- @new_resource.priority.each do |level, o|
+ new_resource.priority.each do |level, o|
action = o[0]
priority = o[1]
args += "#{action} #{priority} #{level} . "
end
- shell_out!("/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
- shell_out!("/usr/sbin/update-rc.d #{@new_resource.service_name} #{args}")
+ shell_out!("/usr/sbin/update-rc.d -f #{new_resource.service_name} remove")
+ shell_out!("/usr/sbin/update-rc.d #{new_resource.service_name} #{args}")
end
end
end
diff --git a/lib/chef/provider/service/freebsd.rb b/lib/chef/provider/service/freebsd.rb
index 08d58232e1..e4a456ac25 100644
--- a/lib/chef/provider/service/freebsd.rb
+++ b/lib/chef/provider/service/freebsd.rb
@@ -27,6 +27,10 @@ class Chef
attr_reader :enabled_state_found
+ provides :service, os: [ "freebsd", "netbsd" ]
+
+ include Chef::Mixin::ShellOut
+
def initialize(new_resource, run_context)
super
@enabled_state_found = false
diff --git a/lib/chef/provider/service/gentoo.rb b/lib/chef/provider/service/gentoo.rb
index e2dff10994..3dab920f06 100644
--- a/lib/chef/provider/service/gentoo.rb
+++ b/lib/chef/provider/service/gentoo.rb
@@ -22,6 +22,9 @@ require 'chef/mixin/command'
require 'chef/util/path_helper'
class Chef::Provider::Service::Gentoo < Chef::Provider::Service::Init
+
+ provides :service, platform_family: "gentoo"
+
def load_current_resource
@new_resource.supports[:status] = true
diff --git a/lib/chef/provider/service/init.rb b/lib/chef/provider/service/init.rb
index 5d8bb5bb38..ab40a720f6 100644
--- a/lib/chef/provider/service/init.rb
+++ b/lib/chef/provider/service/init.rb
@@ -26,6 +26,8 @@ class Chef
attr_accessor :init_command
+ provides :service, os: "!windows"
+
def initialize(new_resource, run_context)
super
@init_command = "/etc/init.d/#{@new_resource.service_name}"
diff --git a/lib/chef/provider/service/insserv.rb b/lib/chef/provider/service/insserv.rb
index 1ee817707a..df5a162a45 100644
--- a/lib/chef/provider/service/insserv.rb
+++ b/lib/chef/provider/service/insserv.rb
@@ -24,26 +24,32 @@ class Chef
class Service
class Insserv < Chef::Provider::Service::Init
+ provides :service, os: "linux"
+
+ def self.supports?(resource, action)
+ Chef::Platform::ServiceHelpers.service_resource_providers.include?(:insserv)
+ end
+
def load_current_resource
super
- # Look for a /etc/rc.*/SnnSERVICE link to signifiy that the service would be started in a runlevel
- if Dir.glob("/etc/rc**/S*#{Chef::Util::PathHelper.escape_glob(@current_resource.service_name)}").empty?
- @current_resource.enabled false
+ # Look for a /etc/rc.*/SnnSERVICE link to signify that the service would be started in a runlevel
+ if Dir.glob("/etc/rc**/S*#{Chef::Util::PathHelper.escape_glob(current_resource.service_name)}").empty?
+ current_resource.enabled false
else
- @current_resource.enabled true
+ current_resource.enabled true
end
- @current_resource
+ current_resource
end
def enable_service()
- shell_out!("/sbin/insserv -r -f #{@new_resource.service_name}")
- shell_out!("/sbin/insserv -d -f #{@new_resource.service_name}")
+ shell_out!("/sbin/insserv -r -f #{new_resource.service_name}")
+ shell_out!("/sbin/insserv -d -f #{new_resource.service_name}")
end
def disable_service()
- shell_out!("/sbin/insserv -r -f #{@new_resource.service_name}")
+ shell_out!("/sbin/insserv -r -f #{new_resource.service_name}")
end
end
end
diff --git a/lib/chef/provider/service/invokercd.rb b/lib/chef/provider/service/invokercd.rb
index e6afa7272a..c7472211bc 100644
--- a/lib/chef/provider/service/invokercd.rb
+++ b/lib/chef/provider/service/invokercd.rb
@@ -23,6 +23,12 @@ class Chef
class Service
class Invokercd < Chef::Provider::Service::Init
+ provides :service, platform_family: "debian"
+
+ def self.supports?(resource, action)
+ Chef::Platform::ServiceHelpers.service_resource_providers.include?(:invokerc)
+ end
+
def initialize(new_resource, run_context)
super
@init_command = "/usr/sbin/invoke-rc.d #{@new_resource.service_name}"
diff --git a/lib/chef/provider/service/macosx.rb b/lib/chef/provider/service/macosx.rb
index ad1535327b..10ad1aa29d 100644
--- a/lib/chef/provider/service/macosx.rb
+++ b/lib/chef/provider/service/macosx.rb
@@ -26,6 +26,8 @@ class Chef
class Service
class Macosx < Chef::Provider::Service::Simple
+ provides :service, os: "darwin"
+
def self.gather_plist_dirs
locations = %w{/Library/LaunchAgents
/Library/LaunchDaemons
diff --git a/lib/chef/provider/service/redhat.rb b/lib/chef/provider/service/redhat.rb
index 7a7b2a1c40..90744ae268 100644
--- a/lib/chef/provider/service/redhat.rb
+++ b/lib/chef/provider/service/redhat.rb
@@ -26,11 +26,17 @@ class Chef
CHKCONFIG_ON = /\d:on/
CHKCONFIG_MISSING = /No such/
+ provides :service, platform_family: [ "rhel", "fedora", "suse" ]
+
+ def self.supports?(resource, action)
+ Chef::Platform::ServiceHelpers.service_resource_providers.include?(:redhat)
+ end
+
def initialize(new_resource, run_context)
super
- @init_command = "/sbin/service #{@new_resource.service_name}"
- @new_resource.supports[:status] = true
- @service_missing = false
+ @init_command = "/sbin/service #{@new_resource.service_name}"
+ @new_resource.supports[:status] = true
+ @service_missing = false
end
def define_resource_requirements
diff --git a/lib/chef/provider/service/simple.rb b/lib/chef/provider/service/simple.rb
index bd51d15f84..ee403ee163 100644
--- a/lib/chef/provider/service/simple.rb
+++ b/lib/chef/provider/service/simple.rb
@@ -25,6 +25,8 @@ class Chef
class Service
class Simple < Chef::Provider::Service
+ # this must be subclassed to be useful so does not directly implement :service
+
attr_reader :status_load_success
def load_current_resource
diff --git a/lib/chef/provider/service/solaris.rb b/lib/chef/provider/service/solaris.rb
index f0584dcf6d..eaea6bb1ab 100644
--- a/lib/chef/provider/service/solaris.rb
+++ b/lib/chef/provider/service/solaris.rb
@@ -26,6 +26,8 @@ class Chef
class Solaris < Chef::Provider::Service
attr_reader :maintenance
+ provides :service, os: "solaris2"
+
def initialize(new_resource, run_context=nil)
super
@init_command = "/usr/sbin/svcadm"
diff --git a/lib/chef/provider/service/systemd.rb b/lib/chef/provider/service/systemd.rb
index 31feee65d4..311751ab9a 100644
--- a/lib/chef/provider/service/systemd.rb
+++ b/lib/chef/provider/service/systemd.rb
@@ -20,6 +20,13 @@ require 'chef/resource/service'
require 'chef/provider/service/simple'
class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
+
+ provides :service, os: "linux"
+
+ def self.supports?(resource, action)
+ Chef::Platform::ServiceHelpers.service_resource_providers.include?(:systemd)
+ end
+
def load_current_resource
@current_resource = Chef::Resource::Service.new(@new_resource.name)
@current_resource.service_name(@new_resource.service_name)
diff --git a/lib/chef/provider/service/upstart.rb b/lib/chef/provider/service/upstart.rb
index 670bf9e5f8..41bd850d6a 100644
--- a/lib/chef/provider/service/upstart.rb
+++ b/lib/chef/provider/service/upstart.rb
@@ -27,6 +27,13 @@ class Chef
class Upstart < Chef::Provider::Service::Simple
UPSTART_STATE_FORMAT = /\w+ \(?(\w+)\)?[\/ ](\w+)/
+ provides :service, os: "linux"
+
+ def self.supports?(resource, action)
+ Chef::Platform::ServiceHelpers.service_resource_providers.include?(:upstart) &&
+ Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:upstart)
+ end
+
# Upstart does more than start or stop a service, creating multiple 'states' [1] that a service can be in.
# In chef, when we ask a service to start, we expect it to have started before performing the next step
# since we have top down dependencies. Which is to say we may follow witha resource next that requires
diff --git a/lib/chef/provider/service/windows.rb b/lib/chef/provider/service/windows.rb
index d31aad4c9d..4b1d2079ec 100644
--- a/lib/chef/provider/service/windows.rb
+++ b/lib/chef/provider/service/windows.rb
@@ -25,6 +25,10 @@ end
class Chef::Provider::Service::Windows < Chef::Provider::Service
+ provides :service, os: "windows"
+
+ include Chef::Mixin::ShellOut
+
#Win32::Service.get_start_type
AUTO_START = 'auto start'
MANUAL = 'demand start'
diff --git a/lib/chef/provider/subversion.rb b/lib/chef/provider/subversion.rb
index 6cf31c8ec8..f4a0e6fc13 100644
--- a/lib/chef/provider/subversion.rb
+++ b/lib/chef/provider/subversion.rb
@@ -27,6 +27,8 @@ class Chef
class Provider
class Subversion < Chef::Provider
+ provides :subversion
+
SVN_INFO_PATTERN = /^([\w\s]+): (.+)$/
include Chef::Mixin::Command
diff --git a/lib/chef/provider/template.rb b/lib/chef/provider/template.rb
index 48cc45f3a8..1e759074b9 100644
--- a/lib/chef/provider/template.rb
+++ b/lib/chef/provider/template.rb
@@ -25,6 +25,7 @@ require 'chef/deprecation/warnings'
class Chef
class Provider
class Template < Chef::Provider::File
+ provides :template
extend Chef::Deprecation::Warnings
include Chef::Deprecation::Provider::Template
diff --git a/lib/chef/provider/whyrun_safe_ruby_block.rb b/lib/chef/provider/whyrun_safe_ruby_block.rb
index e5f35debd7..3b95752cc4 100644
--- a/lib/chef/provider/whyrun_safe_ruby_block.rb
+++ b/lib/chef/provider/whyrun_safe_ruby_block.rb
@@ -19,6 +19,8 @@
class Chef
class Provider
class WhyrunSafeRubyBlock < Chef::Provider::RubyBlock
+ provides :whyrun_safe_ruby_block
+
def action_run
@new_resource.block.call
@new_resource.updated_by_last_action(true)
diff --git a/lib/chef/provider_resolver.rb b/lib/chef/provider_resolver.rb
new file mode 100644
index 0000000000..c819b0c87f
--- /dev/null
+++ b/lib/chef/provider_resolver.rb
@@ -0,0 +1,103 @@
+#
+# Author:: Richard Manyanza (<liseki@nyikacraftsmen.com>)
+# Copyright:: Copyright (c) 2014 Richard Manyanza.
+# 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/provider_priority_map'
+
+class Chef
+ class ProviderResolver
+
+ attr_reader :node
+
+ def initialize(node)
+ @node = node
+ end
+
+ # return a deterministically sorted list of Chef::Provider subclasses
+ def providers
+ Chef::Provider.descendants.sort {|a,b| a.to_s <=> b.to_s }
+ end
+
+ def resolve(resource, action)
+ maybe_explicit_provider(resource) ||
+ maybe_dynamic_provider_resolution(resource, action) ||
+ maybe_chef_platform_lookup(resource)
+ end
+
+ private
+
+ # if resource.provider is set, just return one of those objects
+ def maybe_explicit_provider(resource)
+ return nil unless resource.provider
+ resource.provider
+ end
+
+ # try dynamically finding a provider based on querying the providers to see what they support
+ def maybe_dynamic_provider_resolution(resource, action)
+ # this cut only depends on the node value and is going to be static for all nodes
+ # will contain all providers that could possibly support a resource on a node
+ enabled_handlers = providers.select do |klass|
+ klass.provides?(node, resource)
+ end
+
+ # log this so we know what providers will work for the generic resource on the node (early cut)
+ Chef::Log.debug "providers for generic #{resource.resource_name} resource enabled on node include: #{enabled_handlers}"
+
+ # ask all the enabled providers if they can actually support the resource
+ supported_handlers = enabled_handlers.select do |klass|
+ klass.supports?(resource, action)
+ end
+
+ # what providers were excluded by machine state (late cut)
+ Chef::Log.debug "providers that refused resource #{resource} were: #{enabled_handlers - supported_handlers}"
+ Chef::Log.debug "providers that support resource #{resource} include: #{supported_handlers}"
+
+ handlers = supported_handlers.empty? ? enabled_handlers : supported_handlers
+
+ if handlers.count >= 2
+ priority_list = [ get_provider_priority_map(resource.resource_name, node) ].flatten.compact
+
+ handlers = handlers.sort_by { |x| i = priority_list.index x; i.nil? ? Float::INFINITY : i }
+
+ handlers = [ handlers.first ]
+ end
+
+ Chef::Log.debug "providers that survived replacement include: #{handlers}"
+
+ raise Chef::Exceptions::AmbiguousProviderResolution.new(resource, handlers) if handlers.count >= 2
+
+ return nil if handlers.empty?
+
+ handlers[0]
+ end
+
+ # try the old static lookup of providers by platform
+ def maybe_chef_platform_lookup(resource)
+ Chef::Platform.find_provider_for_node(node, resource)
+ end
+
+ # dep injection hooks
+ def get_provider_priority_map(resource_name, node)
+ provider_priority_map.get(node, resource_name)
+ end
+
+ def provider_priority_map
+ Chef::Platform::ProviderPriorityMap.instance.priority_map
+ end
+ end
+end
diff --git a/lib/chef/providers.rb b/lib/chef/providers.rb
index fec00d0e63..c4f1ce769d 100644
--- a/lib/chef/providers.rb
+++ b/lib/chef/providers.rb
@@ -75,19 +75,21 @@ require 'chef/provider/package/smartos'
require 'chef/provider/package/aix'
require 'chef/provider/service/arch'
-require 'chef/provider/service/debian'
require 'chef/provider/service/freebsd'
require 'chef/provider/service/gentoo'
require 'chef/provider/service/init'
-require 'chef/provider/service/insserv'
require 'chef/provider/service/invokercd'
+require 'chef/provider/service/debian'
require 'chef/provider/service/redhat'
+require 'chef/provider/service/insserv'
require 'chef/provider/service/simple'
require 'chef/provider/service/systemd'
require 'chef/provider/service/upstart'
require 'chef/provider/service/windows'
require 'chef/provider/service/solaris'
require 'chef/provider/service/macosx'
+require 'chef/provider/service/aixinit'
+require 'chef/provider/service/aix'
require 'chef/provider/user/dscl'
require 'chef/provider/user/pw'
diff --git a/lib/chef/recipe.rb b/lib/chef/recipe.rb
index 32578da5ab..de72a8d0c4 100644
--- a/lib/chef/recipe.rb
+++ b/lib/chef/recipe.rb
@@ -96,6 +96,8 @@ class Chef
# true<TrueClass>:: If all the parameters are present
# false<FalseClass>:: If any of the parameters are missing
def tagged?(*tags)
+ return false if run_context.node[:tags].nil?
+
tags.each do |tag|
return false unless run_context.node[:tags].include?(tag)
end
diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb
index 70abfbcdb0..c38f36aa72 100644
--- a/lib/chef/resource.rb
+++ b/lib/chef/resource.rb
@@ -27,11 +27,12 @@ require 'chef/guard_interpreter/resource_guard_interpreter'
require 'chef/resource/conditional'
require 'chef/resource/conditional_action_not_nothing'
require 'chef/resource_collection'
-require 'chef/resource_platform_map'
+require 'chef/node_map'
require 'chef/node'
require 'chef/platform'
require 'chef/mixin/deprecation'
+require 'chef/mixin/descendants_tracker'
class Chef
class Resource
@@ -133,6 +134,7 @@ F
include Chef::Mixin::Deprecation
extend Chef::Mixin::ConvertToClassName
+ extend Chef::Mixin::DescendantsTracker
if Module.method(:const_defined?).arity == 1
def self.strict_const_defined?(const)
@@ -144,24 +146,13 @@ F
end
end
- # Track all subclasses of Resource. This is used so names can be looked up
- # when attempting to deserialize from JSON. (See: json_compat)
- def self.resource_classes
- # Using a class variable here ensures we have one variable to track
- # subclasses shared by the entire class hierarchy; without this, each
- # subclass would have its own list of subclasses.
- @@resource_classes ||= []
- end
-
- # Callback when subclass is defined. Adds subclass to list of subclasses.
- def self.inherited(subclass)
- resource_classes << subclass
- end
-
- # Look up a subclass by +class_name+ which should be a string that matches
- # `Subclass.name`
- def self.find_subclass_by_name(class_name)
- resource_classes.first {|c| c.name == class_name }
+ class << self
+ # back-compat
+ # NOTE: that we do not support unregistering classes as descendents like
+ # we used to for LWRP unloading because that was horrible and removed in
+ # Chef-12.
+ alias :resource_classes :descendants
+ alias :find_subclass_by_name :find_descendants_by_name
end
# Set or return the list of "state attributes" implemented by the Resource
@@ -229,6 +220,8 @@ F
attr_reader :elapsed_time
+ attr_reader :default_guard_interpreter
+
# Each notify entry is a resource/action pair, modeled as an
# Struct with a #resource and #action member
@@ -250,7 +243,13 @@ F
@not_if = []
@only_if = []
@source_line = nil
- @guard_interpreter = :default
+ # We would like to raise an error when the user gives us a guard
+ # interpreter and a ruby_block to the guard. In order to achieve this
+ # we need to understand when the user overrides the default guard
+ # interpreter. Therefore we store the default separately in a different
+ # attribute.
+ @guard_interpreter = nil
+ @default_guard_interpreter = :default
@elapsed_time = 0
@sensitive = false
end
@@ -297,12 +296,13 @@ F
end
end
- def load_prior_resource
+ def load_prior_resource(resource_type, instance_name)
begin
- prior_resource = run_context.resource_collection.lookup(self.to_s)
+ key = ::Chef::ResourceCollection::ResourceSet.create_key(resource_type, instance_name)
+ prior_resource = run_context.resource_collection.lookup(key)
# if we get here, there is a prior resource (otherwise we'd have jumped
# to the rescue clause).
- Chef::Log.warn("Cloning resource attributes for #{self.to_s} from prior resource (CHEF-3694)")
+ Chef::Log.warn("Cloning resource attributes for #{key} from prior resource (CHEF-3694)")
Chef::Log.warn("Previous #{prior_resource}: #{prior_resource.source_line}") if prior_resource.source_line
Chef::Log.warn("Current #{self}: #{self.source_line}") if self.source_line
prior_resource.instance_variables.each do |iv|
@@ -410,11 +410,15 @@ F
end
def guard_interpreter(arg=nil)
- set_or_return(
- :guard_interpreter,
- arg,
- :kind_of => Symbol
- )
+ if arg.nil?
+ @guard_interpreter || @default_guard_interpreter
+ else
+ set_or_return(
+ :guard_interpreter,
+ arg,
+ :kind_of => Symbol
+ )
+ end
end
# Sets up a notification from this resource to the resource specified by +resource_spec+.
@@ -639,6 +643,11 @@ F
# on accident
updated_by_last_action(false)
+ # Don't modify @retries directly and keep it intact, so that the
+ # recipe_snippet from ResourceFailureInspector can print the value
+ # that was set in the resource block initially.
+ remaining_retries = retries
+
begin
return if should_skip?(action)
provider_for_action(action).run_action
@@ -646,10 +655,10 @@ F
if ignore_failure
Chef::Log.error("#{custom_exception_message(e)}; ignore_failure is set, continuing")
events.resource_failed(self, action, e)
- elsif retries > 0
- events.resource_failed_retriable(self, action, retries, e)
- @retries -= 1
- Chef::Log.info("Retrying execution of #{self}, #{retries} attempt(s) left")
+ elsif remaining_retries > 0
+ events.resource_failed_retriable(self, action, remaining_retries, e)
+ remaining_retries -= 1
+ Chef::Log.info("Retrying execution of #{self}, #{remaining_retries} attempt(s) left")
sleep retry_delay
retry
else
@@ -670,16 +679,9 @@ F
end
def provider_for_action(action)
- # leverage new platform => short_name => resource
- # which requires explicitly setting provider in
- # resource class
- if self.provider
- provider = self.provider.new(self, self.run_context)
- provider.action = action
- provider
- else # fall back to old provider resolution
- Chef::Platform.provider_for_resource(self, action)
- end
+ provider = run_context.provider_resolver.resolve(self, action).new(self, run_context)
+ provider.action = action
+ provider
end
def custom_exception_message(e)
@@ -754,8 +756,8 @@ F
@provider_base ||= Chef::Provider
end
- def self.platform_map
- @@platform_map ||= PlatformMap.new
+ def self.node_map
+ @@node_map ||= NodeMap.new
end
# Maps a short_name (and optionally a platform and version) to a
@@ -764,66 +766,55 @@ F
# (I'm looking at you Chef::Resource::Package)
# Ex:
# class WindowsFile < Chef::Resource
- # provides :file, :on_platforms => ["windows"]
+ # 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
#
- # TODO: 2011-11-02 schisamo - platform_version support
- def self.provides(short_name, opts={})
+ 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
- if opts.has_key?(:on_platforms)
- platforms = [opts[:on_platforms]].flatten
- platforms.each do |p|
- p = :default if :all == p.to_sym
- platform_map.set(
- :platform => p.to_sym,
- :short_name => short_name_sym,
- :resource => self
- )
- end
- else
- platform_map.set(
- :short_name => short_name_sym,
- :resource => self
- )
- end
+ node_map.set(short_name_sym, constantize(self.name), opts, &block)
end
- # Returns a resource based on a short_name anda platform and version.
- #
+ # Returns a resource based on a short_name and node
#
# ==== Parameters
# short_name<Symbol>:: short_name of the resource (ie :directory)
- # platform<Symbol,String>:: platform name
- # version<String>:: platform version
+ # node<Chef::Node>:: Node object to look up platform and version in
#
# === Returns
# <Chef::Resource>:: returns the proper Chef::Resource class
- def self.resource_for_platform(short_name, platform=nil, version=nil)
- platform_map.get(short_name, platform, version)
+ def self.resource_for_node(short_name, node)
+ klass = node_map.get(node, short_name) ||
+ resource_matching_short_name(short_name)
+ raise Chef::Exceptions::NoSuchResourceType.new(short_name, node) if klass.nil?
+ klass
end
- # Returns a resource based on a short_name and a node's
- # platform and version.
- #
+ # Returns the class of a Chef::Resource based on the short name
# ==== Parameters
# short_name<Symbol>:: short_name of the resource (ie :directory)
- # node<Chef::Node>:: Node object to look up platform and version in
#
# === Returns
# <Chef::Resource>:: returns the proper Chef::Resource class
- def self.resource_for_node(short_name, node)
+ def self.resource_matching_short_name(short_name)
begin
- platform, version = Chef::Platform.find_platform_and_version(node)
- rescue ArgumentError
+ rname = convert_to_class_name(short_name.to_s)
+ Chef::Resource.const_get(rname)
+ rescue NameError
+ nil
end
- resource = resource_for_platform(short_name, platform, version)
- resource
end
private
diff --git a/lib/chef/resource/apt_package.rb b/lib/chef/resource/apt_package.rb
index 050cf838ae..f944825ac3 100644
--- a/lib/chef/resource/apt_package.rb
+++ b/lib/chef/resource/apt_package.rb
@@ -23,10 +23,12 @@ class Chef
class Resource
class AptPackage < Chef::Resource::Package
+ provides :apt_package
+ provides :package, os: "linux", platform_family: [ "debian" ]
+
def initialize(name, run_context=nil)
super
@resource_name = :apt_package
- @provider = Chef::Provider::Package::Apt
@default_release = nil
end
diff --git a/lib/chef/resource/bash.rb b/lib/chef/resource/bash.rb
index c56de5fe20..0add0ce501 100644
--- a/lib/chef/resource/bash.rb
+++ b/lib/chef/resource/bash.rb
@@ -17,6 +17,7 @@
#
require 'chef/resource/script'
+require 'chef/provider/script'
class Chef
class Resource
diff --git a/lib/chef/resource/bff_package.rb b/lib/chef/resource/bff_package.rb
index 2d78483e4b..917f0d1d50 100644
--- a/lib/chef/resource/bff_package.rb
+++ b/lib/chef/resource/bff_package.rb
@@ -26,7 +26,6 @@ class Chef
def initialize(name, run_context=nil)
super
@resource_name = :bff_package
- @provider = Chef::Provider::Package::Aix
end
end
diff --git a/lib/chef/resource/breakpoint.rb b/lib/chef/resource/breakpoint.rb
index 83c397bd5b..b2210262d2 100644
--- a/lib/chef/resource/breakpoint.rb
+++ b/lib/chef/resource/breakpoint.rb
@@ -28,7 +28,7 @@ class Chef
super(@name, *args)
@action = "break"
@allowed_actions << :break
- @provider = Chef::Provider::Breakpoint
+ @resource_name = :breakpoint
end
end
end
diff --git a/lib/chef/resource/chef_gem.rb b/lib/chef/resource/chef_gem.rb
index af45cb93e6..b4ead11f1d 100644
--- a/lib/chef/resource/chef_gem.rb
+++ b/lib/chef/resource/chef_gem.rb
@@ -23,13 +23,12 @@ class Chef
class Resource
class ChefGem < Chef::Resource::Package::GemPackage
- provides :chef_gem, :on_platforms => :all
+ provides :chef_gem
def initialize(name, run_context=nil)
super
@resource_name = :chef_gem
@gem_binary = RbConfig::CONFIG['bindir'] + "/gem"
- @provider = Chef::Provider::Package::Rubygems
end
# The chef_gem resources is for installing gems to the current gem environment only for use by Chef cookbooks.
diff --git a/lib/chef/resource/conditional.rb b/lib/chef/resource/conditional.rb
index 324c5a4676..8960a4d57f 100644
--- a/lib/chef/resource/conditional.rb
+++ b/lib/chef/resource/conditional.rb
@@ -59,8 +59,10 @@ class Chef
@guard_interpreter = new_guard_interpreter(@parent_resource, @command, @command_opts, &@block)
@block = nil
when nil
- # we should have a block if we get here
- if @parent_resource.guard_interpreter != :default
+ # We should have a block if we get here
+ # Check to see if the user set the guard_interpreter on the parent resource. Note that
+ # this error will not be raised when using the default_guard_interpreter
+ if @parent_resource.guard_interpreter != @parent_resource.default_guard_interpreter
msg = "#{@parent_resource.name} was given a guard_interpreter of #{@parent_resource.guard_interpreter}, "
msg << "but not given a command as a string. guard_interpreter does not support blocks (because they just contain ruby)."
raise ArgumentError, msg
diff --git a/lib/chef/resource/cookbook_file.rb b/lib/chef/resource/cookbook_file.rb
index de758aef71..7be353b648 100644
--- a/lib/chef/resource/cookbook_file.rb
+++ b/lib/chef/resource/cookbook_file.rb
@@ -27,7 +27,7 @@ class Chef
class CookbookFile < Chef::Resource::File
include Chef::Mixin::Securable
- provides :cookbook_file, :on_platforms => :all
+ provides :cookbook_file
def initialize(name, run_context=nil)
super
@@ -36,11 +36,10 @@ class Chef
@action = "create"
@source = ::File.basename(name)
@cookbook = nil
- @provider = Chef::Provider::CookbookFile
end
def source(source_filename=nil)
- set_or_return(:source, source_filename, :kind_of => String)
+ set_or_return(:source, source_filename, :kind_of => [ String, Array ])
end
def cookbook(cookbook_name=nil)
diff --git a/lib/chef/resource/csh.rb b/lib/chef/resource/csh.rb
index 95aa8afd7a..36659c349b 100644
--- a/lib/chef/resource/csh.rb
+++ b/lib/chef/resource/csh.rb
@@ -17,6 +17,7 @@
#
require 'chef/resource/script'
+require 'chef/provider/script'
class Chef
class Resource
diff --git a/lib/chef/resource/deploy.rb b/lib/chef/resource/deploy.rb
index a08e8aeeea..4252aa230f 100644
--- a/lib/chef/resource/deploy.rb
+++ b/lib/chef/resource/deploy.rb
@@ -77,7 +77,6 @@ class Chef
@shallow_clone = false
@scm_provider = Chef::Provider::Git
@svn_force_export = false
- @provider = Chef::Provider::Deploy::Timestamped
@allowed_actions.push(:force_deploy, :deploy, :rollback)
@additional_remotes = Hash[]
@keep_releases = 5
diff --git a/lib/chef/resource/deploy_revision.rb b/lib/chef/resource/deploy_revision.rb
index ceac26e91a..e144ce2162 100644
--- a/lib/chef/resource/deploy_revision.rb
+++ b/lib/chef/resource/deploy_revision.rb
@@ -22,14 +22,19 @@ class Chef
# Convenience class for using the deploy resource with the revision
# deployment strategy (provider)
class DeployRevision < Chef::Resource::Deploy
+
+ provides :deploy_revision
+
def initialize(*args, &block)
super
@resource_name = :deploy_revision
- @provider = Chef::Provider::Deploy::Revision
end
end
class DeployBranch < Chef::Resource::DeployRevision
+
+ provides :deploy_branch
+
def initialize(*args, &block)
super
@resource_name = :deploy_branch
diff --git a/lib/chef/resource/directory.rb b/lib/chef/resource/directory.rb
index 423c0bbe27..1ab7f0d16d 100644
--- a/lib/chef/resource/directory.rb
+++ b/lib/chef/resource/directory.rb
@@ -32,7 +32,7 @@ class Chef
include Chef::Mixin::Securable
- provides :directory, :on_platforms => :all
+ provides :directory
def initialize(name, run_context=nil)
super
@@ -41,7 +41,6 @@ class Chef
@action = :create
@recursive = false
@allowed_actions.push(:create, :delete)
- @provider = Chef::Provider::Directory
end
def recursive(arg=nil)
diff --git a/lib/chef/resource/dpkg_package.rb b/lib/chef/resource/dpkg_package.rb
index 2fb5b5c249..35a47e8a82 100644
--- a/lib/chef/resource/dpkg_package.rb
+++ b/lib/chef/resource/dpkg_package.rb
@@ -23,10 +23,11 @@ class Chef
class Resource
class DpkgPackage < Chef::Resource::Package
+ provides :dpkg_package, os: "linux"
+
def initialize(name, run_context=nil)
super
@resource_name = :dpkg_package
- @provider = Chef::Provider::Package::Dpkg
end
end
diff --git a/lib/chef/resource/dsc_script.rb b/lib/chef/resource/dsc_script.rb
index 76ac6659d6..82907c25db 100644
--- a/lib/chef/resource/dsc_script.rb
+++ b/lib/chef/resource/dsc_script.rb
@@ -22,13 +22,12 @@ class Chef
class Resource
class DscScript < Chef::Resource
- provides :dsc_script, :on_platforms => ["windows"]
+ provides :dsc_script, platform: "windows"
def initialize(name, run_context=nil)
super
@allowed_actions.push(:run)
@action = :run
- @provider = Chef::Provider::DscScript
@resource_name = :dsc_script
end
diff --git a/lib/chef/resource/easy_install_package.rb b/lib/chef/resource/easy_install_package.rb
index f25e1ac22f..5286e9a289 100644
--- a/lib/chef/resource/easy_install_package.rb
+++ b/lib/chef/resource/easy_install_package.rb
@@ -22,10 +22,11 @@ class Chef
class Resource
class EasyInstallPackage < Chef::Resource::Package
+ provides :easy_install_package
+
def initialize(name, run_context=nil)
super
@resource_name = :easy_install_package
- @provider = Chef::Provider::Package::EasyInstall
end
def easy_install_binary(arg=nil)
diff --git a/lib/chef/resource/erl_call.rb b/lib/chef/resource/erl_call.rb
index 959856af66..24009d51c7 100644
--- a/lib/chef/resource/erl_call.rb
+++ b/lib/chef/resource/erl_call.rb
@@ -18,6 +18,7 @@
#
require 'chef/resource'
+require 'chef/provider/erl_call'
class Chef
class Resource
diff --git a/lib/chef/resource/execute.rb b/lib/chef/resource/execute.rb
index 7c4fa48c0a..980035b079 100644
--- a/lib/chef/resource/execute.rb
+++ b/lib/chef/resource/execute.rb
@@ -18,6 +18,7 @@
#
require 'chef/resource'
+require 'chef/provider/execute'
class Chef
class Resource
@@ -35,12 +36,12 @@ class Chef
@cwd = nil
@environment = nil
@group = nil
- @path = nil
@returns = 0
@timeout = nil
@user = nil
@allowed_actions.push(:run)
@umask = nil
+ @default_guard_interpreter = :execute
end
def umask(arg=nil)
@@ -93,14 +94,6 @@ class Chef
)
end
- def path(arg=nil)
- set_or_return(
- :path,
- arg,
- :kind_of => [ Array ]
- )
- end
-
def returns(arg=nil)
set_or_return(
:returns,
@@ -125,6 +118,30 @@ class Chef
)
end
+ def self.set_guard_inherited_attributes(*inherited_attributes)
+ @class_inherited_attributes = inherited_attributes
+ end
+
+ def self.guard_inherited_attributes(*inherited_attributes)
+ # Similar to patterns elsewhere, return attributes from this
+ # class and superclasses as a form of inheritance
+ ancestor_attributes = []
+
+ if superclass.respond_to?(:guard_inherited_attributes)
+ ancestor_attributes = superclass.guard_inherited_attributes
+ end
+
+ ancestor_attributes.concat(@class_inherited_attributes ? @class_inherited_attributes : []).uniq
+ end
+
+ set_guard_inherited_attributes(
+ :cwd,
+ :environment,
+ :group,
+ :user,
+ :umask
+ )
+
end
end
end
diff --git a/lib/chef/resource/file.rb b/lib/chef/resource/file.rb
index 3c1f4785ef..16491f9bc8 100644
--- a/lib/chef/resource/file.rb
+++ b/lib/chef/resource/file.rb
@@ -19,7 +19,6 @@
require 'chef/resource'
require 'chef/platform/query_helpers'
-require 'chef/provider/file'
require 'chef/mixin/securable'
class Chef
@@ -38,7 +37,7 @@ class Chef
attr_writer :checksum
- provides :file, :on_platforms => :all
+ provides :file
def initialize(name, run_context=nil)
super
@@ -47,7 +46,6 @@ class Chef
@backup = 5
@action = "create"
@allowed_actions.push(:create, :delete, :touch, :create_if_missing)
- @provider = Chef::Provider::File
@atomic_update = Chef::Config[:file_atomic_update]
@force_unlink = false
@manage_symlink_source = nil
diff --git a/lib/chef/resource/freebsd_package.rb b/lib/chef/resource/freebsd_package.rb
index 70ef62ae8a..9c8db506f8 100644
--- a/lib/chef/resource/freebsd_package.rb
+++ b/lib/chef/resource/freebsd_package.rb
@@ -29,51 +29,38 @@ class Chef
class FreebsdPackage < Chef::Resource::Package
include Chef::Mixin::ShellOut
- provides :package, :on_platforms => ["freebsd"]
-
- attr_accessor :created_as_type
+ provides :package, platform: "freebsd"
def initialize(name, run_context=nil)
super
@resource_name = :freebsd_package
- @created_as_type = "freebsd_package"
end
def after_created
assign_provider
end
- # This resource can be invoked with multiple names package & freebsd_package.
- # We override the to_s method to ensure the key in resource collection
- # matches the type resource is declared as using created_as_type. This
- # logic can be removed once Chef does this for all resource in Chef 12:
- # https://github.com/opscode/chef/issues/1817
- def to_s
- "#{created_as_type}[#{name}]"
+ def supports_pkgng?
+ ships_with_pkgng? || !!shell_out!("make -V WITH_PKGNG", :env => nil).stdout.match(/yes/i)
end
private
+ def ships_with_pkgng?
+ # It was not until __FreeBSD_version 1000017 that pkgng became
+ # the default binary package manager. See '/usr/ports/Mk/bsd.port.mk'.
+ node.automatic[:os_version].to_i >= 1000017
+ end
+
def assign_provider
@provider = if @source.to_s =~ /^ports$/i
Chef::Provider::Package::Freebsd::Port
- elsif ships_with_pkgng? || supports_pkgng?
+ elsif supports_pkgng?
Chef::Provider::Package::Freebsd::Pkgng
else
Chef::Provider::Package::Freebsd::Pkg
end
end
-
- def ships_with_pkgng?
- # It was not until __FreeBSD_version 1000017 that pkgng became
- # the default binary package manager. See '/usr/ports/Mk/bsd.port.mk'.
- node[:os_version].to_i >= 1000017
- end
-
- def supports_pkgng?
- !!shell_out!("make -V WITH_PKGNG", :env => nil).stdout.match(/yes/i)
- end
-
end
end
end
diff --git a/lib/chef/resource/gem_package.rb b/lib/chef/resource/gem_package.rb
index 6def7b6653..631aa13f56 100644
--- a/lib/chef/resource/gem_package.rb
+++ b/lib/chef/resource/gem_package.rb
@@ -22,10 +22,11 @@ class Chef
class Resource
class GemPackage < Chef::Resource::Package
+ provides :gem_package
+
def initialize(name, run_context=nil)
super
@resource_name = :gem_package
- @provider = Chef::Provider::Package::Rubygems
end
def source(arg=nil)
diff --git a/lib/chef/resource/git.rb b/lib/chef/resource/git.rb
index 774bb24f24..7156873315 100644
--- a/lib/chef/resource/git.rb
+++ b/lib/chef/resource/git.rb
@@ -22,10 +22,11 @@ class Chef
class Resource
class Git < Chef::Resource::Scm
+ provides :git
+
def initialize(name, run_context=nil)
super
@resource_name = :git
- @provider = Chef::Provider::Git
@additional_remotes = Hash[]
end
diff --git a/lib/chef/resource/homebrew_package.rb b/lib/chef/resource/homebrew_package.rb
index e1d50c1739..952552e3a8 100644
--- a/lib/chef/resource/homebrew_package.rb
+++ b/lib/chef/resource/homebrew_package.rb
@@ -25,10 +25,11 @@ class Chef
class Resource
class HomebrewPackage < Chef::Resource::Package
+ provides :homebrew_package, os: "mac_os_x"
+
def initialize(name, run_context=nil)
super
@resource_name = :homebrew_package
- @provider = Chef::Provider::Package::Homebrew
@homebrew_user = nil
end
diff --git a/lib/chef/resource/http_request.rb b/lib/chef/resource/http_request.rb
index 47f6286fb4..ccb0a26629 100644
--- a/lib/chef/resource/http_request.rb
+++ b/lib/chef/resource/http_request.rb
@@ -18,6 +18,7 @@
#
require 'chef/resource'
+require 'chef/provider/http_request'
class Chef
class Resource
diff --git a/lib/chef/resource/ips_package.rb b/lib/chef/resource/ips_package.rb
index 88c6e9a538..77b3387946 100644
--- a/lib/chef/resource/ips_package.rb
+++ b/lib/chef/resource/ips_package.rb
@@ -22,10 +22,12 @@ require 'chef/provider/package/ips'
class Chef
class Resource
class IpsPackage < ::Chef::Resource::Package
+
+ provides :ips_package, os: "solaris2"
+
def initialize(name, run_context = nil)
super(name, run_context)
@resource_name = :ips_package
- @provider = Chef::Provider::Package::Ips
@allowed_actions = [ :install, :remove, :upgrade ]
@accept_license = false
end
diff --git a/lib/chef/resource/link.rb b/lib/chef/resource/link.rb
index e53b386a74..8726eded1d 100644
--- a/lib/chef/resource/link.rb
+++ b/lib/chef/resource/link.rb
@@ -25,7 +25,7 @@ class Chef
class Link < Chef::Resource
include Chef::Mixin::Securable
- provides :link, :on_platform => :all
+ provides :link
identity_attr :target_file
@@ -40,7 +40,6 @@ class Chef
@link_type = :symbolic
@target_file = name
@allowed_actions.push(:create, :delete)
- @provider = Chef::Provider::Link
end
def to(arg=nil)
diff --git a/lib/chef/resource/log.rb b/lib/chef/resource/log.rb
index 391c3b5393..7f970a87a4 100644
--- a/lib/chef/resource/log.rb
+++ b/lib/chef/resource/log.rb
@@ -16,6 +16,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+
+require 'chef/resource'
+require 'chef/provider/log'
+
class Chef
class Resource
class Log < Chef::Resource
diff --git a/lib/chef/resource/lwrp_base.rb b/lib/chef/resource/lwrp_base.rb
index 5b67941a8b..a4606be842 100644
--- a/lib/chef/resource/lwrp_base.rb
+++ b/lib/chef/resource/lwrp_base.rb
@@ -35,26 +35,24 @@ class Chef
# Evaluates the LWRP resource file and instantiates a new Resource class.
def self.build_from_file(cookbook_name, filename, run_context)
+ resource_class = nil
rname = filename_to_qualified_string(cookbook_name, filename)
- # Add log entry if we override an existing lightweight resource.
class_name = convert_to_class_name(rname)
if Resource.strict_const_defined?(class_name)
- old_class = Resource.send(:remove_const, class_name)
- # CHEF-3432 -- Chef::Resource keeps a list of subclasses; need to
- # remove old ones from the list when replacing.
- resource_classes.delete(old_class)
- Chef::Log.info("#{class_name} lightweight resource already initialized -- overriding!")
- end
-
- resource_class = Class.new(self)
+ Chef::Log.info("#{class_name} light-weight resource is already initialized -- Skipping loading #{filename}!")
+ Chef::Log.debug("Overriding already defined LWRPs is not supported anymore starting with Chef 12.")
+ resource_class = Resource.const_get(class_name)
+ else
+ resource_class = Class.new(self)
- resource_class.resource_name = rname
- resource_class.run_context = run_context
- resource_class.class_from_file(filename)
+ resource_class.resource_name = rname
+ resource_class.run_context = run_context
+ resource_class.class_from_file(filename)
- Chef::Resource.const_set(class_name, resource_class)
- Chef::Log.debug("Loaded contents of #{filename} into a resource named #{rname} defined in Chef::Resource::#{class_name}")
+ Chef::Resource.const_set(class_name, resource_class)
+ Chef::Log.debug("Loaded contents of #{filename} into a resource named #{rname} defined in Chef::Resource::#{class_name}")
+ end
resource_class
end
@@ -112,10 +110,21 @@ class Chef
if action_names.empty?
defined?(@actions) ? @actions : from_superclass(:actions, []).dup
else
- @actions = action_names
+ # BC-compat way for checking if actions have already been defined
+ if defined?(@actions)
+ @actions.push(*action_names)
+ else
+ @actions = action_names
+ end
end
end
+ # @deprecated
+ def self.valid_actions(*args)
+ Chef::Log.warn("`valid_actions' is deprecated, please use actions `instead'!")
+ actions(*args)
+ end
+
# Set the run context on the class. Used to provide access to the node
# during class definition.
def self.run_context=(run_context)
diff --git a/lib/chef/resource/macports_package.rb b/lib/chef/resource/macports_package.rb
index c9434c9e69..bdc8698155 100644
--- a/lib/chef/resource/macports_package.rb
+++ b/lib/chef/resource/macports_package.rb
@@ -19,10 +19,12 @@
class Chef
class Resource
class MacportsPackage < Chef::Resource::Package
+
+ provides :macports_package, os: "mac_os_x"
+
def initialize(name, run_context=nil)
super
@resource_name = :macports_package
- @provider = Chef::Provider::Package::Macports
end
end
end
diff --git a/lib/chef/resource/pacman_package.rb b/lib/chef/resource/pacman_package.rb
index 2894e415ac..4c45dd004f 100644
--- a/lib/chef/resource/pacman_package.rb
+++ b/lib/chef/resource/pacman_package.rb
@@ -22,10 +22,11 @@ class Chef
class Resource
class PacmanPackage < Chef::Resource::Package
+ provides :pacman_package, os: "linux"
+
def initialize(name, run_context=nil)
super
@resource_name = :pacman_package
- @provider = Chef::Provider::Package::Pacman
end
end
diff --git a/lib/chef/resource/paludis_package.rb b/lib/chef/resource/paludis_package.rb
index fde25e69b3..7eddf8690b 100644
--- a/lib/chef/resource/paludis_package.rb
+++ b/lib/chef/resource/paludis_package.rb
@@ -22,10 +22,12 @@ require 'chef/provider/package/paludis'
class Chef
class Resource
class PaludisPackage < Chef::Resource::Package
+
+ provides :paludis_package, os: "linux"
+
def initialize(name, run_context=nil)
super(name, run_context)
@resource_name = :paludis_package
- @provider = Chef::Provider::Package::Paludis
@allowed_actions = [ :install, :remove, :upgrade ]
@timeout = 3600
end
diff --git a/lib/chef/resource/perl.rb b/lib/chef/resource/perl.rb
index 546f639e1f..c4bdb6e130 100644
--- a/lib/chef/resource/perl.rb
+++ b/lib/chef/resource/perl.rb
@@ -17,6 +17,7 @@
#
require 'chef/resource/script'
+require 'chef/provider/script'
class Chef
class Resource
diff --git a/lib/chef/resource/powershell_script.rb b/lib/chef/resource/powershell_script.rb
index 1b47e7411a..a88fb5701b 100644
--- a/lib/chef/resource/powershell_script.rb
+++ b/lib/chef/resource/powershell_script.rb
@@ -21,8 +21,6 @@ class Chef
class Resource
class PowershellScript < Chef::Resource::WindowsScript
- set_guard_inherited_attributes(:architecture)
-
def initialize(name, run_context=nil)
super(name, run_context, :powershell_script, "powershell.exe")
@convert_boolean_return = false
diff --git a/lib/chef/resource/python.rb b/lib/chef/resource/python.rb
index f340afdb39..b1f23d13ce 100644
--- a/lib/chef/resource/python.rb
+++ b/lib/chef/resource/python.rb
@@ -1,4 +1,3 @@
-#
# Author:: Adam Jacob (<adam@opscode.com>)
# Copyright:: Copyright (c) 2008 Opscode, Inc.
# License:: Apache License, Version 2.0
@@ -17,6 +16,7 @@
#
require 'chef/resource/script'
+require 'chef/provider/script'
class Chef
class Resource
diff --git a/lib/chef/resource/remote_directory.rb b/lib/chef/resource/remote_directory.rb
index 0f7e0eb5de..d4108da47a 100644
--- a/lib/chef/resource/remote_directory.rb
+++ b/lib/chef/resource/remote_directory.rb
@@ -26,7 +26,7 @@ class Chef
class RemoteDirectory < Chef::Resource::Directory
include Chef::Mixin::Securable
- provides :remote_directory, :on_platforms => :all
+ provides :remote_directory
identity_attr :path
@@ -48,7 +48,6 @@ class Chef
@overwrite = true
@allowed_actions.push(:create, :create_if_missing, :delete)
@cookbook = nil
- @provider = Chef::Provider::RemoteDirectory
end
if Chef::Platform.windows?
diff --git a/lib/chef/resource/remote_file.rb b/lib/chef/resource/remote_file.rb
index 6334b1bf44..46516fd3fb 100644
--- a/lib/chef/resource/remote_file.rb
+++ b/lib/chef/resource/remote_file.rb
@@ -26,7 +26,7 @@ class Chef
class RemoteFile < Chef::Resource::File
include Chef::Mixin::Securable
- provides :remote_file, :on_platforms => :all
+ provides :remote_file
def initialize(name, run_context=nil)
super
diff --git a/lib/chef/resource/rpm_package.rb b/lib/chef/resource/rpm_package.rb
index 200a9633ce..8634f1e25d 100644
--- a/lib/chef/resource/rpm_package.rb
+++ b/lib/chef/resource/rpm_package.rb
@@ -23,10 +23,11 @@ class Chef
class Resource
class RpmPackage < Chef::Resource::Package
+ provides :rpm_package, os: [ "linux", "aix" ]
+
def initialize(name, run_context=nil)
super
@resource_name = :rpm_package
- @provider = Chef::Provider::Package::Rpm
end
end
diff --git a/lib/chef/resource/ruby.rb b/lib/chef/resource/ruby.rb
index 605d27b00d..2b2aa0249d 100644
--- a/lib/chef/resource/ruby.rb
+++ b/lib/chef/resource/ruby.rb
@@ -17,6 +17,7 @@
#
require 'chef/resource/script'
+require 'chef/provider/script'
class Chef
class Resource
diff --git a/lib/chef/resource/ruby_block.rb b/lib/chef/resource/ruby_block.rb
index d9b8954a90..a9cbf234cf 100644
--- a/lib/chef/resource/ruby_block.rb
+++ b/lib/chef/resource/ruby_block.rb
@@ -17,6 +17,9 @@
# limitations under the License.
#
+require 'chef/resource'
+require 'chef/provider/ruby_block'
+
class Chef
class Resource
class RubyBlock < Chef::Resource
diff --git a/lib/chef/resource/script.rb b/lib/chef/resource/script.rb
index 6f66fb9094..479295922c 100644
--- a/lib/chef/resource/script.rb
+++ b/lib/chef/resource/script.rb
@@ -18,6 +18,7 @@
#
require 'chef/resource/execute'
+require 'chef/provider/script'
class Chef
class Resource
@@ -32,6 +33,7 @@ class Chef
@code = nil
@interpreter = nil
@flags = nil
+ @default_guard_interpreter = :default
end
def code(arg=nil)
@@ -58,31 +60,6 @@ class Chef
)
end
- def self.set_guard_inherited_attributes(*inherited_attributes)
- @class_inherited_attributes = inherited_attributes
- end
-
- def self.guard_inherited_attributes(*inherited_attributes)
- # Similar to patterns elsewhere, return attributes from this
- # class and superclasses as a form of inheritance
- ancestor_attributes = []
-
- if superclass.respond_to?(:guard_inherited_attributes)
- ancestor_attributes = superclass.guard_inherited_attributes
- end
-
- ancestor_attributes.concat(@class_inherited_attributes ? @class_inherited_attributes : []).uniq
- end
-
- set_guard_inherited_attributes(
- :cwd,
- :environment,
- :group,
- :path,
- :user,
- :umask
- )
-
end
end
end
diff --git a/lib/chef/resource/service.rb b/lib/chef/resource/service.rb
index 4d64c3e3f4..36df7c859a 100644
--- a/lib/chef/resource/service.rb
+++ b/lib/chef/resource/service.rb
@@ -46,10 +46,6 @@ class Chef
@action = "nothing"
@supports = { :restart => false, :reload => false, :status => false }
@allowed_actions.push(:enable, :disable, :start, :stop, :restart, :reload)
-
- if(run_context && run_context.node[:init_package] == "systemd")
- @provider = Chef::Provider::Service::Systemd
- end
end
def service_name(arg=nil)
diff --git a/lib/chef/resource/smartos_package.rb b/lib/chef/resource/smartos_package.rb
index 0f4f6d8b0a..99b3b953b0 100644
--- a/lib/chef/resource/smartos_package.rb
+++ b/lib/chef/resource/smartos_package.rb
@@ -23,16 +23,15 @@ class Chef
class Resource
class SmartosPackage < Chef::Resource::Package
+ provides :smartos_package
+ provides :package, os: "solaris2", platform_family: "smartos"
+
def initialize(name, run_context=nil)
super
@resource_name = :smartos_package
- @provider = Chef::Provider::Package::SmartOS
end
end
end
end
-# Backwards compatability
-# @todo remove in Chef 12
-Chef::Resource::SmartOSPackage = Chef::Resource::SmartosPackage
diff --git a/lib/chef/resource/solaris_package.rb b/lib/chef/resource/solaris_package.rb
index 3513703076..94be4693b6 100644
--- a/lib/chef/resource/solaris_package.rb
+++ b/lib/chef/resource/solaris_package.rb
@@ -24,10 +24,16 @@ class Chef
class Resource
class SolarisPackage < Chef::Resource::Package
+ provides :solaris_package
+ provides :package, os: "solaris2", platform_family: "nexentacore"
+ provides :package, os: "solaris2", platform_family: "solaris2" do |node|
+ # on >= Solaris 11 we default to IPS packages instead
+ node[:platform_version].to_f <= 5.10
+ end
+
def initialize(name, run_context=nil)
super
@resource_name = :solaris_package
- @provider = Chef::Provider::Package::Solaris
end
end
diff --git a/lib/chef/resource/subversion.rb b/lib/chef/resource/subversion.rb
index 44158cb080..3afbe0baaf 100644
--- a/lib/chef/resource/subversion.rb
+++ b/lib/chef/resource/subversion.rb
@@ -28,7 +28,6 @@ class Chef
@svn_arguments = '--no-auth-cache'
@svn_info_args = '--no-auth-cache'
@resource_name = :subversion
- @provider = Chef::Provider::Subversion
allowed_actions << :force_export
end
diff --git a/lib/chef/resource/template.rb b/lib/chef/resource/template.rb
index 9cba6f1c38..8c9607ee07 100644
--- a/lib/chef/resource/template.rb
+++ b/lib/chef/resource/template.rb
@@ -27,7 +27,7 @@ class Chef
class Template < Chef::Resource::File
include Chef::Mixin::Securable
- provides :template, :on_platforms => :all
+ provides :template
attr_reader :inline_helper_blocks
attr_reader :inline_helper_modules
@@ -40,7 +40,6 @@ class Chef
@cookbook = nil
@local = false
@variables = Hash.new
- @provider = Chef::Provider::Template
@inline_helper_blocks = {}
@inline_helper_modules = []
@helper_modules = []
@@ -50,7 +49,7 @@ class Chef
set_or_return(
:source,
file,
- :kind_of => [ String ]
+ :kind_of => [ String, Array ]
)
end
diff --git a/lib/chef/resource/timestamped_deploy.rb b/lib/chef/resource/timestamped_deploy.rb
index 4032ae9854..b2109db85c 100644
--- a/lib/chef/resource/timestamped_deploy.rb
+++ b/lib/chef/resource/timestamped_deploy.rb
@@ -18,13 +18,12 @@
class Chef
class Resource
-
# Convenience class for using the deploy resource with the timestamped
# deployment strategy (provider)
class TimestampedDeploy < Chef::Resource::Deploy
+ provides :timestamped_deploy
def initialize(*args, &block)
super(*args, &block)
- @provider = Chef::Provider::Deploy::Timestamped
end
end
end
diff --git a/lib/chef/resource/whyrun_safe_ruby_block.rb b/lib/chef/resource/whyrun_safe_ruby_block.rb
index ddb9d91dc3..6fa5383f5d 100644
--- a/lib/chef/resource/whyrun_safe_ruby_block.rb
+++ b/lib/chef/resource/whyrun_safe_ruby_block.rb
@@ -23,7 +23,6 @@ class Chef
def initialize(name, run_context=nil)
super
@resource_name = :whyrun_safe_ruby_block
- @provider = Chef::Provider::WhyrunSafeRubyBlock
end
end
diff --git a/lib/chef/resource/windows_package.rb b/lib/chef/resource/windows_package.rb
index 8bd41e0cb7..c563ba5fdc 100644
--- a/lib/chef/resource/windows_package.rb
+++ b/lib/chef/resource/windows_package.rb
@@ -24,12 +24,11 @@ class Chef
class Resource
class WindowsPackage < Chef::Resource::Package
- provides :package, :on_platforms => ["windows"]
+ provides :package, platform: "windows"
def initialize(name, run_context=nil)
super
@allowed_actions = [ :install, :remove ]
- @provider = Chef::Provider::Package::Windows
@resource_name = :windows_package
@source ||= source(@package_name)
@@ -76,4 +75,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/resource/windows_script.rb b/lib/chef/resource/windows_script.rb
index 108891e9ba..6b0827b77c 100644
--- a/lib/chef/resource/windows_script.rb
+++ b/lib/chef/resource/windows_script.rb
@@ -23,12 +23,15 @@ class Chef
class Resource
class WindowsScript < Chef::Resource::Script
+ set_guard_inherited_attributes(:architecture)
+
protected
def initialize(name, run_context, resource_name, interpreter_command)
super(name, run_context)
@interpreter = interpreter_command
@resource_name = resource_name
+ @default_guard_interpreter = resource_name
end
include Chef::Mixin::WindowsArchitectureHelper
diff --git a/lib/chef/resource/windows_service.rb b/lib/chef/resource/windows_service.rb
index 5ed8e76cbd..49495117ee 100644
--- a/lib/chef/resource/windows_service.rb
+++ b/lib/chef/resource/windows_service.rb
@@ -25,7 +25,7 @@ class Chef
# Until #1773 is resolved, you need to manually specify the windows_service resource
# to use action :configure_startup and attribute startup_type
- # provides :service, :on_platforms => ["windows"]
+ provides :service, platform: "windows"
identity_attr :service_name
@@ -34,7 +34,6 @@ class Chef
def initialize(name, run_context=nil)
super
@resource_name = :windows_service
- @provider = Chef::Provider::Service::Windows
@allowed_actions.push(:configure_startup)
@startup_type = :automatic
end
diff --git a/lib/chef/resource/yum_package.rb b/lib/chef/resource/yum_package.rb
index dff70bcf62..8fbca9b097 100644
--- a/lib/chef/resource/yum_package.rb
+++ b/lib/chef/resource/yum_package.rb
@@ -23,10 +23,12 @@ class Chef
class Resource
class YumPackage < Chef::Resource::Package
+ provides :yum_package
+ provides :package, os: "linux", platform_family: [ "rhel", "fedora" ]
+
def initialize(name, run_context=nil)
super
@resource_name = :yum_package
- @provider = Chef::Provider::Package::Yum
@flush_cache = { :before => false, :after => false }
@allow_downgrade = false
end
diff --git a/lib/chef/resource_collection.rb b/lib/chef/resource_collection.rb
index cc14a03962..30520cff7e 100644
--- a/lib/chef/resource_collection.rb
+++ b/lib/chef/resource_collection.rb
@@ -17,250 +17,75 @@
# limitations under the License.
#
-require 'chef/resource'
-require 'chef/resource_collection/stepable_iterator'
-
+require 'chef/resource_collection/resource_set'
+require 'chef/resource_collection/resource_list'
+require 'chef/resource_collection/resource_collection_serialization'
+require 'chef/log'
+require 'forwardable'
+
+##
+# ResourceCollection currently handles two tasks:
+# 1) Keeps an ordered list of resources to use when converging the node
+# 2) Keeps a unique list of resources (keyed as `type[name]`) used for notifications
class Chef
class ResourceCollection
- include Enumerable
-
- # Matches a multiple resource lookup specification,
- # e.g., "service[nginx,unicorn]"
- MULTIPLE_RESOURCE_MATCH = /^(.+)\[(.+?),(.+)\]$/
+ include ResourceCollectionSerialization
+ extend Forwardable
- # Matches a single resource lookup specification,
- # e.g., "service[nginx]"
- SINGLE_RESOURCE_MATCH = /^(.+)\[(.+)\]$/
-
- attr_reader :iterator
+ attr_reader :resource_set, :resource_list
+ private :resource_set, :resource_list
def initialize
- @resources = Array.new
- @resources_by_name = Hash.new
- @insert_after_idx = nil
- end
-
- def all_resources
- @resources
- end
-
- def [](index)
- @resources[index]
- end
-
- def []=(index, arg)
- is_chef_resource(arg)
- @resources[index] = arg
- @resources_by_name[arg.to_s] = index
- end
-
- def <<(*args)
- args.flatten.each do |a|
- is_chef_resource(a)
- @resources << a
- @resources_by_name[a.to_s] = @resources.length - 1
- end
- self
- end
-
- # 'push' is an alias method to <<
- alias_method :push, :<<
-
- def insert(resource)
- if @insert_after_idx
- # in the middle of executing a run, so any resources inserted now should
- # be placed after the most recent addition done by the currently executing
- # resource
- insert_at(@insert_after_idx + 1, resource)
- @insert_after_idx += 1
+ @resource_set = ResourceSet.new
+ @resource_list = ResourceList.new
+ end
+
+ # @param resource [Chef::Resource] The resource to insert
+ # @param resource_type [String,Symbol] If known, the resource type used in the recipe, Eg `package`, `execute`
+ # @param instance_name [String] If known, the recource name as used in the recipe, IE `vim` in `package 'vim'`
+ # @param at_location [Integer] If know, a location in the @resource_list to insert resource
+ # If you know the at_location but not the resource_type or instance_name, pass them in as nil
+ # This method is meant to be the 1 insert method necessary in the future. It should support all known use cases
+ # for writing into the ResourceCollection.
+ def insert(resource, opts={})
+ resource_type ||= opts[:resource_type] # Would rather use Ruby 2.x syntax, but oh well
+ instance_name ||= opts[:instance_name]
+ resource_list.insert(resource)
+ if !(resource_type.nil? && instance_name.nil?)
+ resource_set.insert_as(resource, resource_type, instance_name)
else
- is_chef_resource(resource)
- @resources << resource
- @resources_by_name[resource.to_s] = @resources.length - 1
+ resource_set.insert_as(resource)
end
end
- def insert_at(insert_at_index, *resources)
- resources.each do |resource|
- is_chef_resource(resource)
- end
- @resources.insert(insert_at_index, *resources)
- # update name -> location mappings and register new resource
- @resources_by_name.each_key do |key|
- @resources_by_name[key] += resources.size if @resources_by_name[key] >= insert_at_index
- end
- resources.each_with_index do |resource, i|
- @resources_by_name[resource.to_s] = insert_at_index + i
- end
+ # @deprecated
+ def []=(index, resource)
+ Chef::Log.warn("`[]=` is deprecated, use `insert` with the `at_location` parameter")
+ resource_list[index] = resource
+ resource_set.insert_as(resource)
end
- def each
- @resources.each do |resource|
- yield resource
+ # @deprecated
+ def push(*resources)
+ Chef::Log.warn("`push` is deprecated, use `insert`")
+ resources.flatten.each do |res|
+ insert(res)
end
+ self
end
- def execute_each_resource(&resource_exec_block)
- @iterator = StepableIterator.for_collection(@resources)
- @iterator.each_with_index do |resource, idx|
- @insert_after_idx = idx
- yield resource
- end
- end
-
- def each_index
- @resources.each_index do |i|
- yield i
- end
- end
-
- def empty?
- @resources.empty?
- end
-
- def lookup(resource)
- lookup_by = nil
- if resource.kind_of?(Chef::Resource)
- lookup_by = resource.to_s
- elsif resource.kind_of?(String)
- lookup_by = resource
- else
- raise ArgumentError, "Must pass a Chef::Resource or String to lookup"
- end
- res = @resources_by_name[lookup_by]
- unless res
- raise Chef::Exceptions::ResourceNotFound, "Cannot find a resource matching #{lookup_by} (did you define it first?)"
- end
- @resources[res]
- end
-
- # Find existing resources by searching the list of existing resources. Possible
- # forms are:
- #
- # find(:file => "foobar")
- # find(:file => [ "foobar", "baz" ])
- # find("file[foobar]", "file[baz]")
- # find("file[foobar,baz]")
- #
- # Returns the matching resource, or an Array of matching resources.
- #
- # Raises an ArgumentError if you feed it bad lookup information
- # Raises a Runtime Error if it can't find the resources you are looking for.
- def find(*args)
- results = Array.new
- args.each do |arg|
- case arg
- when Hash
- results << find_resource_by_hash(arg)
- when String
- results << find_resource_by_string(arg)
- else
- msg = "arguments to #{self.class.name}#find should be of the form :resource => 'name' or resource[name]"
- raise Chef::Exceptions::InvalidResourceSpecification, msg
- end
- end
- flat_results = results.flatten
- flat_results.length == 1 ? flat_results[0] : flat_results
- end
-
- # resources is a poorly named, but we have to maintain it for back
- # compat.
- alias_method :resources, :find
-
- # Returns true if +query_object+ is a valid string for looking up a
- # resource, or raises InvalidResourceSpecification if not.
- # === Arguments
- # * query_object should be a string of the form
- # "resource_type[resource_name]", a single element Hash (e.g., :service =>
- # "apache2"), or a Chef::Resource (this is the happy path). Other arguments
- # will raise an exception.
- # === Returns
- # * true returns true for all valid input.
- # === Raises
- # * Chef::Exceptions::InvalidResourceSpecification for all invalid input.
- def validate_lookup_spec!(query_object)
- case query_object
- when Chef::Resource
- true
- when SINGLE_RESOURCE_MATCH, MULTIPLE_RESOURCE_MATCH
- true
- when Hash
- true
- when String
- raise Chef::Exceptions::InvalidResourceSpecification,
- "The string `#{query_object}' is not valid for resource collection lookup. Correct syntax is `resource_type[resource_name]'"
- else
- raise Chef::Exceptions::InvalidResourceSpecification,
- "The object `#{query_object.inspect}' is not valid for resource collection lookup. " +
- "Use a String like `resource_type[resource_name]' or a Chef::Resource object"
- end
- end
-
- # Serialize this object as a hash
- def to_hash
- instance_vars = Hash.new
- self.instance_variables.each do |iv|
- instance_vars[iv] = self.instance_variable_get(iv)
- end
- {
- 'json_class' => self.class.name,
- 'instance_vars' => instance_vars
- }
- end
-
- def to_json(*a)
- Chef::JSONCompat.to_json(to_hash, *a)
- end
-
- def self.json_create(o)
- collection = self.new()
- o["instance_vars"].each do |k,v|
- collection.instance_variable_set(k.to_sym, v)
- end
- collection
- end
+ # @deprecated
+ alias_method :<<, :insert
- private
+ # Read-only methods are simple to delegate - doing that below
- def find_resource_by_hash(arg)
- results = Array.new
- arg.each do |resource_name, name_list|
- names = name_list.kind_of?(Array) ? name_list : [ name_list ]
- names.each do |name|
- res_name = "#{resource_name.to_s}[#{name}]"
- results << lookup(res_name)
- end
- end
- return results
- end
+ resource_list_methods = Enumerable.instance_methods +
+ [:iterator, :all_resources, :[], :each, :execute_each_resource, :each_index, :empty?] -
+ [:find] # find needs to run on the set
+ resource_set_methods = [:lookup, :find, :resources, :keys, :validate_lookup_spec!]
- def find_resource_by_string(arg)
- results = Array.new
- case arg
- when MULTIPLE_RESOURCE_MATCH
- resource_type = $1
- arg =~ /^.+\[(.+)\]$/
- resource_list = $1
- resource_list.split(",").each do |name|
- resource_name = "#{resource_type}[#{name}]"
- results << lookup(resource_name)
- end
- when SINGLE_RESOURCE_MATCH
- resource_type = $1
- name = $2
- resource_name = "#{resource_type}[#{name}]"
- results << lookup(resource_name)
- else
- raise ArgumentError, "Bad string format #{arg}, you must have a string like resource_type[name]!"
- end
- return results
- end
+ def_delegators :resource_list, *resource_list_methods
+ def_delegators :resource_set, *resource_set_methods
- def is_chef_resource(arg)
- unless arg.kind_of?(Chef::Resource)
- raise ArgumentError, "Cannot insert a #{arg.class} into a resource collection: must be a subclass of Chef::Resource"
- end
- true
- end
end
end
diff --git a/lib/chef/resource_collection/resource_collection_serialization.rb b/lib/chef/resource_collection/resource_collection_serialization.rb
new file mode 100644
index 0000000000..3651fb2a2a
--- /dev/null
+++ b/lib/chef/resource_collection/resource_collection_serialization.rb
@@ -0,0 +1,59 @@
+#
+# Author:: Tyler Ball (<tball@getchef.com>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+class Chef
+ class ResourceCollection
+ module ResourceCollectionSerialization
+ # Serialize this object as a hash
+ def to_hash
+ instance_vars = Hash.new
+ self.instance_variables.each do |iv|
+ instance_vars[iv] = self.instance_variable_get(iv)
+ end
+ {
+ 'json_class' => self.class.name,
+ 'instance_vars' => instance_vars
+ }
+ end
+
+ def to_json(*a)
+ Chef::JSONCompat.to_json(to_hash, *a)
+ end
+
+ def self.included(base)
+ base.extend(ClassMethods)
+ end
+
+ module ClassMethods
+ def json_create(o)
+ collection = self.new()
+ o["instance_vars"].each do |k,v|
+ collection.instance_variable_set(k.to_sym, v)
+ end
+ collection
+ end
+ end
+
+ def is_chef_resource!(arg)
+ unless arg.kind_of?(Chef::Resource)
+ raise ArgumentError, "Cannot insert a #{arg.class} into a resource collection: must be a subclass of Chef::Resource"
+ end
+ true
+ end
+ end
+ end
+end
diff --git a/lib/chef/resource_collection/resource_list.rb b/lib/chef/resource_collection/resource_list.rb
new file mode 100644
index 0000000000..a26bd347aa
--- /dev/null
+++ b/lib/chef/resource_collection/resource_list.rb
@@ -0,0 +1,89 @@
+#
+# Author:: Tyler Ball (<tball@getchef.com>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/resource'
+require 'chef/resource_collection/stepable_iterator'
+require 'chef/resource_collection/resource_collection_serialization'
+require 'forwardable'
+
+# This class keeps the list of all known Resources in the order they are to be executed in. It also keeps a pointer
+# to the most recently executed resource so we can add resources-to-execute after this point.
+class Chef
+ class ResourceCollection
+ class ResourceList
+ include ResourceCollection::ResourceCollectionSerialization
+ include Enumerable
+ extend Forwardable
+
+ attr_reader :iterator
+
+ attr_reader :resources
+ private :resources
+ # Delegate direct access methods to the @resources array
+ # 4 extra methods here are not included in the Enumerable's instance methods
+ direct_access_methods = Enumerable.instance_methods + [ :[], :each, :each_index, :empty? ]
+ def_delegators :resources, *(direct_access_methods)
+
+ def initialize
+ @resources = Array.new
+ @insert_after_idx = nil
+ end
+
+ # @param resource [Chef::Resource] The resource to insert
+ # If @insert_after_idx is nil, we are not currently executing a converge so the Resource is appended to the
+ # end of the list. If @insert_after_idx is NOT nil, we ARE currently executing a converge so the resource
+ # is inserted into the middle of the list after the last resource that was converged. If it is called multiple
+ # times (when an LWRP contains multiple resources) it keeps track of that. See this example ResourceList:
+ # [File1, LWRP1, File2] # The iterator starts and points to File1. It is executed and @insert_after_idx=0
+ # [File1, LWRP1, File2] # The iterator moves to LWRP1. It is executed and @insert_after_idx=1
+ # [File1, LWRP1, Service1, File2] # The LWRP execution inserts Service1 and @insert_after_idx=2
+ # [File1, LWRP1, Service1, Service2, File2] # The LWRP inserts Service2 and @insert_after_idx=3. The LWRP
+ # finishes executing
+ # [File1, LWRP1, Service1, Service2, File2] # The iterator moves to Service1 since it is the next non-executed
+ # resource. The execute_each_resource call below resets @insert_after_idx=2
+ # If Service1 was another LWRP, it would insert its resources between Service1 and Service2. The iterator keeps
+ # track of executed resources and @insert_after_idx keeps track of where the next resource to insert should be.
+ def insert(resource)
+ is_chef_resource!(resource)
+ if @insert_after_idx
+ @resources.insert(@insert_after_idx += 1, resource)
+ else
+ @resources << resource
+ end
+ end
+
+ # @deprecated - can be removed when it is removed from resource_collection.rb
+ def []=(index, resource)
+ @resources[index] = resource
+ end
+
+ def all_resources
+ @resources
+ end
+
+ def execute_each_resource(&resource_exec_block)
+ @iterator = ResourceCollection::StepableIterator.for_collection(@resources)
+ @iterator.each_with_index do |resource, idx|
+ @insert_after_idx = idx
+ yield resource
+ end
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/resource_collection/resource_set.rb b/lib/chef/resource_collection/resource_set.rb
new file mode 100644
index 0000000000..6425c2ab08
--- /dev/null
+++ b/lib/chef/resource_collection/resource_set.rb
@@ -0,0 +1,170 @@
+#
+# Author:: Tyler Ball (<tball@getchef.com>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/resource'
+require 'chef/resource_collection/resource_collection_serialization'
+
+class Chef
+ class ResourceCollection
+ class ResourceSet
+ include ResourceCollection::ResourceCollectionSerialization
+
+ # Matches a multiple resource lookup specification,
+ # e.g., "service[nginx,unicorn]"
+ MULTIPLE_RESOURCE_MATCH = /^(.+)\[(.+?),(.+)\]$/
+
+ # Matches a single resource lookup specification,
+ # e.g., "service[nginx]"
+ SINGLE_RESOURCE_MATCH = /^(.+)\[(.+)\]$/
+
+ def initialize
+ @resources_by_key = Hash.new
+ end
+
+ def keys
+ @resources_by_key.keys
+ end
+
+ def insert_as(resource, resource_type=nil, instance_name=nil)
+ is_chef_resource!(resource)
+ resource_type ||= resource.resource_name
+ instance_name ||= resource.name
+ key = ResourceSet.create_key(resource_type, instance_name)
+ @resources_by_key[key] = resource
+ end
+
+ def lookup(key)
+ case
+ when key.kind_of?(String)
+ lookup_by = key
+ when key.kind_of?(Chef::Resource)
+ lookup_by = ResourceSet.create_key(key.resource_name, key.name)
+ else
+ raise ArgumentError, "Must pass a Chef::Resource or String to lookup"
+ end
+
+ res = @resources_by_key[lookup_by]
+ unless res
+ raise Chef::Exceptions::ResourceNotFound, "Cannot find a resource matching #{lookup_by} (did you define it first?)"
+ end
+ res
+ end
+
+ # Find existing resources by searching the list of existing resources. Possible
+ # forms are:
+ #
+ # find(:file => "foobar")
+ # find(:file => [ "foobar", "baz" ])
+ # find("file[foobar]", "file[baz]")
+ # find("file[foobar,baz]")
+ #
+ # Returns the matching resource, or an Array of matching resources.
+ #
+ # Raises an ArgumentError if you feed it bad lookup information
+ # Raises a Runtime Error if it can't find the resources you are looking for.
+ def find(*args)
+ results = Array.new
+ args.each do |arg|
+ case arg
+ when Hash
+ results << find_resource_by_hash(arg)
+ when String
+ results << find_resource_by_string(arg)
+ else
+ msg = "arguments to #{self.class.name}#find should be of the form :resource => 'name' or 'resource[name]'"
+ raise Chef::Exceptions::InvalidResourceSpecification, msg
+ end
+ end
+ flat_results = results.flatten
+ flat_results.length == 1 ? flat_results[0] : flat_results
+ end
+
+ # @deprecated
+ # resources is a poorly named, but we have to maintain it for back
+ # compat.
+ alias_method :resources, :find
+
+ # Returns true if +query_object+ is a valid string for looking up a
+ # resource, or raises InvalidResourceSpecification if not.
+ # === Arguments
+ # * query_object should be a string of the form
+ # "resource_type[resource_name]", a single element Hash (e.g., :service =>
+ # "apache2"), or a Chef::Resource (this is the happy path). Other arguments
+ # will raise an exception.
+ # === Returns
+ # * true returns true for all valid input.
+ # === Raises
+ # * Chef::Exceptions::InvalidResourceSpecification for all invalid input.
+ def validate_lookup_spec!(query_object)
+ case query_object
+ when Chef::Resource
+ true
+ when SINGLE_RESOURCE_MATCH, MULTIPLE_RESOURCE_MATCH
+ true
+ when Hash
+ true
+ when String
+ raise Chef::Exceptions::InvalidResourceSpecification,
+ "The string `#{query_object}' is not valid for resource collection lookup. Correct syntax is `resource_type[resource_name]'"
+ else
+ raise Chef::Exceptions::InvalidResourceSpecification,
+ "The object `#{query_object.inspect}' is not valid for resource collection lookup. " +
+ "Use a String like `resource_type[resource_name]' or a Chef::Resource object"
+ end
+ end
+
+ def self.create_key(resource_type, instance_name)
+ "#{resource_type}[#{instance_name}]"
+ end
+
+ private
+
+ def find_resource_by_hash(arg)
+ results = Array.new
+ arg.each do |resource_type, name_list|
+ instance_names = name_list.kind_of?(Array) ? name_list : [ name_list ]
+ instance_names.each do |instance_name|
+ results << lookup(ResourceSet.create_key(resource_type, instance_name))
+ end
+ end
+ return results
+ end
+
+ def find_resource_by_string(arg)
+ results = Array.new
+ case arg
+ when MULTIPLE_RESOURCE_MATCH
+ resource_type = $1
+ arg =~ /^.+\[(.+)\]$/
+ resource_list = $1
+ resource_list.split(",").each do |instance_name|
+ results << lookup(ResourceSet.create_key(resource_type, instance_name))
+ end
+ when SINGLE_RESOURCE_MATCH
+ resource_type = $1
+ name = $2
+ results << lookup(ResourceSet.create_key(resource_type, name))
+ else
+ raise ArgumentError, "Bad string format #{arg}, you must have a string like resource_type[name]!"
+ end
+ return results
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/resource_platform_map.rb b/lib/chef/resource_platform_map.rb
deleted file mode 100644
index a678f5be4b..0000000000
--- a/lib/chef/resource_platform_map.rb
+++ /dev/null
@@ -1,151 +0,0 @@
-#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 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 'chef/mixin/params_validate'
-require 'chef/mixin/convert_to_class_name'
-
-class Chef
- class Resource
- class PlatformMap
-
- include Chef::Mixin::ParamsValidate
- include Chef::Mixin::ConvertToClassName
-
- attr_reader :map
-
- def initialize(map={:default => {}})
- @map = map
- end
-
- def filter(platform, version)
- resource_map = map[:default].clone
- platform_sym = platform
- if platform.kind_of?(String)
- platform.downcase!
- platform.gsub!(/\s/, "_")
- platform_sym = platform.to_sym
- end
-
- if map.has_key?(platform_sym)
- if map[platform_sym].has_key?(version)
- if map[platform_sym].has_key?(:default)
- resource_map.merge!(map[platform_sym][:default])
- end
- resource_map.merge!(map[platform_sym][version])
- elsif map[platform_sym].has_key?(:default)
- resource_map.merge!(map[platform_sym][:default])
- end
- end
- resource_map
- end
-
- def set(args)
- validate(
- args,
- {
- :platform => {
- :kind_of => Symbol,
- :required => false
- },
- :version => {
- :kind_of => String,
- :required => false
- },
- :short_name => {
- :kind_of => Symbol,
- :required => true
- },
- :resource => {
- :kind_of => [ String, Symbol, Class ],
- :required => true
- }
- }
- )
- if args.has_key?(:platform)
- if args.has_key?(:version)
- if map.has_key?(args[:platform])
- if map[args[:platform]].has_key?(args[:version])
- map[args[:platform]][args[:version]][args[:short_name].to_sym] = args[:resource]
- else
- map[args[:platform]][args[:version]] = {
- args[:short_name].to_sym => args[:resource]
- }
- end
- else
- map[args[:platform]] = {
- args[:version] => {
- args[:short_name].to_sym => args[:resource]
- }
- }
- end
- else
- if map.has_key?(args[:platform])
- if map[args[:platform]].has_key?(:default)
- map[args[:platform]][:default][args[:short_name].to_sym] = args[:resource]
- else
- map[args[:platform]] = { :default => { args[:short_name].to_sym => args[:resource] } }
- end
- else
- map[args[:platform]] = {
- :default => {
- args[:short_name].to_sym => args[:resource]
- }
- }
- end
- end
- else
- if map.has_key?(:default)
- map[:default][args[:short_name].to_sym] = args[:resource]
- else
- map[:default] = {
- args[:short_name].to_sym => args[:resource]
- }
- end
- end
- end
-
- def get(short_name, platform=nil, version=nil)
- resource_klass = platform_resource(short_name, platform, version) ||
- resource_matching_short_name(short_name)
-
- raise Exceptions::NoSuchResourceType, "Cannot find a resource for #{short_name} on #{platform} version #{version}" if resource_klass.nil?
-
- resource_klass
- end
-
- private
-
- def platform_resource(short_name, platform, version)
- pmap = filter(platform, version)
- rtkey = short_name.kind_of?(Chef::Resource) ? short_name.resource_name.to_sym : short_name
-
- pmap.has_key?(rtkey) ? pmap[rtkey] : nil
- end
-
- def resource_matching_short_name(short_name)
- begin
- rname = convert_to_class_name(short_name.to_s)
- Chef::Resource.const_get(rname)
- rescue NameError
- nil
- end
- end
-
- end
- end
-end
diff --git a/lib/chef/run_context.rb b/lib/chef/run_context.rb
index bbe2f9eba0..18d353ac61 100644
--- a/lib/chef/run_context.rb
+++ b/lib/chef/run_context.rb
@@ -18,6 +18,7 @@
# limitations under the License.
require 'chef/resource_collection'
+require 'chef/provider_resolver'
require 'chef/cookbook_version'
require 'chef/node'
require 'chef/role'
@@ -50,6 +51,9 @@ class Chef
# recipes, which is triggered by #load. (See also: CookbookCompiler)
attr_accessor :resource_collection
+ # Chef::ProviderResolver for this run
+ attr_accessor :provider_resolver
+
# A Hash containing the immediate notifications triggered by resources
# during the converge phase of the chef run.
attr_accessor :immediate_notification_collection
@@ -82,8 +86,8 @@ class Chef
@reboot_info = {}
@node.run_context = self
-
@cookbook_compiler = nil
+ @provider_resolver = Chef::ProviderResolver.new(@node)
end
# Triggers the compile phase of the chef run. Implemented by
diff --git a/lib/chef/shell/ext.rb b/lib/chef/shell/ext.rb
index bc4e955169..fd785e2f79 100644
--- a/lib/chef/shell/ext.rb
+++ b/lib/chef/shell/ext.rb
@@ -547,7 +547,7 @@ E
desc "list all the resources on the current recipe"
def resources(*args)
if args.empty?
- pp run_context.resource_collection.instance_variable_get(:@resources_by_name).keys
+ pp run_context.resource_collection.keys
else
pp resources = original_resources(*args)
resources
diff --git a/lib/chef/util/dsc/local_configuration_manager.rb b/lib/chef/util/dsc/local_configuration_manager.rb
index 4a56b6a397..f498a2bfea 100644
--- a/lib/chef/util/dsc/local_configuration_manager.rb
+++ b/lib/chef/util/dsc/local_configuration_manager.rb
@@ -29,7 +29,7 @@ class Chef::Util::DSC
def test_configuration(configuration_document)
status = run_configuration_cmdlet(configuration_document)
- handle_what_if_exception!(status.stderr) unless status.succeeded?
+ log_what_if_exception(status.stderr) unless status.succeeded?
configuration_update_required?(status.return_value)
end
@@ -78,18 +78,22 @@ $ProgressPreference = 'SilentlyContinue';start-dscconfiguration -path #{@configu
EOH
end
- def handle_what_if_exception!(what_if_exception_output)
- if what_if_exception_output.gsub(/\s+/, ' ') =~ /A parameter cannot be found that matches parameter name 'Whatif'/i
- # LCM returns an error if any of the resources do not support the opptional What-If
- Chef::Log::warn("Received error while testing configuration due to resource not supporting 'WhatIf'")
- elsif output_has_dsc_module_failure?(what_if_exception_output)
- Chef::Log::warn("Received error while testing configuration due to a module for an imported resource possibly not being fully installed:\n#{what_if_exception_output.gsub(/\s+/, ' ')}")
- else
- raise Chef::Exceptions::PowershellCmdletException, "Powershell Cmdlet failed: #{what_if_exception_output.gsub(/\s+/, ' ')}"
- end
+ def log_what_if_exception(what_if_exception_output)
+ if whatif_not_supported?(what_if_exception_output)
+ # LCM returns an error if any of the resources do not support the opptional What-If
+ Chef::Log::warn("Received error while testing configuration due to resource not supporting 'WhatIf'")
+ elsif dsc_module_import_failure?(what_if_exception_output)
+ Chef::Log::warn("Received error while testing configuration due to a module for an imported resource possibly not being fully installed:\n#{what_if_exception_output.gsub(/\s+/, ' ')}")
+ else
+ Chef::Log::warn("Received error while testing configuration:\n#{what_if_exception_output.gsub(/\s+/, ' ')}")
+ end
+ end
+
+ def whatif_not_supported?(what_if_exception_output)
+ !! (what_if_exception_output.gsub(/[\r\n]+/, '').gsub(/\s+/, ' ') =~ /A parameter cannot be found that matches parameter name 'Whatif'/i)
end
- def output_has_dsc_module_failure?(what_if_output)
+ def dsc_module_import_failure?(what_if_output)
!! (what_if_output =~ /\sCimException/ &&
what_if_output =~ /ProviderOperationExecutionFailure/ &&
what_if_output =~ /\smodule\s+is\s+installed/)
diff --git a/lib/chef/win32/version.rb b/lib/chef/win32/version.rb
index d2138289f5..d16bd8c12f 100644
--- a/lib/chef/win32/version.rb
+++ b/lib/chef/win32/version.rb
@@ -48,6 +48,8 @@ class Chef
public
WIN_VERSIONS = {
+ "Windows 10" => {:major => 6, :minor => 4, :callable => lambda{ |product_type, suite_mask| product_type == VER_NT_WORKSTATION }},
+ "Windows Server 10" => {:major => 6, :minor => 4, :callable => lambda {|product_type, suite_mask| product_type != VER_NT_WORKSTATION }},
"Windows 8.1" => {:major => 6, :minor => 3, :callable => lambda{ |product_type, suite_mask| product_type == VER_NT_WORKSTATION }},
"Windows Server 2012 R2" => {:major => 6, :minor => 3, :callable => lambda {|product_type, suite_mask| product_type != VER_NT_WORKSTATION }},
"Windows 8" => {:major => 6, :minor => 2, :callable => lambda{ |product_type, suite_mask| product_type == VER_NT_WORKSTATION }},
diff --git a/spec/data/cb_version_cookbooks/cookbook2/files/test.txt b/spec/data/cb_version_cookbooks/cookbook2/files/test.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/spec/data/cb_version_cookbooks/cookbook2/files/test.txt
diff --git a/spec/data/cb_version_cookbooks/cookbook2/templates/test.erb b/spec/data/cb_version_cookbooks/cookbook2/templates/test.erb
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/spec/data/cb_version_cookbooks/cookbook2/templates/test.erb
diff --git a/spec/data/cookbooks/ignorken/files/default/not_me.rb b/spec/data/cookbooks/ignorken/files/default/not_me.rb
new file mode 100644
index 0000000000..8063e32a95
--- /dev/null
+++ b/spec/data/cookbooks/ignorken/files/default/not_me.rb
@@ -0,0 +1,2 @@
+a cat walked on the keyboard one day...
+(*&(*&(*&(*&(*^%$%^%#^^&(*)(*{}}}}}}}}+++++===))))))
diff --git a/spec/data/cookbooks/ignorken/templates/ubuntu-12.10/not_me.rb b/spec/data/cookbooks/ignorken/templates/ubuntu-12.10/not_me.rb
new file mode 100644
index 0000000000..8063e32a95
--- /dev/null
+++ b/spec/data/cookbooks/ignorken/templates/ubuntu-12.10/not_me.rb
@@ -0,0 +1,2 @@
+a cat walked on the keyboard one day...
+(*&(*&(*&(*&(*^%$%^%#^^&(*)(*{}}}}}}}}+++++===))))))
diff --git a/spec/data/cookbooks/openldap/libraries/openldap.rb b/spec/data/cookbooks/openldap/libraries/openldap.rb
new file mode 100644
index 0000000000..6a3f058f95
--- /dev/null
+++ b/spec/data/cookbooks/openldap/libraries/openldap.rb
@@ -0,0 +1,4 @@
+require_relative './openldap/version.rb'
+
+class OpenLDAP
+end
diff --git a/spec/data/cookbooks/openldap/libraries/openldap/version.rb b/spec/data/cookbooks/openldap/libraries/openldap/version.rb
new file mode 100644
index 0000000000..4bff12b01c
--- /dev/null
+++ b/spec/data/cookbooks/openldap/libraries/openldap/version.rb
@@ -0,0 +1,3 @@
+class OpenLDAP
+ VERSION = '8.9.10'
+end
diff --git a/spec/data/lwrp/providers/buck_passer.rb b/spec/data/lwrp/providers/buck_passer.rb
index 1f83e5098b..8d5156af81 100644
--- a/spec/data/lwrp/providers/buck_passer.rb
+++ b/spec/data/lwrp/providers/buck_passer.rb
@@ -1,3 +1,10 @@
-action :buck_stops_here do
- log "This should be overwritten by ../lwrp_override/buck_passer.rb"
+action :pass_buck do
+ lwrp_foo :prepared_thumbs do
+ action :prepare_thumbs
+ provider :lwrp_thumb_twiddler
+ end
+ lwrp_foo :twiddled_thumbs do
+ action :twiddle_thumbs
+ provider :lwrp_thumb_twiddler
+ end
end
diff --git a/spec/data/lwrp/resources/foo.rb b/spec/data/lwrp/resources/foo.rb
index c881c80530..0ee83f0cd0 100644
--- a/spec/data/lwrp/resources/foo.rb
+++ b/spec/data/lwrp/resources/foo.rb
@@ -1,3 +1,4 @@
-actions :never_execute
+actions :prepare_thumbs, :twiddle_thumbs
+default_action :pass_buck
-attribute :ever, :kind_of => String
+attribute :monkey, :kind_of => String
diff --git a/spec/data/lwrp_override/providers/buck_passer.rb b/spec/data/lwrp_override/providers/buck_passer.rb
index 75917a58c9..2061b391dc 100644
--- a/spec/data/lwrp_override/providers/buck_passer.rb
+++ b/spec/data/lwrp_override/providers/buck_passer.rb
@@ -1,10 +1,5 @@
-action :pass_buck do
- lwrp_foo :prepared_thumbs do
- action :prepare_thumbs
- provider :lwrp_thumb_twiddler
- end
- lwrp_foo :twiddled_thumbs do
- action :twiddle_thumbs
- provider :lwrp_thumb_twiddler
- end
-end \ No newline at end of file
+# Starting with Chef 12 reloading an LWRP shouldn't reload the file anymore
+
+action :buck_stops_here do
+ log "This should be overwritten by ../lwrp_override/buck_passer.rb"
+end
diff --git a/spec/data/lwrp_override/resources/foo.rb b/spec/data/lwrp_override/resources/foo.rb
index 0ee83f0cd0..14decb9634 100644
--- a/spec/data/lwrp_override/resources/foo.rb
+++ b/spec/data/lwrp_override/resources/foo.rb
@@ -1,4 +1,5 @@
-actions :prepare_thumbs, :twiddle_thumbs
-default_action :pass_buck
+# Starting with Chef 12 reloading an LWRP shouldn't reload the file anymore
-attribute :monkey, :kind_of => String
+actions :never_execute
+
+attribute :ever, :kind_of => String
diff --git a/spec/functional/assets/chefinittest b/spec/functional/assets/chefinittest
new file mode 100755
index 0000000000..79e064cd5f
--- /dev/null
+++ b/spec/functional/assets/chefinittest
@@ -0,0 +1,34 @@
+#!/bin/ksh
+
+function create_chef_txt {
+ touch /tmp/chefinittest.txt
+}
+
+function delete_chef_txt {
+ rm /tmp/chefinittest.txt
+}
+
+function rename_chef_txt {
+ mv /tmp/chefinittest.txt /tmp/$1
+}
+
+case "$1" in
+start )
+ create_chef_txt
+ ;;
+stop )
+ delete_chef_txt
+ ;;
+status )
+ [ -f /tmp/chefinittest.txt ] || [ -f /tmp/chefinittest_reload.txt ] || [ -f /tmp/chefinittest_restart.txt ]
+ ;;
+reload )
+ rename_chef_txt "chefinittest_reload.txt"
+ ;;
+restart )
+ rename_chef_txt "chefinittest_restart.txt"
+ ;;
+* )
+ echo "Usage: $0 (start | stop | restart | reload)"
+ exit 1
+esac
diff --git a/spec/functional/assets/testchefsubsys b/spec/functional/assets/testchefsubsys
new file mode 100755
index 0000000000..e9ff30d4aa
--- /dev/null
+++ b/spec/functional/assets/testchefsubsys
@@ -0,0 +1,11 @@
+#!/bin/bash
+# trapchild
+
+sleep 120 &
+
+pid="$!"
+
+trap 'echo I am going down, so killing off my processes..; kill $pid; exit' SIGHUP SIGINT
+ SIGQUIT SIGTERM
+
+wait \ No newline at end of file
diff --git a/spec/functional/event_loggers/windows_eventlog_spec.rb b/spec/functional/event_loggers/windows_eventlog_spec.rb
new file mode 100644
index 0000000000..9da9f60fa9
--- /dev/null
+++ b/spec/functional/event_loggers/windows_eventlog_spec.rb
@@ -0,0 +1,82 @@
+#
+# Author:: Jay Mundrawala (<jdm@getchef.com>)
+#
+# Copyright:: 2014, Chef Software, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+require 'securerandom'
+require 'chef/event_loggers/windows_eventlog'
+if Chef::Platform.windows?
+ require 'win32/eventlog'
+ include Win32
+end
+
+describe Chef::EventLoggers::WindowsEventLogger, :windows_only do
+ let(:run_id) { SecureRandom.uuid }
+ let(:version) { SecureRandom.uuid }
+ let(:elapsed_time) { SecureRandom.random_number(100) }
+ let(:logger) { Chef::EventLoggers::WindowsEventLogger.new }
+ let(:flags) { nil }
+ let(:node) { nil }
+ let(:run_status) { double('Run Status', {run_id: run_id, elapsed_time: elapsed_time }) }
+ let(:event_log) { EventLog.new("Application") }
+ let!(:offset) { event_log.read_last_event.record_number }
+ let(:mock_exception) { double('Exception', {message: SecureRandom.uuid, backtrace:[SecureRandom.uuid, SecureRandom.uuid]})}
+
+ it 'is available' do
+ Chef::EventLoggers::WindowsEventLogger.available?.should be_true
+ end
+
+ it 'writes run_start event with event_id 10000 and contains version' do
+ logger.run_start(version)
+
+ expect(event_log.read(flags, offset).any? { |e| e.source == 'Chef' && e.event_id == 10000 &&
+ e.string_inserts[0].include?(version)}).to be_true
+ end
+
+ it 'writes run_started event with event_id 10001 and contains the run_id' do
+ logger.run_started(run_status)
+
+ expect(event_log.read(flags, offset).any? { |e| e.source == 'Chef' && e.event_id == 10001 &&
+ e.string_inserts[0].include?(run_id)}).to be_true
+ end
+
+ it 'writes run_completed event with event_id 10002 and contains the run_id and elapsed time' do
+ logger.run_started(run_status)
+ logger.run_completed(node)
+
+ expect(event_log.read(flags, offset).any? { |e| e.source == 'Chef' && e.event_id == 10002 &&
+ e.string_inserts[0].include?(run_id) &&
+ e.string_inserts[1].include?(elapsed_time.to_s)
+ }).to be_true
+ end
+
+ it 'writes run_failed event with event_id 10003 and contains the run_id, elapsed time, and exception info' do
+ logger.run_started(run_status)
+ 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?(run_id) &&
+ e.string_inserts[1].include?(elapsed_time.to_s) &&
+ 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_true
+ end
+
+end
diff --git a/spec/functional/resource/aix_service_spec.rb b/spec/functional/resource/aix_service_spec.rb
new file mode 100755
index 0000000000..6008fdea8f
--- /dev/null
+++ b/spec/functional/resource/aix_service_spec.rb
@@ -0,0 +1,136 @@
+# encoding: UTF-8
+#
+# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+require 'functional/resource/base'
+require 'chef/mixin/shell_out'
+
+shared_examples "src service" do
+
+ include Chef::Mixin::ShellOut
+
+ def service_should_be_started
+ expect(shell_out!("lssrc -a | grep #{new_resource.service_name}").stdout.split(' ').last).to eq("active")
+ end
+
+ def service_should_be_stopped
+ expect(shell_out!("lssrc -a | grep #{new_resource.service_name}").stdout.split(' ').last).to eq("inoperative")
+ end
+
+ def get_service_pid
+ args = shell_out!("lssrc -a | grep #{new_resource.service_name}").stdout.split(' ')
+ if args.length == 3
+ args[1]
+ else
+ args[2]
+ end
+ end
+
+ describe "start service" do
+ it "should start the service" do
+ new_resource.run_action(:start)
+ service_should_be_started
+ end
+ end
+
+ describe "stop service" do
+ before do
+ new_resource.run_action(:start)
+ end
+
+ it "should stop the service" do
+ new_resource.run_action(:stop)
+ service_should_be_stopped
+ end
+ end
+
+ describe "restart service" do
+ before do
+ new_resource.run_action(:start)
+ end
+
+ it "should restart the service" do
+ new_resource.run_action(:restart)
+ service_should_be_started
+ end
+ end
+end
+
+describe Chef::Resource::Service, :requires_root, :aix_only do
+ def get_user_id
+ shell_out("id -u #{ENV['USER']}").stdout.chomp
+ end
+
+ describe "When service is a subsystem" do
+ before(:all) do
+ script_dir = File.join(File.dirname(__FILE__), "/../assets/")
+ shell_out!("mkssys -s ctestsys -p #{script_dir}/testchefsubsys -u #{get_user_id} -S -n 15 -f 9 -R -Q")
+ end
+
+ after(:each) do
+ shell_out("stopsrc -s ctestsys")
+ end
+
+ after(:all) do
+ shell_out!("rmssys -s ctestsys")
+ end
+
+
+ let(:new_resource) do
+ new_resource = Chef::Resource::Service.new("ctestsys", run_context)
+ new_resource
+ end
+
+ let(:provider) do
+ provider = new_resource.provider_for_action(new_resource.action)
+ provider
+ end
+
+ it_behaves_like "src service"
+ end
+
+
+ describe "When service is a group" do
+ before(:all) do
+ script_dir = File.join(File.dirname(__FILE__), "/../assets/")
+ shell_out!("mkssys -s ctestsys -p #{script_dir}/testchefsubsys -u #{get_user_id} -S -n 15 -f 9 -R -Q -G ctestgrp")
+ end
+
+ after(:each) do
+ shell_out("stopsrc -g ctestgrp")
+ end
+
+ after(:all) do
+ # rmssys supports only -s option.
+ shell_out!("rmssys -s ctestsys")
+ end
+
+ let(:new_resource) do
+ new_resource = Chef::Resource::Service.new("ctestgrp", run_context)
+ new_resource
+ end
+
+ let(:provider) do
+ provider = new_resource.provider_for_action(new_resource.action)
+ provider
+ end
+
+ it_behaves_like "src service"
+ end
+end
diff --git a/spec/functional/resource/aixinit_service_spec.rb b/spec/functional/resource/aixinit_service_spec.rb
new file mode 100755
index 0000000000..a99309187c
--- /dev/null
+++ b/spec/functional/resource/aixinit_service_spec.rb
@@ -0,0 +1,211 @@
+# encoding: UTF-8
+#
+# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+require 'functional/resource/base'
+require 'chef/mixin/shell_out'
+require 'fileutils'
+
+describe Chef::Resource::Service, :requires_root, :aix_only do
+
+ include Chef::Mixin::ShellOut
+
+ # Platform specific validation routines.
+ def service_should_be_started(file_name)
+ # The existance of this file indicates that the service was started.
+ expect(File.exists?("/tmp/#{file_name}")).to be_true
+ end
+
+ def service_should_be_stopped(file_name)
+ expect(File.exists?("/tmp/#{file_name}")).to be_false
+ end
+
+ def valide_symlinks(expected_output, run_level = nil, status = nil, priority = nil)
+ directory = []
+ if priority.is_a?Hash
+ priority.each do |level,o|
+ directory << "/etc/rc.d/rc#{level}.d/#{(o[0] == :start ? 'S' : 'K')}#{o[1]}#{new_resource.service_name}"
+ end
+ directory
+ else
+ directory << "/etc/rc.d/rc#{run_level}.d/#{status}#{priority}#{new_resource.service_name}"
+ end
+ expect(Dir.glob(directory)).to eq(expected_output)
+ File.delete(*directory)
+ end
+
+ def delete_test_files
+ files = Dir.glob("/tmp/chefinit[a-z_]*.txt")
+ File.delete(*files)
+ end
+
+ # Actual tests
+ let(:new_resource) do
+ new_resource = Chef::Resource::Service.new("chefinittest", run_context)
+ new_resource.provider Chef::Provider::Service::AixInit
+ new_resource.supports({:status => true, :restart => true, :reload => true})
+ new_resource
+ end
+
+ let(:provider) do
+ provider = new_resource.provider_for_action(new_resource.action)
+ provider
+ end
+
+ before(:all) do
+ File.delete("/etc/rc.d/init.d/chefinittest") if File.exists?("/etc/rc.d/init.d/chefinittest")
+ FileUtils.cp("#{File.join(File.dirname(__FILE__), "/../assets/chefinittest")}", "/etc/rc.d/init.d/chefinittest")
+ end
+
+ after(:all) do
+ File.delete("/etc/rc.d/init.d/chefinittest") if File.exists?("/etc/rc.d/init.d/chefinittest")
+ end
+
+ before(:each) do
+ delete_test_files
+ end
+
+ after(:each) do
+ delete_test_files
+ end
+
+ describe "start service" do
+ it "should start the service" do
+ new_resource.run_action(:start)
+ service_should_be_started("chefinittest.txt")
+ end
+ end
+
+ describe "stop service" do
+ before do
+ new_resource.run_action(:start)
+ end
+
+ it "should stop the service" do
+ new_resource.run_action(:stop)
+ service_should_be_stopped("chefinittest.txt")
+ end
+ end
+
+ describe "restart service" do
+ before do
+ new_resource.run_action(:start)
+ end
+
+ it "should restart the service" do
+ new_resource.run_action(:restart)
+ service_should_be_started("chefinittest_restart.txt")
+ end
+ end
+
+ describe "reload service" do
+ before do
+ new_resource.run_action(:start)
+ end
+
+ it "should reload the service" do
+ new_resource.run_action(:reload)
+ service_should_be_started("chefinittest_reload.txt")
+ end
+ end
+
+ describe "enable service" do
+
+ context "when the service doesn't set a priority" do
+ it "creates symlink with status S" do
+ new_resource.run_action(:enable)
+ valide_symlinks(["/etc/rc.d/rc2.d/Schefinittest"],2,'S')
+ end
+ end
+
+ context "when the service sets a simple priority (integer)" do
+ before do
+ new_resource.priority(75)
+ end
+
+ it "creates a symlink with status S and a priority" do
+ new_resource.run_action(:enable)
+ valide_symlinks(["/etc/rc.d/rc2.d/S75chefinittest"], 2,'S',75)
+ end
+ end
+
+ context "when the service sets complex priorities (hash)" do
+ before do
+ priority = {2 => [:start, 20], 3 => [:stop, 10]}
+ new_resource.priority(priority)
+ end
+
+ it "create symlink with status start (S) or stop (K) and a priority " do
+ new_resource.run_action(:enable)
+ valide_symlinks(["/etc/rc.d/rc2.d/S20chefinittest", "/etc/rc.d/rc3.d/K10chefinittest"], 2,'S',new_resource.priority)
+ end
+ end
+ end
+
+ describe "disable_service" do
+
+ context "when the service doesn't set a priority" do
+ before do
+ File.symlink("/etc/rc.d/init.d/chefinittest", "/etc/rc.d/rc2.d/Schefinittest")
+ end
+
+ after do
+ File.delete("/etc/rc.d/rc2.d/Schefinittest") if File.exists?("/etc/rc.d/rc2.d/chefinittest")
+ end
+
+ it "creates symlink with status K" do
+ new_resource.run_action(:disable)
+ valide_symlinks(["/etc/rc.d/rc2.d/Kchefinittest"], 2,'K')
+ end
+ end
+
+ context "when the service sets a simple priority (integer)" do
+ before do
+ new_resource.priority(75)
+ File.symlink("/etc/rc.d/init.d/chefinittest", "/etc/rc.d/rc2.d/Schefinittest")
+ end
+
+ after do
+ File.delete("/etc/rc.d/rc2.d/Schefinittest") if File.exists?("/etc/rc.d/rc2.d/chefinittest")
+ end
+
+ it "creates a symlink with status K and a priority" do
+ new_resource.run_action(:disable)
+ valide_symlinks(["/etc/rc.d/rc2.d/K25chefinittest"], 2,'K',25)
+ end
+ end
+
+ context "when the service sets complex priorities (hash)" do
+ before do
+ @priority = {2 => [:stop, 20], 3 => [:start, 10]}
+ new_resource.priority(@priority)
+ File.symlink("/etc/rc.d/init.d/chefinittest", "/etc/rc.d/rc2.d/Schefinittest")
+ end
+
+ after do
+ File.delete("/etc/rc.d/rc2.d/Schefinittest") if File.exists?("/etc/rc.d/rc2.d/chefinittest")
+ end
+
+ it "create symlink with status stop (K) and a priority " do
+ new_resource.run_action(:disable)
+ valide_symlinks(["/etc/rc.d/rc2.d/K80chefinittest"], 2,'K',80)
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/spec/functional/resource/batch_spec.rb b/spec/functional/resource/batch_spec.rb
index baa01ee5d9..39133fd40b 100644
--- a/spec/functional/resource/batch_spec.rb
+++ b/spec/functional/resource/batch_spec.rb
@@ -21,17 +21,10 @@ require 'spec_helper'
describe Chef::Resource::WindowsScript::Batch, :windows_only do
include_context Chef::Resource::WindowsScript
- let(:script_content) { "whoami" }
+ let(:output_command) { ' > ' }
- let!(:resource) do
- Chef::Resource::WindowsScript::Batch.new("Batch resource functional test", @run_context)
- end
+ let (:architecture_command) { '@echo %PROCESSOR_ARCHITECTURE%' }
+
+ it_behaves_like "a Windows script running on Windows"
- describe "when the run action is invoked on Windows" do
- it "executes the script code" do
- resource.code(script_content + " > #{script_output_path}")
- resource.returns(0)
- resource.run_action(:run)
- end
- end
end
diff --git a/spec/functional/resource/cron_spec.rb b/spec/functional/resource/cron_spec.rb
index 0a19fae0ed..287b5a1391 100644
--- a/spec/functional/resource/cron_spec.rb
+++ b/spec/functional/resource/cron_spec.rb
@@ -17,6 +17,7 @@
# limitations under the License.
#
+require 'spec_helper'
require 'functional/resource/base'
require 'chef/mixin/shell_out'
@@ -55,7 +56,12 @@ describe Chef::Resource::Cron, :requires_root, :unix_only do
let(:new_resource) do
new_resource = Chef::Resource::Cron.new("Chef functional test cron", run_context)
new_resource.user 'root'
- new_resource.minute '@hourly'
+ # @hourly is not supported on solaris
+ if ohai[:platform] == "solaris" || ohai[:platform] == "solaris2"
+ new_resource.minute "0 * * * *"
+ else
+ new_resource.minute '@hourly'
+ end
new_resource.hour ''
new_resource.day ''
new_resource.month ''
diff --git a/spec/functional/resource/dsc_script_spec.rb b/spec/functional/resource/dsc_script_spec.rb
index fa13296c02..a736949c6b 100644
--- a/spec/functional/resource/dsc_script_spec.rb
+++ b/spec/functional/resource/dsc_script_spec.rb
@@ -81,17 +81,28 @@ describe Chef::Resource::DscScript, :windows_powershell_dsc_only do
let(:test_registry_value) { 'Registration' }
let(:test_registry_data1) { 'LL927' }
let(:test_registry_data2) { 'LL928' }
- let(:dsc_code) { <<-EOH
+ let(:reg_key_name_param_name) { 'testregkeyname' }
+ let(:reg_key_value_param_name) { 'testregvaluename' }
+ let(:registry_embedded_parameters) { "$#{reg_key_name_param_name} = '#{test_registry_key}';$#{reg_key_value_param_name} = '#{test_registry_value}'"}
+ let(:dsc_reg_code) { <<-EOH
+ #{registry_embedded_parameters}
Registry "ChefRegKey"
{
- Key = '#{test_registry_key}'
- ValueName = '#{test_registry_value}'
+ Key = $#{reg_key_name_param_name}
+ ValueName = $#{reg_key_value_param_name}
ValueData = '#{test_registry_data}'
Ensure = 'Present'
}
EOH
}
+ let(:dsc_code) { dsc_reg_code }
+ let(:dsc_reg_script) { <<-EOH
+ param($testregkeyname, $testregvaluename)
+ #{dsc_reg_code}
+EOH
+ }
+
let(:dsc_user_prefix) { 'dsc' }
let(:dsc_user_suffix) { 'chefx' }
let(:dsc_user) {"#{dsc_user_prefix}_usr_#{dsc_user_suffix}" }
@@ -175,7 +186,7 @@ environment "whatsmydir"
Ensure = 'Present'
}
EOH
- }
+}
let(:dsc_config_name) {
dsc_test_resource_base.name
@@ -227,41 +238,79 @@ environment 'removethis'
EOH
removal_resource.run_action(:run)
end
- let(:dsc_code) { dsc_environment_config }
- it 'should not raise an exception if the cwd is not etc' do
- dsc_test_resource.cwd(dsc_environment_no_fail_not_etc_directory)
- expect {dsc_test_resource.run_action(:run)}.not_to raise_error
- end
- it 'should raise an exception if the cwd is etc' do
- dsc_test_resource.cwd(dsc_environment_fail_etc_directory)
- expect {dsc_test_resource.run_action(:run)}.to raise_error(Chef::Exceptions::PowershellCmdletException)
- begin
- dsc_test_resource.run_action(:run)
- rescue Chef::Exceptions::PowershellCmdletException => e
- expect(e.message).to match(exception_message_signature)
+ describe 'when the DSC configuration contains code that raises an exception if cwd has a specific value' do
+ let(:dsc_code) { dsc_environment_config }
+ it 'should not raise an exception if the cwd is not etc' do
+ dsc_test_resource.cwd(dsc_environment_no_fail_not_etc_directory)
+ expect {dsc_test_resource.run_action(:run)}.not_to raise_error
+ end
+
+ it 'should raise an exception if the cwd is etc' do
+ dsc_test_resource.cwd(dsc_environment_fail_etc_directory)
+ expect {dsc_test_resource.run_action(:run)}.to raise_error(Chef::Exceptions::PowershellCmdletException)
+ begin
+ dsc_test_resource.run_action(:run)
+ rescue Chef::Exceptions::PowershellCmdletException => e
+ expect(e.message).to match(exception_message_signature)
+ end
end
end
end
shared_examples_for 'a parameterized DSC configuration script' do
- context 'when specifying environment variables in the environment attribute' do
- let(:dsc_user_prefix_code) { dsc_user_prefix_env_code }
- let(:dsc_user_suffix_code) { dsc_user_suffix_env_code }
- it_behaves_like 'a dsc_script with configuration that uses environment variables'
+ let(:dsc_user_prefix_code) { dsc_user_prefix_env_code }
+ let(:dsc_user_suffix_code) { dsc_user_suffix_env_code }
+ it_behaves_like 'a dsc_script with configuration that uses environment variables'
+ end
+
+ shared_examples_for 'a dsc_script without configuration data that takes parameters' do
+ context 'when configuration data is not specified' do
+
+ before(:each) do
+ test_key_resource = Chef::Resource::RegistryKey.new(test_registry_key, dsc_test_run_context)
+ test_key_resource.recursive(true)
+ test_key_resource.run_action(:delete_key)
+ end
+
+ after(:each) do
+ test_key_resource = Chef::Resource::RegistryKey.new(test_registry_key, dsc_test_run_context)
+ test_key_resource.recursive(true)
+ test_key_resource.run_action(:delete_key)
+ end
+
+ let(:test_registry_data) { test_registry_data1 }
+ let(:dsc_parameterized_env_param_value) { "val" + Random::rand.to_s }
+
+ it 'should have a default value of nil for the configuration_data attribute' do
+ expect(dsc_test_resource.configuration_data).to eql(nil)
+ end
+
+ it 'should have a default value of nil for the configuration_data_path attribute' do
+ expect(dsc_test_resource.configuration_data_script).to eql(nil)
+ end
+
+ let(:dsc_test_resource) { dsc_resource_from_path }
+ let(:registry_embedded_parameters) { '' }
+ let(:dsc_code) { dsc_reg_script }
+
+ it 'should set a registry key according to parameters passed to the configuration' do
+ dsc_test_resource.configuration_name(config_name_value)
+ dsc_test_resource.flags({:"#{reg_key_name_param_name}" => test_registry_key, :"#{reg_key_value_param_name}" => test_registry_value})
+ expect(dsc_test_resource.registry_key_exists?(test_registry_key)).to eq(false)
+ dsc_test_resource.run_action(:run)
+ expect(dsc_test_resource.registry_key_exists?(test_registry_key)).to eq(true)
+ expect(dsc_test_resource.registry_value_exists?(test_registry_key, {:name => test_registry_value, :type => :string, :data => test_registry_data})).to eq(true)
+ end
end
end
shared_examples_for 'a dsc_script with configuration data' do
- context 'when using the configuration_data attribute' do
- let(:configuration_data_attribute) { 'configuration_data' }
- it_behaves_like 'a dsc_script with configuration data set via an attribute'
- end
+ let(:configuration_data_attribute) { 'configuration_data' }
+ it_behaves_like 'a dsc_script with configuration data set via an attribute'
- context 'when using the configuration_data_script attribute' do
- let(:configuration_data_attribute) { 'configuration_data_script' }
- it_behaves_like 'a dsc_script with configuration data set via an attribute'
- end
+ let(:configuration_data_attribute) { 'configuration_data_script' }
+ it_behaves_like 'a dsc_script with configuration data set via an attribute'
end
shared_examples_for 'a dsc_script with configuration data set via an attribute' do
@@ -282,33 +331,28 @@ EOH
end
shared_examples_for 'a dsc_script with configuration data that takes parameters' do
- context 'when script code takes parameters for configuration' do
- let(:dsc_user_code) { dsc_user_param_code }
- let(:config_param_section) { config_params }
- let(:config_flags) {{:"#{dsc_user_prefix_param_name}" => "#{dsc_user_prefix}", :"#{dsc_user_suffix_param_name}" => "#{dsc_user_suffix}"}}
- it 'does not directly contain the user name' do
- configuration_script_content = ::File.open(dsc_test_resource.command) do | file |
- file.read
- end
- expect(configuration_script_content.include?(dsc_user)).to be(false)
+ let(:dsc_user_code) { dsc_user_param_code }
+ let(:config_param_section) { config_params }
+ let(:config_flags) {{:"#{dsc_user_prefix_param_name}" => "#{dsc_user_prefix}", :"#{dsc_user_suffix_param_name}" => "#{dsc_user_suffix}"}}
+ it 'does not directly contain the user name' do
+ configuration_script_content = ::File.open(dsc_test_resource.command) do | file |
+ file.read
end
- it_behaves_like 'a dsc_script with configuration data'
+ expect(configuration_script_content.include?(dsc_user)).to be(false)
end
-
+ it_behaves_like 'a dsc_script with configuration data'
end
shared_examples_for 'a dsc_script with configuration data that uses environment variables' do
- context 'when script code uses environment variables' do
- let(:dsc_user_code) { dsc_user_env_code }
+ let(:dsc_user_code) { dsc_user_env_code }
- it 'does not directly contain the user name' do
- configuration_script_content = ::File.open(dsc_test_resource.command) do | file |
- file.read
- end
- expect(configuration_script_content.include?(dsc_user)).to be(false)
+ it 'does not directly contain the user name' do
+ configuration_script_content = ::File.open(dsc_test_resource.command) do | file |
+ file.read
end
- it_behaves_like 'a dsc_script with configuration data'
+ expect(configuration_script_content.include?(dsc_user)).to be(false)
end
+ it_behaves_like 'a dsc_script with configuration data'
end
context 'when supplying configuration through the configuration attribute' do
@@ -333,5 +377,6 @@ EOH
it_behaves_like 'a dsc_script with configuration data'
it_behaves_like 'a dsc_script with configuration data that uses environment variables'
it_behaves_like 'a dsc_script with configuration data that takes parameters'
+ it_behaves_like 'a dsc_script without configuration data that takes parameters'
end
end
diff --git a/spec/functional/resource/env_spec.rb b/spec/functional/resource/env_spec.rb
index 24fe5e1dff..8178eeba3d 100755
--- a/spec/functional/resource/env_spec.rb
+++ b/spec/functional/resource/env_spec.rb
@@ -22,6 +22,7 @@ describe Chef::Resource::Env, :windows_only do
context 'when running on Windows' do
let(:chef_env_test_lower_case) { 'chefenvtest' }
let(:chef_env_test_mixed_case) { 'chefENVtest' }
+ let(:env_dne_key) { 'env_dne_key' }
let(:env_value1) { 'value1' }
let(:env_value2) { 'value2' }
@@ -126,7 +127,8 @@ describe Chef::Resource::Env, :windows_only do
context 'when using PATH' do
let(:random_name) { Time.now.to_i }
let(:env_val) { "#{env_value_expandable}_#{random_name}"}
- let(:path_before) { test_resource.provider_for_action(test_resource.action).env_value('PATH') }
+ let!(:path_before) { test_resource.provider_for_action(test_resource.action).env_value('PATH') || '' }
+ let!(:env_path_before) { ENV['PATH'] }
it 'should expand PATH' do
path_before.should_not include(env_val)
@@ -142,9 +144,7 @@ describe Chef::Resource::Env, :windows_only do
test_resource.key_name('PATH')
test_resource.value(path_before)
test_resource.run_action(:create)
- if test_resource.provider_for_action(test_resource.action).env_value('PATH') != path_before
- raise 'Failed to cleanup after ourselves'
- end
+ ENV['PATH'] = env_path_before
end
end
@@ -178,6 +178,14 @@ describe Chef::Resource::Env, :windows_only do
expect(ENV[chef_env_test_lower_case]).to eq(nil)
expect(ENV[chef_env_test_mixed_case]).to eq(nil)
end
+
+ it "should delete a value from the current process even if it is not in the registry" do
+ expect(ENV[env_dne_key]).to eq(nil)
+ ENV[env_dne_key] = env_value1
+ test_resource.key_name(env_dne_key)
+ test_resource.run_action(:delete)
+ expect(ENV[env_dne_key]).to eq(nil)
+ end
end
end
end
diff --git a/spec/functional/resource/execute_spec.rb b/spec/functional/resource/execute_spec.rb
new file mode 100644
index 0000000000..ff358fe045
--- /dev/null
+++ b/spec/functional/resource/execute_spec.rb
@@ -0,0 +1,113 @@
+#
+# Author:: Serdar Sutay (<serdar@opscode.com>)
+# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+require 'functional/resource/base'
+
+describe Chef::Resource::Execute do
+ let(:execute_resource) {
+ exec_resource = Chef::Resource::Execute.new("foo_resource", run_context)
+
+ exec_resource.environment(resource_environment) if resource_environment
+ exec_resource.cwd(resource_cwd) if resource_cwd
+ exec_resource.command("echo hello")
+ if guard
+ if guard_options
+ exec_resource.only_if(guard, guard_options)
+ else
+ exec_resource.only_if(guard)
+ end
+ end
+ exec_resource
+ }
+
+ let(:resource_environment) { nil }
+ let(:resource_cwd) { nil }
+ let(:guard) { nil }
+ let(:guard_options) { nil }
+
+ describe "when guard is ruby block" do
+ it "guard can still run" do
+ execute_resource.only_if do
+ true
+ end
+ execute_resource.run_action(:run)
+ execute_resource.should be_updated_by_last_action
+ end
+ end
+
+ describe "when parent resource sets :cwd" do
+ let(:resource_cwd) { CHEF_SPEC_DATA }
+
+ let(:guard) { %{ruby -e 'exit 1 unless File.exists?("./big_json_plus_one.json")'} }
+
+ it "guard inherits :cwd from resource" do
+ execute_resource.run_action(:run)
+ execute_resource.should be_updated_by_last_action
+ end
+ end
+
+ describe "when parent resource sets :environment" do
+ let(:resource_environment) do
+ {
+ "SAWS_SECRET" => "supersecret",
+ "SAWS_KEY" => "qwerty"
+ }
+ end
+
+ # We use ruby command so that we don't need to deal with platform specific
+ # commands while testing execute resource. We set it so that the resource
+ # will be updated if the ENV variable is set to what we are intending
+ let(:guard) { %{ruby -e 'exit 1 if ENV["SAWS_SECRET"] != "supersecret"'} }
+
+ it "guard inherits :environment value from resource" do
+ execute_resource.run_action(:run)
+ execute_resource.should be_updated_by_last_action
+ end
+
+ describe "when guard sets additional values in the :environment" do
+ let(:guard) { %{ruby -e 'exit 1 if ENV["SGCE_SECRET"] != "regularsecret"'} }
+
+ let(:guard_options) do
+ {
+ :environment => { 'SGCE_SECRET' => "regularsecret" }
+ }
+ end
+
+ it "guard sees merged value for in its ENV" do
+ execute_resource.run_action(:run)
+ execute_resource.should be_updated_by_last_action
+ end
+ end
+
+ describe "when guard sets same value in the :environment" do
+ let(:guard) { %{ruby -e 'exit 1 if ENV["SAWS_SECRET"] != "regularsecret"'} }
+
+ let(:guard_options) do
+ {
+ :environment => { 'SAWS_SECRET' => "regularsecret" }
+ }
+ end
+
+ it "guard sees value from guard options in its ENV" do
+ execute_resource.run_action(:run)
+ execute_resource.should be_updated_by_last_action
+ end
+ end
+ end
+end
diff --git a/spec/functional/resource/file_spec.rb b/spec/functional/resource/file_spec.rb
index 99966f85c8..83f051ea06 100644
--- a/spec/functional/resource/file_spec.rb
+++ b/spec/functional/resource/file_spec.rb
@@ -17,6 +17,7 @@
#
require 'spec_helper'
+require 'tmpdir'
describe Chef::Resource::File do
include_context Chef::Resource::File
@@ -30,6 +31,7 @@ describe Chef::Resource::File do
run_context = Chef::RunContext.new(node, {}, events)
use_path = if opts[:use_relative_path]
+ Dir.chdir(Dir.tmpdir)
File.basename(path)
else
path
diff --git a/spec/functional/resource/powershell_spec.rb b/spec/functional/resource/powershell_spec.rb
index 96a356f441..e1e9f787a3 100644
--- a/spec/functional/resource/powershell_spec.rb
+++ b/spec/functional/resource/powershell_spec.rb
@@ -22,6 +22,12 @@ describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
include_context Chef::Resource::WindowsScript
+ let (:architecture_command) { 'echo $env:PROCESSOR_ARCHITECTURE' }
+ let (:output_command) { ' | out-file -encoding ASCII ' }
+
+ it_behaves_like "a Windows script running on Windows"
+
+
let(:successful_executable_script_content) { "#{ENV['SystemRoot']}\\system32\\attrib.exe $env:systemroot" }
let(:failed_executable_script_content) { "#{ENV['SystemRoot']}\\system32\\attrib.exe /badargument" }
let(:processor_architecture_script_content) { "echo $env:PROCESSOR_ARCHITECTURE" }
@@ -36,6 +42,7 @@ describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
let(:arbitrary_nonzero_process_exit_code_content) { "exit #{arbitrary_nonzero_process_exit_code}" }
let(:invalid_powershell_interpreter_flag) { "/thisflagisinvalid" }
let(:valid_powershell_interpreter_flag) { "-Sta" }
+
let!(:resource) do
r = Chef::Resource::WindowsScript::PowershellScript.new("Powershell resource functional test", @run_context)
r.code(successful_executable_script_content)
@@ -214,32 +221,36 @@ describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
before(:each) do
resource.not_if.clear
resource.only_if.clear
- # resource.guard_interpreter should be :default by default
end
- it "evaluates a succeeding not_if block using cmd.exe as false by default" do
- resource.not_if "exit /b 0"
- resource.should_skip?(:run).should be_true
- end
+ context "when the guard_interpreter's default value of :powershell_script is overridden to :default" do
+ before(:each) do
+ resource.guard_interpreter :default
+ end
- it "evaluates a failing not_if block using cmd.exe as true by default" do
- resource.not_if "exit /b 2"
- resource.should_skip?(:run).should be_false
- end
+ it "evaluates a succeeding not_if block using cmd.exe as false by default" do
+ resource.not_if "exit /b 0"
+ resource.should_skip?(:run).should be_true
+ end
- it "evaluates an succeeding only_if block using cmd.exe as true by default" do
- resource.only_if "exit /b 0"
- resource.should_skip?(:run).should be_false
- end
+ it "evaluates a failing not_if block using cmd.exe as true by default" do
+ resource.not_if "exit /b 2"
+ resource.should_skip?(:run).should be_false
+ end
+
+ it "evaluates an succeeding only_if block using cmd.exe as true by default" do
+ resource.only_if "exit /b 0"
+ resource.should_skip?(:run).should be_false
+ end
- it "evaluates a failing only_if block using cmd.exe as false by default" do
- resource.only_if "exit /b 2"
- resource.should_skip?(:run).should be_true
+ it "evaluates a failing only_if block using cmd.exe as false by default" do
+ resource.only_if "exit /b 2"
+ resource.should_skip?(:run).should be_true
+ end
end
context "the only_if is specified before the guard" do
before do
- # force the guard_interpreter to :default in case the default changes later
resource.guard_interpreter :default
end
@@ -251,8 +262,9 @@ describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
end
context "with powershell_script as the guard_interpreter" do
- before(:each) do
- resource.guard_interpreter :powershell_script
+
+ it "has a guard_interpreter attribute set to :powershell_script" do
+ expect(resource.guard_interpreter).to eq(:powershell_script)
end
it "evaluates a powershell $false for a not_if block as true" do
diff --git a/spec/functional/resource/rpm_spec.rb b/spec/functional/resource/rpm_spec.rb
index 7825377c6b..b37ee781f1 100644
--- a/spec/functional/resource/rpm_spec.rb
+++ b/spec/functional/resource/rpm_spec.rb
@@ -16,6 +16,7 @@
# limitations under the License.
#
+require 'spec_helper'
require 'functional/resource/base'
require 'chef/mixin/shell_out'
@@ -60,12 +61,12 @@ describe Chef::Resource::RpmPackage, :requires_root, :external => exclude_test d
@pkg_name = "dummy"
@pkg_version = "1-0"
@pkg_path = "/tmp/dummy-1-0.aix6.1.noarch.rpm"
- FileUtils.cp 'spec/functional/assets/dummy-1-0.aix6.1.noarch.rpm' , @pkg_path
+ FileUtils.cp(File.join(CHEF_SPEC_ASSETS, 'dummy-1-0.aix6.1.noarch.rpm') , @pkg_path)
when "centos", "redhat", "suse"
@pkg_name = "mytest"
@pkg_version = "1.0-1"
@pkg_path = "/tmp/mytest-1.0-1.noarch.rpm"
- FileUtils.cp 'spec/functional/assets/mytest-1.0-1.noarch.rpm' , @pkg_path
+ FileUtils.cp(File.join(CHEF_SPEC_ASSETS, 'mytest-1.0-1.noarch.rpm') , @pkg_path)
end
end
@@ -101,11 +102,11 @@ describe Chef::Resource::RpmPackage, :requires_root, :external => exclude_test d
if ohai[:platform] == 'aix'
@pkg_version = "2-0"
@pkg_path = "/tmp/dummy-2-0.aix6.1.noarch.rpm"
- FileUtils.cp 'spec/functional/assets/dummy-2-0.aix6.1.noarch.rpm' , @pkg_path
+ FileUtils.cp(File.join(CHEF_SPEC_ASSETS, 'dummy-2-0.aix6.1.noarch.rpm') , @pkg_path)
else
@pkg_version = "2.0-1"
@pkg_path = "/tmp/mytest-2.0-1.noarch.rpm"
- FileUtils.cp 'spec/functional/assets/mytest-2.0-1.noarch.rpm' , @pkg_path
+ FileUtils.cp(File.join(CHEF_SPEC_ASSETS, 'mytest-2.0-1.noarch.rpm') , @pkg_path)
end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 1760aab871..b1d7cdbd64 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -119,6 +119,7 @@ RSpec.configure do |config|
config.filter_run_excluding :solaris_only => true unless solaris?
config.filter_run_excluding :system_windows_service_gem_only => true unless system_windows_service_gem?
config.filter_run_excluding :unix_only => true unless unix?
+ config.filter_run_excluding :aix_only => true unless aix?
config.filter_run_excluding :supports_cloexec => true unless supports_cloexec?
config.filter_run_excluding :selinux_only => true unless selinux_enabled?
config.filter_run_excluding :ruby_18_only => true unless ruby_18?
@@ -133,6 +134,7 @@ RSpec.configure do |config|
config.filter_run_excluding :ruby_gte_20_and_openssl_gte_101 => true unless (ruby_gte_20? && openssl_gte_101?)
config.filter_run_excluding :openssl_lt_101 => true unless openssl_lt_101?
config.filter_run_excluding :ruby_lt_20 => true unless ruby_lt_20?
+ config.filter_run_excluding :aes_256_gcm_only => true unless aes_256_gcm?
running_platform_arch = `uname -m`.strip
@@ -162,6 +164,10 @@ RSpec.configure do |config|
config.before(:each) do
Chef::Config.reset
end
+
+ config.before(:suite) do
+ ARGV.clear
+ end
end
require 'webrick/utils'
diff --git a/spec/support/chef_helpers.rb b/spec/support/chef_helpers.rb
index f31355f50a..237543748c 100644
--- a/spec/support/chef_helpers.rb
+++ b/spec/support/chef_helpers.rb
@@ -14,6 +14,7 @@
# limitations under the License.
#
CHEF_SPEC_DATA = File.expand_path(File.dirname(__FILE__) + "/../data/")
+CHEF_SPEC_ASSETS = File.expand_path(File.dirname(__FILE__) + "/../functional/assets/")
CHEF_SPEC_BACKUP_PATH = File.join(Dir.tmpdir, 'test-backup-path')
Chef::Config[:log_level] = :fatal
diff --git a/spec/support/lib/chef/provider/snakeoil.rb b/spec/support/lib/chef/provider/snakeoil.rb
index e9d01f654f..485d37329f 100644
--- a/spec/support/lib/chef/provider/snakeoil.rb
+++ b/spec/support/lib/chef/provider/snakeoil.rb
@@ -19,6 +19,7 @@
class Chef
class Provider
class SnakeOil < Chef::Provider
+
def load_current_resource
true
end
diff --git a/spec/support/lib/chef/resource/zen_follower.rb b/spec/support/lib/chef/resource/zen_follower.rb
index 0fa0c4af5b..ddc289e48d 100644
--- a/spec/support/lib/chef/resource/zen_follower.rb
+++ b/spec/support/lib/chef/resource/zen_follower.rb
@@ -21,20 +21,14 @@ require 'chef/json_compat'
class Chef
class Resource
class ZenFollower < Chef::Resource
- attr_accessor :created_as_type
- provides :follower, :on_platforms => ["zen"]
+ provides :follower, platform: "zen"
def initialize(name, run_context=nil)
@resource_name = :zen_follower
- @created_as_type = "zen_follower"
super
end
- def to_s
- "#{created_as_type}[#{name}]"
- end
-
def master(arg=nil)
if !arg.nil?
@master = arg
diff --git a/spec/support/platform_helpers.rb b/spec/support/platform_helpers.rb
index f8cad6de7f..8d17af3993 100644
--- a/spec/support/platform_helpers.rb
+++ b/spec/support/platform_helpers.rb
@@ -165,3 +165,7 @@ end
def openssl_lt_101?
!openssl_gte_101?
end
+
+def aes_256_gcm?
+ OpenSSL::Cipher.ciphers.include?("aes-256-gcm")
+end
diff --git a/spec/support/shared/functional/windows_script.rb b/spec/support/shared/functional/windows_script.rb
index fc06fb55d0..f677828167 100644
--- a/spec/support/shared/functional/windows_script.rb
+++ b/spec/support/shared/functional/windows_script.rb
@@ -44,4 +44,122 @@ shared_context Chef::Resource::WindowsScript do
after(:each) do
File.delete(script_output_path) if File.exists?(script_output_path)
end
+
+ let!(:resource) do
+ Chef::Resource::WindowsScript::Batch.new("Batch resource functional test", @run_context)
+ end
+
+ shared_examples_for "a script resource with architecture attribute" do
+ context "with the given architecture attribute value" do
+ let(:resource_architecture) { architecture }
+ let(:expected_architecture) do
+ if architecture
+ expected_architecture = architecture
+ else
+ expected_architecture = :i386
+ end
+ end
+ let(:expected_architecture_output) do
+ expected_architecture == :i386 ? 'X86' : 'AMD64'
+ end
+ let(:guard_script_suffix) do
+ "guard"
+ end
+ let(:guard_script_output_path) do
+ "#{script_output_path}#{guard_script_suffix}"
+ end
+ let(:resource_command) do
+ "#{architecture_command} #{output_command} #{script_output_path}"
+ end
+ let(:resource_guard_command) do
+ "#{architecture_command} #{output_command} #{guard_script_output_path}"
+ end
+
+ before(:each) do
+ resource.code resource_command
+ (resource.architecture architecture) if architecture
+ resource.returns(0)
+ end
+
+ it "should create a process with the expected architecture" do
+ resource.run_action(:run)
+ get_process_architecture.should == expected_architecture_output.downcase
+ end
+
+ it "should execute guards with the same architecture as the resource" do
+ resource.only_if resource_guard_command
+ resource.run_action(:run)
+ get_process_architecture.should == expected_architecture_output.downcase
+ get_guard_process_architecture.should == expected_architecture_output.downcase
+ get_guard_process_architecture.should == get_process_architecture
+ end
+
+ let (:architecture) { :x86_64 }
+ it "should execute a 64-bit guard if the guard's architecture is specified as 64-bit" do
+ resource.only_if resource_guard_command, :architecture => :x86_64
+ resource.run_action(:run)
+ get_guard_process_architecture.should == 'amd64'
+ end
+
+ let (:architecture) { :i386 }
+ it "should execute a 32-bit guard if the guard's architecture is specified as 32-bit" do
+ resource.only_if resource_guard_command, :architecture => :i386
+ resource.run_action(:run)
+ get_guard_process_architecture.should == 'x86'
+ end
+ end
+ end
+
+ shared_examples_for "a Windows script running on Windows" do
+
+ describe "when the run action is invoked on Windows" do
+ it "executes the script code" do
+ resource.code("@whoami > #{script_output_path}")
+ resource.returns(0)
+ resource.run_action(:run)
+ end
+ end
+
+ context "when evaluating guards" do
+ it "has a guard_interpreter attribute set to the short name of the resource" do
+ resource.guard_interpreter.should == resource.resource_name
+ resource.not_if "findstr.exe /thiscommandhasnonzeroexitstatus"
+ expect(Chef::Resource).to receive(:resource_for_node).and_call_original
+ expect(resource.class).to receive(:new).and_call_original
+ resource.should_skip?(:run).should be_false
+ end
+ end
+
+ context "when the architecture attribute is not set" do
+ let(:architecture) { nil }
+ it_behaves_like "a script resource with architecture attribute"
+ end
+
+ context "when the architecture attribute is :i386" do
+ let(:architecture) { :i386 }
+ it_behaves_like "a script resource with architecture attribute"
+ end
+
+ context "when the architecture attribute is :x86_64" do
+ let(:architecture) { :x86_64 }
+ it_behaves_like "a script resource with architecture attribute"
+ end
+ end
+
+ def get_windows_script_output(suffix = '')
+ File.read("#{script_output_path}#{suffix}")
+ end
+
+ def source_contains_case_insensitive_content?( source, content )
+ source.downcase.include?(content.downcase)
+ end
+
+ def get_guard_process_architecture
+ get_process_architecture(guard_script_suffix)
+ end
+
+ def get_process_architecture(suffix = '')
+ get_windows_script_output(suffix).strip.downcase
+ end
+
end
diff --git a/spec/support/shared/unit/execute_resource.rb b/spec/support/shared/unit/execute_resource.rb
index 609e77ad63..298e0c5baf 100644
--- a/spec/support/shared/unit/execute_resource.rb
+++ b/spec/support/shared/unit/execute_resource.rb
@@ -76,11 +76,6 @@ shared_examples_for "an execute resource" do
@resource.group.should eql(1)
end
- it "should accept an array for the execution path" do
- @resource.path ["woot"]
- @resource.path.should eql(["woot"])
- end
-
it "should accept an integer for the return code" do
@resource.returns 1
@resource.returns.should eql(1)
@@ -112,7 +107,6 @@ shared_examples_for "an execute resource" do
@resource.cwd("/tmp/")
@resource.environment({ :one => :two })
@resource.group("legos")
- @resource.path(["/var/local/"])
@resource.returns(1)
@resource.user("root")
end
@@ -122,4 +116,3 @@ shared_examples_for "an execute resource" do
end
end
end
-
diff --git a/spec/support/shared/unit/resource/static_provider_resolution.rb b/spec/support/shared/unit/resource/static_provider_resolution.rb
new file mode 100644
index 0000000000..147852598a
--- /dev/null
+++ b/spec/support/shared/unit/resource/static_provider_resolution.rb
@@ -0,0 +1,71 @@
+#
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+
+
+#
+# This is for typical "static" provider resolution which maps resources onto
+# providers based only on the node data. Its not really 'static' because it
+# all goes through the Chef::ProviderResolver, but the effective result is
+# a static mapping for the node (unlike the service resource which is
+# complicated).
+#
+def static_provider_resolution(opts={})
+ action = opts[:action]
+ provider_class = opts[:provider]
+ resource_class = opts[:resource]
+ name = opts[:name]
+ os = opts[:os]
+ platform_family = opts[:platform_family]
+ platform_version = opts[:platform_version]
+
+ describe resource_class, "static provider initialization" do
+ let(:node) {
+ node = Chef::Node.new
+ node.automatic_attrs[:os] = os
+ node.automatic_attrs[:platform_family] = platform_family
+ node.automatic_attrs[:platform_version] = platform_version
+ node
+ }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:provider_resolver) { Chef::ProviderResolver.new(node) }
+ let(:run_context) {
+ run_context = Chef::RunContext.new(node, {}, events)
+ run_context.provider_resolver = provider_resolver
+ run_context
+ }
+ let(:resource) { resource_class.new("foo", run_context) }
+
+ it "should return a #{resource_class}" do
+ expect(resource).to be_a_kind_of(resource_class)
+ end
+
+ it "should set the resource_name to #{name}" do
+ expect(resource.resource_name).to eql(name)
+ end
+
+ it "should leave the provider nil" do
+ expect(resource.provider).to eql(nil)
+ end
+
+ it "should resolve to a #{provider_class}" do
+ expect(resource.provider_for_action(action)).to be_a(provider_class)
+ end
+ end
+end
+
diff --git a/spec/support/shared/unit/script_resource.rb b/spec/support/shared/unit/script_resource.rb
index 1137958420..a34f930fc8 100644
--- a/spec/support/shared/unit/script_resource.rb
+++ b/spec/support/shared/unit/script_resource.rb
@@ -72,8 +72,8 @@ shared_examples_for "a script resource" do
it "when guard_interpreter is set to the default value, the guard command string should be evaluated by command execution and not through a resource" do
Chef::Resource::Conditional.any_instance.should_not_receive(:evaluate_block)
- Chef::Resource::Conditional.any_instance.should_receive(:evaluate_command).and_return(true)
Chef::GuardInterpreter::ResourceGuardInterpreter.any_instance.should_not_receive(:evaluate_action)
+ Chef::GuardInterpreter::DefaultGuardInterpreter.any_instance.should_receive(:evaluate).and_return(true)
resource.only_if 'echo hi'
resource.should_skip?(:run).should == nil
end
diff --git a/spec/support/shared/unit/windows_script_resource.rb b/spec/support/shared/unit/windows_script_resource.rb
index 23dbfbe722..888ad600c5 100644
--- a/spec/support/shared/unit/windows_script_resource.rb
+++ b/spec/support/shared/unit/windows_script_resource.rb
@@ -39,8 +39,41 @@ shared_examples_for "a Windows script resource" do
@resource.should be_a_kind_of(Chef::Resource::WindowsScript)
end
- context "script" do
- let(:script_resource) { resource_instance }
+ context "when evaluating guards" do
+ it "should have a default_guard_interpreter attribute that is the same as the resource" do
+ @resource.default_guard_interpreter.should == @resource.resource_name
+ end
+
+ it "should default to using guard_interpreter attribute that is the same as the resource" do
+ @resource.guard_interpreter.should == @resource.resource_name
+ end
+
+ it "should use a resource to evaluate the guard when guard_interpreter is not specified" do
+ Chef::GuardInterpreter::ResourceGuardInterpreter.any_instance.should_receive(:evaluate_action).and_return(true)
+ Chef::GuardInterpreter::DefaultGuardInterpreter.any_instance.should_not_receive(:evaluate)
+ @resource.only_if 'echo hi'
+ @resource.should_skip?(:run).should == nil
+ end
+
+ describe "when the guard is given a ruby block" do
+ it "should evaluate the guard if the guard_interpreter is set to its default value" do
+ @resource.only_if { true }
+ @resource.should_skip?(:run).should == nil
+ end
+
+ it "should raise an exception if the guard_interpreter is overridden from its default value" do
+ @resource.guard_interpreter :bash
+ @resource.only_if { true }
+ expect { @resource.should_skip?(:run) }.to raise_error
+ end
+ end
+ end
+
+ context "script with a default guard interpreter" do
+ let(:script_resource) do
+ resource_instance.guard_interpreter :default
+ resource_instance
+ end
it_should_behave_like "a script resource"
end
diff --git a/spec/unit/application/apply.rb b/spec/unit/application/apply_spec.rb
index 62a53c2a31..e29c038340 100644
--- a/spec/unit/application/apply.rb
+++ b/spec/unit/application/apply_spec.rb
@@ -35,24 +35,32 @@ describe Chef::Application::Apply do
describe "read_recipe_file" do
before do
@recipe_file_name = "foo.rb"
- @recipe_path = File.expand_path("foo.rb")
+ @recipe_path = File.expand_path(@recipe_file_name)
@recipe_file = double("Tempfile (mock)", :read => @recipe_text)
@app.stub(:open).with(@recipe_path).and_return(@recipe_file)
- File.stub(:exist?).with("foo.rb").and_return(true)
+ File.stub(:exist?).with(@recipe_path).and_return(true)
Chef::Application.stub(:fatal!).and_return(true)
end
+
it "should read text properly" do
@app.read_recipe_file(@recipe_file_name)[0].should == @recipe_text
end
it "should return a file_handle" do
@app.read_recipe_file(@recipe_file_name)[1].should be_instance_of(RSpec::Mocks::Mock)
end
+
+ describe "when recipe is nil" do
+ it "should raise a fatal with the missing filename message" do
+ Chef::Application.should_receive(:fatal!).with("No recipe file was provided", 1)
+ @app.read_recipe_file(nil)
+ end
+ end
describe "when recipe doesn't exist" do
before do
- File.stub(:exist?).with(@recipe_file_name).and_return(false)
+ File.stub(:exist?).with(@recipe_path).and_return(false)
end
- it "should raise a fatal" do
- Chef::Application.should_receive(:fatal!)
+ it "should raise a fatal with the file doesn't exist message" do
+ Chef::Application.should_receive(:fatal!).with(/^No file exists at/, 1)
@app.read_recipe_file(@recipe_file_name)
end
end
diff --git a/spec/unit/client_spec.rb b/spec/unit/client_spec.rb
index e05245c413..e03773ae03 100644
--- a/spec/unit/client_spec.rb
+++ b/spec/unit/client_spec.rb
@@ -61,6 +61,7 @@ describe Chef::Client do
let(:client_opts) { {} }
let(:client) do
+ Chef::Config[:event_loggers] = []
Chef::Client.new(json_attribs, client_opts).tap do |c|
c.node = node
end
@@ -384,7 +385,6 @@ describe Chef::Client do
@events = double("Chef::EventDispatch::Dispatcher").as_null_object
Chef::EventDispatch::Dispatcher.stub(:new).and_return(@events)
-
# @events is created on Chef::Client.new, so we need to recreate it after mocking
client = Chef::Client.new
client.stub(:load_node).and_raise(Exception)
diff --git a/spec/unit/config_spec.rb b/spec/unit/config_spec.rb
index 41411669e6..cc83ca3c45 100644
--- a/spec/unit/config_spec.rb
+++ b/spec/unit/config_spec.rb
@@ -417,6 +417,95 @@ describe Chef::Config do
end
end
end
+
+ describe "Chef::Config[:internal_locale]" do
+ let(:shell_out) do
+ double("Chef::Mixin::ShellOut double", :exitstatus => 0, :stdout => locales)
+ end
+
+ let(:locales) { locale_array.join("\n") }
+
+ before do
+ allow(Chef::Config).to receive(:shell_out_with_systems_locale).with("locale -a").and_return(shell_out)
+ end
+
+ shared_examples_for "a suitable locale" do
+ it "returns an English UTF-8 locale" do
+ expect(Chef::Log).to_not receive(:warn).with(/Please install an English UTF-8 locale for Chef to use/)
+ expect(Chef::Log).to_not receive(:debug).with(/Defaulting to locale en_US.UTF-8 on Windows/)
+ expect(Chef::Log).to_not receive(:debug).with(/No usable locale -a command found/)
+ expect(Chef::Config[:internal_locale]).to eq expected_locale
+ end
+ end
+
+ context "when the result includes 'C.UTF-8'" do
+ include_examples "a suitable locale" do
+ let(:locale_array) { [expected_locale, "en_US.UTF-8"] }
+ let(:expected_locale) { "C.UTF-8" }
+ end
+ end
+
+ context "when the result includes 'en_US.UTF-8'" do
+ include_examples "a suitable locale" do
+ let(:locale_array) { ["en_CA.UTF-8", expected_locale, "en_NZ.UTF-8"] }
+ let(:expected_locale) { "en_US.UTF-8" }
+ end
+ end
+
+ context "when the result includes 'en_US.utf8'" do
+ include_examples "a suitable locale" do
+ let(:locale_array) { ["en_CA.utf8", "en_US.utf8", "en_NZ.utf8"] }
+ let(:expected_locale) { "en_US.UTF-8" }
+ end
+ end
+
+ context "when the result includes 'en.UTF-8'" do
+ include_examples "a suitable locale" do
+ let(:locale_array) { ["en.ISO8859-1", expected_locale] }
+ let(:expected_locale) { "en.UTF-8" }
+ end
+ end
+
+ context "when the result includes 'en_*.UTF-8'" do
+ include_examples "a suitable locale" do
+ let(:locale_array) { [expected_locale, "en_CA.UTF-8", "en_GB.UTF-8"] }
+ let(:expected_locale) { "en_AU.UTF-8" }
+ end
+ end
+
+ context "when the result includes 'en_*.utf8'" do
+ include_examples "a suitable locale" do
+ let(:locale_array) { ["en_AU.utf8", "en_CA.utf8", "en_GB.utf8"] }
+ let(:expected_locale) { "en_AU.UTF-8" }
+ end
+ end
+
+ context "when the result does not include 'en_*.UTF-8'" do
+ let(:locale_array) { ["af_ZA", "af_ZA.ISO8859-1", "af_ZA.ISO8859-15", "af_ZA.UTF-8"] }
+
+ it "should fall back to C locale" do
+ expect(Chef::Log).to receive(:warn).with("Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support.")
+ expect(Chef::Config[:internal_locale]).to eq 'C'
+ end
+ end
+
+ context "on error" do
+ let(:locale_array) { [] }
+
+ before do
+ allow(Chef::Config).to receive(:shell_out_with_systems_locale).and_raise("THIS IS AN ERROR")
+ end
+
+ it "should default to 'en_US.UTF-8'" do
+ if is_windows
+ expect(Chef::Log).to receive(:debug).with("Defaulting to locale en_US.UTF-8 on Windows, until it matters that we do something else.")
+ else
+ expect(Chef::Log).to receive(:debug).with("No usable locale -a command found, assuming you have en_US.UTF-8 installed.")
+ end
+ expect(Chef::Config[:internal_locale]).to eq "en_US.UTF-8"
+ end
+ end
+ end
end
end
end
diff --git a/spec/unit/cookbook/cookbook_version_loader_spec.rb b/spec/unit/cookbook/cookbook_version_loader_spec.rb
index 5772c5352d..4ba4e1de57 100644
--- a/spec/unit/cookbook/cookbook_version_loader_spec.rb
+++ b/spec/unit/cookbook/cookbook_version_loader_spec.rb
@@ -57,6 +57,11 @@ describe Chef::Cookbook::CookbookVersionLoader do
expect(loaded_cookbook.recipe_filenames).to include(full_path("/recipes/return.rb"))
end
+ it "loads libraries" do
+ expect(loaded_cookbook.library_filenames).to include(full_path('/libraries/openldap.rb'))
+ expect(loaded_cookbook.library_filenames).to include(full_path('/libraries/openldap/version.rb'))
+ end
+
it "loads static files in the files/ dir" do
expect(loaded_cookbook.file_filenames).to include(full_path("/files/default/remotedir/remotesubdir/remote_subdir_file1.txt"))
expect(loaded_cookbook.file_filenames).to include(full_path("/files/default/remotedir/remotesubdir/remote_subdir_file2.txt"))
diff --git a/spec/unit/cookbook/metadata_spec.rb b/spec/unit/cookbook/metadata_spec.rb
index 86be0d2390..51814320d4 100644
--- a/spec/unit/cookbook/metadata_spec.rb
+++ b/spec/unit/cookbook/metadata_spec.rb
@@ -29,7 +29,8 @@ describe Chef::Cookbook::Metadata do
@fields = [ :name, :description, :long_description, :maintainer,
:maintainer_email, :license, :platforms, :dependencies,
:recommendations, :suggestions, :conflicting, :providing,
- :replacing, :attributes, :groupings, :recipes, :version]
+ :replacing, :attributes, :groupings, :recipes, :version,
+ :source_url, :issues_url ]
end
it "does not depend on object identity for equality" do
@@ -140,6 +141,13 @@ describe Chef::Cookbook::Metadata do
metadata.recipes.should eq(Mash.new)
end
+ it "has an empty source_url string" do
+ metadata.source_url.should eq('')
+ end
+
+ it "has an empty issues_url string" do
+ metadata.issues_url.should eq('')
+ end
end
describe "validation" do
@@ -188,7 +196,9 @@ describe Chef::Cookbook::Metadata do
:license => "Apache v2.0",
:description => "Foobar!",
:long_description => "Much Longer\nSeriously",
- :version => "0.6.0"
+ :version => "0.6.0",
+ :source_url => "http://example.com",
+ :issues_url => "http://example.com/issues"
}
params.sort { |a,b| a.to_s <=> b.to_s }.each do |field, field_value|
describe field do
@@ -333,7 +343,9 @@ describe Chef::Cookbook::Metadata do
"type" => 'string',
"required" => 'recommended',
"recipes" => [ "mysql::server", "mysql::master" ],
- "default" => [ ]
+ "default" => [ ],
+ "source_url" => "http://example.com",
+ "issues_url" => "http://example.com/issues"
}
metadata.attribute("/db/mysql/databases", attrs).should == attrs
end
@@ -356,6 +368,24 @@ describe Chef::Cookbook::Metadata do
}.should raise_error(ArgumentError)
end
+ it "should not accept anything but a string for the source_url" do
+ lambda {
+ metadata.attribute("db/mysql/databases", :source_url => "foo")
+ }.should_not raise_error
+ lambda {
+ metadata.attribute("db/mysql/databases", :source_url => Hash.new)
+ }.should raise_error(ArgumentError)
+ end
+
+ it "should not accept anything but a string for the issues_url" do
+ lambda {
+ metadata.attribute("db/mysql/databases", :issues_url => "foo")
+ }.should_not raise_error
+ lambda {
+ metadata.attribute("db/mysql/databases", :issues_url => Hash.new)
+ }.should raise_error(ArgumentError)
+ end
+
it "should not accept anything but an array of strings for choice" do
lambda {
metadata.attribute("db/mysql/databases", :choice => ['dedicated', 'shared'])
@@ -652,6 +682,8 @@ describe Chef::Cookbook::Metadata do
attributes
recipes
version
+ source_url
+ issues_url
}.each do |t|
it "should include '#{t}'" do
deserialized_metadata[t].should == metadata.send(t.to_sym)
@@ -685,6 +717,8 @@ describe Chef::Cookbook::Metadata do
attributes
recipes
version
+ source_url
+ issues_url
}.each do |t|
it "should match '#{t}'" do
deserialized_metadata.send(t.to_sym).should == metadata.send(t.to_sym)
@@ -735,5 +769,4 @@ describe Chef::Cookbook::Metadata do
end
end
-
end
diff --git a/spec/unit/cookbook/syntax_check_spec.rb b/spec/unit/cookbook/syntax_check_spec.rb
index cd1ce96716..4d22e0e920 100644
--- a/spec/unit/cookbook/syntax_check_spec.rb
+++ b/spec/unit/cookbook/syntax_check_spec.rb
@@ -28,10 +28,12 @@ describe Chef::Cookbook::SyntaxCheck do
let(:syntax_check) { Chef::Cookbook::SyntaxCheck.new(cookbook_path) }
let(:open_ldap_cookbook_files) do
- %w{ attributes/default.rb
+ %w{ attributes/default.rb
attributes/smokey.rb
definitions/client.rb
definitions/server.rb
+ libraries/openldap.rb
+ libraries/openldap/version.rb
metadata.rb
recipes/default.rb
recipes/gigantor.rb
@@ -44,9 +46,10 @@ describe Chef::Cookbook::SyntaxCheck do
Chef::Log.level = :warn # suppress "Syntax OK" messages
@attr_files = %w{default.rb smokey.rb}.map { |f| File.join(cookbook_path, 'attributes', f) }
+ @libr_files = %w{openldap.rb openldap/version.rb}.map { |f| File.join(cookbook_path, 'libraries', f) }
@defn_files = %w{client.rb server.rb}.map { |f| File.join(cookbook_path, 'definitions', f)}
@recipes = %w{default.rb gigantor.rb one.rb return.rb}.map { |f| File.join(cookbook_path, 'recipes', f) }
- @ruby_files = @attr_files + @defn_files + @recipes + [File.join(cookbook_path, "metadata.rb")]
+ @ruby_files = @attr_files + @libr_files + @defn_files + @recipes + [File.join(cookbook_path, "metadata.rb")]
basenames = %w{ helpers_via_partial_test.erb
helper_test.erb
openldap_stuff.conf.erb
diff --git a/spec/unit/cookbook_version_spec.rb b/spec/unit/cookbook_version_spec.rb
index 25bc936569..8436e5c480 100644
--- a/spec/unit/cookbook_version_spec.rb
+++ b/spec/unit/cookbook_version_spec.rb
@@ -115,14 +115,13 @@ describe Chef::CookbookVersion do
@cookbook[:provider_filenames] = Dir[File.join(@cookbook_root, 'providers', '**', '*.rb')]
@cookbook[:root_filenames] = Array(File.join(@cookbook_root, 'README.rdoc'))
@cookbook[:metadata_filenames] = Array(File.join(@cookbook_root, 'metadata.json'))
-
end
describe "and a cookbook with the same name" do
before do
# Currently the cookbook loader finds all the files then tells CookbookVersion
# where they are.
- @cookbook_version = Chef::CookbookVersion.new("tatft", @cookbook_root)
+ @cookbook_version = Chef::CookbookVersion.new('tatft', @cookbook_root)
@cookbook_version.attribute_filenames = @cookbook[:attribute_filenames]
@cookbook_version.definition_filenames = @cookbook[:definition_filenames]
@@ -350,6 +349,84 @@ describe Chef::CookbookVersion do
readme["specificity"].should == "default"
end
end
+ end
+
+ describe 'with a cookbook directory named cookbook2 that has unscoped files' do
+ before do
+ @cookbook = Hash.new { |hash, key| hash[key] = [] }
+
+ @cookbook_root = File.join(CHEF_SPEC_DATA, 'cb_version_cookbooks', 'cookbook2')
+
+ # Dunno if the paths here are representitive of what is set by CookbookLoader...
+ @cookbook[:attribute_filenames] = Dir[File.join(@cookbook_root, 'attributes', '**', '*.rb')]
+ @cookbook[:definition_filenames] = Dir[File.join(@cookbook_root, 'definitions', '**', '*.rb')]
+ @cookbook[:file_filenames] = Dir[File.join(@cookbook_root, 'files', '**', '*.*')]
+ @cookbook[:recipe_filenames] = Dir[File.join(@cookbook_root, 'recipes', '**', '*.rb')]
+ @cookbook[:template_filenames] = Dir[File.join(@cookbook_root, 'templates', '**', '*.*')]
+ @cookbook[:library_filenames] = Dir[File.join(@cookbook_root, 'libraries', '**', '*.rb')]
+ @cookbook[:resource_filenames] = Dir[File.join(@cookbook_root, 'resources', '**', '*.rb')]
+ @cookbook[:provider_filenames] = Dir[File.join(@cookbook_root, 'providers', '**', '*.rb')]
+ @cookbook[:root_filenames] = Array(File.join(@cookbook_root, 'README.rdoc'))
+ @cookbook[:metadata_filenames] = Array(File.join(@cookbook_root, 'metadata.json'))
+
+ @cookbook_version = Chef::CookbookVersion.new('cookbook2', @cookbook_root)
+ @cookbook_version.attribute_filenames = @cookbook[:attribute_filenames]
+ @cookbook_version.definition_filenames = @cookbook[:definition_filenames]
+ @cookbook_version.recipe_filenames = @cookbook[:recipe_filenames]
+ @cookbook_version.template_filenames = @cookbook[:template_filenames]
+ @cookbook_version.file_filenames = @cookbook[:file_filenames]
+ @cookbook_version.library_filenames = @cookbook[:library_filenames]
+ @cookbook_version.resource_filenames = @cookbook[:resource_filenames]
+ @cookbook_version.provider_filenames = @cookbook[:provider_filenames]
+ @cookbook_version.root_filenames = @cookbook[:root_filenames]
+ @cookbook_version.metadata_filenames = @cookbook[:metadata_filenames]
+
+ # Used to test file-specificity related file lookups
+ @node = Chef::Node.new
+ @node.set[:platform] = "ubuntu"
+ @node.set[:platform_version] = "13.04"
+ @node.name("testing")
+ end
+
+ it "should see a template" do
+ @cookbook_version.should have_template_for_node(@node, "test.erb")
+ end
+
+ it "should see a template using an array lookup" do
+ @cookbook_version.should have_template_for_node(@node, ["test.erb"])
+ end
+
+ it "should see a template using an array lookup with non-existant elements" do
+ @cookbook_version.should have_template_for_node(@node, ["missing.txt", "test.erb"])
+ end
+
+ it "should see a file" do
+ @cookbook_version.should have_cookbook_file_for_node(@node, "test.txt")
+ end
+
+ it "should see a file using an array lookup" do
+ @cookbook_version.should have_cookbook_file_for_node(@node, ["test.txt"])
+ end
+
+ it "should see a file using an array lookup with non-existant elements" do
+ @cookbook_version.should have_cookbook_file_for_node(@node, ["missing.txt", "test.txt"])
+ end
+
+ it "should not see a non-existant template" do
+ @cookbook_version.should_not have_template_for_node(@node, "missing.erb")
+ end
+
+ it "should not see a non-existant template using an array lookup" do
+ @cookbook_version.should_not have_template_for_node(@node, ["missing.erb"])
+ end
+
+ it "should not see a non-existant file" do
+ @cookbook_version.should_not have_cookbook_file_for_node(@node, "missing.txt")
+ end
+
+ it "should not see a non-existant file using an array lookup" do
+ @cookbook_version.should_not have_cookbook_file_for_node(@node, ["missing.txt"])
+ end
end
diff --git a/spec/unit/encrypted_data_bag_item/check_encrypted_spec.rb b/spec/unit/encrypted_data_bag_item/check_encrypted_spec.rb
index 1da5efb36e..1e2b2a85e8 100644
--- a/spec/unit/encrypted_data_bag_item/check_encrypted_spec.rb
+++ b/spec/unit/encrypted_data_bag_item/check_encrypted_spec.rb
@@ -83,7 +83,7 @@ describe Chef::EncryptedDataBagItem::CheckEncrypted do
end
end
- context "when encryption version is 3", :ruby_20_only do
+ context "when encryption version is 3", :aes_256_gcm_only, :ruby_20_only do
include_examples "encryption detected" do
let(:version) { 3 }
let(:encryptor) { Chef::EncryptedDataBagItem::Encryptor::Version3Encryptor }
diff --git a/spec/unit/encrypted_data_bag_item_spec.rb b/spec/unit/encrypted_data_bag_item_spec.rb
index 9335889ef3..499fabdcf9 100644
--- a/spec/unit/encrypted_data_bag_item_spec.rb
+++ b/spec/unit/encrypted_data_bag_item_spec.rb
@@ -97,7 +97,7 @@ describe Chef::EncryptedDataBagItem::Encryptor do
Chef::Config[:data_bag_encrypt_version] = 3
end
- context "on supported platforms", :ruby_gte_20_and_openssl_gte_101 do
+ context "on supported platforms", :aes_256_gcm_only, :ruby_20_only do
it "creates a version 3 encryptor" do
encryptor.should be_a_instance_of(Chef::EncryptedDataBagItem::Encryptor::Version3Encryptor)
@@ -182,7 +182,7 @@ describe Chef::EncryptedDataBagItem::Decryptor do
context "when decrypting a version 3 (JSON+aes-256-gcm+random iv+auth tag) encrypted value" do
- context "on supported platforms", :ruby_gte_20_and_openssl_gte_101 do
+ context "on supported platforms", :aes_256_gcm_only, :ruby_20_only do
let(:encrypted_value) do
Chef::EncryptedDataBagItem::Encryptor::Version3Encryptor.new(plaintext_data, encryption_key).for_encrypted_item
diff --git a/spec/unit/knife/cookbook_site_share_spec.rb b/spec/unit/knife/cookbook_site_share_spec.rb
index ad3f32fecc..b85db98d53 100644
--- a/spec/unit/knife/cookbook_site_share_spec.rb
+++ b/spec/unit/knife/cookbook_site_share_spec.rb
@@ -25,6 +25,8 @@ describe Chef::Knife::CookbookSiteShare do
before(:each) do
@knife = Chef::Knife::CookbookSiteShare.new
+ # Merge default settings in.
+ @knife.merge_configs
@knife.name_args = ['cookbook_name', 'AwesomeSausage']
@cookbook = Chef::CookbookVersion.new('cookbook_name')
@@ -34,6 +36,9 @@ describe Chef::Knife::CookbookSiteShare do
@cookbook_loader.stub(:[]).and_return(@cookbook)
Chef::CookbookLoader.stub(:new).and_return(@cookbook_loader)
+ @noauth_rest = double(Chef::REST)
+ @knife.stub(:noauth_rest).and_return(@noauth_rest)
+
@cookbook_uploader = Chef::CookbookUploader.new('herpderp', :rest => "norest")
Chef::CookbookUploader.stub(:new).and_return(@cookbook_uploader)
@cookbook_uploader.stub(:validate_cookbooks).and_return(true)
@@ -48,6 +53,20 @@ describe Chef::Knife::CookbookSiteShare do
before(:each) do
@knife.stub(:do_upload).and_return(true)
+ @category_response = {
+ "name" => "cookbook_name",
+ "category" => "Testing Category"
+ }
+ @bad_category_response = {
+ "error_code" => "NOT_FOUND",
+ "error_messages" => [
+ "Resource does not exist."
+ ]
+ }
+ end
+
+ it 'should set true to config[:dry_run] as default' do
+ @knife.config[:dry_run].should be_false
end
it 'should should print usage and exit when given no arguments' do
@@ -57,9 +76,23 @@ describe Chef::Knife::CookbookSiteShare do
lambda { @knife.run }.should raise_error(SystemExit)
end
- it 'should print usage and exit when given only 1 argument' do
+ it 'should not fail when given only 1 argument and can determine category' do
@knife.name_args = ['cookbook_name']
- @knife.should_receive(:show_usage)
+ @noauth_rest.should_receive(:get_rest).with("http://cookbooks.opscode.com/api/v1/cookbooks/cookbook_name").and_return(@category_response)
+ @knife.should_receive(:do_upload)
+ @knife.run
+ end
+
+ it 'should print error and exit when given only 1 argument and cannot determine category' do
+ @knife.name_args = ['cookbook_name']
+ @noauth_rest.should_receive(:get_rest).with("http://cookbooks.opscode.com/api/v1/cookbooks/cookbook_name").and_return(@bad_category_response)
+ @knife.ui.should_receive(:fatal)
+ lambda { @knife.run }.should raise_error(SystemExit)
+ end
+
+ it 'should print error and exit when given only 1 argument and Chef::REST throws an exception' do
+ @knife.name_args = ['cookbook_name']
+ @noauth_rest.should_receive(:get_rest).with("http://cookbooks.opscode.com/api/v1/cookbooks/cookbook_name") { raise Errno::ECONNREFUSED, "Connection refused" }
@knife.ui.should_receive(:fatal)
lambda { @knife.run }.should raise_error(SystemExit)
end
@@ -93,6 +126,26 @@ describe Chef::Knife::CookbookSiteShare do
FileUtils.should_receive(:rm_rf)
@knife.run
end
+
+ context "when the --dry-run flag is specified" do
+ before do
+ Chef::CookbookSiteStreamingUploader.stub(:create_build_dir).and_return("/var/tmp/dummy")
+ @knife.config = { :dry_run => true }
+ @knife.stub_chain(:shell_out!, :stdout).and_return('file')
+ end
+
+ it "should list files in the tarball" do
+ expect(@knife).to receive(:shell_out!).with("tar -czf #{@cookbook.name}.tgz #{@cookbook.name}", {:cwd => "/var/tmp/dummy"})
+ expect(@knife).to receive(:shell_out!).with("tar -tzf #{@cookbook.name}.tgz", {:cwd => "/var/tmp/dummy"})
+ @knife.run
+ end
+
+ it "does not upload the cookbook" do
+ allow(@knife).to receive(:shell_out!).and_return(true)
+ expect(@knife).not_to receive(:do_upload)
+ @knife.run
+ end
+ end
end
describe 'do_upload' do
diff --git a/spec/unit/knife/core/ui_spec.rb b/spec/unit/knife/core/ui_spec.rb
index 9044bc2f2f..ed1037ebd5 100644
--- a/spec/unit/knife/core/ui_spec.rb
+++ b/spec/unit/knife/core/ui_spec.rb
@@ -403,6 +403,34 @@ EOM
@ui.format_cookbook_list_for_display(@item).should == response
end
end
+
+ context "when running on Windows" do
+ before(:each) do
+ stdout = double('StringIO', :tty? => true)
+ @ui.stub(:stdout).and_return(stdout)
+ Chef::Platform.stub(:windows?) { true }
+ Chef::Config.reset
+ end
+
+ after(:each) do
+ Chef::Config.reset
+ end
+
+ it "should have color set to true if knife config has color explicitly set to true" do
+ Chef::Config[:color] = true
+ @ui.config[:color] = true
+ expect(@ui.color?).to eql(true)
+ end
+
+ it "should have color set to false if knife config has color explicitly set to false" do
+ Chef::Config[:color] = false
+ expect(@ui.color?).to eql(false)
+ end
+
+ it "should not have color set to false by default" do
+ expect(@ui.color?).to eql(false)
+ end
+ end
end
describe "confirm" do
diff --git a/spec/unit/knife/status_spec.rb b/spec/unit/knife/status_spec.rb
index 6d8d9d5b25..bb43dd25e5 100644
--- a/spec/unit/knife/status_spec.rb
+++ b/spec/unit/knife/status_spec.rb
@@ -17,7 +17,6 @@
#
require 'spec_helper'
-require 'highline'
describe Chef::Knife::Status do
before(:each) do
@@ -30,7 +29,7 @@ describe Chef::Knife::Status do
Chef::Search::Query.stub(:new).and_return(query)
@knife = Chef::Knife::Status.new
@stdout = StringIO.new
- @knife.stub(:highline).and_return(HighLine.new(StringIO.new, @stdout))
+ @knife.ui.stub(:stdout).and_return(@stdout)
end
describe "run" do
diff --git a/spec/unit/knife_spec.rb b/spec/unit/knife_spec.rb
index 2db6b40b28..6d4763e087 100644
--- a/spec/unit/knife_spec.rb
+++ b/spec/unit/knife_spec.rb
@@ -260,8 +260,25 @@ describe Chef::Knife do
knife_command.configure_chef
knife_command.config[:opt_with_default].should == "from-cli"
end
- end
+ context "verbosity is greater than zero" do
+ let(:fake_config) { "/does/not/exist/knife.rb" }
+
+ before do
+ @knife.config[:verbosity] = 1
+ @knife.config[:config_file] = fake_config
+ config_loader = double("Chef::WorkstationConfigLoader", :load => true, :no_config_found? => false, :chef_config_dir => "/etc/chef", :config_location => fake_config)
+ allow(Chef::WorkstationConfigLoader).to receive(:new).and_return(config_loader)
+ end
+
+ it "prints the path to the configuration file used" do
+ @stdout, @stderr, @stdin = StringIO.new, StringIO.new, StringIO.new
+ @knife.ui = Chef::Knife::UI.new(@stdout, @stderr, @stdin, {})
+ expect(Chef::Log).to receive(:info).with("Using configuration from #{fake_config}")
+ @knife.configure_chef
+ end
+ end
+ end
end
describe "when first created" do
diff --git a/spec/unit/lwrp_spec.rb b/spec/unit/lwrp_spec.rb
index 960aff3c36..452e1da2a4 100644
--- a/spec/unit/lwrp_spec.rb
+++ b/spec/unit/lwrp_spec.rb
@@ -42,7 +42,8 @@ describe "LWRP" do
end
Dir[File.expand_path( "lwrp/resources/*", CHEF_SPEC_DATA)].each do |file|
- Chef::Log.should_receive(:info).with(/overriding/)
+ Chef::Log.should_receive(:info).with(/Skipping/)
+ Chef::Log.should_receive(:debug).with(/anymore/)
Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil)
end
end
@@ -53,16 +54,15 @@ describe "LWRP" do
end
Dir[File.expand_path( "lwrp/providers/*", CHEF_SPEC_DATA)].each do |file|
- Chef::Log.should_receive(:info).with(/overriding/)
+ Chef::Log.should_receive(:info).with(/Skipping/)
+ Chef::Log.should_receive(:debug).with(/anymore/)
Chef::Provider::LWRPBase.build_from_file("lwrp", file, nil)
end
end
- it "removes the old LRWP resource class from the list of resource subclasses [CHEF-3432]" do
- # CHEF-3432 regression test:
- # Chef::Resource keeps a list of all subclasses to assist class inflation
- # for json parsing (see Chef::JSONCompat). When replacing LWRP resources,
- # we need to ensure the old resource class is remove from that list.
+ it "keeps the old LRWP resource class in the list of resource subclasses" do
+ # This was originally CHEF-3432 regression test. But with Chef 12 we are
+ # not replacing the original classes anymore.
Dir[File.expand_path( "lwrp/resources/*", CHEF_SPEC_DATA)].each do |file|
Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil)
end
@@ -71,7 +71,7 @@ describe "LWRP" do
Dir[File.expand_path( "lwrp/resources/*", CHEF_SPEC_DATA)].each do |file|
Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil)
end
- Chef::Resource.resource_classes.should_not include(first_lwr_foo_class)
+ Chef::Resource.resource_classes.should include(first_lwr_foo_class)
end
it "does not attempt to remove classes from higher up namespaces [CHEF-4117]" do
@@ -231,6 +231,27 @@ describe "LWRP" do
expect(child.default_action).to eq(:dont_eat)
end
end
+
+ context "when actions are already defined" do
+ let(:child) do
+ Class.new(parent) do
+ actions :eat
+ actions :sleep
+ actions :drink
+ end
+ end
+
+ def raise_if_deprecated!
+ if Chef::VERSION.split('.').first.to_i > 12
+ raise "This test should be removed and the associated code should be removed!"
+ end
+ end
+
+ it "ammends actions when they are already defined" do
+ raise_if_deprecated!
+ expect(child.actions).to eq([:eat, :sleep, :drink])
+ end
+ end
end
end
diff --git a/spec/unit/node_map_spec.rb b/spec/unit/node_map_spec.rb
new file mode 100644
index 0000000000..fe7372961b
--- /dev/null
+++ b/spec/unit/node_map_spec.rb
@@ -0,0 +1,155 @@
+#
+# Author:: Lamont Granquist (<lamont@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+require 'chef/node_map'
+
+describe Chef::NodeMap do
+
+ let(:node_map) { Chef::NodeMap.new }
+
+ let(:node) { Chef::Node.new }
+
+ describe "with a bad filter name" do
+ it "should raise an error" do
+ expect{ node_map.set(node, :thing, on_platform_family: 'rhel') }.to raise_error
+ end
+ end
+
+ describe "when no matchers are set at all" do
+ before do
+ node_map.set(:thing, :foo)
+ end
+
+ it "returns the value" do
+ expect(node_map.get(node, :thing)).to eql(:foo)
+ end
+
+ it "returns nil for keys that do not exist" do
+ expect(node_map.get(node, :other_thing)).to eql(nil)
+ end
+ end
+
+ describe "filtering by os" do
+ before do
+ node_map.set(:thing, :foo, os: ["windows"])
+ node_map.set(:thing, :bar, os: "linux")
+ end
+ it "returns the correct value for windows" do
+ allow(node).to receive(:[]).with(:os).and_return("windows")
+ expect(node_map.get(node, :thing)).to eql(:foo)
+ end
+ it "returns the correct value for linux" do
+ allow(node).to receive(:[]).with(:os).and_return("linux")
+ expect(node_map.get(node, :thing)).to eql(:bar)
+ end
+ it "returns nil for a non-matching os" do
+ allow(node).to receive(:[]).with(:os).and_return("freebsd")
+ expect(node_map.get(node, :thing)).to eql(nil)
+ end
+ end
+
+ describe "rejecting an os" do
+ before do
+ node_map.set(:thing, :foo, os: "!windows")
+ end
+ it "returns nil for windows" do
+ allow(node).to receive(:[]).with(:os).and_return("windows")
+ expect(node_map.get(node, :thing)).to eql(nil)
+ end
+ it "returns the correct value for linux" do
+ allow(node).to receive(:[]).with(:os).and_return("linux")
+ expect(node_map.get(node, :thing)).to eql(:foo)
+ end
+ end
+
+ describe "filtering by os and platform_family" do
+ before do
+ node_map.set(:thing, :bar, os: "linux", platform_family: "rhel")
+ end
+
+ it "returns the correct value when both match" do
+ allow(node).to receive(:[]).with(:os).and_return("linux")
+ allow(node).to receive(:[]).with(:platform_family).and_return("rhel")
+ expect(node_map.get(node, :thing)).to eql(:bar)
+ end
+
+ it "returns nil for a non-matching os" do
+ allow(node).to receive(:[]).with(:os).and_return("freebsd")
+ expect(node_map.get(node, :thing)).to eql(nil)
+ end
+
+ it "returns nil when the platform_family does not match" do
+ allow(node).to receive(:[]).with(:os).and_return("linux")
+ allow(node).to receive(:[]).with(:platform_family).and_return("debian")
+ expect(node_map.get(node, :thing)).to eql(nil)
+ end
+ end
+
+ describe "with a block doing platform_version checks" do
+ before do
+ node_map.set(:thing, :foo, platform_family: "rhel") do |node|
+ node[:platform_version].to_i >= 7
+ end
+ end
+
+ it "returns the value when the node matches" do
+ allow(node).to receive(:[]).with(:platform_family).and_return("rhel")
+ allow(node).to receive(:[]).with(:platform_version).and_return("7.0")
+ expect(node_map.get(node, :thing)).to eql(:foo)
+ end
+
+ it "returns nil when the block does not match" do
+ allow(node).to receive(:[]).with(:platform_family).and_return("rhel")
+ allow(node).to receive(:[]).with(:platform_version).and_return("6.4")
+ expect(node_map.get(node, :thing)).to eql(nil)
+ end
+
+ it "returns nil when the platform_family filter does not match" do
+ allow(node).to receive(:[]).with(:platform_family).and_return("debian")
+ allow(node).to receive(:[]).with(:platform_version).and_return("7.0")
+ expect(node_map.get(node, :thing)).to eql(nil)
+ end
+
+ it "returns nil when both do not match" do
+ allow(node).to receive(:[]).with(:platform_family).and_return("debian")
+ allow(node).to receive(:[]).with(:platform_version).and_return("6.0")
+ expect(node_map.get(node, :thing)).to eql(nil)
+ end
+ end
+
+ describe "resource back-compat testing" do
+ it "should handle :on_platforms => :all" do
+ node_map.set(:chef_gem, :foo, :on_platforms => :all)
+ allow(node).to receive(:[]).with(:platform).and_return("windows")
+ expect(node_map.get(node, :chef_gem)).to eql(:foo)
+ end
+ it "should handle :on_platforms => [ 'windows' ]" do
+ node_map.set(:dsc_script, :foo, :on_platforms => [ 'windows' ])
+ allow(node).to receive(:[]).with(:platform).and_return("windows")
+ expect(node_map.get(node, :dsc_script)).to eql(:foo)
+ end
+ it "should handle :on_platform => :all" do
+ node_map.set(:link, :foo, :on_platform => :all)
+ allow(node).to receive(:[]).with(:platform).and_return("windows")
+ expect(node_map.get(node, :link)).to eql(:foo)
+ end
+ end
+
+end
+
diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb
index 00879dcb13..da7a67aec1 100644
--- a/spec/unit/node_spec.rb
+++ b/spec/unit/node_spec.rb
@@ -700,6 +700,10 @@ describe Chef::Node do
h["run_list"].should be_include("recipe[stalinist]")
h["chef_environment"].should == "dev"
end
+
+ it 'should return an empty array for empty run_list' do
+ node.to_hash["run_list"].should == []
+ end
end
describe "converting to or from json" do
diff --git a/spec/unit/platform_spec.rb b/spec/unit/platform_spec.rb
index 029fc29aae..9a65cbe878 100644
--- a/spec/unit/platform_spec.rb
+++ b/spec/unit/platform_spec.rb
@@ -278,6 +278,29 @@ describe Chef::Platform do
pmap[:package].should eql(Chef::Provider::Package::Ips)
end
+ it "should use the Redhat service provider on SLES11" do
+ 1.upto(3) do |sp|
+ pmap = Chef::Platform.find("SUSE", "11.#{sp}")
+ pmap[:service].should eql(Chef::Provider::Service::Redhat)
+ end
+ end
+
+ it "should use the Systemd service provider on SLES12" do
+ pmap = Chef::Platform.find("SUSE", "12.0")
+ pmap[:service].should eql(Chef::Provider::Service::Systemd)
+ end
+
+ it "should use the SUSE group provider on SLES11" do
+ 1.upto(3) do |sp|
+ pmap = Chef::Platform.find("SUSE", "11.#{sp}")
+ pmap[:group].should eql(Chef::Provider::Group::Suse)
+ end
+ end
+
+ it "should use the Gpasswd group provider on SLES12" do
+ pmap = Chef::Platform.find("SUSE", "12.0")
+ pmap[:group].should eql(Chef::Provider::Group::Gpasswd)
+ end
end
end
diff --git a/spec/unit/provider/cron/unix_spec.rb b/spec/unit/provider/cron/unix_spec.rb
index 60e09baceb..3d7a5675fc 100644
--- a/spec/unit/provider/cron/unix_spec.rb
+++ b/spec/unit/provider/cron/unix_spec.rb
@@ -21,26 +21,34 @@
require 'spec_helper'
describe Chef::Provider::Cron::Unix do
- before do
- @node = Chef::Node.new
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::Cron.new("cronhole some stuff")
- @new_resource.user "root"
- @new_resource.minute "30"
- @new_resource.command "/bin/true"
-
- @provider = Chef::Provider::Cron::Unix.new(@new_resource, @run_context)
+
+ subject(:provider) { Chef::Provider::Cron::Unix.new(new_resource, run_context) }
+
+ let(:username) { "root" }
+
+ let(:node) { Chef::Node.new }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
+ let(:new_resource) do
+ Chef::Resource::Cron.new("cronhole some stuff").tap do |resource|
+ resource.user username
+ resource.minute "30"
+ resource.command "/bin/true"
+ end
end
- it "should inherit from Chef::Provider:Cron" do
- @provider.should be_a(Chef::Provider::Cron)
+ let(:status) { double('Process::Status', :exitstatus => exitstatus) }
+ let(:exitstatus) { 0 }
+ let(:shell_out) { double('Mixlib::ShellOut', :status => status, :stdout => stdout, :stderr => stderr) }
+
+ it "is a Chef::Provider:Cron" do
+ expect(provider).to be_a(Chef::Provider::Cron)
end
describe "read_crontab" do
- before :each do
- @status = double("Status", :exitstatus => 0)
- @stdout = StringIO.new(<<-CRONTAB)
+ let(:stderr) { "" }
+ let(:stdout) do
+ String.new(<<-CRONTAB)
0 2 * * * /some/other/command
# Chef Name: something else
@@ -48,74 +56,84 @@ describe Chef::Provider::Cron::Unix do
# Another comment
CRONTAB
- @provider.stub(:popen4).and_yield(1234, StringIO.new, @stdout, StringIO.new).and_return(@status)
+ end
+
+ before do
+ allow(Chef::Log).to receive(:debug)
+ allow(shell_out).to receive(:format_for_exception).and_return("formatted command output")
+ allow(provider).to receive(:shell_out).with('/usr/bin/crontab -l', :user => username).and_return(shell_out)
end
it "should call crontab -l with the user" do
- @provider.should_receive(:popen4).with("crontab -l #{@new_resource.user}").and_return(@status)
- @provider.send(:read_crontab)
+ provider.send(:read_crontab)
+ expect(provider).to have_received(:shell_out).with('/usr/bin/crontab -l', :user => username)
end
it "should return the contents of the crontab" do
- crontab = @provider.send(:read_crontab)
- crontab.should == <<-CRONTAB
-0 2 * * * /some/other/command
+ crontab = provider.send(:read_crontab)
+ expect(crontab).to eq(stdout)
+ end
-# Chef Name: something else
-* 5 * * * /bin/true
+ context "when the user has no crontab" do
+ let(:exitstatus) { 1 }
-# Another comment
-CRONTAB
- end
+ it "should return nil if the user has no crontab" do
+ expect(provider.send(:read_crontab)).to be_nil
+ end
- it "should return nil if the user has no crontab" do
- status = double("Status", :exitstatus => 1)
- @provider.stub(:popen4).and_return(status)
- @provider.send(:read_crontab).should == nil
+ it "logs the crontab output to debug" do
+ provider.send(:read_crontab)
+ expect(Chef::Log).to have_received(:debug).with("formatted command output")
+ end
end
- it "should raise an exception if another error occurs" do
- status = double("Status", :exitstatus => 2)
- @provider.stub(:popen4).and_return(status)
- lambda do
- @provider.send(:read_crontab)
- end.should raise_error(Chef::Exceptions::Cron, "Error determining state of #{@new_resource.name}, exit: 2")
+ context "when any other error occurs" do
+ let (:exitstatus) { 2 }
+
+ it "should raise an exception if another error occurs" do
+ expect {
+ provider.send(:read_crontab)
+ }.to raise_error(Chef::Exceptions::Cron, "Error determining state of #{new_resource.name}, exit: 2")
+ end
+
+ it "logs the crontab output to debug" do
+ provider.send(:read_crontab) rescue nil
+ expect(Chef::Log).to have_received(:debug).with("formatted command output")
+ end
end
end
describe "write_crontab" do
- before :each do
- @status = double("Status", :exitstatus => 0)
- @provider.stub(:run_command_and_return_stdout_stderr).and_return(@status, String.new, String.new)
- @tempfile = double("foo", :path => "/tmp/foo", :close => true)
- Tempfile.stub(:new).and_return(@tempfile)
- @tempfile.should_receive(:flush)
- @tempfile.should_receive(:chmod).with(420)
- @tempfile.should_receive(:close!)
+ let(:stdout) { "" }
+ let(:stderr) { "" }
+ let(:tempfile) { double("foo", :path => "/tmp/foo", :close => true) }
+
+ before do
+ expect(Tempfile).to receive(:new).and_return(tempfile)
+ expect(tempfile).to receive(:flush)
+ expect(tempfile).to receive(:chmod).with(420)
+ expect(tempfile).to receive(:close!)
+ allow(tempfile).to receive(:<<)
+ allow(provider).to receive(:shell_out).with("/usr/bin/crontab #{tempfile.path}", :user => username).and_return(shell_out)
end
it "should call crontab for the user" do
- @provider.should_receive(:run_command_and_return_stdout_stderr).with(hash_including(:user => @new_resource.user))
- @tempfile.should_receive(:<<).with("Foo")
- @provider.send(:write_crontab, "Foo")
+ provider.send(:write_crontab, "Foo")
+ expect(provider).to have_received(:shell_out).with("/usr/bin/crontab #{tempfile.path}", :user => username)
end
it "should call crontab with a file containing the crontab" do
- @provider.should_receive(:run_command_and_return_stdout_stderr) do |args|
- (args[:command] =~ %r{\A/usr/bin/crontab (/\S+)\z}).should be_true
- $1.should == "/tmp/foo"
- @status
- end
- @tempfile.should_receive(:<<).with("Foo\n# wibble\n wah!!")
- @provider.send(:write_crontab, "Foo\n# wibble\n wah!!")
+ provider.send(:write_crontab, "Foo\n# wibble\n wah!!")
+ expect(tempfile).to have_received(:<<).with("Foo\n# wibble\n wah!!")
end
- it "should raise an exception if the command returns non-zero" do
- @tempfile.should_receive(:<<).with("Foo")
- @status.stub(:exitstatus).and_return(1)
- lambda do
- @provider.send(:write_crontab, "Foo")
- end.should raise_error(Chef::Exceptions::Cron, /Error updating state of #{@new_resource.name}, exit: 1/)
+ context "when writing the crontab fails" do
+ let(:exitstatus) { 1 }
+ it "should raise an exception if the command returns non-zero" do
+ expect {
+ provider.send(:write_crontab, "Foo")
+ }.to raise_error(Chef::Exceptions::Cron, /Error updating state of #{new_resource.name}, exit: 1/)
+ end
end
end
end
diff --git a/spec/unit/provider/env/windows_spec.rb b/spec/unit/provider/env/windows_spec.rb
index 2ea137c1d9..84582d8b4d 100644
--- a/spec/unit/provider/env/windows_spec.rb
+++ b/spec/unit/provider/env/windows_spec.rb
@@ -53,7 +53,7 @@ describe Chef::Provider::Env::Windows, :windows_only do
end
it "should update the ruby ENV object when it updates the value" do
- provider.should_receive(:compare_value).and_return(true)
+ provider.should_receive(:requires_modify_or_create?).and_return(true)
new_resource.value("foobar")
provider.action_modify
expect(ENV['CHEF_WINDOWS_ENV_TEST']).to eql('foobar')
@@ -92,7 +92,7 @@ describe Chef::Provider::Env::Windows, :windows_only do
end
it "replaces Windows system variables" do
- provider.should_receive(:compare_value).and_return(true)
+ provider.should_receive(:requires_modify_or_create?).and_return(true)
provider.should_receive(:expand_path).with(system_root).and_return(system_root_value)
provider.action_modify
expect(ENV['PATH']).to eql(system_root_value)
diff --git a/spec/unit/provider/env_spec.rb b/spec/unit/provider/env_spec.rb
index dc6176d45c..f8803f9bb6 100644
--- a/spec/unit/provider/env_spec.rb
+++ b/spec/unit/provider/env_spec.rb
@@ -88,20 +88,20 @@ describe Chef::Provider::Env do
it "should check to see if the values are the same if the key exists" do
@provider.key_exists = true
- @provider.should_receive(:compare_value).and_return(false)
+ @provider.should_receive(:requires_modify_or_create?).and_return(false)
@provider.action_create
end
it "should call modify_env if the key exists and values are not equal" do
@provider.key_exists = true
- @provider.stub(:compare_value).and_return(true)
+ @provider.stub(:requires_modify_or_create?).and_return(true)
@provider.should_receive(:modify_env).and_return(true)
@provider.action_create
end
it "should set the new_resources updated flag when it updates an existing value" do
@provider.key_exists = true
- @provider.stub(:compare_value).and_return(true)
+ @provider.stub(:requires_modify_or_create?).and_return(true)
@provider.stub(:modify_env).and_return(true)
@provider.action_create
@new_resource.should be_updated
@@ -147,20 +147,20 @@ describe Chef::Provider::Env do
end
it "should call modify_group if the key exists and values are not equal" do
- @provider.should_receive(:compare_value).and_return(true)
+ @provider.should_receive(:requires_modify_or_create?).and_return(true)
@provider.should_receive(:modify_env).and_return(true)
@provider.action_modify
end
it "should set the new resources updated flag to true if modify_env is called" do
- @provider.stub(:compare_value).and_return(true)
+ @provider.stub(:requires_modify_or_create?).and_return(true)
@provider.stub(:modify_env).and_return(true)
@provider.action_modify
@new_resource.should be_updated
end
it "should not call modify_env if the key exists but the values are equal" do
- @provider.should_receive(:compare_value).and_return(false)
+ @provider.should_receive(:requires_modify_or_create?).and_return(false)
@provider.should_not_receive(:modify_env)
@provider.action_modify
end
@@ -198,9 +198,31 @@ describe Chef::Provider::Env do
@provider.delete_element.should eql(true)
@new_resource.should be_updated
end
+
+ context "when new_resource's value contains the delimiter" do
+ it "should return false if all the elements are deleted" do
+ # This indicates that the entire key needs to be deleted
+ @new_resource.value("C:/foo/bin;C:/bar/bin")
+ @provider.delete_element.should eql(false)
+ @new_resource.should_not be_updated # This will be updated in action_delete
+ end
+
+ it "should return true if any, but not all, of the elements are deleted" do
+ @new_resource.value("C:/foo/bin;C:/notbaz/bin")
+ @provider.should_receive(:create_env)
+ @provider.delete_element.should eql(true)
+ @new_resource.should be_updated
+ end
+
+ it "should return true if none of the elements are deleted" do
+ @new_resource.value("C:/notfoo/bin;C:/notbaz/bin")
+ @provider.delete_element.should eql(true)
+ @new_resource.should_not be_updated
+ end
+ end
end
- describe "compare_value" do
+ describe "requires_modify_or_create?" do
before(:each) do
@new_resource.value("C:/bar")
@current_resource = @new_resource.clone
@@ -208,25 +230,41 @@ describe Chef::Provider::Env do
end
it "should return false if the values are equal" do
- @provider.compare_value.should be_false
+ @provider.requires_modify_or_create?.should be_false
end
it "should return true if the values not are equal" do
@new_resource.value("C:/elsewhere")
- @provider.compare_value.should be_true
+ @provider.requires_modify_or_create?.should be_true
end
it "should return false if the current value contains the element" do
@new_resource.delim(";")
@current_resource.value("C:/bar;C:/foo;C:/baz")
- @provider.compare_value.should be_false
+ @provider.requires_modify_or_create?.should be_false
end
it "should return true if the current value does not contain the element" do
@new_resource.delim(";")
@current_resource.value("C:/biz;C:/foo/bin;C:/baz")
- @provider.compare_value.should be_true
+ @provider.requires_modify_or_create?.should be_true
+ end
+
+ context "when new_resource's value contains the delimiter" do
+ it "should return false if all the current values are contained" do
+ @new_resource.value("C:/biz;C:/baz")
+ @new_resource.delim(";")
+ @current_resource.value("C:/biz;C:/foo/bin;C:/baz")
+ @provider.requires_modify_or_create?.should be_false
+ end
+
+ it "should return true if any of the new values are not contained" do
+ @new_resource.value("C:/biz;C:/baz;C:/bin")
+ @new_resource.delim(";")
+ @current_resource.value("C:/biz;C:/foo/bin;C:/baz")
+ @provider.requires_modify_or_create?.should be_true
+ end
end
end
@@ -247,5 +285,13 @@ describe Chef::Provider::Env do
@provider.modify_env
passed_value.should == new_value
end
+
+ it "should only add values not already contained when a delimiter is provided" do
+ @new_resource.value("C:/foo;C:/bar;C:/baz")
+ @new_resource.delim(";")
+ @current_resource.value("C:/foo/bar;C:/bar;C:/baz")
+ @provider.modify_env
+ @new_resource.value.should eq("C:/foo;C:/foo/bar;C:/bar;C:/baz")
+ end
end
end
diff --git a/spec/unit/provider/execute_spec.rb b/spec/unit/provider/execute_spec.rb
index 78216a89fa..6aa48f1e2a 100644
--- a/spec/unit/provider/execute_spec.rb
+++ b/spec/unit/provider/execute_spec.rb
@@ -36,22 +36,38 @@ describe Chef::Provider::Execute do
STDOUT.stub(:tty?).and_return(true)
end
+ let(:opts) do
+ {
+ timeout: @new_resource.timeout,
+ returns: @new_resource.returns,
+ log_level: :info,
+ log_tag: @new_resource.to_s,
+ live_stream: STDOUT
+ }
+ end
it "should execute foo_resource" do
@provider.stub(:load_current_resource)
- opts = {}
- opts[:timeout] = @new_resource.timeout
- opts[:returns] = @new_resource.returns
- opts[:log_level] = :info
- opts[:log_tag] = @new_resource.to_s
- opts[:live_stream] = STDOUT
@provider.should_receive(:shell_out!).with(@new_resource.command, opts)
+ @provider.should_receive(:converge_by).with("execute foo_resource").and_call_original
Chef::Log.should_not_receive(:warn)
@provider.run_action(:run)
@new_resource.should be_updated
end
+ it "should honor sensitive attribute" do
+ @new_resource.sensitive true
+ @provider = Chef::Provider::Execute.new(@new_resource, @run_context)
+ @provider.stub(:load_current_resource)
+ # Since the resource is sensitive, it should not have :live_stream set
+ @provider.should_receive(:shell_out!).with(@new_resource.command, opts.reject { |k| k == :live_stream })
+ Chef::Log.should_not_receive(:warn)
+ @provider.should_receive(:converge_by).with("execute sensitive resource").and_call_original
+ @provider.run_action(:run)
+ @new_resource.should be_updated
+ end
+
it "should do nothing if the sentinel file exists" do
@provider.stub(:load_current_resource)
File.should_receive(:exists?).with(@new_resource.creates).and_return(true)
diff --git a/spec/unit/provider/git_spec.rb b/spec/unit/provider/git_spec.rb
index ff1c0b0398..02d155efbd 100644
--- a/spec/unit/provider/git_spec.rb
+++ b/spec/unit/provider/git_spec.rb
@@ -106,6 +106,52 @@ describe Chef::Provider::Git do
@provider.target_revision.should eql("663c22a5e41f5ae3193460cca044ed1435029f53")
end
+ it "converts resource.revision from a tag to a SHA using an exact match" do
+ @resource.revision "v1.0"
+ @stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
+ "663c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/releases/v1.0\n" +
+ "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/v1.0\n")
+ @provider.should_receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+ @provider.target_revision.should eql("503c22a5e41f5ae3193460cca044ed1435029f53")
+ end
+
+ it "converts resource.revision from a tag to a SHA, matching tags first, then heads" do
+ @resource.revision "v1.0"
+ @stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
+ "663c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/v1.0\n" +
+ "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n")
+ @provider.should_receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+ @provider.target_revision.should eql("663c22a5e41f5ae3193460cca044ed1435029f53")
+ end
+
+ it "converts resource.revision from a tag to a SHA, matching heads if no tags match" do
+ @resource.revision "v1.0"
+ @stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
+ "663c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/v1.1\n" +
+ "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n")
+ @provider.should_receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+ @provider.target_revision.should eql("503c22a5e41f5ae3193460cca044ed1435029f53")
+ end
+
+ it "converts resource.revision from a tag to a SHA, matching tags first, then heads, then revision" do
+ @resource.revision "refs/pulls/v1.0"
+ @stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
+ "663c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/v1.0\n" +
+ "805c22a5e41f5ae3193460cca044ed1435029f53\trefs/pulls/v1.0\n" +
+ "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n")
+ @provider.should_receive(:shell_out!).with(@git_ls_remote + "\"refs/pulls/v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+ @provider.target_revision.should eql("805c22a5e41f5ae3193460cca044ed1435029f53")
+ end
+
+ it "converts resource.revision from a tag to a SHA, using full path if provided" do
+ @resource.revision "refs/heads/v1.0"
+ @stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
+ "663c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/v1.0\n" +
+ "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n")
+ @provider.should_receive(:shell_out!).with(@git_ls_remote + "\"refs/heads/v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+ @provider.target_revision.should eql("503c22a5e41f5ae3193460cca044ed1435029f53")
+ end
+
it "raises an invalid remote reference error if you try to deploy from ``origin'' and assertions are run" do
@resource.revision "origin/"
@provider.action = :checkout
diff --git a/spec/unit/provider/log_spec.rb b/spec/unit/provider/log_spec.rb
index a270ee4822..1ecc633ce1 100644
--- a/spec/unit/provider/log_spec.rb
+++ b/spec/unit/provider/log_spec.rb
@@ -32,10 +32,6 @@ describe Chef::Provider::Log::ChefLog do
let(:provider) { Chef::Provider::Log::ChefLog.new(new_resource, run_context) }
- it "should be registered with the default platform hash" do
- expect(Chef::Platform.platforms[:default][:log]).not_to be_nil
- end
-
it "should write the string to the Chef::Log object at default level (info)" do
expect(Chef::Log).to receive(:info).with(log_str).and_return(true)
provider.run_action(:write)
diff --git a/spec/unit/provider/mount/mount_spec.rb b/spec/unit/provider/mount/mount_spec.rb
index d6f71bc613..abab7640c0 100644
--- a/spec/unit/provider/mount/mount_spec.rb
+++ b/spec/unit/provider/mount/mount_spec.rb
@@ -107,16 +107,12 @@ describe Chef::Provider::Mount::Mount do
lambda { @provider.load_current_resource();@provider.mountable? }.should raise_error(Chef::Exceptions::Mount)
end
- it "does not expect the device to exist for tmpfs" do
- @new_resource.fstype("tmpfs")
- @new_resource.device("whatever")
- lambda { @provider.load_current_resource();@provider.mountable? }.should_not raise_error
- end
-
- it "does not expect the device to exist for Fuse filesystems" do
- @new_resource.fstype("fuse")
- @new_resource.device("nilfs#xxx")
- lambda { @provider.load_current_resource();@provider.mountable? }.should_not raise_error
+ [ "tmpfs", "fuse", "cgroup" ].each do |fstype|
+ it "does not expect the device to exist for #{fstype}" do
+ @new_resource.fstype(fstype)
+ @new_resource.device("whatever")
+ lambda { @provider.load_current_resource();@provider.mountable? }.should_not raise_error
+ end
end
it "does not expect the device to exist if it's none" do
diff --git a/spec/unit/provider/package/apt_spec.rb b/spec/unit/provider/package/apt_spec.rb
index a94b248418..90e9dd6d3f 100644
--- a/spec/unit/provider/package/apt_spec.rb
+++ b/spec/unit/provider/package/apt_spec.rb
@@ -229,7 +229,7 @@ SHOWPKG_STDOUT
@new_resource = nil
@new_resource = Chef::Resource::AptPackage.new("irssi", @run_context)
@new_resource.default_release("lenny-backports")
-
+ @new_resource.provider = @provider
@provider.new_resource = @new_resource
@provider.should_receive(:shell_out!).with(
diff --git a/spec/unit/provider/package/freebsd/port_spec.rb b/spec/unit/provider/package/freebsd/port_spec.rb
index e946719451..8725e5440f 100644
--- a/spec/unit/provider/package/freebsd/port_spec.rb
+++ b/spec/unit/provider/package/freebsd/port_spec.rb
@@ -26,7 +26,7 @@ describe Chef::Provider::Package::Freebsd::Port do
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::Package.new("zsh")
+ @new_resource = Chef::Resource::FreebsdPackage.new("zsh", @run_context)
@provider = Chef::Provider::Package::Freebsd::Port.new(@new_resource, @run_context)
end
@@ -66,24 +66,34 @@ describe Chef::Provider::Package::Freebsd::Port do
describe "determining current installed version" do
before(:each) do
- @provider.stub(:supports_pkgng?)
@pkg_info = OpenStruct.new(:stdout => "zsh-3.1.7\n")
end
it "should check 'pkg_info' if system uses pkg_* tools" do
- @provider.should_receive(:supports_pkgng?).and_return(false)
+ @new_resource.stub(:supports_pkgng?)
+ @new_resource.should_receive(:supports_pkgng?).and_return(false)
@provider.should_receive(:shell_out!).with('pkg_info -E "zsh*"', :env => nil, :returns => [0,1]).and_return(@pkg_info)
@provider.current_installed_version.should == "3.1.7"
end
- it "should check 'pkg info' if system uses pkgng" do
- @provider.should_receive(:supports_pkgng?).and_return(true)
+ it "should check 'pkg info' if make supports WITH_PKGNG if freebsd version is < 1000017" do
+ pkg_enabled = OpenStruct.new(:stdout => "yes\n")
+ [1000016, 1000000, 901503, 902506, 802511].each do |__freebsd_version|
+ @node.automatic_attrs[:os_version] = __freebsd_version
+ @new_resource.should_receive(:shell_out!).with('make -V WITH_PKGNG', :env => nil).and_return(pkg_enabled)
+ @provider.should_receive(:shell_out!).with('pkg info "zsh"', :env => nil, :returns => [0,70]).and_return(@pkg_info)
+ @provider.current_installed_version.should == "3.1.7"
+ end
+ end
+
+ it "should check 'pkg info' if the freebsd version is greater than or equal to 1000017" do
+ __freebsd_version = 1000017
+ @node.automatic_attrs[:os_version] = __freebsd_version
@provider.should_receive(:shell_out!).with('pkg info "zsh"', :env => nil, :returns => [0,70]).and_return(@pkg_info)
@provider.current_installed_version.should == "3.1.7"
end
end
-
describe "determining candidate version" do
before(:each) do
@port_version = OpenStruct.new(:stdout => "5.0.5\n", :exitstatus => 0)
diff --git a/spec/unit/provider/package/homebrew_spec.rb b/spec/unit/provider/package/homebrew_spec.rb
index d38458546d..dccd8edf11 100644
--- a/spec/unit/provider/package/homebrew_spec.rb
+++ b/spec/unit/provider/package/homebrew_spec.rb
@@ -158,6 +158,15 @@ describe Chef::Provider::Package::Homebrew do
allow(provider).to receive(:shell_out!).and_return(OpenStruct.new(:stdout => 'homestarrunner'))
expect(provider.brew('info', 'opts', 'bananas')).to eql('homestarrunner')
end
+
+ context "when new_resource is Package" do
+ let(:new_resource) { Chef::Resource::Package.new('emacs') }
+
+ it "does not try to read homebrew_user from Package, which does not have it" do
+ allow(provider).to receive(:shell_out!).and_return(OpenStruct.new(:stdout => 'zombo'))
+ expect(provider.brew).to eql('zombo')
+ end
+ end
end
context 'when testing actions' do
diff --git a/spec/unit/provider/package/pacman_spec.rb b/spec/unit/provider/package/pacman_spec.rb
index 0c1c487980..ed10513350 100644
--- a/spec/unit/provider/package/pacman_spec.rb
+++ b/spec/unit/provider/package/pacman_spec.rb
@@ -94,10 +94,7 @@ PACMAN
end
it "should set the candidate version if pacman has one" do
- @stdout.stub(:each).and_yield("core/nano 2.2.3-1 (base)").
- and_yield(" Pico editor clone with enhancements").
- and_yield("community/nanoblogger 3.4.1-1").
- and_yield(" NanoBlogger is a small weblog engine written in Bash for the command line")
+ @stdout.stub(:each).and_yield("core nano 2.2.3-1")
@provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
@provider.load_current_resource
@provider.candidate_version.should eql("2.2.3-1")
@@ -124,8 +121,7 @@ PACMAN_CONF
::File.stub(:exists?).with("/etc/pacman.conf").and_return(true)
::File.stub(:read).with("/etc/pacman.conf").and_return(@pacman_conf)
- @stdout.stub(:each).and_yield("customrepo/nano 1.2.3-4").
- and_yield(" My custom package")
+ @stdout.stub(:each).and_yield("customrepo nano 1.2.3-4")
@provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
@provider.load_current_resource
diff --git a/spec/unit/provider/package/paludis_spec.rb b/spec/unit/provider/package/paludis_spec.rb
index c99600e535..8387bb1252 100644
--- a/spec/unit/provider/package/paludis_spec.rb
+++ b/spec/unit/provider/package/paludis_spec.rb
@@ -59,7 +59,7 @@ PKG_STATUS
end
it "should run pkg info with the package name" do
- @provider.should_receive(:shell_out!).with("cave -L warning print-ids -M none -m \"*/#{@new_resource.package_name.split('/').last}\" -f \"%c/%p %v %r\n\"").and_return(@shell_out)
+ @provider.should_receive(:shell_out!).with("cave -L warning print-ids -M none -m \"#{@new_resource.package_name}\" -f \"%c/%p %v %r\n\"").and_return(@shell_out)
@provider.load_current_resource
end
diff --git a/spec/unit/provider/package/rubygems_spec.rb b/spec/unit/provider/package/rubygems_spec.rb
index d3cb9cf7fa..f4d0cebf62 100644
--- a/spec/unit/provider/package/rubygems_spec.rb
+++ b/spec/unit/provider/package/rubygems_spec.rb
@@ -359,10 +359,12 @@ RBX_GEM_ENV
end
describe Chef::Provider::Package::Rubygems do
+ let(:target_version) { nil }
+
before(:each) do
@node = Chef::Node.new
@new_resource = Chef::Resource::GemPackage.new("rspec-core")
- @spec_version = @new_resource.version RSpec::Core::Version::STRING
+ @spec_version = @new_resource.version(target_version)
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
@@ -371,269 +373,281 @@ describe Chef::Provider::Package::Rubygems do
@provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
end
- it "triggers a gem configuration load so a later one will not stomp its config values" do
- # ugly, is there a better way?
- Gem.instance_variable_get(:@configuration).should_not be_nil
- end
+ describe "when new_resource version is nil" do
+ let(:target_version) { nil }
- it "uses the CurrentGemEnvironment implementation when no gem_binary_path is provided" do
- @provider.gem_env.should be_a_kind_of(Chef::Provider::Package::Rubygems::CurrentGemEnvironment)
+ it "target_version_already_installed? should return false so that we can search for candidates" do
+ @provider.load_current_resource
+ @provider.target_version_already_installed?.should be_false
+ end
end
- it "uses the AlternateGemEnvironment implementation when a gem_binary_path is provided" do
- @new_resource.gem_binary('/usr/weird/bin/gem')
- provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
- provider.gem_env.gem_binary_location.should == '/usr/weird/bin/gem'
- end
+ describe "when new_resource version is current rspec version" do
+ let(:target_version) { RSpec::Core::Version::STRING }
- it "searches for a gem binary when running on Omnibus on Unix" do
- platform_mock :unix do
- RbConfig::CONFIG.stub(:[]).with('bindir').and_return("/opt/chef/embedded/bin")
- ENV.stub(:[]).with('PATH').and_return("/usr/bin:/usr/sbin:/opt/chef/embedded/bin")
- File.stub(:exists?).with('/usr/bin/gem').and_return(false)
- File.stub(:exists?).with('/usr/sbin/gem').and_return(true)
- File.stub(:exists?).with('/opt/chef/embedded/bin/gem').and_return(true) # should not get here
- provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
- provider.gem_env.gem_binary_location.should == '/usr/sbin/gem'
+ it "triggers a gem configuration load so a later one will not stomp its config values" do
+ # ugly, is there a better way?
+ Gem.instance_variable_get(:@configuration).should_not be_nil
end
- end
- it "searches for a gem binary when running on Omnibus on Windows" do
- platform_mock :windows do
- RbConfig::CONFIG.stub(:[]).with('bindir').and_return("d:/opscode/chef/embedded/bin")
- ENV.stub(:[]).with('PATH').and_return('C:\windows\system32;C:\windows;C:\Ruby186\bin;d:\opscode\chef\embedded\bin')
- File.stub(:exists?).with('C:\\windows\\system32\\gem').and_return(false)
- File.stub(:exists?).with('C:\\windows\\gem').and_return(false)
- File.stub(:exists?).with('C:\\Ruby186\\bin\\gem').and_return(true)
- File.stub(:exists?).with('d:\\opscode\\chef\\bin\\gem').and_return(false) # should not get here
- File.stub(:exists?).with('d:\\opscode\\chef\\embedded\\bin\\gem').and_return(false) # should not get here
- provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
- provider.gem_env.gem_binary_location.should == 'C:\Ruby186\bin\gem'
+ it "uses the CurrentGemEnvironment implementation when no gem_binary_path is provided" do
+ @provider.gem_env.should be_a_kind_of(Chef::Provider::Package::Rubygems::CurrentGemEnvironment)
end
- end
-
- it "smites you when you try to use a hash of install options with an explicit gem binary" do
- @new_resource.gem_binary('/foo/bar')
- @new_resource.options(:fail => :burger)
- lambda {Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)}.should raise_error(ArgumentError)
- end
- it "converts the new resource into a gem dependency" do
- @provider.gem_dependency.should == Gem::Dependency.new('rspec-core', @spec_version)
- @new_resource.version('~> 1.2.0')
- @provider.gem_dependency.should == Gem::Dependency.new('rspec-core', '~> 1.2.0')
- end
+ it "uses the AlternateGemEnvironment implementation when a gem_binary_path is provided" do
+ @new_resource.gem_binary('/usr/weird/bin/gem')
+ provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
+ provider.gem_env.gem_binary_location.should == '/usr/weird/bin/gem'
+ end
- describe "when determining the currently installed version" do
+ it "searches for a gem binary when running on Omnibus on Unix" do
+ platform_mock :unix do
+ RbConfig::CONFIG.stub(:[]).with('bindir').and_return("/opt/chef/embedded/bin")
+ ENV.stub(:[]).with('PATH').and_return("/usr/bin:/usr/sbin:/opt/chef/embedded/bin")
+ File.stub(:exists?).with('/usr/bin/gem').and_return(false)
+ File.stub(:exists?).with('/usr/sbin/gem').and_return(true)
+ File.stub(:exists?).with('/opt/chef/embedded/bin/gem').and_return(true) # should not get here
+ provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
+ provider.gem_env.gem_binary_location.should == '/usr/sbin/gem'
+ end
+ end
- it "sets the current version to the version specified by the new resource if that version is installed" do
- @provider.load_current_resource
- @provider.current_resource.version.should == @spec_version
+ it "searches for a gem binary when running on Omnibus on Windows" do
+ platform_mock :windows do
+ RbConfig::CONFIG.stub(:[]).with('bindir').and_return("d:/opscode/chef/embedded/bin")
+ ENV.stub(:[]).with('PATH').and_return('C:\windows\system32;C:\windows;C:\Ruby186\bin;d:\opscode\chef\embedded\bin')
+ File.stub(:exists?).with('C:\\windows\\system32\\gem').and_return(false)
+ File.stub(:exists?).with('C:\\windows\\gem').and_return(false)
+ File.stub(:exists?).with('C:\\Ruby186\\bin\\gem').and_return(true)
+ File.stub(:exists?).with('d:\\opscode\\chef\\bin\\gem').and_return(false) # should not get here
+ File.stub(:exists?).with('d:\\opscode\\chef\\embedded\\bin\\gem').and_return(false) # should not get here
+ provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
+ provider.gem_env.gem_binary_location.should == 'C:\Ruby186\bin\gem'
+ end
end
- it "sets the current version to the highest installed version if the requested version is not installed" do
- @new_resource.version('9000.0.2')
- @provider.load_current_resource
- @provider.current_resource.version.should == @spec_version
+ it "smites you when you try to use a hash of install options with an explicit gem binary" do
+ @new_resource.gem_binary('/foo/bar')
+ @new_resource.options(:fail => :burger)
+ lambda {Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)}.should raise_error(ArgumentError)
end
- it "leaves the current version at nil if the package is not installed" do
- @new_resource.package_name("no-such-gem-should-exist-with-this-name")
- @provider.load_current_resource
- @provider.current_resource.version.should be_nil
+ it "converts the new resource into a gem dependency" do
+ @provider.gem_dependency.should == Gem::Dependency.new('rspec-core', @spec_version)
+ @new_resource.version('~> 1.2.0')
+ @provider.gem_dependency.should == Gem::Dependency.new('rspec-core', '~> 1.2.0')
end
- end
+ describe "when determining the currently installed version" do
- describe "when determining the candidate version to install" do
+ it "sets the current version to the version specified by the new resource if that version is installed" do
+ @provider.load_current_resource
+ @provider.current_resource.version.should == @spec_version
+ end
- it "does not query for available versions when the current version is the target version" do
- @provider.current_resource = @new_resource.dup
- @provider.candidate_version.should be_nil
- end
+ it "sets the current version to the highest installed version if the requested version is not installed" do
+ @new_resource.version('9000.0.2')
+ @provider.load_current_resource
+ @provider.current_resource.version.should == @spec_version
+ end
- it "determines the candidate version by querying the remote gem servers" do
- @new_resource.source('http://mygems.example.com')
- version = Gem::Version.new(@spec_version)
- @provider.gem_env.should_receive(:candidate_version_from_remote).
- with(Gem::Dependency.new('rspec-core', @spec_version), "http://mygems.example.com").
- and_return(version)
- @provider.candidate_version.should == @spec_version
- end
+ it "leaves the current version at nil if the package is not installed" do
+ @new_resource.package_name("no-such-gem-should-exist-with-this-name")
+ @provider.load_current_resource
+ @provider.current_resource.version.should be_nil
+ end
- it "parses the gem's specification if the requested source is a file" do
- @new_resource.package_name('chef-integration-test')
- @new_resource.version('>= 0')
- @new_resource.source(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
- @provider.candidate_version.should == '0.1.0'
end
- end
-
- describe "when installing a gem" do
- before do
- @current_resource = Chef::Resource::GemPackage.new('rspec-core')
- @provider.current_resource = @current_resource
- @gem_dep = Gem::Dependency.new('rspec-core', @spec_version)
- @provider.stub(:load_current_resource)
- end
+ describe "when determining the candidate version to install" do
- describe "in the current gem environment" do
- it "installs the gem via the gems api when no explicit options are used" do
- @provider.gem_env.should_receive(:install).with(@gem_dep, :sources => nil)
- @provider.action_install.should be_true
+ it "does not query for available versions when the current version is the target version" do
+ @provider.current_resource = @new_resource.dup
+ @provider.candidate_version.should be_nil
end
- it "installs the gem via the gems api when a remote source is provided" do
- @new_resource.source('http://gems.example.org')
- sources = ['http://gems.example.org']
- @provider.gem_env.should_receive(:install).with(@gem_dep, :sources => sources)
- @provider.action_install.should be_true
+ it "determines the candidate version by querying the remote gem servers" do
+ @new_resource.source('http://mygems.example.com')
+ version = Gem::Version.new(@spec_version)
+ @provider.gem_env.should_receive(:candidate_version_from_remote).
+ with(Gem::Dependency.new('rspec-core', @spec_version), "http://mygems.example.com").
+ and_return(version)
+ @provider.candidate_version.should == @spec_version
end
- it "installs the gem from file via the gems api when no explicit options are used" do
+ it "parses the gem's specification if the requested source is a file" do
+ @new_resource.package_name('chef-integration-test')
+ @new_resource.version('>= 0')
@new_resource.source(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
- @provider.gem_env.should_receive(:install).with(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
- @provider.action_install.should be_true
+ @provider.candidate_version.should == '0.1.0'
end
- it "installs the gem from file via the gems api when the package is a path and the source is nil" do
- @new_resource = Chef::Resource::GemPackage.new(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
- @provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
+ end
+
+ describe "when installing a gem" do
+ before do
+ @current_resource = Chef::Resource::GemPackage.new('rspec-core')
@provider.current_resource = @current_resource
- @new_resource.source.should == CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem'
- @provider.gem_env.should_receive(:install).with(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
- @provider.action_install.should be_true
+ @gem_dep = Gem::Dependency.new('rspec-core', @spec_version)
+ @provider.stub(:load_current_resource)
end
- # this catches 'gem_package "foo"' when "./foo" is a file in the cwd, and instead of installing './foo' it fetches the remote gem
- it "installs the gem via the gems api, when the package has no file separator characters in it, but a matching file exists in cwd" do
- ::File.stub(:exists?).and_return(true)
- @new_resource.package_name('rspec-core')
- @provider.gem_env.should_receive(:install).with(@gem_dep, :sources => nil)
- @provider.action_install.should be_true
- end
+ describe "in the current gem environment" do
+ it "installs the gem via the gems api when no explicit options are used" do
+ @provider.gem_env.should_receive(:install).with(@gem_dep, :sources => nil)
+ @provider.action_install.should be_true
+ end
- it "installs the gem by shelling out when options are provided as a String" do
- @new_resource.options('-i /alt/install/location')
- expected ="gem install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\" -i /alt/install/location"
- @provider.should_receive(:shell_out!).with(expected, :env => nil)
- @provider.action_install.should be_true
- end
+ it "installs the gem via the gems api when a remote source is provided" do
+ @new_resource.source('http://gems.example.org')
+ sources = ['http://gems.example.org']
+ @provider.gem_env.should_receive(:install).with(@gem_dep, :sources => sources)
+ @provider.action_install.should be_true
+ end
- it "installs the gem via the gems api when options are given as a Hash" do
- @new_resource.options(:install_dir => '/alt/install/location')
- @provider.gem_env.should_receive(:install).with(@gem_dep, :sources => nil, :install_dir => '/alt/install/location')
- @provider.action_install.should be_true
- end
+ it "installs the gem from file via the gems api when no explicit options are used" do
+ @new_resource.source(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
+ @provider.gem_env.should_receive(:install).with(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
+ @provider.action_install.should be_true
+ end
- describe "at a specific version" do
- before do
- @gem_dep = Gem::Dependency.new('rspec-core', @spec_version)
+ it "installs the gem from file via the gems api when the package is a path and the source is nil" do
+ @new_resource = Chef::Resource::GemPackage.new(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
+ @provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
+ @provider.current_resource = @current_resource
+ @new_resource.source.should == CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem'
+ @provider.gem_env.should_receive(:install).with(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
+ @provider.action_install.should be_true
end
- it "installs the gem via the gems api" do
+ # this catches 'gem_package "foo"' when "./foo" is a file in the cwd, and instead of installing './foo' it fetches the remote gem
+ it "installs the gem via the gems api, when the package has no file separator characters in it, but a matching file exists in cwd" do
+ ::File.stub(:exists?).and_return(true)
+ @new_resource.package_name('rspec-core')
@provider.gem_env.should_receive(:install).with(@gem_dep, :sources => nil)
@provider.action_install.should be_true
end
- end
- describe "at version specified with comparison operator" do
- it "skips install if current version satisifies requested version" do
- @current_resource.stub(:version).and_return("2.3.3")
- @new_resource.stub(:version).and_return(">=2.3.0")
- @provider.gem_env.should_not_receive(:install)
- @provider.action_install
+ it "installs the gem by shelling out when options are provided as a String" do
+ @new_resource.options('-i /alt/install/location')
+ expected ="gem install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\" -i /alt/install/location"
+ @provider.should_receive(:shell_out!).with(expected, :env => nil)
+ @provider.action_install.should be_true
+ end
+
+ it "installs the gem via the gems api when options are given as a Hash" do
+ @new_resource.options(:install_dir => '/alt/install/location')
+ @provider.gem_env.should_receive(:install).with(@gem_dep, :sources => nil, :install_dir => '/alt/install/location')
+ @provider.action_install.should be_true
end
- it "allows user to specify gem version with fuzzy operator" do
- @current_resource.stub(:version).and_return("2.3.3")
- @new_resource.stub(:version).and_return("~>2.3.0")
+ describe "at a specific version" do
+ before do
+ @gem_dep = Gem::Dependency.new('rspec-core', @spec_version)
+ end
- @provider.gem_env.should_not_receive(:install)
- @provider.action_install
+ it "installs the gem via the gems api" do
+ @provider.gem_env.should_receive(:install).with(@gem_dep, :sources => nil)
+ @provider.action_install.should be_true
+ end
+ end
+ describe "at version specified with comparison operator" do
+ it "skips install if current version satisifies requested version" do
+ @current_resource.stub(:version).and_return("2.3.3")
+ @new_resource.stub(:version).and_return(">=2.3.0")
+
+ @provider.gem_env.should_not_receive(:install)
+ @provider.action_install
+ end
+
+ it "allows user to specify gem version with fuzzy operator" do
+ @current_resource.stub(:version).and_return("2.3.3")
+ @new_resource.stub(:version).and_return("~>2.3.0")
+
+ @provider.gem_env.should_not_receive(:install)
+ @provider.action_install
+ end
end
end
- end
- describe "in an alternate gem environment" do
- it "installs the gem by shelling out to gem install" do
- @new_resource.gem_binary('/usr/weird/bin/gem')
- @provider.should_receive(:shell_out!).with("/usr/weird/bin/gem install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\"", :env=>nil)
- @provider.action_install.should be_true
- end
+ describe "in an alternate gem environment" do
+ it "installs the gem by shelling out to gem install" do
+ @new_resource.gem_binary('/usr/weird/bin/gem')
+ @provider.should_receive(:shell_out!).with("/usr/weird/bin/gem install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\"", :env=>nil)
+ @provider.action_install.should be_true
+ end
- it "installs the gem from file by shelling out to gem install" do
- @new_resource.gem_binary('/usr/weird/bin/gem')
- @new_resource.source(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
- @new_resource.version('>= 0')
- @provider.should_receive(:shell_out!).with("/usr/weird/bin/gem install #{CHEF_SPEC_DATA}/gems/chef-integration-test-0.1.0.gem -q --no-rdoc --no-ri -v \">= 0\"", :env=>nil)
- @provider.action_install.should be_true
- end
+ it "installs the gem from file by shelling out to gem install" do
+ @new_resource.gem_binary('/usr/weird/bin/gem')
+ @new_resource.source(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
+ @new_resource.version('>= 0')
+ @provider.should_receive(:shell_out!).with("/usr/weird/bin/gem install #{CHEF_SPEC_DATA}/gems/chef-integration-test-0.1.0.gem -q --no-rdoc --no-ri -v \">= 0\"", :env=>nil)
+ @provider.action_install.should be_true
+ end
- it "installs the gem from file by shelling out to gem install when the package is a path and the source is nil" do
- @new_resource = Chef::Resource::GemPackage.new(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
- @provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
- @provider.current_resource = @current_resource
- @new_resource.gem_binary('/usr/weird/bin/gem')
- @new_resource.version('>= 0')
- @new_resource.source.should == CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem'
- @provider.should_receive(:shell_out!).with("/usr/weird/bin/gem install #{CHEF_SPEC_DATA}/gems/chef-integration-test-0.1.0.gem -q --no-rdoc --no-ri -v \">= 0\"", :env=>nil)
- @provider.action_install.should be_true
+ it "installs the gem from file by shelling out to gem install when the package is a path and the source is nil" do
+ @new_resource = Chef::Resource::GemPackage.new(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
+ @provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
+ @provider.current_resource = @current_resource
+ @new_resource.gem_binary('/usr/weird/bin/gem')
+ @new_resource.version('>= 0')
+ @new_resource.source.should == CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem'
+ @provider.should_receive(:shell_out!).with("/usr/weird/bin/gem install #{CHEF_SPEC_DATA}/gems/chef-integration-test-0.1.0.gem -q --no-rdoc --no-ri -v \">= 0\"", :env=>nil)
+ @provider.action_install.should be_true
+ end
end
- end
- end
-
- describe "when uninstalling a gem" do
- before do
- @new_resource = Chef::Resource::GemPackage.new("rspec")
- @current_resource = @new_resource.dup
- @current_resource.version('1.2.3')
- @provider.new_resource = @new_resource
- @provider.current_resource = @current_resource
end
- describe "in the current gem environment" do
- it "uninstalls via the api when no explicit options are used" do
- # pre-reqs for action_remove to actually remove the package:
- @provider.new_resource.version.should be_nil
- @provider.current_resource.version.should_not be_nil
- # the behavior we're testing:
- @provider.gem_env.should_receive(:uninstall).with('rspec', nil)
- @provider.action_remove
+ describe "when uninstalling a gem" do
+ before do
+ @new_resource = Chef::Resource::GemPackage.new("rspec")
+ @current_resource = @new_resource.dup
+ @current_resource.version('1.2.3')
+ @provider.new_resource = @new_resource
+ @provider.current_resource = @current_resource
end
- it "uninstalls via the api when options are given as a Hash" do
- # pre-reqs for action_remove to actually remove the package:
- @provider.new_resource.version.should be_nil
- @provider.current_resource.version.should_not be_nil
- # the behavior we're testing:
- @new_resource.options(:install_dir => '/alt/install/location')
- @provider.gem_env.should_receive(:uninstall).with('rspec', nil, :install_dir => '/alt/install/location')
- @provider.action_remove
- end
+ describe "in the current gem environment" do
+ it "uninstalls via the api when no explicit options are used" do
+ # pre-reqs for action_remove to actually remove the package:
+ @provider.new_resource.version.should be_nil
+ @provider.current_resource.version.should_not be_nil
+ # the behavior we're testing:
+ @provider.gem_env.should_receive(:uninstall).with('rspec', nil)
+ @provider.action_remove
+ end
- it "uninstalls via the gem command when options are given as a String" do
- @new_resource.options('-i /alt/install/location')
- @provider.should_receive(:shell_out!).with("gem uninstall rspec -q -x -I -a -i /alt/install/location", :env=>nil)
- @provider.action_remove
- end
+ it "uninstalls via the api when options are given as a Hash" do
+ # pre-reqs for action_remove to actually remove the package:
+ @provider.new_resource.version.should be_nil
+ @provider.current_resource.version.should_not be_nil
+ # the behavior we're testing:
+ @new_resource.options(:install_dir => '/alt/install/location')
+ @provider.gem_env.should_receive(:uninstall).with('rspec', nil, :install_dir => '/alt/install/location')
+ @provider.action_remove
+ end
+
+ it "uninstalls via the gem command when options are given as a String" do
+ @new_resource.options('-i /alt/install/location')
+ @provider.should_receive(:shell_out!).with("gem uninstall rspec -q -x -I -a -i /alt/install/location", :env=>nil)
+ @provider.action_remove
+ end
- it "uninstalls a specific version of a gem when a version is provided" do
- @new_resource.version('1.2.3')
- @provider.gem_env.should_receive(:uninstall).with('rspec', '1.2.3')
- @provider.action_remove
+ it "uninstalls a specific version of a gem when a version is provided" do
+ @new_resource.version('1.2.3')
+ @provider.gem_env.should_receive(:uninstall).with('rspec', '1.2.3')
+ @provider.action_remove
+ end
end
- end
- describe "in an alternate gem environment" do
- it "uninstalls via the gem command" do
- @new_resource.gem_binary('/usr/weird/bin/gem')
- @provider.should_receive(:shell_out!).with("/usr/weird/bin/gem uninstall rspec -q -x -I -a", :env=>nil)
- @provider.action_remove
+ describe "in an alternate gem environment" do
+ it "uninstalls via the gem command" do
+ @new_resource.gem_binary('/usr/weird/bin/gem')
+ @provider.should_receive(:shell_out!).with("/usr/weird/bin/gem uninstall rspec -q -x -I -a", :env=>nil)
+ @provider.action_remove
+ end
end
end
end
end
-
diff --git a/spec/unit/provider/service/aix_service_spec.rb b/spec/unit/provider/service/aix_service_spec.rb
new file mode 100644
index 0000000000..070f618b99
--- /dev/null
+++ b/spec/unit/provider/service/aix_service_spec.rb
@@ -0,0 +1,181 @@
+#
+# Author:: Kaustubh <kaustubh@clogeny.com>
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+describe Chef::Provider::Service::Aix do
+ before(:each) do
+ @node = Chef::Node.new
+ @events = Chef::EventDispatch::Dispatcher.new
+ @run_context = Chef::RunContext.new(@node, {}, @events)
+
+ @new_resource = Chef::Resource::Service.new("chef")
+ @current_resource = Chef::Resource::Service.new("chef")
+
+ @provider = Chef::Provider::Service::Aix.new(@new_resource, @run_context)
+ Chef::Resource::Service.stub(:new).and_return(@current_resource)
+ end
+
+ describe "load current resource" do
+ it "should create a current resource with the name of the new resource and determine the status" do
+ @status = double("Status", :exitstatus => 0, :stdout => @stdout)
+ @provider.stub(:shell_out!).and_return(@status)
+
+ Chef::Resource::Service.should_receive(:new).and_return(@current_resource)
+ @current_resource.should_receive(:service_name).with("chef")
+ @provider.should_receive(:determine_current_status!)
+
+ @provider.load_current_resource
+ end
+ end
+
+ describe "determine current status" do
+ context "when the service is active" do
+ before do
+ @status = double("Status", :exitstatus => 0, :stdout => "chef chef 12345 active\n")
+ end
+
+ it "current resource is running" do
+ @provider.should_receive(:shell_out!).with("lssrc -a | grep -w chef").and_return(@status)
+ @provider.should_receive(:is_resource_group?).with(["chef chef 12345 active"])
+
+ @provider.load_current_resource
+ @current_resource.running.should be_true
+ end
+ end
+
+ context "when the service is inoprative" do
+ before do
+ @status = double("Status", :exitstatus => 0, :stdout => "chef chef inoperative\n")
+ end
+
+ it "current resource is not running" do
+ @provider.should_receive(:shell_out!).with("lssrc -a | grep -w chef").and_return(@status)
+ @provider.should_receive(:is_resource_group?).with(["chef chef inoperative"])
+
+ @provider.load_current_resource
+ @current_resource.running.should be_false
+ end
+ end
+ end
+
+ describe "is resource group" do
+ context "when there are mutiple subsystems associated with group" do
+ before do
+ @status = double("Status", :exitstatus => 0, :stdout => "chef1 chef 12345 active\nchef2 chef 12334 active\nchef3 chef inoperative")
+ end
+
+ it "service is a group" do
+ @provider.should_receive(:shell_out!).with("lssrc -a | grep -w chef").and_return(@status)
+ @provider.load_current_resource
+ @provider.instance_eval("@is_resource_group").should be_true
+ end
+ end
+
+ context "when there is a single subsystem in the group" do
+ before do
+ @status = double("Status", :exitstatus => 0, :stdout => "chef1 chef inoperative\n")
+ end
+
+ it "service is a group" do
+ @provider.should_receive(:shell_out!).with("lssrc -a | grep -w chef").and_return(@status)
+ @provider.load_current_resource
+ @provider.instance_eval("@is_resource_group").should be_true
+ end
+ end
+
+ context "when there service is a subsytem" do
+ before do
+ @status = double("Status", :exitstatus => 0, :stdout => "chef chef123 inoperative\n")
+ end
+
+ it "service is a subsystem" do
+ @provider.should_receive(:shell_out!).with("lssrc -a | grep -w chef").and_return(@status)
+ @provider.load_current_resource
+ @provider.instance_eval("@is_resource_group").should be_false
+ end
+ end
+ end
+
+ describe "when starting the service" do
+ before do
+ @new_resource.service_name "apache"
+ end
+
+ it "should call the start command for groups" do
+ @provider.instance_eval('@is_resource_group = true')
+ @provider.should_receive(:shell_out!).with("startsrc -g #{@new_resource.service_name}")
+
+ @provider.start_service
+ end
+
+ it "should call the start command for subsystem" do
+ @provider.should_receive(:shell_out!).with("startsrc -s #{@new_resource.service_name}")
+
+ @provider.start_service
+ end
+ end
+
+ describe "when stopping a service" do
+ before do
+ @new_resource.service_name "apache"
+ end
+
+ it "should call the stop command for groups" do
+ @provider.instance_eval('@is_resource_group = true')
+ @provider.should_receive(:shell_out!).with("stopsrc -g #{@new_resource.service_name}")
+
+ @provider.stop_service
+ end
+
+ it "should call the stop command for subsystem" do
+ @provider.should_receive(:shell_out!).with("stopsrc -s #{@new_resource.service_name}")
+
+ @provider.stop_service
+ end
+ end
+
+ describe "when reloading a service" do
+ before do
+ @new_resource.service_name "apache"
+ end
+
+ it "should call the reload command for groups" do
+ @provider.instance_eval('@is_resource_group = true')
+ @provider.should_receive(:shell_out!).with("refresh -g #{@new_resource.service_name}")
+
+ @provider.reload_service
+ end
+
+ it "should call the reload command for subsystem" do
+ @provider.should_receive(:shell_out!).with("refresh -s #{@new_resource.service_name}")
+
+ @provider.reload_service
+ end
+ end
+
+ describe "when restarting the service" do
+ it "should call stop service followed by start service" do
+ @provider.should_receive(:stop_service)
+ @provider.should_receive(:start_service)
+
+ @provider.restart_service
+ end
+ end
+end
+
diff --git a/spec/unit/provider/service/aixinit_service_spec.rb b/spec/unit/provider/service/aixinit_service_spec.rb
new file mode 100644
index 0000000000..bb090b112c
--- /dev/null
+++ b/spec/unit/provider/service/aixinit_service_spec.rb
@@ -0,0 +1,269 @@
+#
+# Author:: kaustubh (<kaustubh@clogeny.com>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+describe Chef::Provider::Service::AixInit do
+ before(:each) do
+ @node = Chef::Node.new
+ @node.automatic_attrs[:command] = {:ps => 'fuuuu'}
+ @events = Chef::EventDispatch::Dispatcher.new
+ @run_context = Chef::RunContext.new(@node, {}, @events)
+
+ @new_resource = Chef::Resource::Service.new("chef")
+ @provider = Chef::Provider::Service::AixInit.new(@new_resource, @run_context)
+
+ @current_resource = Chef::Resource::Service.new("chef")
+ @provider.current_resource = @current_resource
+
+ @pid, @stdin, @stdout, @stderr = nil, nil, nil, nil
+ end
+
+ describe "load_current_resource" do
+ it "sets current resource attributes" do
+ @provider.should_receive(:set_current_resource_attributes)
+
+ @provider.load_current_resource
+ end
+ end
+
+ describe "action_enable" do
+ shared_examples_for "the service is up to date" do
+ it "does not enable the service" do
+ @provider.should_not_receive(:enable_service)
+ @provider.action_enable
+ @provider.set_updated_status
+ @provider.new_resource.should_not be_updated
+ end
+ end
+
+ shared_examples_for "the service is not up to date" do
+ it "enables the service and sets the resource as updated" do
+ @provider.should_receive(:enable_service).and_return(true)
+ @provider.action_enable
+ @provider.set_updated_status
+ @provider.new_resource.should be_updated
+ end
+ end
+
+ context "when the service is disabled" do
+ before do
+ @current_resource.enabled(false)
+ end
+
+ it_behaves_like "the service is not up to date"
+ end
+
+ context "when the service is enabled" do
+ before do
+ @current_resource.enabled(true)
+ @current_resource.priority(80)
+ end
+
+ context "and the service sets no priority" do
+ it_behaves_like "the service is up to date"
+ end
+
+ context "and the service requests the same priority as is set" do
+ before do
+ @new_resource.priority(80)
+ end
+ it_behaves_like "the service is up to date"
+ end
+
+ context "and the service requests a different priority than is set" do
+ before do
+ @new_resource.priority(20)
+ end
+ it_behaves_like "the service is not up to date"
+ end
+ end
+ end
+
+ describe "enable_service" do
+ before do
+ Dir.stub(:glob).with(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]#{@new_resource.service_name}"]).and_return([])
+ end
+
+ context "when the service doesn't set a priority" do
+ it "creates symlink with status S" do
+ @provider.should_receive(:create_symlink).with(2,'S','')
+
+ @provider.enable_service
+ end
+ end
+
+ context "when the service sets a simple priority (integer)" do
+ before do
+ @new_resource.priority(75)
+ end
+
+ it "creates a symlink with status S and a priority" do
+ @provider.should_receive(:create_symlink).with(2,'S',75)
+
+ @provider.enable_service
+ end
+ end
+
+ context "when the service sets complex priorities (hash)" do
+ before do
+ priority = {2 => [:start, 20], 3 => [:stop, 10]}
+ @new_resource.priority(priority)
+ end
+
+ it "create symlink with status start (S) or stop (K) and a priority " do
+ @provider.should_receive(:create_symlink).with(2,'S',20)
+ @provider.should_receive(:create_symlink).with(3,'K',10)
+
+ @provider.enable_service
+ end
+ end
+ end
+
+ describe "disable_service" do
+ before do
+ Dir.stub(:glob).with(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]#{@new_resource.service_name}"]).and_return([])
+ end
+
+ context "when the service doesn't set a priority" do
+ it "creates symlinks with status stop (K)" do
+ @provider.should_receive(:create_symlink).with(2,'K','')
+
+ @provider.disable_service
+ end
+ end
+
+ context "when the service sets a simple priority (integer)" do
+ before do
+ @new_resource.priority(75)
+ end
+
+ it "create symlink with status stop (k) and a priority " do
+ @provider.should_receive(:create_symlink).with(2,'K',25)
+
+ @provider.disable_service
+ end
+ end
+
+ context "when the service sets complex priorities (hash)" do
+ before do
+ @priority = {2 => [:start, 20], 3 => [:stop, 10]}
+ @new_resource.priority(@priority)
+ end
+
+ it "create symlink with status stop (k) and a priority " do
+ @provider.should_receive(:create_symlink).with(3,'K',90)
+
+ @provider.disable_service
+ end
+ end
+ end
+
+ describe "set_current_resource_attributes" do
+ context "when rc2.d contains only start script" do
+ before do
+ files = ["/etc/rc.d/rc2.d/S20apache"]
+
+ Dir.stub(:glob).with(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]chef"]).and_return(files)
+ end
+
+ it "the service is enabled" do
+ @provider.current_resource.should_receive(:enabled).with(true)
+ @provider.current_resource.should_receive(:priority).with(20)
+
+ @provider.set_current_resource_attributes
+ end
+ end
+
+ context "when rc2.d contains only stop script" do
+ before do
+ files = ["/etc/rc.d/rc2.d/K20apache"]
+ @priority = {2 => [:stop, 20]}
+
+ Dir.stub(:glob).with(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]chef"]).and_return(files)
+ end
+ it "the service is not enabled" do
+ @provider.current_resource.should_receive(:enabled).with(false)
+ @provider.current_resource.should_receive(:priority).with(@priority)
+
+ @provider.set_current_resource_attributes
+ end
+ end
+
+ context "when rc2.d contains both start and stop scripts" do
+ before do
+ @files = ["/etc/rc.d/rc2.d/S20apache", "/etc/rc.d/rc2.d/K80apache"]
+ @priority = {2 => [:start, 20], 2 => [:stop, 80]}
+
+ Dir.stub(:glob).with(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]chef"]).and_return(@files)
+ end
+ it "the service is enabled" do
+ @current_resource.should_receive(:enabled).with(true)
+ @current_resource.should_receive(:priority).with(@priority)
+
+ @provider.set_current_resource_attributes
+ end
+ end
+
+ context "when rc2.d contains only start script (without priority)" do
+ before do
+ files = ["/etc/rc.d/rc2.d/Sapache"]
+
+ Dir.stub(:glob).with(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]#{@new_resource.service_name}"]).and_return(files)
+ end
+
+ it "the service is enabled" do
+ @provider.current_resource.should_receive(:enabled).with(true)
+ @provider.current_resource.should_receive(:priority).with('')
+
+ @provider.set_current_resource_attributes
+ end
+ end
+
+ context "when rc2.d contains only stop script (without priority)" do
+ before do
+ files = ["/etc/rc.d/rc2.d/Kapache"]
+ @priority = {2 => [:stop, '']}
+
+ Dir.stub(:glob).with(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]#{@new_resource.service_name}"]).and_return(files)
+ end
+ it "the service is not enabled" do
+ @provider.current_resource.should_receive(:enabled).with(false)
+ @provider.current_resource.should_receive(:priority).with(@priority)
+
+ @provider.set_current_resource_attributes
+ end
+ end
+
+ context "when rc2.d contains both start and stop scripts" do
+ before do
+ files = ["/etc/rc.d/rc2.d/Sapache", "/etc/rc.d/rc2.d/Kapache"]
+ @priority = {2 => [:start, ''], 2 => [:stop, '']}
+
+ Dir.stub(:glob).with(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]#{@new_resource.service_name}"]).and_return(files)
+ end
+ it "the service is enabled" do
+ @current_resource.should_receive(:enabled).with(true)
+ @current_resource.should_receive(:priority).with(@priority)
+
+ @provider.set_current_resource_attributes
+ end
+ end
+ end
+end
+
diff --git a/spec/unit/provider_resolver_spec.rb b/spec/unit/provider_resolver_spec.rb
new file mode 100644
index 0000000000..927cca4f58
--- /dev/null
+++ b/spec/unit/provider_resolver_spec.rb
@@ -0,0 +1,387 @@
+#
+# Author:: Lamont Granquist (<lamont@getchef.com>)
+# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+require 'chef/mixin/convert_to_class_name'
+
+include Chef::Mixin::ConvertToClassName
+
+describe Chef::ProviderResolver do
+
+ let(:node) do
+ node = Chef::Node.new
+ allow(node).to receive(:[]).with(:os).and_return(os)
+ allow(node).to receive(:[]).with(:platform_family).and_return(platform_family)
+ allow(node).to receive(:[]).with(:platform).and_return(platform)
+ allow(node).to receive(:[]).with(:platform_version).and_return(platform_version)
+ allow(node).to receive(:is_a?).and_return(Chef::Node)
+ node
+ end
+
+ let(:provider_resolver) { Chef::ProviderResolver.new(node) }
+
+ let(:action) { :start }
+
+ let(:resolved_provider) { provider_resolver.resolve(resource, action) }
+
+ let(:provider) { nil }
+
+ let(:resource_name) { :service }
+
+ let(:resource) { double(Chef::Resource, provider: provider, resource_name: resource_name) }
+
+ describe "resolving service resource" do
+ def stub_service_providers(*services)
+ services ||= []
+ allow(Chef::Platform::ServiceHelpers).to receive(:service_resource_providers)
+ .and_return(services)
+ end
+
+ def stub_service_configs(*configs)
+ configs ||= []
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return(configs)
+ end
+
+ before do
+ expect(provider_resolver).not_to receive(:maybe_chef_platform_lookup)
+ allow(resource).to receive(:service_name).and_return("ntp")
+ end
+
+ shared_examples_for "a debian platform with upstart and update-rc.d" do
+ before do
+ stub_service_providers(:debian, :invokercd, :upstart)
+ end
+
+ it "when only the SysV init script exists, it returns a Service::Debian provider" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :initd ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Debian)
+ end
+
+ it "when both SysV and Upstart scripts exist, it returns a Service::Upstart provider" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :initd, :upstart ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
+ end
+
+ it "when only the Upstart script exists, it returns a Service::Upstart provider" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :upstart ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
+ end
+
+ it "when both do not exist, it calls the old style provider resolver and returns a Debian Provider" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Debian)
+ end
+ end
+
+ shared_examples_for "a debian platform using the insserv provider" do
+ context "with a default install" do
+ before do
+ stub_service_providers(:debian, :invokercd, :insserv)
+ end
+
+ it "uses the Service::Insserv Provider to manage sysv init scripts" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :initd ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Insserv)
+ end
+ end
+
+ context "when the user has installed upstart" do
+ before do
+ stub_service_providers(:debian, :invokercd, :insserv, :upstart)
+ end
+
+ it "when only the SysV init script exists, it returns a Service::Debian provider" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :initd ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Insserv)
+ end
+
+ it "when both SysV and Upstart scripts exist, it returns a Service::Upstart provider" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :initd, :upstart ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
+ end
+
+ it "when only the Upstart script exists, it returns a Service::Upstart provider" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :upstart ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
+ end
+
+ it "when both do not exist, it calls the old style provider resolver and returns a Debian Provider" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Insserv)
+ end
+ end
+ end
+
+ describe "on Linux" do
+ end
+
+ describe "on Ubuntu 14.04" do
+ let(:os) { "linux" }
+ let(:platform) { "ubuntu" }
+ let(:platform_family) { "debian" }
+ let(:platform_version) { "14.04" }
+
+ it_behaves_like "a debian platform with upstart and update-rc.d"
+ end
+
+ describe "on Ubuntu 10.04" do
+ let(:os) { "linux" }
+ let(:platform) { "ubuntu" }
+ let(:platform_family) { "debian" }
+ let(:platform_version) { "10.04" }
+
+ it_behaves_like "a debian platform with upstart and update-rc.d"
+ end
+
+ # old debian uses the Debian provider (does not have insserv or upstart, or update-rc.d???)
+ describe "on Debian 4.0" do
+ let(:os) { "linux" }
+ let(:platform) { "debian" }
+ let(:platform_family) { "debian" }
+ let(:platform_version) { "4.0" }
+
+ #it_behaves_like "a debian platform using the debian provider"
+ end
+
+ # Debian replaced the debian provider with insserv in the FIXME:VERSION distro
+ describe "on Debian 7.0" do
+ let(:os) { "linux" }
+ let(:platform) { "debian" }
+ let(:platform_family) { "debian" }
+ let(:platform_version) { "7.0" }
+
+ it_behaves_like "a debian platform using the insserv provider"
+ end
+
+ %w{solaris2 openindiana opensolaris nexentacore omnios smartos}.each do |platform|
+ describe "on #{platform}" do
+ let(:os) { "solaris2" }
+ let(:platform) { platform }
+ let(:platform_family) { platform }
+ let(:platform_version) { "5.11" }
+
+ it "returns a Solaris provider" do
+ stub_service_providers
+ stub_service_configs
+ expect(resolved_provider).to eql(Chef::Provider::Service::Solaris)
+ end
+
+ it "always returns a Solaris provider" do
+ # no matter what we stub on the next two lines we should get a Solaris provider
+ stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
+ stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Solaris)
+ end
+ end
+ end
+
+ %w{mswin mingw32 windows}.each do |platform|
+ describe "on #{platform}" do
+ let(:os) { "windows" }
+ let(:platform) { platform }
+ let(:platform_family) { "windows" }
+ let(:platform_version) { "5.11" }
+
+ it "returns a Windows provider" do
+ stub_service_providers
+ stub_service_configs
+ expect(resolved_provider).to eql(Chef::Provider::Service::Windows)
+ end
+
+ it "always returns a Windows provider" do
+ # no matter what we stub on the next two lines we should get a Windows provider
+ stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
+ stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Windows)
+ end
+ end
+ end
+
+ %w{mac_os_x mac_os_x_server}.each do |platform|
+ describe "on #{platform}" do
+ let(:os) { "darwin" }
+ let(:platform) { platform }
+ let(:platform_family) { "mac_os_x" }
+ let(:platform_version) { "10.9.2" }
+
+ it "returns a Macosx provider" do
+ stub_service_providers
+ stub_service_configs
+ expect(resolved_provider).to eql(Chef::Provider::Service::Macosx)
+ end
+
+ it "always returns a Macosx provider" do
+ # no matter what we stub on the next two lines we should get a Macosx provider
+ stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
+ stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Macosx)
+ end
+ end
+ end
+
+ %w{freebsd netbsd}.each do |platform|
+ describe "on #{platform}" do
+ let(:os) { platform }
+ let(:platform) { platform }
+ let(:platform_family) { platform }
+ let(:platform_version) { "10.0-RELEASE" }
+
+ it "returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do
+ stub_service_providers
+ stub_service_configs(:usr_local_etc_rcd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
+ end
+
+ it "returns a Freebsd provider if it finds the /etc/rc.d initscript" do
+ stub_service_providers
+ stub_service_configs(:etc_rcd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
+ end
+
+ it "always returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do
+ # should only care about :usr_local_etc_rcd stub in the service configs
+ stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
+ stub_service_configs(:usr_local_etc_rcd, :initd, :upstart, :xinetd, :systemd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
+ end
+
+ it "always returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do
+ # should only care about :etc_rcd stub in the service configs
+ stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
+ stub_service_configs(:etc_rcd, :initd, :upstart, :xinetd, :systemd)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
+ end
+
+ it "foo" do
+ stub_service_providers
+ stub_service_configs
+ expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
+ end
+ end
+ end
+
+ end
+
+ describe "resolving static providers" do
+ def resource_class(resource)
+ Chef::Resource.const_get(convert_to_class_name(resource.to_s))
+ end
+ static_mapping = {
+ apt_package: Chef::Provider::Package::Apt,
+ bash: Chef::Provider::Script,
+ bff_package: Chef::Provider::Package::Aix,
+ breakpoint: Chef::Provider::Breakpoint,
+ chef_gem: Chef::Provider::Package::Rubygems,
+ cookbook_file: Chef::Provider::CookbookFile,
+ csh: Chef::Provider::Script,
+ deploy: Chef::Provider::Deploy::Timestamped,
+ deploy_revision: Chef::Provider::Deploy::Revision,
+ directory: Chef::Provider::Directory,
+ dpkg_package: Chef::Provider::Package::Dpkg,
+ dsc_script: Chef::Provider::DscScript,
+ easy_install_package: Chef::Provider::Package::EasyInstall,
+ erl_call: Chef::Provider::ErlCall,
+ execute: Chef::Provider::Execute,
+ file: Chef::Provider::File,
+ gem_package: Chef::Provider::Package::Rubygems,
+ git: Chef::Provider::Git,
+ homebrew_package: Chef::Provider::Package::Homebrew,
+ http_request: Chef::Provider::HttpRequest,
+ ips_package: Chef::Provider::Package::Ips,
+ link: Chef::Provider::Link,
+ log: Chef::Provider::Log::ChefLog,
+ macports_package: Chef::Provider::Package::Macports,
+ pacman_package: Chef::Provider::Package::Pacman,
+ paludis_package: Chef::Provider::Package::Paludis,
+ perl: Chef::Provider::Script,
+ portage_package: Chef::Provider::Package::Portage,
+ python: Chef::Provider::Script,
+ remote_directory: Chef::Provider::RemoteDirectory,
+ route: Chef::Provider::Route,
+ rpm_package: Chef::Provider::Package::Rpm,
+ ruby: Chef::Provider::Script,
+ ruby_block: Chef::Provider::RubyBlock,
+ script: Chef::Provider::Script,
+ smartos_package: Chef::Provider::Package::SmartOS,
+ solaris_package: Chef::Provider::Package::Solaris,
+ subversion: Chef::Provider::Subversion,
+ template: Chef::Provider::Template,
+ timestamped_deploy: Chef::Provider::Deploy::Timestamped,
+ whyrun_safe_ruby_block: Chef::Provider::WhyrunSafeRubyBlock,
+ windows_package: Chef::Provider::Package::Windows,
+ windows_service: Chef::Provider::Service::Windows,
+ yum_package: Chef::Provider::Package::Yum,
+ }
+
+ describe "on Ubuntu 14.04" do
+ let(:os) { "linux" }
+ let(:platform) { "ubuntu" }
+ let(:platform_family) { "debian" }
+ let(:platform_version) { "14.04" }
+
+ supported_providers = [
+ :apt_package, :bash, :breakpoint, :chef_gem, :cookbook_file, :csh, :deploy,
+ :deploy_revision, :directory, :dpkg_package, :easy_install_package,
+ :erl_call, :execute, :file, :gem_package, :git, :http_request, :link, :log, :pacman_package, :paludis_package,
+ :perl, :python, :remote_directory, :route, :rpm_package, :ruby, :ruby_block, :script,
+ :subversion, :template, :timestamped_deploy, :whyrun_safe_ruby_block, :yum_package,
+ ]
+
+ supported_providers.each do |static_resource|
+ static_provider = static_mapping[static_resource]
+ context "when the resource is a #{static_resource}" do
+ let(:resource) { double(Chef::Resource, provider: nil, resource_name: static_resource) }
+ let(:action) { :start } # in reality this doesn't matter much
+ it "should resolve to a #{static_provider} provider" do
+ expect(provider_resolver).not_to receive(:maybe_chef_platform_lookup)
+ expect(resolved_provider).to eql(static_provider)
+ end
+ end
+ end
+
+ unsupported_providers = [
+ :bff_package, :dsc_script, :homebrew_package, :ips_package, :macports_package,
+ :smartos_package, :solaris_package, :windows_package,
+ :windows_service,
+ ]
+
+ unsupported_providers.each do |static_resource|
+ static_provider = static_mapping[static_resource]
+ context "when the resource is a #{static_resource}" do
+ let(:resource) { double(Chef::Resource, provider: nil, resource_name: static_resource) }
+ let(:action) { :start } # in reality this doesn't matter much
+ it "should fall back into the old provider mapper code and hooks" do
+ retval = Object.new
+ expect(provider_resolver).to receive(:maybe_chef_platform_lookup).and_return(retval)
+ expect(resolved_provider).to equal(retval)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/unit/recipe_spec.rb b/spec/unit/recipe_spec.rb
index c795ba3788..0e660dc0cc 100644
--- a/spec/unit/recipe_spec.rb
+++ b/spec/unit/recipe_spec.rb
@@ -119,7 +119,8 @@ describe Chef::Recipe do
describe "should locate platform mapped resources" do
it "locate resource for particular platform" do
- Object.const_set('ShaunTheSheep', Class.new(Chef::Resource){ provides :laughter, :on_platforms => ["television"] })
+ ShaunTheSheep = Class.new(Chef::Resource)
+ ShaunTheSheep.provides :laughter, :on_platforms => ["television"]
node.automatic[:platform] = "television"
node.automatic[:platform_version] = "123"
res = recipe.laughter "timmy"
@@ -128,7 +129,8 @@ describe Chef::Recipe do
end
it "locate a resource for all platforms" do
- Object.const_set("YourMom", Class.new(Chef::Resource){ provides :love_and_caring })
+ YourMom = Class.new(Chef::Resource)
+ YourMom.provides :love_and_caring
res = recipe.love_and_caring "mommy"
res.name.should eql("mommy")
res.kind_of?(YourMom)
@@ -188,16 +190,7 @@ describe Chef::Recipe do
# zen_follower resource has this:
# provides :follower, :on_platforms => ["zen"]
before do
- node.stub(:[]) do |key|
- case key
- when :platform
- :zen
- when :platform_version
- "1.0.0"
- else
- nil
- end
- end
+ node.automatic_attrs[:platform] = "zen"
end
let(:resource_follower) do
@@ -345,6 +338,17 @@ describe Chef::Recipe do
end
recipe.resources(:zen_master => "lao tzu").something.should eql(false)
end
+
+ it "should return the last statement in the definition as the retval" do
+ crow_define = Chef::ResourceDefinition.new
+ crow_define.define :crow, :peace => false, :something => true do
+ "the return val"
+ end
+ run_context.definitions[:crow] = crow_define
+ recipe.crow "mine" do
+ peace true
+ end.should eql("the return val")
+ end
end
end
@@ -361,6 +365,15 @@ describe Chef::Recipe do
end
end
+ describe "handle exec calls" do
+ it "should raise ResourceNotFound error if exec is used" do
+ code = <<-CODE
+ exec 'do_not_try_to_exec'
+ CODE
+ lambda { recipe.instance_eval(code) }.should raise_error(Chef::Exceptions::ResourceNotFound)
+ end
+ end
+
describe "from_file" do
it "should load a resource from a ruby file" do
recipe.from_file(File.join(CHEF_SPEC_DATA, "recipes", "test.rb"))
@@ -414,6 +427,14 @@ describe Chef::Recipe do
end
describe "tags" do
+ describe "with the default node object" do
+ let(:node) { Chef::Node.new }
+
+ it "should return false for any tags" do
+ recipe.tagged?("foo").should be(false)
+ end
+ end
+
it "should set tags via tag" do
recipe.tag "foo"
node[:tags].should include("foo")
diff --git a/spec/unit/resource/apt_package_spec.rb b/spec/unit/resource/apt_package_spec.rb
index 58b007c327..9503e0cbe1 100644
--- a/spec/unit/resource/apt_package_spec.rb
+++ b/spec/unit/resource/apt_package_spec.rb
@@ -17,25 +17,22 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::AptPackage, "initialize" do
+ static_provider_resolution(
+ resource: Chef::Resource::AptPackage,
+ provider: Chef::Provider::Package::Apt,
+ name: :apt_package,
+ action: :install,
+ os: "linux",
+ )
+
before(:each) do
@resource = Chef::Resource::AptPackage.new("foo")
end
- it "should return a Chef::Resource::AptPackage" do
- @resource.should be_a_kind_of(Chef::Resource::AptPackage)
- end
-
- it "should set the resource_name to :apt_package" do
- @resource.resource_name.should eql(:apt_package)
- end
-
- it "should set the provider to Chef::Provider::Package::Apt" do
- @resource.provider.should eql(Chef::Provider::Package::Apt)
- end
-
it "should support default_release" do
@resource.default_release("lenny-backports")
@resource.default_release.should eql("lenny-backports")
diff --git a/spec/unit/resource/breakpoint_spec.rb b/spec/unit/resource/breakpoint_spec.rb
index 412211a038..ed655b84a6 100644
--- a/spec/unit/resource/breakpoint_spec.rb
+++ b/spec/unit/resource/breakpoint_spec.rb
@@ -17,9 +17,17 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::Breakpoint do
+ static_provider_resolution(
+ resource: Chef::Resource::Breakpoint,
+ provider: Chef::Provider::Breakpoint,
+ name: :breakpoint,
+ action: :break,
+ )
+
before do
@breakpoint = Chef::Resource::Breakpoint.new
end
@@ -36,8 +44,4 @@ describe Chef::Resource::Breakpoint do
@breakpoint.name.should match(/breakpoint_spec\.rb\:[\d]{2}\:in \`new\'$/)
end
- it "uses the breakpoint provider" do
- @breakpoint.provider.should == Chef::Provider::Breakpoint
- end
-
end
diff --git a/spec/unit/resource/chef_gem_spec.rb b/spec/unit/resource/chef_gem_spec.rb
index dda65f8741..6a419b3f3b 100644
--- a/spec/unit/resource/chef_gem_spec.rb
+++ b/spec/unit/resource/chef_gem_spec.rb
@@ -18,24 +18,17 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::ChefGem, "initialize" do
- before(:each) do
- @resource = Chef::Resource::ChefGem.new("foo")
- end
-
- it "should return a Chef::Resource::ChefGem" do
- @resource.should be_a_kind_of(Chef::Resource::ChefGem)
- end
-
- it "should set the resource_name to :chef_gem" do
- @resource.resource_name.should eql(:chef_gem)
- end
+ static_provider_resolution(
+ resource: Chef::Resource::ChefGem,
+ provider: Chef::Provider::Package::Rubygems,
+ name: :chef_gem,
+ action: :install,
+ )
- it "should set the provider to Chef::Provider::Package::Rubygems" do
- @resource.provider.should eql(Chef::Provider::Package::Rubygems)
- end
end
describe Chef::Resource::ChefGem, "gem_binary" do
diff --git a/spec/unit/resource/deploy_revision_spec.rb b/spec/unit/resource/deploy_revision_spec.rb
index 1f509992aa..d136aa251e 100644
--- a/spec/unit/resource/deploy_revision_spec.rb
+++ b/spec/unit/resource/deploy_revision_spec.rb
@@ -17,31 +17,26 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::DeployRevision do
- it "defaults to the revision deploy provider" do
- @resource = Chef::Resource::DeployRevision.new("deploy _this_!")
- @resource.provider.should == Chef::Provider::Deploy::Revision
- end
-
- it "has a name of deploy_revision" do
- @resource = Chef::Resource::DeployRevision.new("deploy _this_!")
- @resource.resource_name.should == :deploy_revision
- end
+ static_provider_resolution(
+ resource: Chef::Resource::DeployRevision,
+ provider: Chef::Provider::Deploy::Revision,
+ name: :deploy_revision,
+ action: :deploy,
+ )
end
describe Chef::Resource::DeployBranch do
- it "defaults to the revision deploy provider" do
- @resource = Chef::Resource::DeployBranch.new("deploy _this_!")
- @resource.provider.should == Chef::Provider::Deploy::Revision
- end
-
- it "has a name of deploy_branch" do
- @resource = Chef::Resource::DeployBranch.new("deploy _this_!")
- @resource.resource_name.should == :deploy_branch
- end
+ static_provider_resolution(
+ resource: Chef::Resource::DeployBranch,
+ provider: Chef::Provider::Deploy::Revision,
+ name: :deploy_branch,
+ action: :deploy,
+ )
end
diff --git a/spec/unit/resource/deploy_spec.rb b/spec/unit/resource/deploy_spec.rb
index 7cc25ed41c..914ea19030 100644
--- a/spec/unit/resource/deploy_spec.rb
+++ b/spec/unit/resource/deploy_spec.rb
@@ -17,9 +17,18 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::Deploy do
+ static_provider_resolution(
+ resource: Chef::Resource::Deploy,
+ provider: Chef::Provider::Deploy::Timestamped,
+ name: :deploy,
+ action: :deploy,
+ )
+
+
class << self
def resource_has_a_string_attribute(attr_name)
it "has a String attribute for #{attr_name.to_s}" do
@@ -196,10 +205,6 @@ describe Chef::Resource::Deploy do
@resource.restart.should == restart_like_this
end
- it "defaults to using the Deploy::Timestamped provider" do
- @resource.provider.should == Chef::Provider::Deploy::Timestamped
- end
-
it "allows providers to be set with a full class name" do
@resource.provider Chef::Provider::Deploy::Timestamped
@resource.provider.should == Chef::Provider::Deploy::Timestamped
diff --git a/spec/unit/resource/dpkg_package_spec.rb b/spec/unit/resource/dpkg_package_spec.rb
index 9ef498a577..931e6763bd 100644
--- a/spec/unit/resource/dpkg_package_spec.rb
+++ b/spec/unit/resource/dpkg_package_spec.rb
@@ -17,22 +17,16 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::DpkgPackage, "initialize" do
- before(:each) do
- @resource = Chef::Resource::DpkgPackage.new("foo")
- end
+ static_provider_resolution(
+ resource: Chef::Resource::DpkgPackage,
+ provider: Chef::Provider::Package::Dpkg,
+ name: :dpkg_package,
+ action: :install,
+ os: 'linux',
+ )
- it "should return a Chef::Resource::DpkgPackage" do
- @resource.should be_a_kind_of(Chef::Resource::DpkgPackage)
- end
-
- it "should set the resource_name to :dpkg_package" do
- @resource.resource_name.should eql(:dpkg_package)
- end
-
- it "should set the provider to Chef::Provider::Package::Dpkg" do
- @resource.provider.should eql(Chef::Provider::Package::Dpkg)
- end
end
diff --git a/spec/unit/resource/easy_install_package_spec.rb b/spec/unit/resource/easy_install_package_spec.rb
index 9682c8177b..d3a5f4a0fe 100644
--- a/spec/unit/resource/easy_install_package_spec.rb
+++ b/spec/unit/resource/easy_install_package_spec.rb
@@ -17,30 +17,21 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::EasyInstallPackage, "initialize" do
+ static_provider_resolution(
+ resource: Chef::Resource::EasyInstallPackage,
+ provider: Chef::Provider::Package::EasyInstall,
+ name: :easy_install_package,
+ action: :install,
+ )
+
before(:each) do
@resource = Chef::Resource::EasyInstallPackage.new("foo")
end
- it "should create a new Chef::Resource::EasyInstallPackage" do
- @resource.should be_a_kind_of(Chef::Resource)
- @resource.should be_a_kind_of(Chef::Resource::EasyInstallPackage)
- end
-
- it "should return a Chef::Resource::EasyInstallPackage" do
- @resource.should be_a_kind_of(Chef::Resource::EasyInstallPackage)
- end
-
- it "should set the resource_name to :easy_install_package" do
- @resource.resource_name.should eql(:easy_install_package)
- end
-
- it "should set the provider to Chef::Provider::Package::EasyInstall" do
- @resource.provider.should eql(Chef::Provider::Package::EasyInstall)
- end
-
it "should allow you to set the easy_install_binary attribute" do
@resource.easy_install_binary "/opt/local/bin/easy_install"
@resource.easy_install_binary.should eql("/opt/local/bin/easy_install")
diff --git a/spec/unit/resource/execute_spec.rb b/spec/unit/resource/execute_spec.rb
index 8c8dcfb6ca..e1728b7892 100644
--- a/spec/unit/resource/execute_spec.rb
+++ b/spec/unit/resource/execute_spec.rb
@@ -23,4 +23,9 @@ describe Chef::Resource::Execute do
let(:resource_instance_name) { "some command" }
let(:execute_resource) { Chef::Resource::Execute.new(resource_instance_name) }
it_behaves_like "an execute resource"
+
+ it "default guard interpreter should be :execute interpreter" do
+ execute_resource.guard_interpreter.should be(:execute)
+ end
+
end
diff --git a/spec/unit/resource/freebsd_package_spec.rb b/spec/unit/resource/freebsd_package_spec.rb
index ae12abac6e..04a6962270 100644
--- a/spec/unit/resource/freebsd_package_spec.rb
+++ b/spec/unit/resource/freebsd_package_spec.rb
@@ -57,7 +57,7 @@ describe Chef::Resource::FreebsdPackage do
describe "if __Freebsd_version is greater than or equal to 1000017" do
it "should be Freebsd::Pkgng" do
[1000017, 1000018, 1000500, 1001001, 1100000].each do |__freebsd_version|
- @node.normal[:os_version] = __freebsd_version
+ @node.automatic_attrs[:os_version] = __freebsd_version
@resource.after_created
@resource.provider.should == Chef::Provider::Package::Freebsd::Pkgng
end
@@ -79,8 +79,7 @@ describe Chef::Resource::FreebsdPackage do
@resource.stub(:shell_out!).with("make -V WITH_PKGNG", :env => nil).and_return(pkg_enabled)
[1000016, 1000000, 901503, 902506, 802511].each do |__freebsd_version|
- @node[:os_version] == __freebsd_version
- @node.normal[:os_version] = __freebsd_version
+ @node.automatic_attrs[:os_version] = __freebsd_version
@resource.after_created
@resource.provider.should == Chef::Provider::Package::Freebsd::Pkg
end
diff --git a/spec/unit/resource/gem_package_spec.rb b/spec/unit/resource/gem_package_spec.rb
index 98703455de..01c4fb6106 100644
--- a/spec/unit/resource/gem_package_spec.rb
+++ b/spec/unit/resource/gem_package_spec.rb
@@ -17,24 +17,17 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::GemPackage, "initialize" do
- before(:each) do
- @resource = Chef::Resource::GemPackage.new("foo")
- end
-
- it "should return a Chef::Resource::GemPackage" do
- @resource.should be_a_kind_of(Chef::Resource::GemPackage)
- end
-
- it "should set the resource_name to :gem_package" do
- @resource.resource_name.should eql(:gem_package)
- end
+ static_provider_resolution(
+ resource: Chef::Resource::GemPackage,
+ provider: Chef::Provider::Package::Rubygems,
+ name: :gem_package,
+ action: :install,
+ )
- it "should set the provider to Chef::Provider::Package::Rubygems" do
- @resource.provider.should eql(Chef::Provider::Package::Rubygems)
- end
end
describe Chef::Resource::GemPackage, "gem_binary" do
diff --git a/spec/unit/resource/git_spec.rb b/spec/unit/resource/git_spec.rb
index 95a30c28a4..da7aee1014 100644
--- a/spec/unit/resource/git_spec.rb
+++ b/spec/unit/resource/git_spec.rb
@@ -17,9 +17,17 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::Git do
+ static_provider_resolution(
+ resource: Chef::Resource::Git,
+ provider: Chef::Provider::Git,
+ name: :git,
+ action: :sync,
+ )
+
before(:each) do
@git = Chef::Resource::Git.new("my awesome webapp")
end
@@ -29,10 +37,6 @@ describe Chef::Resource::Git do
@git.should be_an_instance_of(Chef::Resource::Git)
end
- it "uses the git provider" do
- @git.provider.should eql(Chef::Provider::Git)
- end
-
it "uses aliases revision as branch" do
@git.branch "HEAD"
@git.revision.should eql("HEAD")
diff --git a/spec/unit/resource/homebrew_package_spec.rb b/spec/unit/resource/homebrew_package_spec.rb
index bb657607b7..bb248d1189 100644
--- a/spec/unit/resource/homebrew_package_spec.rb
+++ b/spec/unit/resource/homebrew_package_spec.rb
@@ -16,26 +16,19 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::HomebrewPackage, 'initialize' do
- let(:resource) { Chef::Resource::HomebrewPackage.new('emacs') }
-
- it 'returns a Chef::Resource::HomebrewPackage' do
- expect(resource).to be_a_kind_of(Chef::Resource::HomebrewPackage)
- end
-
- it 'sets the resource_name to :homebrew_package' do
- expect(resource.resource_name).to eql(:homebrew_package)
- end
+ static_provider_resolution(
+ resource: Chef::Resource::HomebrewPackage,
+ provider: Chef::Provider::Package::Homebrew,
+ name: :homebrew_package,
+ action: :install,
+ os: "mac_os_x",
+ )
- it 'sets the provider to Chef::Provider::Package::Homebrew' do
- expect(resource.provider).to eql(Chef::Provider::Package::Homebrew)
- end
-
- it 'sets the homebrew_user to nil' do
- expect(resource.homebrew_user).to eql(nil)
- end
+ let(:resource) { Chef::Resource::HomebrewPackage.new('emacs') }
shared_examples 'home_brew user set and returned' do
it 'returns the configured homebrew_user' do
diff --git a/spec/unit/resource/ips_package_spec.rb b/spec/unit/resource/ips_package_spec.rb
index 61661922fa..8718c5c093 100644
--- a/spec/unit/resource/ips_package_spec.rb
+++ b/spec/unit/resource/ips_package_spec.rb
@@ -17,25 +17,22 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::IpsPackage, "initialize" do
+ static_provider_resolution(
+ resource: Chef::Resource::IpsPackage,
+ provider: Chef::Provider::Package::Ips,
+ name: :ips_package,
+ action: :install,
+ os: "solaris2",
+ )
+
before(:each) do
@resource = Chef::Resource::IpsPackage.new("crypto/gnupg")
end
- it "should return a Chef::Resource::IpsPackage" do
- @resource.should be_a_kind_of(Chef::Resource::IpsPackage)
- end
-
- it "should set the resource_name to :ips_package" do
- @resource.resource_name.should eql(:ips_package)
- end
-
- it "should set the provider to Chef::Provider::Package::Ips" do
- @resource.provider.should eql(Chef::Provider::Package::Ips)
- end
-
it "should support accept_license" do
@resource.accept_license(true)
@resource.accept_license.should eql(true)
diff --git a/spec/unit/resource/macports_package_spec.rb b/spec/unit/resource/macports_package_spec.rb
index 7e2e200487..0a203b2e97 100644
--- a/spec/unit/resource/macports_package_spec.rb
+++ b/spec/unit/resource/macports_package_spec.rb
@@ -17,21 +17,16 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::MacportsPackage, "initialize" do
- before(:each) do
- @resource = Chef::Resource::MacportsPackage.new("foo")
- end
- it "should return a Chef::Resource::MacportsPackage" do
- @resource.should be_a_kind_of(Chef::Resource::MacportsPackage)
- end
+ static_provider_resolution(
+ resource: Chef::Resource::MacportsPackage,
+ provider: Chef::Provider::Package::Macports,
+ name: :macports_package,
+ action: :install,
+ os: "mac_os_x",
+ )
- it "should set the resource_name to :macports_package" do
- @resource.resource_name.should eql(:macports_package)
- end
-
- it "should set the provider to Chef::Provider::Package::Macports" do
- @resource.provider.should eql(Chef::Provider::Package::Macports)
- end
end
diff --git a/spec/unit/resource/pacman_package_spec.rb b/spec/unit/resource/pacman_package_spec.rb
index ec5feeb82c..975863d04f 100644
--- a/spec/unit/resource/pacman_package_spec.rb
+++ b/spec/unit/resource/pacman_package_spec.rb
@@ -17,22 +17,16 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::PacmanPackage, "initialize" do
- before(:each) do
- @resource = Chef::Resource::PacmanPackage.new("foo")
- end
+ static_provider_resolution(
+ resource: Chef::Resource::PacmanPackage,
+ provider: Chef::Provider::Package::Pacman,
+ name: :pacman_package,
+ action: :install,
+ os: "linux",
+ )
- it "should return a Chef::Resource::PacmanPackage" do
- @resource.should be_a_kind_of(Chef::Resource::PacmanPackage)
- end
-
- it "should set the resource_name to :pacman_package" do
- @resource.resource_name.should eql(:pacman_package)
- end
-
- it "should set the provider to Chef::Provider::Package::Pacman" do
- @resource.provider.should eql(Chef::Provider::Package::Pacman)
- end
end
diff --git a/spec/unit/resource/rpm_package_spec.rb b/spec/unit/resource/rpm_package_spec.rb
index 25930a5484..d209c6a5a2 100644
--- a/spec/unit/resource/rpm_package_spec.rb
+++ b/spec/unit/resource/rpm_package_spec.rb
@@ -17,22 +17,18 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::RpmPackage, "initialize" do
- before(:each) do
- @resource = Chef::Resource::RpmPackage.new("foo")
+ %w{linux aix}.each do |os|
+ static_provider_resolution(
+ resource: Chef::Resource::RpmPackage,
+ provider: Chef::Provider::Package::Rpm,
+ name: :rpm_package,
+ action: :install,
+ os: os
+ )
end
- it "should return a Chef::Resource::RpmPackage" do
- @resource.should be_a_kind_of(Chef::Resource::RpmPackage)
- end
-
- it "should set the resource_name to :rpm_package" do
- @resource.resource_name.should eql(:rpm_package)
- end
-
- it "should set the provider to Chef::Provider::Package::Rpm" do
- @resource.provider.should eql(Chef::Provider::Package::Rpm)
- end
end
diff --git a/spec/unit/resource/service_spec.rb b/spec/unit/resource/service_spec.rb
index ec62d012bb..9b779e5830 100644
--- a/spec/unit/resource/service_spec.rb
+++ b/spec/unit/resource/service_spec.rb
@@ -29,20 +29,10 @@ describe Chef::Resource::Service do
@resource.should be_a_kind_of(Chef::Resource)
@resource.should be_a_kind_of(Chef::Resource::Service)
end
-
+
it "should not set a provider unless node[:init_package] is defined as systemd" do
@resource.provider.should == nil
end
-
- it "should set the provider to Chef::Provider::Service::Systemd if node[:init_package] is systemd" do
- node = Chef::Node.new
- node.set[:init_package] = "systemd"
- cookbook_collection = Chef::CookbookCollection.new([])
- events = Chef::EventDispatch::Dispatcher.new
- run_context = Chef::RunContext.new(node, cookbook_collection, events)
- @resource = Chef::Resource::Service.new("chef", run_context)
- @resource.provider.should == Chef::Provider::Service::Systemd
- end
it "should set the service_name to the first argument to new" do
@resource.service_name.should eql("chef")
diff --git a/spec/unit/resource/smartos_package_spec.rb b/spec/unit/resource/smartos_package_spec.rb
index 391713c8ff..c2cf546dd5 100644
--- a/spec/unit/resource/smartos_package_spec.rb
+++ b/spec/unit/resource/smartos_package_spec.rb
@@ -16,23 +16,18 @@
# limitations under the License.
#
-require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
+require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::SmartosPackage, "initialize" do
- before(:each) do
- @resource = Chef::Resource::SmartosPackage.new("foo")
- end
+ static_provider_resolution(
+ resource: Chef::Resource::SmartosPackage,
+ provider: Chef::Provider::Package::SmartOS,
+ name: :smartos_package,
+ action: :install,
+ os: "solaris2",
+ platform_family: "smartos",
+ )
- it "should return a Chef::Resource::SmartosPackage" do
- @resource.should be_a_kind_of(Chef::Resource::SmartosPackage)
- end
-
- it "should set the resource_name to :smartos_package" do
- @resource.resource_name.should eql(:smartos_package)
- end
-
- it "should set the provider to Chef::Provider::Package::SmartOS" do
- @resource.provider.should eql(Chef::Provider::Package::SmartOS)
- end
end
diff --git a/spec/unit/resource/solaris_package_spec.rb b/spec/unit/resource/solaris_package_spec.rb
index 6d0260ab5a..ab4e03807d 100644
--- a/spec/unit/resource/solaris_package_spec.rb
+++ b/spec/unit/resource/solaris_package_spec.rb
@@ -17,41 +17,26 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::SolarisPackage, "initialize" do
- before(:each) do
- @resource = Chef::Resource::SolarisPackage.new("foo")
- end
-
- it "should return a Chef::Resource::SolarisPackage object" do
- @resource.should be_a_kind_of(Chef::Resource::SolarisPackage)
+ %w{solaris2 nexentacore}.each do |platform_family|
+ static_provider_resolution(
+ resource: Chef::Resource::SolarisPackage,
+ provider: Chef::Provider::Package::Solaris,
+ name: :solaris_package,
+ action: :install,
+ os: "solaris2",
+ platform_family: platform_family,
+ )
end
- it "should not raise any Error when valid number of arguments are provided" do
- expect { Chef::Resource::SolarisPackage.new("foo") }.to_not raise_error
- end
-
- it "should raise ArgumentError when incorrect number of arguments are provided" do
- expect { Chef::Resource::SolarisPackage.new }.to raise_error(ArgumentError)
+ before(:each) do
+ @resource = Chef::Resource::SolarisPackage.new("foo")
end
it "should set the package_name to the name provided" do
@resource.package_name.should eql("foo")
end
-
- it "should set the resource_name to :solaris_package" do
- @resource.resource_name.should eql(:solaris_package)
- end
-
- it "should set the run_context to the run_context provided" do
- @run_context = double()
- @run_context.stub(:node)
- resource = Chef::Resource::SolarisPackage.new("foo", @run_context)
- resource.run_context.should eql(@run_context)
- end
-
- it "should set the provider to Chef::Provider::Package::Solaris" do
- @resource.provider.should eql(Chef::Provider::Package::Solaris)
- end
end
diff --git a/spec/unit/resource/subversion_spec.rb b/spec/unit/resource/subversion_spec.rb
index ae06ce665a..a52d8421c6 100644
--- a/spec/unit/resource/subversion_spec.rb
+++ b/spec/unit/resource/subversion_spec.rb
@@ -17,9 +17,17 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::Subversion do
+ static_provider_resolution(
+ resource: Chef::Resource::Subversion,
+ provider: Chef::Provider::Subversion,
+ name: :subversion,
+ action: :install,
+ )
+
before do
@svn = Chef::Resource::Subversion.new("ohai, svn project!")
end
@@ -29,10 +37,6 @@ describe Chef::Resource::Subversion do
@svn.should be_a_kind_of(Chef::Resource::Scm)
end
- it "uses the subversion provider" do
- @svn.provider.should eql(Chef::Provider::Subversion)
- end
-
it "allows the force_export action" do
@svn.allowed_actions.should include(:force_export)
end
diff --git a/spec/unit/resource/timestamped_deploy_spec.rb b/spec/unit/resource/timestamped_deploy_spec.rb
index f380ffca87..2af9d8bb0f 100644
--- a/spec/unit/resource/timestamped_deploy_spec.rb
+++ b/spec/unit/resource/timestamped_deploy_spec.rb
@@ -18,11 +18,37 @@
require 'spec_helper'
-describe Chef::Resource::TimestampedDeploy do
+describe Chef::Resource::TimestampedDeploy, "initialize" do
- it "defaults to the TimestampedDeploy provider" do
- @resource = Chef::Resource::TimestampedDeploy.new("stuff")
- @resource.provider.should == Chef::Provider::Deploy::Timestamped
+ let(:node) {
+ node = Chef::Node.new
+ node.automatic_attrs[:os] = 'linux'
+ node.automatic_attrs[:platform_family] = 'rhel'
+ node
+ }
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:provider_resolver) { Chef::ProviderResolver.new(node) }
+ let(:run_context) {
+ run_context = Chef::RunContext.new(node, {}, events)
+ run_context.provider_resolver = provider_resolver
+ run_context
+ }
+ let(:resource) { Chef::Resource::TimestampedDeploy.new("stuff", run_context) }
+
+ it "should return a Chef::Resource::TimestampedDeploy" do
+ expect(resource).to be_a_kind_of(Chef::Resource::TimestampedDeploy)
+ end
+
+ it "should set the resource_name to :timestamped_deploy" do
+ expect(resource.resource_name).to eql(:deploy)
end
+ it "should leave the provider nil" do
+ expect(resource.provider).to eql(nil)
+ end
+
+ it "should resolve to a Chef::Provider::Deploy::Timestamped" do
+ expect(resource.provider_for_action(:install)).to be_a(Chef::Provider::Deploy::Timestamped)
+ end
end
+
diff --git a/spec/unit/resource/yum_package_spec.rb b/spec/unit/resource/yum_package_spec.rb
index 57ab4dfcd9..7e1979fdfd 100644
--- a/spec/unit/resource/yum_package_spec.rb
+++ b/spec/unit/resource/yum_package_spec.rb
@@ -17,24 +17,19 @@
#
require 'spec_helper'
+require 'support/shared/unit/resource/static_provider_resolution'
describe Chef::Resource::YumPackage, "initialize" do
- before(:each) do
- @resource = Chef::Resource::YumPackage.new("foo")
- end
-
- it "should return a Chef::Resource::YumPackage" do
- @resource.should be_a_kind_of(Chef::Resource::YumPackage)
- end
-
- it "should set the resource_name to :yum_package" do
- @resource.resource_name.should eql(:yum_package)
- end
+ static_provider_resolution(
+ resource: Chef::Resource::YumPackage,
+ provider: Chef::Provider::Package::Yum,
+ name: :yum_package,
+ action: :install,
+ os: 'linux',
+ platform_family: 'rhel',
+ )
- it "should set the provider to Chef::Provider::Package::Yum" do
- @resource.provider.should eql(Chef::Provider::Package::Yum)
- end
end
describe Chef::Resource::YumPackage, "arch" do
diff --git a/spec/unit/resource_collection/resource_list_spec.rb b/spec/unit/resource_collection/resource_list_spec.rb
new file mode 100644
index 0000000000..641fe55c8d
--- /dev/null
+++ b/spec/unit/resource_collection/resource_list_spec.rb
@@ -0,0 +1,137 @@
+#
+# Author:: Serdar Sutay (<serdar@getchef.com>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+describe Chef::ResourceCollection::ResourceList do
+ let(:resource_list) { Chef::ResourceCollection::ResourceList.new() }
+ let(:resource) { Chef::Resource::ZenMaster.new("makoto") }
+ let(:second_resource) { Chef::Resource::ZenMaster.new("hattori") }
+
+ def insert_resource(res)
+ expect{ resource_list.insert(res) }.not_to raise_error
+ end
+
+ describe "initialize" do
+ it "should return a Chef::ResourceList" do
+ expect(resource_list).to be_instance_of(Chef::ResourceCollection::ResourceList)
+ end
+ end
+
+ describe "insert" do
+ it "should be able to insert a Chef::Resource" do
+ insert_resource(resource)
+ expect(resource_list[0]).to be(resource)
+ end
+
+ it "should insert things in order" do
+ insert_resource(resource)
+ insert_resource(second_resource)
+ expect(resource_list[0]).to be(resource)
+ expect(resource_list[1]).to be(second_resource)
+ end
+
+ it "should raise error when trying to install something other than Chef::Resource" do
+ expect{ resource_list.insert("not a resource") }.to raise_error(ArgumentError)
+ end
+ end
+
+ describe "accessors" do
+ it "should be able to insert with []=" do
+ expect{ resource_list[0] = resource }.not_to raise_error
+ expect{ resource_list[1] = second_resource }.not_to raise_error
+ expect(resource_list[0]).to be(resource)
+ expect(resource_list[1]).to be(second_resource)
+ end
+
+ it "should be empty by default" do
+ expect(resource_list.empty?).to be_true
+ end
+
+ describe "when resources are inserted" do
+ before do
+ insert_resource(resource)
+ insert_resource(second_resource)
+ end
+
+ it "should get resources with all_resources method" do
+ resources = resource_list.all_resources
+
+ expect(resources[0]).to be(resource)
+ expect(resources[1]).to be(second_resource)
+ end
+
+ it "should be able to get resources with each" do
+ current = 0
+ expected_resources = [resource, second_resource]
+
+ resource_list.each do |r|
+ expect(r).to be(expected_resources[current])
+ current += 1
+ end
+
+ expect(current).to eq(2)
+ end
+
+ it "should be able to get resources with each_index" do
+ current = 0
+
+ resource_list.each_index do |i|
+ expect(i).to eq(current)
+ current += 1
+ end
+
+ expect(current).to eq(2)
+ end
+
+ it "should be able to check if the list is empty" do
+ expect(resource_list.empty?).to be_false
+ end
+ end
+ end
+
+ describe "during execute" do
+ before(:each) do
+ insert_resource(resource)
+ insert_resource(second_resource)
+ end
+
+ it "should execute resources in order" do
+ current = 0
+ expected_resources = [resource, second_resource]
+
+ resource_list.execute_each_resource do |r|
+ expect(r).to be(expected_resources[current])
+ current += 1
+ end
+
+ expect(current).to eq(2)
+ end
+
+ it "should be able to insert resources on the fly" do
+ resource_to_inject = Chef::Resource::ZenMaster.new("there is no spoon")
+ expected_resources = [resource, resource_to_inject, second_resource]
+
+ resource_list.execute_each_resource do |r|
+ resource_list.insert(resource_to_inject) if r == resource
+ end
+
+ expect(resource_list.all_resources).to eq(expected_resources)
+ end
+ end
+end
diff --git a/spec/unit/resource_collection/resource_set_spec.rb b/spec/unit/resource_collection/resource_set_spec.rb
new file mode 100644
index 0000000000..8be31cd9f6
--- /dev/null
+++ b/spec/unit/resource_collection/resource_set_spec.rb
@@ -0,0 +1,199 @@
+#
+# Author:: Tyler Ball (<tball@getchef.com>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+describe Chef::ResourceCollection::ResourceSet do
+ let(:collection) { Chef::ResourceCollection::ResourceSet.new }
+
+ let(:zen_master_name) { "Neo" }
+ let(:zen_master2_name) { "Morpheus" }
+ let(:zen_follower_name) { "Squid" }
+ let(:zen_master) { Chef::Resource::ZenMaster.new(zen_master_name) }
+ let(:zen_master2) { Chef::Resource::ZenMaster.new(zen_master2_name) }
+ let(:zen_follower) { Chef::Resource::ZenFollower.new(zen_follower_name) }
+
+ describe "initialize" do
+ it "should return a Chef::ResourceSet" do
+ expect(collection).to be_instance_of(Chef::ResourceCollection::ResourceSet)
+ end
+ end
+
+ describe "keys" do
+ it "should return an empty list for an empty ResourceSet" do
+ expect(collection.keys).to eq([])
+ end
+
+ it "should return the keys for a non-empty ResourceSet" do
+ collection.instance_variable_get(:@resources_by_key)["key"] = nil
+ expect(collection.keys).to eq(["key"])
+ end
+ end
+
+ describe "insert_as, lookup and find" do
+ # To validate insert_as you need lookup, and vice-versa - putting all tests in 1 context to avoid duplication
+ it "should accept only Chef::Resources" do
+ expect { collection.insert_as(zen_master) }.to_not raise_error
+ expect { collection.insert_as("string") }.to raise_error(ArgumentError)
+ end
+
+ it "should allow you to lookup resources by a default .to_s" do
+ collection.insert_as(zen_master)
+ expect(collection.lookup(zen_master.to_s)).to equal(zen_master)
+ end
+
+ it "should use a custom type and name to insert" do
+ collection.insert_as(zen_master, "OtherResource", "other_resource")
+ expect(collection.lookup("OtherResource[other_resource]")).to equal(zen_master)
+ end
+
+ it "should raise an exception if you send something strange to lookup" do
+ expect { collection.lookup(:symbol) }.to raise_error(ArgumentError)
+ end
+
+ it "should raise an exception if it cannot find a resource with lookup" do
+ expect { collection.lookup(zen_master.to_s) }.to raise_error(Chef::Exceptions::ResourceNotFound)
+ end
+
+ it "should find a resource by type symbol and name" do
+ collection.insert_as(zen_master)
+ expect(collection.find(:zen_master => zen_master_name)).to equal(zen_master)
+ end
+
+ it "should find a resource by type symbol and array of names" do
+ collection.insert_as(zen_master)
+ collection.insert_as(zen_master2)
+ check_by_names(collection.find(:zen_master => [zen_master_name,zen_master2_name]), zen_master_name, zen_master2_name)
+ end
+
+ it "should find a resource by type symbol and array of names with custom names" do
+ collection.insert_as(zen_master, :zzz, "name1")
+ collection.insert_as(zen_master2, :zzz, "name2")
+ check_by_names(collection.find( :zzz => ["name1","name2"]), zen_master_name, zen_master2_name)
+ end
+
+ it "should find resources of multiple kinds (:zen_master => a, :zen_follower => b)" do
+ collection.insert_as(zen_master)
+ collection.insert_as(zen_follower)
+ check_by_names(collection.find(:zen_master => [zen_master_name], :zen_follower => [zen_follower_name]),
+ zen_master_name, zen_follower_name)
+ end
+
+ it "should find resources of multiple kinds (:zen_master => a, :zen_follower => b with custom names)" do
+ collection.insert_as(zen_master, :zzz, "name1")
+ collection.insert_as(zen_master2, :zzz, "name2")
+ collection.insert_as(zen_follower, :yyy, "name3")
+ check_by_names(collection.find(:zzz => ["name1","name2"], :yyy => ["name3"]),
+ zen_master_name, zen_follower_name, zen_master2_name)
+ end
+
+ it "should find a resource by string zen_master[a]" do
+ collection.insert_as(zen_master)
+ expect(collection.find("zen_master[#{zen_master_name}]")).to eq(zen_master)
+ end
+
+ it "should find a resource by string zen_master[a] with custom names" do
+ collection.insert_as(zen_master, :zzz, "name1")
+ expect(collection.find("zzz[name1]")).to eq(zen_master)
+ end
+
+ it "should find resources by strings of zen_master[a,b]" do
+ collection.insert_as(zen_master)
+ collection.insert_as(zen_master2)
+ check_by_names(collection.find("zen_master[#{zen_master_name},#{zen_master2_name}]"),
+ zen_master_name, zen_master2_name)
+ end
+
+ it "should find resources by strings of zen_master[a,b] with custom names" do
+ collection.insert_as(zen_master, :zzz, "name1")
+ collection.insert_as(zen_master2, :zzz, "name2")
+ check_by_names(collection.find("zzz[name1,name2]"),
+ zen_master_name, zen_master2_name)
+ end
+
+ it "should find resources of multiple types by strings of zen_master[a]" do
+ collection.insert_as(zen_master)
+ collection.insert_as(zen_follower)
+ check_by_names(collection.find("zen_master[#{zen_master_name}]", "zen_follower[#{zen_follower_name}]"),
+ zen_master_name, zen_follower_name)
+ end
+
+ it "should find resources of multiple types by strings of zen_master[a] with custom names" do
+ collection.insert_as(zen_master, :zzz, "name1")
+ collection.insert_as(zen_master2, :zzz, "name2")
+ collection.insert_as(zen_follower, :yyy, "name3")
+ check_by_names(collection.find("zzz[name1,name2]", "yyy[name3]"),
+ zen_master_name, zen_follower_name,zen_master2_name)
+ end
+
+ it "should only keep the last copy when multiple instances of a Resource are inserted" do
+ collection.insert_as(zen_master)
+ expect(collection.find("zen_master[#{zen_master_name}]")).to eq(zen_master)
+ new_zm =zen_master.dup
+ new_zm.retries = 10
+ expect(new_zm).to_not eq(zen_master)
+ collection.insert_as(new_zm)
+ expect(collection.find("zen_master[#{zen_master_name}]")).to eq(new_zm)
+ end
+
+ it "should raise an exception if you pass a bad name to resources" do
+ expect { collection.find("michael jackson") }.to raise_error(ArgumentError)
+ end
+
+ it "should raise an exception if you pass something other than a string or hash to resource" do
+ expect { collection.find([Array.new]) }.to raise_error(ArgumentError)
+ end
+
+ it "raises an error when attempting to find a resource that does not exist" do
+ expect { collection.find("script[nonesuch]") }.to raise_error(Chef::Exceptions::ResourceNotFound)
+ end
+ end
+
+ describe "validate_lookup_spec!" do
+ it "accepts a string of the form 'resource_type[resource_name]'" do
+ expect(collection.validate_lookup_spec!("resource_type[resource_name]")).to be_true
+ end
+
+ it "accepts a single-element :resource_type => 'resource_name' Hash" do
+ expect(collection.validate_lookup_spec!(:service => "apache2")).to be_true
+ end
+
+ it "accepts a chef resource object" do
+ expect(collection.validate_lookup_spec!(zen_master)).to be_true
+ end
+
+ it "rejects a malformed query string" do
+ expect { collection.validate_lookup_spec!("resource_type[missing-end-bracket") }.to \
+ raise_error(Chef::Exceptions::InvalidResourceSpecification)
+ end
+
+ it "rejects an argument that is not a String, Hash, or Chef::Resource" do
+ expect { collection.validate_lookup_spec!(Object.new) }.to \
+ raise_error(Chef::Exceptions::InvalidResourceSpecification)
+ end
+
+ end
+
+ def check_by_names(results, *names)
+ expect(results.size).to eq(names.size)
+ names.each do |name|
+ expect(results.detect{|r| r.name == name}).to_not eq(nil)
+ end
+ end
+
+end
diff --git a/spec/unit/resource_collection_spec.rb b/spec/unit/resource_collection_spec.rb
index cf119f1ab0..5966fdd1f2 100644
--- a/spec/unit/resource_collection_spec.rb
+++ b/spec/unit/resource_collection_spec.rb
@@ -20,104 +20,77 @@
require 'spec_helper'
describe Chef::ResourceCollection do
+ let(:rc) { Chef::ResourceCollection.new() }
+ let(:resource) { Chef::Resource::ZenMaster.new("makoto") }
- before(:each) do
- @rc = Chef::ResourceCollection.new()
- @resource = Chef::Resource::ZenMaster.new("makoto")
+ it "should throw an error when calling a non-delegated method" do
+ expect { rc.not_a_method }.to raise_error(NoMethodError)
end
describe "initialize" do
it "should return a Chef::ResourceCollection" do
- @rc.should be_kind_of(Chef::ResourceCollection)
+ rc.should be_kind_of(Chef::ResourceCollection)
end
end
describe "[]" do
it "should accept Chef::Resources through [index]" do
- lambda { @rc[0] = @resource }.should_not raise_error
- lambda { @rc[0] = "string" }.should raise_error
+ lambda { rc[0] = resource }.should_not raise_error
+ lambda { rc[0] = "string" }.should raise_error(ArgumentError)
end
it "should allow you to fetch Chef::Resources by position" do
- @rc[0] = @resource
- @rc[0].should eql(@resource)
+ rc[0] = resource
+ rc[0].should eql(resource)
end
end
describe "push" do
it "should accept Chef::Resources through pushing" do
- lambda { @rc.push(@resource) }.should_not raise_error
- lambda { @rc.push("string") }.should raise_error
+ lambda { rc.push(resource) }.should_not raise_error
+ lambda { rc.push("string") }.should raise_error(ArgumentError)
end
end
describe "<<" do
it "should accept the << operator" do
- lambda { @rc << @resource }.should_not raise_error
+ lambda { rc << resource }.should_not raise_error
end
end
describe "insert" do
it "should accept only Chef::Resources" do
- lambda { @rc.insert(@resource) }.should_not raise_error
- lambda { @rc.insert("string") }.should raise_error
+ lambda { rc.insert(resource) }.should_not raise_error
+ lambda { rc.insert("string") }.should raise_error(ArgumentError)
+ end
+
+ it "should accept named arguments in any order" do
+ rc.insert(resource, :instance_name => 'foo', :resource_type =>'bar')
+ expect(rc[0]).to eq(resource)
end
it "should append resources to the end of the collection when not executing a run" do
zmr = Chef::Resource::ZenMaster.new("there is no spoon")
- @rc.insert(@resource)
- @rc.insert(zmr)
- @rc[0].should eql(@resource)
- @rc[1].should eql(zmr)
+ rc.insert(resource)
+ rc.insert(zmr)
+ rc[0].should eql(resource)
+ rc[1].should eql(zmr)
end
it "should insert resources to the middle of the collection if called while executing a run" do
resource_to_inject = Chef::Resource::ZenMaster.new("there is no spoon")
zmr = Chef::Resource::ZenMaster.new("morpheus")
dummy = Chef::Resource::ZenMaster.new("keanu reeves")
- @rc.insert(zmr)
- @rc.insert(dummy)
+ rc.insert(zmr)
+ rc.insert(dummy)
- @rc.execute_each_resource do |resource|
- @rc.insert(resource_to_inject) if resource == zmr
+ rc.execute_each_resource do |resource|
+ rc.insert(resource_to_inject) if resource == zmr
end
- @rc[0].should eql(zmr)
- @rc[1].should eql(resource_to_inject)
- @rc[2].should eql(dummy)
- end
- end
-
- describe "insert_at" do
- it "should accept only Chef::Resources" do
- lambda { @rc.insert_at(0, @resource, @resource) }.should_not raise_error
- lambda { @rc.insert_at(0, "string") }.should raise_error
- lambda { @rc.insert_at(0, @resource, "string") }.should raise_error
- end
-
- it "should toss an error if it receives a bad index" do
- @rc.insert_at(10, @resource)
- end
-
- it "should insert resources at the beginning when asked" do
- @rc.insert(Chef::Resource::ZenMaster.new('1'))
- @rc.insert(Chef::Resource::ZenMaster.new('2'))
- @rc.insert_at(0, Chef::Resource::ZenMaster.new('X'))
- @rc.all_resources.map { |r| r.name }.should == [ 'X', '1', '2' ]
- end
-
- it "should insert resources in the middle when asked" do
- @rc.insert(Chef::Resource::ZenMaster.new('1'))
- @rc.insert(Chef::Resource::ZenMaster.new('2'))
- @rc.insert_at(1, Chef::Resource::ZenMaster.new('X'))
- @rc.all_resources.map { |r| r.name }.should == [ '1', 'X', '2' ]
- end
-
- it "should insert resources at the end when asked" do
- @rc.insert(Chef::Resource::ZenMaster.new('1'))
- @rc.insert(Chef::Resource::ZenMaster.new('2'))
- @rc.insert_at(2, Chef::Resource::ZenMaster.new('X'))
- @rc.all_resources.map { |r| r.name }.should == [ '1', '2', 'X' ]
+ rc[0].should eql(zmr)
+ rc[1].should eql(resource_to_inject)
+ rc[2].should eql(dummy)
end
end
@@ -126,7 +99,7 @@ describe Chef::ResourceCollection do
load_up_resources
results = Array.new
lambda {
- @rc.each do |r|
+ rc.each do |r|
results << r.name
end
}.should_not raise_error
@@ -148,8 +121,8 @@ describe Chef::ResourceCollection do
load_up_resources
results = Array.new
lambda {
- @rc.each_index do |i|
- results << @rc[i].name
+ rc.each_index do |i|
+ results << rc[i].name
end
}.should_not raise_error
results.each_index do |i|
@@ -168,24 +141,24 @@ describe Chef::ResourceCollection do
describe "lookup" do
it "should allow you to find resources by name via lookup" do
zmr = Chef::Resource::ZenMaster.new("dog")
- @rc << zmr
- @rc.lookup(zmr.to_s).should eql(zmr)
+ rc << zmr
+ rc.lookup(zmr.to_s).should eql(zmr)
zmr = Chef::Resource::ZenMaster.new("cat")
- @rc[0] = zmr
- @rc.lookup(zmr).should eql(zmr)
+ rc[0] = zmr
+ rc.lookup(zmr).should eql(zmr)
zmr = Chef::Resource::ZenMaster.new("monkey")
- @rc.push(zmr)
- @rc.lookup(zmr).should eql(zmr)
+ rc.push(zmr)
+ rc.lookup(zmr).should eql(zmr)
end
it "should raise an exception if you send something strange to lookup" do
- lambda { @rc.lookup(:symbol) }.should raise_error(ArgumentError)
+ lambda { rc.lookup(:symbol) }.should raise_error(ArgumentError)
end
it "should raise an exception if it cannot find a resource with lookup" do
- lambda { @rc.lookup("zen_master[dog]") }.should raise_error(Chef::Exceptions::ResourceNotFound)
+ lambda { rc.lookup("zen_master[dog]") }.should raise_error(Chef::Exceptions::ResourceNotFound)
end
end
@@ -193,80 +166,80 @@ describe Chef::ResourceCollection do
it "should find a resource by symbol and name (:zen_master => monkey)" do
load_up_resources
- @rc.resources(:zen_master => "monkey").name.should eql("monkey")
+ rc.resources(:zen_master => "monkey").name.should eql("monkey")
end
it "should find a resource by symbol and array of names (:zen_master => [a,b])" do
load_up_resources
- results = @rc.resources(:zen_master => [ "monkey", "dog" ])
+ results = rc.resources(:zen_master => [ "monkey", "dog" ])
results.length.should eql(2)
check_by_names(results, "monkey", "dog")
end
it "should find resources of multiple kinds (:zen_master => a, :file => b)" do
load_up_resources
- results = @rc.resources(:zen_master => "monkey", :file => "something")
+ results = rc.resources(:zen_master => "monkey", :file => "something")
results.length.should eql(2)
check_by_names(results, "monkey", "something")
end
it "should find a resource by string zen_master[a]" do
load_up_resources
- @rc.resources("zen_master[monkey]").name.should eql("monkey")
+ rc.resources("zen_master[monkey]").name.should eql("monkey")
end
it "should find resources by strings of zen_master[a,b]" do
load_up_resources
- results = @rc.resources("zen_master[monkey,dog]")
+ results = rc.resources("zen_master[monkey,dog]")
results.length.should eql(2)
check_by_names(results, "monkey", "dog")
end
it "should find resources of multiple types by strings of zen_master[a]" do
load_up_resources
- results = @rc.resources("zen_master[monkey]", "file[something]")
+ results = rc.resources("zen_master[monkey]", "file[something]")
results.length.should eql(2)
check_by_names(results, "monkey", "something")
end
it "should raise an exception if you pass a bad name to resources" do
- lambda { @rc.resources("michael jackson") }.should raise_error(ArgumentError)
+ lambda { rc.resources("michael jackson") }.should raise_error(ArgumentError)
end
it "should raise an exception if you pass something other than a string or hash to resource" do
- lambda { @rc.resources([Array.new]) }.should raise_error(ArgumentError)
+ lambda { rc.resources([Array.new]) }.should raise_error(ArgumentError)
end
it "raises an error when attempting to find a resource that does not exist" do
- lambda {@rc.find("script[nonesuch]")}.should raise_error(Chef::Exceptions::ResourceNotFound)
+ lambda {rc.find("script[nonesuch]")}.should raise_error(Chef::Exceptions::ResourceNotFound)
end
end
describe "when validating a resource query object" do
it "accepts a string of the form 'resource_type[resource_name]'" do
- @rc.validate_lookup_spec!("resource_type[resource_name]").should be_true
+ rc.validate_lookup_spec!("resource_type[resource_name]").should be_true
end
it "accepts a single-element :resource_type => 'resource_name' Hash" do
- @rc.validate_lookup_spec!(:service => "apache2").should be_true
+ rc.validate_lookup_spec!(:service => "apache2").should be_true
end
it "accepts a chef resource object" do
res = Chef::Resource.new("foo", nil)
- @rc.validate_lookup_spec!(res).should be_true
+ rc.validate_lookup_spec!(res).should be_true
end
it "rejects a malformed query string" do
lambda do
- @rc.validate_lookup_spec!("resource_type[missing-end-bracket")
+ rc.validate_lookup_spec!("resource_type[missing-end-bracket")
end.should raise_error(Chef::Exceptions::InvalidResourceSpecification)
end
it "rejects an argument that is not a String, Hash, or Chef::Resource" do
lambda do
- @rc.validate_lookup_spec!(Object.new)
+ rc.validate_lookup_spec!(Object.new)
end.should raise_error(Chef::Exceptions::InvalidResourceSpecification)
end
@@ -274,40 +247,40 @@ describe Chef::ResourceCollection do
describe "to_json" do
it "should serialize to json" do
- json = @rc.to_json
+ json = rc.to_json
json.should =~ /json_class/
json.should =~ /instance_vars/
end
include_examples "to_json equalivent to Chef::JSONCompat.to_json" do
- let(:jsonable) { @rc }
+ let(:jsonable) { rc }
end
end
describe "self.from_json" do
it "should not respond to this method" do
- expect(@rc.respond_to?(:from_json)).to eq(false)
+ expect(rc.respond_to?(:from_json)).to eq(false)
end
it "should convert from json using the CHEF::JSONCompat library" do
- @rc << @resource
- json = Chef::JSONCompat.to_json(@rc)
+ rc << resource
+ json = Chef::JSONCompat.to_json(rc)
s_rc = Chef::JSONCompat.from_json(json)
s_rc.should be_a_kind_of(Chef::ResourceCollection)
- s_rc[0].name.should eql(@resource.name)
+ s_rc[0].name.should eql(resource.name)
end
end
describe "provides access to the raw resources array" do
it "returns the resources via the all_resources method" do
- @rc.all_resources.should equal(@rc.instance_variable_get(:@resources))
+ rc.all_resources.should equal(rc.instance_variable_get(:@resource_list).instance_variable_get(:@resources))
end
end
describe "provides access to stepable iterator" do
it "returns the iterator object" do
- @rc.instance_variable_set(:@iterator, :fooboar)
- @rc.iterator.should == :fooboar
+ rc.instance_variable_get(:@resource_list).instance_variable_set(:@iterator, :fooboar)
+ rc.iterator.should == :fooboar
end
end
@@ -319,9 +292,9 @@ describe Chef::ResourceCollection do
def load_up_resources
%w{dog cat monkey}.each do |n|
- @rc << Chef::Resource::ZenMaster.new(n)
+ rc << Chef::Resource::ZenMaster.new(n)
end
- @rc << Chef::Resource::File.new("something")
+ rc << Chef::Resource::File.new("something")
end
end
diff --git a/spec/unit/resource_definition_spec.rb b/spec/unit/resource_definition_spec.rb
index f24254cfce..01e28bf091 100644
--- a/spec/unit/resource_definition_spec.rb
+++ b/spec/unit/resource_definition_spec.rb
@@ -19,24 +19,22 @@
require 'spec_helper'
describe Chef::ResourceDefinition do
- before(:each) do
- @def = Chef::ResourceDefinition.new()
- end
+ let(:defn) { Chef::ResourceDefinition.new() }
describe "initialize" do
it "should be a Chef::ResourceDefinition" do
- @def.should be_a_kind_of(Chef::ResourceDefinition)
+ expect(defn).to be_a_kind_of(Chef::ResourceDefinition)
end
it "should not initialize a new node if one is not provided" do
- @def.node.should eql(nil)
+ expect(defn.node).to eql(nil)
end
it "should accept a node as an argument" do
node = Chef::Node.new
node.name("bobo")
- @def = Chef::ResourceDefinition.new(node)
- @def.node.name.should == "bobo"
+ defn = Chef::ResourceDefinition.new(node)
+ expect(defn.node.name).to eq("bobo")
end
end
@@ -44,76 +42,76 @@ describe Chef::ResourceDefinition do
it "should set the node with node=" do
node = Chef::Node.new
node.name("bobo")
- @def.node = node
- @def.node.name.should == "bobo"
+ defn.node = node
+ expect(defn.node.name).to eq("bobo")
end
it "should return the node" do
- @def.node = Chef::Node.new
- @def.node.should be_a_kind_of(Chef::Node)
+ defn.node = Chef::Node.new
+ expect(defn.node).to be_a_kind_of(Chef::Node)
end
end
it "should accept a new definition with a symbol for a name" do
- lambda {
- @def.define :smoke do
+ expect {
+ defn.define :smoke do
end
- }.should_not raise_error
- lambda {
- @def.define "george washington" do
+ }.not_to raise_error
+ expect {
+ defn.define "george washington" do
end
- }.should raise_error(ArgumentError)
- @def.name.should eql(:smoke)
+ }.to raise_error(ArgumentError)
+ expect(defn.name).to eql(:smoke)
end
it "should accept a new definition with a hash" do
- lambda {
- @def.define :smoke, :cigar => "cuban", :cigarette => "marlboro" do
+ expect {
+ defn.define :smoke, :cigar => "cuban", :cigarette => "marlboro" do
end
- }.should_not raise_error
+ }.not_to raise_error
end
it "should expose the prototype hash params in the params hash" do
- @def.define :smoke, :cigar => "cuban", :cigarette => "marlboro" do; end
- @def.params[:cigar].should eql("cuban")
- @def.params[:cigarette].should eql("marlboro")
+ defn.define :smoke, :cigar => "cuban", :cigarette => "marlboro" do; end
+ expect(defn.params[:cigar]).to eql("cuban")
+ expect(defn.params[:cigarette]).to eql("marlboro")
end
it "should store the block passed to define as a proc under recipe" do
- @def.define :smoke do
+ defn.define :smoke do
"I am what I am"
end
- @def.recipe.should be_a_kind_of(Proc)
- @def.recipe.call.should eql("I am what I am")
+ expect(defn.recipe).to be_a_kind_of(Proc)
+ expect(defn.recipe.call).to eql("I am what I am")
end
it "should set paramaters based on method_missing" do
- @def.mind "to fly"
- @def.params[:mind].should eql("to fly")
+ defn.mind "to fly"
+ expect(defn.params[:mind]).to eql("to fly")
end
it "should raise an exception if prototype_params is not a hash" do
- lambda {
- @def.define :monkey, Array.new do
+ expect {
+ defn.define :monkey, Array.new do
end
- }.should raise_error(ArgumentError)
+ }.to raise_error(ArgumentError)
end
it "should raise an exception if define is called without a block" do
- lambda {
- @def.define :monkey
- }.should raise_error(ArgumentError)
+ expect {
+ defn.define :monkey
+ }.to raise_error(ArgumentError)
end
it "should load a description from a file" do
- @def.from_file(File.join(CHEF_SPEC_DATA, "definitions", "test.rb"))
- @def.name.should eql(:rico_suave)
- @def.params[:rich].should eql("smooth")
+ defn.from_file(File.join(CHEF_SPEC_DATA, "definitions", "test.rb"))
+ expect(defn.name).to eql(:rico_suave)
+ expect(defn.params[:rich]).to eql("smooth")
end
it "should turn itself into a string based on the name with to_s" do
- @def.name = :woot
- @def.to_s.should eql("woot")
+ defn.name = :woot
+ expect(defn.to_s).to eql("woot")
end
end
diff --git a/spec/unit/resource_platform_map_spec.rb b/spec/unit/resource_platform_map_spec.rb
deleted file mode 100644
index 99673d868f..0000000000
--- a/spec/unit/resource_platform_map_spec.rb
+++ /dev/null
@@ -1,164 +0,0 @@
-#
-# Author:: Seth Chisamore (<schisamo@opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'spec_helper'
-
-describe Chef::Resource::PlatformMap do
-
- before(:each) do
- @platform_map = Chef::Resource::PlatformMap.new({
- :windows => {
- "6.1" => {
- :file => "softiefile",
- :else => "thing"
- },
- :default => {
- :file => Chef::Resource::File,
- :ping => "pong",
- :cat => "nice"
- }
- },
- :pop_tron => {
- },
- :default => {
- :soundwave => "lazerbeak",
- :directory => Chef::Resource::Directory,
- }
- })
- end
-
- describe 'filtering the map' do
- it "returns resources for platform and version" do
- pmap = @platform_map.filter("Windows", "6.1")
- pmap.should be_a_kind_of(Hash)
- pmap[:file].should eql("softiefile")
- end
-
- it "returns platform default resources if version does not exist" do
- pmap = @platform_map.filter("windows", "1")
- pmap.should be_a_kind_of(Hash)
- pmap[:file].should eql(Chef::Resource::File)
- end
-
- it "returns global default resources if none exist for plaform" do
- pmap = @platform_map.filter("pop_tron", "1")
- pmap.should be_a_kind_of(Hash)
- pmap[:directory].should eql(Chef::Resource::Directory)
- end
-
- it "returns global default resources if platform does not exist" do
- pmap = @platform_map.filter("BeOS", "1")
- pmap.should be_a_kind_of(Hash)
- pmap[:soundwave].should eql("lazerbeak")
- end
-
- it "returns a merged map of platform version and plaform default resources" do
- pmap = @platform_map.filter("Windows", "6.1")
- pmap[:file].should eql("softiefile")
- pmap[:ping].should eql("pong")
- end
-
- it "returns a merged map of platform specific version and global defaults" do
- pmap = @platform_map.filter("Windows", "6.1")
- pmap[:file].should eql("softiefile")
- pmap[:soundwave].should eql("lazerbeak")
- end
- end
-
- describe 'finding a resource' do
- it "returns a resource for a platform directly by short name" do
- @platform_map.get(:file, "windows", "6.1").should eql("softiefile")
- end
-
- it "returns a default resource if platform and version don't exist" do
- @platform_map.get(:remote_file).should eql(Chef::Resource::RemoteFile)
- end
-
- it "raises an exception if a resource cannot be found" do
- lambda { @platform_map.get(:coffee, "windows", "6.1")}.should raise_error(NameError)
- end
-
- it "returns a resource with a Chef::Resource object" do
- kitty = Chef::Resource::Cat.new("loulou")
- @platform_map.get(kitty, "windows", "6.1").should eql("nice")
- end
- end
-
- describe 'building the map' do
- it "allows passing of a resource map at creation time" do
- @new_map = Chef::Resource::PlatformMap.new({:the_dude => {:default => 'abides'}})
- @new_map.map[:the_dude][:default].should eql("abides")
- end
-
- it "defaults to a resource map with :default key" do
- @new_map = Chef::Resource::PlatformMap.new
- @new_map.map.has_key?(:default)
- end
-
- it "updates the resource map with a map" do
- @platform_map.set(
- :platform => :darwin,
- :version => "9.2.2",
- :short_name => :file,
- :resource => "masterful"
- )
- @platform_map.map[:darwin]["9.2.2"][:file].should eql("masterful")
-
- @platform_map.set(
- :platform => :darwin,
- :short_name => :file,
- :resource => "masterful"
- )
- @platform_map.map[:darwin][:default][:file].should eql("masterful")
-
- @platform_map.set(
- :short_name => :file,
- :resource => "masterful"
- )
- @platform_map.map[:default][:file].should eql("masterful")
-
- @platform_map.set(
- :platform => :hero,
- :version => "9.2.2",
- :short_name => :file,
- :resource => "masterful"
- )
- @platform_map.map[:hero]["9.2.2"][:file].should eql("masterful")
-
- @platform_map.set(
- :short_name => :file,
- :resource => "masterful"
- )
- @platform_map.map[:default][:file].should eql("masterful")
-
- @platform_map.set(
- :short_name => :file,
- :resource => "masterful"
- )
- @platform_map.map[:default][:file].should eql("masterful")
-
- @platform_map.set(
- :platform => :neurosis,
- :short_name => :package,
- :resource => "masterful"
- )
- @platform_map.map[:neurosis][:default][:package].should eql("masterful")
- end
- end
-
-end
diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb
index 692345c943..2163cf181e 100644
--- a/spec/unit/resource_spec.rb
+++ b/spec/unit/resource_spec.rb
@@ -174,12 +174,12 @@ describe Chef::Resource do
end
it "should load the attributes of a prior resource" do
- @resource.load_prior_resource
+ @resource.load_prior_resource(@resource.resource_name, @resource.name)
@resource.supports.should == { :funky => true }
end
it "should not inherit the action from the prior resource" do
- @resource.load_prior_resource
+ @resource.load_prior_resource(@resource.resource_name, @resource.name)
@resource.action.should_not == @prior_resource.action
end
end
@@ -349,7 +349,7 @@ describe Chef::Resource do
:updated_by_last_action, :before, :supports,
:noop, :ignore_failure, :name, :source_line,
:action, :retries, :retry_delay, :elapsed_time,
- :guard_interpreter, :sensitive ]
+ :default_guard_interpreter, :guard_interpreter, :sensitive ]
(hash.keys - expected_keys).should == []
(expected_keys - hash.keys).should == []
hash[:name].should eql("funk")
@@ -394,22 +394,44 @@ describe Chef::Resource do
end
describe "retries" do
+ before do
+ @retriable_resource = Chef::Resource::Cat.new("precious", @run_context)
+ @retriable_resource.provider = Chef::Provider::SnakeOil
+ @retriable_resource.action = :purr
+
+ @node.automatic_attrs[:platform] = "fubuntu"
+ @node.automatic_attrs[:platform_version] = '10.04'
+ end
+
it "should default to not retrying if a provider fails for a resource" do
- @resource.retries.should == 0
+ @retriable_resource.retries.should == 0
end
it "should allow you to set how many retries a provider should attempt after a failure" do
- @resource.retries(2)
- @resource.retries.should == 2
+ @retriable_resource.retries(2)
+ @retriable_resource.retries.should == 2
end
it "should default to a retry delay of 2 seconds" do
- @resource.retry_delay.should == 2
+ @retriable_resource.retry_delay.should == 2
end
it "should allow you to set the retry delay" do
- @resource.retry_delay(10)
- @resource.retry_delay.should == 10
+ @retriable_resource.retry_delay(10)
+ @retriable_resource.retry_delay.should == 10
+ end
+
+ it "should keep given value of retries intact after the provider fails for a resource" do
+ @retriable_resource.retries(3)
+ @retriable_resource.retry_delay(0) # No need to wait.
+
+ provider = Chef::Provider::SnakeOil.new(@retriable_resource, @run_context)
+ Chef::Provider::SnakeOil.stub(:new).and_return(provider)
+ provider.stub(:action_purr).and_raise
+
+ @retriable_resource.should_receive(:sleep).exactly(3).times
+ expect { @retriable_resource.run_action(:purr) }.to raise_error
+ @retriable_resource.retries.should == 3
end
end
@@ -670,24 +692,33 @@ describe Chef::Resource do
describe "building the platform map" do
+ let(:klz) { Class.new(Chef::Resource) }
+
+ before do
+ Chef::Resource::Klz = klz
+ end
+
+ after do
+ Chef::Resource.send(:remove_const, :Klz)
+ end
+
it 'adds mappings for a single platform' do
- klz = Class.new(Chef::Resource)
- Chef::Resource.platform_map.should_receive(:set).with(
- :platform => :autobots, :short_name => :dinobot, :resource => klz
+ expect(Chef::Resource.node_map).to receive(:set).with(
+ :dinobot, Chef::Resource::Klz, { platform: ['autobots'] }
)
- klz.provides :dinobot, :on_platforms => ['autobots']
+ klz.provides :dinobot, platform: ['autobots']
end
it 'adds mappings for multiple platforms' do
- klz = Class.new(Chef::Resource)
- Chef::Resource.platform_map.should_receive(:set).twice
- klz.provides :energy, :on_platforms => ['autobots','decepticons']
+ expect(Chef::Resource.node_map).to receive(:set).with(
+ :energy, Chef::Resource::Klz, { platform: ['autobots', 'decepticons']}
+ )
+ klz.provides :energy, platform: ['autobots', 'decepticons']
end
it 'adds mappings for all platforms' do
- klz = Class.new(Chef::Resource)
- Chef::Resource.platform_map.should_receive(:set).with(
- :short_name => :tape_deck, :resource => klz
+ expect(Chef::Resource.node_map).to receive(:set).with(
+ :tape_deck, Chef::Resource::Klz, {}
)
klz.provides :tape_deck
end
@@ -695,28 +726,26 @@ describe Chef::Resource do
end
describe "lookups from the platform map" do
+ let(:klz1) { Class.new(Chef::Resource) }
+ let(:klz2) { Class.new(Chef::Resource) }
before(:each) do
+ Chef::Resource::Klz1 = klz1
+ Chef::Resource::Klz2 = klz2
@node = Chef::Node.new
@node.name("bumblebee")
@node.automatic[:platform] = "autobots"
@node.automatic[:platform_version] = "6.1"
- Object.const_set('Soundwave', Class.new(Chef::Resource))
- Object.const_set('Grimlock', Class.new(Chef::Resource){ provides :dinobot, :on_platforms => ['autobots'] })
+ Object.const_set('Soundwave', klz1)
+ klz2.provides :dinobot, :on_platforms => ['autobots']
+ Object.const_set('Grimlock', klz2)
end
after(:each) do
Object.send(:remove_const, :Soundwave)
Object.send(:remove_const, :Grimlock)
- end
-
- describe "resource_for_platform" do
- it 'return a resource by short_name and platform' do
- Chef::Resource.resource_for_platform(:dinobot,'autobots','6.1').should eql(Grimlock)
- end
- it "returns a resource by short_name if nothing else matches" do
- Chef::Resource.resource_for_node(:soundwave, @node).should eql(Soundwave)
- end
+ Chef::Resource.send(:remove_const, :Klz1)
+ Chef::Resource.send(:remove_const, :Klz2)
end
describe "resource_for_node" do
diff --git a/spec/unit/rest_spec.rb b/spec/unit/rest_spec.rb
index 424fd12ee9..3047366c47 100644
--- a/spec/unit/rest_spec.rb
+++ b/spec/unit/rest_spec.rb
@@ -62,8 +62,8 @@ describe Chef::REST do
let(:request_id) {"1234"}
let(:rest) do
- Chef::REST::CookieJar.stub(:instance).and_return({})
- Chef::RequestID.instance.stub(:request_id).and_return(request_id)
+ allow(Chef::REST::CookieJar).to receive(:instance).and_return({})
+ allow(Chef::RequestID.instance).to receive(:request_id).and_return(request_id)
rest = Chef::REST.new(base_url, nil, nil)
Chef::REST::CookieJar.instance.clear
rest
@@ -81,9 +81,9 @@ describe Chef::REST do
content_length = middlewares.find_index { |e| e.is_a? Chef::HTTP::ValidateContentLength }
decompressor = middlewares.find_index { |e| e.is_a? Chef::HTTP::Decompressor }
- content_length.should_not be_nil
- decompressor.should_not be_nil
- (decompressor < content_length).should be_true
+ expect(content_length).not_to be_nil
+ expect(decompressor).not_to be_nil
+ expect(decompressor < content_length).to be_true
end
it "should allow the options hash to be frozen" do
@@ -102,43 +102,43 @@ describe Chef::REST do
end
it "makes a :GET request with the composed url object" do
- rest.should_receive(:send_http_request).
+ expect(rest).to receive(:send_http_request).
with(:GET, monkey_uri, standard_read_headers, false).
and_return([1,2,3])
- rest.should_receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3])
- rest.should_receive('success_response?'.to_sym).with(1).and_return(true)
+ expect(rest).to receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3])
+ expect(rest).to receive('success_response?'.to_sym).with(1).and_return(true)
rest.get_rest("monkey")
end
it "makes a :GET reqest for a streaming download with the composed url" do
- rest.should_receive(:streaming_request).with('monkey', {})
+ expect(rest).to receive(:streaming_request).with('monkey', {})
rest.get_rest("monkey", true)
end
it "makes a :DELETE request with the composed url object" do
- rest.should_receive(:send_http_request).
+ expect(rest).to receive(:send_http_request).
with(:DELETE, monkey_uri, standard_read_headers, false).
and_return([1,2,3])
- rest.should_receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3])
- rest.should_receive('success_response?'.to_sym).with(1).and_return(true)
+ expect(rest).to receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3])
+ expect(rest).to receive('success_response?'.to_sym).with(1).and_return(true)
rest.delete_rest("monkey")
end
it "makes a :POST request with the composed url object and data" do
- rest.should_receive(:send_http_request).
+ expect(rest).to receive(:send_http_request).
with(:POST, monkey_uri, standard_write_headers, "\"data\"").
and_return([1,2,3])
- rest.should_receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3])
- rest.should_receive('success_response?'.to_sym).with(1).and_return(true)
+ expect(rest).to receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3])
+ expect(rest).to receive('success_response?'.to_sym).with(1).and_return(true)
rest.post_rest("monkey", "data")
end
it "makes a :PUT request with the composed url object and data" do
- rest.should_receive(:send_http_request).
+ expect(rest).to receive(:send_http_request).
with(:PUT, monkey_uri, standard_write_headers, "\"data\"").
and_return([1,2,3])
- rest.should_receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3])
- rest.should_receive('success_response?'.to_sym).with(1).and_return(true)
+ expect(rest).to receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3])
+ expect(rest).to receive('success_response?'.to_sym).with(1).and_return(true)
rest.put_rest("monkey", "data")
end
end
@@ -162,13 +162,13 @@ describe Chef::REST do
auth_headers = standard_write_headers.merge({"auth_done"=>"yep"})
- rest.authenticator.should_receive(:handle_request).
+ expect(rest.authenticator).to receive(:handle_request).
with(:POST, monkey_uri, standard_write_headers, data).
and_return([:POST, monkey_uri, auth_headers, data])
- rest.should_receive(:send_http_request).
+ expect(rest).to receive(:send_http_request).
with(:POST, monkey_uri, auth_headers, data).
and_return([1,2,3])
- rest.should_receive('success_response?'.to_sym).with(1).and_return(true)
+ expect(rest).to receive('success_response?'.to_sym).with(1).and_return(true)
rest.raw_http_request(:POST, monkey_uri, standard_write_headers, data)
end
@@ -176,10 +176,10 @@ describe Chef::REST do
data = "\"secure data\""
method, uri, auth_headers, d = rest.authenticator.handle_request(:POST, monkey_uri, standard_write_headers, data)
- rest.should_receive(:send_http_request).
+ expect(rest).to receive(:send_http_request).
with(:POST, monkey_uri, auth_headers, data).
and_return([1,2,3])
- rest.should_receive('success_response?'.to_sym).with(1).and_return(true)
+ expect(rest).to receive('success_response?'.to_sym).with(1).and_return(true)
rest.raw_http_request(:POST, monkey_uri, standard_write_headers, data)
end
end
@@ -241,8 +241,8 @@ describe Chef::REST do
let(:http_response) do
http_response = Net::HTTPSuccess.new("1.1", "200", "successful rest req")
- http_response.stub(:read_body)
- http_response.stub(:body).and_return(body)
+ allow(http_response).to receive(:read_body)
+ allow(http_response).to receive(:body).and_return(body)
http_response["Content-Length"] = body.bytesize.to_s
http_response
end
@@ -255,14 +255,14 @@ describe Chef::REST do
let!(:http_client) do
http_client = Net::HTTP.new(url.host, url.port)
- http_client.stub(:request).and_yield(http_response).and_return(http_response)
+ allow(http_client).to receive(:request).and_yield(http_response).and_return(http_response)
http_client
end
let(:rest) do
- Net::HTTP.stub(:new).and_return(http_client)
- Chef::REST::CookieJar.stub(:instance).and_return({})
- Chef::RequestID.instance.stub(:request_id).and_return(request_id)
+ allow(Net::HTTP).to receive(:new).and_return(http_client)
+ allow(Chef::REST::CookieJar).to receive(:instance).and_return({})
+ allow(Chef::RequestID.instance).to receive(:request_id).and_return(request_id)
rest = Chef::REST.new(base_url, nil, nil)
Chef::REST::CookieJar.instance.clear
rest
@@ -300,16 +300,16 @@ describe Chef::REST do
end
before do
- Net::HTTP::Get.stub(:new).and_return(request_mock)
+ allow(Net::HTTP::Get).to receive(:new).and_return(request_mock)
end
it "should always include the X-Chef-Version header" do
- Net::HTTP::Get.should_receive(:new).with("/?foo=bar", base_headers).and_return(request_mock)
+ expect(Net::HTTP::Get).to receive(:new).with("/?foo=bar", base_headers).and_return(request_mock)
rest.request(:GET, url, {})
end
it "should always include the X-Remote-Request-Id header" do
- Net::HTTP::Get.should_receive(:new).with("/?foo=bar", base_headers).and_return(request_mock)
+ expect(Net::HTTP::Get).to receive(:new).with("/?foo=bar", base_headers).and_return(request_mock)
rest.request(:GET, url, {})
end
@@ -323,7 +323,7 @@ describe Chef::REST do
# CHEF-3140
context "when configured to disable compression" do
let(:rest) do
- Net::HTTP.stub(:new).and_return(http_client)
+ allow(Net::HTTP).to receive(:new).and_return(http_client)
Chef::REST.new(base_url, nil, nil, :disable_gzip => true)
end
@@ -334,7 +334,7 @@ describe Chef::REST do
it "does not decompress a response encoded as gzip" do
http_response.add_field("content-encoding", "gzip")
request = Net::HTTP::Get.new(url.path)
- Net::HTTP::Get.should_receive(:new).and_return(request)
+ expect(Net::HTTP::Get).to receive(:new).and_return(request)
# will raise a Zlib error if incorrect
expect(rest.request(:GET, url, {})).to eq("ninja")
end
@@ -359,28 +359,28 @@ describe Chef::REST do
it "should set them on the http request" do
url_string = an_instance_of(String)
header_hash = hash_including(custom_headers)
- Net::HTTP::Get.should_receive(:new).with(url_string, header_hash)
+ expect(Net::HTTP::Get).to receive(:new).with(url_string, header_hash)
rest.request(:GET, url, {})
end
end
context "when setting cookies" do
let(:rest) do
- Net::HTTP.stub(:new).and_return(http_client)
+ allow(Net::HTTP).to receive(:new).and_return(http_client)
Chef::REST::CookieJar.instance["#{url.host}:#{url.port}"] = "cookie monster"
- Chef::RequestID.instance.stub(:request_id).and_return(request_id)
+ allow(Chef::RequestID.instance).to receive(:request_id).and_return(request_id)
rest = Chef::REST.new(base_url, nil, nil)
rest
end
it "should set the cookie for this request if one exists for the given host:port" do
- Net::HTTP::Get.should_receive(:new).with("/?foo=bar", base_headers.merge('Cookie' => "cookie monster")).and_return(request_mock)
+ expect(Net::HTTP::Get).to receive(:new).with("/?foo=bar", base_headers.merge('Cookie' => "cookie monster")).and_return(request_mock)
rest.request(:GET, url, {})
end
end
it "should build a new HTTP GET request" do
- Net::HTTP::Get.should_receive(:new).with("/?foo=bar", base_headers).and_return(request_mock)
+ expect(Net::HTTP::Get).to receive(:new).with("/?foo=bar", base_headers).and_return(request_mock)
rest.request(:GET, url, {})
end
@@ -388,7 +388,7 @@ describe Chef::REST do
request = Net::HTTP::Post.new(url.path)
expected_headers = base_headers.merge("Content-Type" => 'application/json', 'Content-Length' => '13')
- Net::HTTP::Post.should_receive(:new).with("/?foo=bar", expected_headers).and_return(request)
+ expect(Net::HTTP::Post).to receive(:new).with("/?foo=bar", expected_headers).and_return(request)
rest.request(:POST, url, {}, {:one=>:two})
expect(request.body).to eq('{"one":"two"}')
end
@@ -396,13 +396,13 @@ describe Chef::REST do
it "should build a new HTTP PUT request" do
request = Net::HTTP::Put.new(url.path)
expected_headers = base_headers.merge("Content-Type" => 'application/json', 'Content-Length' => '13')
- Net::HTTP::Put.should_receive(:new).with("/?foo=bar",expected_headers).and_return(request)
+ expect(Net::HTTP::Put).to receive(:new).with("/?foo=bar",expected_headers).and_return(request)
rest.request(:PUT, url, {}, {:one=>:two})
expect(request.body).to eq('{"one":"two"}')
end
it "should build a new HTTP DELETE request" do
- Net::HTTP::Delete.should_receive(:new).with("/?foo=bar", base_headers).and_return(request_mock)
+ expect(Net::HTTP::Delete).to receive(:new).with("/?foo=bar", base_headers).and_return(request_mock)
rest.request(:DELETE, url)
end
@@ -440,7 +440,7 @@ describe Chef::REST do
resp_code = Net::HTTPResponse::CODE_TO_OBJ.keys.detect { |k| Net::HTTPResponse::CODE_TO_OBJ[k] == resp_cls }
http_response = Net::HTTPFound.new("1.1", resp_code, "bob is somewhere else again")
http_response.add_field("location", url.path)
- http_response.stub(:read_body)
+ allow(http_response).to receive(:read_body)
http_response
end
it "should call request again" do
@@ -457,7 +457,7 @@ describe Chef::REST do
context "when the response is 304 NotModified" do
let (:http_response) do
http_response = Net::HTTPNotModified.new("1.1", "304", "it's the same as when you asked 5 minutes ago")
- http_response.stub(:read_body)
+ allow(http_response).to receive(:read_body)
http_response
end
@@ -480,13 +480,13 @@ describe Chef::REST do
let(:http_response) do
http_response = Net::HTTPServerError.new("1.1", "500", "drooling from inside of mouth")
http_response.add_field("content-type", "application/json")
- http_response.stub(:body).and_return('{ "error":[ "Ears get sore!", "Not even four" ] }')
- http_response.stub(:read_body)
+ allow(http_response).to receive(:body).and_return('{ "error":[ "Ears get sore!", "Not even four" ] }')
+ allow(http_response).to receive(:read_body)
http_response
end
it "should show the JSON error message" do
- rest.stub(:sleep)
+ allow(rest).to receive(:sleep)
expect {rest.request(:GET, url)}.to raise_error(Net::HTTPFatalError)
expect(log_stringio.string).to match(Regexp.escape('INFO: HTTP Request Returned 500 drooling from inside of mouth: Ears get sore!, Not even four'))
@@ -502,17 +502,21 @@ describe Chef::REST do
gzipped_body = Zlib::Deflate.deflate(unzipped_body)
gzipped_body.force_encoding(Encoding::BINARY) if "strings".respond_to?(:force_encoding)
- http_response.stub(:body).and_return gzipped_body
- http_response.stub(:read_body)
+ allow(http_response).to receive(:body).and_return gzipped_body
+ allow(http_response).to receive(:read_body)
http_response
end
- it "decompresses the JSON error message" do
- rest.stub(:sleep)
- rest.stub(:http_retry_count).and_return(0)
+ before do
+ allow(rest).to receive(:sleep)
+ allow(rest).to receive(:http_retry_count).and_return(0)
+ end
+
+ it "decompresses the JSON error message" do
expect {rest.request(:GET, url)}.to raise_error(Net::HTTPFatalError)
expect(log_stringio.string).to match(Regexp.escape('INFO: HTTP Request Returned 500 drooling from inside of mouth: Ears get sore!, Not even four'))
end
+
it "fails when the compressed body is truncated" do
http_response["Content-Length"] = (body.bytesize + 99).to_s
expect {rest.request(:GET, url)}.to raise_error(Chef::Exceptions::ContentLengthMismatch)
@@ -522,13 +526,13 @@ describe Chef::REST do
context "on a generic unsuccessful request" do
let(:http_response) do
http_response = Net::HTTPServerError.new("1.1", "500", "drooling from inside of mouth")
- http_response.stub(:body)
- http_response.stub(:read_body)
+ allow(http_response).to receive(:body)
+ allow(http_response).to receive(:read_body)
http_response
end
it "retries then throws an exception" do
- rest.stub(:sleep)
+ allow(rest).to receive(:sleep)
expect {rest.request(:GET, url)}.to raise_error(Net::HTTPFatalError)
count = Chef::Config[:http_retry_count]
expect(log_stringio.string).to match(Regexp.escape("ERROR: Server returned error 500 for #{url}, retrying #{count}/#{count}"))
@@ -545,8 +549,8 @@ describe Chef::REST do
let(:http_response) do
http_response = Net::HTTPSuccess.new("1.1",'200', "it-works")
- http_response.stub(:read_body)
- http_response.should_not_receive(:body)
+ allow(http_response).to receive(:read_body)
+ expect(http_response).not_to receive(:body)
http_response["Content-Length"] = "0" # call set_content_length (in test), if otherwise
http_response
end
@@ -560,8 +564,8 @@ describe Chef::REST do
end
before do
- Tempfile.stub(:new).with("chef-rest").and_return(tempfile)
- Net::HTTP::Get.stub(:new).and_return(request_mock)
+ allow(Tempfile).to receive(:new).with("chef-rest").and_return(tempfile)
+ allow(Net::HTTP::Get).to receive(:new).and_return(request_mock)
end
after do
@@ -575,7 +579,7 @@ describe Chef::REST do
'Host' => host_header,
'X-REMOTE-REQUEST-ID'=> request_id
}
- Net::HTTP::Get.should_receive(:new).with("/?foo=bar", expected_headers).and_return(request_mock)
+ expect(Net::HTTP::Get).to receive(:new).with("/?foo=bar", expected_headers).and_return(request_mock)
rest.streaming_request(url, {})
end
@@ -586,7 +590,7 @@ describe Chef::REST do
'Host' => host_header,
'X-REMOTE-REQUEST-ID'=> request_id
}
- Net::HTTP::Get.should_receive(:new).with("/?foo=bar", expected_headers).and_return(request_mock)
+ expect(Net::HTTP::Get).to receive(:new).with("/?foo=bar", expected_headers).and_return(request_mock)
rest.streaming_request(url, {})
end
@@ -595,7 +599,7 @@ describe Chef::REST do
end
it "writes the response body to a tempfile" do
- http_response.stub(:read_body).and_yield("real").and_yield("ultimate").and_yield("power")
+ allow(http_response).to receive(:read_body).and_yield("real").and_yield("ultimate").and_yield("power")
set_content_length
rest.streaming_request(url, {})
expect(IO.read(tempfile.path).chomp).to eq("realultimatepower")
@@ -607,7 +611,7 @@ describe Chef::REST do
end
it "yields the tempfile containing the streamed response body and then unlinks it when given a block" do
- http_response.stub(:read_body).and_yield("real").and_yield("ultimate").and_yield("power")
+ allow(http_response).to receive(:read_body).and_yield("real").and_yield("ultimate").and_yield("power")
set_content_length
tempfile_path = nil
rest.streaming_request(url, {}) do |tempfile|
@@ -620,24 +624,24 @@ describe Chef::REST do
it "does not raise a divide by zero exception if the content's actual size is 0" do
http_response['Content-Length'] = "5"
- http_response.stub(:read_body).and_yield('')
+ allow(http_response).to receive(:read_body).and_yield('')
expect { rest.streaming_request(url, {}) }.to raise_error(Chef::Exceptions::ContentLengthMismatch)
end
it "does not raise a divide by zero exception when the Content-Length is 0" do
http_response['Content-Length'] = "0"
- http_response.stub(:read_body).and_yield("ninja")
+ allow(http_response).to receive(:read_body).and_yield("ninja")
expect { rest.streaming_request(url, {}) }.to raise_error(Chef::Exceptions::ContentLengthMismatch)
end
it "it raises an exception when the download is truncated" do
http_response["Content-Length"] = (body.bytesize + 99).to_s
- http_response.stub(:read_body).and_yield("ninja")
+ allow(http_response).to receive(:read_body).and_yield("ninja")
expect { rest.streaming_request(url, {}) }.to raise_error(Chef::Exceptions::ContentLengthMismatch)
end
it "fetches a file and yields the tempfile it is streamed to" do
- http_response.stub(:read_body).and_yield("real").and_yield("ultimate").and_yield("power")
+ allow(http_response).to receive(:read_body).and_yield("real").and_yield("ultimate").and_yield("power")
set_content_length
tempfile_path = nil
rest.fetch("cookbooks/a_cookbook") do |tempfile|
@@ -650,32 +654,32 @@ describe Chef::REST do
it "closes and unlinks the tempfile if there is an error while streaming the content to the tempfile" do
path = tempfile.path
expect(path).not_to be_nil
- tempfile.stub(:write).and_raise(IOError)
+ allow(tempfile).to receive(:write).and_raise(IOError)
rest.fetch("cookbooks/a_cookbook") {|tmpfile| "shouldn't get here"}
expect(File.exists?(path)).to be_false
end
it "closes and unlinks the tempfile when the response is a redirect" do
tempfile = double("A tempfile", :path => "/tmp/ragefist", :close => true, :binmode => true)
- tempfile.should_receive(:close!).at_least(1).times
- Tempfile.stub(:new).with("chef-rest").and_return(tempfile)
+ expect(tempfile).to receive(:close!).at_least(1).times
+ allow(Tempfile).to receive(:new).with("chef-rest").and_return(tempfile)
redirect = Net::HTTPFound.new("1.1", "302", "bob is taking care of that one for me today")
redirect.add_field("location", url.path)
- redirect.stub(:read_body)
+ allow(redirect).to receive(:read_body)
- http_client.should_receive(:request).and_yield(redirect).and_return(redirect)
- http_client.should_receive(:request).and_yield(http_response).and_return(http_response)
+ expect(http_client).to receive(:request).and_yield(redirect).and_return(redirect)
+ expect(http_client).to receive(:request).and_yield(http_response).and_return(http_response)
rest.fetch("cookbooks/a_cookbook") {|tmpfile| "shouldn't get here"}
end
it "passes the original block to the redirected request" do
http_redirect = Net::HTTPFound.new("1.1", "302", "bob is taking care of that one for me today")
http_redirect.add_field("location","/that-thing-is-here-now")
- http_redirect.stub(:read_body)
+ allow(http_redirect).to receive(:read_body)
block_called = false
- http_client.stub(:request).and_yield(http_response).and_return(http_redirect, http_response)
+ allow(http_client).to receive(:request).and_yield(http_response).and_return(http_redirect, http_response)
rest.fetch("cookbooks/a_cookbook") do |tmpfile|
block_called = true
end
diff --git a/spec/unit/runner_spec.rb b/spec/unit/runner_spec.rb
index 68d8b0e011..9bd4199418 100644
--- a/spec/unit/runner_spec.rb
+++ b/spec/unit/runner_spec.rb
@@ -81,322 +81,329 @@ end
describe Chef::Runner do
- before(:each) do
- @node = Chef::Node.new
- @node.name "latte"
- @node.automatic[:platform] = "mac_os_x"
- @node.automatic[:platform_version] = "10.5.1"
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, Chef::CookbookCollection.new({}), @events)
- @first_resource = Chef::Resource::Cat.new("loulou1", @run_context)
- @run_context.resource_collection << @first_resource
- Chef::Platform.set(
- :resource => :cat,
- :provider => Chef::Provider::SnakeOil
- )
- @runner = Chef::Runner.new(@run_context)
+ let(:node) do
+ node = Chef::Node.new
+ node.name "latte"
+ node.automatic[:platform] = "mac_os_x"
+ node.automatic[:platform_version] = "10.5.1"
+ node
end
- it "should pass each resource in the collection to a provider" do
- @run_context.resource_collection.should_receive(:execute_each_resource).once
- @runner.converge
- end
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:run_context) { Chef::RunContext.new(node, Chef::CookbookCollection.new({}), events) }
+ let(:first_resource) { Chef::Resource::Cat.new("loulou1", run_context) }
+ let(:runner) { Chef::Runner.new(run_context) }
- it "should use the provider specified by the resource (if it has one)" do
- provider = Chef::Provider::Easy.new(@run_context.resource_collection[0], @run_context)
- # Expect provider to be called twice, because will fall back to old provider lookup
- @run_context.resource_collection[0].should_receive(:provider).twice.and_return(Chef::Provider::Easy)
- Chef::Provider::Easy.should_receive(:new).once.and_return(provider)
- @runner.converge
+ before do
+ run_context.resource_collection << first_resource
end
- it "should use the platform provider if it has one" do
- Chef::Platform.should_receive(:find_provider_for_node).once.and_return(Chef::Provider::SnakeOil)
- @runner.converge
- end
+ context "when we fall through to old Chef::Platform resolution" do
+ before do
+ # set up old Chef::Platform resolution instead of provider_resolver
+ Chef::Platform.set(
+ :resource => :cat,
+ :provider => Chef::Provider::SnakeOil
+ )
+ allow(run_context.provider_resolver).to receive(:maybe_dynamic_provider_resolution).with(first_resource, anything()).and_return(nil)
+ end
- it "should run the action for each resource" do
- Chef::Platform.should_receive(:find_provider_for_node).once.and_return(Chef::Provider::SnakeOil)
- provider = Chef::Provider::SnakeOil.new(@run_context.resource_collection[0], @run_context)
- provider.should_receive(:action_sell).once.and_return(true)
- Chef::Provider::SnakeOil.should_receive(:new).once.and_return(provider)
- @runner.converge
+ it "should use the platform provider if it has one" do
+ expect(Chef::Platform).to receive(:find_provider_for_node).with(node, first_resource).and_call_original
+ runner.converge
+ end
end
- it "should raise exceptions as thrown by a provider" do
- provider = Chef::Provider::SnakeOil.new(@run_context.resource_collection[0], @run_context)
- Chef::Provider::SnakeOil.stub(:new).once.and_return(provider)
- provider.stub(:action_sell).once.and_raise(ArgumentError)
- lambda { @runner.converge }.should raise_error(ArgumentError)
- end
+ context "when we are doing dynamic provider resolution" do
- it "should not raise exceptions thrown by providers if the resource has ignore_failure set to true" do
- @run_context.resource_collection[0].stub(:ignore_failure).and_return(true)
- provider = Chef::Provider::SnakeOil.new(@run_context.resource_collection[0], @run_context)
- Chef::Provider::SnakeOil.stub(:new).once.and_return(provider)
- provider.stub(:action_sell).once.and_raise(ArgumentError)
- lambda { @runner.converge }.should_not raise_error
- end
+ it "should pass each resource in the collection to a provider" do
+ expect(run_context.resource_collection).to receive(:execute_each_resource).once
+ runner.converge
+ end
- it "should retry with the specified delay if retries are specified" do
- @first_resource.retries 3
- provider = Chef::Provider::SnakeOil.new(@run_context.resource_collection[0], @run_context)
- Chef::Provider::SnakeOil.stub(:new).once.and_return(provider)
- provider.stub(:action_sell).and_raise(ArgumentError)
- @first_resource.should_receive(:sleep).with(2).exactly(3).times
- lambda { @runner.converge }.should raise_error(ArgumentError)
- end
+ it "should use the provider specified by the resource (if it has one)" do
+ provider = Chef::Provider::Easy.new(run_context.resource_collection[0], run_context)
+ # Expect provider to be called twice, because will fall back to old provider lookup
+ expect(run_context.resource_collection[0]).to receive(:provider).twice.and_return(Chef::Provider::Easy)
+ expect(Chef::Provider::Easy).to receive(:new).once.and_return(provider)
+ runner.converge
+ end
- it "should execute immediate actions on changed resources" do
- notifying_resource = Chef::Resource::Cat.new("peanut", @run_context)
- notifying_resource.action = :purr # only action that will set updated on the resource
+ it "should run the action for each resource" do
+ provider = Chef::Provider::SnakeOil.new(run_context.resource_collection[0], run_context)
+ expect(provider).to receive(:action_sell).once.and_return(true)
+ expect(Chef::Provider::SnakeOil).to receive(:new).once.and_return(provider)
+ runner.converge
+ end
- @run_context.resource_collection << notifying_resource
- @first_resource.action = :nothing # won't be updated unless notified by other resource
+ it "should raise exceptions as thrown by a provider" do
+ provider = Chef::Provider::SnakeOil.new(run_context.resource_collection[0], run_context)
+ allow(Chef::Provider::SnakeOil).to receive(:new).once.and_return(provider)
+ allow(provider).to receive(:action_sell).once.and_raise(ArgumentError)
+ expect { runner.converge }.to raise_error(ArgumentError)
+ end
- notifying_resource.notifies(:purr, @first_resource, :immediately)
+ it "should not raise exceptions thrown by providers if the resource has ignore_failure set to true" do
+ allow(run_context.resource_collection[0]).to receive(:ignore_failure).and_return(true)
+ provider = Chef::Provider::SnakeOil.new(run_context.resource_collection[0], run_context)
+ allow(Chef::Provider::SnakeOil).to receive(:new).once.and_return(provider)
+ allow(provider).to receive(:action_sell).once.and_raise(ArgumentError)
+ expect { runner.converge }.not_to raise_error
+ end
- @runner.converge
+ it "should retry with the specified delay if retries are specified" do
+ first_resource.retries 3
+ provider = Chef::Provider::SnakeOil.new(run_context.resource_collection[0], run_context)
+ allow(Chef::Provider::SnakeOil).to receive(:new).once.and_return(provider)
+ allow(provider).to receive(:action_sell).and_raise(ArgumentError)
+ expect(first_resource).to receive(:sleep).with(2).exactly(3).times
+ expect { runner.converge }.to raise_error(ArgumentError)
+ end
- @first_resource.should be_updated
- end
+ it "should execute immediate actions on changed resources" do
+ notifying_resource = Chef::Resource::Cat.new("peanut", run_context)
+ notifying_resource.action = :purr # only action that will set updated on the resource
- it "should follow a chain of actions" do
- @first_resource.action = :nothing
+ run_context.resource_collection << notifying_resource
+ first_resource.action = :nothing # won't be updated unless notified by other resource
- middle_resource = Chef::Resource::Cat.new("peanut", @run_context)
- middle_resource.action = :nothing
- @run_context.resource_collection << middle_resource
- middle_resource.notifies(:purr, @first_resource, :immediately)
+ notifying_resource.notifies(:purr, first_resource, :immediately)
- last_resource = Chef::Resource::Cat.new("snuffles", @run_context)
- last_resource.action = :purr
- @run_context.resource_collection << last_resource
- last_resource.notifies(:purr, middle_resource, :immediately)
+ runner.converge
- @runner.converge
+ expect(first_resource).to be_updated
+ end
- last_resource.should be_updated # by action(:purr)
- middle_resource.should be_updated # by notification from last_resource
- @first_resource.should be_updated # by notification from middle_resource
- end
+ it "should follow a chain of actions" do
+ first_resource.action = :nothing
- it "should execute delayed actions on changed resources" do
- @first_resource.action = :nothing
- second_resource = Chef::Resource::Cat.new("peanut", @run_context)
- second_resource.action = :purr
+ middle_resource = Chef::Resource::Cat.new("peanut", run_context)
+ middle_resource.action = :nothing
+ run_context.resource_collection << middle_resource
+ middle_resource.notifies(:purr, first_resource, :immediately)
- @run_context.resource_collection << second_resource
- second_resource.notifies(:purr, @first_resource, :delayed)
+ last_resource = Chef::Resource::Cat.new("snuffles", run_context)
+ last_resource.action = :purr
+ run_context.resource_collection << last_resource
+ last_resource.notifies(:purr, middle_resource, :immediately)
- @runner.converge
+ runner.converge
- @first_resource.should be_updated
- end
+ expect(last_resource).to be_updated # by action(:purr)
+ expect(middle_resource).to be_updated # by notification from last_resource
+ expect(first_resource).to be_updated # by notification from middle_resource
+ end
- it "should execute delayed notifications when a failure occurs in the chef client run" do
- @first_resource.action = :nothing
- second_resource = Chef::Resource::Cat.new("peanut", @run_context)
- second_resource.action = :purr
+ it "should execute delayed actions on changed resources" do
+ first_resource.action = :nothing
+ second_resource = Chef::Resource::Cat.new("peanut", run_context)
+ second_resource.action = :purr
- @run_context.resource_collection << second_resource
- second_resource.notifies(:purr, @first_resource, :delayed)
+ run_context.resource_collection << second_resource
+ second_resource.notifies(:purr, first_resource, :delayed)
- third_resource = FailureResource.new("explode", @run_context)
- @run_context.resource_collection << third_resource
+ runner.converge
- lambda {@runner.converge}.should raise_error(FailureProvider::ChefClientFail)
+ expect(first_resource).to be_updated
+ end
- @first_resource.should be_updated
- end
+ it "should execute delayed notifications when a failure occurs in the chef client run" do
+ first_resource.action = :nothing
+ second_resource = Chef::Resource::Cat.new("peanut", run_context)
+ second_resource.action = :purr
- it "should execute delayed notifications when a failure occurs in a notification" do
- @first_resource.action = :nothing
- second_resource = Chef::Resource::Cat.new("peanut", @run_context)
- second_resource.action = :purr
+ run_context.resource_collection << second_resource
+ second_resource.notifies(:purr, first_resource, :delayed)
- @run_context.resource_collection << second_resource
+ third_resource = FailureResource.new("explode", run_context)
+ run_context.resource_collection << third_resource
- third_resource = FailureResource.new("explode", @run_context)
- third_resource.action = :nothing
- @run_context.resource_collection << third_resource
+ expect { runner.converge }.to raise_error(FailureProvider::ChefClientFail)
- second_resource.notifies(:fail, third_resource, :delayed)
- second_resource.notifies(:purr, @first_resource, :delayed)
+ expect(first_resource).to be_updated
+ end
- lambda {@runner.converge}.should raise_error(FailureProvider::ChefClientFail)
+ it "should execute delayed notifications when a failure occurs in a notification" do
+ first_resource.action = :nothing
+ second_resource = Chef::Resource::Cat.new("peanut", run_context)
+ second_resource.action = :purr
- @first_resource.should be_updated
- end
+ run_context.resource_collection << second_resource
- it "should execute delayed notifications when a failure occurs in multiple notifications" do
- @first_resource.action = :nothing
- second_resource = Chef::Resource::Cat.new("peanut", @run_context)
- second_resource.action = :purr
+ third_resource = FailureResource.new("explode", run_context)
+ third_resource.action = :nothing
+ run_context.resource_collection << third_resource
- @run_context.resource_collection << second_resource
+ second_resource.notifies(:fail, third_resource, :delayed)
+ second_resource.notifies(:purr, first_resource, :delayed)
- third_resource = FailureResource.new("explode", @run_context)
- third_resource.action = :nothing
- @run_context.resource_collection << third_resource
+ expect {runner.converge}.to raise_error(FailureProvider::ChefClientFail)
- fourth_resource = FailureResource.new("explode again", @run_context)
- fourth_resource.action = :nothing
- @run_context.resource_collection << fourth_resource
+ expect(first_resource).to be_updated
+ end
- second_resource.notifies(:fail, third_resource, :delayed)
- second_resource.notifies(:fail, fourth_resource, :delayed)
- second_resource.notifies(:purr, @first_resource, :delayed)
+ it "should execute delayed notifications when a failure occurs in multiple notifications" do
+ first_resource.action = :nothing
+ second_resource = Chef::Resource::Cat.new("peanut", run_context)
+ second_resource.action = :purr
- exception = nil
- begin
- @runner.converge
- rescue => e
- exception = e
- end
- exception.should be_a(Chef::Exceptions::MultipleFailures)
+ run_context.resource_collection << second_resource
+
+ third_resource = FailureResource.new("explode", run_context)
+ third_resource.action = :nothing
+ run_context.resource_collection << third_resource
+
+ fourth_resource = FailureResource.new("explode again", run_context)
+ fourth_resource.action = :nothing
+ run_context.resource_collection << fourth_resource
+
+ second_resource.notifies(:fail, third_resource, :delayed)
+ second_resource.notifies(:fail, fourth_resource, :delayed)
+ second_resource.notifies(:purr, first_resource, :delayed)
+
+ exception = nil
+ begin
+ runner.converge
+ rescue => e
+ exception = e
+ end
+ expect(exception).to be_a(Chef::Exceptions::MultipleFailures)
- expected_message =<<-E
+ expected_message =<<-E
Multiple failures occurred:
* FailureProvider::ChefClientFail occurred in delayed notification: [explode] (dynamically defined) had an error: FailureProvider::ChefClientFail: chef had an error of some sort
* FailureProvider::ChefClientFail occurred in delayed notification: [explode again] (dynamically defined) had an error: FailureProvider::ChefClientFail: chef had an error of some sort
-E
- exception.message.should == expected_message
+ E
+ expect(exception.message).to eq(expected_message)
- @first_resource.should be_updated
- end
-
- it "does not duplicate delayed notifications" do
- SnitchyProvider.clear_action_record
-
- Chef::Platform.set(
- :resource => :cat,
- :provider => SnitchyProvider
- )
+ expect(first_resource).to be_updated
+ end
- @first_resource.action = :nothing
+ it "does not duplicate delayed notifications" do
+ SnitchyProvider.clear_action_record
- second_resource = Chef::Resource::Cat.new("peanut", @run_context)
- second_resource.action = :first_action
- @run_context.resource_collection << second_resource
+ first_resource.action = :nothing
+ first_resource.provider = SnitchyProvider
- third_resource = Chef::Resource::Cat.new("snickers", @run_context)
- third_resource.action = :first_action
- @run_context.resource_collection << third_resource
+ second_resource = Chef::Resource::Cat.new("peanut", run_context)
+ second_resource.action = :first_action
+ second_resource.provider = SnitchyProvider
+ run_context.resource_collection << second_resource
- second_resource.notifies(:second_action, @first_resource, :delayed)
- second_resource.notifies(:third_action, @first_resource, :delayed)
+ third_resource = Chef::Resource::Cat.new("snickers", run_context)
+ third_resource.action = :first_action
+ third_resource.provider = SnitchyProvider
+ run_context.resource_collection << third_resource
- third_resource.notifies(:second_action, @first_resource, :delayed)
- third_resource.notifies(:third_action, @first_resource, :delayed)
+ second_resource.notifies(:second_action, first_resource, :delayed)
+ second_resource.notifies(:third_action, first_resource, :delayed)
- @runner.converge
- # resources 2 and 3 call :first_action in the course of normal resource
- # execution, and schedule delayed actions :second and :third on the first
- # resource. The duplicate actions should "collapse" to a single notification
- # and order should be preserved.
- SnitchyProvider.all_actions_called.should == [:first, :first, :second, :third]
- end
+ third_resource.notifies(:second_action, first_resource, :delayed)
+ third_resource.notifies(:third_action, first_resource, :delayed)
- it "executes delayed notifications in the order they were declared" do
- SnitchyProvider.clear_action_record
+ runner.converge
+ # resources 2 and 3 call :first_action in the course of normal resource
+ # execution, and schedule delayed actions :second and :third on the first
+ # resource. The duplicate actions should "collapse" to a single notification
+ # and order should be preserved.
+ expect(SnitchyProvider.all_actions_called).to eq([:first, :first, :second, :third])
+ end
- Chef::Platform.set(
- :resource => :cat,
- :provider => SnitchyProvider
- )
+ it "executes delayed notifications in the order they were declared" do
+ SnitchyProvider.clear_action_record
- @first_resource.action = :nothing
+ first_resource.action = :nothing
+ first_resource.provider = SnitchyProvider
- second_resource = Chef::Resource::Cat.new("peanut", @run_context)
- second_resource.action = :first_action
- @run_context.resource_collection << second_resource
+ second_resource = Chef::Resource::Cat.new("peanut", run_context)
+ second_resource.action = :first_action
+ second_resource.provider = SnitchyProvider
+ run_context.resource_collection << second_resource
- third_resource = Chef::Resource::Cat.new("snickers", @run_context)
- third_resource.action = :first_action
- @run_context.resource_collection << third_resource
+ third_resource = Chef::Resource::Cat.new("snickers", run_context)
+ third_resource.action = :first_action
+ third_resource.provider = SnitchyProvider
+ run_context.resource_collection << third_resource
- second_resource.notifies(:second_action, @first_resource, :delayed)
- second_resource.notifies(:second_action, @first_resource, :delayed)
+ second_resource.notifies(:second_action, first_resource, :delayed)
+ second_resource.notifies(:second_action, first_resource, :delayed)
- third_resource.notifies(:third_action, @first_resource, :delayed)
- third_resource.notifies(:third_action, @first_resource, :delayed)
+ third_resource.notifies(:third_action, first_resource, :delayed)
+ third_resource.notifies(:third_action, first_resource, :delayed)
- @runner.converge
- SnitchyProvider.all_actions_called.should == [:first, :first, :second, :third]
- end
+ runner.converge
+ expect(SnitchyProvider.all_actions_called).to eq([:first, :first, :second, :third])
+ end
- it "does not fire notifications if the resource was not updated by the last action executed" do
- # REGRESSION TEST FOR CHEF-1452
- SnitchyProvider.clear_action_record
+ it "does not fire notifications if the resource was not updated by the last action executed" do
+ # REGRESSION TEST FOR CHEF-1452
+ SnitchyProvider.clear_action_record
- Chef::Platform.set(
- :resource => :cat,
- :provider => SnitchyProvider
- )
+ first_resource.action = :first_action
+ first_resource.provider = SnitchyProvider
- @first_resource.action = :first_action
+ second_resource = Chef::Resource::Cat.new("peanut", run_context)
+ second_resource.action = :nothing
+ second_resource.provider = SnitchyProvider
+ run_context.resource_collection << second_resource
- second_resource = Chef::Resource::Cat.new("peanut", @run_context)
- second_resource.action = :nothing
- @run_context.resource_collection << second_resource
+ third_resource = Chef::Resource::Cat.new("snickers", run_context)
+ third_resource.action = :nothing
+ third_resource.provider = SnitchyProvider
+ run_context.resource_collection << third_resource
- third_resource = Chef::Resource::Cat.new("snickers", @run_context)
- third_resource.action = :nothing
- @run_context.resource_collection << third_resource
+ first_resource.notifies(:second_action, second_resource, :immediately)
+ second_resource.notifies(:third_action, third_resource, :immediately)
- @first_resource.notifies(:second_action, second_resource, :immediately)
- second_resource.notifies(:third_action, third_resource, :immediately)
+ runner.converge
- @runner.converge
+ # All of the resources should only fire once:
+ expect(SnitchyProvider.all_actions_called).to eq([:first, :second, :third])
- # All of the resources should only fire once:
- SnitchyProvider.all_actions_called.should == [:first, :second, :third]
+ # all of the resources should be marked as updated for reporting purposes
+ expect(first_resource).to be_updated
+ expect(second_resource).to be_updated
+ expect(third_resource).to be_updated
+ end
- # all of the resources should be marked as updated for reporting purposes
- @first_resource.should be_updated
- second_resource.should be_updated
- third_resource.should be_updated
- end
+ it "should check a resource's only_if and not_if if notified by another resource" do
+ first_resource.action = :buy
- it "should check a resource's only_if and not_if if notified by another resource" do
- @first_resource.action = :buy
+ only_if_called_times = 0
+ first_resource.only_if {only_if_called_times += 1; true}
- only_if_called_times = 0
- @first_resource.only_if {only_if_called_times += 1; true}
+ not_if_called_times = 0
+ first_resource.not_if {not_if_called_times += 1; false}
- not_if_called_times = 0
- @first_resource.not_if {not_if_called_times += 1; false}
+ second_resource = Chef::Resource::Cat.new("carmel", run_context)
+ run_context.resource_collection << second_resource
+ second_resource.notifies(:purr, first_resource, :delayed)
+ second_resource.action = :purr
- second_resource = Chef::Resource::Cat.new("carmel", @run_context)
- @run_context.resource_collection << second_resource
- second_resource.notifies(:purr, @first_resource, :delayed)
- second_resource.action = :purr
+ # hits only_if first time when the resource is run in order, second on notify
+ runner.converge
- # hits only_if first time when the resource is run in order, second on notify
- @runner.converge
+ expect(only_if_called_times).to eq(2)
+ expect(not_if_called_times).to eq(2)
+ end
- only_if_called_times.should == 2
- not_if_called_times.should == 2
- end
+ it "should resolve resource references in notifications when resources are defined lazily" do
+ first_resource.action = :nothing
- it "should resolve resource references in notifications when resources are defined lazily" do
- @first_resource.action = :nothing
+ lazy_resources = lambda {
+ last_resource = Chef::Resource::Cat.new("peanut", run_context)
+ run_context.resource_collection << last_resource
+ last_resource.notifies(:purr, first_resource.to_s, :delayed)
+ last_resource.action = :purr
+ }
+ second_resource = Chef::Resource::RubyBlock.new("myblock", run_context)
+ run_context.resource_collection << second_resource
+ second_resource.block { lazy_resources.call }
- lazy_resources = lambda {
- last_resource = Chef::Resource::Cat.new("peanut", @run_context)
- @run_context.resource_collection << last_resource
- last_resource.notifies(:purr, @first_resource.to_s, :delayed)
- last_resource.action = :purr
- }
- second_resource = Chef::Resource::RubyBlock.new("myblock", @run_context)
- @run_context.resource_collection << second_resource
- second_resource.block { lazy_resources.call }
+ runner.converge
- @runner.converge
+ expect(first_resource).to be_updated
+ end
- @first_resource.should be_updated
end
-
end
-
diff --git a/spec/unit/shell/shell_ext_spec.rb b/spec/unit/shell/shell_ext_spec.rb
index c24acbca3e..8485b66d23 100644
--- a/spec/unit/shell/shell_ext_spec.rb
+++ b/spec/unit/shell/shell_ext_spec.rb
@@ -121,7 +121,7 @@ describe Shell::Extensions do
Shell.session.stub(:rebuild_context)
events = Chef::EventDispatch::Dispatcher.new
run_context = Chef::RunContext.new(Chef::Node.new, {}, events)
- run_context.resource_collection.instance_variable_set(:@iterator, :the_iterator)
+ run_context.resource_collection.instance_variable_get(:@resource_list).instance_variable_set(:@iterator, :the_iterator)
Shell.session.run_context = run_context
@root_context.chef_run.should == :the_iterator
end
diff --git a/spec/unit/util/dsc/local_configuration_manager_spec.rb b/spec/unit/util/dsc/local_configuration_manager_spec.rb
index fb6664bd40..eb27e9e94e 100644
--- a/spec/unit/util/dsc/local_configuration_manager_spec.rb
+++ b/spec/unit/util/dsc/local_configuration_manager_spec.rb
@@ -32,7 +32,7 @@ EOH
}
let(:no_whatif_lcm_output) { <<-EOH
-Start-DscConfiguration : A parameter cannot be found that matches parameter name 'whatif'.
+Start-DscConfiguration : A parameter cannot be found\r\n that matches parameter name 'whatif'.
At line:1 char:123
+ run-somecommand -whatif
+ ~~~~~~~~
@@ -77,8 +77,13 @@ EOH
let(:lcm_standard_error) { no_whatif_lcm_output }
let(:lcm_cmdlet_success) { false }
+ it 'returns true when passed to #whatif_not_supported?' do
+ expect(lcm.send(:whatif_not_supported?, no_whatif_lcm_output)).to be_true
+ end
+
it 'should should return a (possibly empty) array of ResourceInfo instances' do
expect(Chef::Log).to receive(:warn)
+ expect(lcm).to receive(:whatif_not_supported?).and_call_original
test_configuration_result = nil
expect {test_configuration_result = lcm.test_configuration('config')}.not_to raise_error
expect(test_configuration_result.class).to be(Array)
@@ -92,7 +97,7 @@ EOH
it 'should log a warning if the message is formatted as expected when a resource import failure occurs' do
expect(Chef::Log).to receive(:warn)
- expect(lcm).to receive(:output_has_dsc_module_failure?).and_call_original
+ expect(lcm).to receive(:dsc_module_import_failure?).and_call_original
test_configuration_result = nil
expect {test_configuration_result = lcm.test_configuration('config')}.not_to raise_error
end
@@ -105,29 +110,29 @@ EOH
end
end
- context 'that fails due to an PowerShell cmdlet error that cannot be handled' do
+ context 'that fails due to an unknown PowerShell cmdlet error' do
let(:lcm_standard_output) { 'some output' }
let(:lcm_standard_error) { 'Abort, Retry, Fail?' }
let(:lcm_cmdlet_success) { false }
- it 'should raise a Chef::Exceptions::PowershellCmdletException' do
- expect(Chef::Log).not_to receive(:warn)
- expect(lcm).to receive(:output_has_dsc_module_failure?).and_call_original
- expect {lcm.test_configuration('config')}.to raise_error(Chef::Exceptions::PowershellCmdletException)
+ it 'should log a warning' do
+ expect(Chef::Log).to receive(:warn)
+ expect(lcm).to receive(:dsc_module_import_failure?).and_call_original
+ expect {lcm.test_configuration('config')}.not_to raise_error
end
end
end
it 'should identify a correctly formatted error message as a resource import failure' do
- expect(lcm.send(:output_has_dsc_module_failure?, dsc_resource_import_failure_output)).to be(true)
+ expect(lcm.send(:dsc_module_import_failure?, dsc_resource_import_failure_output)).to be(true)
end
it 'should not identify an incorrectly formatted error message as a resource import failure' do
- expect(lcm.send(:output_has_dsc_module_failure?, dsc_resource_import_failure_output.gsub('module', 'gibberish'))).to be(false)
+ expect(lcm.send(:dsc_module_import_failure?, dsc_resource_import_failure_output.gsub('module', 'gibberish'))).to be(false)
end
it 'should not identify a message without a CimException reference as a resource import failure' do
- expect(lcm.send(:output_has_dsc_module_failure?, dsc_resource_import_failure_output.gsub('CimException', 'ArgumentException'))).to be(false)
+ expect(lcm.send(:dsc_module_import_failure?, dsc_resource_import_failure_output.gsub('CimException', 'ArgumentException'))).to be(false)
end
end
end