diff options
author | Bryan McLellan <btm@opscode.com> | 2012-10-30 13:44:23 -0700 |
---|---|---|
committer | Bryan McLellan <btm@opscode.com> | 2012-10-30 13:44:23 -0700 |
commit | 40bb09b6605852b362875ec99438f22af6c35676 (patch) | |
tree | 932e28c75bcccc5a18a86d1371612b0fcdd9429c | |
parent | 7c757e2281e862a26c22795ffd957e6048da02b1 (diff) | |
parent | 6668c614b3762ded59595241f4719dbec98eaa1f (diff) | |
download | chef-40bb09b6605852b362875ec99438f22af6c35676.tar.gz |
Merge branch '10-stable'
Conflicts:
chef-expander/lib/chef/expander/version.rb
chef-server-api/lib/chef-server-api/version.rb
chef-server-webui/lib/chef-server-webui/version.rb
chef-server/lib/chef-server/version.rb
chef-solr/lib/chef/solr/version.rb
chef/lib/chef/node/attribute.rb
lib/chef/node.rb
-rw-r--r-- | Gemfile | 6 | ||||
-rw-r--r-- | chef/spec/functional/resource/cookbook_file_spec.rb | 51 | ||||
-rw-r--r-- | lib/chef/application.rb | 15 | ||||
-rw-r--r-- | lib/chef/application/client.rb | 12 | ||||
-rw-r--r-- | lib/chef/application/solo.rb | 12 | ||||
-rw-r--r-- | lib/chef/application/windows_service.rb | 11 | ||||
-rw-r--r-- | lib/chef/config.rb | 3 | ||||
-rw-r--r-- | lib/chef/knife/cookbook_site_install.rb | 11 | ||||
-rw-r--r-- | lib/chef/provider/cookbook_file.rb | 3 | ||||
-rw-r--r-- | lib/chef/provider/file.rb | 25 | ||||
-rw-r--r-- | lib/chef/provider/remote_directory.rb | 39 | ||||
-rw-r--r-- | lib/chef/resource_reporter.rb | 39 | ||||
-rw-r--r-- | spec/unit/application/solo_spec.rb | 4 | ||||
-rw-r--r-- | spec/unit/mixin/enforce_ownership_and_permissions_spec.rb | 2 | ||||
-rw-r--r-- | spec/unit/provider/directory_spec.rb | 138 | ||||
-rw-r--r-- | spec/unit/provider/file_spec.rb | 138 | ||||
-rw-r--r-- | spec/unit/provider/remote_directory_spec.rb | 7 | ||||
-rw-r--r-- | spec/unit/resource_reporter_spec.rb | 19 |
18 files changed, 324 insertions, 211 deletions
@@ -7,11 +7,7 @@ gem "ronn" group(:development, :test) do gem 'rack' - - # The 'ruby' platform is surprisingly just unix-y platforms - # thin requires eventmachine, which won't work under Ruby 1.9 on Windows - # http://gembundler.com/man/gemfile.5.html - gem 'thin', :platforms => :ruby + gem 'thin' # Eventmachine 1.0.0 is causing functional test failures on Solaris # 9 SPARC. Pinning em to 0.12.10 solves this issue until we can diff --git a/chef/spec/functional/resource/cookbook_file_spec.rb b/chef/spec/functional/resource/cookbook_file_spec.rb new file mode 100644 index 0000000000..adc1f7eef8 --- /dev/null +++ b/chef/spec/functional/resource/cookbook_file_spec.rb @@ -0,0 +1,51 @@ +# +# Author:: Tim Hinderliter (<tim@opscode.com>) +# Copyright:: Copyright (c) 2012 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'spec_helper' + +describe Chef::Resource::CookbookFile do + include_context Chef::Resource::File + + let(:file_base) { 'cookbook_file_spec' } + let(:source) { 'java.response' } + let(:cookbook_name) { 'java' } + let(:expected_content) { IO.read(File.join(CHEF_SPEC_DATA, 'cookbooks', 'java', 'files', 'default', 'java.response')) } + + def create_resource + # 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) } + cookbook_collection = Chef::CookbookCollection.new(Chef::CookbookLoader.new(cookbook_repo)) + + node = Chef::Node.new + events = Chef::EventDispatch::Dispatcher.new + run_context = Chef::RunContext.new(node, cookbook_collection, events) + resource = Chef::Resource::CookbookFile.new(path, run_context) + resource.cookbook(cookbook_name) + resource.source(source) + + resource + end + + let!(:resource) do + create_resource + end + + it_behaves_like "a file resource" +end diff --git a/lib/chef/application.rb b/lib/chef/application.rb index 328a81a2eb..f864996ea5 100644 --- a/lib/chef/application.rb +++ b/lib/chef/application.rb @@ -34,6 +34,8 @@ class Chef::Application def initialize super + @chef_client = nil + @chef_client_json = nil trap("TERM") do Chef::Application.fatal!("SIGTERM received, stopping", 1) end @@ -127,6 +129,18 @@ class Chef::Application raise Chef::Exceptions::Application, "#{self.to_s}: you must override run_application" end + # Initializes Chef::Client instance and runs it + def run_chef_client + @chef_client = Chef::Client.new( + @chef_client_json, + :override_runlist => config[:override_runlist] + ) + @chef_client_json = nil + + @chef_client.run + @chef_client = nil + end + private def apply_config(config_file_path) @@ -134,7 +148,6 @@ class Chef::Application Chef::Config.merge!(config) end - class << self def debug_stacktrace(e) message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}" diff --git a/lib/chef/application/client.rb b/lib/chef/application/client.rb index 3a68a41c14..ef40a7a358 100644 --- a/lib/chef/application/client.rb +++ b/lib/chef/application/client.rb @@ -186,9 +186,6 @@ class Chef::Application::Client < Chef::Application def initialize super - - @chef_client = nil - @chef_client_json = nil end # Reconfigure the chef client @@ -274,14 +271,7 @@ class Chef::Application::Client < Chef::Application Chef::Log.debug("Splay sleep #{splay} seconds") sleep splay end - @chef_client = Chef::Client.new( - @chef_client_json, - :override_runlist => config[:override_runlist] - ) - @chef_client_json = nil - - @chef_client.run - @chef_client = nil + run_chef_client if Chef::Config[:interval] Chef::Log.debug("Sleeping for #{Chef::Config[:interval]} seconds") unless SELF_PIPE.empty? diff --git a/lib/chef/application/solo.rb b/lib/chef/application/solo.rb index 7ec6c36e76..4aca7238f6 100644 --- a/lib/chef/application/solo.rb +++ b/lib/chef/application/solo.rb @@ -149,8 +149,6 @@ class Chef::Application::Solo < Chef::Application def initialize super - @chef_solo = nil - @chef_solo_json = nil end def reconfigure @@ -182,7 +180,7 @@ class Chef::Application::Solo < Chef::Application end begin - @chef_solo_json = Chef::JSONCompat.from_json(json_io.read) + @chef_client_json = Chef::JSONCompat.from_json(json_io.read) json_io.close unless json_io.closed? rescue JSON::ParserError => error Chef::Application.fatal!("Could not parse the provided JSON file (#{Chef::Config[:json_attribs]})!: " + error.message, 2) @@ -223,12 +221,7 @@ class Chef::Application::Solo < Chef::Application sleep splay end - @chef_solo = Chef::Client.new( - @chef_solo_json, - :override_runlist => config[:override_runlist] - ) - @chef_solo.run - @chef_solo = nil + run_chef_client if Chef::Config[:interval] Chef::Log.debug("Sleeping for #{Chef::Config[:interval]} seconds") sleep Chef::Config[:interval] @@ -251,4 +244,5 @@ class Chef::Application::Solo < Chef::Application end end end + end diff --git a/lib/chef/application/windows_service.rb b/lib/chef/application/windows_service.rb index 961ec8f92f..0d4a022fdf 100644 --- a/lib/chef/application/windows_service.rb +++ b/lib/chef/application/windows_service.rb @@ -88,14 +88,7 @@ class Chef # If we've stopped, then bail out now, instead of going on to run Chef next if state != RUNNING - @chef_client = Chef::Client.new( - @chef_client_json, - :override_runlist => config[:override_runlist] - ) - @chef_client_json = nil - - @chef_client.run - @chef_client = nil + run_chef_client Chef::Log.debug("Sleeping for #{Chef::Config[:interval]} seconds") client_sleep Chef::Config[:interval] @@ -225,7 +218,7 @@ class Chef sleep chunk_length end end - + end end end diff --git a/lib/chef/config.rb b/lib/chef/config.rb index 61c8806a66..dceac4fa34 100644 --- a/lib/chef/config.rb +++ b/lib/chef/config.rb @@ -287,6 +287,9 @@ class Chef cache_type "BasicFile" cache_options({ :path => platform_specific_path("/var/chef/cache/checksums"), :skip_expires => true }) + # Set to false to silence Chef 11 deprecation warnings: + chef11_deprecation_warnings true + # Arbitrary knife configuration data knife Hash.new diff --git a/lib/chef/knife/cookbook_site_install.rb b/lib/chef/knife/cookbook_site_install.rb index b2e0d84751..584735d8ff 100644 --- a/lib/chef/knife/cookbook_site_install.rb +++ b/lib/chef/knife/cookbook_site_install.rb @@ -107,6 +107,7 @@ class Chef end end + unless config[:no_deps] md = Chef::Cookbook::Metadata.new md.from_file(File.join(@install_path, @cookbook_name, "metadata.rb")) @@ -143,13 +144,21 @@ class Chef def extract_cookbook(upstream_file, version) ui.info("Uncompressing #{@cookbook_name} version #{version}.") - shell_out!("tar zxvf #{Shellwords.escape upstream_file}", :cwd => @install_path) + shell_out!("tar zxvf #{convert_path upstream_file}", :cwd => @install_path) end def clear_existing_files(cookbook_path) ui.info("Removing pre-existing version.") FileUtils.rmtree(cookbook_path) if File.directory?(cookbook_path) end + + def convert_path(upstream_file) + if ENV['MSYSTEM'] == 'MINGW32' + return upstream_file.sub(/^([[:alpha:]]):/, '/\1') + else + return Shellwords.escape upstream_file + end + end end end end diff --git a/lib/chef/provider/cookbook_file.rb b/lib/chef/provider/cookbook_file.rb index 431f3f2367..144afbddeb 100644 --- a/lib/chef/provider/cookbook_file.rb +++ b/lib/chef/provider/cookbook_file.rb @@ -44,9 +44,6 @@ class Chef Chef::Log.debug("#{@new_resource} staging #{file_cache_location} to #{tempfile.path}") tempfile.close FileUtils.cp(file_cache_location, tempfile.path) - # Since the @new_resource.path file will not be updated - # at the time of converge, we must use the tempfile - update_new_file_state(tempfile.path) end Chef::Log.info("#{@new_resource} created file #{@new_resource.path}") end diff --git a/lib/chef/provider/file.rb b/lib/chef/provider/file.rb index 659afc6517..77f5217027 100644 --- a/lib/chef/provider/file.rb +++ b/lib/chef/provider/file.rb @@ -132,7 +132,9 @@ class Chef @current_resource.path(@new_resource.path) if !::File.directory?(@new_resource.path) if ::File.exist?(@new_resource.path) - @current_resource.checksum(checksum(@new_resource.path)) + if @action != :create_if_missing + @current_resource.checksum(checksum(@new_resource.path)) + end end end load_current_resource_attrs @@ -142,6 +144,13 @@ class Chef end def load_current_resource_attrs + if Chef::Platform.windows? + # TODO: To work around CHEF-3554, add support for Windows + # equivalent, or implicit resource reporting won't work for + # Windows. + return + end + if ::File.exist?(@new_resource.path) stat = ::File.stat(@new_resource.path) @current_resource.owner(stat.uid) @@ -215,13 +224,21 @@ class Chef # override the default with the tempfile, since the # file at @new_resource.path will not be updated on converge def update_new_file_state(path=@new_resource.path) + if !::File.directory?(path) + @new_resource.checksum(checksum(path)) + end + + if Chef::Platform.windows? + # TODO: To work around CHEF-3554, add support for Windows + # equivalent, or implicit resource reporting won't work for + # Windows. + return + end + stat = ::File.stat(path) @new_resource.owner(stat.uid) @new_resource.mode(stat.mode & 07777) @new_resource.group(stat.gid) - if !::File.directory?(path) - @new_resource.checksum(checksum(path)) - end end def action_create diff --git a/lib/chef/provider/remote_directory.rb b/lib/chef/provider/remote_directory.rb index 9ccd7ea056..dee383f763 100644 --- a/lib/chef/provider/remote_directory.rb +++ b/lib/chef/provider/remote_directory.rb @@ -34,23 +34,27 @@ class Chef def action_create super - - files_to_purge = Set.new( - Dir.glob(::File.join(@new_resource.path, '**', '*'), ::File::FNM_DOTMATCH).select do |name| - 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 - files_to_purge.delete(::File.join(@new_resource.path, cookbook_file_relative_path)) - # parent directories are also removed from the purge list - directories=::File.dirname(::File.join(@new_resource.path, cookbook_file_relative_path)).split(::File::SEPARATOR) - for i in 0..directories.length-1 - files_to_purge.delete(::File.join(directories[0..i])) + files_to_purge = Set.new(Dir.glob(::File.join(@new_resource.path, '**', '*'), + ::File::FNM_DOTMATCH).select do |name| + name !~ /(?:^|#{Regexp.escape(::File::SEPARATOR)})\.\.?$/ + end) + + converge_by("Create managed files in directory") do + files_to_transfer.each do |cookbook_file_relative_path| + create_cookbook_file(cookbook_file_relative_path) + # the file is removed from the purge list + files_to_purge.delete(::File.join(@new_resource.path, cookbook_file_relative_path)) + # parent directories are also removed from the purge list + directories=::File.dirname(::File.join(@new_resource.path, cookbook_file_relative_path)).split(::File::SEPARATOR) + for i in 0..directories.length-1 + files_to_purge.delete(::File.join(directories[0..i])) + end end end - purge_unmanaged_files(files_to_purge) + + converge_by("Purge unmanaged files from directory") do + purge_unmanaged_files(files_to_purge) + end end def action_create_if_missing @@ -170,5 +174,10 @@ class Chef end end + + def whyrun_supported? + true + end + end end diff --git a/lib/chef/resource_reporter.rb b/lib/chef/resource_reporter.rb index 3d10c1e961..f9ad5e1cb9 100644 --- a/lib/chef/resource_reporter.rb +++ b/lib/chef/resource_reporter.rb @@ -116,15 +116,15 @@ class Chef Chef::Log.info("Chef server generated run history id: #{@run_id}") @summary_only = server_response["summary_only"] rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError => e - if !e.response || e.response.code.to_s != 404 + if !e.response || e.response.code.to_s != "404" if Chef::Config[:enable_reporting_url_fatals] - Chef::Log.error("Received exception attempting to generate run history id (URL Path: #{resource_history_url}), and enable_reporting_url_fatals is set, aborting run.") + Chef::Log.error("Received exception #{"(" + e.response.code + ") " if e.response.code}attempting to generate run history id (URL Path: #{resource_history_url}), and enable_reporting_url_fatals is set, aborting run.") raise else - Chef::Log.info("Received exception attempting to generate run history id (URL Path: #{resource_history_url}), disabling reporting for this run.") + Chef::Log.info("Received exception #{"(" + e.response.code + ") " if e.response.code}attempting to generate run history id (URL Path: #{resource_history_url}), disabling reporting for this run.") end else - Chef::Log.debug("Received 404 attempting to generate run history id (URL Path: #{resource_history_url}), assuming feature is not supported.") + Chef::Log.debug("Received 404 attempting to generate run history id (URL Path: #{resource_history_url}), assuming feature is not supported on server.") end @reporting_enabled = false end @@ -187,17 +187,26 @@ class Chef Chef::Log.info("Sending resource update report (run-id: #{@run_id})") Chef::Log.debug run_data.inspect compressed_data = encode_gzip(run_data.to_json) - #if summary only is enabled send the uncompressed run_data excluding the run_data["resources"] and some additional metrics. - if @summary_only - run_data = report_summary(run_data, compressed_data) - Chef::Log.info("run_data_summary: #{run_data}") - @rest_client.post_rest(resource_history_url, run_data) - else - Chef::Log.debug("Sending Compressed Run Data...") - # Since we're posting compressed data we can not directly call - # post_rest which expects JSON - reporting_url = @rest_client.create_url(resource_history_url) - @rest_client.raw_http_request(:POST, reporting_url, {'Content-Encoding' => 'gzip'}, compressed_data) + begin + #if summary only is enabled send the uncompressed run_data excluding the run_data["resources"] and some additional metrics. + if @summary_only + run_data = report_summary(run_data, compressed_data) + Chef::Log.info("run_data_summary: #{run_data}") + @rest_client.post_rest(resource_history_url, run_data) + else + Chef::Log.debug("Sending compressed run data...") + # Since we're posting compressed data we can not directly call + # post_rest which expects JSON + reporting_url = @rest_client.create_url(resource_history_url) + @rest_client.raw_http_request(:POST, reporting_url, {'Content-Encoding' => 'gzip'}, compressed_data) + end + rescue Net::HTTPServerException => e + if e.response.code.to_s == "400" + Chef::FileCache.store("failed-reporting-data.json", Chef::JSONCompat.to_json_pretty(run_data), 0640) + Chef::Log.error("Failed to post reporting data to server (HTTP 400), saving to #{Chef::FileCache.load("failed-reporting-data.json", false)}") + else + Chef::Log.error("Failed to post reporting data to server (HTTP #{e.response.code.to_s})") + end end else Chef::Log.debug("Server doesn't support resource history, skipping resource report.") diff --git a/spec/unit/application/solo_spec.rb b/spec/unit/application/solo_spec.rb index 148fb3cf87..96c89a37a6 100644 --- a/spec/unit/application/solo_spec.rb +++ b/spec/unit/application/solo_spec.rb @@ -71,7 +71,7 @@ describe Chef::Application::Solo do it "should perform a RESTful GET on the supplied URL" do @app.reconfigure - @app.chef_solo_json.should == {"a" => "b"} + @app.instance_variable_get(:@chef_client_json).should == {"a" => "b"} end end @@ -84,7 +84,7 @@ describe Chef::Application::Solo do it "should parse the json out of the file" do @app.reconfigure - @app.chef_solo_json.should == {"a" => "b"} + @app.instance_variable_get(:@chef_client_json).should == {"a" => "b"} end end diff --git a/spec/unit/mixin/enforce_ownership_and_permissions_spec.rb b/spec/unit/mixin/enforce_ownership_and_permissions_spec.rb index 53a8260cdc..efbbe9218e 100644 --- a/spec/unit/mixin/enforce_ownership_and_permissions_spec.rb +++ b/spec/unit/mixin/enforce_ownership_and_permissions_spec.rb @@ -84,6 +84,8 @@ describe Chef::Mixin::EnforceOwnershipAndPermissions do end it "sets updated_by_last_action on the new resource" do + @provider.new_resource.owner(0) # CHEF-3557 hack - Set these because we don't for windows + @provider.new_resource.group(0) # CHEF-3557 hack - Set these because we don't for windows @provider.new_resource.should_receive(:updated_by_last_action) Chef::FileAccessControl.any_instance.stub(:set_all) @provider.run_action(:create) diff --git a/spec/unit/provider/directory_spec.rb b/spec/unit/provider/directory_spec.rb index 4f297e0115..5118d086fc 100644 --- a/spec/unit/provider/directory_spec.rb +++ b/spec/unit/provider/directory_spec.rb @@ -33,74 +33,80 @@ describe Chef::Provider::Directory do @directory = Chef::Provider::Directory.new(@new_resource, @run_context) end - it "should load the current resource based on the new resource" do - File.stub!(:exist?).and_return(true) - cstats = mock("stats") - cstats.stub!(:uid).and_return(500) - cstats.stub!(:gid).and_return(500) - cstats.stub!(:mode).and_return(0755) - File.should_receive(:stat).twice.and_return(cstats) - @directory.load_current_resource - @directory.current_resource.path.should eql(@new_resource.path) - @directory.current_resource.owner.should eql(500) - @directory.current_resource.group.should eql(500) - @directory.current_resource.mode.should == 00755 - end - - it "should create a new directory on create, setting updated to true" do - @new_resource.path "/tmp/foo" - - File.should_receive(:exist?).exactly(3).and_return(false) - Dir.should_receive(:mkdir).with(@new_resource.path).once.and_return(true) - - @directory.should_receive(:set_all_access_controls) - @directory.stub!(:update_new_file_state) - @directory.run_action(:create) - @directory.new_resource.should be_updated - end - - it "should raise an exception if the parent directory does not exist and recursive is false" do - @new_resource.path "/tmp/some/dir" - @new_resource.recursive false - lambda { @directory.run_action(:create) }.should raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist) - end - - it "should create a new directory when parent directory does not exist if recursive is true and permissions are correct" do - @new_resource.path "/path/to/dir" - @new_resource.recursive true - File.should_receive(:exist?).with(@new_resource.path).ordered.and_return(false) - File.should_receive(:exist?).with(@new_resource.path).ordered.and_return(false) - - File.should_receive(:exist?).with('/path/to').ordered.and_return(false) - File.should_receive(:exist?).with('/path').ordered.and_return(true) - File.should_receive(:writable?).with('/path').ordered.and_return(true) - File.should_receive(:exist?).with(@new_resource.path).ordered.and_return(false) - - FileUtils.should_receive(:mkdir_p).with(@new_resource.path).and_return(true) - @directory.should_receive(:set_all_access_controls) - @directory.stub!(:update_new_file_state) - @directory.run_action(:create) - @new_resource.should be_updated - end - - # it "should raise an error when creating a directory recursively and permissions do not allow creation" do + context "load_current_resource_attrs", :unix_only do + it "should load the current resource based on the new resource" do + File.stub!(:exist?).and_return(true) + cstats = mock("stats") + cstats.stub!(:uid).and_return(500) + cstats.stub!(:gid).and_return(500) + cstats.stub!(:mode).and_return(0755) + File.should_receive(:stat).twice.and_return(cstats) + @directory.load_current_resource + @directory.current_resource.path.should eql(@new_resource.path) + @directory.current_resource.owner.should eql(500) + @directory.current_resource.group.should eql(500) + @directory.current_resource.mode.should == 00755 + end + + it "should create a new directory on create, setting updated to true" do + @new_resource.path "/tmp/foo" + + File.should_receive(:exist?).exactly(3).and_return(false) + Dir.should_receive(:mkdir).with(@new_resource.path).once.and_return(true) + + @directory.should_receive(:set_all_access_controls) + @directory.stub!(:update_new_file_state) + @directory.run_action(:create) + @directory.new_resource.should be_updated + end + + it "should raise an exception if the parent directory does not exist and recursive is false" do + @new_resource.path "/tmp/some/dir" + @new_resource.recursive false + lambda { @directory.run_action(:create) }.should raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist) + end + + it "should create a new directory when parent directory does not exist if recursive is true and permissions are correct" do + @new_resource.path "/path/to/dir" + @new_resource.recursive true + File.should_receive(:exist?).with(@new_resource.path).ordered.and_return(false) + File.should_receive(:exist?).with(@new_resource.path).ordered.and_return(false) + + File.should_receive(:exist?).with('/path/to').ordered.and_return(false) + File.should_receive(:exist?).with('/path').ordered.and_return(true) + File.should_receive(:writable?).with('/path').ordered.and_return(true) + File.should_receive(:exist?).with(@new_resource.path).ordered.and_return(false) + + FileUtils.should_receive(:mkdir_p).with(@new_resource.path).and_return(true) + @directory.should_receive(:set_all_access_controls) + @directory.stub!(:update_new_file_state) + @directory.run_action(:create) + @new_resource.should be_updated + end + + # it "should raise an error when creating a directory recursively and permissions do not allow creation" do + + # end + + it "should raise an error when creating a directory when parent directory is a file" do + File.should_receive(:directory?).and_return(false) + Dir.should_not_receive(:mkdir).with(@new_resource.path) + lambda { @directory.run_action(:create) }.should raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist) + @directory.new_resource.should_not be_updated + end - # end - - it "should raise an error when creating a directory when parent directory is a file" do - File.should_receive(:directory?).and_return(false) - Dir.should_not_receive(:mkdir).with(@new_resource.path) - lambda { @directory.run_action(:create) }.should raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist) - @directory.new_resource.should_not be_updated + it "should not create the directory if it already exists" do + stub_file_cstats + @new_resource.path "/tmp/foo" + File.should_receive(:exist?).exactly(3).and_return(true) + Dir.should_not_receive(:mkdir).with(@new_resource.path) + @directory.should_receive(:set_all_access_controls) + @directory.run_action(:create) + end end - - it "should not create the directory if it already exists" do - stub_file_cstats - @new_resource.path "/tmp/foo" - File.should_receive(:exist?).exactly(3).and_return(true) - Dir.should_not_receive(:mkdir).with(@new_resource.path) - @directory.should_receive(:set_all_access_controls) - @directory.run_action(:create) + + context "load_current_resource_attrs", :windows_only do + pending "CHEF-3557: Fix implicit resource change collection on Windows" end it "should delete the directory if it exists, and is writable with action_delete" do diff --git a/spec/unit/provider/file_spec.rb b/spec/unit/provider/file_spec.rb index 13b79e4bd6..28d2aac2b5 100644 --- a/spec/unit/provider/file_spec.rb +++ b/spec/unit/provider/file_spec.rb @@ -53,76 +53,82 @@ describe Chef::Provider::File do @provider.current_resource.content.should eql(nil) end - it "should collect the current state of the file on the filesystem and populate current_resource" do - # test setup - stat_struct = mock("::File.stat", :mode => 0600, :uid => 0, :gid => 0, :mtime => 10000) - ::File.should_receive(:stat).exactly(3).with(@resource.path).and_return(stat_struct) - - # test execution - @provider.load_current_resource - - # post-condition checks - @provider.current_resource.mode.should == 0600 - @provider.current_resource.owner.should == 0 - @provider.current_resource.group.should == 0 - end - - it "should NOT update the new_resource state with the current_resourse state if new_resource state is already specified" do - # test setup - stat_struct = mock("::File.stat", :mode => 0600, :uid => 0, :gid => 0, :mtime => 10000) - ::File.should_receive(:stat).exactly(3).with(@resource.path).and_return(stat_struct) - - @provider.new_resource.group(1) - @provider.new_resource.owner(1) - @provider.new_resource.mode(0644) - - # test execution - @provider.load_current_resource - - # post-condition checks - @provider.new_resource.group.should == 1 - @provider.new_resource.owner.should == 1 - @provider.new_resource.mode.should == 0644 + context "load_current_resource_attrs", :unix_only do + it "should collect the current state of the file on the filesystem and populate current_resource" do + # test setup + stat_struct = mock("::File.stat", :mode => 0600, :uid => 0, :gid => 0, :mtime => 10000) + ::File.should_receive(:stat).exactly(3).with(@resource.path).and_return(stat_struct) + + # test execution + @provider.load_current_resource + + # post-condition checks + @provider.current_resource.mode.should == 0600 + @provider.current_resource.owner.should == 0 + @provider.current_resource.group.should == 0 + end + + it "should NOT update the new_resource state with the current_resourse state if new_resource state is already specified" do + # test setup + stat_struct = mock("::File.stat", :mode => 0600, :uid => 0, :gid => 0, :mtime => 10000) + ::File.should_receive(:stat).exactly(3).with(@resource.path).and_return(stat_struct) + + @provider.new_resource.group(1) + @provider.new_resource.owner(1) + @provider.new_resource.mode(0644) + + # test execution + @provider.load_current_resource + + # post-condition checks + @provider.new_resource.group.should == 1 + @provider.new_resource.owner.should == 1 + @provider.new_resource.mode.should == 0644 + end + + it "should update the new_resource state with the current_resource state if the new_resource state is not specified." do + # test setup + stat_struct = mock("::File.stat", :mode => 0600, :uid => 0, :gid => 0, :mtime => 10000) + ::File.should_receive(:stat).exactly(3).with(@resource.path).and_return(stat_struct) + + @provider.new_resource.group(nil) + @provider.new_resource.owner(nil) + @provider.new_resource.mode(nil) + + # test execution + @provider.load_current_resource + + # post-condition checks + @provider.new_resource.group.should eql(@provider.current_resource.group) + @provider.new_resource.owner.should eql(@provider.current_resource.owner) + @provider.new_resource.mode.should eql(@provider.current_resource.mode) + end + + it "should update the new_resource when attempting to set the new state" do + # test setup + stat_struct = mock("::File.stat", :mode => 0600, :uid => 0, :gid => 0, :mtime => 10000) + # called once in update_new_file_state and once in checksum + ::File.should_receive(:stat).twice.with(@provider.new_resource.path).and_return(stat_struct) + ::File.should_receive(:directory?).once.with(@provider.new_resource.path).and_return(false) + + @provider.new_resource.group(nil) + @provider.new_resource.owner(nil) + @provider.new_resource.mode(nil) + + # test exectution + @provider.update_new_file_state + + # post-condition checks + @provider.new_resource.group.should == 0 + @provider.new_resource.owner.should == 0 + @provider.new_resource.mode.should == 0600 + end end - it "should update the new_resource state with the current_resource state if the new_resource state is not specified." do - # test setup - stat_struct = mock("::File.stat", :mode => 0600, :uid => 0, :gid => 0, :mtime => 10000) - ::File.should_receive(:stat).exactly(3).with(@resource.path).and_return(stat_struct) - - @provider.new_resource.group(nil) - @provider.new_resource.owner(nil) - @provider.new_resource.mode(nil) - - # test execution - @provider.load_current_resource - - # post-condition checks - @provider.new_resource.group.should eql(@provider.current_resource.group) - @provider.new_resource.owner.should eql(@provider.current_resource.owner) - @provider.new_resource.mode.should eql(@provider.current_resource.mode) + context "load_current_resource_attrs", :windows_only do + pending "CHEF-3557: Fix implicit resource change collection on Windows" end - it "should update the new_resource when attempting to set the new state" do - # test setup - stat_struct = mock("::File.stat", :mode => 0600, :uid => 0, :gid => 0, :mtime => 10000) - # called once in update_new_file_state and once in checksum - ::File.should_receive(:stat).twice.with(@provider.new_resource.path).and_return(stat_struct) - ::File.should_receive(:directory?).once.with(@provider.new_resource.path).and_return(false) - - @provider.new_resource.group(nil) - @provider.new_resource.owner(nil) - @provider.new_resource.mode(nil) - - # test exectution - @provider.update_new_file_state - - # post-condition checks - @provider.new_resource.group.should == 0 - @provider.new_resource.owner.should == 0 - @provider.new_resource.mode.should == 0600 -end - it "should load a mostly blank current resource if the file specified in new_resource doesn't exist/isn't readable" do resource = Chef::Resource::File.new("seattle") resource.path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates", "woot.txt"))) diff --git a/spec/unit/provider/remote_directory_spec.rb b/spec/unit/provider/remote_directory_spec.rb index 19a17c269f..0171853eb3 100644 --- a/spec/unit/provider/remote_directory_spec.rb +++ b/spec/unit/provider/remote_directory_spec.rb @@ -100,6 +100,13 @@ describe Chef::Provider::RemoteDirectory do after {FileUtils.rm_rf(@destination_dir)} + # CHEF-3552 + it "creates the toplevel directory without error " do + @resource.recursive(false) + @provider.run_action(:create) + ::File.exist?(@destination_dir).should be_true + end + it "transfers the directory with all contents" do @provider.run_action(:create) ::File.exist?(@destination_dir + '/remote_dir_file1.txt').should be_true diff --git a/spec/unit/resource_reporter_spec.rb b/spec/unit/resource_reporter_spec.rb index bc8e3995f7..51f4ba7c19 100644 --- a/spec/unit/resource_reporter_spec.rb +++ b/spec/unit/resource_reporter_spec.rb @@ -413,18 +413,24 @@ describe Chef::ResourceReporter do @rest_client.should_receive(:post_rest). with("reports/nodes/spitfire/runs", {:action => :begin}). and_raise(@error) - @resource_reporter.node_load_completed(@node, :expanded_run_list, :config) end it "assumes the feature is not enabled" do + @resource_reporter.node_load_completed(@node, :expanded_run_list, :config) @resource_reporter.reporting_enabled?.should be_false end it "does not send a resource report to the server" do + @resource_reporter.node_load_completed(@node, :expanded_run_list, :config) @rest_client.should_not_receive(:post_rest) @resource_reporter.run_completed(@node) end + it "prints an error about the 404" do + Chef::Log.should_receive(:debug).with(/404/) + @resource_reporter.node_load_completed(@node, :expanded_run_list, :config) + end + end context "when the server returns a 500 to the client" do @@ -435,18 +441,23 @@ describe Chef::ResourceReporter do @rest_client.should_receive(:post_rest). with("reports/nodes/spitfire/runs", {:action => :begin}). and_raise(@error) - @resource_reporter.node_load_completed(@node, :expanded_run_list, :config) end it "assumes the feature is not enabled" do + @resource_reporter.node_load_completed(@node, :expanded_run_list, :config) @resource_reporter.reporting_enabled?.should be_false end it "does not send a resource report to the server" do + @resource_reporter.node_load_completed(@node, :expanded_run_list, :config) @rest_client.should_not_receive(:post_rest) @resource_reporter.run_completed(@node) end + it "prints an error about the error" do + Chef::Log.should_receive(:info).with(/500/) + @resource_reporter.node_load_completed(@node, :expanded_run_list, :config) + end end context "when the server returns a 500 to the client and enable_reporting_url_fatals is true" do @@ -465,12 +476,12 @@ describe Chef::ResourceReporter do Chef::Config[:enable_reporting_url_fatals] = @enable_reporting_url_fatals end - it "fails the run" do + it "fails the run and prints an message about the error" do + Chef::Log.should_receive(:error).with(/500/) lambda { @resource_reporter.node_load_completed(@node, :expanded_run_list, :config) }.should raise_error(Net::HTTPServerException) end - end context "after creating the run history document" do |