class ManifestV20070829

Manifest Version 2007-08-29. Not backwards compatible

Manifest Version 2007-08-29. Not backwards compatible

Constants

VERSION
VERSION_STRING

Public Class Methods

new(xml = nil) click to toggle source
# File lib/ec2/amitools/manifestv20070829.rb, line 39
def initialize(xml = nil)
  if xml == nil
    @doc = REXML::Document.new
  else
    # Convert to string if necessary.
    xml = (xml.kind_of?(IO) ? xml.read : xml)
    @doc = REXML::Document.new(xml)
  end
end
version() click to toggle source

Expose the version

# File lib/ec2/amitools/manifestv20070829.rb, line 24
def self.version
  VERSION
end
version20070829?(xml) click to toggle source
# File lib/ec2/amitools/manifestv20070829.rb, line 200
def self::version20070829?(xml)
  doc = REXML::Document.new(xml)
  version = REXML::XPath.first(doc.root, 'version')
  return true if (version and version.text and version.text == VERSION_STRING)
  return (version and version.text and version.text == VERSION.to_s)
end

Public Instance Methods

ami_part_info_list() click to toggle source

Retrieve a list of AMI bundle parts info. Each element is a hash with the following elements:

  • 'digest'

  • 'filename'

  • 'index'

# File lib/ec2/amitools/manifestv20070829.rb, line 251
def ami_part_info_list
  parts = Array.new
  REXML::XPath.each(@doc.root,'image/parts/part') do |part|
    index = part.attribute('index').to_s.to_i
    filename = REXML::XPath.first(part, 'filename').text
    digest = REXML::XPath.first(part, 'digest').text
    parts << { 'digest'=>digest, 'filename'=>filename, 'index'=>index }
  end
  return parts
end
arch() click to toggle source

Return the (optional) architecture of the AMI.

# File lib/ec2/amitools/manifestv20070829.rb, line 280
def arch()
  return get_element_text('machine_configuration/architecture')
end
authenticate(cert) click to toggle source

Verify the signature

# File lib/ec2/amitools/manifestv20070829.rb, line 329
def authenticate(cert)
  machine_configuration_xml = XMLUtil.get_xml(@doc.to_s, 'machine_configuration') || ""
  image_xml = XMLUtil.get_xml(@doc.to_s, 'image')
  pubkey = Crypto::cert2pubkey(cert)
  Crypto::authenticate(machine_configuration_xml + image_xml, Format::hex2bin(signature), pubkey)
end
bundled_size() click to toggle source

Return the bundled size of the AMI.

# File lib/ec2/amitools/manifestv20070829.rb, line 285
def bundled_size()
  return get_element_text('image/bundled_size').to_i
end
bundler_name() click to toggle source

Return the bundler name.

# File lib/ec2/amitools/manifestv20070829.rb, line 290
def bundler_name()
  return get_element_text('bundler/name')
end
bundler_release() click to toggle source

Return the bundler release.

# File lib/ec2/amitools/manifestv20070829.rb, line 300
def bundler_release()
  return get_element_text('bundler/release')
end
bundler_version() click to toggle source

Return the bundler version.

# File lib/ec2/amitools/manifestv20070829.rb, line 295
def bundler_version()
  return get_element_text('bundler/version')
end
cipher_algorithm() click to toggle source

Get cipher algorithm used.

# File lib/ec2/amitools/manifestv20070829.rb, line 242
def cipher_algorithm()
  return REXML::XPath.first(@doc.root, 'image/ec2_encrypted_key/@algorithm').to_s
end
digest() click to toggle source

Return the AMI's digest hex encoded.

# File lib/ec2/amitools/manifestv20070829.rb, line 208
def digest()
  return get_element_text('image/digest')
end
digest_algorithm() click to toggle source

Get digest algorithm used.

# File lib/ec2/amitools/manifestv20070829.rb, line 237
def digest_algorithm()
  return REXML::XPath.first(@doc.root, 'image/digest/@algorithm').to_s
end
doc() click to toggle source

for debugging only

# File lib/ec2/amitools/manifestv20070829.rb, line 50
def doc
  @doc
end
ec2_encrypted_iv() click to toggle source

The ec2 encrypted initialization vector hex encoded.

# File lib/ec2/amitools/manifestv20070829.rb, line 227
def ec2_encrypted_iv()
  return get_element_text('image/ec2_encrypted_iv')
end
ec2_encrypted_key() click to toggle source

The ec2 encrypted key hex encoded.

