summaryrefslogtreecommitdiff
path: root/lib/chef/provider/remote_file/content.rb
diff options
context:
space:
mode:
authorLamont Granquist <lamont@opscode.com>2013-03-20 15:13:05 -0700
committerLamont Granquist <lamont@opscode.com>2013-03-20 15:13:05 -0700
commit7655abea85be5731aa872489ee9561c69f7be0be (patch)
treea30da1e7a2c3a5d940d9fc3934d96f4d3b557971 /lib/chef/provider/remote_file/content.rb
parentde0452180a1464d4a74992e0f9a83733ff4d8da2 (diff)
downloadchef-7655abea85be5731aa872489ee9561c69f7be0be.tar.gz
locate objects closer to their primary concerns
Diffstat (limited to 'lib/chef/provider/remote_file/content.rb')
-rw-r--r--lib/chef/provider/remote_file/content.rb110
1 files changed, 110 insertions, 0 deletions
diff --git a/lib/chef/provider/remote_file/content.rb b/lib/chef/provider/remote_file/content.rb
new file mode 100644
index 0000000000..fbd7a6bb24
--- /dev/null
+++ b/lib/chef/provider/remote_file/content.rb
@@ -0,0 +1,110 @@
+#
+# Author:: Jesse Campbell (<hikeit@gmail.com>)
+# Author:: Lamont Granquist (<lamont@opscode.com>)
+# Copyright:: Copyright (c) 2013 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 'rest_client'
+require 'uri'
+require 'tempfile'
+require 'chef/provider/file_content_base'
+
+class Chef
+ class Provider
+ class RemoteFile
+ class Content < Chef::Provider::FileContentBase
+
+ attr_reader :raw_file_source
+
+ private
+
+ def file_for_provider
+ Chef::Log.debug("#{@new_resource} checking for changes")
+
+ if current_resource_matches_target_checksum?
+ Chef::Log.debug("#{@new_resource} checksum matches target checksum (#{@new_resource.checksum}) - not updating")
+ else
+ sources = @new_resource.source
+ raw_file, @raw_file_source = try_multiple_sources(sources)
+ end
+ raw_file
+ end
+
+ private
+
+ # Given an array of source uris, iterate through them until one does not fail
+ def try_multiple_sources(sources)
+ sources = sources.dup
+ source = sources.shift
+ begin
+ uri = URI.parse(source)
+ raw_file = grab_file_from_uri(uri)
+ rescue SocketError, Errno::ECONNREFUSED, Errno::ENOENT, Errno::EACCES, Timeout::Error, Net::HTTPFatalError, Net::FTPError => e
+ Chef::Log.warn("#{@new_resource} cannot be downloaded from #{source}: #{e.to_s}")
+ if source = sources.shift
+ Chef::Log.info("#{@new_resource} trying to download from another mirror")
+ retry
+ else
+ raise e
+ end
+ end
+ if uri.userinfo
+ uri.password = "********"
+ end
+ return raw_file, uri.to_s
+ end
+
+ # Given a source uri, return a Tempfile, or a File that acts like a Tempfile (close! method)
+ def grab_file_from_uri(uri)
+ if_modified_since = @new_resource.last_modified
+ if_none_match = @new_resource.etag
+ uri_dup = uri.dup
+ if uri_dup.userinfo
+ uri_dup.password = "********"
+ end
+ if uri_dup.to_s == @current_resource.source[0]
+ if_modified_since ||= @current_resource.last_modified
+ if_none_match ||= @current_resource.etag
+ end
+ if URI::HTTP === uri
+ #HTTP or HTTPS
+ raw_file, mtime, etag = Chef::Provider::RemoteFile::HTTP.fetch(uri, if_modified_since, if_none_match)
+ elsif URI::FTP === uri
+ #FTP
+ raw_file, mtime = Chef::Provider::RemoteFile::FTP.fetch(uri, @new_resource.ftp_active_mode, if_modified_since)
+ etag = nil
+ elsif uri.scheme == "file"
+ #local/network file
+ raw_file, mtime = Chef::Provider::RemoteFile::LocalFile.fetch(uri, if_modified_since)
+ etag = nil
+ else
+ raise ArgumentError, "Invalid uri. Only http(s), ftp, and file are currently supported"
+ end
+ unless raw_file.nil?
+ @new_resource.etag etag unless @new_resource.etag
+ @new_resource.last_modified mtime unless @new_resource.last_modified
+ end
+ return raw_file
+ end
+
+ def current_resource_matches_target_checksum?
+ @new_resource.checksum && @current_resource.checksum && @current_resource.checksum =~ /^#{Regexp.escape(@new_resource.checksum)}/
+ end
+
+ end
+ end
+ end
+end