summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel DeLeo <dan@opscode.com>2011-03-17 16:10:36 -0700
committerDaniel DeLeo <dan@opscode.com>2011-03-17 16:10:36 -0700
commit4fc9da10432e7e6a14bb2e9a89337ec22db99008 (patch)
treeebe53df92fe3ad3e2be7fcf79499413ab7ad95e9
parenta35ad6a7f3eb4b58d30661e477df60fff3505b8c (diff)
parent652fac0115ed524e5e30321a0835d283a0831922 (diff)
downloadchef-4fc9da10432e7e6a14bb2e9a89337ec22db99008.tar.gz
Merge branch 'CHEF-1852'
-rw-r--r--chef/lib/chef/exceptions.rb1
-rw-r--r--chef/lib/chef/provider/cookbook_file.rb41
-rw-r--r--chef/lib/chef/provider/file.rb31
-rw-r--r--chef/lib/chef/provider/remote_file.rb2
-rw-r--r--chef/lib/chef/runner.rb22
-rw-r--r--chef/spec/unit/lwrp_spec.rb10
-rw-r--r--chef/spec/unit/provider/cookbook_file_spec.rb9
-rw-r--r--chef/spec/unit/provider/file_spec.rb12
-rw-r--r--chef/spec/unit/provider/remote_file_spec.rb10
-rw-r--r--chef/spec/unit/resource/file_spec.rb5
10 files changed, 86 insertions, 57 deletions
diff --git a/chef/lib/chef/exceptions.rb b/chef/lib/chef/exceptions.rb
index 74de82d952..dd8a0d2543 100644
--- a/chef/lib/chef/exceptions.rb
+++ b/chef/lib/chef/exceptions.rb
@@ -74,5 +74,6 @@ class Chef
class InvalidEnvironmentRunListSpecification < ArgumentError; end
class InvalidDataBagItemID < ArgumentError; end
class InvalidDataBagName < ArgumentError; end
+ class EnclosingDirectoryDoesNotExist < ArgumentError; end
end
end
diff --git a/chef/lib/chef/provider/cookbook_file.rb b/chef/lib/chef/provider/cookbook_file.rb
index b831c9cbb4..082d2140f9 100644
--- a/chef/lib/chef/provider/cookbook_file.rb
+++ b/chef/lib/chef/provider/cookbook_file.rb
@@ -23,7 +23,7 @@ require 'tempfile'
class Chef
class Provider
class CookbookFile < Chef::Provider::File
-
+
def load_current_resource
@current_resource = Chef::Resource::CookbookFile.new(@new_resource.name)
@new_resource.path.gsub!(/\\/, "/") # for Windows
@@ -33,21 +33,22 @@ class Chef
def action_create
- if file_cache_location && content_stale?
- Chef::Log.debug("content of file #{@new_resource.path} requires update")
- backup_new_resource
- Tempfile.open(::File.basename(@new_resource.name)) do |staging_file|
- Chef::Log.debug("staging #{file_cache_location} to #{staging_file.path}")
- staging_file.close
- stage_file_to_tmpdir(staging_file.path)
- FileUtils.mv(staging_file.path, @new_resource.path)
- end
- @new_resource.updated_by_last_action(true)
- else
- set_all_access_controls(@new_resource.path)
- end
- @new_resource.updated_by_last_action?
- end
+ assert_enclosing_directory_exists!
+ if file_cache_location && content_stale?
+ Chef::Log.debug("content of file #{@new_resource.path} requires update")
+ backup_new_resource
+ Tempfile.open(::File.basename(@new_resource.name)) do |staging_file|
+ Chef::Log.debug("staging #{file_cache_location} to #{staging_file.path}")
+ staging_file.close
+ stage_file_to_tmpdir(staging_file.path)
+ FileUtils.mv(staging_file.path, @new_resource.path)
+ end
+ @new_resource.updated_by_last_action(true)
+ else
+ set_all_access_controls(@new_resource.path)
+ end
+ @new_resource.updated_by_last_action?
+ end
def action_create_if_missing
if ::File.exists?(@new_resource.path)
@@ -56,21 +57,21 @@ class Chef
action_create
end
end
-
+
def file_cache_location
@file_cache_location ||= begin
cookbook = run_context.cookbook_collection[resource_cookbook]
cookbook.preferred_filename_on_disk_location(node, :files, @new_resource.source, @new_resource.path)
end
end
-
- # Determine the cookbook to get the file from. If new resource sets an
+
+ # Determine the cookbook to get the file from. If new resource sets an
# explicit cookbook, use it, otherwise fall back to the implicit cookbook
# i.e., the cookbook the resource was declared in.
def resource_cookbook
@new_resource.cookbook || @new_resource.cookbook_name
end
-
+
# Copy the file from the cookbook cache to a temporary location and then
# set its file access control settings.
def stage_file_to_tmpdir(staging_file_location)
diff --git a/chef/lib/chef/provider/file.rb b/chef/lib/chef/provider/file.rb
index f8f01e53fc..b516cc47c8 100644
--- a/chef/lib/chef/provider/file.rb
+++ b/chef/lib/chef/provider/file.rb
@@ -75,12 +75,12 @@ class Chef
return false if @new_resource.owner.nil?
@set_user_id = case @new_resource.owner
- when /^\d+$/, Integer
- @new_resource.owner.to_i
- else
- # This raises an ArgumentError if you can't find the user
- Etc.getpwnam(@new_resource.owner).uid
- end
+ when /^\d+$/, Integer
+ @new_resource.owner.to_i
+ else
+ # This raises an ArgumentError if you can't find the user
+ Etc.getpwnam(@new_resource.owner).uid
+ end
@set_user_id == @current_resource.owner
end
@@ -100,11 +100,11 @@ class Chef
return false if @new_resource.group.nil?
@set_group_id = case @new_resource.group
- when /^\d+$/, Integer
- @new_resource.group.to_i
- else
- Etc.getgrnam(@new_resource.group).gid
- end
+ when /^\d+$/, Integer
+ @new_resource.group.to_i
+ else
+ Etc.getgrnam(@new_resource.group).gid
+ end
@set_group_id == @current_resource.group
end
@@ -137,6 +137,7 @@ class Chef
end
def action_create
+ assert_enclosing_directory_exists!
unless ::File.exists?(@new_resource.path)
Chef::Log.info("Creating #{@new_resource} at #{@new_resource.path}")
::File.open(@new_resource.path, "w+") {|f| f.write @new_resource.content }
@@ -205,6 +206,14 @@ class Chef
private
+ def assert_enclosing_directory_exists!
+ enclosing_dir = ::File.dirname(@new_resource.path)
+ unless ::File.directory?(enclosing_dir)
+ msg = "Cannot create a file at #{@new_resource.path} because the enclosing directory (#{enclosing_dir}) does not exist"
+ raise Chef::Exceptions::EnclosingDirectoryDoesNotExist, msg
+ end
+ end
+
def new_resource_content_checksum
@new_resource.content && Digest::SHA2.hexdigest(@new_resource.content)
end
diff --git a/chef/lib/chef/provider/remote_file.rb b/chef/lib/chef/provider/remote_file.rb
index f4eaf4dbbb..e2c3cf58e2 100644
--- a/chef/lib/chef/provider/remote_file.rb
+++ b/chef/lib/chef/provider/remote_file.rb
@@ -35,6 +35,8 @@ class Chef
end
def action_create
+ assert_enclosing_directory_exists!
+
Chef::Log.debug("Checking #{@new_resource} for changes")
if current_resource_matches_target_checksum?
diff --git a/chef/lib/chef/runner.rb b/chef/lib/chef/runner.rb
index 2f00e55364..7e94f40eca 100644
--- a/chef/lib/chef/runner.rb
+++ b/chef/lib/chef/runner.rb
@@ -8,9 +8,9 @@
# 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.
@@ -27,7 +27,7 @@ class Chef
# == Chef::Runner
# This class is responsible for executing the steps in a Chef run.
class Runner
-
+
attr_reader :run_context
attr_reader :delayed_actions
@@ -38,15 +38,7 @@ class Chef
@run_context = run_context
@delayed_actions = []
end
-
- def build_provider(resource)
- provider_class = Chef::Platform.find_provider_for_node(run_context.node, resource)
- Chef::Log.debug("#{resource} using #{provider_class.to_s}")
- provider = provider_class.new(resource, run_context)
- provider.load_current_resource
- provider
- end
-
+
# Determine the appropriate provider for the given resource, then
# execute it.
def run_action(resource, action)
@@ -71,7 +63,7 @@ class Chef
end
end
end
-
+
# Iterates over the +resource_collection+ in the +run_context+ calling
# +run_action+ for each resource in turn.
def converge
@@ -84,7 +76,7 @@ class Chef
run_context.resource_collection.execute_each_resource do |resource|
begin
Chef::Log.debug("Processing #{resource} on #{run_context.node.name}")
-
+
# Execute each of this resource's actions.
Array(resource.action).each {|action| run_action(resource, action)}
rescue => e
@@ -92,7 +84,7 @@ class Chef
raise e unless resource.ignore_failure
end
end
-
+
# Run all our :delayed actions
delayed_actions.each do |notification|
Chef::Log.info( "#{notification.notifying_resource} sending #{notification.action}"\
diff --git a/chef/spec/unit/lwrp_spec.rb b/chef/spec/unit/lwrp_spec.rb
index 738c8dac2a..05e1eb9c20 100644
--- a/chef/spec/unit/lwrp_spec.rb
+++ b/chef/spec/unit/lwrp_spec.rb
@@ -171,23 +171,23 @@ describe "LWRP" do
end
it "should properly handle a new_resource reference" do
- resource = Chef::Resource::LwrpFoo.new("morpheus")
+ resource = Chef::Resource::LwrpFoo.new("morpheus", @run_context)
resource.monkey("bob")
resource.provider(:lwrp_monkey_name_printer)
- provider = @runner.build_provider(resource)
+ provider = Chef::Platform.provider_for_resource(resource)
provider.action_twiddle_thumbs
provider.monkey_name.should == "my monkey's name is 'bob'"
end
it "should properly handle an embedded Resource accessing the enclosing Provider's scope" do
-
- resource = Chef::Resource::LwrpFoo.new("morpheus")
+ resource = Chef::Resource::LwrpFoo.new("morpheus", @run_context)
resource.monkey("bob")
resource.provider(:lwrp_embedded_resource_accesses_providers_scope)
- provider = @runner.build_provider(resource)
+ provider = Chef::Platform.provider_for_resource(resource)
+ #provider = @runner.build_provider(resource)
provider.action_twiddle_thumbs
provider.enclosed_resource.monkey.should == 'bob, the monkey'
diff --git a/chef/spec/unit/provider/cookbook_file_spec.rb b/chef/spec/unit/provider/cookbook_file_spec.rb
index 1c41a65ad9..a4ced07fba 100644
--- a/chef/spec/unit/provider/cookbook_file_spec.rb
+++ b/chef/spec/unit/provider/cookbook_file_spec.rb
@@ -63,6 +63,15 @@ EXPECTED
end
end
+ describe "when the enclosing directory of the target file location doesn't exist" do
+ before do
+ @new_resource.path("/tmp/no/such/intermediate/path/file.txt")
+ end
+
+ it "raises a specific error alerting the user to the problem" do
+ lambda {@provider.action_create}.should raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist)
+ end
+ end
describe "when the file doesn't yet exist" do
before do
@install_to = Dir.tmpdir + '/apache2_modconf.pl'
diff --git a/chef/spec/unit/provider/file_spec.rb b/chef/spec/unit/provider/file_spec.rb
index fac48e8657..26d2e50e67 100644
--- a/chef/spec/unit/provider/file_spec.rb
+++ b/chef/spec/unit/provider/file_spec.rb
@@ -25,7 +25,7 @@ describe Chef::Provider::File do
@node = Chef::Node.new
@node.name "latte"
@run_context = Chef::RunContext.new(@node, {})
-
+
@resource = Chef::Resource::File.new("seattle")
@resource.path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates", "seattle.txt")))
@provider = Chef::Provider::File.new(@resource, @run_context)
@@ -339,6 +339,16 @@ describe Chef::Provider::File do
@provider.backup
end
+ describe "when the enclosing directory does not exist" do
+ before do
+ @resource.path("/tmp/no-such-path/file.txt")
+ end
+
+ it "raises a specific error describing the problem" do
+ lambda {@provider.action_create}.should raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist)
+ end
+ end
+
describe "when creating a file if it's missing" do
before(:each) do
@resource.path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates", "seattle.txt")))
diff --git a/chef/spec/unit/provider/remote_file_spec.rb b/chef/spec/unit/provider/remote_file_spec.rb
index 75e5ca5ff9..f4b4ba7d2e 100644
--- a/chef/spec/unit/provider/remote_file_spec.rb
+++ b/chef/spec/unit/provider/remote_file_spec.rb
@@ -63,6 +63,16 @@ describe Chef::Provider::RemoteFile, "action_create" do
@resource.source("http://opscode.com/seattle.txt")
end
+ describe "and the target location's enclosing directory does not exist" do
+ before do
+ @resource.path("/tmp/this/path/does/not/exist/file.txt")
+ end
+
+ it "raises a specific error describing the problem" do
+ lambda {@provider.action_create}.should raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist)
+ end
+ end
+
describe "and the resource specifies a checksum" do
describe "and the existing file matches the checksum exactly" do
diff --git a/chef/spec/unit/resource/file_spec.rb b/chef/spec/unit/resource/file_spec.rb
index 7183369946..23a4fdecb2 100644
--- a/chef/spec/unit/resource/file_spec.rb
+++ b/chef/spec/unit/resource/file_spec.rb
@@ -24,11 +24,6 @@ describe Chef::Resource::File do
@resource = Chef::Resource::File.new("fakey_fakerton")
end
- it "should create a new Chef::Resource::File" do
- @resource.should be_a_kind_of(Chef::Resource)
- @resource.should be_a_kind_of(Chef::Resource::File)
- end
-
it "should have a name" do
@resource.name.should eql("fakey_fakerton")
end