X-Git-Url: https://git.adam-barratt.org.uk/?a=blobdiff_plain;f=3rdparty%2Fmodules%2Farchive%2Flib%2Fpuppet_x%2Fbodeco%2Futil.rb;fp=3rdparty%2Fmodules%2Farchive%2Flib%2Fpuppet_x%2Fbodeco%2Futil.rb;h=96ac6dfc7ebfcd62311dffbb67ef47247623d1f8;hb=ce70d6baf887ae03a2a6a7f5e73eb2e2c3dea208;hp=0000000000000000000000000000000000000000;hpb=0ba93256399fbad7ed8fabfa39c24dd47169dde3;p=mirror%2Fdsa-puppet.git diff --git a/3rdparty/modules/archive/lib/puppet_x/bodeco/util.rb b/3rdparty/modules/archive/lib/puppet_x/bodeco/util.rb new file mode 100644 index 000000000..96ac6dfc7 --- /dev/null +++ b/3rdparty/modules/archive/lib/puppet_x/bodeco/util.rb @@ -0,0 +1,180 @@ +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