summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml1
-rw-r--r--CHANGELOG.md19
-rw-r--r--RELEASE_NOTES.md72
-rw-r--r--chef.gemspec4
-rw-r--r--lib/chef/chef_fs/file_system/cookbooks_dir.rb4
-rw-r--r--lib/chef/config.rb26
-rw-r--r--lib/chef/cookbook/file_system_file_vendor.rb3
-rw-r--r--lib/chef/cookbook/file_vendor.rb32
-rw-r--r--lib/chef/cookbook/remote_file_vendor.rb3
-rw-r--r--lib/chef/cookbook/synchronizer.rb58
-rw-r--r--lib/chef/cookbook_uploader.rb31
-rw-r--r--lib/chef/cookbook_version.rb1
-rw-r--r--lib/chef/dsl/recipe.rb1
-rw-r--r--lib/chef/file_content_management/tempfile.rb9
-rw-r--r--lib/chef/formatters/base.rb7
-rw-r--r--lib/chef/http/json_input.rb13
-rw-r--r--lib/chef/knife/cookbook_site_share.rb2
-rw-r--r--lib/chef/knife/cookbook_upload.rb4
-rw-r--r--lib/chef/knife/core/ui.rb15
-rw-r--r--lib/chef/policy_builder/expand_node_object.rb7
-rw-r--r--lib/chef/policy_builder/policyfile.rb5
-rw-r--r--lib/chef/provider.rb2
-rw-r--r--lib/chef/provider/cookbook_file.rb1
-rw-r--r--lib/chef/provider/deploy.rb1
-rw-r--r--lib/chef/provider/execute.rb3
-rw-r--r--lib/chef/provider/file.rb3
-rw-r--r--lib/chef/provider/git.rb6
-rw-r--r--lib/chef/provider/group/gpasswd.rb3
-rw-r--r--lib/chef/provider/group/groupmod.rb4
-rw-r--r--lib/chef/provider/group/suse.rb3
-rw-r--r--lib/chef/provider/group/usermod.rb3
-rw-r--r--lib/chef/provider/http_request.rb8
-rw-r--r--lib/chef/provider/link.rb2
-rw-r--r--lib/chef/provider/log.rb19
-rw-r--r--lib/chef/provider/mdadm.rb3
-rw-r--r--lib/chef/provider/mount/mount.rb2
-rw-r--r--lib/chef/provider/mount/solaris.rb2
-rw-r--r--lib/chef/provider/package.rb1
-rw-r--r--lib/chef/provider/package/apt.rb3
-rw-r--r--lib/chef/provider/package/easy_install.rb4
-rw-r--r--lib/chef/provider/package/freebsd/base.rb3
-rw-r--r--lib/chef/provider/package/freebsd/pkgng.rb2
-rw-r--r--lib/chef/provider/package/freebsd/port.rb2
-rw-r--r--lib/chef/provider/package/ips.rb3
-rw-r--r--lib/chef/provider/package/paludis.rb5
-rw-r--r--lib/chef/provider/package/portage.rb2
-rw-r--r--lib/chef/provider/package/rpm.rb2
-rw-r--r--lib/chef/provider/package/rubygems.rb2
-rw-r--r--lib/chef/provider/package/smartos.rb3
-rw-r--r--lib/chef/provider/package/windows/msi.rb2
-rw-r--r--lib/chef/provider/package/yum.rb4
-rw-r--r--lib/chef/provider/package/zypper.rb3
-rw-r--r--lib/chef/provider/registry_key.rb2
-rw-r--r--lib/chef/provider/remote_directory.rb1
-rw-r--r--lib/chef/provider/remote_file.rb1
-rw-r--r--lib/chef/provider/remote_file/cache_control_data.rb2
-rw-r--r--lib/chef/provider/remote_file/fetcher.rb2
-rw-r--r--lib/chef/provider/remote_file/ftp.rb1
-rw-r--r--lib/chef/provider/resource_update.rb3
-rw-r--r--lib/chef/provider/service/freebsd.rb3
-rw-r--r--lib/chef/provider/service/init.rb3
-rw-r--r--lib/chef/provider/service/macosx.rb1
-rw-r--r--lib/chef/provider/service/redhat.rb2
-rw-r--r--lib/chef/provider/service/simple.rb3
-rw-r--r--lib/chef/provider/service/solaris.rb3
-rw-r--r--lib/chef/provider/service/systemd.rb1
-rw-r--r--lib/chef/provider/service/windows.rb3
-rw-r--r--lib/chef/provider/subversion.rb2
-rw-r--r--lib/chef/provider/template.rb2
-rw-r--r--lib/chef/provider/template/content.rb1
-rw-r--r--lib/chef/provider/user/dscl.rb2
-rw-r--r--lib/chef/provider/user/solaris.rb1
-rw-r--r--lib/chef/provider/user/useradd.rb3
-rw-r--r--lib/chef/resource/lwrp_base.rb13
-rw-r--r--lib/chef/shell/shell_session.rb4
-rw-r--r--lib/chef/streaming_cookbook_uploader.rb205
-rw-r--r--lib/chef/tasks/chef_repo.rake395
-rw-r--r--pedant.gemfile4
-rw-r--r--spec/functional/resource/base.rb10
-rw-r--r--spec/functional/resource/cookbook_file_spec.rb2
-rw-r--r--spec/functional/resource/package_spec.rb4
-rw-r--r--spec/functional/resource/remote_directory_spec.rb2
-rw-r--r--spec/functional/resource/template_spec.rb2
-rw-r--r--spec/integration/knife/chef_fs_data_store_spec.rb4
-rw-r--r--spec/support/platform_helpers.rb5
-rw-r--r--spec/unit/cookbook/file_vendor_spec.rb78
-rw-r--r--spec/unit/cookbook/synchronizer_spec.rb667
-rw-r--r--spec/unit/cookbook_uploader_spec.rb160
-rw-r--r--spec/unit/dsl/recipe_spec.rb12
-rw-r--r--spec/unit/formatters/base_spec.rb48
-rw-r--r--spec/unit/http/json_input_spec.rb128
-rw-r--r--spec/unit/knife/client_create_spec.rb6
-rw-r--r--spec/unit/knife/configure_client_spec.rb11
-rw-r--r--spec/unit/knife/cookbook_delete_spec.rb2
-rw-r--r--spec/unit/knife/cookbook_download_spec.rb10
-rw-r--r--spec/unit/knife/cookbook_metadata_spec.rb2
-rw-r--r--spec/unit/knife/cookbook_site_download_spec.rb20
-rw-r--r--spec/unit/knife/cookbook_site_share_spec.rb4
-rw-r--r--spec/unit/knife/cookbook_upload_spec.rb5
-rw-r--r--spec/unit/knife/tag_create_spec.rb6
-rw-r--r--spec/unit/knife/tag_delete_spec.rb6
-rw-r--r--spec/unit/knife/user_create_spec.rb2
-rw-r--r--spec/unit/knife_spec.rb28
-rw-r--r--spec/unit/lwrp_spec.rb13
-rw-r--r--spec/unit/mixin/template_spec.rb2
-rw-r--r--spec/unit/provider/http_request_spec.rb16
-rw-r--r--spec/unit/provider/log_spec.rb18
-rw-r--r--spec/unit/provider/package_spec.rb2
-rw-r--r--spec/unit/provider/remote_directory_spec.rb2
-rw-r--r--spec/unit/provider/template/content_spec.rb2
-rw-r--r--spec/unit/provider_spec.rb12
-rw-r--r--spec/unit/shell/shell_session_spec.rb2
112 files changed, 1381 insertions, 998 deletions
diff --git a/.travis.yml b/.travis.yml
index 5c45a016b6..f1146a4aaa 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,7 +13,6 @@ before_install:
matrix:
include:
- - rvm: 1.8.7-p374
- rvm: 1.9.3
- rvm: 2.0.0
- rvm: 2.1.1
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 387ef8912a..ce47b3e752 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,12 +1,31 @@
# Chef Client Changelog
## Unreleased:
+
+* Fix a bug in the experimental Policyfile mode that caused errors when
+ using templates.
+* Disable JSON encoding of request body when non-JSON content type is
+ specified.
+* Clean up FileVendor and CookbookUploader internal APIs
* [**Vasiliy Tolstov**](https://github.com/vtolstov):
Reload systemd service only if it's running, otherwise start.
+* [**Chris Jerdonek**](https://github.com/cjerdonek):
+ knife diagnostic messages sent to stdout instead of stderr
+* [**Xabier de Zuazo**](https://github.com/zuazo):
+ Remove the unused StreamingCookbookUploader class (CHEF-4586)
+* http_request no longer appends "?message=" query string to GET and HEAD requests
+* added shell_out commands directly to the recipe DSL
+* cookbook synchronizer deletes old files from cookbooks
+* do not clear file cache when override run list is set (CHEF-3684)
+* ruby 1.8.7/1.9.1/1.9.2 support is dropped
+* set no_lazy_load to true (CHEF-4961)
+* set file_stating_uses_destdir config option default to true (CHEF-5040)
* remove dependency on rest-client gem
* Add method shell_out_with_systems_locale to ShellOut.
* Fix knife cookbook site share on windows (CHEF-4994)
+* chef-repo rake tasks are deprecated; print relevant information for
+ each one.
## Last Release: 11.14.0
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index f05b99e09e..b1da138bd8 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,54 @@
# Chef Client Release Notes:
+## http_request resource no longer appends query string
+
+Previously the http_request GET and HEAD requests appended a hard-coded "?message=resource_name"
+query parameter that could not be overridden. That feature has been dropped. Cookbooks that
+actually relied on that should manually add the message query string to the URL they pass to
+the resource.
+
+## Added Chef::Mixin::ShellOut methods to Recipe DSL
+
+Added the ability to use shell_out, shell_out! and shell_out_with_systems_locale in the Recipe
+DSL without needing to explicitly extend/include the mixin.
+
+## Cookbook Synchronizer Cleans Deleted Files
+
+At the start of the Chef client run any files which are in active cookbooks, but are no longer in the
+manifest for the cookbook will be deleted from the cookbook file cache.
+
+## When given an override run list Chef does not clean the file_cache
+
+In order to avoid redownloading the file_cache for all the cookbooks and files that are skipped when an
+override run list is used, when an override run list is set the file cache is not cleaned at all.
+
+## Dropped Support For Ruby 1.8.7/1.9.1/1.9.2
+
+Ruby 1.8.7, 1.9.1 and 1.9.2 are no longer supported.
+
+## Changed no_lazy_load config default to True
+
+Previously the default behavior of chef-client was lazily synchronize cookbook files and templates as
+they were actually used. With this setting being true, all the files and templates in a cookbook will
+be synchronized at the beginning of the chef-client run. This avoids the problem where time-sensitive
+URLs in the cookbook manifest may timeout before the `cookbook_file` or `template` resource is actually
+converged. Many users find the lazy behavior confusing as well and expect that the cookbook should
+be fully synchronized at the start.
+
+Some users who distribute large files via cookbooks may see performance issues with this turned on. They
+should disable the setting and go back to the old lazy behavior, or else refactor how they are doing
+file distribution (using `remote_file` to download artifacts from S3 or a similar service is usually a
+better approach, or individual large artifacts could be encapsulated into individual different cookbooks).
+
+## Changed file_staging_uses_destdir config default to True
+
+Staging into the system's tempdir (usually /tmp or /var/tmp) rather than the destination directory can
+cause issues with permissions or available space. It can also become problematic when doing cross-devices
+renames which turn move operations into copy operations (using mv uses a new inode on Unix which avoids
+ETXTBSY exceptions, while cp reuses the inode and can raise that error). Staging the tempfile for the
+Chef file providers into the destination directory solve these problems for users. Windows ACLs on the
+directory will also be inherited correctly.
+
## Removed Rest-Client dependency
- cookbooks that previously were able to use rest-client directly will now need to install it via `chef_gem "rest-client"`.
@@ -10,3 +59,26 @@
- to avoid crashes, by default, Chef will now scan a port range and take the first available port from 8889-9999.
- to change this behavior, you can pass --chef-zero-port=PORT_RANGE (for example, 10,20,30 or 10000-20000) or modify Chef::Config.chef_zero.port to be a port string, an enumerable of ports, or a single port number.
+
+## Knife now logs to stderr
+
+Informational messages from knife are now sent to stderr, allowing you to pipe the output of knife to other commands without having to filter these messages out.
+
+# Internal API Changes in this Release
+
+These changes do not impact any cookbook code, but may impact tools that
+use the code base as a library. Authors of tools that rely on Chef
+internals should review these changes carefully and update their
+applications.
+
+## Changes to CookbookUpload
+
+`Chef::CookbookUpload.new` previously took a path as the second
+argument, but due to internal changes, this parameter was not used, and
+it has been removed. See: https://github.com/opscode/chef/commit/12c9bed3a5a7ab86ff78cb660d96f8b77ad6395d
+
+## Changes to FileVendor
+
+`Chef::Cookbook::FileVendor` was previously configured by passing a
+block to the `on_create` method; it is now configured by calling either
+`fetch_from_remote` or `fetch_from_disk`. See: https://github.com/opscode/chef/commit/3b2b4de8e7f0d55524f2a0ccaf3e1aa9f2d371eb
diff --git a/chef.gemspec b/chef.gemspec
index c171bda880..2bbabbc3f2 100644
--- a/chef.gemspec
+++ b/chef.gemspec
@@ -12,12 +12,14 @@ Gem::Specification.new do |s|
s.email = "adam@getchef.com"
s.homepage = "http://www.getchef.com"
+ s.required_ruby_version = ">= 1.9.3"
+
s.add_dependency "mixlib-config", "~> 2.0"
s.add_dependency "mixlib-cli", "~> 1.4"
s.add_dependency "mixlib-log", "~> 1.3"
s.add_dependency "mixlib-authentication", "~> 1.3"
s.add_dependency "mixlib-shellout", "~> 1.4"
- s.add_dependency "ohai", "= 7.2.0.rc.1"
+ s.add_dependency "ohai", "~> 7.2"
s.add_dependency "ffi-yajl", "~> 1.0"
s.add_dependency "net-ssh", "~> 2.6"
diff --git a/lib/chef/chef_fs/file_system/cookbooks_dir.rb b/lib/chef/chef_fs/file_system/cookbooks_dir.rb
index a58bfdd1f2..d4857cdabd 100644
--- a/lib/chef/chef_fs/file_system/cookbooks_dir.rb
+++ b/lib/chef/chef_fs/file_system/cookbooks_dir.rb
@@ -106,7 +106,7 @@ class Chef
cookbook_to_upload.freeze_version if options[:freeze]
# Instantiate a new uploader based on the proxy loader
- uploader = Chef::CookbookUploader.new(cookbook_to_upload, proxy_cookbook_path, :force => options[:force], :rest => root.chef_rest)
+ uploader = Chef::CookbookUploader.new(cookbook_to_upload, :force => options[:force], :rest => root.chef_rest)
with_actual_cookbooks_dir(temp_cookbooks_path) do
upload_cookbook!(uploader)
@@ -128,7 +128,7 @@ class Chef
def upload_unversioned_cookbook(other, options)
cookbook_to_upload = other.chef_object
cookbook_to_upload.freeze_version if options[:freeze]
- uploader = Chef::CookbookUploader.new(cookbook_to_upload, other.parent.file_path, :force => options[:force], :rest => root.chef_rest)
+ uploader = Chef::CookbookUploader.new(cookbook_to_upload, :force => options[:force], :rest => root.chef_rest)
with_actual_cookbooks_dir(other.parent.file_path) do
upload_cookbook!(uploader)
diff --git a/lib/chef/config.rb b/lib/chef/config.rb
index 65952b8cf7..93cd05d0ef 100644
--- a/lib/chef/config.rb
+++ b/lib/chef/config.rb
@@ -567,7 +567,7 @@ class Chef
# If false file staging is will be done via tempfiles that are
# created under ENV['TMP'] otherwise tempfiles will be created in
# the directory that files are going to reside.
- default :file_staging_uses_destdir, false
+ default :file_staging_uses_destdir, true
# Exit if another run is in progress and the chef-client is unable to
# get the lock before time expires. If nil, no timeout is enforced. (Exits
@@ -580,6 +580,30 @@ class Chef
# the number of threads will help.
default :cookbook_sync_threads, 10
+ # At the beginning of the Chef Client run, the cookbook manifests are downloaded which
+ # contain URLs for every file in every relevant cookbook. Most of the files
+ # (recipes, resources, providers, libraries, etc) are immediately synchronized
+ # at the start of the run. The handling of "files" and "templates" directories,
+ # however, have two modes of operation. They can either all be downloaded immediately
+ # at the start of the run (no_lazy_load==true) or else they can be lazily loaded as
+ # cookbook_file or template resources are converged which require them (no_lazy_load==false).
+ #
+ # The advantage of lazily loading these files is that unnecessary files are not
+ # synchronized. This may be useful to users with large files checked into cookbooks which
+ # are only selectively downloaded to a subset of clients which use the cookbook. However,
+ # better solutions are to either isolate large files into individual cookbooks and only
+ # include those cookbooks in the run lists of the servers that need them -- or move to
+ # using remote_file and a more appropriate backing store like S3 for large file
+ # distribution.
+ #
+ # The disadvantages of lazily loading files are that users some time find it
+ # confusing that their cookbooks are not fully synchronzied to the cache initially,
+ # and more importantly the time-sensitive URLs which are in the manifest may time
+ # out on long Chef runs before the resource that uses the file is converged
+ # (leading to many confusing 403 errors on template/cookbook_file resources).
+ #
+ default :no_lazy_load, true
+
# A whitelisted array of attributes you want sent over the wire when node
# data is saved.
# The default setting is nil, which collects all data. Setting to [] will not
diff --git a/lib/chef/cookbook/file_system_file_vendor.rb b/lib/chef/cookbook/file_system_file_vendor.rb
index 8896e3ed30..e351ec4702 100644
--- a/lib/chef/cookbook/file_system_file_vendor.rb
+++ b/lib/chef/cookbook/file_system_file_vendor.rb
@@ -31,6 +31,9 @@ class Chef
# non-sensical.
class FileSystemFileVendor < FileVendor
+ attr_reader :cookbook_name
+ attr_reader :repo_paths
+
def initialize(manifest, *repo_paths)
@cookbook_name = manifest[:cookbook_name]
@repo_paths = repo_paths.flatten
diff --git a/lib/chef/cookbook/file_vendor.rb b/lib/chef/cookbook/file_vendor.rb
index 406f23ca25..b82b52f90c 100644
--- a/lib/chef/cookbook/file_vendor.rb
+++ b/lib/chef/cookbook/file_vendor.rb
@@ -24,15 +24,39 @@ class Chef
# This class handles fetching of cookbook files based on specificity.
class FileVendor
- def self.on_create(&block)
- @instance_creator = block
+ @vendor_class = nil
+ @initialization_options = nil
+
+ # Configures FileVendor to use the RemoteFileVendor implementation. After
+ # calling this, subsequent calls to create_from_manifest will return a
+ # RemoteFileVendor object initialized with the given http_client
+ def self.fetch_from_remote(http_client)
+ @vendor_class = RemoteFileVendor
+ @initialization_options = http_client
+ end
+
+ def self.fetch_from_disk(cookbook_paths)
+ @vendor_class = FileSystemFileVendor
+ @initialization_options = cookbook_paths
+ end
+
+ # Returns the implementation class that is currently configured, or `nil`
+ # if one has not been configured yet.
+ def self.vendor_class
+ @vendor_class
+ end
+
+ def self.initialization_options
+ @initialization_options
end
# Factory method that creates the appropriate kind of
# Cookbook::FileVendor to serve the contents of the manifest
def self.create_from_manifest(manifest)
- raise "Must call Chef::Cookbook::FileVendor.on_create before calling create_from_manifest factory" unless defined?(@instance_creator)
- @instance_creator.call(manifest)
+ if @vendor_class.nil?
+ raise "Must configure FileVendor to use a specific implementation before creating an instance"
+ end
+ @vendor_class.new(manifest, @initialization_options)
end
# Gets the on-disk location for the given cookbook file.
diff --git a/lib/chef/cookbook/remote_file_vendor.rb b/lib/chef/cookbook/remote_file_vendor.rb
index 49de62cf65..2ddce31001 100644
--- a/lib/chef/cookbook/remote_file_vendor.rb
+++ b/lib/chef/cookbook/remote_file_vendor.rb
@@ -25,6 +25,9 @@ class Chef
# if not available, loading them from the remote server.
class RemoteFileVendor < FileVendor
+ attr_reader :rest
+ attr_reader :cookbook_name
+
def initialize(manifest, rest)
@manifest = manifest
@cookbook_name = @manifest[:cookbook_name]
diff --git a/lib/chef/cookbook/synchronizer.rb b/lib/chef/cookbook/synchronizer.rb
index 7df3f554bb..1b96d0510b 100644
--- a/lib/chef/cookbook/synchronizer.rb
+++ b/lib/chef/cookbook/synchronizer.rb
@@ -10,6 +10,8 @@ class Chef
# cache.
class CookbookCacheCleaner
+ attr_accessor :skip_removal
+
# Setup a notification to clear the valid_cache_entries when a Chef client
# run starts
Chef::Client.when_run_starts do |run_status|
@@ -40,15 +42,17 @@ class Chef
end
def cleanup_file_cache
- unless Chef::Config[:solo]
+ unless Chef::Config[:solo] || skip_removal
# Delete each file in the cache that we didn't encounter in the
# manifest.
- cache.find(File.join(%w{cookbooks ** *})).each do |cache_filename|
+ cache.find(File.join(%w{cookbooks ** {*,.*}})).each do |cache_filename|
unless @valid_cache_entries[cache_filename]
Chef::Log.info("Removing #{cache_filename} from the cache; it is no longer needed by chef-client.")
cache.delete(cache_filename)
end
end
+ else
+ Chef::Log.info("Skipping removal of unused files from the cache")
end
end
@@ -59,6 +63,8 @@ class Chef
class CookbookSynchronizer
CookbookFile = Struct.new(:cookbook, :segment, :manifest_record)
+ attr_accessor :remove_obsoleted_files
+
def initialize(cookbooks_by_name, events)
@eager_segments = Chef::CookbookVersion::COOKBOOK_SEGMENTS.dup
unless Chef::Config[:no_lazy_load]
@@ -70,6 +76,7 @@ class Chef
@cookbooks_by_name, @events = cookbooks_by_name, events
@cookbook_full_file_paths = {}
+ @remove_obsoleted_files = true
end
def cache
@@ -92,6 +99,10 @@ class Chef
@cookbooks_by_name.key?(cookbook_name)
end
+ def cookbook_segment(cookbook_name, segment)
+ @cookbooks_by_name[cookbook_name].manifest[segment]
+ end
+
def files
@files ||= cookbooks.inject([]) do |memo, cookbook|
@eager_segments.each do |segment|
@@ -169,12 +180,10 @@ class Chef
@cookbook_full_file_paths[file.cookbook][file.segment] << full_path
end
- # Iterates over cached cookbooks' files, removing files belonging to
- # cookbooks that don't appear in +cookbook_hash+
- def clear_obsoleted_cookbooks
- @events.cookbook_clean_start
- # Remove all cookbooks no longer relevant to this node
- cache.find(File.join(%w{cookbooks ** *})).each do |cache_file|
+ # remove cookbooks that are not referenced in the expanded run_list at all
+ # (if we have an override run_list we may not want to do this)
+ def remove_old_cookbooks
+ cache.find(File.join(%w{cookbooks ** {*,.*}})).each do |cache_file|
cache_file =~ /^cookbooks\/([^\/]+)\//
unless have_cookbook?($1)
Chef::Log.info("Removing #{cache_file} from the cache; its cookbook is no longer needed on this client.")
@@ -182,6 +191,39 @@ class Chef
@events.removed_cookbook_file(cache_file)
end
end
+ end
+
+ # remove deleted files in cookbooks that are being used on the node
+ def remove_deleted_files
+ cache.find(File.join(%w{cookbooks ** {*,.*}})).each do |cache_file|
+ md = cache_file.match(/^cookbooks\/([^\/]+)\/([^\/]+)\/(.*)/)
+ next unless md
+ ( cookbook_name, segment, file ) = md[1..3]
+ if have_cookbook?(cookbook_name)
+ manifest_segment = cookbook_segment(cookbook_name, segment)
+ if manifest_segment.select { |manifest_record| manifest_record["path"] == "#{segment}/#{file}" }.empty?
+ Chef::Log.info("Removing #{cache_file} from the cache; its is no longer in the cookbook manifest.")
+ cache.delete(cache_file)
+ @events.removed_cookbook_file(cache_file)
+ end
+ end
+ end
+ end
+
+ # Iterates over cached cookbooks' files, removing files belonging to
+ # cookbooks that don't appear in +cookbook_hash+
+ def clear_obsoleted_cookbooks
+ @events.cookbook_clean_start
+
+ if remove_obsoleted_files
+ remove_old_cookbooks
+ else
+ Chef::Log.info("Skipping removal of obsoleted cookbooks from the cache")
+ CookbookCacheCleaner.instance.skip_removal = true
+ end
+
+ remove_deleted_files
+
@events.cookbook_clean_complete
end
diff --git a/lib/chef/cookbook_uploader.rb b/lib/chef/cookbook_uploader.rb
index adad55b4ca..2d8bf5bc7e 100644
--- a/lib/chef/cookbook_uploader.rb
+++ b/lib/chef/cookbook_uploader.rb
@@ -35,8 +35,8 @@ class Chef
# in Chef::Config.
# * :concurrency An integer that decided how many threads will be used to
# perform concurrent uploads
- def initialize(cookbooks, path, opts={})
- @path, @opts = path, opts
+ def initialize(cookbooks, opts={})
+ @opts = opts
@cookbooks = Array(cookbooks)
@rest = opts[:rest] || Chef::REST.new(Chef::Config[:chef_server_url])
@concurrency = opts[:concurrency] || 10
@@ -53,7 +53,7 @@ class Chef
end
checksums = checksum_files.inject({}){|memo,elt| memo[elt.first]=nil ; memo}
- new_sandbox = rest.post_rest("sandboxes", { :checksums => checksums })
+ new_sandbox = rest.post("sandboxes", { :checksums => checksums })
Chef::Log.info("Uploading files")
@@ -80,7 +80,7 @@ class Chef
# in eventual consistency)
retries = 0
begin
- rest.put_rest(sandbox_url, {:is_completed => true})
+ rest.put(sandbox_url, {:is_completed => true})
rescue Net::HTTPServerException => e
if e.message =~ /^400/ && (retries += 1) <= 5
sleep 2
@@ -94,7 +94,7 @@ class Chef
cookbooks.each do |cb|
save_url = opts[:force] ? cb.force_save_url : cb.save_url
begin
- rest.put_rest(save_url, cb)
+ rest.put(save_url, cb)
rescue Net::HTTPServerException => e
case e.response.code
when "409"
@@ -108,32 +108,19 @@ class Chef
Chef::Log.info("Upload complete!")
end
- def worker_thread(work_queue)
- end
-
def uploader_function_for(file, checksum, url, checksums_to_upload)
lambda do
# Checksum is the hexadecimal representation of the md5,
# but we need the base64 encoding for the content-md5
# header
checksum64 = Base64.encode64([checksum].pack("H*")).strip
- timestamp = Time.now.utc.iso8601
file_contents = File.open(file, "rb") {|f| f.read}
- # TODO - 5/28/2010, cw: make signing and sending the request streaming
+
+ # Custom headers. 'content-type' disables JSON serialization of the request body.
headers = { 'content-type' => 'application/x-binary', 'content-md5' => checksum64, "accept" => 'application/json' }
- if rest.signing_key
- sign_obj = Mixlib::Authentication::SignedHeaderAuth.signing_object(
- :http_method => :put,
- :path => URI.parse(url).path,
- :body => file_contents,
- :timestamp => timestamp,
- :user_id => rest.client_name
- )
- headers.merge!(sign_obj.sign(OpenSSL::PKey::RSA.new(rest.signing_key)))
- end
begin
- Chef::HTTP::Simple.new(url, :headers=>headers).put(url, file_contents)
+ rest.put(url, file_contents, headers)
checksums_to_upload.delete(checksum)
rescue Net::HTTPServerException, Net::HTTPFatalError, Errno::ECONNREFUSED, Timeout::Error, Errno::ETIMEDOUT, SocketError => e
error_message = "Failed to upload #{file} (#{checksum}) to #{url} : #{e.message}"
@@ -146,7 +133,7 @@ class Chef
def validate_cookbooks
cookbooks.each do |cb|
- syntax_checker = Chef::Cookbook::SyntaxCheck.for_cookbook(cb.name, @user_cookbook_path)
+ syntax_checker = Chef::Cookbook::SyntaxCheck.for_cookbook(cb.name)
Chef::Log.info("Validating ruby files")
exit(1) unless syntax_checker.validate_ruby_files
Chef::Log.info("Validating templates")
diff --git a/lib/chef/cookbook_version.rb b/lib/chef/cookbook_version.rb
index 3d8b9fb908..778a6043bf 100644
--- a/lib/chef/cookbook_version.rb
+++ b/lib/chef/cookbook_version.rb
@@ -25,6 +25,7 @@ require 'chef/cookbook/metadata'
require 'chef/version_class'
require 'pathname'
require 'chef/monkey_patches/pathname'
+require 'chef/digester'
class Chef
diff --git a/lib/chef/dsl/recipe.rb b/lib/chef/dsl/recipe.rb
index 6846703f09..23cfbd558c 100644
--- a/lib/chef/dsl/recipe.rb
+++ b/lib/chef/dsl/recipe.rb
@@ -28,6 +28,7 @@ class Chef
# objects via method calls.
module Recipe
+ include Chef::Mixin::ShellOut
include Chef::Mixin::ConvertToClassName
def method_missing(method_symbol, *args, &block)
diff --git a/lib/chef/file_content_management/tempfile.rb b/lib/chef/file_content_management/tempfile.rb
index 0bb7f3a6fa..61a5ce2a7c 100644
--- a/lib/chef/file_content_management/tempfile.rb
+++ b/lib/chef/file_content_management/tempfile.rb
@@ -54,7 +54,14 @@ class Chef
end
def tempfile_dirname
- Chef::Config[:file_staging_uses_destdir] ? ::File.dirname(@new_resource.path) : Dir::tmpdir
+ # in why-run mode we need to create a Tempfile to compare against, which we will never
+ # wind up deploying, but our enclosing directory for the destdir may not exist yet, so
+ # instead we can reliably always create a Tempfile to compare against in Dir::tmpdir
+ if Chef::Config[:file_staging_uses_destdir] && !Chef::Config[:why_run]
+ ::File.dirname(@new_resource.path)
+ else
+ Dir::tmpdir
+ end
end
end
end
diff --git a/lib/chef/formatters/base.rb b/lib/chef/formatters/base.rb
index 636ba9c83f..c901068aa0 100644
--- a/lib/chef/formatters/base.rb
+++ b/lib/chef/formatters/base.rb
@@ -93,6 +93,13 @@ class Chef
def indent_by(amount)
@output.indent += amount
+ if @output.indent < 0
+ # This is left commented out for now. We need to uncomment it and fix at least one bug in
+ # the formatter, and then leave this line uncommented in the future.
+ #Chef::Log.warn "Internal Formatter Error -- Attempt to indent by negative number of spaces"
+ @output.indent = 0
+ end
+ @output.indent
end
# Input: a Formatters::ErrorDescription object.
diff --git a/lib/chef/http/json_input.rb b/lib/chef/http/json_input.rb
index 1e4e736030..23ccc3a8a7 100644
--- a/lib/chef/http/json_input.rb
+++ b/lib/chef/http/json_input.rb
@@ -29,7 +29,8 @@ class Chef
end
def handle_request(method, url, headers={}, data=false)
- if data
+ if data && should_encode_as_json?(headers)
+ headers.delete_if { |key, _value| key.downcase == 'content-type' }
headers["Content-Type"] = 'application/json'
data = Chef::JSONCompat.to_json(data)
# Force encoding to binary to fix SSL related EOFErrors
@@ -52,6 +53,16 @@ class Chef
[http_response, rest_request, return_value]
end
+ private
+
+ def should_encode_as_json?(headers)
+ # ruby/Net::HTTP don't enforce capitalized headers (it normalizes them
+ # for you before sending the request), so we have to account for all
+ # the variations we might find
+ requested_content_type = headers.find {|k, v| k.downcase == "content-type" }
+ requested_content_type.nil? || requested_content_type.last.include?("json")
+ end
+
end
end
end
diff --git a/lib/chef/knife/cookbook_site_share.rb b/lib/chef/knife/cookbook_site_share.rb
index 4dcce42d7f..330f3cb229 100644
--- a/lib/chef/knife/cookbook_site_share.rb
+++ b/lib/chef/knife/cookbook_site_share.rb
@@ -54,7 +54,7 @@ class Chef
cl = Chef::CookbookLoader.new(config[:cookbook_path])
if cl.cookbook_exists?(cookbook_name)
cookbook = cl[cookbook_name]
- Chef::CookbookUploader.new(cookbook,config[:cookbook_path]).validate_cookbooks
+ Chef::CookbookUploader.new(cookbook).validate_cookbooks
tmp_cookbook_dir = Chef::CookbookSiteStreamingUploader.create_build_dir(cookbook)
begin
Chef::Log.debug("Temp cookbook directory is #{tmp_cookbook_dir.inspect}")
diff --git a/lib/chef/knife/cookbook_upload.rb b/lib/chef/knife/cookbook_upload.rb
index 9d6e0d438d..f5002be3a7 100644
--- a/lib/chef/knife/cookbook_upload.rb
+++ b/lib/chef/knife/cookbook_upload.rb
@@ -184,7 +184,7 @@ class Chef
def cookbook_repo
@cookbook_loader ||= begin
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, config[:cookbook_path]) }
+ Chef::Cookbook::FileVendor.fetch_from_disk(config[:cookbook_path])
Chef::CookbookLoader.new(config[:cookbook_path])
end
end
@@ -240,7 +240,7 @@ WARNING
check_for_broken_links!(cb)
check_for_dependencies!(cb)
end
- Chef::CookbookUploader.new(cookbooks, config[:cookbook_path], :force => config[:force], :concurrency => config[:concurrency]).upload_cookbooks
+ Chef::CookbookUploader.new(cookbooks, :force => config[:force], :concurrency => config[:concurrency]).upload_cookbooks
rescue Chef::Exceptions::CookbookFrozen => e
ui.error e
raise
diff --git a/lib/chef/knife/core/ui.rb b/lib/chef/knife/core/ui.rb
index ff2545cfed..c4d7d73b00 100644
--- a/lib/chef/knife/core/ui.rb
+++ b/lib/chef/knife/core/ui.rb
@@ -73,10 +73,8 @@ class Chef
end
end
- alias :info :msg
-
- # Prints a msg to stderr. Used for warn, error, and fatal.
- def err(message)
+ # Prints a msg to stderr. Used for info, warn, error, and fatal.
+ def log(message)
begin
stderr.puts message
rescue Errno::EPIPE => e
@@ -85,19 +83,22 @@ class Chef
end
end
+ alias :info :log
+ alias :err :log
+
# Print a warning message
def warn(message)
- err("#{color('WARNING:', :yellow, :bold)} #{message}")
+ log("#{color('WARNING:', :yellow, :bold)} #{message}")
end
# Print an error message
def error(message)
- err("#{color('ERROR:', :red, :bold)} #{message}")
+ log("#{color('ERROR:', :red, :bold)} #{message}")
end
# Print a message describing a fatal error.
def fatal(message)
- err("#{color('FATAL:', :red, :bold)} #{message}")
+ log("#{color('FATAL:', :red, :bold)} #{message}")
end
def color(string, *colors)
diff --git a/lib/chef/policy_builder/expand_node_object.rb b/lib/chef/policy_builder/expand_node_object.rb
index 161e14ca38..2ee8a23258 100644
--- a/lib/chef/policy_builder/expand_node_object.rb
+++ b/lib/chef/policy_builder/expand_node_object.rb
@@ -56,13 +56,13 @@ class Chef
def setup_run_context(specific_recipes=nil)
if Chef::Config[:solo]
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, Chef::Config[:cookbook_path]) }
+ Chef::Cookbook::FileVendor.fetch_from_disk(Chef::Config[:cookbook_path])
cl = Chef::CookbookLoader.new(Chef::Config[:cookbook_path])
cl.load_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cl)
run_context = Chef::RunContext.new(node, cookbook_collection, @events)
else
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::RemoteFileVendor.new(manifest, api_service) }
+ Chef::Cookbook::FileVendor.fetch_from_remote(api_service)
cookbook_hash = sync_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cookbook_hash)
run_context = Chef::RunContext.new(node, cookbook_collection, @events)
@@ -176,6 +176,9 @@ class Chef
end
synchronizer = Chef::CookbookSynchronizer.new(cookbook_hash, events)
+ if temporary_policy?
+ synchronizer.remove_obsoleted_files = false
+ end
synchronizer.sync_cookbooks
# register the file cache path in the cookbook path so that CookbookLoader actually picks up the synced cookbooks
diff --git a/lib/chef/policy_builder/policyfile.rb b/lib/chef/policy_builder/policyfile.rb
index 4baa6340d4..0df3dd5dd2 100644
--- a/lib/chef/policy_builder/policyfile.rb
+++ b/lib/chef/policy_builder/policyfile.rb
@@ -154,10 +154,7 @@ class Chef
end
def setup_run_context(specific_recipes=nil)
- # TODO: This file vendor stuff is duplicated and initializing it with a
- # block traps a reference to this object in a global context which will
- # prevent it from getting GC'd. Simplify it.
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::RemoteFileVendor.new(manifest, api_service) }
+ Chef::Cookbook::FileVendor.fetch_from_remote(http_api)
sync_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cookbooks_to_sync)
run_context = Chef::RunContext.new(node, cookbook_collection, events)
diff --git a/lib/chef/provider.rb b/lib/chef/provider.rb
index 90b6ead716..db7629dbcb 100644
--- a/lib/chef/provider.rb
+++ b/lib/chef/provider.rb
@@ -22,11 +22,13 @@ require 'chef/mixin/convert_to_class_name'
require 'chef/dsl/recipe'
require 'chef/mixin/enforce_ownership_and_permissions'
require 'chef/mixin/why_run'
+require 'chef/mixin/shell_out'
class Chef
class Provider
include Chef::DSL::Recipe
include Chef::Mixin::WhyRun
+ include Chef::Mixin::ShellOut
attr_accessor :new_resource
attr_accessor :current_resource
diff --git a/lib/chef/provider/cookbook_file.rb b/lib/chef/provider/cookbook_file.rb
index 18af70d415..26d6ebf1d9 100644
--- a/lib/chef/provider/cookbook_file.rb
+++ b/lib/chef/provider/cookbook_file.rb
@@ -49,4 +49,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/provider/deploy.rb b/lib/chef/provider/deploy.rb
index 18f396f89e..541cc9e846 100644
--- a/lib/chef/provider/deploy.rb
+++ b/lib/chef/provider/deploy.rb
@@ -175,7 +175,6 @@ class Chef
restart
end
-
def callback(what, callback_code=nil)
@collection = Chef::ResourceCollection.new
case callback_code
diff --git a/lib/chef/provider/execute.rb b/lib/chef/provider/execute.rb
index 2907688e88..d469bea769 100644
--- a/lib/chef/provider/execute.rb
+++ b/lib/chef/provider/execute.rb
@@ -16,7 +16,6 @@
# limitations under the License.
#
-require 'chef/mixin/shell_out'
require 'chef/log'
require 'chef/provider'
@@ -24,8 +23,6 @@ class Chef
class Provider
class Execute < Chef::Provider
- include Chef::Mixin::ShellOut
-
def load_current_resource
true
end
diff --git a/lib/chef/provider/file.rb b/lib/chef/provider/file.rb
index 2dffcc6ddc..031d0fb005 100644
--- a/lib/chef/provider/file.rb
+++ b/lib/chef/provider/file.rb
@@ -25,7 +25,6 @@ require 'etc'
require 'fileutils'
require 'chef/scan_access_control'
require 'chef/mixin/checksum'
-require 'chef/mixin/shell_out'
require 'chef/mixin/file_class'
require 'chef/util/backup'
require 'chef/util/diff'
@@ -48,7 +47,6 @@ class Chef
class File < Chef::Provider
include Chef::Mixin::EnforceOwnershipAndPermissions
include Chef::Mixin::Checksum
- include Chef::Mixin::ShellOut
include Chef::Util::Selinux
include Chef::Mixin::FileClass
@@ -247,7 +245,6 @@ class Chef
"Assuming symlink source would be created by a previous resource" ]
end
-
def content
@content ||= begin
load_current_resource if @current_resource.nil?
diff --git a/lib/chef/provider/git.rb b/lib/chef/provider/git.rb
index 3999edc16a..263014d229 100644
--- a/lib/chef/provider/git.rb
+++ b/lib/chef/provider/git.rb
@@ -16,19 +16,15 @@
# limitations under the License.
#
-
require 'chef/exceptions'
require 'chef/log'
require 'chef/provider'
-require 'chef/mixin/shell_out'
require 'fileutils'
class Chef
class Provider
class Git < Chef::Provider
- include Chef::Mixin::ShellOut
-
def whyrun_supported?
true
end
@@ -51,7 +47,6 @@ class Chef
"Cannot clone #{@new_resource} to #{@new_resource.destination}, the enclosing directory #{dirname} does not exist")
end
-
requirements.assert(:all_actions) do |a|
a.assertion { !(@new_resource.revision =~ /^origin\//) }
a.failure_message Chef::Exceptions::InvalidRemoteGitReference,
@@ -107,7 +102,6 @@ class Chef
end
end
-
def existing_git_clone?
::File.exist?(::File.join(@new_resource.destination, ".git"))
end
diff --git a/lib/chef/provider/group/gpasswd.rb b/lib/chef/provider/group/gpasswd.rb
index a65a7ffd53..521affac11 100644
--- a/lib/chef/provider/group/gpasswd.rb
+++ b/lib/chef/provider/group/gpasswd.rb
@@ -17,15 +17,12 @@
#
require 'chef/provider/group/groupadd'
-require 'chef/mixin/shell_out'
class Chef
class Provider
class Group
class Gpasswd < Chef::Provider::Group::Groupadd
- include Chef::Mixin::ShellOut
-
def load_current_resource
super
end
diff --git a/lib/chef/provider/group/groupmod.rb b/lib/chef/provider/group/groupmod.rb
index c8b6458db0..7ad762af8d 100644
--- a/lib/chef/provider/group/groupmod.rb
+++ b/lib/chef/provider/group/groupmod.rb
@@ -16,15 +16,11 @@
# limitations under the License.
#
-require 'chef/mixin/shell_out'
-
class Chef
class Provider
class Group
class Groupmod < Chef::Provider::Group
- include Chef::Mixin::ShellOut
-
def load_current_resource
super
[ "group", "user" ].each do |binary|
diff --git a/lib/chef/provider/group/suse.rb b/lib/chef/provider/group/suse.rb
index 14380f1705..7ac2831d02 100644
--- a/lib/chef/provider/group/suse.rb
+++ b/lib/chef/provider/group/suse.rb
@@ -17,15 +17,12 @@
#
require 'chef/provider/group/groupadd'
-require 'chef/mixin/shell_out'
class Chef
class Provider
class Group
class Suse < Chef::Provider::Group::Groupadd
- include Chef::Mixin::ShellOut
-
def load_current_resource
super
end
diff --git a/lib/chef/provider/group/usermod.rb b/lib/chef/provider/group/usermod.rb
index e6f3fc9e0f..e9dcc38b43 100644
--- a/lib/chef/provider/group/usermod.rb
+++ b/lib/chef/provider/group/usermod.rb
@@ -17,15 +17,12 @@
#
require 'chef/provider/group/groupadd'
-require 'chef/mixin/shell_out'
class Chef
class Provider
class Group
class Usermod < Chef::Provider::Group::Groupadd
- include Chef::Mixin::ShellOut
-
def load_current_resource
super
end
diff --git a/lib/chef/provider/http_request.rb b/lib/chef/provider/http_request.rb
index 2bbd20aa2c..ba54b10195 100644
--- a/lib/chef/provider/http_request.rb
+++ b/lib/chef/provider/http_request.rb
@@ -33,13 +33,13 @@ class Chef
@http = Chef::HTTP::Simple.new(@new_resource.url)
end
- # Send a HEAD request to @new_resource.url, with ?message=@new_resource.message
+ # Send a HEAD request to @new_resource.url
def action_head
message = check_message(@new_resource.message)
# CHEF-4762: we expect a nil return value from Chef::HTTP for a "200 Success" response
# and false for a "304 Not Modified" response
modified = @http.head(
- "#{@new_resource.url}?message=#{message}",
+ "#{@new_resource.url}",
@new_resource.headers
)
Chef::Log.info("#{@new_resource} HEAD to #{@new_resource.url} successful")
@@ -50,13 +50,13 @@ class Chef
end
end
- # Send a GET request to @new_resource.url, with ?message=@new_resource.message
+ # Send a GET request to @new_resource.url
def action_get
converge_by("#{@new_resource} GET to #{@new_resource.url}") do
message = check_message(@new_resource.message)
body = @http.get(
- "#{@new_resource.url}?message=#{message}",
+ "#{@new_resource.url}",
@new_resource.headers
)
Chef::Log.info("#{@new_resource} GET to #{@new_resource.url} successful")
diff --git a/lib/chef/provider/link.rb b/lib/chef/provider/link.rb
index c41fbcad95..d6602c2e03 100644
--- a/lib/chef/provider/link.rb
+++ b/lib/chef/provider/link.rb
@@ -18,7 +18,6 @@
require 'chef/config'
require 'chef/log'
-require 'chef/mixin/shell_out'
require 'chef/mixin/file_class'
require 'chef/resource/link'
require 'chef/provider'
@@ -29,7 +28,6 @@ class Chef
class Link < Chef::Provider
include Chef::Mixin::EnforceOwnershipAndPermissions
- include Chef::Mixin::ShellOut
include Chef::Mixin::FileClass
def negative_complement(big)
diff --git a/lib/chef/provider/log.rb b/lib/chef/provider/log.rb
index e65f01e69a..0aee349705 100644
--- a/lib/chef/provider/log.rb
+++ b/lib/chef/provider/log.rb
@@ -25,9 +25,6 @@ class Chef
# Chef log provider, allows logging to chef's logs from recipes
class ChefLog < Chef::Provider
- # ordered array of the log levels
- @@levels = [ :debug, :info, :warn, :error, :fatal ]
-
# No concept of a 'current' resource for logs, this is a no-op
#
# === Return
@@ -42,18 +39,7 @@ class Chef
# true:: Always return true
def action_write
Chef::Log.send(@new_resource.level, @new_resource.message)
-
- # resolve the integers for the current log levels
- global_level = Mixlib::Log::LEVELS.fetch(Chef::Log.level)
- resource_level = Mixlib::Log::LEVELS.fetch(@new_resource.level)
-
- # If the resource level is greater than or the same os the global
- # level, then it should have been written to the log. Mark the
- # resource as updated.
- if resource_level >= global_level
- @new_resource.updated_by_last_action(true)
- end
-
+ @new_resource.updated_by_last_action(true)
end
end
@@ -63,6 +49,3 @@ class Chef
end
end
-
-
-
diff --git a/lib/chef/provider/mdadm.rb b/lib/chef/provider/mdadm.rb
index 51c9b8d3c6..d156e49d48 100644
--- a/lib/chef/provider/mdadm.rb
+++ b/lib/chef/provider/mdadm.rb
@@ -17,15 +17,12 @@
#
require 'chef/log'
-require 'chef/mixin/shell_out'
require 'chef/provider'
class Chef
class Provider
class Mdadm < Chef::Provider
- include Chef::Mixin::ShellOut
-
def popen4
raise Exception, "deprecated"
end
diff --git a/lib/chef/provider/mount/mount.rb b/lib/chef/provider/mount/mount.rb
index 22d61a9236..bb1b796290 100644
--- a/lib/chef/provider/mount/mount.rb
+++ b/lib/chef/provider/mount/mount.rb
@@ -18,13 +18,11 @@
require 'chef/provider/mount'
require 'chef/log'
-require 'chef/mixin/shell_out'
class Chef
class Provider
class Mount
class Mount < Chef::Provider::Mount
- include Chef::Mixin::ShellOut
def initialize(new_resource, run_context)
super
diff --git a/lib/chef/provider/mount/solaris.rb b/lib/chef/provider/mount/solaris.rb
index 85158eb564..462fa32b71 100644
--- a/lib/chef/provider/mount/solaris.rb
+++ b/lib/chef/provider/mount/solaris.rb
@@ -20,14 +20,12 @@
require 'chef/provider/mount'
require 'chef/log'
-require 'chef/mixin/shell_out'
require 'forwardable'
class Chef
class Provider
class Mount
class Solaris < Chef::Provider::Mount
- include Chef::Mixin::ShellOut
extend Forwardable
VFSTAB = "/etc/vfstab".freeze
diff --git a/lib/chef/provider/package.rb b/lib/chef/provider/package.rb
index adae880b7f..a4a056dfec 100644
--- a/lib/chef/provider/package.rb
+++ b/lib/chef/provider/package.rb
@@ -198,7 +198,6 @@ class Chef
Chef::Log.debug("#{@new_resource} fetching preseed file to #{cache_seed_to}")
-
if template_available?(@new_resource.response_file)
Chef::Log.debug("#{@new_resource} fetching preseed file via Template")
remote_file = Chef::Resource::Template.new(cache_seed_to, run_context)
diff --git a/lib/chef/provider/package/apt.rb b/lib/chef/provider/package/apt.rb
index 76d90a5a97..0d91d0d1f0 100644
--- a/lib/chef/provider/package/apt.rb
+++ b/lib/chef/provider/package/apt.rb
@@ -19,15 +19,12 @@
require 'chef/provider/package'
require 'chef/mixin/command'
require 'chef/resource/package'
-require 'chef/mixin/shell_out'
-
class Chef
class Provider
class Package
class Apt < Chef::Provider::Package
- include Chef::Mixin::ShellOut
attr_accessor :is_virtual_package
def load_current_resource
diff --git a/lib/chef/provider/package/easy_install.rb b/lib/chef/provider/package/easy_install.rb
index 6c9dacc55d..2af8a72e61 100644
--- a/lib/chef/provider/package/easy_install.rb
+++ b/lib/chef/provider/package/easy_install.rb
@@ -18,17 +18,13 @@
require 'chef/provider/package'
require 'chef/mixin/command'
-require 'chef/mixin/shell_out'
require 'chef/resource/package'
-require 'chef/mixin/shell_out'
class Chef
class Provider
class Package
class EasyInstall < Chef::Provider::Package
- include Chef::Mixin::ShellOut
-
def install_check(name)
check = false
diff --git a/lib/chef/provider/package/freebsd/base.rb b/lib/chef/provider/package/freebsd/base.rb
index 24f79484f0..b0f05667ff 100644
--- a/lib/chef/provider/package/freebsd/base.rb
+++ b/lib/chef/provider/package/freebsd/base.rb
@@ -21,7 +21,6 @@
require 'chef/resource/package'
require 'chef/provider/package'
-require 'chef/mixin/shell_out'
require 'chef/mixin/get_source_from_package'
class Chef
@@ -63,9 +62,7 @@ class Chef
end
end
-
class Base < Chef::Provider::Package
- include Chef::Mixin::ShellOut
include Chef::Mixin::GetSourceFromPackage
def initialize(*args)
diff --git a/lib/chef/provider/package/freebsd/pkgng.rb b/lib/chef/provider/package/freebsd/pkgng.rb
index da531facc1..0741a4d95f 100644
--- a/lib/chef/provider/package/freebsd/pkgng.rb
+++ b/lib/chef/provider/package/freebsd/pkgng.rb
@@ -52,8 +52,6 @@ class Chef
@new_resource.source ? file_candidate_version : repo_candidate_version
end
-
-
private
def file_candidate_version
diff --git a/lib/chef/provider/package/freebsd/port.rb b/lib/chef/provider/package/freebsd/port.rb
index 6f4471a6f7..4b3510f0e9 100644
--- a/lib/chef/provider/package/freebsd/port.rb
+++ b/lib/chef/provider/package/freebsd/port.rb
@@ -54,8 +54,6 @@ class Chef
super(@new_resource.package_name)
end
-
-
private
def supports_pkgng?
diff --git a/lib/chef/provider/package/ips.rb b/lib/chef/provider/package/ips.rb
index 2c6d98d81a..fed3e34124 100644
--- a/lib/chef/provider/package/ips.rb
+++ b/lib/chef/provider/package/ips.rb
@@ -21,14 +21,12 @@ require 'open3'
require 'chef/provider/package'
require 'chef/mixin/command'
require 'chef/resource/package'
-require 'chef/mixin/shell_out'
class Chef
class Provider
class Package
class Ips < Chef::Provider::Package
- include Chef::Mixin::ShellOut
attr_accessor :virtual
def define_resource_requirements
@@ -98,4 +96,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/provider/package/paludis.rb b/lib/chef/provider/package/paludis.rb
index e304cd3b8e..f40962d74d 100644
--- a/lib/chef/provider/package/paludis.rb
+++ b/lib/chef/provider/package/paludis.rb
@@ -18,15 +18,12 @@
require 'chef/provider/package'
require 'chef/resource/package'
-require 'chef/mixin/shell_out'
class Chef
class Provider
class Package
class Paludis < Chef::Provider::Package
- include Chef::Mixin::ShellOut
-
def load_current_resource
@current_resource = Chef::Resource::Package.new(@new_resource.package_name)
@current_resource.package_name(@new_resource.package_name)
@@ -87,5 +84,3 @@ class Chef
end
end
end
-
-
diff --git a/lib/chef/provider/package/portage.rb b/lib/chef/provider/package/portage.rb
index ea8e37e5d4..6a3587558a 100644
--- a/lib/chef/provider/package/portage.rb
+++ b/lib/chef/provider/package/portage.rb
@@ -55,7 +55,6 @@ class Chef
@current_resource
end
-
def parse_emerge(package, txt)
availables = {}
found_package_name = nil
@@ -103,7 +102,6 @@ class Chef
end
-
def install_package(name, version)
pkg = "=#{name}-#{version}"
diff --git a/lib/chef/provider/package/rpm.rb b/lib/chef/provider/package/rpm.rb
index 74baddb062..9cfd6bb010 100644
--- a/lib/chef/provider/package/rpm.rb
+++ b/lib/chef/provider/package/rpm.rb
@@ -85,7 +85,6 @@ class Chef
end
end
-
@current_resource
end
@@ -119,4 +118,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/provider/package/rubygems.rb b/lib/chef/provider/package/rubygems.rb
index b423c199a0..be0022f4aa 100644
--- a/lib/chef/provider/package/rubygems.rb
+++ b/lib/chef/provider/package/rubygems.rb
@@ -352,8 +352,6 @@ class Chef
end
- include Chef::Mixin::ShellOut
-
attr_reader :gem_env
attr_reader :cleanup_gem_env
diff --git a/lib/chef/provider/package/smartos.rb b/lib/chef/provider/package/smartos.rb
index 28d56ddc2c..19a6b9efef 100644
--- a/lib/chef/provider/package/smartos.rb
+++ b/lib/chef/provider/package/smartos.rb
@@ -20,7 +20,6 @@
#
require 'chef/provider/package'
-require 'chef/mixin/shell_out'
require 'chef/resource/package'
require 'chef/mixin/get_source_from_package'
@@ -28,10 +27,8 @@ class Chef
class Provider
class Package
class SmartOS < Chef::Provider::Package
- include Chef::Mixin::ShellOut
attr_accessor :is_virtual_package
-
def load_current_resource
Chef::Log.debug("#{@new_resource} loading current resource")
@current_resource = Chef::Resource::Package.new(@new_resource.name)
diff --git a/lib/chef/provider/package/windows/msi.rb b/lib/chef/provider/package/windows/msi.rb
index a342600678..cc07909d8e 100644
--- a/lib/chef/provider/package/windows/msi.rb
+++ b/lib/chef/provider/package/windows/msi.rb
@@ -18,7 +18,6 @@
# TODO: Allow @new_resource.source to be a Product Code as a GUID for uninstall / network install
-require 'chef/mixin/shell_out'
require 'chef/win32/api/installer' if RUBY_PLATFORM =~ /mswin|mingw32|windows/
class Chef
@@ -27,7 +26,6 @@ class Chef
class Windows
class MSI
include Chef::ReservedNames::Win32::API::Installer if RUBY_PLATFORM =~ /mswin|mingw32|windows/
- include Chef::Mixin::ShellOut
def initialize(resource)
@new_resource = resource
diff --git a/lib/chef/provider/package/yum.rb b/lib/chef/provider/package/yum.rb
index c241c7fd6d..d15f22ae16 100644
--- a/lib/chef/provider/package/yum.rb
+++ b/lib/chef/provider/package/yum.rb
@@ -19,12 +19,10 @@
require 'chef/config'
require 'chef/provider/package'
require 'chef/mixin/command'
-require 'chef/mixin/shell_out'
require 'chef/resource/package'
require 'singleton'
require 'chef/mixin/get_source_from_package'
-
class Chef
class Provider
class Package
@@ -647,7 +645,6 @@ class Chef
# Cache for our installed and available packages, pulled in from yum-dump.py
class YumCache
include Chef::Mixin::Command
- include Chef::Mixin::ShellOut
include Singleton
def initialize
@@ -949,7 +946,6 @@ class Chef
end # YumCache
include Chef::Mixin::GetSourceFromPackage
- include Chef::Mixin::ShellOut
def initialize(new_resource, run_context)
super
diff --git a/lib/chef/provider/package/zypper.rb b/lib/chef/provider/package/zypper.rb
index b288d5d954..2639f18deb 100644
--- a/lib/chef/provider/package/zypper.rb
+++ b/lib/chef/provider/package/zypper.rb
@@ -22,7 +22,6 @@
require 'chef/provider/package'
require 'chef/mixin/command'
require 'chef/resource/package'
-require 'chef/mixin/shell_out'
require 'singleton'
class Chef
@@ -30,8 +29,6 @@ class Chef
class Package
class Zypper < Chef::Provider::Package
- include Chef::Mixin::ShellOut
-
def load_current_resource
@current_resource = Chef::Resource::Package.new(@new_resource.name)
@current_resource.package_name(@new_resource.package_name)
diff --git a/lib/chef/provider/registry_key.rb b/lib/chef/provider/registry_key.rb
index 3b5be93ba1..01ee57895e 100644
--- a/lib/chef/provider/registry_key.rb
+++ b/lib/chef/provider/registry_key.rb
@@ -25,7 +25,6 @@ require 'chef/provider'
require 'etc'
require 'fileutils'
require 'chef/scan_access_control'
-require 'chef/mixin/shell_out'
require 'chef/win32/registry'
class Chef
@@ -33,7 +32,6 @@ class Chef
class Provider
class RegistryKey < Chef::Provider
include Chef::Mixin::Checksum
- include Chef::Mixin::ShellOut
def whyrun_supported?
true
diff --git a/lib/chef/provider/remote_directory.rb b/lib/chef/provider/remote_directory.rb
index 129c5208f0..77e2754b08 100644
--- a/lib/chef/provider/remote_directory.rb
+++ b/lib/chef/provider/remote_directory.rb
@@ -40,7 +40,6 @@ class Chef
name !~ /(?:^|#{Regexp.escape(::File::SEPARATOR)})\.\.?$/
end)
-
files_to_transfer.each do |cookbook_file_relative_path|
create_cookbook_file(cookbook_file_relative_path)
# the file is removed from the purge list
diff --git a/lib/chef/provider/remote_file.rb b/lib/chef/provider/remote_file.rb
index ed99c0bb84..da2573dacb 100644
--- a/lib/chef/provider/remote_file.rb
+++ b/lib/chef/provider/remote_file.rb
@@ -50,4 +50,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/provider/remote_file/cache_control_data.rb b/lib/chef/provider/remote_file/cache_control_data.rb
index 0add74f50a..8331f3d31a 100644
--- a/lib/chef/provider/remote_file/cache_control_data.rb
+++ b/lib/chef/provider/remote_file/cache_control_data.rb
@@ -161,5 +161,3 @@ class Chef
end
end
end
-
-
diff --git a/lib/chef/provider/remote_file/fetcher.rb b/lib/chef/provider/remote_file/fetcher.rb
index c3a098ed35..249b29186f 100644
--- a/lib/chef/provider/remote_file/fetcher.rb
+++ b/lib/chef/provider/remote_file/fetcher.rb
@@ -17,7 +17,6 @@
# limitations under the License.
#
-
class Chef
class Provider
class RemoteFile
@@ -40,4 +39,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/provider/remote_file/ftp.rb b/lib/chef/provider/remote_file/ftp.rb
index 7f3fdbf383..3f78286aa3 100644
--- a/lib/chef/provider/remote_file/ftp.rb
+++ b/lib/chef/provider/remote_file/ftp.rb
@@ -81,7 +81,6 @@ class Chef
@filename
end
-
def fetch
with_connection do
get
diff --git a/lib/chef/provider/resource_update.rb b/lib/chef/provider/resource_update.rb
index 54f25738ed..e069a8201c 100644
--- a/lib/chef/provider/resource_update.rb
+++ b/lib/chef/provider/resource_update.rb
@@ -50,6 +50,3 @@ class Chef
end
end
end
-
-
-
diff --git a/lib/chef/provider/service/freebsd.rb b/lib/chef/provider/service/freebsd.rb
index 7da29851c2..800cd4ec13 100644
--- a/lib/chef/provider/service/freebsd.rb
+++ b/lib/chef/provider/service/freebsd.rb
@@ -16,7 +16,6 @@
# limitations under the License.
#
-require 'chef/mixin/shell_out'
require 'chef/resource/service'
require 'chef/provider/service/init'
require 'chef/mixin/command'
@@ -26,8 +25,6 @@ class Chef
class Service
class Freebsd < Chef::Provider::Service::Init
- include Chef::Mixin::ShellOut
-
def load_current_resource
@current_resource = Chef::Resource::Service.new(@new_resource.name)
@current_resource.service_name(@new_resource.service_name)
diff --git a/lib/chef/provider/service/init.rb b/lib/chef/provider/service/init.rb
index 64f4074d8b..cf5da852c3 100644
--- a/lib/chef/provider/service/init.rb
+++ b/lib/chef/provider/service/init.rb
@@ -16,7 +16,6 @@
# limitations under the License.
#
-require 'chef/mixin/shell_out'
require 'chef/provider/service/simple'
require 'chef/mixin/command'
@@ -25,8 +24,6 @@ class Chef
class Service
class Init < Chef::Provider::Service::Simple
- include Chef::Mixin::ShellOut
-
def initialize(new_resource, run_context)
super
@init_command = "/etc/init.d/#{@new_resource.service_name}"
diff --git a/lib/chef/provider/service/macosx.rb b/lib/chef/provider/service/macosx.rb
index 2642a7e204..36930ee4ac 100644
--- a/lib/chef/provider/service/macosx.rb
+++ b/lib/chef/provider/service/macosx.rb
@@ -24,7 +24,6 @@ class Chef
class Provider
class Service
class Macosx < Chef::Provider::Service::Simple
- include Chef::Mixin::ShellOut
def self.gather_plist_dirs
locations = %w{/Library/LaunchAgents
diff --git a/lib/chef/provider/service/redhat.rb b/lib/chef/provider/service/redhat.rb
index 5275bcac29..7a7b2a1c40 100644
--- a/lib/chef/provider/service/redhat.rb
+++ b/lib/chef/provider/service/redhat.rb
@@ -17,13 +17,11 @@
#
require 'chef/provider/service/init'
-require 'chef/mixin/shell_out'
class Chef
class Provider
class Service
class Redhat < Chef::Provider::Service::Init
- include Chef::Mixin::ShellOut
CHKCONFIG_ON = /\d:on/
CHKCONFIG_MISSING = /No such/
diff --git a/lib/chef/provider/service/simple.rb b/lib/chef/provider/service/simple.rb
index 3b3e539d40..f03b8a18a1 100644
--- a/lib/chef/provider/service/simple.rb
+++ b/lib/chef/provider/service/simple.rb
@@ -16,7 +16,6 @@
# limitations under the License.
#
-require 'chef/mixin/shell_out'
require 'chef/provider/service'
require 'chef/resource/service'
require 'chef/mixin/command'
@@ -26,8 +25,6 @@ class Chef
class Service
class Simple < Chef::Provider::Service
- include Chef::Mixin::ShellOut
-
def load_current_resource
@current_resource = Chef::Resource::Service.new(@new_resource.name)
@current_resource.service_name(@new_resource.service_name)
diff --git a/lib/chef/provider/service/solaris.rb b/lib/chef/provider/service/solaris.rb
index 69a79e6226..0c47a3462b 100644
--- a/lib/chef/provider/service/solaris.rb
+++ b/lib/chef/provider/service/solaris.rb
@@ -16,7 +16,6 @@
# limitations under the License.
#
-require 'chef/mixin/shell_out'
require 'chef/provider/service'
require 'chef/resource/service'
require 'chef/mixin/command'
@@ -25,7 +24,6 @@ class Chef
class Provider
class Service
class Solaris < Chef::Provider::Service
- include Chef::Mixin::ShellOut
attr_reader :maintenance
def initialize(new_resource, run_context=nil)
@@ -35,7 +33,6 @@ class Chef
@maintenace = false
end
-
def load_current_resource
@current_resource = Chef::Resource::Service.new(@new_resource.name)
@current_resource.service_name(@new_resource.service_name)
diff --git a/lib/chef/provider/service/systemd.rb b/lib/chef/provider/service/systemd.rb
index ea43e658e4..6231603d03 100644
--- a/lib/chef/provider/service/systemd.rb
+++ b/lib/chef/provider/service/systemd.rb
@@ -18,7 +18,6 @@
require 'chef/resource/service'
require 'chef/provider/service/simple'
-require 'chef/mixin/shell_out'
class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
def load_current_resource
diff --git a/lib/chef/provider/service/windows.rb b/lib/chef/provider/service/windows.rb
index 2cfa9d44c1..2d478fa9fe 100644
--- a/lib/chef/provider/service/windows.rb
+++ b/lib/chef/provider/service/windows.rb
@@ -18,7 +18,6 @@
# limitations under the License.
#
-require 'chef/mixin/shell_out'
require 'chef/provider/service/simple'
if RUBY_PLATFORM =~ /mswin|mingw32|windows/
require 'win32/service'
@@ -26,8 +25,6 @@ end
class Chef::Provider::Service::Windows < Chef::Provider::Service
- include Chef::Mixin::ShellOut
-
#Win32::Service.get_start_type
AUTO_START = 'auto start'
DISABLED = 'disabled'
diff --git a/lib/chef/provider/subversion.rb b/lib/chef/provider/subversion.rb
index 6ceb3e592a..81ed639c53 100644
--- a/lib/chef/provider/subversion.rb
+++ b/lib/chef/provider/subversion.rb
@@ -16,7 +16,6 @@
# limitations under the License.
#
-
#TODO subversion and git should both extend from a base SCM provider.
require 'chef/log'
@@ -199,7 +198,6 @@ class Chef
['svn', *args].compact.join(" ")
end
-
def target_dir_non_existent_or_empty?
!::File.exist?(@new_resource.destination) || Dir.entries(@new_resource.destination).sort == ['.','..']
end
diff --git a/lib/chef/provider/template.rb b/lib/chef/provider/template.rb
index 555f4f14f0..48cc45f3a8 100644
--- a/lib/chef/provider/template.rb
+++ b/lib/chef/provider/template.rb
@@ -22,7 +22,6 @@ require 'chef/provider/file'
require 'chef/deprecation/provider/template'
require 'chef/deprecation/warnings'
-
class Chef
class Provider
class Template < Chef::Provider::File
@@ -63,4 +62,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/provider/template/content.rb b/lib/chef/provider/template/content.rb
index 472ea331a3..7fc680ec85 100644
--- a/lib/chef/provider/template/content.rb
+++ b/lib/chef/provider/template/content.rb
@@ -58,4 +58,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/provider/user/dscl.rb b/lib/chef/provider/user/dscl.rb
index b01931609e..96b5db24ba 100644
--- a/lib/chef/provider/user/dscl.rb
+++ b/lib/chef/provider/user/dscl.rb
@@ -16,7 +16,6 @@
# limitations under the License.
#
-require 'chef/mixin/shell_out'
require 'chef/provider/user'
require 'openssl'
@@ -24,7 +23,6 @@ class Chef
class Provider
class User
class Dscl < Chef::Provider::User
- include Chef::Mixin::ShellOut
NFS_HOME_DIRECTORY = %r{^NFSHomeDirectory: (.*)$}
AUTHENTICATION_AUTHORITY = %r{^AuthenticationAuthority: (.*)$}
diff --git a/lib/chef/provider/user/solaris.rb b/lib/chef/provider/user/solaris.rb
index df491ac697..d480acaced 100644
--- a/lib/chef/provider/user/solaris.rb
+++ b/lib/chef/provider/user/solaris.rb
@@ -89,4 +89,3 @@ class Chef
end
end
end
-
diff --git a/lib/chef/provider/user/useradd.rb b/lib/chef/provider/user/useradd.rb
index 201bcbe542..cad9d58e7e 100644
--- a/lib/chef/provider/user/useradd.rb
+++ b/lib/chef/provider/user/useradd.rb
@@ -17,7 +17,6 @@
#
require 'pathname'
-require 'chef/mixin/shell_out'
require 'chef/provider/user'
class Chef
@@ -25,8 +24,6 @@ class Chef
class User
class Useradd < Chef::Provider::User
- include Chef::Mixin::ShellOut
-
UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:password, "-p"], [:shell, "-s"], [:uid, "-u"]]
def create_user
diff --git a/lib/chef/resource/lwrp_base.rb b/lib/chef/resource/lwrp_base.rb
index b293b85944..5b67941a8b 100644
--- a/lib/chef/resource/lwrp_base.rb
+++ b/lib/chef/resource/lwrp_base.rb
@@ -92,9 +92,16 @@ class Chef
# Sets the default action
def self.default_action(action_name=NULL_ARG)
unless action_name.equal?(NULL_ARG)
- action = action_name.to_sym
- actions.push(action) unless actions.include?(action)
- @default_action = action
+ @actions ||= []
+ if action_name.is_a?(Array)
+ action = action_name.map { |arg| arg.to_sym }
+ @actions = actions | action
+ @default_action = action
+ else
+ action = action_name.to_sym
+ @actions.push(action) unless @actions.include?(action)
+ @default_action = action
+ end
end
@default_action ||= from_superclass(:default_action)
diff --git a/lib/chef/shell/shell_session.rb b/lib/chef/shell/shell_session.rb
index a158020116..73e6c34ebb 100644
--- a/lib/chef/shell/shell_session.rb
+++ b/lib/chef/shell/shell_session.rb
@@ -169,7 +169,7 @@ module Shell
def rebuild_context
@run_status = Chef::RunStatus.new(@node, @events)
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, Chef::Config[:cookbook_path]) }
+ Chef::Cookbook::FileVendor.fetch_from_disk(Chef::Config[:cookbook_path])
cl = Chef::CookbookLoader.new(Chef::Config[:cookbook_path])
cl.load_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cl)
@@ -201,7 +201,7 @@ module Shell
def rebuild_context
@run_status = Chef::RunStatus.new(@node, @events)
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::RemoteFileVendor.new(manifest, Chef::REST.new(Chef::Config[:server_url])) }
+ Chef::Cookbook::FileVendor.fetch_from_remote(Chef::REST.new(Chef::Config[:chef_server_url]))
cookbook_hash = @client.sync_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cookbook_hash)
@run_context = Chef::RunContext.new(node, cookbook_collection, @events)
diff --git a/lib/chef/streaming_cookbook_uploader.rb b/lib/chef/streaming_cookbook_uploader.rb
deleted file mode 100644
index 9e638f6367..0000000000
--- a/lib/chef/streaming_cookbook_uploader.rb
+++ /dev/null
@@ -1,205 +0,0 @@
-# inspired by/cargo-culted from http://stanislavvitvitskiy.blogspot.com/2008/12/multipart-post-in-ruby.html
-# On Apr 6, 2010, at 3:00 PM, Stanislav Vitvitskiy wrote:
-#
-# It's free to use / modify / distribute. No need to mention anything. Just copy/paste and use.
-#
-# Regards,
-# Stan
-
-require 'net/http'
-require 'mixlib/authentication/signedheaderauth'
-require 'openssl'
-require 'chef/version'
-
-class Chef
- class StreamingCookbookUploader
-
- DefaultHeaders = { 'accept' => 'application/json', 'x-chef-version' => ::Chef::VERSION }
-
- class << self
-
- def post(to_url, user_id, secret_key_filename, params = {}, headers = {})
- make_request(:post, to_url, user_id, secret_key_filename, params, headers)
- end
-
- def put(to_url, user_id, secret_key_filename, params = {}, headers = {})
- make_request(:put, to_url, user_id, secret_key_filename, params, headers)
- end
-
- def make_request(http_verb, to_url, user_id, secret_key_filename, params = {}, headers = {})
- Chef::Log.warn('[DEPRECATED] StreamingCookbookUploader class is deprecated. It will be removed in Chef 12. Please use CookbookSiteStreamingUploader instead.')
- boundary = '----RubyMultipartClient' + rand(1000000).to_s + 'ZZZZZ'
- parts = []
- content_file = nil
-
- timestamp = Time.now.utc.iso8601
- secret_key = OpenSSL::PKey::RSA.new(File.read(secret_key_filename))
-
- unless params.nil? || params.empty?
- params.each do |key, value|
- if value.kind_of?(File)
- content_file = value
- filepath = value.path
- filename = File.basename(filepath)
- parts << StringPart.new( "--" + boundary + "\r\n" +
- "Content-Disposition: form-data; name=\"" + key.to_s + "\"; filename=\"" + filename + "\"\r\n" +
- "Content-Type: application/octet-stream\r\n\r\n")
- parts << StreamPart.new(value, File.size(filepath))
- parts << StringPart.new("\r\n")
- else
- parts << StringPart.new( "--" + boundary + "\r\n" +
- "Content-Disposition: form-data; name=\"" + key.to_s + "\"\r\n\r\n")
- parts << StringPart.new(value.to_s + "\r\n")
- end
- end
- parts << StringPart.new("--" + boundary + "--\r\n")
- end
-
- body_stream = MultipartStream.new(parts)
-
- timestamp = Time.now.utc.iso8601
-
- url = URI.parse(to_url)
-
- Chef::Log.logger.debug("Signing: method: #{http_verb}, path: #{url.path}, file: #{content_file}, User-id: #{user_id}, Timestamp: #{timestamp}")
-
- # We use the body for signing the request if the file parameter
- # wasn't a valid file or wasn't included. Extract the body (with
- # multi-part delimiters intact) to sign the request.
- # TODO: tim: 2009-12-28: It'd be nice to remove this special case, and
- # always hash the entire request body. In the file case it would just be
- # expanded multipart text - the entire body of the POST.
- content_body = parts.inject("") { |result,part| result + part.read(0, part.size) }
- content_file.rewind if content_file # we consumed the file for the above operation, so rewind it.
-
- signing_options = {
- :http_method=>http_verb,
- :path=>url.path,
- :user_id=>user_id,
- :timestamp=>timestamp}
- (content_file && signing_options[:file] = content_file) || (signing_options[:body] = (content_body || ""))
-
- headers.merge!(Mixlib::Authentication::SignedHeaderAuth.signing_object(signing_options).sign(secret_key))
-
- content_file.rewind if content_file
-
- # net/http doesn't like symbols for header keys, so we'll to_s each one just in case
- headers = DefaultHeaders.merge(Hash[*headers.map{ |k,v| [k.to_s, v] }.flatten])
-
- req = case http_verb
- when :put
- Net::HTTP::Put.new(url.path, headers)
- when :post
- Net::HTTP::Post.new(url.path, headers)
- end
- req.content_length = body_stream.size
- req.content_type = 'multipart/form-data; boundary=' + boundary unless parts.empty?
- req.body_stream = body_stream
-
- http = Net::HTTP.new(url.host, url.port)
- if url.scheme == "https"
- http.use_ssl = true
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
- end
- res = http.request(req)
- #res = http.start {|http_proc| http_proc.request(req) }
-
- # alias status to code and to_s to body for test purposes
- # TODO: stop the following madness!
- class << res
- alias :to_s :body
-
- # BUGBUG this makes the response compatible with what respsonse_steps expects to test headers (response.headers[] -> response[])
- def headers
- self
- end
-
- def status
- code.to_i
- end
- end
- res
- end
-
- end
-
- class StreamPart
- def initialize(stream, size)
- Chef::Log.warn('[DEPRECATED] StreamingCookbookUploader::StreamPart class is deprecated. It will be removed in Chef 12. Please use CookbookSiteStreamingUploader::StreamPart instead.')
- @stream, @size = stream, size
- end
-
- def size
- @size
- end
-
- # read the specified amount from the stream
- def read(offset, how_much)
- @stream.read(how_much)
- end
- end
-
- class StringPart
- def initialize(str)
- Chef::Log.warn('[DEPRECATED] StreamingCookbookUploader::StringPart class is deprecated. It will be removed in Chef 12. Please use CookbookSiteStreamingUploader::StringPart instead.')
- @str = str
- end
-
- def size
- @str.length
- end
-
- # read the specified amount from the string startiung at the offset
- def read(offset, how_much)
- @str[offset, how_much]
- end
- end
-
- class MultipartStream
- def initialize(parts)
- Chef::Log.warn('[DEPRECATED] StreamingCookbookUploader::MultipartStream class is deprecated. It will be removed in Chef 12. Please use CookbookSiteStreamingUploader::MultipartStream instead.')
- @parts = parts
- @part_no = 0
- @part_offset = 0
- end
-
- def size
- @parts.inject(0) {|size, part| size + part.size}
- end
-
- def read(how_much)
- return nil if @part_no >= @parts.size
-
- how_much_current_part = @parts[@part_no].size - @part_offset
-
- how_much_current_part = if how_much_current_part > how_much
- how_much
- else
- how_much_current_part
- end
-
- how_much_next_part = how_much - how_much_current_part
-
- current_part = @parts[@part_no].read(@part_offset, how_much_current_part)
-
- # recurse into the next part if the current one was not large enough
- if how_much_next_part > 0
- @part_no += 1
- @part_offset = 0
- next_part = read(how_much_next_part)
- current_part + if next_part
- next_part
- else
- ''
- end
- else
- @part_offset += how_much_current_part
- current_part
- end
- end
- end
-
- end
-
-
-end
diff --git a/lib/chef/tasks/chef_repo.rake b/lib/chef/tasks/chef_repo.rake
index 704557ebb3..14a5bcc0c1 100644
--- a/lib/chef/tasks/chef_repo.rake
+++ b/lib/chef/tasks/chef_repo.rake
@@ -1,6 +1,7 @@
#
# Author:: Adam Jacob (<adam@opscode.com>)
# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Copyright:: Copyright (c) 2014, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,320 +16,186 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-
-require 'rubygems'
-require 'chef/json_compat'
-require 'chef'
-require 'chef/role'
-require 'chef/cookbook/metadata'
-require 'tempfile'
+TOPDIR = '.'
require 'rake'
-# Allow REMOTE options to be overridden on the command line
-REMOTE_HOST = ENV["REMOTE_HOST"] if ENV["REMOTE_HOST"] != nil
-REMOTE_SUDO = ENV["REMOTE_SUDO"] if ENV["REMOTE_SUDO"] != nil
-if defined? REMOTE_HOST
- REMOTE_PATH_PREFIX = "#{REMOTE_HOST}:"
- REMOTE_EXEC_PREFIX = "ssh #{REMOTE_HOST}"
- REMOTE_EXEC_PREFIX += " sudo" if defined? REMOTE_SUDO
- LOCAL_EXEC_PREFIX = ""
-else
- REMOTE_PATH_PREFIX = ""
- REMOTE_EXEC_PREFIX = ""
- LOCAL_EXEC_PREFIX = "sudo"
-end
-
-desc "Update your repository from source control"
-task :update do
- puts "** Updating your repository"
-
- case $vcs
- when :svn
- sh %{svn up}
- when :git
- pull = false
- IO.foreach(File.join(TOPDIR, ".git", "config")) do |line|
- pull = true if line =~ /\[remote "origin"\]/
- end
- if pull
- sh %{git pull}
- else
- puts "* Skipping git pull, no origin specified"
- end
- else
- puts "* No SCM configured, skipping update"
- end
+desc "By default, print deprecation notice"
+task :default do
+ puts deprecation_notice
end
desc "Install the latest copy of the repository on this Chef Server"
-task :install => [ :update, :roles, :upload_cookbooks ] do
- if File.exists?(File.join(TOPDIR, "config", "server.rb"))
- puts "* Installing new Chef Server Config"
- sh "#{LOCAL_EXEC_PREFIX} rsync -rlt --delete --exclude '.svn' --exclude '.git*' config/server.rb #{REMOTE_PATH_PREFIX}#{CHEF_SERVER_CONFIG}"
- end
- if File.exists?(File.join(TOPDIR, "config", "client.rb"))
- puts "* Installing new Chef Client Config"
- sh "#{LOCAL_EXEC_PREFIX} rsync -rlt --delete --exclude '.svn' --exclude '.git*' config/client.rb #{REMOTE_PATH_PREFIX}#{CHEF_CLIENT_CONFIG}"
- end
+task :install do
+ puts deprecation_notice
+ puts 'The `install` rake task, which included the `update`, `roles`, and'
+ puts '`upload_cookbooks` rake tasks is replaced by the `knife upload`'
+ puts 'sub-command. The notion of "installing" the chef-repo to the Chef'
+ puts 'Server. Previously the `install` task would manage server and'
+ puts 'client configuration. This will not work at all on Chef Server 11+'
+ puts 'and client configuration should be managed with the `chef-client`'
+ puts 'cookbook.'
end
-desc "By default, run rake test_cookbooks"
-task :default => [ :test_cookbooks ]
+desc "Update your repository from source control"
+task :update do
+ puts deprecation_notice
+ puts 'The `update` rake task previously updated the chef-repo from'
+ puts 'the detected version control system, either svn or git. However,'
+ puts 'it has not been recommended for users for years. Most users in'
+ puts 'the community use `git`, so the Subversion functionality is not'
+ puts 'required, and `git pull` is sufficient for many workflows. The'
+ puts 'world of git workflows is rather different now than it was when'
+ puts 'this rake task was created.'
+end
desc "Create a new cookbook (with COOKBOOK=name, optional CB_PREFIX=site-)"
task :new_cookbook do
- puts "***WARN: rake new_cookbook is deprecated. Please use 'knife cookbook create COOKBOOK' command.***"
- create_cookbook(File.join(TOPDIR, "#{ENV["CB_PREFIX"]}cookbooks"))
- create_readme(File.join(TOPDIR, "#{ENV["CB_PREFIX"]}cookbooks"))
- create_metadata(File.join(TOPDIR, "#{ENV["CB_PREFIX"]}cookbooks"))
-end
-
-def create_cookbook(dir)
- raise "Must provide a COOKBOOK=" unless ENV["COOKBOOK"]
- puts "** Creating cookbook #{ENV["COOKBOOK"]}"
- sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "attributes")}"
- sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "recipes")}"
- sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "definitions")}"
- sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "libraries")}"
- sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "resources")}"
- sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "providers")}"
- sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "files", "default")}"
- sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "templates", "default")}"
- unless File.exists?(File.join(dir, ENV["COOKBOOK"], "recipes", "default.rb"))
- open(File.join(dir, ENV["COOKBOOK"], "recipes", "default.rb"), "w") do |file|
- file.puts <<-EOH
-#
-# Cookbook Name:: #{ENV["COOKBOOK"]}
-# Recipe:: default
-#
-# Copyright #{Time.now.year}, #{COMPANY_NAME}
-#
-EOH
- case NEW_COOKBOOK_LICENSE
- when :apachev2
- file.puts <<-EOH
-# 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.
-#
-EOH
- when :none
- file.puts <<-EOH
-# All rights reserved - Do Not Redistribute
-#
-EOH
- end
- end
- end
-end
-
-def create_readme(dir)
- raise "Must provide a COOKBOOK=" unless ENV["COOKBOOK"]
- puts "** Creating README for cookbook: #{ENV["COOKBOOK"]}"
- unless File.exists?(File.join(dir, ENV["COOKBOOK"], "README.rdoc"))
- open(File.join(dir, ENV["COOKBOOK"], "README.md"), "w") do |file|
- file.puts <<-EOH
-Description
-===========
-
-Requirements
-============
-
-Attributes
-==========
-
-Usage
-=====
-
-EOH
- end
- end
-end
-
-def create_metadata(dir)
- raise "Must provide a COOKBOOK=" unless ENV["COOKBOOK"]
- puts "** Creating metadata for cookbook: #{ENV["COOKBOOK"]}"
-
- case NEW_COOKBOOK_LICENSE
- when :apachev2
- license = "Apache 2.0"
- when :none
- license = "All rights reserved"
- end
-
- unless File.exists?(File.join(dir, ENV["COOKBOOK"], "metadata.rb"))
- open(File.join(dir, ENV["COOKBOOK"], "metadata.rb"), "w") do |file|
- if File.exists?(File.join(dir, ENV["COOKBOOK"], 'README.rdoc'))
- long_description = "long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc'))"
- end
- file.puts <<-EOH
-maintainer "#{COMPANY_NAME}"
-maintainer_email "#{SSL_EMAIL_ADDRESS}"
-license "#{license}"
-description "Installs/Configures #{ENV["COOKBOOK"]}"
-#{long_description}
-version "0.1"
-EOH
- end
- end
+ cb = ENV['COOKBOOK'] || 'my_cookbook_name'
+ puts deprecation_notice
+ puts 'The `new_cookbook` rake task is replaced by the ChefDK cookbook'
+ puts 'generator. To generate a new cookbook run:'
+ puts
+ puts "chef generate cookbook #{ENV['COOKBOOK']}"
+ puts
+ puts 'Or, if you are not using ChefDK, use `knife cookbook create`:'
+ puts
+ puts "knife cookbook create #{ENV['COOKBOOK']}"
end
desc "Create a new self-signed SSL certificate for FQDN=foo.example.com"
task :ssl_cert do
- $expect_verbose = true
- fqdn = ENV["FQDN"]
- fqdn =~ /^(.+?)\.(.+)$/
- hostname = $1
- domain = $2
- raise "Must provide FQDN!" unless fqdn && hostname && domain
- keyfile = fqdn.gsub("*", "wildcard")
- puts "** Creating self signed SSL Certificate for #{fqdn}"
- sh("(cd #{CADIR} && openssl genrsa 2048 > #{keyfile}.key)")
- sh("(cd #{CADIR} && chmod 644 #{keyfile}.key)")
- puts "* Generating Self Signed Certificate Request"
- tf = Tempfile.new("#{keyfile}.ssl-conf")
- ssl_config = <<EOH
-[ req ]
-distinguished_name = req_distinguished_name
-prompt = no
-
-[ req_distinguished_name ]
-C = #{SSL_COUNTRY_NAME}
-ST = #{SSL_STATE_NAME}
-L = #{SSL_LOCALITY_NAME}
-O = #{COMPANY_NAME}
-OU = #{SSL_ORGANIZATIONAL_UNIT_NAME}
-CN = #{fqdn}
-emailAddress = #{SSL_EMAIL_ADDRESS}
-EOH
- tf.puts(ssl_config)
- tf.close
- sh("(cd #{CADIR} && openssl req -config '#{tf.path}' -new -x509 -nodes -sha1 -days 3650 -key #{keyfile}.key > #{keyfile}.crt)")
- sh("(cd #{CADIR} && openssl x509 -noout -fingerprint -text < #{keyfile}.crt > #{keyfile}.info)")
- sh("(cd #{CADIR} && cat #{keyfile}.crt #{keyfile}.key > #{keyfile}.pem)")
- sh("(cd #{CADIR} && chmod 644 #{keyfile}.pem)")
-end
-
-rule(%r{\b(?:site-)?cookbooks/[^/]+/metadata\.json\Z} => [ proc { |task_name| task_name.sub(/\.[^.]+$/, '.rb') } ]) do |t|
- system("knife cookbook metadata from file #{t.source}")
+ puts deprecation_notice
+ puts 'The `ssl_cert` rake task is superseded by using the CHEF-maintained'
+ puts '`openssl` cookbook\'s `openssl_x509` resource which can generate'
+ puts 'self-signed certificate chains as convergent resources.'
+ puts
+ puts 'https://supermarket.getchef.com/cookbooks/openssl'
end
desc "Build cookbook metadata.json from metadata.rb"
-task :metadata => FileList[File.join(TOPDIR, '*cookbooks', ENV['COOKBOOK'] || '*', 'metadata.rb')].pathmap('%X.json')
-
-rule(%r{\broles/\S+\.json\Z} => [ proc { |task_name| task_name.sub(/\.[^.]+$/, '.rb') } ]) do |t|
- system("knife role from file #{t.source}")
+task :metadata do
+ puts deprecation_notice
+ puts 'The `metadata` rake task is not recommended. Cookbook'
+ puts '`metadata.json` is automatically generated from `metadata.rb`'
+ puts 'by `knife` when uploading cookbooks to the Chef Server.'
end
desc "Update roles"
-task :roles => FileList[File.join(TOPDIR, 'roles', '**', '*.rb')].pathmap('%X.json')
+task :roles do
+ puts deprecation_notice
+ puts 'The `roles` rake task is not recommended. If you are using Ruby'
+ puts 'role files (roles/*.rb), you can upload them all with:'
+ puts
+ puts 'knife role from file roles/*'
+ puts
+ puts 'If you are using JSON role files (roles/*.json), you can upload'
+ puts 'them all with:'
+ puts
+ puts 'knife upload roles/*.json'
+end
desc "Update a specific role"
-task :role, :role_name do |t, args|
- system("knife role from file #{File.join(TOPDIR, 'roles', args.role_name)}.rb")
+task :role do
+ puts deprecation_notice
+ puts 'The `role` rake task is not recommended. If you are using Ruby'
+ puts 'role files, you can upload a single role with:'
+ puts
+ puts 'knife role from file rolename.rb'
+ puts
+ puts 'If you are using JSON role files, you can upload a single role with'
+ puts
+ puts 'knife upload roles/rolename.json'
end
desc "Upload all cookbooks"
-task :upload_cookbooks => [ :metadata ]
task :upload_cookbooks do
- system("knife cookbook upload --all")
+ puts deprecation_notice
+ puts deprecated_cookbook_upload
end
desc "Upload a single cookbook"
-task :upload_cookbook => [ :metadata ]
-task :upload_cookbook, :cookbook do |t, args|
- system("knife cookbook upload #{args.cookbook}")
+task :upload_cookbook do
+ puts deprecation_notice
+ puts deprecated_cookbook_upload
end
desc "Test all cookbooks"
task :test_cookbooks do
- system("knife cookbook test --all")
+ puts deprecation_notice
+ puts 'The `test_cookbooks` rake task is no longer recommended. Previously'
+ puts 'it only performed a syntax check, and did no other kind of testing,'
+ puts 'and the Chef Community has a rich ecosystem of testing tools for'
+ puts 'various purposes:'
+ puts
+ puts '- knife cookbook test will perform a syntax check, as this task did'
+ puts ' before.'
+ puts '- rubocop and foodcritic will perform lint checking for Ruby and'
+ puts ' Chef cookbook style according to community standards.'
+ puts '- ChefSpec will perform unit testing'
+ puts '- Test Kitchen will perform convergence and post-convergence'
+ puts ' testing on virtual machines.'
end
desc "Test a single cookbook"
-task :test_cookbook, :cookbook do |t, args|
- system("knife cookbook test #{args.cookbook}")
-end
+task :test_cookbook => [:test_cookbooks]
namespace :databag do
- path = "data_bags"
-
desc "Upload a single databag"
- task :upload, :databag do |t, args|
- input_databag = args[:databag] || 'none_specified'
- databag = File.join(path, input_databag)
-
- if File.exists?(databag) && File.directory?(databag)
- system "knife data bag create #{input_databag}"
- Dir.foreach(databag) do |item|
- name, type = item.split('.')
- if type == 'json' && name.length > 0
- system "knife data bag from file #{input_databag} " + File.join(databag, item)
- end
- end
- else
- puts "ERROR: Could not find the databag in your databag path (" + File.join(path, input_databag) + "), skipping it"
- end
+ task :upload do
+ puts deprecation_notice
+ puts 'The `data_bags:upload` task is not recommended. You should use'
+ puts 'the `knife upload` sub-command for uploading data bag items.'
+ puts
+ puts 'knife upload data_bags/bagname/itemname.json'
end
desc "Upload all databags"
task :upload_all do
- if File.exists?(path) && File.directory?(path)
- Dir.foreach(path) do |databag|
- if databag == databag[/^[\-[:alnum:]_]+$/]
- Rake::Task['databag:upload'].execute( { :databag => databag } )
- end
- end
- else
- puts "ERROR: Could not find any databags, skipping it"
- end
+ puts deprecation_notice
+ puts 'The `data_bags:upload_all` task is not recommended. You should'
+ puts 'use the `knife upload` sub-command for uploading data bag items.'
+ puts
+ puts 'knife upload data_bags/*'
end
desc "Create a databag"
- task :create, :databag do |t, args|
- input_databag = args[:databag] || 'none_specified'
-
- FileUtils.mkdir(path) unless File.exists?(path)
- databag = File.join(path, input_databag)
- FileUtils.mkdir(databag) unless File.exists?(databag)
+ task :create do
+ puts deprecation_notice
+ puts deprecated_data_bag_creation
end
desc "Create a databag item stub"
- task :create_item, :databag, :item do |t, args|
- input_databag = args[:databag] || 'none_specified'
- input_item = args[:item] || false
-
- databag = File.join(path, input_databag)
- if File.exists?(databag) && File.directory?(databag)
- if input_item
- json_filename = File.join(databag, "#{input_item}.json")
- if !File.exists?(json_filename)
- stub = <<EOH
-{
- "id" : "#{input_item}"
-}
-EOH
- json_file = File.new(json_filename, "w")
- json_file.write(stub)
- json_file.close
- else
- puts "ERROR: databag item already exists (#{json_filename}), skipping it"
- end
- else
- puts "ERROR: No item id specified, skipping it"
- end
- else
- puts "ERROR: Could not find your databag (#{databag}), skipping it"
- end
+ task :create_item do
+ puts deprecation_notice
+ puts deprecated_data_bag_creation
end
+end
+
+def deprecation_notice
+ %Q[*************************************************
+NOTICE: Chef Repository Rake Tasks Are Deprecated
+*************************************************
+]
end
+def deprecated_cookbook_upload
+ %Q[
+The `upload_cookbook` and `upload_cookbooks` rake tasks are not
+recommended. These tasks are replaced by other, better workflow
+tools, such as `knife cookbook upload`, `knife upload`, or `berks`
+]
+end
+
+def deprecated_data_bag_creation
+ %Q[
+The `data_bags:create` and `data_bags:create_item` tasks are not
+recommended. You should create data bag items as JSON files in the data_bags
+directory, with a sub-directory for each bag, and use `knife upload` to
+upload them. For example, if you have a data bags named `users`, with
+`finn`, and `jake` items, you would have:
+
+./data_bags/users/finn.json
+./data-bags/users/jake.json
+]
+end
diff --git a/pedant.gemfile b/pedant.gemfile
index 8f223defde..2ce3ed27fb 100644
--- a/pedant.gemfile
+++ b/pedant.gemfile
@@ -1,8 +1,8 @@
source "https://rubygems.org"
gemspec :name => "chef"
-gem 'rest-client', :github => 'opscode/rest-client'
-gem 'chef-pedant', :github => 'opscode/chef-pedant', :ref => '4744d7f318b629ff60a0d22cf02296df36936397'
+gem 'rest-client', :github => 'opscode/rest-client', :branch => 'lcg/1.6.7-version-lying'
+gem 'chef-pedant', :github => 'opscode/chef-pedant', :ref => 'd12864964a18994b467908daa91811eee1f1bf68'
# TODO figure out how to grab this stuff from the main Gemfile
gem "activesupport", "< 4.0.0", :group => :compat_testing, :platform => "ruby"
diff --git a/spec/functional/resource/base.rb b/spec/functional/resource/base.rb
index 056db39877..cdb52fbc1b 100644
--- a/spec/functional/resource/base.rb
+++ b/spec/functional/resource/base.rb
@@ -16,16 +16,6 @@
# limitations under the License.
#
-require 'spec_helper'
-
-def ohai
- # provider is platform-dependent, we need platform ohai data:
- @OHAI_SYSTEM ||= begin
- ohai = Ohai::System.new
- ohai.all_plugins("platform")
- ohai
- end
-end
def run_context
@run_context ||= begin
diff --git a/spec/functional/resource/cookbook_file_spec.rb b/spec/functional/resource/cookbook_file_spec.rb
index 173dac8268..7797ed0041 100644
--- a/spec/functional/resource/cookbook_file_spec.rb
+++ b/spec/functional/resource/cookbook_file_spec.rb
@@ -40,7 +40,7 @@ describe Chef::Resource::CookbookFile do
# set up cookbook collection for this run to use, based on our
# spec data.
cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, 'cookbooks'))
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, cookbook_repo) }
+ Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_repo)
loader = Chef::CookbookLoader.new(cookbook_repo)
loader.load_cookbooks
cookbook_collection = Chef::CookbookCollection.new(loader)
diff --git a/spec/functional/resource/package_spec.rb b/spec/functional/resource/package_spec.rb
index 797f308cf9..548db40e79 100644
--- a/spec/functional/resource/package_spec.rb
+++ b/spec/functional/resource/package_spec.rb
@@ -135,9 +135,7 @@ describe Chef::Resource::Package, metadata do
cookbook_path = File.join(CHEF_SPEC_DATA, "cookbooks")
cl = Chef::CookbookLoader.new(cookbook_path)
cl.load_cookbooks
- Chef::Cookbook::FileVendor.on_create do |manifest|
- Chef::Cookbook::FileSystemFileVendor.new(manifest, cookbook_path)
- end
+ Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_path)
Chef::CookbookCollection.new(cl)
end
diff --git a/spec/functional/resource/remote_directory_spec.rb b/spec/functional/resource/remote_directory_spec.rb
index 70e575abb0..f9eb20711e 100644
--- a/spec/functional/resource/remote_directory_spec.rb
+++ b/spec/functional/resource/remote_directory_spec.rb
@@ -26,7 +26,7 @@ describe Chef::Resource::RemoteDirectory do
def create_resource
cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, cookbook_repo) }
+ Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_repo)
node = Chef::Node.new
cl = Chef::CookbookLoader.new(cookbook_repo)
cl.load_cookbooks
diff --git a/spec/functional/resource/template_spec.rb b/spec/functional/resource/template_spec.rb
index 7816d6357b..fefd995743 100644
--- a/spec/functional/resource/template_spec.rb
+++ b/spec/functional/resource/template_spec.rb
@@ -37,7 +37,7 @@ describe Chef::Resource::Template do
def create_resource
cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, cookbook_repo) }
+ Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_repo)
cl = Chef::CookbookLoader.new(cookbook_repo)
cl.load_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cl)
diff --git a/spec/integration/knife/chef_fs_data_store_spec.rb b/spec/integration/knife/chef_fs_data_store_spec.rb
index e8a3b3dde5..7e55aa7319 100644
--- a/spec/integration/knife/chef_fs_data_store_spec.rb
+++ b/spec/integration/knife/chef_fs_data_store_spec.rb
@@ -141,7 +141,7 @@ EOM
end
it 'knife cookbook upload works' do
- knife("cookbook upload -z --cookbook-path #{path_to('cookbooks_to_upload')} x").should_succeed <<EOM
+ knife("cookbook upload -z --cookbook-path #{path_to('cookbooks_to_upload')} x").should_succeed :stderr => <<EOM
Uploading x [1.0.0]
Uploaded 1 cookbook.
EOM
@@ -199,7 +199,7 @@ EOM
end
it 'knife cookbook upload works' do
- knife("cookbook upload -z --cookbook-path #{path_to('cookbooks_to_upload')} z").should_succeed <<EOM
+ knife("cookbook upload -z --cookbook-path #{path_to('cookbooks_to_upload')} z").should_succeed :stderr => <<EOM
Uploading z [1.0.0]
Uploaded 1 cookbook.
EOM
diff --git a/spec/support/platform_helpers.rb b/spec/support/platform_helpers.rb
index 75ab0c9cde..ad7104d170 100644
--- a/spec/support/platform_helpers.rb
+++ b/spec/support/platform_helpers.rb
@@ -27,6 +27,11 @@ def windows?
!!(RUBY_PLATFORM =~ /mswin|mingw|windows/)
end
+def ohai
+ # This is defined in spec_helper; it has the `platform` populated.
+ OHAI_SYSTEM
+end
+
require 'wmi-lite/wmi' if windows?
def windows_domain_joined?
diff --git a/spec/unit/cookbook/file_vendor_spec.rb b/spec/unit/cookbook/file_vendor_spec.rb
new file mode 100644
index 0000000000..4fad7d5808
--- /dev/null
+++ b/spec/unit/cookbook/file_vendor_spec.rb
@@ -0,0 +1,78 @@
+#--
+# Author:: Daniel DeLeo (<dan@getchef.com>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+require 'spec_helper'
+
+describe Chef::Cookbook::FileVendor do
+
+ let(:file_vendor_class) { Class.new(described_class) }
+
+ # A manifest is a Hash of the format defined by Chef::CookbookVersion#manifest
+ let(:manifest) { {:cookbook_name => "bob"} }
+
+ context "when configured to fetch files over http" do
+
+ let(:http) { double("Chef::REST") }
+
+ before do
+ file_vendor_class.fetch_from_remote(http)
+ end
+
+ it "sets the vendor class to RemoteFileVendor" do
+ expect(file_vendor_class.vendor_class).to eq(Chef::Cookbook::RemoteFileVendor)
+ end
+
+ it "sets the initialization options to the given http object" do
+ expect(file_vendor_class.initialization_options).to eq(http)
+ end
+
+ it "creates a RemoteFileVendor for a given manifest" do
+ file_vendor = file_vendor_class.create_from_manifest(manifest)
+ expect(file_vendor).to be_a_kind_of(Chef::Cookbook::RemoteFileVendor)
+ expect(file_vendor.rest).to eq(http)
+ expect(file_vendor.cookbook_name).to eq("bob")
+ end
+
+ end
+
+ context "when configured to load files from disk" do
+
+ let(:cookbook_path) { %w[/var/chef/cookbooks /var/chef/other_cookbooks] }
+
+ before do
+ file_vendor_class.fetch_from_disk(cookbook_path)
+ end
+
+ it "sets the vendor class to FileSystemFileVendor" do
+ expect(file_vendor_class.vendor_class).to eq(Chef::Cookbook::FileSystemFileVendor)
+ end
+
+ it "sets the initialization options to the given cookbook paths" do
+ expect(file_vendor_class.initialization_options).to eq(cookbook_path)
+ end
+
+ it "creates a FileSystemFileVendor for a given manifest" do
+ file_vendor = file_vendor_class.create_from_manifest(manifest)
+ expect(file_vendor).to be_a_kind_of(Chef::Cookbook::FileSystemFileVendor)
+ expect(file_vendor.cookbook_name).to eq("bob")
+ expect(file_vendor.repo_paths).to eq(cookbook_path)
+ end
+
+ end
+
+end
+
diff --git a/spec/unit/cookbook/synchronizer_spec.rb b/spec/unit/cookbook/synchronizer_spec.rb
index c52593287a..2b040f3c95 100644
--- a/spec/unit/cookbook/synchronizer_spec.rb
+++ b/spec/unit/cookbook/synchronizer_spec.rb
@@ -5,302 +5,517 @@ require 'chef/cookbook_version'
describe Chef::CookbookCacheCleaner do
describe "when cleaning up unused cookbook components" do
- before do
- @cleaner = Chef::CookbookCacheCleaner.instance
- @cleaner.reset!
+ let(:cleaner) do
+ cleaner = Chef::CookbookCacheCleaner.instance
+ cleaner.reset!
+ cleaner
end
- it "removes all files that belong to unused cookbooks" do
- end
+ let(:file_cache) { double("Chef::FileCache with files from unused cookbooks") }
- it "removes all files not validated during the chef run" do
- file_cache = double("Chef::FileCache with files from unused cookbooks")
- unused_template_files = %w{cookbooks/unused/templates/default/foo.conf.erb cookbooks/unused/tempaltes/default/bar.conf.erb}
- valid_cached_cb_files = %w{cookbooks/valid1/recipes/default.rb cookbooks/valid2/recipes/default.rb}
- @cleaner.mark_file_as_valid('cookbooks/valid1/recipes/default.rb')
- @cleaner.mark_file_as_valid('cookbooks/valid2/recipes/default.rb')
- file_cache.should_receive(:find).with(File.join(%w{cookbooks ** *})).and_return(valid_cached_cb_files + unused_template_files)
- file_cache.should_receive(:delete).with('cookbooks/unused/templates/default/foo.conf.erb')
- file_cache.should_receive(:delete).with('cookbooks/unused/tempaltes/default/bar.conf.erb')
- cookbook_hash = {"valid1"=> {}, "valid2" => {}}
- @cleaner.stub(:cache).and_return(file_cache)
- @cleaner.cleanup_file_cache
+ let(:unused_template_files) do
+ %w{
+ cookbooks/unused/templates/default/foo.conf.erb
+ cookbooks/unused/tempaltes/default/bar.conf.erb
+ }
end
- describe "on chef-solo" do
- before do
- Chef::Config[:solo] = true
- end
+ let(:valid_cached_cb_files) do
+ %w{
+ cookbooks/valid1/recipes/default.rb
+ cookbooks/valid2/recipes/default.rb
+ }
+ end
- after do
- Chef::Config[:solo] = false
+ before do
+ valid_cached_cb_files.each do |cbf|
+ cleaner.mark_file_as_valid(cbf)
end
+ end
- it "does not remove anything" do
- @cleaner.cache.stub(:find).and_return(%w{cookbooks/valid1/recipes/default.rb cookbooks/valid2/recipes/default.rb})
- @cleaner.cache.should_not_receive(:delete)
- @cleaner.cleanup_file_cache
+ it "removes all files not validated during the chef run" do
+ expect(file_cache).to receive(:find).with(File.join(%w{cookbooks ** {*,.*}})).and_return(valid_cached_cb_files + unused_template_files)
+ unused_template_files.each do |cbf|
+ expect(file_cache).to receive(:delete).with(cbf)
end
+ cookbook_hash = {"valid1"=> {}, "valid2" => {}}
+ allow(cleaner).to receive(:cache).and_return(file_cache)
+ cleaner.cleanup_file_cache
+ end
+ it "does not remove anything when skip_removal is true" do
+ cleaner.skip_removal = true
+ allow(cleaner.cache).to receive(:find).and_return(%w{cookbooks/valid1/recipes/default.rb cookbooks/valid2/recipes/default.rb})
+ expect(cleaner.cache).not_to receive(:delete)
+ cleaner.cleanup_file_cache
end
+ it "does not remove anything on chef-solo" do
+ Chef::Config[:solo] = true
+ allow(cleaner.cache).to receive(:find).and_return(%w{cookbooks/valid1/recipes/default.rb cookbooks/valid2/recipes/default.rb})
+ expect(cleaner.cache).not_to receive(:delete)
+ cleaner.cleanup_file_cache
+ end
end
end
describe Chef::CookbookSynchronizer do
- before do
+ let(:cookbook_a_default_recipe) do
+ {
+ "path" => "recipes/default.rb",
+ "url" => "http://chef.example.com/abc123",
+ "checksum" => "abc123",
+ }
+ end
+
+ let(:cookbook_a_default_attrs) do
+ {
+ "path" => "attributes/default.rb",
+ "url" => "http://chef.example.com/abc456",
+ "checksum" => "abc456",
+ }
+ end
+
+ let(:cookbook_a_template) do
+ {
+ "path" => "templates/default/apache2.conf.erb",
+ "url" => "http://chef.example.com/ffffff",
+ "checksum" => "abc125",
+ }
+ end
+
+ let(:cookbook_a_file) do
+ {
+ "path" => "files/default/megaman.conf",
+ "url" => "http://chef.example.com/megaman.conf",
+ "checksum" => "abc124",
+ }
+ end
+
+ let(:cookbook_a_manifest) do
segments = [ :resources, :providers, :recipes, :definitions, :libraries, :attributes, :files, :templates, :root_files ]
- @cookbook_manifest = {}
- @cookbook_a = Chef::CookbookVersion.new("cookbook_a")
- @cookbook_a_manifest = segments.inject({}) {|h, segment| h[segment.to_s] = []; h}
- @cookbook_a_default_recipe = { "path" => "recipes/default.rb",
- "url" => "http://chef.example.com/abc123",
- "checksum" => "abc123" }
- @cookbook_a_manifest["recipes"] = [ @cookbook_a_default_recipe ]
-
- @cookbook_a_default_attrs = { "path" => "attributes/default.rb",
- "url" => "http://chef.example.com/abc456",
- "checksum" => "abc456" }
- @cookbook_a_manifest["attributes"] = [ @cookbook_a_default_attrs ]
- @cookbook_a_manifest["templates"] = [{"path" => "templates/default/apache2.conf.erb", "url" => "http://chef.example.com/ffffff"}]
- @cookbook_a_manifest["files"] = [{"path" => "files/default/megaman.conf", "url" => "http://chef.example.com/megaman.conf"}]
- @cookbook_a.manifest = @cookbook_a_manifest
- @cookbook_manifest["cookbook_a"] = @cookbook_a
-
- @events = Chef::EventDispatch::Dispatcher.new
- @synchronizer = Chef::CookbookSynchronizer.new(@cookbook_manifest, @events)
+ cookbook_a_manifest = segments.inject({}) {|h, segment| h[segment.to_s] = []; h}
+ cookbook_a_manifest["recipes"] = [ cookbook_a_default_recipe ]
+ cookbook_a_manifest["attributes"] = [ cookbook_a_default_attrs ]
+ cookbook_a_manifest["templates"] = [ cookbook_a_template ]
+ cookbook_a_manifest["files"] = [ cookbook_a_file ]
+ cookbook_a_manifest
+ end
+
+ let(:cookbook_a) do
+ cookbook_a = Chef::CookbookVersion.new("cookbook_a")
+ cookbook_a.manifest = cookbook_a_manifest
+ cookbook_a
+ end
+
+ let(:cookbook_manifest) do
+ {
+ "cookbook_a" => cookbook_a
+ }
+ end
+
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+
+ let(:no_lazy_load) { true }
+
+ let(:synchronizer) do
+ Chef::Config[:no_lazy_load] = no_lazy_load
+ Chef::CookbookSynchronizer.new(cookbook_manifest, events)
end
it "lists the cookbook names" do
- @synchronizer.cookbook_names.should == %w[cookbook_a]
+ expect(synchronizer.cookbook_names).to eq(%w[cookbook_a])
end
it "lists the cookbook manifests" do
- @synchronizer.cookbooks.should == [@cookbook_a]
+ expect(synchronizer.cookbooks).to eq([cookbook_a])
end
- context "when the cache contains unneeded cookbooks" do
- before do
- @file_cache = double("Chef::FileCache with files from unused cookbooks")
- @valid_cached_cb_files = %w{cookbooks/valid1/recipes/default.rb cookbooks/valid2/recipes/default.rb}
- @obsolete_cb_files = %w{cookbooks/old1/recipes/default.rb cookbooks/old2/recipes/default.rb}
+ context "#clear_obsoleted_cookbooks" do
+ after do
+ # Singletons == Global State == Bad
+ Chef::CookbookCacheCleaner.instance.skip_removal = nil
+ end
- @cookbook_hash = {"valid1"=> {}, "valid2" => {}}
+ it "behaves correctly when remove_obsoleted_files is false" do
+ synchronizer.remove_obsoleted_files = false
+ expect(synchronizer).not_to receive(:remove_old_cookbooks)
+ expect(synchronizer).to receive(:remove_deleted_files)
+ synchronizer.clear_obsoleted_cookbooks
+ expect(Chef::CookbookCacheCleaner.instance.skip_removal).to be true
+ end
+
+ it "behaves correctly when remove_obsoleted_files is true" do
+ synchronizer.remove_obsoleted_files = true
+ expect(synchronizer).to receive(:remove_old_cookbooks)
+ expect(synchronizer).to receive(:remove_deleted_files)
+ synchronizer.clear_obsoleted_cookbooks
+ expect(Chef::CookbookCacheCleaner.instance.skip_removal).to be nil
+ end
+ end
+
+ context "#remove_old_cookbooks" do
+ let(:file_cache) { double("Chef::FileCache with files from unused cookbooks") }
- @synchronizer = Chef::CookbookSynchronizer.new(@cookbook_hash, @events)
+ let(:cookbook_manifest) do
+ {"valid1"=> {}, "valid2" => {}}
end
it "removes unneeded cookbooks" do
- @file_cache.should_receive(:find).with(File.join(%w{cookbooks ** *})).and_return(@valid_cached_cb_files + @obsolete_cb_files)
- @file_cache.should_receive(:delete).with('cookbooks/old1/recipes/default.rb')
- @file_cache.should_receive(:delete).with('cookbooks/old2/recipes/default.rb')
- @synchronizer.stub(:cache).and_return(@file_cache)
- @synchronizer.clear_obsoleted_cookbooks
+ valid_cached_cb_files = %w{cookbooks/valid1/recipes/default.rb cookbooks/valid2/recipes/default.rb}
+ obsolete_cb_files = %w{cookbooks/old1/recipes/default.rb cookbooks/old2/recipes/default.rb}
+ expect(file_cache).to receive(:find).with(File.join(%w{cookbooks ** {*,.*}})).and_return(valid_cached_cb_files + obsolete_cb_files)
+ expect(file_cache).to receive(:delete).with('cookbooks/old1/recipes/default.rb')
+ expect(file_cache).to receive(:delete).with('cookbooks/old2/recipes/default.rb')
+ allow(synchronizer).to receive(:cache).and_return(file_cache)
+ synchronizer.remove_old_cookbooks
end
end
- describe "when syncing cookbooks with the server" do
- before do
- # Would rather not stub out methods on the test subject, but setting up
- # the state is a PITA and tests for this behavior are above.
- @synchronizer.stub(:clear_obsoleted_cookbooks)
+ context "#remove_deleted_files" do
+ let(:file_cache) { double("Chef::FileCache with files from unused cookbooks") }
+
+ let(:cookbook_manifest) do
+ {"valid1"=> {}, "valid2" => {}}
+ end
+
+ it "removes only deleted files" do
+ valid_cached_cb_files = %w{cookbooks/valid1/recipes/default.rb cookbooks/valid2/recipes/default.rb}
+ obsolete_cb_files = %w{cookbooks/valid1/recipes/deleted.rb cookbooks/valid2/recipes/deleted.rb}
+ expect(file_cache).to receive(:find).with(File.join(%w{cookbooks ** {*,.*}})).and_return(valid_cached_cb_files + obsolete_cb_files)
+ # valid1 is a cookbook in our run_list
+ expect(synchronizer).to receive(:have_cookbook?).with("valid1").at_least(:once).and_return(true)
+ # valid2 is a cookbook not in our run_list (we're simulating an override run_list where valid2 needs to be preserved)
+ expect(synchronizer).to receive(:have_cookbook?).with("valid2").at_least(:once).and_return(false)
+ expect(file_cache).to receive(:delete).with('cookbooks/valid1/recipes/deleted.rb')
+ expect(synchronizer).to receive(:cookbook_segment).with("valid1", "recipes").at_least(:once).and_return([ { "path" => "recipes/default.rb" }])
+ allow(synchronizer).to receive(:cache).and_return(file_cache)
+ synchronizer.remove_deleted_files
+ end
+ end
+
+ let(:cookbook_a_default_recipe_tempfile) do
+ double("Tempfile for cookbook_a default.rb recipe",
+ :path => "/tmp/cookbook_a_recipes_default_rb")
+ end
- @server_api = double("Chef::REST (mock)")
- @file_cache = double("Chef::FileCache (mock)")
- @synchronizer.stub(:server_api).and_return(@server_api)
- @synchronizer.stub(:cache).and_return(@file_cache)
+ let(:cookbook_a_default_attribute_tempfile) do
+ double("Tempfile for cookbook_a default.rb attr file",
+ :path => "/tmp/cookbook_a_attributes_default_rb")
+ end
+ let(:cookbook_a_file_default_tempfile) do
+ double("Tempfile for cookbook_a megaman.conf file",
+ :path => "/tmp/cookbook_a_file_default_tempfile")
+ end
- @cookbook_a_default_recipe_tempfile = double("Tempfile for cookbook_a default.rb recipe",
- :path => "/tmp/cookbook_a_recipes_default_rb")
+ let(:cookbook_a_template_default_tempfile) do
+ double("Tempfile for cookbook_a apache.conf.erb template",
+ :path => "/tmp/cookbook_a_template_default_tempfile")
+ end
- @cookbook_a_default_attribute_tempfile = double("Tempfile for cookbook_a default.rb attr file",
- :path => "/tmp/cookbook_a_attributes_default_rb")
+ def setup_common_files_missing_expectations
+ # Files are not in the cache:
+ expect(file_cache).to receive(:has_key?).
+ with("cookbooks/cookbook_a/recipes/default.rb").
+ and_return(false)
+ expect(file_cache).to receive(:has_key?).
+ with("cookbooks/cookbook_a/attributes/default.rb").
+ and_return(false)
+
+ # Fetch and copy default.rb recipe
+ expect(server_api).to receive(:get_rest).
+ with('http://chef.example.com/abc123', true).
+ and_return(cookbook_a_default_recipe_tempfile)
+ expect(file_cache).to receive(:move_to).
+ with("/tmp/cookbook_a_recipes_default_rb", "cookbooks/cookbook_a/recipes/default.rb")
+ expect(file_cache).to receive(:load).
+ with("cookbooks/cookbook_a/recipes/default.rb", false).
+ and_return("/file-cache/cookbooks/cookbook_a/recipes/default.rb")
+
+ # Fetch and copy default.rb attribute file
+ expect(server_api).to receive(:get_rest).
+ with('http://chef.example.com/abc456', true).
+ and_return(cookbook_a_default_attribute_tempfile)
+ expect(file_cache).to receive(:move_to).
+ with("/tmp/cookbook_a_attributes_default_rb", "cookbooks/cookbook_a/attributes/default.rb")
+ expect(file_cache).to receive(:load).
+ with("cookbooks/cookbook_a/attributes/default.rb", false).
+ and_return("/file-cache/cookbooks/cookbook_a/attributes/default.rb")
+ end
+ def setup_no_lazy_files_and_templates_missing_expectations
+ expect(file_cache).to receive(:has_key?).
+ with("cookbooks/cookbook_a/files/default/megaman.conf").
+ and_return(false)
+ expect(file_cache).to receive(:has_key?).
+ with("cookbooks/cookbook_a/templates/default/apache2.conf.erb").
+ and_return(false)
+
+ expect(server_api).to receive(:get_rest).
+ with('http://chef.example.com/megaman.conf', true).
+ and_return(cookbook_a_file_default_tempfile)
+ expect(file_cache).to receive(:move_to).
+ with("/tmp/cookbook_a_file_default_tempfile", "cookbooks/cookbook_a/files/default/megaman.conf")
+ expect(file_cache).to receive(:load).
+ with("cookbooks/cookbook_a/files/default/megaman.conf", false).
+ and_return("/file-cache/cookbooks/cookbook_a/default/megaman.conf")
+
+ expect(server_api).to receive(:get_rest).
+ with('http://chef.example.com/ffffff', true).
+ and_return(cookbook_a_template_default_tempfile)
+ expect(file_cache).to receive(:move_to).
+ with("/tmp/cookbook_a_template_default_tempfile", "cookbooks/cookbook_a/templates/default/apache2.conf.erb")
+ expect(file_cache).to receive(:load).
+ with("cookbooks/cookbook_a/templates/default/apache2.conf.erb", false).
+ and_return("/file-cache/cookbooks/cookbook_a/templates/default/apache2.conf.erb")
+ end
+
+ def setup_common_files_chksum_mismatch_expectations
+ # Files are in the cache:
+ expect(file_cache).to receive(:has_key?).
+ with("cookbooks/cookbook_a/recipes/default.rb").
+ and_return(true)
+ expect(file_cache).to receive(:has_key?).
+ with("cookbooks/cookbook_a/attributes/default.rb").
+ and_return(true)
+
+ # Fetch and copy default.rb recipe
+ expect(server_api).to receive(:get_rest).
+ with('http://chef.example.com/abc123', true).
+ and_return(cookbook_a_default_recipe_tempfile)
+ expect(file_cache).to receive(:move_to).
+ with("/tmp/cookbook_a_recipes_default_rb", "cookbooks/cookbook_a/recipes/default.rb")
+ expect(file_cache).to receive(:load).
+ with("cookbooks/cookbook_a/recipes/default.rb", false).
+ twice.
+ and_return("/file-cache/cookbooks/cookbook_a/recipes/default.rb")
+
+ # Current file has fff000, want abc123
+ expect(Chef::CookbookVersion).to receive(:checksum_cookbook_file).
+ with("/file-cache/cookbooks/cookbook_a/recipes/default.rb").
+ and_return("fff000")
+
+ # Fetch and copy default.rb attribute file
+ expect(server_api).to receive(:get_rest).
+ with('http://chef.example.com/abc456', true).
+ and_return(cookbook_a_default_attribute_tempfile)
+ expect(file_cache).to receive(:move_to).
+ with("/tmp/cookbook_a_attributes_default_rb", "cookbooks/cookbook_a/attributes/default.rb")
+ expect(file_cache).to receive(:load).
+ with("cookbooks/cookbook_a/attributes/default.rb", false).
+ twice.
+ and_return("/file-cache/cookbooks/cookbook_a/attributes/default.rb")
+
+ # Current file has fff000, want abc456
+ expect(Chef::CookbookVersion).to receive(:checksum_cookbook_file).
+ with("/file-cache/cookbooks/cookbook_a/attributes/default.rb").
+ and_return("fff000")
+ end
+
+ def setup_no_lazy_files_and_templates_chksum_mismatch_expectations
+ # Files are in the cache:
+ expect(file_cache).to receive(:has_key?).
+ with("cookbooks/cookbook_a/files/default/megaman.conf").
+ and_return(true)
+ expect(file_cache).to receive(:has_key?).
+ with("cookbooks/cookbook_a/templates/default/apache2.conf.erb").
+ and_return(true)
+
+ # Fetch and copy megaman.conf
+ expect(server_api).to receive(:get_rest).
+ with('http://chef.example.com/megaman.conf', true).
+ and_return(cookbook_a_file_default_tempfile)
+ expect(file_cache).to receive(:move_to).
+ with("/tmp/cookbook_a_file_default_tempfile", "cookbooks/cookbook_a/files/default/megaman.conf")
+ expect(file_cache).to receive(:load).
+ with("cookbooks/cookbook_a/files/default/megaman.conf", false).
+ twice.
+ and_return("/file-cache/cookbooks/cookbook_a/default/megaman.conf")
+
+ # Fetch and copy apache2.conf template
+ expect(server_api).to receive(:get_rest).
+ with('http://chef.example.com/ffffff', true).
+ and_return(cookbook_a_template_default_tempfile)
+ expect(file_cache).to receive(:move_to).
+ with("/tmp/cookbook_a_template_default_tempfile", "cookbooks/cookbook_a/templates/default/apache2.conf.erb")
+ expect(file_cache).to receive(:load).
+ with("cookbooks/cookbook_a/templates/default/apache2.conf.erb", false).
+ twice.
+ and_return("/file-cache/cookbooks/cookbook_a/templates/default/apache2.conf.erb")
+
+ # Current file has fff000
+ expect(Chef::CookbookVersion).to receive(:checksum_cookbook_file).
+ with("/file-cache/cookbooks/cookbook_a/default/megaman.conf").
+ and_return("fff000")
+
+ # Current file has fff000
+ expect(Chef::CookbookVersion).to receive(:checksum_cookbook_file).
+ with("/file-cache/cookbooks/cookbook_a/templates/default/apache2.conf.erb").
+ and_return("fff000")
+ end
+
+ def setup_common_files_present_expectations
+ # Files are in the cache:
+ expect(file_cache).to receive(:has_key?).
+ with("cookbooks/cookbook_a/recipes/default.rb").
+ and_return(true)
+ expect(file_cache).to receive(:has_key?).
+ with("cookbooks/cookbook_a/attributes/default.rb").
+ and_return(true)
+
+ # Current file has abc123, want abc123
+ expect(Chef::CookbookVersion).to receive(:checksum_cookbook_file).
+ with("/file-cache/cookbooks/cookbook_a/recipes/default.rb").
+ and_return("abc123")
+
+ # Current file has abc456, want abc456
+ expect(Chef::CookbookVersion).to receive(:checksum_cookbook_file).
+ with("/file-cache/cookbooks/cookbook_a/attributes/default.rb").
+ and_return("abc456")
+
+ # :load called twice
+ expect(file_cache).to receive(:load).
+ with("cookbooks/cookbook_a/recipes/default.rb", false).
+ twice.
+ and_return("/file-cache/cookbooks/cookbook_a/recipes/default.rb")
+ expect(file_cache).to receive(:load).
+ with("cookbooks/cookbook_a/attributes/default.rb", false).
+ twice.
+ and_return("/file-cache/cookbooks/cookbook_a/attributes/default.rb")
+ end
+
+ def setup_no_lazy_files_and_templates_present_expectations
+ # Files are in the cache:
+ expect(file_cache).to receive(:has_key?).
+ with("cookbooks/cookbook_a/files/default/megaman.conf").
+ and_return(true)
+ expect(file_cache).to receive(:has_key?).
+ with("cookbooks/cookbook_a/templates/default/apache2.conf.erb").
+ and_return(true)
+
+ # Current file has abc124, want abc124
+ expect(Chef::CookbookVersion).to receive(:checksum_cookbook_file).
+ with("/file-cache/cookbooks/cookbook_a/default/megaman.conf").
+ and_return("abc124")
+
+ # Current file has abc125, want abc125
+ expect(Chef::CookbookVersion).to receive(:checksum_cookbook_file).
+ with("/file-cache/cookbooks/cookbook_a/templates/default/apache2.conf.erb").
+ and_return("abc125")
+
+ # :load called twice
+ expect(file_cache).to receive(:load).
+ with("cookbooks/cookbook_a/files/default/megaman.conf", false).
+ twice.
+ and_return("/file-cache/cookbooks/cookbook_a/default/megaman.conf")
+ expect(file_cache).to receive(:load).
+ with("cookbooks/cookbook_a/templates/default/apache2.conf.erb", false).
+ twice.
+ and_return("/file-cache/cookbooks/cookbook_a/templates/default/apache2.conf.erb")
+ end
+
+ describe "when syncing cookbooks with the server" do
+ let(:server_api) { double("Chef::REST (mock)") }
+
+ let(:file_cache) { double("Chef::FileCache (mock)") }
+
+ before do
+ # Would rather not stub out methods on the test subject, but setting up
+ # the state is a PITA and tests for this behavior are above.
+ allow(synchronizer).to receive(:clear_obsoleted_cookbooks)
+ allow(synchronizer).to receive(:server_api).and_return(server_api)
+ allow(synchronizer).to receive(:cache).and_return(file_cache)
end
context "when the cache does not contain the desired files" do
before do
-
- # Files are not in the cache:
- @file_cache.should_receive(:has_key?).
- with("cookbooks/cookbook_a/recipes/default.rb").
- and_return(false)
- @file_cache.should_receive(:has_key?).
- with("cookbooks/cookbook_a/attributes/default.rb").
- and_return(false)
-
- # Fetch and copy default.rb recipe
- @server_api.should_receive(:get_rest).
- with('http://chef.example.com/abc123', true).
- and_return(@cookbook_a_default_recipe_tempfile)
- @file_cache.should_receive(:move_to).
- with("/tmp/cookbook_a_recipes_default_rb", "cookbooks/cookbook_a/recipes/default.rb")
- @file_cache.should_receive(:load).
- with("cookbooks/cookbook_a/recipes/default.rb", false).
- and_return("/file-cache/cookbooks/cookbook_a/recipes/default.rb")
-
- # Fetch and copy default.rb attribute file
- @server_api.should_receive(:get_rest).
- with('http://chef.example.com/abc456', true).
- and_return(@cookbook_a_default_attribute_tempfile)
- @file_cache.should_receive(:move_to).
- with("/tmp/cookbook_a_attributes_default_rb", "cookbooks/cookbook_a/attributes/default.rb")
- @file_cache.should_receive(:load).
- with("cookbooks/cookbook_a/attributes/default.rb", false).
- and_return("/file-cache/cookbooks/cookbook_a/attributes/default.rb")
+ setup_common_files_missing_expectations
end
- it "fetches eagerly loaded files" do
- @synchronizer.sync_cookbooks
- end
+ context "Chef::Config[:no_lazy_load] is false" do
+ let(:no_lazy_load) { false }
- it "does not fetch templates or cookbook files" do
- # Implicitly tested in previous test; this test is just for behavior specification.
- @server_api.should_not_receive(:get_rest).
- with('http://chef.example.com/ffffff', true)
+ it "fetches eagerly loaded files" do
+ synchronizer.sync_cookbooks
+ end
+
+ it "does not fetch templates or cookbook files" do
+ # Implicitly tested in previous test; this test is just for behavior specification.
+ expect(server_api).not_to receive(:get_rest).
+ with('http://chef.example.com/ffffff', true)
- @synchronizer.sync_cookbooks
+ synchronizer.sync_cookbooks
+ end
end
context "Chef::Config[:no_lazy_load] is true" do
- before do
- Chef::Config[:no_lazy_load] = true
- @synchronizer = Chef::CookbookSynchronizer.new(@cookbook_manifest, @events)
- @synchronizer.stub(:server_api).and_return(@server_api)
- @synchronizer.stub(:cache).and_return(@file_cache)
- @synchronizer.stub(:clear_obsoleted_cookbooks)
-
- @cookbook_a_file_default_tempfile = double("Tempfile for cookbook_a megaman.conf file",
- :path => "/tmp/cookbook_a_file_default_tempfile")
- @cookbook_a_template_default_tempfile = double("Tempfile for cookbook_a apache.conf.erb template",
- :path => "/tmp/cookbook_a_template_default_tempfile")
- end
+ let(:no_lazy_load) { true }
- after do
- Chef::Config[:no_lazy_load] = false
+ before do
+ setup_no_lazy_files_and_templates_missing_expectations
end
it "fetches templates and cookbook files" do
- @file_cache.should_receive(:has_key?).
- with("cookbooks/cookbook_a/files/default/megaman.conf").
- and_return(false)
- @file_cache.should_receive(:has_key?).
- with("cookbooks/cookbook_a/templates/default/apache2.conf.erb").
- and_return(false)
-
- @server_api.should_receive(:get_rest).
- with('http://chef.example.com/megaman.conf', true).
- and_return(@cookbook_a_file_default_tempfile)
- @file_cache.should_receive(:move_to).
- with("/tmp/cookbook_a_file_default_tempfile", "cookbooks/cookbook_a/files/default/megaman.conf")
- @file_cache.should_receive(:load).
- with("cookbooks/cookbook_a/files/default/megaman.conf", false).
- and_return("/file-cache/cookbooks/cookbook_a/default/megaman.conf")
-
- @server_api.should_receive(:get_rest).
- with('http://chef.example.com/ffffff', true).
- and_return(@cookbook_a_template_default_tempfile)
- @file_cache.should_receive(:move_to).
- with("/tmp/cookbook_a_template_default_tempfile", "cookbooks/cookbook_a/templates/default/apache2.conf.erb")
- @file_cache.should_receive(:load).
- with("cookbooks/cookbook_a/templates/default/apache2.conf.erb", false).
- and_return("/file-cache/cookbooks/cookbook_a/templates/default/apache2.conf.erb")
-
- @synchronizer.sync_cookbooks
+ synchronizer.sync_cookbooks
end
end
end
context "when the cache contains outdated files" do
before do
- # Files are in the cache:
- @file_cache.should_receive(:has_key?).
- with("cookbooks/cookbook_a/recipes/default.rb").
- and_return(true)
- @file_cache.should_receive(:has_key?).
- with("cookbooks/cookbook_a/attributes/default.rb").
- and_return(true)
-
-
- # Fetch and copy default.rb recipe
- @server_api.should_receive(:get_rest).
- with('http://chef.example.com/abc123', true).
- and_return(@cookbook_a_default_recipe_tempfile)
- @file_cache.should_receive(:move_to).
- with("/tmp/cookbook_a_recipes_default_rb", "cookbooks/cookbook_a/recipes/default.rb")
- @file_cache.should_receive(:load).
- with("cookbooks/cookbook_a/recipes/default.rb", false).
- twice.
- and_return("/file-cache/cookbooks/cookbook_a/recipes/default.rb")
-
- # Current file has fff000, want abc123
- Chef::CookbookVersion.should_receive(:checksum_cookbook_file).
- with("/file-cache/cookbooks/cookbook_a/recipes/default.rb").
- and_return("fff000")
-
- # Fetch and copy default.rb attribute file
- @server_api.should_receive(:get_rest).
- with('http://chef.example.com/abc456', true).
- and_return(@cookbook_a_default_attribute_tempfile)
- @file_cache.should_receive(:move_to).
- with("/tmp/cookbook_a_attributes_default_rb", "cookbooks/cookbook_a/attributes/default.rb")
- @file_cache.should_receive(:load).
- with("cookbooks/cookbook_a/attributes/default.rb", false).
- twice.
- and_return("/file-cache/cookbooks/cookbook_a/attributes/default.rb")
-
- # Current file has fff000, want abc456
- Chef::CookbookVersion.should_receive(:checksum_cookbook_file).
- with("/file-cache/cookbooks/cookbook_a/attributes/default.rb").
- and_return("fff000")
+ setup_common_files_chksum_mismatch_expectations
end
- it "updates the outdated files" do
- @synchronizer.sync_cookbooks
+ context "Chef::Config[:no_lazy_load] is true" do
+ let(:no_lazy_load) { true }
+
+ before do
+ setup_no_lazy_files_and_templates_chksum_mismatch_expectations
+ end
+
+ it "updates the outdated files" do
+ synchronizer.sync_cookbooks
+ end
+ end
+
+ context "Chef::Config[:no_lazy_load] is false" do
+ let(:no_lazy_load) { false }
+
+ it "updates the outdated files" do
+ synchronizer.sync_cookbooks
+ end
end
end
context "when the cache is up to date" do
before do
- # Files are in the cache:
- @file_cache.should_receive(:has_key?).
- with("cookbooks/cookbook_a/recipes/default.rb").
- and_return(true)
- @file_cache.should_receive(:has_key?).
- with("cookbooks/cookbook_a/attributes/default.rb").
- and_return(true)
-
- # Current file has abc123, want abc123
- Chef::CookbookVersion.should_receive(:checksum_cookbook_file).
- with("/file-cache/cookbooks/cookbook_a/recipes/default.rb").
- and_return("abc123")
-
- # Current file has abc456, want abc456
- Chef::CookbookVersion.should_receive(:checksum_cookbook_file).
- with("/file-cache/cookbooks/cookbook_a/attributes/default.rb").
- and_return("abc456")
-
- @file_cache.should_receive(:load).
- with("cookbooks/cookbook_a/recipes/default.rb", false).
- twice.
- and_return("/file-cache/cookbooks/cookbook_a/recipes/default.rb")
-
- @file_cache.should_receive(:load).
- with("cookbooks/cookbook_a/attributes/default.rb", false).
- twice.
- and_return("/file-cache/cookbooks/cookbook_a/attributes/default.rb")
+ setup_common_files_present_expectations
end
- it "does not update files" do
- @file_cache.should_not_receive(:move_to)
- @server_api.should_not_receive(:get_rest)
- @synchronizer.sync_cookbooks
+ context "Chef::Config[:no_lazy_load] is true" do
+ let(:no_lazy_load) { true }
+
+ before do
+ setup_no_lazy_files_and_templates_present_expectations
+ end
+
+ it "does not update files" do
+ expect(file_cache).not_to receive(:move_to)
+ expect(server_api).not_to receive(:get_rest)
+ synchronizer.sync_cookbooks
+ end
end
- end
+ context "Chef::Config[:no_lazy_load] is false" do
+ let(:no_lazy_load) { false }
+ it "does not update files" do
+ expect(file_cache).not_to receive(:move_to)
+ expect(server_api).not_to receive(:get_rest)
+ synchronizer.sync_cookbooks
+ end
+ end
+ end
end
-
end
-
diff --git a/spec/unit/cookbook_uploader_spec.rb b/spec/unit/cookbook_uploader_spec.rb
new file mode 100644
index 0000000000..af25baff13
--- /dev/null
+++ b/spec/unit/cookbook_uploader_spec.rb
@@ -0,0 +1,160 @@
+#
+# Author:: Daniel DeLeo (<dan@getchef.com>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+describe Chef::CookbookUploader do
+
+ let(:http_client) { double("Chef::REST") }
+
+ let(:cookbook_loader) do
+ loader = Chef::CookbookLoader.new(File.join(CHEF_SPEC_DATA, "cookbooks"))
+ loader.load_cookbooks
+ loader
+ end
+
+ let(:apache2_cookbook) { cookbook_loader.cookbooks_by_name["apache2"] }
+
+ let(:java_cookbook) { cookbook_loader.cookbooks_by_name["java"] }
+
+ let(:cookbooks_to_upload) { [apache2_cookbook, java_cookbook] }
+
+ let(:checksums_of_cookbook_files) { apache2_cookbook.checksums.merge(java_cookbook.checksums) }
+
+ let(:checksums_set) do
+ checksums_of_cookbook_files.keys.inject({}) do |set, cksum|
+ set[cksum] = nil
+ set
+ end
+ end
+
+ let(:sandbox_commit_uri) { "https://chef.example.org/sandboxes/abc123" }
+
+ let(:uploader) { described_class.new(cookbooks_to_upload, :rest => http_client) }
+
+ it "has a list of cookbooks to upload" do
+ expect(uploader.cookbooks).to eq(cookbooks_to_upload)
+ end
+
+ it "creates an HTTP client with default configuration when not initialized with one" do
+ default_http_client = double("Chef::REST")
+ expect(Chef::REST).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(default_http_client)
+ uploader = described_class.new(cookbooks_to_upload)
+ expect(uploader.rest).to eq(default_http_client)
+ end
+
+ describe "uploading cookbooks" do
+
+ def url_for(cksum)
+ "https://storage.example.com/#{cksum}"
+ end
+
+ let(:sandbox_response) do
+ sandbox_checksums = cksums_not_on_remote.inject({}) do |cksum_map, cksum|
+ cksum_map[cksum] = { "needs_upload" => true, "url" => url_for(cksum)}
+ cksum_map
+ end
+ { "checksums" => sandbox_checksums, "uri" => sandbox_commit_uri }
+ end
+
+ def expect_sandbox_create
+ expect(http_client).to receive(:post).
+ with("sandboxes", {:checksums => checksums_set}).
+ and_return(sandbox_response)
+ end
+
+ def expect_checksum_upload
+ checksums_of_cookbook_files.each do |md5, file_path|
+ next unless cksums_not_on_remote.include?(md5)
+
+ upload_headers = {
+ "content-type" => "application/x-binary",
+ "content-md5" => an_instance_of(String),
+ "accept" => "application/json"
+ }
+
+ expect(http_client).to receive(:put).
+ with(url_for(md5), IO.binread(file_path), upload_headers)
+
+ end
+ end
+
+ def expect_sandbox_commit
+ expect(http_client).to receive(:put).with(sandbox_commit_uri, {:is_completed => true})
+ end
+
+ def expect_cookbook_create
+ cookbooks_to_upload.each do |cookbook|
+
+ expect(http_client).to receive(:put).
+ with(cookbook.save_url, cookbook)
+
+ end
+ end
+
+ context "when no files exist on the server" do
+
+ let(:cksums_not_on_remote) do
+ checksums_of_cookbook_files.keys
+ end
+
+ it "uploads all files in a sandbox transaction, then creates cookbooks on the server" do
+ expect_sandbox_create
+ expect_checksum_upload
+ expect_sandbox_commit
+ expect_cookbook_create
+
+ uploader.upload_cookbooks
+ end
+
+ end
+
+ context "when some files exist on the server" do
+
+ let(:cksums_not_on_remote) do
+ checksums_of_cookbook_files.keys[0, 1]
+ end
+
+ it "uploads all files in a sandbox transaction, then creates cookbooks on the server" do
+ expect_sandbox_create
+ expect_checksum_upload
+ expect_sandbox_commit
+ expect_cookbook_create
+
+ uploader.upload_cookbooks
+ end
+
+ end
+
+ context "when all files already exist on the server" do
+
+ let(:cksums_not_on_remote) { [] }
+
+ it "uploads all files in a sandbox transaction, then creates cookbooks on the server" do
+ expect_sandbox_create
+ expect_checksum_upload
+ expect_sandbox_commit
+ expect_cookbook_create
+
+ uploader.upload_cookbooks
+ end
+
+ end
+ end
+
+end
diff --git a/spec/unit/dsl/recipe_spec.rb b/spec/unit/dsl/recipe_spec.rb
index 14ee30be44..dfaad0b73e 100644
--- a/spec/unit/dsl/recipe_spec.rb
+++ b/spec/unit/dsl/recipe_spec.rb
@@ -46,6 +46,18 @@ describe Chef::DSL::Recipe do
it "responds to recipe_name" do
expect(recipe.recipe_name).to eq(recipe_name)
end
+
+ it "responds to shell_out" do
+ expect(recipe.respond_to?(:shell_out)).to be true
+ end
+
+ it "responds to shell_out" do
+ expect(recipe.respond_to?(:shell_out!)).to be true
+ end
+
+ it "responds to shell_out" do
+ expect(recipe.respond_to?(:shell_out_with_systems_locale)).to be true
+ end
end
context "when included in a class that defines the required interface directly" do
diff --git a/spec/unit/formatters/base_spec.rb b/spec/unit/formatters/base_spec.rb
new file mode 100644
index 0000000000..6a843ea775
--- /dev/null
+++ b/spec/unit/formatters/base_spec.rb
@@ -0,0 +1,48 @@
+#
+# Author:: Lamont Granquist (<lamont@getchef.com>)
+#
+# Copyright:: Copyright (c) 2012 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+describe Chef::Formatters::Base do
+ let(:out) { double("out") }
+ let(:err) { double("err") }
+ let(:formatter) { Chef::Formatters::Base.new(out, err) }
+
+ it "starts with an indentation of zero" do
+ expect(formatter.output.indent).to eql(0)
+ end
+
+ it "increments it to two correctly" do
+ formatter.indent_by(2)
+ expect(formatter.output.indent).to eql(2)
+ end
+
+ it "increments it and then decrements it corectly" do
+ formatter.indent_by(2)
+ formatter.indent_by(-2)
+ expect(formatter.output.indent).to eql(0)
+ end
+
+ it "does not allow negative indentation" do
+ formatter.indent_by(-2)
+ expect(formatter.output.indent).to eql(0)
+ end
+end
+
+
diff --git a/spec/unit/http/json_input_spec.rb b/spec/unit/http/json_input_spec.rb
new file mode 100644
index 0000000000..fbf8f22503
--- /dev/null
+++ b/spec/unit/http/json_input_spec.rb
@@ -0,0 +1,128 @@
+#--
+# Author:: Daniel DeLeo (<dan@getchef.com>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+require 'chef/http/json_input'
+
+describe Chef::HTTP::JSONInput do
+
+ let(:json_encoder) { described_class.new() }
+
+ let(:url) { URI.parse("http://example.com") }
+ let(:headers) { {} }
+
+ def handle_request
+ json_encoder.handle_request(http_method, url, headers, data)
+ end
+
+ it "passes the response unmodified" do
+ http_response = double("Net::HTTPSuccess")
+ request = double("Chef::HTTP::HTTPRequest")
+ return_value = "response body"
+
+ result = json_encoder.handle_response(http_response, request, return_value)
+ expect(result).to eq([http_response, request, return_value])
+ end
+
+ it "doesn't handle streaming responses" do
+ http_response = double("Net::HTTPSuccess")
+ expect(json_encoder.stream_response_handler(http_response)).to be nil
+ end
+
+ it "does nothing for stream completion" do
+ http_response = double("Net::HTTPSuccess")
+ request = double("Chef::HTTP::HTTPRequest")
+ return_value = "response body"
+
+ result = json_encoder.handle_response(http_response, request, return_value)
+ expect(result).to eq([http_response, request, return_value])
+ end
+
+ context "when handling a request with no body" do
+
+ let(:http_method) { :get }
+ let(:data) { nil }
+
+ it "passes the request unmodified" do
+ expect(handle_request).to eq([http_method, url, headers, data])
+ end
+ end
+
+ context "when the request should be serialized" do
+
+ let(:http_method) { :put }
+ let(:data) { {foo: "bar"} }
+ let(:expected_data) { %q[{"foo":"bar"}] }
+
+ context "and the request has a ruby object as the body and no explicit content-type" do
+
+ it "serializes the body to json" do
+ # Headers Hash get mutated, so we start by asserting it's empty:
+ expect(headers).to be_empty
+
+ expect(handle_request).to eq([http_method, url, headers, expected_data])
+
+ # Now the headers Hash should have json content type:
+ expect(headers).to have_key("Content-Type")
+ expect(headers["Content-Type"]).to eq("application/json")
+ end
+ end
+
+ context "ant the request has an explicit content type of json" do
+
+ it "serializes the body to json when content-type is all lowercase" do
+ headers["content-type"] = "application/json"
+
+ expect(handle_request).to eq([http_method, url, headers, expected_data])
+
+ # Content-Type header should be normalized:
+ expect(headers.size).to eq(1)
+ expect(headers).to have_key("Content-Type")
+ expect(headers["Content-Type"]).to eq("application/json")
+ end
+
+ end
+
+ end
+
+ context "when handling a request with an explicit content type other than json" do
+
+ let(:http_method) { :put }
+ let(:data) { "some arbitrary bytes" }
+
+ it "does not serialize the body to json when content type is given as lowercase" do
+ headers["content-type"] = "application/x-binary"
+
+ expect(handle_request).to eq([http_method, url, headers, data])
+
+ # not normalized
+ expect(headers).to eq({"content-type" => "application/x-binary"})
+ end
+
+ it "does not serialize the body to json when content type is given in capitalized form" do
+ headers["Content-Type"] = "application/x-binary"
+
+ expect(handle_request).to eq([http_method, url, headers, data])
+
+ # not normalized
+ expect(headers).to eq({"Content-Type" => "application/x-binary"})
+ end
+
+ end
+
+end
diff --git a/spec/unit/knife/client_create_spec.rb b/spec/unit/knife/client_create_spec.rb
index 897cee8974..59238d69ec 100644
--- a/spec/unit/knife/client_create_spec.rb
+++ b/spec/unit/knife/client_create_spec.rb
@@ -35,15 +35,15 @@ describe Chef::Knife::ClientCreate do
@knife.stub(:edit_data).and_return(@client)
@knife.stub(:puts)
Chef::ApiClient.stub(:new).and_return(@client)
- @stdout = StringIO.new
- @knife.ui.stub(:stdout).and_return(@stdout)
+ @stderr = StringIO.new
+ @knife.ui.stub(:stderr).and_return(@stderr)
end
describe "run" do
it "should create a new Client" do
Chef::ApiClient.should_receive(:new).and_return(@client)
@knife.run
- @stdout.string.should match /created client.+adam/i
+ @stderr.string.should match /created client.+adam/i
end
it "should set the Client name" do
diff --git a/spec/unit/knife/configure_client_spec.rb b/spec/unit/knife/configure_client_spec.rb
index d101780317..de2a5a41e5 100644
--- a/spec/unit/knife/configure_client_spec.rb
+++ b/spec/unit/knife/configure_client_spec.rb
@@ -25,8 +25,8 @@ describe Chef::Knife::ConfigureClient do
Chef::Config[:validation_client_name] = 'chef-validator'
Chef::Config[:validation_key] = '/etc/chef/validation.pem'
- @stdout = StringIO.new
- @knife.ui.stub(:stdout).and_return(@stdout)
+ @stderr = StringIO.new
+ @knife.ui.stub(:stderr).and_return(@stderr)
end
describe 'run' do
@@ -73,11 +73,12 @@ describe Chef::Knife::ConfigureClient do
it 'should print information on what is being configured' do
FileUtils.stub(:mkdir_p)
@knife.run
- @stdout.string.should match /creating client configuration/i
- @stdout.string.should match /writing client\.rb/i
- @stdout.string.should match /writing validation\.pem/i
+ @stderr.string.should match /creating client configuration/i
+ @stderr.string.should match /writing client\.rb/i
+ @stderr.string.should match /writing validation\.pem/i
end
end
end
end
+
diff --git a/spec/unit/knife/cookbook_delete_spec.rb b/spec/unit/knife/cookbook_delete_spec.rb
index f4ba46f513..53b120be71 100644
--- a/spec/unit/knife/cookbook_delete_spec.rb
+++ b/spec/unit/knife/cookbook_delete_spec.rb
@@ -204,7 +204,7 @@ describe Chef::Knife::CookbookDelete do
it 'should output that the cookbook was deleted' do
@knife.stub(:delete_request)
@knife.delete_version_without_confirmation('1.0.0')
- @stdout.string.should match /deleted cookbook\[foobar\]\[1.0.0\]/im
+ @stderr.string.should match /deleted cookbook\[foobar\]\[1.0.0\]/im
end
describe 'with --print-after' do
diff --git a/spec/unit/knife/cookbook_download_spec.rb b/spec/unit/knife/cookbook_download_spec.rb
index efab98f646..6f40a3396b 100644
--- a/spec/unit/knife/cookbook_download_spec.rb
+++ b/spec/unit/knife/cookbook_download_spec.rb
@@ -21,8 +21,8 @@ require 'spec_helper'
describe Chef::Knife::CookbookDownload do
before(:each) do
@knife = Chef::Knife::CookbookDownload.new
- @stdout = StringIO.new
- @knife.ui.stub(:stdout).and_return(@stdout)
+ @stderr = StringIO.new
+ @knife.ui.stub(:stderr).and_return(@stderr)
end
describe 'run' do
@@ -121,10 +121,10 @@ describe Chef::Knife::CookbookDownload do
File.should_receive(:exists?).with('/var/tmp/chef/foobar-1.0.0').and_return(false)
@knife.run
['attributes', 'recipes', 'templates'].each do |segment|
- @stdout.string.should match /downloading #{segment}/im
+ @stderr.string.should match /downloading #{segment}/im
end
- @stdout.string.should match /downloading foobar cookbook version 1\.0\.0/im
- @stdout.string.should match /cookbook downloaded to \/var\/tmp\/chef\/foobar-1\.0\.0/im
+ @stderr.string.should match /downloading foobar cookbook version 1\.0\.0/im
+ @stderr.string.should match /cookbook downloaded to \/var\/tmp\/chef\/foobar-1\.0\.0/im
end
describe 'with -f or --force' do
diff --git a/spec/unit/knife/cookbook_metadata_spec.rb b/spec/unit/knife/cookbook_metadata_spec.rb
index 26ff43829c..1d6568739c 100644
--- a/spec/unit/knife/cookbook_metadata_spec.rb
+++ b/spec/unit/knife/cookbook_metadata_spec.rb
@@ -119,7 +119,7 @@ describe Chef::Knife::CookbookMetadata do
Chef::JSONCompat.should_receive(:to_json_pretty).with(@metadata_mock).
and_return(@json_data)
@knife.generate_metadata_from_file('foobar', "#{@cookbook_dir}/foobar/metadata.rb")
- @stdout.string.should match /generating metadata for foobar from #{@cookbook_dir}\/foobar\/metadata\.rb/im
+ @stderr.string.should match /generating metadata for foobar from #{@cookbook_dir}\/foobar\/metadata\.rb/im
end
{ Chef::Exceptions::ObsoleteDependencySyntax => 'obsolote dependency',
diff --git a/spec/unit/knife/cookbook_site_download_spec.rb b/spec/unit/knife/cookbook_site_download_spec.rb
index faf58f7bc7..7cd71c2211 100644
--- a/spec/unit/knife/cookbook_site_download_spec.rb
+++ b/spec/unit/knife/cookbook_site_download_spec.rb
@@ -25,7 +25,7 @@ describe Chef::Knife::CookbookSiteDownload do
@knife = Chef::Knife::CookbookSiteDownload.new
@knife.name_args = ['apache2']
@noauth_rest = double('no auth rest')
- @stdout = StringIO.new
+ @stderr = StringIO.new
@cookbook_api_url = 'http://cookbooks.opscode.com/api/v1/cookbooks'
@version = '1.0.2'
@version_us = @version.gsub '.', '_'
@@ -33,7 +33,7 @@ describe Chef::Knife::CookbookSiteDownload do
'latest_version' => "#{@cookbook_api_url}/apache2/versions/#{@version_us}",
'replacement' => 'other_apache2' }
- @knife.ui.stub(:stdout).and_return(@stdout)
+ @knife.ui.stub(:stderr).and_return(@stderr)
@knife.stub(:noauth_rest).and_return(@noauth_rest)
@noauth_rest.should_receive(:get_rest).
with("#{@cookbook_api_url}/apache2").
@@ -85,8 +85,8 @@ describe Chef::Knife::CookbookSiteDownload do
with(/.+deprecated.+replaced by other_apache2.+/i)
FileUtils.should_receive(:cp).with(@temp_file.path, @file)
@knife.run
- @stdout.string.should match /downloading apache2.+version.+#{Regexp.escape(@version)}/i
- @stdout.string.should match /cookbook save.+#{Regexp.escape(@file)}/i
+ @stderr.string.should match /downloading apache2.+version.+#{Regexp.escape(@version)}/i
+ @stderr.string.should match /cookbook save.+#{Regexp.escape(@file)}/i
end
end
@@ -94,8 +94,8 @@ describe Chef::Knife::CookbookSiteDownload do
it 'should download the latest version' do
FileUtils.should_receive(:cp).with(@temp_file.path, @file)
@knife.run
- @stdout.string.should match /downloading apache2.+version.+#{Regexp.escape(@version)}/i
- @stdout.string.should match /cookbook save.+#{Regexp.escape(@file)}/i
+ @stderr.string.should match /downloading apache2.+version.+#{Regexp.escape(@version)}/i
+ @stderr.string.should match /cookbook save.+#{Regexp.escape(@file)}/i
end
context 'with -f or --file' do
@@ -107,8 +107,8 @@ describe Chef::Knife::CookbookSiteDownload do
it 'should download the cookbook to the desired file' do
@knife.run
- @stdout.string.should match /downloading apache2.+version.+#{Regexp.escape(@version)}/i
- @stdout.string.should match /cookbook save.+#{Regexp.escape(@file)}/i
+ @stderr.string.should match /downloading apache2.+version.+#{Regexp.escape(@version)}/i
+ @stderr.string.should match /cookbook save.+#{Regexp.escape(@file)}/i
end
end
@@ -139,8 +139,8 @@ describe Chef::Knife::CookbookSiteDownload do
and_return(@temp_file)
FileUtils.should_receive(:cp).with(@temp_file.path, @file)
@knife.run
- @stdout.string.should match /downloading apache2.+version.+#{Regexp.escape(@version)}/i
- @stdout.string.should match /cookbook save.+#{Regexp.escape(@file)}/i
+ @stderr.string.should match /downloading apache2.+version.+#{Regexp.escape(@version)}/i
+ @stderr.string.should match /cookbook save.+#{Regexp.escape(@file)}/i
end
end
diff --git a/spec/unit/knife/cookbook_site_share_spec.rb b/spec/unit/knife/cookbook_site_share_spec.rb
index 28b2a509fd..a46783274b 100644
--- a/spec/unit/knife/cookbook_site_share_spec.rb
+++ b/spec/unit/knife/cookbook_site_share_spec.rb
@@ -34,7 +34,7 @@ describe Chef::Knife::CookbookSiteShare do
@cookbook_loader.stub(:[]).and_return(@cookbook)
Chef::CookbookLoader.stub(:new).and_return(@cookbook_loader)
- @cookbook_uploader = Chef::CookbookUploader.new('herpderp', File.join(CHEF_SPEC_DATA, 'cookbooks'), :rest => "norest")
+ @cookbook_uploader = Chef::CookbookUploader.new('herpderp', :rest => "norest")
Chef::CookbookUploader.stub(:new).and_return(@cookbook_uploader)
@cookbook_uploader.stub(:validate_cookbooks).and_return(true)
Chef::CookbookSiteStreamingUploader.stub(:create_build_dir).and_return(Dir.mktmpdir)
@@ -77,7 +77,7 @@ describe Chef::Knife::CookbookSiteShare do
it 'should make a tarball of the cookbook' do
@knife.should_receive(:shell_out!) do |args|
- args.to_s.should match /tar -czf/
+ args.to_s.should match(/tar -czf/)
end
@knife.run
end
diff --git a/spec/unit/knife/cookbook_upload_spec.rb b/spec/unit/knife/cookbook_upload_spec.rb
index 6a99a80459..e5c9a40cf1 100644
--- a/spec/unit/knife/cookbook_upload_spec.rb
+++ b/spec/unit/knife/cookbook_upload_spec.rb
@@ -61,8 +61,9 @@ describe Chef::Knife::CookbookUpload do
test_cookbook = Chef::CookbookVersion.new('test_cookbook', '/tmp/blah')
cookbook_loader.stub(:each).and_yield("test_cookbook", test_cookbook)
cookbook_loader.stub(:cookbook_names).and_return(["test_cookbook"])
- Chef::CookbookUploader.should_receive(:new).with( kind_of(Array), kind_of(Array),
- {:force=>nil, :concurrency => 3}).and_return(double("Chef::CookbookUploader", :upload_cookbooks=> true))
+ Chef::CookbookUploader.should_receive(:new).
+ with( kind_of(Array), { :force => nil, :concurrency => 3}).
+ and_return(double("Chef::CookbookUploader", :upload_cookbooks=> true))
knife.run
end
end
diff --git a/spec/unit/knife/tag_create_spec.rb b/spec/unit/knife/tag_create_spec.rb
index 82e3ad68cd..bafea8d268 100644
--- a/spec/unit/knife/tag_create_spec.rb
+++ b/spec/unit/knife/tag_create_spec.rb
@@ -9,15 +9,15 @@ describe Chef::Knife::TagCreate do
@node = Chef::Node.new
@node.stub :save
Chef::Node.stub(:load).and_return @node
- @stdout = StringIO.new
- @knife.ui.stub(:stdout).and_return(@stdout)
+ @stderr = StringIO.new
+ @knife.ui.stub(:stderr).and_return(@stderr)
end
describe "run" do
it "can create tags on a node" do
@knife.run
@node.tags.should == ["happytag"]
- @stdout.string.should match /created tags happytag.+node webmonkey.example.com/i
+ @stderr.string.should match /created tags happytag.+node webmonkey.example.com/i
end
end
end
diff --git a/spec/unit/knife/tag_delete_spec.rb b/spec/unit/knife/tag_delete_spec.rb
index 67e3dd3ff0..514228f0a2 100644
--- a/spec/unit/knife/tag_delete_spec.rb
+++ b/spec/unit/knife/tag_delete_spec.rb
@@ -10,8 +10,8 @@ describe Chef::Knife::TagDelete do
@node.stub :save
@node.tags << "sadtag" << "happytag"
Chef::Node.stub(:load).and_return @node
- @stdout = StringIO.new
- @knife.ui.stub(:stdout).and_return(@stdout)
+ @stderr = StringIO.new
+ @knife.ui.stub(:stderr).and_return(@stderr)
end
describe "run" do
@@ -19,7 +19,7 @@ describe Chef::Knife::TagDelete do
@node.tags.should == ["sadtag", "happytag"]
@knife.run
@node.tags.should == ["happytag"]
- @stdout.string.should match /deleted.+sadtag/i
+ @stderr.string.should match /deleted.+sadtag/i
end
end
end
diff --git a/spec/unit/knife/user_create_spec.rb b/spec/unit/knife/user_create_spec.rb
index 039d4659b0..58ef868053 100644
--- a/spec/unit/knife/user_create_spec.rb
+++ b/spec/unit/knife/user_create_spec.rb
@@ -46,7 +46,7 @@ describe Chef::Knife::UserCreate do
Chef::User.should_receive(:new).and_return(@user)
@user.should_receive(:create)
@knife.run
- @stdout.string.should match /created user.+a_user/i
+ @stderr.string.should match /created user.+a_user/i
end
it "sets the password" do
diff --git a/spec/unit/knife_spec.rb b/spec/unit/knife_spec.rb
index 52784741d7..70b60a2f96 100644
--- a/spec/unit/knife_spec.rb
+++ b/spec/unit/knife_spec.rb
@@ -41,7 +41,7 @@ describe Chef::Knife do
Chef::Log.stub(level_sym)
end
Chef::Knife.stub(:puts)
- @stdout = StringIO.new
+ @stderr = StringIO.new
end
describe "selecting a config file" do
@@ -241,7 +241,7 @@ describe Chef::Knife do
end
it "exits if no subcommand matches the CLI args" do
- Chef::Knife.ui.stub(:stdout).and_return(@stdout)
+ Chef::Knife.ui.stub(:stderr).and_return(@stderr)
Chef::Knife.ui.should_receive(:fatal)
lambda {Chef::Knife.run(%w{fuuu uuuu fuuuu})}.should raise_error(SystemExit) { |e| e.status.should_not == 0 }
end
@@ -326,7 +326,7 @@ describe Chef::Knife do
@knife.stub(:run).and_raise(Net::HTTPServerException.new("401 Unauthorized", response))
@knife.run_with_pretty_exceptions
@stderr.string.should match(/ERROR: Failed to authenticate to/)
- @stdout.string.should match(/Response: y u no syncronize your clock\?/)
+ @stderr.string.should match(/Response: y u no syncronize your clock\?/)
end
it "formats 403s nicely" do
@@ -337,7 +337,7 @@ describe Chef::Knife do
@knife.stub(:username).and_return("sadpanda")
@knife.run_with_pretty_exceptions
@stderr.string.should match(%r[ERROR: You authenticated successfully to http.+ as sadpanda but you are not authorized for this action])
- @stdout.string.should match(%r[Response: y u no administrator])
+ @stderr.string.should match(%r[Response: y u no administrator])
end
it "formats 400s nicely" do
@@ -347,7 +347,7 @@ describe Chef::Knife do
@knife.stub(:run).and_raise(Net::HTTPServerException.new("400 Bad Request", response))
@knife.run_with_pretty_exceptions
@stderr.string.should match(%r[ERROR: The data in your request was invalid])
- @stdout.string.should match(%r[Response: y u search wrong])
+ @stderr.string.should match(%r[Response: y u search wrong])
end
it "formats 404s nicely" do
@@ -357,7 +357,7 @@ describe Chef::Knife do
@knife.stub(:run).and_raise(Net::HTTPServerException.new("404 Not Found", response))
@knife.run_with_pretty_exceptions
@stderr.string.should match(%r[ERROR: The object you are looking for could not be found])
- @stdout.string.should match(%r[Response: nothing to see here])
+ @stderr.string.should match(%r[Response: nothing to see here])
end
it "formats 500s nicely" do
@@ -367,7 +367,7 @@ describe Chef::Knife do
@knife.stub(:run).and_raise(Net::HTTPFatalError.new("500 Internal Server Error", response))
@knife.run_with_pretty_exceptions
@stderr.string.should match(%r[ERROR: internal server error])
- @stdout.string.should match(%r[Response: sad trombone])
+ @stderr.string.should match(%r[Response: sad trombone])
end
it "formats 502s nicely" do
@@ -377,7 +377,7 @@ describe Chef::Knife do
@knife.stub(:run).and_raise(Net::HTTPFatalError.new("502 Bad Gateway", response))
@knife.run_with_pretty_exceptions
@stderr.string.should match(%r[ERROR: bad gateway])
- @stdout.string.should match(%r[Response: sadder trombone])
+ @stderr.string.should match(%r[Response: sadder trombone])
end
it "formats 503s nicely" do
@@ -387,7 +387,7 @@ describe Chef::Knife do
@knife.stub(:run).and_raise(Net::HTTPFatalError.new("503 Service Unavailable", response))
@knife.run_with_pretty_exceptions
@stderr.string.should match(%r[ERROR: Service temporarily unavailable])
- @stdout.string.should match(%r[Response: saddest trombone])
+ @stderr.string.should match(%r[Response: saddest trombone])
end
it "formats other HTTP errors nicely" do
@@ -397,15 +397,15 @@ describe Chef::Knife do
@knife.stub(:run).and_raise(Net::HTTPServerException.new("402 Payment Required", response))
@knife.run_with_pretty_exceptions
@stderr.string.should match(%r[ERROR: Payment Required])
- @stdout.string.should match(%r[Response: nobugfixtillyoubuy])
+ @stderr.string.should match(%r[Response: nobugfixtillyoubuy])
end
it "formats NameError and NoMethodError nicely" do
@knife.stub(:run).and_raise(NameError.new("Undefined constant FUUU"))
@knife.run_with_pretty_exceptions
@stderr.string.should match(%r[ERROR: knife encountered an unexpected error])
- @stdout.string.should match(%r[This may be a bug in the 'knife' knife command or plugin])
- @stdout.string.should match(%r[Exception: NameError: Undefined constant FUUU])
+ @stderr.string.should match(%r[This may be a bug in the 'knife' knife command or plugin])
+ @stderr.string.should match(%r[Exception: NameError: Undefined constant FUUU])
end
it "formats missing private key errors nicely" do
@@ -413,7 +413,7 @@ describe Chef::Knife do
@knife.stub(:api_key).and_return("/home/root/.chef/no-key-here.pem")
@knife.run_with_pretty_exceptions
@stderr.string.should match(%r[ERROR: Your private key could not be loaded from /home/root/.chef/no-key-here.pem])
- @stdout.string.should match(%r[Check your configuration file and ensure that your private key is readable])
+ @stderr.string.should match(%r[Check your configuration file and ensure that your private key is readable])
end
it "formats connection refused errors nicely" do
@@ -423,7 +423,7 @@ describe Chef::Knife do
# *nix = Errno::ECONNREFUSED: Connection refused
# win32: Errno::ECONNREFUSED: No connection could be made because the target machine actively refused it.
@stderr.string.should match(%r[ERROR: Network Error: .* - y u no shut up])
- @stdout.string.should match(%r[Check your knife configuration and network settings])
+ @stderr.string.should match(%r[Check your knife configuration and network settings])
end
end
diff --git a/spec/unit/lwrp_spec.rb b/spec/unit/lwrp_spec.rb
index 9a775f2dff..960aff3c36 100644
--- a/spec/unit/lwrp_spec.rb
+++ b/spec/unit/lwrp_spec.rb
@@ -180,6 +180,19 @@ describe "LWRP" do
end
end
+ describe "when #default_action is an array" do
+ let(:lwrp) do
+ Class.new(Chef::Resource::LWRPBase) do
+ actions :eat, :sleep
+ default_action [:eat, :sleep]
+ end
+ end
+
+ it "returns the array of default actions" do
+ expect(lwrp.default_action).to eq([:eat, :sleep])
+ end
+ end
+
describe "when inheriting from LWRPBase" do
let(:parent) do
Class.new(Chef::Resource::LWRPBase) do
diff --git a/spec/unit/mixin/template_spec.rb b/spec/unit/mixin/template_spec.rb
index 3aa0b9ba22..63fa81782e 100644
--- a/spec/unit/mixin/template_spec.rb
+++ b/spec/unit/mixin/template_spec.rb
@@ -76,7 +76,7 @@ describe Chef::Mixin::Template, "render_template" do
describe "with a template resource" do
before :each do
@cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, @cookbook_repo) }
+ Chef::Cookbook::FileVendor.fetch_from_disk(@cookbook_repo)
@node = Chef::Node.new
cl = Chef::CookbookLoader.new(@cookbook_repo)
diff --git a/spec/unit/provider/http_request_spec.rb b/spec/unit/provider/http_request_spec.rb
index 605287fcc3..3077685b97 100644
--- a/spec/unit/provider/http_request_spec.rb
+++ b/spec/unit/provider/http_request_spec.rb
@@ -53,13 +53,13 @@ describe Chef::Provider::HttpRequest do
it "should inflate a message block at runtime" do
@new_resource.message { "return" }
- @http.should_receive(:get).with("http://www.opscode.com/?message=return", {})
+ @http.should_receive(:get).with("http://www.opscode.com/", {})
@provider.run_action(:get)
@new_resource.should be_updated
end
it "should run a GET request" do
- @http.should_receive(:get).with("http://www.opscode.com/?message=is cool", {})
+ @http.should_receive(:get).with("http://www.opscode.com/", {})
@provider.run_action(:get)
@new_resource.should be_updated
end
@@ -112,25 +112,25 @@ describe Chef::Provider::HttpRequest do
it "should inflate a message block at runtime" do
@new_resource.message { "return" }
- @http.should_receive(:head).with("http://www.opscode.com/?message=return", {}).and_return(nil)
+ @http.should_receive(:head).with("http://www.opscode.com/", {}).and_return(nil)
@provider.run_action(:head)
@new_resource.should be_updated
end
it "should run a HEAD request" do
- @http.should_receive(:head).with("http://www.opscode.com/?message=is cool", {}).and_return(nil)
+ @http.should_receive(:head).with("http://www.opscode.com/", {}).and_return(nil)
@provider.run_action(:head)
@new_resource.should be_updated
end
it "should update a HEAD request with empty string response body (CHEF-4762)" do
- @http.should_receive(:head).with("http://www.opscode.com/?message=is cool", {}).and_return("")
+ @http.should_receive(:head).with("http://www.opscode.com/", {}).and_return("")
@provider.run_action(:head)
@new_resource.should be_updated
end
it "should update a HEAD request with nil response body (CHEF-4762)" do
- @http.should_receive(:head).with("http://www.opscode.com/?message=is cool", {}).and_return(nil)
+ @http.should_receive(:head).with("http://www.opscode.com/", {}).and_return(nil)
@provider.run_action(:head)
@new_resource.should be_updated
end
@@ -138,14 +138,14 @@ describe Chef::Provider::HttpRequest do
it "should not update a HEAD request if a not modified response (CHEF-4762)" do
if_modified_since = File.mtime(__FILE__).httpdate
@new_resource.headers "If-Modified-Since" => if_modified_since
- @http.should_receive(:head).with("http://www.opscode.com/?message=is cool", {"If-Modified-Since" => if_modified_since}).and_return(false)
+ @http.should_receive(:head).with("http://www.opscode.com/", {"If-Modified-Since" => if_modified_since}).and_return(false)
@provider.run_action(:head)
@new_resource.should_not be_updated
end
it "should run a HEAD request with If-Modified-Since header" do
@new_resource.headers "If-Modified-Since" => File.mtime(__FILE__).httpdate
- @http.should_receive(:head).with("http://www.opscode.com/?message=is cool", @new_resource.headers)
+ @http.should_receive(:head).with("http://www.opscode.com/", @new_resource.headers)
@provider.run_action(:head)
end
diff --git a/spec/unit/provider/log_spec.rb b/spec/unit/provider/log_spec.rb
index 8f411e461a..f6ff526dd4 100644
--- a/spec/unit/provider/log_spec.rb
+++ b/spec/unit/provider/log_spec.rb
@@ -78,22 +78,4 @@ describe Chef::Provider::Log::ChefLog do
@provider.action_write
end
- it "should not update the resource if the message was not written to the log" do
- Chef::Log.level = :fatal
- @new_resource = Chef::Resource::Log.new(@log_str)
- @new_resource.level :info
- @provider = Chef::Provider::Log::ChefLog.new(@new_resource, @run_context)
- @provider.action_write
- @new_resource.updated.should be_false
- end
-
- it "should update the resource if the message has been written to the log" do
- Chef::Log.level = :debug
- @new_resource = Chef::Resource::Log.new(@log_str)
- @new_resource.level :info
- @provider = Chef::Provider::Log::ChefLog.new(@new_resource, @run_context)
- @provider.action_write
- @new_resource.updated.should be_true
- end
-
end
diff --git a/spec/unit/provider/package_spec.rb b/spec/unit/provider/package_spec.rb
index 33b4f8186a..375a0d0646 100644
--- a/spec/unit/provider/package_spec.rb
+++ b/spec/unit/provider/package_spec.rb
@@ -339,7 +339,7 @@ describe Chef::Provider::Package do
describe "when given a response file" do
before(:each) do
@cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, @cookbook_repo) }
+ Chef::Cookbook::FileVendor.fetch_from_disk(@cookbook_repo)
@node = Chef::Node.new
cl = Chef::CookbookLoader.new(@cookbook_repo)
diff --git a/spec/unit/provider/remote_directory_spec.rb b/spec/unit/provider/remote_directory_spec.rb
index d3f1438f0f..b986e2c8ad 100644
--- a/spec/unit/provider/remote_directory_spec.rb
+++ b/spec/unit/provider/remote_directory_spec.rb
@@ -35,7 +35,7 @@ describe Chef::Provider::RemoteDirectory do
@resource.cookbook('openldap')
@cookbook_repo = ::File.expand_path(::File.join(CHEF_SPEC_DATA, "cookbooks"))
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, @cookbook_repo) }
+ Chef::Cookbook::FileVendor.fetch_from_disk(@cookbook_repo)
@node = Chef::Node.new
cl = Chef::CookbookLoader.new(@cookbook_repo)
diff --git a/spec/unit/provider/template/content_spec.rb b/spec/unit/provider/template/content_spec.rb
index dfc5d21c2a..b419e70519 100644
--- a/spec/unit/provider/template/content_spec.rb
+++ b/spec/unit/provider/template/content_spec.rb
@@ -36,7 +36,7 @@ describe Chef::Provider::Template::Content do
let(:run_context) do
cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
- Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, cookbook_repo) }
+ Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_repo)
cl = Chef::CookbookLoader.new(cookbook_repo)
cl.load_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cl)
diff --git a/spec/unit/provider_spec.rb b/spec/unit/provider_spec.rb
index 363649ec46..9b89fc1888 100644
--- a/spec/unit/provider_spec.rb
+++ b/spec/unit/provider_spec.rb
@@ -61,6 +61,18 @@ describe Chef::Provider do
@provider = Chef::Provider.new(@resource, @run_context)
end
+ it "should mixin shell_out" do
+ expect(@provider.respond_to?(:shell_out)).to be true
+ end
+
+ it "should mixin shell_out!" do
+ expect(@provider.respond_to?(:shell_out!)).to be true
+ end
+
+ it "should mixin shell_out_with_systems_locale" do
+ expect(@provider.respond_to?(:shell_out_with_systems_locale)).to be true
+ end
+
it "should store the resource passed to new as new_resource" do
@provider.new_resource.should eql(@resource)
end
diff --git a/spec/unit/shell/shell_session_spec.rb b/spec/unit/shell/shell_session_spec.rb
index 92a2e5d538..f49c9fc805 100644
--- a/spec/unit/shell/shell_session_spec.rb
+++ b/spec/unit/shell/shell_session_spec.rb
@@ -50,6 +50,7 @@ end
describe Shell::ClientSession do
before do
Chef::Config[:shell_config] = { :override_runlist => [Chef::RunList::RunListItem.new('shell::override')] }
+ @chef_rest = double("Chef::REST")
@session = Shell::ClientSession.instance
@node = Chef::Node.build("foo")
@session.node = @node
@@ -66,6 +67,7 @@ describe Shell::ClientSession do
@expansion = Chef::RunList::RunListExpansion.new(@node.chef_environment, [])
@node.run_list.should_receive(:expand).with(@node.chef_environment).and_return(@expansion)
+ Chef::REST.should_receive(:new).with(Chef::Config[:chef_server_url]).and_return(@chef_rest)
@session.rebuild_context
end