4 def self.download(url, filepath, options = {})
6 @connection = PuppetX::Bodeco.const_get(uri.scheme.upcase).new("#{uri.scheme}://#{uri.host}:#{uri.port}", options)
7 @connection.download(uri, filepath)
10 def self.content(url, options = {})
12 @connection = PuppetX::Bodeco.const_get(uri.scheme.upcase).new("#{uri.scheme}://#{uri.host}:#{uri.port}", options)
13 @connection.content(uri)
17 # This allows you to use a puppet syntax for a file and return it's content.
20 # puppet_download 'puppet:///modules/my_module_name/my_file.dat
22 # @param [String] url this is the puppet url of the file to be fetched
23 # @param [String] filepath this is path of the file to create
25 # @raise [ArgumentError] when the file doesn't exist
27 def self.puppet_download(url, filepath)
28 # Somehow there is no consistent way to determine what terminus to use. So we switch to a
29 # trial and error method. First we start withe the default. And if it doesn't work, we try the
31 status = load_file_with_any_terminus(url)
32 raise ArgumentError, "Could not retrieve information from environment #{Puppet['environment']} source(s) #{url}'" unless status
33 File.open(filepath, 'w') { |file| file.write(status.content) }
37 # rubocop:disable HandleExceptions
38 def self.load_file_with_any_terminus(url)
39 termini_to_try = [:file_server, :rest]
40 termini_to_try.each do |terminus|
41 with_terminus(terminus) do
43 content = Puppet::FileServing::Content.indirection.find(url)
44 rescue SocketError, Timeout::Error, Errno::ECONNREFUSED, Errno::EHOSTDOWN, Errno::EHOSTUNREACH, Errno::ETIMEDOUT
45 # rescue any network error
47 return content if content
52 # rubocop:enable HandleExceptions
54 def self.with_terminus(terminus)
55 old_terminus = Puppet[:default_file_terminus]
56 Puppet[:default_file_terminus] = terminus
58 Puppet[:default_file_terminus] = old_terminus
66 URI_UNSAFE = %r{[^\-_.!~*'()a-zA-Z\d;\/?:@&=+$,\[\]%]}
68 def initialize(_url, options)
69 @username = options[:username]
70 @password = options[:password]
71 @cookie = options[:cookie]
72 @insecure = options[:insecure]
74 if options[:proxy_server]
75 uri = URI(options[:proxy_server])
77 uri = URI("#{options[:proxy_type]}://#{options[:proxy_server]}")
79 @proxy_addr = uri.hostname
80 @proxy_port = uri.port
83 ENV['SSL_CERT_FILE'] = File.expand_path(File.join(__FILE__, '..', 'cacert.pem')) if Facter.value(:osfamily) == 'windows' && !ENV.key?('SSL_CERT_FILE')
86 def generate_request(uri)
87 header = @cookie && { 'Cookie' => @cookie }
89 request = Net::HTTP::Get.new(uri.request_uri, header)
90 request.basic_auth(@username, @password) if @username && @password
94 def follow_redirect(uri, option = { limit: FOLLOW_LIMIT }, &block)
95 http_opts = if uri.scheme == 'https'
97 verify_mode: (@insecure ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER) }
101 Net::HTTP.start(uri.host, uri.port, @proxy_addr, @proxy_port, http_opts) do |http|
102 http.request(generate_request(uri)) do |response|
104 when Net::HTTPSuccess
106 when Net::HTTPRedirection
107 limit = option[:limit] - 1
108 raise Puppet::Error, "Redirect limit exceeded, last url: #{uri}" if limit < 0
109 location = safe_escape(response['location'])
110 new_uri = URI(location)
111 new_uri = URI(uri.to_s + location) if new_uri.relative?
112 follow_redirect(new_uri, limit: limit, &block)
114 raise Puppet::Error, "HTTP Error Code #{response.code}\nURL: #{uri}\nContent:\n#{response.body}"
120 def download(uri, file_path, option = { limit: FOLLOW_LIMIT })
121 follow_redirect(uri, option) do |response|
122 File.open file_path, 'wb' do |io|
123 response.read_body do |chunk|
130 def content(uri, option = { limit: FOLLOW_LIMIT })
131 follow_redirect(uri, option) do |response|
137 uri.to_s.gsub(URI_UNSAFE) do |match|
138 '%' + match.unpack('H2' * match.bytesize).join('%').upcase
149 def initialize(url, options)
151 username = options[:username]
152 password = options[:password]
153 proxy_server = options[:proxy_server]
154 proxy_type = options[:proxy_type]
156 ENV["#{proxy_type}_proxy"] = proxy_server
159 @ftp.connect(uri.host, uri.port)
161 @ftp.login(username, password)
167 def download(uri, file_path)
168 @ftp.getbinaryfile(uri.path, file_path)
173 def initialize(_url, _options) end
175 def download(uri, file_path)
176 FileUtils.copy(uri.path, file_path)