ovfparse 0.0.7 → 0.0.81
Sign up to get free protection for your applications and to get access to all the features.
- data/README +3 -2
- data/lib/ovfparse/vmpackage.rb +531 -2
- metadata +12 -5
data/README
CHANGED
data/lib/ovfparse/vmpackage.rb
CHANGED
@@ -20,6 +20,32 @@ class VmPackage
|
|
20
20
|
COPYING = 4
|
21
21
|
BOOTING = 5
|
22
22
|
CONFIGURING = 6
|
23
|
+
|
24
|
+
# List of attributes in an OVF product that we will extract / set
|
25
|
+
PRODUCT_ATTRIBUTES = [ {'full_name' => 'ovf:instance', 'node_ref' => 'instance', 'attribute_ref' => 'instance'},
|
26
|
+
{'full_name' => 'ovf:class', 'node_ref' => 'class', 'attribute_ref' => 'product_class'} ]
|
27
|
+
|
28
|
+
# List of elements in an OVF product that we will extract / set
|
29
|
+
PRODUCT_ELEMENTS = [ {'full_name' => 'ovf:Info', 'node_ref' => 'Info', 'element_ref' => 'description', 'required' => false},
|
30
|
+
{'full_name' => 'ovf:Product', 'node_ref' => 'Product', 'element_ref' => 'name', 'required' => false},
|
31
|
+
{'full_name' => 'ovf:Vendor', 'node_ref' => 'Vendor', 'element_ref' => 'vendor', 'required' => false},
|
32
|
+
{'full_name' => 'ovf:Version', 'node_ref' => 'Version', 'element_ref' => 'version', 'required' => false} ]
|
33
|
+
|
34
|
+
# List of attributes in an OVF property that we will extract / set
|
35
|
+
PROPERTY_ATTRIBUTES = [ {'full_name' => 'ovf:value', 'node_ref' => 'value', 'attribute_ref' => 'value'},
|
36
|
+
{'full_name' => 'ovf:key', 'node_ref' => 'key', 'attribute_ref' => 'key'},
|
37
|
+
{'full_name' => 'ovf:userConfigurable', 'node_ref' => 'userConfigurable', 'attribute_ref' => 'userConfigurable'},
|
38
|
+
{'full_name' => 'ovf:password', 'node_ref' => 'password', 'attribute_ref' => 'password'},
|
39
|
+
{'full_name' => 'ovf:required', 'node_ref' => 'required', 'attribute_ref' => 'required'},
|
40
|
+
{'full_name' => 'ovf:type', 'node_ref' => 'type', 'attribute_ref' => 'value_basetype'},
|
41
|
+
{'full_name' => 'cops:valueType', 'node_ref' => 'valueType', 'attribute_ref' => 'valueType'},
|
42
|
+
{'full_name' => 'cops:uuid', 'node_ref' => 'uuid', 'attribute_ref' => 'uuid'} ]
|
43
|
+
|
44
|
+
# List of elements in an OVF property that we will extract / set
|
45
|
+
PROPERTY_ELEMENTS = [ {'full_name' => 'ovf:Label', 'node_ref' => 'Label', 'element_ref' => 'name', 'required' => false},
|
46
|
+
{'full_name' => 'ovf:Description', 'node_ref' => 'Description', 'element_ref' => 'description', 'required' => false},
|
47
|
+
{'full_name' => 'cops:Example', 'node_ref' => 'cops:Example', 'element_ref' => 'example', 'required' => true},
|
48
|
+
{'full_name' => 'cops:NoneType', 'node_ref' => 'cops:NoneType', 'element_ref' => 'nonetype', 'required' => true} ]
|
23
49
|
|
24
50
|
OVF_NAMESPACE = {'ovf' => 'http://schemas.dmtf.org/ovf/envelope/1'}
|
25
51
|
|
@@ -120,6 +146,510 @@ class VmPackage
|
|
120
146
|
|
121
147
|
end
|
122
148
|
|
149
|
+
def checkschema(schema)
|
150
|
+
xsd = Nokogiri::XML::Schema(File.read(schema))
|
151
|
+
response = ""
|
152
|
+
|
153
|
+
isValid = true
|
154
|
+
xsd.validate(@xml).each do |error|
|
155
|
+
response << error.message + "\n"
|
156
|
+
isValid = false
|
157
|
+
end
|
158
|
+
|
159
|
+
return [isValid, response]
|
160
|
+
end
|
161
|
+
|
162
|
+
def getVmName
|
163
|
+
return xml.xpath('ovf:Envelope/ovf:VirtualSystem')[0]['id']
|
164
|
+
end
|
165
|
+
|
166
|
+
def getVmDescription
|
167
|
+
descNode = xml.xpath('ovf:Envelope/ovf:VirtualSystem/ovf:Info')[0]
|
168
|
+
return descNode.nil? ? '' : descNode.content
|
169
|
+
end
|
170
|
+
|
171
|
+
def getVmOS_ID
|
172
|
+
return xml.xpath('ovf:Envelope/ovf:VirtualSystem/ovf:OperatingSystemSection')[0]['id']
|
173
|
+
end
|
174
|
+
|
175
|
+
def getVmPatchLevel
|
176
|
+
patchNode = xml.xpath('ovf:Envelope/ovf:VirtualSystem/ovf:OperatingSystemSection/ovf:Description')[0]
|
177
|
+
return patchNode.nil? ? '' : patchNode.text
|
178
|
+
end
|
179
|
+
|
180
|
+
def getVmAttributes
|
181
|
+
return {
|
182
|
+
'name' => getVmName,
|
183
|
+
'description' => getVmDescription,
|
184
|
+
'OS' => getVmOS_ID,
|
185
|
+
'patch_level' => getVmPatchLevel,
|
186
|
+
'CPUs' => getVmCPUs,
|
187
|
+
'RAM' => getVmRAM
|
188
|
+
}
|
189
|
+
end
|
190
|
+
|
191
|
+
def getVmDisks
|
192
|
+
disks = Array.new
|
193
|
+
filenames = Hash.new
|
194
|
+
xml.xpath('ovf:Envelope/ovf:References/ovf:File').each { |node|
|
195
|
+
filenames[node['id']] = node['href']
|
196
|
+
}
|
197
|
+
|
198
|
+
xml.xpath('ovf:Envelope/ovf:DiskSection/ovf:Disk').each { |node|
|
199
|
+
disks.push({ 'name' => node['diskId'], 'location' => filenames[node['fileRef']], 'size' => node['capacity'] })
|
200
|
+
}
|
201
|
+
|
202
|
+
return disks
|
203
|
+
end
|
204
|
+
|
205
|
+
def getVmNetworks
|
206
|
+
networks = Array.new
|
207
|
+
xml.xpath('ovf:Envelope/ovf:NetworkSection/ovf:Network').each { |node|
|
208
|
+
descriptionNode = node.xpath('ovf:Description')[0]
|
209
|
+
text = descriptionNode.nil? ? '' : descriptionNode.text
|
210
|
+
networks.push({'location' => node['name'], 'notes' => text })
|
211
|
+
}
|
212
|
+
return networks
|
213
|
+
end
|
214
|
+
|
215
|
+
# What a long strange trip it's been.
|
216
|
+
def getVmProducts
|
217
|
+
products = Array.new
|
218
|
+
xml.root.add_namespace('cops', 'http://cops.mitre.org/1.1')
|
219
|
+
xml.root.add_namespace('cpe', 'http://cpe.mitre.org/dictionary/2.0')
|
220
|
+
|
221
|
+
xml.xpath('ovf:Envelope/ovf:VirtualSystem/ovf:ProductSection').each { |productNode|
|
222
|
+
product = Hash.new
|
223
|
+
|
224
|
+
PRODUCT_ATTRIBUTES.each { |attribute_details|
|
225
|
+
product[attribute_details['attribute_ref']] = productNode[attribute_details['node_ref']]
|
226
|
+
}
|
227
|
+
|
228
|
+
PRODUCT_ELEMENTS.each { |element_details|
|
229
|
+
childNode = productNode.xpath(element_details['full_name'])[0]
|
230
|
+
product[element_details['element_ref']] = childNode.nil? ? '' : childNode.content
|
231
|
+
}
|
232
|
+
|
233
|
+
childNode = productNode.xpath('ovf:Icon')[0]
|
234
|
+
begin
|
235
|
+
product['icon'] = childNode.nil? ? '' :
|
236
|
+
(xml.xpath('ovf:Envelope/ovf:References/ovf:File').detect { |file| file['id'] == childNode['fileRef'] })['href']
|
237
|
+
rescue
|
238
|
+
puts "You have an icon reference to a file that doesn't exist in the References section."
|
239
|
+
return ''
|
240
|
+
end
|
241
|
+
|
242
|
+
properties = Array.new
|
243
|
+
productNode.xpath('ovf:Property').each { |propertyNode|
|
244
|
+
property = Hash.new
|
245
|
+
PROPERTY_ATTRIBUTES.each { |attribute_details|
|
246
|
+
property[attribute_details['attribute_ref']] = propertyNode[attribute_details['node_ref']]
|
247
|
+
}
|
248
|
+
|
249
|
+
PROPERTY_ELEMENTS.each { |element_details|
|
250
|
+
childNode = propertyNode.xpath(element_details['full_name'])[0]
|
251
|
+
property[element_details['element_ref']] = childNode.nil? ? '' : childNode.content
|
252
|
+
}
|
253
|
+
|
254
|
+
valueOptionsArray = Array.new
|
255
|
+
|
256
|
+
node = propertyNode.xpath('cops:ValueOptions')[0]
|
257
|
+
if(!node.nil?)
|
258
|
+
if (!node['selection'].nil?)
|
259
|
+
property['selection'] = node['selection']
|
260
|
+
end
|
261
|
+
node.xpath('cops:Option').each { |valueOption|
|
262
|
+
valueOptionsArray.push(valueOption.content)
|
263
|
+
}
|
264
|
+
end
|
265
|
+
|
266
|
+
default = propertyNode['value']
|
267
|
+
existingDefault = valueOptionsArray.detect { |option| option == default }
|
268
|
+
if (!default.nil? && default != '' && existingDefault.nil?)
|
269
|
+
valueOptionsArray.insert(0, default)
|
270
|
+
end
|
271
|
+
|
272
|
+
property['valueoptions'] = valueOptionsArray.join("\n")
|
273
|
+
|
274
|
+
actions = Array.new
|
275
|
+
node = propertyNode.xpath('cops:Action')[0]
|
276
|
+
if(!node.nil?)
|
277
|
+
node.xpath('cops:FindReplace').each { |findReplace|
|
278
|
+
actions.push({'action_type' => 'FindReplace', 'path' => findReplace.xpath('cops:Path')[0].content, 'value' => findReplace.xpath('cops:Token')[0].content})
|
279
|
+
}
|
280
|
+
node.xpath('cops:Insert').each { |insert|
|
281
|
+
lineNumberNode = insert.xpath('cops:LineNumber')[0]
|
282
|
+
lineNumber = lineNumberNode.nil? ? '' : lineNumberNode.content
|
283
|
+
actions.push({'action_type' => 'Insert', 'path' => insert.xpath('cops:Path')[0].content, 'value' => lineNumber})
|
284
|
+
}
|
285
|
+
node.xpath('cops:Registry').each { |registry|
|
286
|
+
actions.push({'action_type' => 'Registry', 'path' => registry.xpath('cops:RegistryPath')[0].content, 'value' => ''})
|
287
|
+
}
|
288
|
+
node.xpath('cops:Execute').each { |execute|
|
289
|
+
optionsNode = execute.xpath('cops:Options')[0]
|
290
|
+
options = optionsNode.nil? ? '' : optionsNode.content
|
291
|
+
actions.push({'action_type' => 'Execute', 'path' => execute.xpath('cops:Path')[0].content, 'value' => options})
|
292
|
+
}
|
293
|
+
|
294
|
+
end
|
295
|
+
|
296
|
+
container = [property, actions]
|
297
|
+
properties.push(container)
|
298
|
+
}
|
299
|
+
|
300
|
+
container = [product, properties]
|
301
|
+
products.push(container)
|
302
|
+
}
|
303
|
+
return products
|
304
|
+
end
|
305
|
+
|
306
|
+
def getVmCPUs
|
307
|
+
return getVirtualQuantity(3)
|
308
|
+
end
|
309
|
+
|
310
|
+
def getVmRAM
|
311
|
+
return getVirtualQuantity(4)
|
312
|
+
end
|
313
|
+
|
314
|
+
def getVirtualQuantity(resource)
|
315
|
+
xml.xpath('ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item').each { |node|
|
316
|
+
resourceType = node.xpath('rasd:ResourceType')[0].text
|
317
|
+
resourceType == resource.to_s ? (return node.xpath('rasd:VirtualQuantity')[0].text) : next
|
318
|
+
}
|
319
|
+
end
|
320
|
+
|
321
|
+
def setVmName(newValue)
|
322
|
+
xml.xpath('ovf:Envelope/ovf:VirtualSystem')[0]['ovf:id'] = newValue
|
323
|
+
nameNode = xml.xpath('ovf:Envelope/ovf:VirtualSystem/ovf:Name')[0] ||
|
324
|
+
xml.xpath('ovf:Envelope/ovf:VirtualSystem/ovf:Info')[0].add_next_sibling(xml.create_element('Name', {}))
|
325
|
+
nameNode.content = newValue
|
326
|
+
end
|
327
|
+
|
328
|
+
def setVmDescription(newValue)
|
329
|
+
xml.xpath('ovf:Envelope/ovf:VirtualSystem/ovf:Info')[0].content = newValue
|
330
|
+
end
|
331
|
+
|
332
|
+
def setVmOS_ID(newValue)
|
333
|
+
xml.xpath('ovf:Envelope/ovf:VirtualSystem/ovf:OperatingSystemSection')[0]['ovf:id'] = newValue.to_s
|
334
|
+
end
|
335
|
+
|
336
|
+
def setVmPatchLevel(newValue)
|
337
|
+
osNode = xml.xpath('ovf:Envelope/ovf:VirtualSystem/ovf:OperatingSystemSection')[0]
|
338
|
+
descNode = osNode.xpath('ovf:Description')[0] || osNode.add_child(xml.create_element('Description', {}))
|
339
|
+
descNode.content = newValue
|
340
|
+
end
|
341
|
+
|
342
|
+
def setVmCPUs(newValue)
|
343
|
+
setVirtualQuantity(3, newValue)
|
344
|
+
end
|
345
|
+
|
346
|
+
def setVmRAM(newValue)
|
347
|
+
setVirtualQuantity(4, newValue)
|
348
|
+
end
|
349
|
+
|
350
|
+
def setVirtualQuantity(resource, newValue)
|
351
|
+
xml.xpath('ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item').each { |node|
|
352
|
+
resourceType = node.xpath('rasd:ResourceType')[0].text
|
353
|
+
resourceType == resource.to_s ? (node.xpath('rasd:VirtualQuantity')[0].content = newValue) : next
|
354
|
+
}
|
355
|
+
end
|
356
|
+
|
357
|
+
def setVmNetworks(networks)
|
358
|
+
networkSection = xml.xpath('ovf:Envelope/ovf:NetworkSection')[0]
|
359
|
+
networkNodes = networkSection.xpath('ovf:Network')
|
360
|
+
|
361
|
+
networkNodes.each { |node|
|
362
|
+
updated_network = networks.detect { |network| network.location == node['name'] }
|
363
|
+
if(updated_network.nil?)
|
364
|
+
node.unlink
|
365
|
+
else
|
366
|
+
descriptionNode = node.xpath('ovf:Description')[0]
|
367
|
+
if((updated_network.notes == '' || updated_network.notes.nil?) && !descriptionNode.nil?)
|
368
|
+
descriptionNode.unlink
|
369
|
+
elsif(updated_network.notes != '' && !updated_network.notes.nil?)
|
370
|
+
descriptionNode = descriptionNode || descriptionNode.add_child(xml.create_element("Description", {}))
|
371
|
+
descriptionNode.content = updated_network.notes
|
372
|
+
end
|
373
|
+
end
|
374
|
+
}
|
375
|
+
|
376
|
+
networks.each { |network|
|
377
|
+
if( (networkNodes.detect { |node| network.location == node['name'] }).nil?)
|
378
|
+
networkNode = networkSection.add_child(xml.create_element('Network', {'ovf:name' => network.location}))
|
379
|
+
if(network.notes != '' && !network.notes.nil?)
|
380
|
+
networkNode.add_child(xml.create_element('Description', network.notes))
|
381
|
+
end
|
382
|
+
end
|
383
|
+
}
|
384
|
+
end
|
385
|
+
|
386
|
+
def setVmDisks(disks)
|
387
|
+
fileSection = xml.xpath('ovf:Envelope/ovf:References')[0]
|
388
|
+
fileNodes = fileSection.xpath('ovf:File')
|
389
|
+
|
390
|
+
diskSection = xml.xpath('ovf:Envelope/ovf:DiskSection')[0]
|
391
|
+
diskNodes = diskSection.xpath('ovf:Disk')
|
392
|
+
|
393
|
+
icons = Array.new
|
394
|
+
xml.xpath('ovf:Envelope/ovf:VirtualSystem/ovf:ProductSection/ovf:Icon').each { |node|
|
395
|
+
icons.push(node['fileRef'])
|
396
|
+
}
|
397
|
+
|
398
|
+
fileNodes.each { |file_node|
|
399
|
+
updated_disk = disks.detect { |disk| disk.location == file_node['href'] }
|
400
|
+
old_disk_node = diskNodes.detect { |old_node| old_node['id'] == file_node['fileRef'] }
|
401
|
+
|
402
|
+
if(updated_disk.nil?)
|
403
|
+
if((icons.detect { |fileRef| fileRef == file_node['id'] }).nil?)
|
404
|
+
file_node.unlink
|
405
|
+
if(!old_disk_node.nil?)
|
406
|
+
old_disk_node.unlink
|
407
|
+
end
|
408
|
+
end
|
409
|
+
else
|
410
|
+
file_node['ovf:id'] = updated_disk.name + '_disk'
|
411
|
+
old_disk_node['ovf:fileRef'] = updated_disk.name + '_disk'
|
412
|
+
old_disk_node['ovf:capacity'] = updated_disk.size.to_s
|
413
|
+
old_disk_node['ovf:diskId'] = updated_disk.name
|
414
|
+
end
|
415
|
+
}
|
416
|
+
|
417
|
+
disks.each { |disk|
|
418
|
+
if( (fileNodes.detect { |node| disk.location == node['href'] }).nil?)
|
419
|
+
diskSection.add_child(xml.create_element('Disk', {'ovf:capacity' => disk.size.to_s, 'ovf:capacityAllocationUnits' => "byte * 2^30", 'ovf:diskId' => disk.name, 'ovf:fileRef' => disk.name + '_disk', 'ovf:format' => "http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" }))
|
420
|
+
fileSection.add_child(xml.create_element('File', {'ovf:href' => disk.location, 'ovf:id' => disk.name + '_disk'}))
|
421
|
+
end
|
422
|
+
}
|
423
|
+
end
|
424
|
+
|
425
|
+
def setVmAttributes(attributes)
|
426
|
+
if attributes['name']
|
427
|
+
setVmName(attributes['name'])
|
428
|
+
end
|
429
|
+
if attributes['description']
|
430
|
+
setVmDescription(attributes['description'])
|
431
|
+
end
|
432
|
+
if attributes['OS']
|
433
|
+
setVmOS_ID(attributes['OS'])
|
434
|
+
end
|
435
|
+
if attributes['patch_level']
|
436
|
+
setVmPatchLevel(attributes['patch_level'])
|
437
|
+
end
|
438
|
+
if attributes['CPUs']
|
439
|
+
setVmCPUs(attributes['CPUs'])
|
440
|
+
end
|
441
|
+
if attributes['RAM']
|
442
|
+
setVmRAM(attributes['RAM'])
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
def setProductIcon(new_icon, productNode)
|
447
|
+
iconNode = productNode.xpath('ovf:Icon')[0]
|
448
|
+
if((new_icon == '' || new_icon.nil?) && !iconNode.nil?)
|
449
|
+
(xml.xpath('ovf:Envelope/ovf:References/ovf:File').detect { |fileNode| fileNode['id'] == iconNode['fileRef']}).unlink
|
450
|
+
iconNode.unlink
|
451
|
+
elsif(new_icon != '' && !new_icon.nil?)
|
452
|
+
if(iconNode.nil?)
|
453
|
+
productNode.add_child(xml.create_element('Icon', {'ovf:fileRef' => productNode['class'] + '_icon'}))
|
454
|
+
xml.xpath('ovf:Envelope/ovf:References')[0].add_child(xml.create_element('File', {'ovf:id' => productNode['class'] + '_icon', 'ovf:href' => new_icon}))
|
455
|
+
else
|
456
|
+
(xml.xpath('ovf:Envelope/ovf:References/ovf:File').detect { |fileNode| fileNode['id'] == iconNode['fileRef']})['ovf:href'] = new_icon
|
457
|
+
end
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
def setElements(updated_element, parent_node, element_list)
|
462
|
+
element_list.each { |element_details|
|
463
|
+
updated_value = updated_element[element_details['element_ref']]
|
464
|
+
element_node = parent_node.xpath(element_details['full_name'])[0]
|
465
|
+
if((updated_value == '' || updated_value.nil?) && !element_node.nil?)
|
466
|
+
element_node.unlink
|
467
|
+
elsif(updated_value != '' && !updated_value.nil?)
|
468
|
+
element_node = element_node || parent_node.add_child(xml.create_element(element_details['node_ref'], updated_value))
|
469
|
+
element_node.content = updated_value
|
470
|
+
if(element_details['required'])
|
471
|
+
element_node['ovf:required'] = 'false'
|
472
|
+
end
|
473
|
+
end
|
474
|
+
}
|
475
|
+
end
|
476
|
+
|
477
|
+
def setAttributes(updated_element, parent_node, attribute_list)
|
478
|
+
attribute_list.each { |attribute_details|
|
479
|
+
updated_value = updated_element[attribute_details['attribute_ref']]
|
480
|
+
(updated_value == '' || updated_value.nil?) ? parent_node.delete(attribute_details['node_ref']) : parent_node[attribute_details['full_name']] = updated_value
|
481
|
+
}
|
482
|
+
end
|
483
|
+
|
484
|
+
def setVmProducts(products)
|
485
|
+
virtualSystem = xml.xpath('ovf:Envelope/ovf:VirtualSystem')[0]
|
486
|
+
productNodes = virtualSystem.xpath('ovf:ProductSection')
|
487
|
+
|
488
|
+
# Removing old ones that don't exist anymore, updating ones that do
|
489
|
+
productNodes.each { |productNode|
|
490
|
+
updated_product = products.detect { |product| productNode['class'] == product.product_class }
|
491
|
+
if(updated_product.nil?)
|
492
|
+
productNode.unlink
|
493
|
+
else
|
494
|
+
setAttributes(updated_product, productNode, PRODUCT_ATTRIBUTES)
|
495
|
+
setElements(updated_product, productNode, PRODUCT_ELEMENTS)
|
496
|
+
setProductIcon(updated_product.icon, productNode)
|
497
|
+
setProperties(productNode, updated_product.coat_properties)
|
498
|
+
end
|
499
|
+
}
|
500
|
+
|
501
|
+
# Adding new products
|
502
|
+
products.each { |product|
|
503
|
+
if((productNodes.detect { |node| node['class'] == product.product_class }).nil?)
|
504
|
+
newProductNode = virtualSystem.add_child(xml.create_element('ProductSection', {}))
|
505
|
+
setAttributes(product, newProductNode, PRODUCT_ATTRIBUTES)
|
506
|
+
setElements(product, newProductNode, PRODUCT_ELEMENTS)
|
507
|
+
setProductIcon(product.icon, newProductNode)
|
508
|
+
setProperties(newProductNode, product.coat_properties)
|
509
|
+
end
|
510
|
+
}
|
511
|
+
end
|
512
|
+
|
513
|
+
def setProperties(product, properties)
|
514
|
+
propertyNodes = product.xpath('ovf:Property')
|
515
|
+
|
516
|
+
propertyNodes.each { |propertyNode|
|
517
|
+
updated_property = properties.detect { |property| propertyNode['key'] == property.key }
|
518
|
+
if(updated_property.nil?)
|
519
|
+
propertyNode.unlink
|
520
|
+
else
|
521
|
+
setAttributes(updated_property, propertyNode, PROPERTY_ATTRIBUTES)
|
522
|
+
setElements(updated_property, propertyNode, PROPERTY_ELEMENTS)
|
523
|
+
setValueOptions(propertyNode, updated_property)
|
524
|
+
propertyNode['ovf:type'] = 'string'
|
525
|
+
setActions(propertyNode, updated_property.coat_actions)
|
526
|
+
end
|
527
|
+
}
|
528
|
+
|
529
|
+
properties.each { |property|
|
530
|
+
if((propertyNodes.detect { |node| node['key'] == property.key }).nil?)
|
531
|
+
newPropertyNode = product.add_child(xml.create_element('Property', {}))
|
532
|
+
setAttributes(property, newPropertyNode, PROPERTY_ATTRIBUTES)
|
533
|
+
setElements(property, newPropertyNode, PROPERTY_ELEMENTS)
|
534
|
+
setValueOptions(newPropertyNode, property)
|
535
|
+
newPropertyNode['ovf:type'] = 'string'
|
536
|
+
setActions(newPropertyNode, property.coat_actions)
|
537
|
+
end
|
538
|
+
}
|
539
|
+
end
|
540
|
+
|
541
|
+
def setValueOptions(property_node, property)
|
542
|
+
values = property.valueoptions.split("\n")
|
543
|
+
valueOptionsNode = property_node.xpath('cops:ValueOptions')[0]
|
544
|
+
if(values.empty? && !valueOptionsNode.nil?)
|
545
|
+
valueOptionsNode.unlink
|
546
|
+
elsif(!values.empty?)
|
547
|
+
valueOptionsNode = valueOptionsNode || property_node.add_child(xml.create_element('ValueOptions', {}))
|
548
|
+
valueOptionsNode.namespace = xml.root.namespace_definitions.detect{ |ns| ns.prefix == 'cops' }
|
549
|
+
valueOptionsNode['cops:selection'] = (property.selection || 'single')
|
550
|
+
valueOptionsNode['ovf:required'] = 'false'
|
551
|
+
valueOptionsNode.children.unlink
|
552
|
+
existingDefault = values.detect { |value| value == property.value }
|
553
|
+
if(property.value != '' && !property.value.nil? && existingValue.nil?)
|
554
|
+
valueOptionsNode.add_child(xml.create_element('Option', property.value))
|
555
|
+
end
|
556
|
+
values.each { |value|
|
557
|
+
valueOptionsNode.add_child(xml.create_element('Option', value))
|
558
|
+
}
|
559
|
+
end
|
560
|
+
end
|
561
|
+
|
562
|
+
def setActions(property, actions)
|
563
|
+
actionsNode = property.xpath('cops:Action')[0]
|
564
|
+
if(actions.empty? && !actionsNode.nil?)
|
565
|
+
actionsNode.unlink
|
566
|
+
elsif(!actions.empty?)
|
567
|
+
actionsNode = actionsNode || property.add_child(xml.create_element('Action', {}))
|
568
|
+
actionsNode.namespace = xml.root.namespace_definitions.detect{ |ns| ns.prefix == 'cops' }
|
569
|
+
actionsNode['ovf:required'] = 'false'
|
570
|
+
actionsNode.children.unlink
|
571
|
+
actions.each { |action|
|
572
|
+
newActionNode = actionsNode.add_child(xml.create_element(action.action_type, {}))
|
573
|
+
if(action.action_type == 'FindReplace')
|
574
|
+
newActionNode.add_child(xml.create_element('Path', action.path))
|
575
|
+
newActionNode.add_child(xml.create_element('Token', action.value))
|
576
|
+
elsif(action.action_type == 'Insert')
|
577
|
+
newActionNode.add_child(xml.create_element('Path', action.path))
|
578
|
+
if(action.value != '' && !action.value.nil?)
|
579
|
+
newActionNode.add_child(xml.create_element('LineNumber', action.value))
|
580
|
+
end
|
581
|
+
elsif(action.action_type == 'Registry')
|
582
|
+
newActionNode.add_child(xml.create_element('RegistryPath', action.path))
|
583
|
+
elsif(action.action_type == 'Execute')
|
584
|
+
newActionNode.add_child(xml.create_element('Path', action.path))
|
585
|
+
if(action.value != '' && !action.value.nil?)
|
586
|
+
newActionNode.add_child(xml.create_element('Options', action.value))
|
587
|
+
end
|
588
|
+
end
|
589
|
+
}
|
590
|
+
end
|
591
|
+
end
|
592
|
+
|
593
|
+
def self.construct_skeleton
|
594
|
+
builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
|
595
|
+
xml.Envelope('xmlns' => 'http://schemas.dmtf.org/ovf/envelope/1', 'xmlns:cim' => "http://schemas.dmtf.org/wbem/wscim/1/common", 'xmlns:ovf' => "http://schemas.dmtf.org/ovf/envelope/1", 'xmlns:rasd' => "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData", 'xmlns:vmw' => "http://www.vmware.com/schema/ovf", 'xmlns:vssd' => "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData", 'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance") {
|
596
|
+
xml.References{}
|
597
|
+
xml.DiskSection{
|
598
|
+
xml.Info "Virtual disk information"
|
599
|
+
}
|
600
|
+
xml.NetworkSection{
|
601
|
+
xml.Info "List of logical networks"
|
602
|
+
}
|
603
|
+
xml.VirtualSystem('ovf:id' => "vm"){
|
604
|
+
xml.Info "A virtual machine"
|
605
|
+
xml.Name "New Virtual Machine"
|
606
|
+
xml.OperatingSystemSection('ovf:id' => "94"){
|
607
|
+
xml.Info "The kind of guest operating system"
|
608
|
+
}
|
609
|
+
xml.VirtualHardwareSection{
|
610
|
+
xml.Info "Virtual hardware requirements"
|
611
|
+
xml.System{
|
612
|
+
xml['vssd'].ElementName "Virtual Hardware Family"
|
613
|
+
xml['vssd'].InstanceID "0"
|
614
|
+
xml['vssd'].VirtualSystemIdentifier "New Virtual Machine"
|
615
|
+
}
|
616
|
+
xml.Item{
|
617
|
+
xml['rasd'].AllocationUnits "herts * 10^6"
|
618
|
+
xml['rasd'].Description "Number of Virtual CPUs"
|
619
|
+
xml['rasd'].ElementName "1 Virtual CPU(s)"
|
620
|
+
xml['rasd'].InstanceID "1"
|
621
|
+
xml['rasd'].ResourceType "3"
|
622
|
+
xml['rasd'].VirtualQuantity "1"
|
623
|
+
}
|
624
|
+
xml.Item{
|
625
|
+
xml['rasd'].AllocationUnits "byte * 2^20"
|
626
|
+
xml['rasd'].Description "Memory Size"
|
627
|
+
xml['rasd'].ElementName "512MB of memory"
|
628
|
+
xml['rasd'].InstanceID "2"
|
629
|
+
xml['rasd'].ResourceType "4"
|
630
|
+
xml['rasd'].VirtualQuantity "512"
|
631
|
+
}
|
632
|
+
}
|
633
|
+
}
|
634
|
+
}
|
635
|
+
node = Nokogiri::XML::Comment.new(xml.doc, ' skeleton framework constructed by COAT ')
|
636
|
+
xml.doc.children[0].add_previous_sibling(node)
|
637
|
+
end
|
638
|
+
return builder.to_xml
|
639
|
+
end
|
640
|
+
|
641
|
+
def write_xml(file)
|
642
|
+
xml.write_xml_to(file)
|
643
|
+
end
|
644
|
+
|
645
|
+
def sign
|
646
|
+
node = Nokogiri::XML::Comment.new(xml, ' made with love by the cops ovf authoring tool. ')
|
647
|
+
xml.children[0].add_next_sibling(node)
|
648
|
+
end
|
649
|
+
|
650
|
+
def xpath(string)
|
651
|
+
puts @xml.xpath(string)
|
652
|
+
end
|
123
653
|
|
124
654
|
end
|
125
655
|
|
@@ -185,8 +715,7 @@ end
|
|
185
715
|
class FileVmPackage < VmPackage
|
186
716
|
def fetch
|
187
717
|
@xml = Nokogiri::XML(File.open(self.url)) do |config|
|
188
|
-
config.strict.noent
|
189
|
-
config.strict
|
718
|
+
config.noblanks.strict.noent
|
190
719
|
end
|
191
720
|
end
|
192
721
|
end
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ovfparse
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 189
|
5
|
+
prerelease:
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
9
|
+
- 81
|
10
|
+
version: 0.0.81
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Jim Barkley
|
@@ -14,16 +15,18 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date:
|
18
|
+
date: 2011-03-14 00:00:00 -04:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: nokogiri
|
22
23
|
prerelease: false
|
23
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
24
26
|
requirements:
|
25
27
|
- - ">="
|
26
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 5
|
27
30
|
segments:
|
28
31
|
- 1
|
29
32
|
- 4
|
@@ -63,23 +66,27 @@ rdoc_options: []
|
|
63
66
|
require_paths:
|
64
67
|
- lib
|
65
68
|
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
66
70
|
requirements:
|
67
71
|
- - ">="
|
68
72
|
- !ruby/object:Gem::Version
|
73
|
+
hash: 3
|
69
74
|
segments:
|
70
75
|
- 0
|
71
76
|
version: "0"
|
72
77
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
73
79
|
requirements:
|
74
80
|
- - ">="
|
75
81
|
- !ruby/object:Gem::Version
|
82
|
+
hash: 3
|
76
83
|
segments:
|
77
84
|
- 0
|
78
85
|
version: "0"
|
79
86
|
requirements: []
|
80
87
|
|
81
88
|
rubyforge_project:
|
82
|
-
rubygems_version: 1.
|
89
|
+
rubygems_version: 1.6.2
|
83
90
|
signing_key:
|
84
91
|
specification_version: 3
|
85
92
|
summary: Retrieves and parses files in the Open Virtualization Format
|