# File lib/ec2/amitools/manifestv20070829.rb, line 217
def ec2_encrypted_key()
  return get_element_text('image/ec2_encrypted_key')
end
init( name, user, arch, reserved, parts, size, bundled_size, user_encrypted_key, ec2_encrypted_key, cipher_algorithm, user_encrypted_iv, ec2_encrypted_iv, digest, digest_algorithm, privkey_filename, bundler_name = nil, bundler_version = nil, bundler_release = nil) click to toggle source

Initialize the manifest with AMI information. Return true if the initialization was succesful. Raise an exception on error.

# File lib/ec2/amitools/manifestv20070829.rb, line 57
def init(
  name,
  user,                   # The user's account number.
  arch,                   # Target architecture for AMI.
  reserved,               # Reserved for future use; pass nil.
  parts,                  # A list of parts filenames and digest pairs.
  size,                   # The size of the AMI in bytes.
  bundled_size,           # The size of the bunled AMI in bytes.
  user_encrypted_key,     # Hex encoded.
  ec2_encrypted_key,      # Hex encoded.
  cipher_algorithm,       # The cipher algorithm used to encrypted the AMI.
  user_encrypted_iv,      # Hex encoded.
  ec2_encrypted_iv,       # Hex encoded.
  digest,                 # Hex encoded.
  digest_algorithm,       # The digest algorithm.
  privkey_filename,       # The user's private key filename.
  bundler_name = nil,
  bundler_version = nil,
  bundler_release = nil)

  # Check reserved parameters are nil
  raise ArgumentError.new("reserved parameters not nil") unless reserved.nil?

  # Check non-String parameter types.
  raise ArgumentError.new("parts parameter type invalid") unless parts.is_a? Array
      
  # XML document.
  @doc = REXML::Document.new
  @doc << REXML::XMLDecl.new

  # manifest - the root element.
  manifest = REXML::Element.new('manifest')

  @doc.add_element(manifest)
  
  # version - indicate the manifest version.
  version = REXML::Element.new('version')
  version.text = VERSION
  manifest.add_element(version)
  
  # bundler information
  if bundler_name or bundler_version or bundler_release
    bundler_element = REXML::Element.new('bundler')
    manifest.add_element(bundler_element)
    
    [['name', bundler_name ], 
     ['version', bundler_version ],
     ['release', bundler_release ]].each do |element_name, text|
      if element_name
        element = REXML::Element.new(element_name)
        element.text = text
        bundler_element.add_element(element)
      end
    end 
  end
  
  # machine_configuration - the target hardware description of the AMI.
  machine_configuration = REXML::Element.new('machine_configuration')
  manifest.add_element(machine_configuration)

  # image - the image element.
  image = REXML::Element.new('image')
  name_element = REXML::Element.new('name')
  name_element.text = name
  image.add_element(name_element)
  manifest.add_element(image)
  
  # user - the user's AWS access key ID.
  user_element = REXML::Element.new('user')
  user_element.text = user
  image.add_element(user_element)

  # m_c arch - the target hardware architecture
  if arch
    arch_element = REXML::Element.new('architecture')
    arch_element.text = arch
    machine_configuration.add_element(arch_element)
  end

  # digest - the digest of the AMI.
  digest_element = REXML::Element.new('digest')
  digest_element.add_attribute('algorithm', digest_algorithm)
  digest_element.add_text(digest)
  image.add_element(digest_element)
  
  # size - the size of the uncompressed AMI.
  size_element = REXML::Element.new('size')
  size_element.text = size.to_s
  image.add_element(size_element)
  
  # bundled size - the size of the bundled AMI.
  bundled_size_element = REXML::Element.new('bundled_size')
  bundled_size_element.text = bundled_size.to_s
  image.add_element(bundled_size_element)
  
  # ec2 encrypted key element.
  ec2_encrypted_key_element = REXML::Element.new('ec2_encrypted_key')
  ec2_encrypted_key_element.add_attribute('algorithm', cipher_algorithm)
  ec2_encrypted_key_element.add_text(ec2_encrypted_key)
  image.add_element(ec2_encrypted_key_element)
  
  # user encrypted key element.
  user_encrypted_key_element = REXML::Element.new('user_encrypted_key')
  user_encrypted_key_element.add_attribute('algorithm', cipher_algorithm)
  user_encrypted_key_element.add_text(user_encrypted_key)
  image.add_element(user_encrypted_key_element)
  
  # ec2 encrypted iv element.
  ec2_encrypted_iv_element = REXML::Element.new('ec2_encrypted_iv')
  ec2_encrypted_iv_element.add_text(ec2_encrypted_iv)
  image.add_element(ec2_encrypted_iv_element)
  
  # user encrypted iv element.
  user_encrypted_iv_element = REXML::Element.new('user_encrypted_iv')
  user_encrypted_iv_element.add_text(user_encrypted_iv)
  image.add_element(user_encrypted_iv_element)
  
  # parts - list of the image parts.
  parts_element = REXML::Element.new('parts')
  parts_element.add_attributes({'count' => parts.size.to_s})
  index=0
  parts.each do |part|
    # Add image part element for each image part.
    part_element = REXML::Element.new('part')
    part_element.add_attribute('index', index.to_s)
    filename = REXML::Element.new('filename')
    filename.add_text(part[0])
    part_element.add_element(filename)
    digest = REXML::Element.new('digest')
    digest.add_attribute('algorithm', digest_algorithm)
    digest.add_text(Format::bin2hex(part[1]))
    part_element.add_element(digest)
    parts_element.add_element(part_element)
    index+=1
  end
  image.add_element(parts_element)

  # Sign the manifest.
  sign(privkey_filename)
  
  return true
