1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
|
# frozen_string_literal: true
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 its 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, "Previous error(s) resulted in Puppet being unable to retrieve information from environment #{Puppet['environment']} source(s) #{url}'\nMost probable cause is file not found." unless status
File.binwrite(filepath, status.content)
end
# @private
def self.load_file_with_any_terminus(url)
termini_to_try = %i[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, Puppet::HTTP::RouteError
# rescue any network error
end
return content if content
end
end
nil
end
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;/?:@&=+$,\[\]%]}.freeze
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])
uri = URI("#{options[:proxy_type]}://#{options[:proxy_server]}") unless uri.scheme
@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.negative?
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
def initialize(url, options)
require 'net/ftp'
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
|