Puppet Function: complyadm::download_image

Defined in:
lib/puppet/functions/complyadm/download_image.rb
Function type:
Ruby 4.x API

Summary

Download container image tarball from image_url

Overview

complyadm::download_image(String[1] $image_url, String[1] $dest_path)Any

Parameters:

  • image_url (String[1])

    URL pointing to the image to download

  • dest_path (String[1])

    Absolute path to the location where image tarballs will be stored on disk

Returns:

  • (Any)


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
# File 'lib/puppet/functions/complyadm/download_image.rb', line 5

Puppet::Functions.create_function(:'complyadm::download_image') do
  # @summary Download container image tarball from image_url
  # @param image_url URL pointing to the image to download
  # @param dest_path Absolute path to the location where image tarballs will be stored on disk
  dispatch :download_image do
    param 'String[1]', :image_url
    param 'String[1]', :dest_path
  end

  def download_image(image_url, dest_path)
    request_uri = URI(image_url)
    request_download(request_uri, dest_path)
  end

  def request_download(src_uri, dest_path)
    image_filename = File.basename(dest_path)

    Net::HTTP.start(src_uri.host, src_uri.port, use_ssl: true) do |http|
      request = Net::HTTP::Get.new src_uri

      out_message("Downloading '#{src_uri}' to '#{dest_path}'")
      http.request request do |response|
        case response
        when Net::HTTPSuccess then
          write_image_to_disk(response, dest_path)
        when Net::HTTPRedirection then
          max_redirects = 50
          redirects_followed = 0
          while redirects_followed < max_redirects
            redir_uri = redirect_uri(response, src_uri)

            Net::HTTP.start(redir_uri.host, redir_uri.port, use_ssl: true) do |redir_http|
              redirect_request = Net::HTTP::Get.new redir_uri
              out_message("Location for '#{image_filename}' has changed, following redirect to '#{redir_uri}'")

              redir_http.request redirect_request do |redirect_response|
                case redirect_response
                when Net::HTTPSuccess then
                  write_image_to_disk(redirect_response, dest_path)
                  break
                when Net::HTTPRedirection then
                  redirects_followed += 1
                  next
                when Net::HTTPNotFound then
                  raise "Could not find '#{image_filename}' to download from '#{redir_uri.host}'\n#{redirect_response.body}"
                else
                  raise "Problem following redirect to download '#{image_filename}' from '#{redir_uri.host}'\n#{redirect_response.body}"
                end
              end
            rescue Exception => e
              raise "Problem with HTTP request to follow redirect and download '#{image_filename}' from '#{redir_uri.host}': #{e}"
            end
          end
          raise "Exceeded maximum 50 redirects attempting to download image from '#{src_uri}'." if redirects_followed >= max_redirects
        when Net::HTTPNotFound then
          raise "Could not find '#{image_filename}' to download from '#{src_uri.host}'\n#{response.body}"
        else
          raise "Problem downloading #{image_filename} from '#{src_uri.host}'\n#{response.body}"
        end
      end
    rescue Exception => e
      raise "There was a problem with the HTTP request to download '#{image_filename}' from '#{src_uri.host}': #{e}"
    end
  end

  def write_image_to_disk(response, dest_path)
    dest_dir = File.dirname(dest_path)

    FileUtils.mkdir_p(dest_dir) unless File.exist?(dest_dir)
    File.open dest_path, 'w' do |file|
      response.read_body do |chunk|
        file.write chunk
      end
    end
  end

  def redirect_uri(response, uri)
    location = response['location']
    location_uri = URI.parse(location)
    URI(location_uri.relative? ? uri.to_s + location : uri)
  end

  def out_message(message)
    call_function('out::message', message)
  end
end