Permalink
Browse files

Merge branch 'CHEF-3375'

  • Loading branch information...
2 parents 42ffed6 + 7f00bf5 commit ea8fe65e1fa4d7c9e843ed36340d7d1e9a1b5eaf @btm btm committed Oct 4, 2012
@@ -37,8 +37,20 @@ def action_create
if current_resource_matches_target_checksum?
Chef::Log.debug("#{@new_resource} checksum matches target checksum (#{@new_resource.checksum}) - not updating")
else
- rest = Chef::REST.new(@new_resource.source, nil, nil, http_client_opts)
- raw_file = rest.streaming_request(rest.create_url(@new_resource.source), {})
+ sources = @new_resource.source
+ source = sources.shift
+ begin
+ rest = Chef::REST.new(source, nil, nil, http_client_opts(source))
+ raw_file = rest.streaming_request(rest.create_url(source), {})
+ rescue SocketError, Errno::ECONNREFUSED, Timeout::Error, Net::HTTPFatalError => e
+ Chef::Log.debug("#{@new_resource} cannot be downloaded from #{source}")
+ if source = sources.shift
+ Chef::Log.debug("#{@new_resource} trying to download from another mirror")
+ retry
+ else
+ raise e
+ end
+ end
if matches_current_checksum?(raw_file)
Chef::Log.debug "#{@new_resource} target and source checksums are the same - not updating"
else
@@ -97,7 +109,7 @@ def source_file(source, current_checksum, &block)
end
end
- def http_client_opts
+ def http_client_opts(source)
opts={}
# CHEF-3140
# 1. If it's already compressed, trying to compress it more will
@@ -107,7 +119,7 @@ def http_client_opts
# which tricks Chef::REST into decompressing the response body. In this
# case you'd end up with a tar archive (no gzip) named, e.g., foo.tgz,
# which is not what you wanted.
- if @new_resource.path =~ /gz$/ or @new_resource.source =~ /gz$/
+ if @new_resource.path =~ /gz$/ or source =~ /gz$/
opts[:disable_gzip] = true
end
opts
@@ -36,14 +36,14 @@ def initialize(name, run_context=nil)
@provider = Chef::Provider::RemoteFile
end
- def source(args=nil)
- validate_source(args) unless args.nil?
-
- set_or_return(
- :source,
- args,
- :kind_of => String
- )
+ def source(*args)
+ if not args.empty?
+ args = Array(args).flatten
+ validate_source(args)
+ @source = args
+ elsif self.instance_variable_defined?(:@source) == true
+ @source
+ end
end
def checksum(args=nil)
@@ -61,14 +61,17 @@ def after_created
private
def validate_source(source)
- unless absolute_uri?(source)
- raise Exceptions::InvalidRemoteFileURI,
- "'#{source}' is not a valid `source` parameter for #{resource_name}. `source` must be an absolute URI"
+ raise ArgumentError, "#{resource_name} has an empty source" if source.empty?
+ source.each do |src|
+ unless absolute_uri?(src)
+ raise Exceptions::InvalidRemoteFileURI,
+ "#{src.inspect} is not a valid `source` parameter for #{resource_name}. `source` must be an absolute URI or an array of URIs."
+ end
end
end
def absolute_uri?(source)
- URI.parse(source).absolute?
+ source.kind_of?(String) and URI.parse(source).absolute?
rescue URI::InvalidURIError
false
end
@@ -79,6 +79,42 @@
end
end
+ shared_examples_for "source specified with multiple URIs" do
+ it "should try to download the next URI when the first one fails" do
+ @rest.should_receive(:streaming_request).with("http://foo", {}).once.and_raise(SocketError)
+ @rest.should_receive(:streaming_request).with("http://bar", {}).once.and_return(@tempfile)
+ @provider.run_action(:create)
+ end
+
+ it "should raise an exception when all the URIs fail" do
+ @rest.should_receive(:streaming_request).with("http://foo", {}).once.and_raise(SocketError)
+ @rest.should_receive(:streaming_request).with("http://bar", {}).once.and_raise(SocketError)
+ lambda { @provider.run_action(:create) }.should raise_error(SocketError)
+ end
+
+ it "should download from only one URI when the first one works" do
+ @rest.should_receive(:streaming_request).once.and_return(@tempfile)
+ @provider.run_action(:create)
+ end
+
+ end
+
+ describe "and the source specifies multiple URIs using multiple arguments" do
+ it_should_behave_like "source specified with multiple URIs"
+
+ before(:each) do
+ @resource.source("http://foo", "http://bar")
+ end
+ end
+
+ describe "and the source specifies multiple URIs using an array" do
+ it_should_behave_like "source specified with multiple URIs"
+
+ before(:each) do
+ @resource.source([ "http://foo", "http://bar" ])
+ end
+ end
+
describe "and the resource specifies a checksum" do
describe "and the existing file matches the checksum exactly" do
@@ -46,13 +46,27 @@
it "should accept a URI for the remote file source" do
@resource.source "http://opscode.com/"
- @resource.source.should eql("http://opscode.com/")
+ @resource.source.should eql([ "http://opscode.com/" ])
+ end
+
+ it "should accept an array of URIs for the remote file source" do
+ @resource.source([ "http://opscode.com/", "http://puppetlabs.com/" ])
+ @resource.source.should eql([ "http://opscode.com/", "http://puppetlabs.com/" ])
+ end
+
+ it "should accept an multiple URIs as arguments for the remote file source" do
+ @resource.source("http://opscode.com/", "http://puppetlabs.com/")
+ @resource.source.should eql([ "http://opscode.com/", "http://puppetlabs.com/" ])
end
it "does not accept a non-URI as the source" do
lambda { @resource.source("not-a-uri") }.should raise_error(Chef::Exceptions::InvalidRemoteFileURI)
end
+ it "should raise and exception when source is an empty array" do
+ lambda { @resource.source([]) }.should raise_error(ArgumentError)
+ end
+
end
describe "checksum" do

0 comments on commit ea8fe65

Please sign in to comment.