end
name() click to toggle source
# File lib/ec2/amitools/manifestv20070829.rb, line 212
def name()
  return get_element_text('image/name')
end
parts() click to toggle source

A list of PartInformation instances representing the AMI parts.

# File lib/ec2/amitools/manifestv20070829.rb, line 263
def parts()
  parts = []
  REXML::XPath.each(@doc.root,'image/parts/part') do |part|
    index = part.attribute('index').to_s.to_i
    filename = REXML::XPath.first(part, 'filename').text
    digest = Format::hex2bin(REXML::XPath.first(part, 'digest').text)
    parts[index] = PartInformation.new(filename, digest)
  end
  return parts
end
sign(privkey_filename) click to toggle source

Sign the manifest. If it is already signed, the signature and certificate will be replaced

# File lib/ec2/amitools/manifestv20070829.rb, line 306
def sign(privkey_filename)
  unless privkey_filename.kind_of? String and File::exist?(privkey_filename)
    raise ArgumentError.new("privkey_filename parameter invalid")
  end
  
  # Get the XML for <machine_configuration> and <image> elements and sign them.
  machine_configuration_xml = XMLUtil.get_xml(@doc.to_s, 'machine_configuration') || ""
  image_xml = XMLUtil.get_xml(@doc.to_s, 'image')
  sig = Crypto::sign(machine_configuration_xml + image_xml, privkey_filename)
       
  # Create the signature and certificate elements.
  signature = REXML::Element.new('signature')
  signature.add_text(Format::bin2hex(sig))
  @doc.root.delete_element('signature')
  @doc.root.add_element(signature)
end
signature() click to toggle source

Return the signature

# File lib/ec2/amitools/manifestv20070829.rb, line 324
def signature
  get_element_text('signature')
end
size() click to toggle source

Return the size of the AMI.

# File lib/ec2/amitools/manifestv20070829.rb, line 275
def size()
  return get_element_text('image/size').to_i()
end
to_s() click to toggle source

Return the manifest as an XML string.

# File lib/ec2/amitools/manifestv20070829.rb, line 337
def to_s()
  return @doc.to_s
end
user() click to toggle source
# File lib/ec2/amitools/manifestv20070829.rb, line 341
def user()
  return get_element_text('image/user')
end
user_encrypted_iv() click to toggle source

The user encrypted initialization vector hex encoded.

# File lib/ec2/amitools/manifestv20070829.rb, line 232
def user_encrypted_iv()
  return get_element_text('image/user_encrypted_iv')
end
user_encrypted_key() click to toggle source

The user encrypted key hex encoded.

# File lib/ec2/amitools/manifestv20070829.rb, line 222
def user_encrypted_key()
  return get_element_text('image/user_encrypted_key')
end
version() click to toggle source
# File lib/ec2/amitools/manifestv20070829.rb, line 345
def version()
  return get_element_text('version').to_i
end

Private Instance Methods

get_element_text(xpath) click to toggle source
# File lib/ec2/amitools/manifestv20070829.rb, line 351
def get_element_text(xpath)
  element = REXML::XPath.first(@doc.root, xpath)
  unless element
    raise "invalid AMI manifest, #{xpath} element not present"
  end
  unless element.text
    raise "invalid AMI manifest, #{xpath} element empty"
  end
  return element.text
end