+++ /dev/null
-module PuppetX
- module Bodeco
- module Util
- def self.download(url, filepath, options = {})
- uri = URI(url)
- @connection = PuppetX::Bodeco.const_get(uri.scheme.upcase).new("#{uri.scheme}://#{uri.host}:#{uri.port}", options)
- @connection.download(uri, filepath)
- end
-
- def self.content(url, options = {})
- uri = URI(url)
- @connection = PuppetX::Bodeco.const_get(uri.scheme.upcase).new("#{uri.scheme}://#{uri.host}:#{uri.port}", options)
- @connection.content(uri)
- end
-
- #
- # This allows you to use a puppet syntax for a file and return it's content.
- #
- # @example
- # puppet_download 'puppet:///modules/my_module_name/my_file.dat
- #
- # @param [String] url this is the puppet url of the file to be fetched
- # @param [String] filepath this is path of the file to create
- #
- # @raise [ArgumentError] when the file doesn't exist
- #
- def self.puppet_download(url, filepath)
- # Somehow there is no consistent way to determine what terminus to use. So we switch to a
- # trial and error method. First we start withe the default. And if it doesn't work, we try the
- # other ones
- status = load_file_with_any_terminus(url)
- raise ArgumentError, "Could not retrieve information from environment #{Puppet['environment']} source(s) #{url}'" unless status
- File.open(filepath, 'w') { |file| file.write(status.content) }
- end
-
- # @private
- # rubocop:disable HandleExceptions
- def self.load_file_with_any_terminus(url)
- termini_to_try = [:file_server, :rest]
- termini_to_try.each do |terminus|
- with_terminus(terminus) do
- begin
- content = Puppet::FileServing::Content.indirection.find(url)
- rescue SocketError, Timeout::Error, Errno::ECONNREFUSED, Errno::EHOSTDOWN, Errno::EHOSTUNREACH, Errno::ETIMEDOUT
- # rescue any network error
- end
- return content if content
- end
- end
- nil
- end
- # rubocop:enable HandleExceptions
-
- def self.with_terminus(terminus)
- old_terminus = Puppet[:default_file_terminus]
- Puppet[:default_file_terminus] = terminus
- value = yield
- Puppet[:default_file_terminus] = old_terminus
- value
- end
- end
- class HTTP
- require 'net/http'
-
- FOLLOW_LIMIT = 5
- URI_UNSAFE = %r{[^\-_.!~*'()a-zA-Z\d;\/?:@&=+$,\[\]%]}
-
- def initialize(_url, options)
- @username = options[:username]
- @password = options[:password]
- @cookie = options[:cookie]
- @insecure = options[:insecure]
-
- if options[:proxy_server]
- uri = URI(options[:proxy_server])
- unless uri.scheme
- uri = URI("#{options[:proxy_type]}://#{options[:proxy_server]}")
- end
- @proxy_addr = uri.hostname
- @proxy_port = uri.port
- end
-
- ENV['SSL_CERT_FILE'] = File.expand_path(File.join(__FILE__, '..', 'cacert.pem')) if Facter.value(:osfamily) == 'windows' && !ENV.key?('SSL_CERT_FILE')
- end
-
- def generate_request(uri)
- header = @cookie && { 'Cookie' => @cookie }
-
- request = Net::HTTP::Get.new(uri.request_uri, header)
- request.basic_auth(@username, @password) if @username && @password
- request
- end
-
- def follow_redirect(uri, option = { limit: FOLLOW_LIMIT }, &block)
- http_opts = if uri.scheme == 'https'
- { use_ssl: true,
- verify_mode: (@insecure ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER) }
- else
- { use_ssl: false }
- end
- Net::HTTP.start(uri.host, uri.port, @proxy_addr, @proxy_port, http_opts) do |http|
- http.request(generate_request(uri)) do |response|
- case response
- when Net::HTTPSuccess
- yield response
- when Net::HTTPRedirection
- limit = option[:limit] - 1
- raise Puppet::Error, "Redirect limit exceeded, last url: #{uri}" if limit < 0
- location = safe_escape(response['location'])
- new_uri = URI(location)
- new_uri = URI(uri.to_s + location) if new_uri.relative?
- follow_redirect(new_uri, limit: limit, &block)
- else
- raise Puppet::Error, "HTTP Error Code #{response.code}\nURL: #{uri}\nContent:\n#{response.body}"
- end
- end
- end
- end
-
- def download(uri, file_path, option = { limit: FOLLOW_LIMIT })
- follow_redirect(uri, option) do |response|
- File.open file_path, 'wb' do |io|
- response.read_body do |chunk|
- io.write chunk
- end
- end
- end
- end
-
- def content(uri, option = { limit: FOLLOW_LIMIT })
- follow_redirect(uri, option) do |response|
- return response.body
- end
- end
-
- def safe_escape(uri)
- uri.to_s.gsub(URI_UNSAFE) do |match|
- '%' + match.unpack('H2' * match.bytesize).join('%').upcase
- end
- end
- end
-
- class HTTPS < HTTP
- end
-
- class FTP
- require 'net/ftp'
-
- def initialize(url, options)
- uri = URI(url)
- username = options[:username]
- password = options[:password]
- proxy_server = options[:proxy_server]
- proxy_type = options[:proxy_type]
-
- ENV["#{proxy_type}_proxy"] = proxy_server
-
- @ftp = Net::FTP.new
- @ftp.connect(uri.host, uri.port)
- if username
- @ftp.login(username, password)
- else
- @ftp.login
- end
- end
-
- def download(uri, file_path)
- @ftp.getbinaryfile(uri.path, file_path)
- end
- end
-
- class FILE
- def initialize(_url, _options) end
-
- def download(uri, file_path)
- FileUtils.copy(uri.path, file_path)
- end
- end
- end
-end