Class: Cloudkeeper::Managers::ImageManager

Inherits:
Object
  • Object
show all
Extended by:
Entities::ImageFormats::Ova
Defined in:
lib/cloudkeeper/managers/image_manager.rb

Constant Summary collapse

FORMATS =
{
  qcow2: /qemu qcow image/i,
  ova: /posix tar archive/i,
  vmdk: /vmware4 disk image/i,
  raw: /boot sector/i,
  vdi: /virtual(box)? disk image/i
}.freeze

Constants included from Entities::ImageFormats::Ova

Entities::ImageFormats::Ova::ARCHIVE_MAX_FILES, Entities::ImageFormats::Ova::OVF_REGEX, Entities::ImageFormats::Ova::VMDK_REGEX

Class Method Summary collapse

Methods included from Entities::ImageFormats::Ova

archive_files, check_file_count!, ova?, ova_structure?

Class Method Details

.check_file!(file) ⇒ Object



31
32
33
34
# File 'lib/cloudkeeper/managers/image_manager.rb', line 31

def check_file!(file)
  raise Cloudkeeper::Errors::NoSuchFileError, "No such file #{file.inspect}" unless File.exist?(file)
  raise Cloudkeeper::Errors::PermissionDeniedError, "Cannot read file #{file.inspect}" unless File.readable?(file)
end

.check_image_checksum!(filename, checksum) ⇒ Object



66
67
68
69
70
# File 'lib/cloudkeeper/managers/image_manager.rb', line 66

def check_image_checksum!(filename, checksum)
  computed = Digest::SHA512.file(filename).hexdigest
  raise Cloudkeeper::Errors::Image::ChecksumError, "Checksum mismatch, expecting #{checksum.inspect} got #{computed.inspect}" \
    unless checksum == computed
end

.connection_options(uri) ⇒ Object



92
93
94
95
96
# File 'lib/cloudkeeper/managers/image_manager.rb', line 92

def connection_options(uri)
  use_ssl = uri.scheme == 'https'
  ca_path = Cloudkeeper::Settings[:'ca-dir'] if Cloudkeeper::Settings[:'ca-dir']
  { use_ssl: use_ssl, ca_path: ca_path }
end

.file_description(file) ⇒ Object



27
28
29
# File 'lib/cloudkeeper/managers/image_manager.rb', line 27

def file_description(file)
  Cloudkeeper::CommandExecutioner.execute('file', '-b', file)
end

.format(file) ⇒ Object



18
19
20
21
22
23
24
25
# File 'lib/cloudkeeper/managers/image_manager.rb', line 18

def format(file)
  check_file!(file)
  recognize_format(file)
rescue Cloudkeeper::Errors::CommandExecutionError, Cloudkeeper::Errors::NoSuchFileError,
       Cloudkeeper::Errors::PermissionDeniedError, Cloudkeeper::Errors::Image::Format::NoFormatRecognizedError,
       Cloudkeeper::Errors::Image::Format::Ova::OvaFormatError => ex
  raise Cloudkeeper::Errors::Image::Format::RecognitionError, ex, "Cannot recognize image format for file #{file.inspect}"
end

.generate_filename(uri) ⇒ Object



98
99
100
# File 'lib/cloudkeeper/managers/image_manager.rb', line 98

def generate_filename(uri)
  File.join(Cloudkeeper::Settings[:'image-dir'], Cloudkeeper::Utils::Filename.sanitize(File.basename(uri.path)))
end

.recognize_format(file) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/cloudkeeper/managers/image_manager.rb', line 36

def recognize_format(file)
  file_format_string = file_description(file)
  FORMATS.each do |format, regex|
    next unless regex =~ file_format_string

    format_test_method = "#{format}?".to_sym
    additional_test_result = respond_to?(format_test_method) ? send(format_test_method, file) : true

    return format if additional_test_result
  end

  raise Cloudkeeper::Errors::Image::Format::NoFormatRecognizedError, "No image format recognized for file #{file.inspect}"
end

.retrieve_image(uri, filename) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/cloudkeeper/managers/image_manager.rb', line 72

def retrieve_image(uri, filename)
  Net::HTTP.start(uri.host, uri.port, connection_options(uri)) do |http|
    request = Net::HTTP::Get.new(uri)

    http.request(request) do |response|
      if response.is_a? Net::HTTPRedirection
        retrieve_image URI.join(uri, response.header['location']), filename
        break
      end

      response.value
      File.open(filename, 'w') { |file| response.read_body { |chunk| file.write(chunk) } }
    end
  end
rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, Errno::ECONNREFUSED, Net::HTTPBadResponse,
       Net::HTTPHeaderSyntaxError, EOFError, Net::HTTPServerException, Net::HTTPRetriableError,
       OpenSSL::SSL::SSLError => ex
  raise Cloudkeeper::Errors::NetworkConnectionError, ex
end

.secure_download_image(url, checksum) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/cloudkeeper/managers/image_manager.rb', line 50

def secure_download_image(url, checksum)
  logger.debug "Downloading image from #{url.inspect}"
  Cloudkeeper::Utils::URL.check!(url)

  uri = URI.parse url
  filename = generate_filename(uri)
  retrieve_image(uri, filename)
  check_image_checksum!(filename, checksum)

  Cloudkeeper::Entities::ImageFile.new filename, format(filename), Cloudkeeper::Utils::Checksum.compute(filename),
                                       File.size(filename)
rescue Cloudkeeper::Errors::InvalidURLError, Cloudkeeper::Errors::Image::Format::RecognitionError,
       Cloudkeeper::Errors::ArgumentError, Cloudkeeper::Errors::NetworkConnectionError, ::IOError => ex
  raise Cloudkeeper::Errors::Image::DownloadError, "Image #{url.inspect} download error: #{ex.message}"
end