Class: ManifestV20071010
- Inherits:
-
Object
- Object
- ManifestV20071010
- Defined in:
- lib/ec2/amitools/manifestv20071010.rb
Overview
Manifest Version 2007-10-10. Not backwards compatible
Defined Under Namespace
Classes: PartInformation
Constant Summary collapse
- VERSION_STRING =
'2007-10-10'- VERSION =
VERSION_STRING.gsub('-','').to_i
- IMAGE_TYPE_KERNEL =
"kernel"
Class Method Summary collapse
-
.version ⇒ Object
Expose the version.
- .version20071010?(xml) ⇒ Boolean
Instance Method Summary collapse
-
#ami_part_info_list ⇒ Object
Retrieve a list of AMI bundle parts info.
-
#ancestor_ami_ids ⇒ Object
Get the manifest’s ancestry.
-
#arch ⇒ Object
Return the (optional) architecture of the AMI.
-
#authenticate(cert) ⇒ Object
Verify the signature.
-
#block_device_mapping ⇒ Object
Get the block device mapping as a map.
-
#bundled_size ⇒ Object
Return the bundled size of the AMI.
-
#bundler_name ⇒ Object
Return the bundler name.
-
#bundler_release ⇒ Object
Return the bundler release.
-
#bundler_version ⇒ Object
Return the bundler version.
-
#cipher_algorithm ⇒ Object
Get cipher algorithm used.
-
#digest ⇒ Object
Return the AMI’s digest hex encoded.
-
#digest_algorithm ⇒ Object
Get digest algorithm used.
-
#doc ⇒ Object
for debugging only.
-
#ec2_encrypted_iv ⇒ Object
The ec2 encrypted initialization vector hex encoded.
-
#ec2_encrypted_key ⇒ Object
The ec2 encrypted key hex encoded.
- #image_type ⇒ Object
-
#init(args) ⇒ Object
Initialize the manifest with AMI information.
-
#initialize(xml = nil) ⇒ ManifestV20071010
constructor
A new instance of ManifestV20071010.
-
#kernel_id ⇒ Object
Get the default kernel_id.
-
#kernel_name ⇒ Object
Get the kernel_name.
- #mandatory_argument(arg, args) ⇒ Object
- #name ⇒ Object
- #optional_argument(arg, args) ⇒ Object
-
#parts ⇒ Object
A list of PartInformation instances representing the AMI parts.
-
#product_codes ⇒ Object
Get the default product codes.
-
#ramdisk_id ⇒ Object
Get the default ramdisk id.
-
#sign(privkey_filename) ⇒ Object
Sign the manifest.
-
#signature ⇒ Object
Return the signature.
-
#size ⇒ Object
Return the size of the AMI.
-
#to_s ⇒ Object
Return the manifest as an XML string.
- #user ⇒ Object
-
#user_encrypted_iv ⇒ Object
The user encrypted initialization vector hex encoded.
-
#user_encrypted_key ⇒ Object
The user encrypted key hex encoded.
- #version ⇒ Object
Constructor Details
#initialize(xml = nil) ⇒ ManifestV20071010
Returns a new instance of ManifestV20071010.
40 41 42 43 44 45 46 47 48 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 40 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 |
Class Method Details
.version ⇒ Object
Expose the version
25 26 27 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 25 def self.version VERSION end |
.version20071010?(xml) ⇒ Boolean
192 193 194 195 196 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 192 def self::version20071010?(xml) doc = REXML::Document.new(xml) version = REXML::XPath.first(doc.root, 'version') return (version and version.text and version.text == VERSION_STRING) end |
Instance Method Details
#ami_part_info_list ⇒ Object
Retrieve a list of AMI bundle parts info. Each element is a hash with the following elements:
-
‘digest’
-
‘filename’
-
‘index’
275 276 277 278 279 280 281 282 283 284 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 275 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 |
#ancestor_ami_ids ⇒ Object
Get the manifest’s ancestry
223 224 225 226 227 228 229 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 223 def ancestor_ami_ids() ancestor_ami_ids = [] REXML::XPath.each(@doc, '/manifest/image/ancestry/ancestor_ami_id') do |node| ancestor_ami_ids << node.text unless (node.text.nil? or node.text.empty?) end ancestor_ami_ids end |
#arch ⇒ Object
Return the (optional) architecture of the AMI.
315 316 317 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 315 def arch() return get_element_text_or_nil('machine_configuration/architecture') end |
#authenticate(cert) ⇒ Object
Verify the signature
361 362 363 364 365 366 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 361 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 |
#block_device_mapping ⇒ Object
Get the block device mapping as a map.
299 300 301 302 303 304 305 306 307 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 299 def block_device_mapping() bdm = {} REXML::XPath.each(@doc.root,'machine_configuration/block_device_mapping/mapping/') do |mapping| virtual = REXML::XPath.first(mapping, 'virtual').text device = REXML::XPath.first(mapping, 'device').text bdm[virtual] = device end bdm end |
#bundled_size ⇒ Object
Return the bundled size of the AMI.
320 321 322 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 320 def bundled_size() return get_element_text( 'image/bundled_size' ).to_i end |
#bundler_name ⇒ Object
Return the bundler name.
325 326 327 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 325 def bundler_name() return get_element_text('bundler/name') end |
#bundler_release ⇒ Object
Return the bundler release.
335 336 337 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 335 def bundler_release() return get_element_text('bundler/release') end |
#bundler_version ⇒ Object
Return the bundler version.
330 331 332 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 330 def bundler_version() return get_element_text('bundler/version') end |
#cipher_algorithm ⇒ Object
Get cipher algorithm used.
266 267 268 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 266 def cipher_algorithm() return REXML::XPath.first(@doc.root, 'image/ec2_encrypted_key/@algorithm').to_s end |
#digest ⇒ Object
Return the AMI’s digest hex encoded.
232 233 234 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 232 def digest() return get_element_text( 'image/digest' ) end |
#digest_algorithm ⇒ Object
Get digest algorithm used.
261 262 263 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 261 def digest_algorithm() return REXML::XPath.first(@doc.root, 'image/digest/@algorithm').to_s end |
#doc ⇒ Object
for debugging only
51 52 53 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 51 def doc @doc end |
#ec2_encrypted_iv ⇒ Object
The ec2 encrypted initialization vector hex encoded.
251 252 253 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 251 def ec2_encrypted_iv() return get_element_text( 'image/ec2_encrypted_iv' ) end |
#ec2_encrypted_key ⇒ Object
The ec2 encrypted key hex encoded.
241 242 243 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 241 def ec2_encrypted_key() return get_element_text('image/ec2_encrypted_key' ) end |
#image_type ⇒ Object
377 378 379 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 377 def image_type() return get_element_text('image/type') end |
#init(args) ⇒ Object
Initialize the manifest with AMI information. Return true if the initialization was succesful. Raise an exception on error.
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 69 def init(args) name = mandatory_argument(:name, args) user = mandatory_argument(:user, args) # The user's account number. arch = mandatory_argument(:arch, args) # Target architecture for AMI. image_type = mandatory_argument(:image_type, args) # Type of image reserved = mandatory_argument(:reserved, args) # Reserved for future use; pass nil. parts = mandatory_argument(:parts, args) # A list of parts filenames and digest pairs. size = mandatory_argument(:size, args) # The size of the AMI in bytes. bundled_size = mandatory_argument(:bundled_size, args) # The size of the bunled AMI in bytes. user_encrypted_key = mandatory_argument(:user_encrypted_key, args) # Hex encoded. ec2_encrypted_key = mandatory_argument(:ec2_encrypted_key, args) # Hex encoded. cipher_algorithm = mandatory_argument(:cipher_algorithm, args) # The cipher algorithm used to encrypted the AMI. user_encrypted_iv = mandatory_argument(:user_encrypted_iv, args) # Hex encoded. ec2_encrypted_iv = mandatory_argument(:ec2_encrypted_iv, args) # Hex encoded. digest = mandatory_argument(:digest, args) # Hex encoded. digest_algorithm = mandatory_argument(:digest_algorithm, args) # The digest algorithm. privkey_filename = mandatory_argument(:privkey_filename, args) # The user's private key filename. # Optional parameters kernel_id = optional_argument(:kernel_id, args) # Optional default kernel image id ramdisk_id = optional_argument(:ramdisk_id, args) # Optional default ramdisk image id product_codes = optional_argument(:product_codes, args) # Optional array of product codes (strings) ancestor_ami_ids = optional_argument(:ancestor_ami_ids, args) # Optional array of ancestor ami ids (strings) bdm = optional_argument(:block_device_mapping, args) ||{} # Optional hash of block device mappings(strings) bundler_name = optional_argument(:bundler_name, args) bundler_version = optional_argument(:bundler_version, args) bundler_release = optional_argument(:bundler_release, args) # Conditional parameters kernel_name = (image_type == IMAGE_TYPE_KERNEL ? mandatory_argument(:kernel_name, args) : nil) # Name of the kernel in the image # 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 # Yeah... the way we used to do this really sucked - manually building up REXML::Element and inserting them into # parent nodes. So I've reinvented the wheel and done a baby xpath xml builder kinda thing # Makes it much easier (from a code point of view) to build up xml docs. Probably less efficient in machine terms but c'mon # if we cared about that we wouldn't be using ruby. builder = XMLBuilder.new(@doc) # version - indicate the manifest version. builder['/manifest/version'] = VERSION_STRING # bundler information builder['/manifest/bundler/name'] = bundler_name builder['/manifest/bundler/version'] = bundler_version builder['/manifest/bundler/release'] = bundler_release # machine_configuration - the target hardware description of the AMI. builder['/manifest/machine_configuration/architecture'] = arch bdm.keys.sort.each_with_index do |key, index| builder["/manifest/machine_configuration/block_device_mapping/mapping[#{index}]/virtual"] = key builder["/manifest/machine_configuration/block_device_mapping/mapping[#{index}]/device"] = bdm[key] end builder['/manifest/machine_configuration/kernel_id'] = kernel_id builder['/manifest/machine_configuration/ramdisk_id'] = ramdisk_id Array(product_codes).each_with_index do |product_code, index| builder["/manifest/machine_configuration/product_codes/product_code[#{index}]"] = product_code end # image - the image element. builder['manifest/image/name'] = name # user - the user's AWS access key ID. builder['/manifest/image/user'] = user builder['/manifest/image/type'] = image_type # The name of the kernel in the image. Only applicable to kernel images. builder['/manifest/image/kernel_name'] = kernel_name # ancestry - the parent ami ids (ancestor_ami_ids || []).each_with_index do |ancestor_ami_id, index| builder["/manifest/image/ancestry/ancestor_ami_id[#{index}]"] = ancestor_ami_id end # digest - the digest of the AMI. builder['/manifest/image/digest'] = digest builder['/manifest/image/digest/@algorithm'] = digest_algorithm # size - the size of the uncompressed AMI. builder['/manifest/image/size'] = size.to_s # bundled size - the size of the bundled AMI. builder['/manifest/image/bundled_size'] = bundled_size.to_s # ec2 encrypted key element. builder['/manifest/image/ec2_encrypted_key'] = ec2_encrypted_key builder['/manifest/image/ec2_encrypted_key/@algorithm'] = cipher_algorithm # user encrypted key element. builder['/manifest/image/user_encrypted_key'] = user_encrypted_key builder['/manifest/image/user_encrypted_key/@algorithm'] = cipher_algorithm # ec2 encrypted iv element. builder['/manifest/image/ec2_encrypted_iv'] = ec2_encrypted_iv # user encrypted iv element. builder['/manifest/image/user_encrypted_iv'] = user_encrypted_iv # parts - list of the image parts. builder['/manifest/image/parts/@count'] = parts.size parts.each_with_index do |part, index| # Add image part element for each image part. builder["/manifest/image/parts/part[#{index}]/@index"] = index builder["/manifest/image/parts/part[#{index}]/filename"] = part[0] builder["/manifest/image/parts/part[#{index}]/digest"] = Format::bin2hex(part[1]) builder["/manifest/image/parts/part[#{index}]/digest/@algorithm"] = digest_algorithm builder["/manifest/image/parts/part[#{index}]/@index"] = index end # Sign the manifest. sign(privkey_filename) return true end |
#kernel_id ⇒ Object
Get the default kernel_id
204 205 206 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 204 def kernel_id() return get_element_text_or_nil('machine_configuration/kernel_id') end |
#kernel_name ⇒ Object
Get the kernel_name
199 200 201 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 199 def kernel_name() return get_element_text_or_nil('image/kernel_name') end |
#mandatory_argument(arg, args) ⇒ Object
55 56 57 58 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 55 def mandatory_argument(arg, args) raise "Missing mandatory argument #{arg} for manifest #{VERSION_STRING}" if !args.key?(arg) args[arg] end |
#name ⇒ Object
236 237 238 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 236 def name() return get_element_text( 'image/name' ) end |
#optional_argument(arg, args) ⇒ Object
60 61 62 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 60 def optional_argument(arg, args) args[arg] end |
#parts ⇒ Object
A list of PartInformation instances representing the AMI parts.
287 288 289 290 291 292 293 294 295 296 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 287 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 |
#product_codes ⇒ Object
Get the default product codes
214 215 216 217 218 219 220 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 214 def product_codes() product_codes = [] REXML::XPath.each(@doc, '/manifest/machine_configuration/product_codes/product_code') do |product_code| product_codes << product_code.text end product_codes end |
#ramdisk_id ⇒ Object
Get the default ramdisk id
209 210 211 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 209 def ramdisk_id() return get_element_text_or_nil('machine_configuration/ramdisk_id') end |
#sign(privkey_filename) ⇒ Object
Sign the manifest. If it is already signed, the signature and certificate will be replaced
341 342 343 344 345 346 347 348 349 350 351 352 353 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 341 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. XMLBuilder.new(@doc)['/manifest/signature'] = Format::bin2hex(sig) end |
#signature ⇒ Object
Return the signature
356 357 358 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 356 def signature get_element_text('signature') end |
#size ⇒ Object
Return the size of the AMI.
310 311 312 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 310 def size() return get_element_text( 'image/size' ).to_i() end |
#to_s ⇒ Object
Return the manifest as an XML string.
369 370 371 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 369 def to_s() return @doc.to_s end |
#user ⇒ Object
373 374 375 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 373 def user() return get_element_text('image/user') end |
#user_encrypted_iv ⇒ Object
The user encrypted initialization vector hex encoded.
256 257 258 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 256 def user_encrypted_iv() return get_element_text( 'image/user_encrypted_iv' ) end |
#user_encrypted_key ⇒ Object
The user encrypted key hex encoded.
246 247 248 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 246 def user_encrypted_key() return get_element_text( 'image/user_encrypted_key' ) end |
#version ⇒ Object
381 382 383 |
# File 'lib/ec2/amitools/manifestv20071010.rb', line 381 def version() return get_element_text('version').gsub('-','').to_i end |