Merge branch 'stable-2.7' into stable-2.8
[ganeti-local] / test / py / ganeti.ovf_unittest.py
1 #!/usr/bin/python
2 #
3
4 # Copyright (C) 2011, 2012 Google Inc.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 # 02110-1301, USA.
20
21
22 """Script for testing ganeti.ovf.
23
24 """
25
26 import optparse
27 import os
28 import os.path
29 import re
30 import shutil
31 import sys
32 import tempfile
33 import unittest
34
35 try:
36   import xml.etree.ElementTree as ET
37 except ImportError:
38   import elementtree.ElementTree as ET
39
40 from ganeti import constants
41 from ganeti import errors
42 from ganeti import ovf
43 from ganeti import utils
44 from ganeti import pathutils
45
46 import testutils
47
48 OUTPUT_DIR = "newdir"
49
50 GANETI_DISKS = {
51   "disk_count": "1",
52   "disk0_dump": "new_disk.raw",
53   "disk0_size": "0",
54   "disk0_ivname": "disk/0",
55 }
56 GANETI_NETWORKS = {
57   "nic_count": "1",
58   "nic0_mode": "bridged",
59   "nic0_ip": "none",
60   "nic0_mac": "aa:00:00:d8:2c:1e",
61   "nic0_link": "xen-br0",
62   "nic0_network": "auto",
63 }
64 GANETI_HYPERVISOR = {
65   "hypervisor_name": "xen-pvm",
66   "root-path": "/dev/sda",
67   "kernel_args": "ro",
68 }
69 GANETI_OS = {"os_name": "lenny-image"}
70 GANETI_BACKEND = {
71   "vcpus": "1",
72   "memory" : "2048",
73   "auto_balance": "False",
74 }
75 GANETI_NAME = "ganeti-test-xen"
76 GANETI_TEMPLATE = "plain"
77 GANETI_TAGS = None
78 GANETI_VERSION = "0"
79
80 VIRTUALBOX_DISKS = {
81   "disk_count": "2",
82   "disk0_ivname": "disk/0",
83   "disk0_dump": "new_disk.raw",
84   "disk0_size": "0",
85   "disk1_ivname": "disk/1",
86   "disk1_dump": "second_disk.raw",
87   "disk1_size": "0",
88 }
89 VIRTUALBOX_NETWORKS = {
90   "nic_count": "1",
91   "nic0_mode": "bridged",
92   "nic0_ip": "none",
93   "nic0_link": "auto",
94   "nic0_mac": "auto",
95   "nic0_network": "auto",
96 }
97 VIRTUALBOX_HYPERVISOR = {"hypervisor_name": "auto"}
98 VIRTUALBOX_OS = {"os_name": None}
99 VIRTUALBOX_BACKEND = {
100  "vcpus": "1",
101   "memory" : "2048",
102   "auto_balance": "auto",
103 }
104 VIRTUALBOX_NAME = None
105 VIRTUALBOX_TEMPLATE = None
106 VIRTUALBOX_TAGS = None
107 VIRTUALBOX_VERSION = None
108
109 EMPTY_DISKS = {}
110 EMPTY_NETWORKS = {}
111 EMPTY_HYPERVISOR = {"hypervisor_name": "auto"}
112 EMPTY_OS = {}
113 EMPTY_BACKEND = {
114   "vcpus": "auto",
115   "memory" : "auto",
116   "auto_balance": "auto",
117 }
118 EMPTY_NAME = None
119 EMPTY_TEMPLATE = None
120 EMPTY_TAGS = None
121 EMPTY_VERSION = None
122
123 CMDARGS_DISKS = {
124   "disk_count": "1",
125   "disk0_ivname": "disk/0",
126   "disk0_dump": "disk0.raw",
127   "disk0_size": "8",
128 }
129 CMDARGS_NETWORKS = {
130   "nic0_link": "auto",
131   "nic0_mode": "bridged",
132   "nic0_ip": "none",
133   "nic0_mac": "auto",
134   "nic_count": "1",
135   "nic0_network": "auto",
136 }
137 CMDARGS_HYPERVISOR = {
138   "hypervisor_name": "xen-pvm"
139 }
140 CMDARGS_OS = {"os_name": "lenny-image"}
141 CMDARGS_BACKEND = {
142   "auto_balance": False,
143   "vcpus": "1",
144   "memory": "256",
145 }
146 CMDARGS_NAME = "test-instance"
147 CMDARGS_TEMPLATE = "plain"
148 CMDARGS_TAGS = "test-tag-1,test-tag-2"
149
150 ARGS_EMPTY = {
151   "output_dir": None,
152   "nics": [],
153   "disks": [],
154   "name": "test-instance",
155   "ova_package": False,
156   "ext_usage": False,
157   "disk_format": "cow",
158   "compression": False,
159 }
160 ARGS_EXPORT_DIR = dict(ARGS_EMPTY, **{
161   "output_dir": OUTPUT_DIR,
162   "name": None,
163   "hypervisor": None,
164   "os": None,
165   "beparams": {},
166   "no_nics": False,
167   "disk_template": None,
168   "tags": None,
169 })
170 ARGS_VBOX = dict(ARGS_EXPORT_DIR, **{
171   "output_dir": OUTPUT_DIR,
172   "name": "test-instance",
173   "os": "lenny-image",
174   "hypervisor": ("xen-pvm", {}),
175   "osparams":{},
176   "disks": [],
177 })
178 ARGS_COMPLETE = dict(ARGS_VBOX, **{
179   "beparams": {"vcpus":"1", "memory":"256", "auto_balance": False},
180   "disks": [(0,{"size":"5mb"})],
181   "nics": [("0",{"mode":"bridged"})],
182   "disk_template": "plain",
183   "tags": "test-tag-1,test-tag-2",
184 })
185 ARGS_BROKEN = dict(ARGS_EXPORT_DIR , **{
186   "no_nics": True,
187   "disk_template": "diskless",
188   "name": "test-instance",
189   "os": "lenny-image",
190   "osparams": {},
191 })
192
193 EXP_ARGS_COMPRESSED = dict(ARGS_EXPORT_DIR, **{
194   "compression": True,
195 })
196
197 EXP_DISKS_LIST = [
198   {
199     "format": "vmdk",
200     "compression": "gzip",
201     "virt-size": 90000,
202     "real-size": 203,
203     "path": "new_disk.cow.gz",
204   },
205   {
206     "format": "cow",
207     "virt-size": 15,
208     "real-size": 15,
209     "path": "new_disk.cow",
210   },
211 ]
212 EXP_NETWORKS_LIST = [
213   {"mac": "aa:00:00:d8:2c:1e", "ip":"None", "link":"br0",
214    "mode":"routed", "network": "test"},
215 ]
216 EXP_PARTIAL_GANETI_DICT = {
217   "hypervisor": {"name": "xen-kvm"},
218   "os": {"name": "lenny-image"},
219   "auto_balance": "True",
220   "version": "0",
221 }
222 EXP_GANETI_DICT = {
223   "tags": None,
224   "auto_balance": "False",
225   "hypervisor": {
226      "root-path": "/dev/sda",
227      "name": "xen-pvm",
228      "kernel_args": "ro"
229    },
230   "version": "0",
231   "disk_template": None,
232   "os": {"name": "lenny-image"}
233 }
234 EXP_NAME ="xen-dev-i1"
235 EXP_VCPUS = 1
236 EXP_MEMORY = 512
237
238 EXPORT_EMPTY = ("<Envelope xml:lang=\"en-US\" xmlns=\"http://schemas.dmtf.org/"
239                 "ovf/envelope/1\" xmlns:gnt=\"http://ganeti\" xmlns:ovf=\""
240                 "http://schemas.dmtf.org/ovf/envelope/1\" xmlns:rasd=\""
241                 "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_Resource"
242                 "AllocationSettingData\" xmlns:vssd=\"http://schemas.dmtf.org"
243                 "/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData\""
244                 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" />")
245 EXPORT_DISKS_EMPTY = ("<References /><DiskSection><Info>Virtual disk"
246                       " information</Info></DiskSection>")
247 EXPORT_DISKS = ("<References><File ovf:compression=\"gzip\" ovf:href=\"new_disk"
248                 ".cow.gz\" ovf:id=\"file0\" ovf:size=\"203\" /><File ovf:href="
249                 "\"new_disk.cow\" ovf:id=\"file1\" ovf:size=\"15\" />"
250                 "</References><DiskSection><Info>Virtual disk information"
251                 "</Info><Disk ovf:capacity=\"90000\" ovf:diskId=\"disk0\" ovf"
252                 ":fileRef=\"file0\" ovf:format=\"http://www.vmware.com/"
253                 "interfaces/specifications/vmdk.html#monolithicSparse\" /><Disk"
254                 " ovf:capacity=\"15\" ovf:diskId=\"disk1\" ovf:fileRef"
255                 "=\"file1\" ovf:format=\"http://www.gnome.org/~markmc/qcow"
256                 "-image-format.html\" /></DiskSection>")
257 EXPORT_NETWORKS_EMPTY = ("<NetworkSection><Info>List of logical networks</Info>"
258                          "</NetworkSection>")
259 EXPORT_NETWORKS = ("<NetworkSection><Info>List of logical networks</Info>"
260                    "<Network ovf:name=\"routed0\" /></NetworkSection>")
261 EXPORT_GANETI_INCOMPLETE = ("<gnt:GanetiSection><gnt:Version>0</gnt:Version>"
262                             "<gnt:AutoBalance>True</gnt:AutoBalance><gnt:"
263                             "OperatingSystem><gnt:Name>lenny-image</gnt:Name>"
264                             "<gnt:Parameters /></gnt:OperatingSystem><gnt:"
265                             "Hypervisor><gnt:Name>xen-kvm</gnt:Name><gnt:"
266                             "Parameters /></gnt:Hypervisor><gnt:Network><gnt:"
267                             "Nic ovf:name=\"routed0\"><gnt:Mode>routed</gnt:"
268                             "Mode><gnt:MACAddress>aa:00:00:d8:2c:1e</gnt:"
269                             "MACAddress><gnt:IPAddress>None</gnt:IPAddress>"
270                             "<gnt:Link>br0</gnt:Link><gnt:Net>test</gnt:Net>"
271                             "</gnt:Nic></gnt:Network></gnt:GanetiSection>")
272 EXPORT_GANETI = ("<gnt:GanetiSection><gnt:Version>0</gnt:Version><gnt:"
273                  "AutoBalance>False</gnt:AutoBalance><gnt:OperatingSystem>"
274                  "<gnt:Name>lenny-image</gnt:Name><gnt:Parameters /></gnt:"
275                  "OperatingSystem><gnt:Hypervisor><gnt:Name>xen-pvm</gnt:Name>"
276                  "<gnt:Parameters><gnt:root-path>/dev/sda</gnt:root-path><gnt:"
277                  "kernel_args>ro</gnt:kernel_args></gnt:Parameters></gnt:"
278                  "Hypervisor><gnt:Network><gnt:Nic ovf:name=\"routed0\"><gnt:"
279                  "Mode>routed</gnt:Mode><gnt:MACAddress>aa:00:00:d8:2c:1e</gnt:"
280                  "MACAddress><gnt:IPAddress>None</gnt:IPAddress><gnt:Link>br0"
281                  "</gnt:Link><gnt:Net>test</gnt:Net></gnt:Nic></gnt:Network>"
282                  "</gnt:GanetiSection>")
283 EXPORT_SYSTEM = ("<References><File ovf:compression=\"gzip\" ovf:href=\"new_"
284                  "disk.cow.gz\" ovf:id=\"file0\" ovf:size=\"203\" /><File ovf:"
285                  "href=\"new_disk.cow\" ovf:id=\"file1\" ovf:size=\"15\" />"
286                  "</References><DiskSection><Info>Virtual disk information"
287                  "</Info><Disk ovf:capacity=\"90000\" ovf:diskId=\"disk0\""
288                  " ovf:fileRef=\"file0\" ovf:format=\"http://www.vmware.com"
289                  "/interfaces/specifications/vmdk.html#monolithicSparse\" />"
290                  "<Disk ovf:capacity=\"15\" ovf:diskId=\"disk1\" ovf:fileRef"
291                  "=\"file1\" ovf:format=\"http://www.gnome.org/~markmc/qcow"
292                  "-image-format.html\" /></DiskSection><NetworkSection><Info>"
293                  "List of logical networks</Info><Network ovf:name=\"routed0\""
294                  " /></NetworkSection><VirtualSystem ovf:id=\"xen-dev-i1\">"
295                  "<Info>A virtual machine</Info><Name>xen-dev-i1</Name>"
296                  "<OperatingSystemSection ovf:id=\"0\"><Info>Installed guest"
297                  " operating system</Info></OperatingSystemSection><Virtual"
298                  "HardwareSection><Info>Virtual hardware requirements</Info>"
299                  "<System><vssd:ElementName>Virtual Hardware Family"
300                  "</vssd:ElementName><vssd:InstanceID>0</vssd:InstanceID><vssd:"
301                  "VirtualSystemIdentifier>xen-dev-i1</vssd:VirtualSystem"
302                  "Identifier><vssd:VirtualSystemType>ganeti-ovf</vssd:Virtual"
303                  "SystemType></System><Item><rasd:ElementName>1 virtual CPU(s)"
304                  "</rasd:ElementName><rasd:InstanceID>1</rasd:InstanceID><rasd:"
305                  "ResourceType>3</rasd:ResourceType><rasd:VirtualQuantity>1"
306                  "</rasd:VirtualQuantity></Item><Item><rasd:AllocationUnits>"
307                  "byte * 2^20</rasd:AllocationUnits><rasd:ElementName>512MB of"
308                  " memory</rasd:ElementName><rasd:InstanceID>2</rasd:"
309                  "InstanceID><rasd:ResourceType>4</rasd:ResourceType><rasd:"
310                  "VirtualQuantity>512</rasd:VirtualQuantity></Item><Item>"
311                  "<rasd:Address>0</rasd:Address><rasd:ElementName>scsi"
312                  "_controller0</rasd:ElementName><rasd:InstanceID>3"
313                  "</rasd:InstanceID><rasd:ResourceSubType>lsilogic</rasd"
314                  ":ResourceSubType><rasd:ResourceType>6</rasd:ResourceType>"
315                  "</Item><Item><rasd:ElementName>disk0</rasd:ElementName><rasd"
316                  ":HostResource>ovf:/disk/disk0</rasd:HostResource><rasd"
317                  ":InstanceID>4</rasd:InstanceID><rasd:Parent>3</rasd:Parent>"
318                  "<rasd:ResourceType>17</rasd:ResourceType></Item><Item><rasd:"
319                  "ElementName>disk1</rasd:ElementName><rasd:HostResource>ovf:/"
320                  "disk/disk1</rasd:HostResource><rasd:InstanceID>5</rasd"
321                  ":InstanceID><rasd:Parent>3</rasd:Parent><rasd:ResourceType>17"
322                  "</rasd:ResourceType></Item><Item><rasd:Address>aa:00"
323                  ":00:d8:2c:1e</rasd:Address><rasd:Connection>routed0</rasd"
324                  ":Connection><rasd:ElementName>routed0</rasd:ElementName><rasd"
325                  ":InstanceID>6</rasd:InstanceID><rasd:ResourceType>10</rasd"
326                  ":ResourceType></Item></VirtualHardwareSection>"
327                  "</VirtualSystem>")
328
329
330 def _GetArgs(args, with_name=False):
331   options = optparse.Values()
332   needed = args
333   if with_name:
334     needed["name"] = "test-instance"
335   options._update_loose(needed)
336   return options
337
338
339 OPTS_EMPTY = _GetArgs(ARGS_EMPTY)
340 OPTS_EXPORT_NO_NAME = _GetArgs(ARGS_EXPORT_DIR)
341 OPTS_EXPORT = _GetArgs(ARGS_EXPORT_DIR, with_name=True)
342
343 EXP_OPTS = OPTS_EXPORT_NO_NAME
344 EXP_OPTS_COMPRESSED = _GetArgs(EXP_ARGS_COMPRESSED)
345
346 OPTS_VBOX = _GetArgs(ARGS_VBOX)
347 OPTS_COMPLETE = _GetArgs(ARGS_COMPLETE)
348 OPTS_NONIC_NODISK = _GetArgs(ARGS_BROKEN)
349
350
351 def _GetFullFilename(file_name):
352   file_path = "%s/test/data/ovfdata/%s" % (testutils.GetSourceDir(),
353     file_name)
354   file_path = os.path.abspath(file_path)
355   return file_path
356
357
358 class BetterUnitTest(unittest.TestCase):
359   def assertRaisesRegexp(self, exception, regexp_val, function, *args):
360     try:
361       function(*args)
362       self.fail("Expected raising %s" % exception)
363     except exception, err:
364       regexp = re.compile(regexp_val)
365       if re.search(regexp, str(err)) == None:
366         self.fail("Expected matching '%s', got '%s'" %
367           (regexp_val, str(err)))
368
369
370 class TestOVFImporter(BetterUnitTest):
371   def setUp(self):
372     self.non_existing_file = _GetFullFilename("not_the_file.ovf")
373     self.ganeti_ovf = _GetFullFilename("ganeti.ovf")
374     self.virtualbox_ovf = _GetFullFilename("virtualbox.ovf")
375     self.ova_package = _GetFullFilename("ova.ova")
376     self.empty_ovf = _GetFullFilename("empty.ovf")
377     self.wrong_extension = _GetFullFilename("wrong_extension.ovd")
378     self.wrong_ova_archive = _GetFullFilename("wrong_ova.ova")
379     self.no_ovf_in_ova = _GetFullFilename("no_ovf.ova")
380     self.importer = None
381
382   def tearDown(self):
383     if self.importer:
384       self.importer.Cleanup()
385     del_dir = os.path.abspath(OUTPUT_DIR)
386     try:
387       shutil.rmtree(del_dir)
388     except OSError:
389       pass
390
391   def testFileDoesNotExistError(self):
392     self.assertRaisesRegexp(errors.OpPrereqError, "does not exist",
393       ovf.OVFImporter, self.non_existing_file, None)
394
395   def testWrongInputFileExtensionError(self):
396     self.assertRaisesRegexp(errors.OpPrereqError,
397       "Unknown file extension", ovf.OVFImporter,
398       self.wrong_extension, None)
399
400   def testOVAUnpackingDirectories(self):
401     self.importer = ovf.OVFImporter(self.ova_package, OPTS_EMPTY)
402     self.assertTrue(self.importer.input_dir != None)
403     self.assertEquals(self.importer.output_dir , pathutils.EXPORT_DIR)
404     self.assertTrue(self.importer.temp_dir != None)
405
406   def testOVFUnpackingDirectories(self):
407     self.importer = ovf.OVFImporter(self.virtualbox_ovf,
408       OPTS_EMPTY)
409     self.assertEquals(self.importer.input_dir , _GetFullFilename(""))
410     self.assertEquals(self.importer.output_dir , pathutils.EXPORT_DIR)
411     self.assertEquals(self.importer.temp_dir , None)
412
413   def testOVFSetOutputDirDirectories(self):
414     self.importer = ovf.OVFImporter(self.ganeti_ovf, OPTS_EXPORT)
415     self.assertEquals(self.importer.input_dir , _GetFullFilename(""))
416     self.assertTrue(OUTPUT_DIR in self.importer.output_dir)
417     self.assertEquals(self.importer.temp_dir , None)
418
419   def testWrongOVAArchiveError(self):
420     self.assertRaisesRegexp(errors.OpPrereqError, "not a proper tar",
421       ovf.OVFImporter, self.wrong_ova_archive, None)
422
423   def testNoOVFFileInOVAPackageError(self):
424     self.assertRaisesRegexp(errors.OpPrereqError, "No .ovf file",
425       ovf.OVFImporter, self.no_ovf_in_ova, None)
426
427   def testParseGanetiOvf(self):
428     self.importer = ovf.OVFImporter(self.ganeti_ovf, OPTS_EXPORT_NO_NAME)
429     self.importer.Parse()
430     self.assertTrue("%s/ganeti-test-xen" % OUTPUT_DIR in
431       self.importer.output_dir)
432     self.assertEqual(self.importer.results_disk, GANETI_DISKS)
433     self.assertEqual(self.importer.results_network, GANETI_NETWORKS)
434     self.assertEqual(self.importer.results_hypervisor, GANETI_HYPERVISOR)
435     self.assertEqual(self.importer.results_os, GANETI_OS)
436     self.assertEqual(self.importer.results_backend, GANETI_BACKEND)
437     self.assertEqual(self.importer.results_name, GANETI_NAME)
438     self.assertEqual(self.importer.results_template, GANETI_TEMPLATE)
439     self.assertEqual(self.importer.results_tags, GANETI_TAGS)
440     self.assertEqual(self.importer.results_version, GANETI_VERSION)
441
442   def testParseVirtualboxOvf(self):
443     self.importer = ovf.OVFImporter(self.virtualbox_ovf, OPTS_VBOX)
444     self.importer.Parse()
445     self.assertTrue("%s/test-instance" % OUTPUT_DIR in self.importer.output_dir)
446     self.assertEquals(self.importer.results_disk, VIRTUALBOX_DISKS)
447     self.assertEquals(self.importer.results_network, VIRTUALBOX_NETWORKS)
448     self.assertEquals(self.importer.results_hypervisor, CMDARGS_HYPERVISOR)
449     self.assertEquals(self.importer.results_os, CMDARGS_OS)
450     self.assertEquals(self.importer.results_backend, VIRTUALBOX_BACKEND)
451     self.assertEquals(self.importer.results_name, CMDARGS_NAME)
452     self.assertEquals(self.importer.results_template, VIRTUALBOX_TEMPLATE)
453     self.assertEqual(self.importer.results_tags, VIRTUALBOX_TAGS)
454     self.assertEqual(self.importer.results_version, constants.EXPORT_VERSION)
455
456   def testParseEmptyOvf(self):
457     self.importer = ovf.OVFImporter(self.empty_ovf, OPTS_COMPLETE)
458     self.importer.Parse()
459     self.assertTrue("%s/test-instance" % OUTPUT_DIR in self.importer.output_dir)
460     self.assertEquals(self.importer.results_disk, CMDARGS_DISKS)
461     self.assertEquals(self.importer.results_network, CMDARGS_NETWORKS)
462     self.assertEquals(self.importer.results_hypervisor, CMDARGS_HYPERVISOR)
463     self.assertEquals(self.importer.results_os, CMDARGS_OS)
464     self.assertEquals(self.importer.results_backend, CMDARGS_BACKEND)
465     self.assertEquals(self.importer.results_name, CMDARGS_NAME)
466     self.assertEquals(self.importer.results_template, CMDARGS_TEMPLATE)
467     self.assertEqual(self.importer.results_tags, CMDARGS_TAGS)
468     self.assertEqual(self.importer.results_version, constants.EXPORT_VERSION)
469
470   def testParseNameOptions(self):
471     self.importer = ovf.OVFImporter(self.empty_ovf, OPTS_COMPLETE)
472     results = self.importer._ParseNameOptions()
473     self.assertEquals(results, CMDARGS_NAME)
474
475   def testParseHypervisorOptions(self):
476     self.importer = ovf.OVFImporter(self.empty_ovf, OPTS_COMPLETE)
477     results = self.importer._ParseHypervisorOptions()
478     self.assertEquals(results, CMDARGS_HYPERVISOR)
479
480   def testParseOSOptions(self):
481     self.importer = ovf.OVFImporter(self.empty_ovf, OPTS_COMPLETE)
482     results = self.importer._ParseOSOptions()
483     self.assertEquals(results, CMDARGS_OS)
484
485   def testParseBackendOptions(self):
486     self.importer = ovf.OVFImporter(self.empty_ovf, OPTS_COMPLETE)
487     results = self.importer._ParseBackendOptions()
488     self.assertEquals(results, CMDARGS_BACKEND)
489
490   def testParseTags(self):
491     self.importer = ovf.OVFImporter(self.empty_ovf, OPTS_COMPLETE)
492     results = self.importer._ParseTags()
493     self.assertEquals(results, CMDARGS_TAGS)
494
495   def testParseNicOptions(self):
496     self.importer = ovf.OVFImporter(self.empty_ovf, OPTS_COMPLETE)
497     results = self.importer._ParseNicOptions()
498     self.assertEquals(results, CMDARGS_NETWORKS)
499
500   def testParseDiskOptionsFromGanetiOVF(self):
501     self.importer = ovf.OVFImporter(self.ganeti_ovf, OPTS_EXPORT)
502     os.mkdir(OUTPUT_DIR)
503     results = self.importer._GetDiskInfo()
504     self.assertEquals(results, GANETI_DISKS)
505
506   def testParseTemplateOptions(self):
507     self.importer = ovf.OVFImporter(self.empty_ovf, OPTS_COMPLETE)
508     results = self.importer._ParseTemplateOptions()
509     self.assertEquals(results, GANETI_TEMPLATE)
510
511   def testParseDiskOptionsFromCmdLine(self):
512     self.importer = ovf.OVFImporter(self.empty_ovf, OPTS_COMPLETE)
513     os.mkdir(OUTPUT_DIR)
514     results = self.importer._ParseDiskOptions()
515     self.assertEquals(results, CMDARGS_DISKS)
516
517   def testGetDiskFormat(self):
518     self.importer = ovf.OVFImporter(self.ganeti_ovf, OPTS_EXPORT)
519     disks_list = self.importer.ovf_reader.GetDisksNames()
520     results = [self.importer._GetDiskQemuInfo("%s/%s" %
521       (self.importer.input_dir, path), "file format: (\S+)")
522       for (path, _) in disks_list]
523     self.assertEqual(results, ["vmdk"])
524
525   def testNoInstanceNameOVF(self):
526     self.importer = ovf.OVFImporter(self.empty_ovf, OPTS_EXPORT_NO_NAME)
527     self.assertRaisesRegexp(errors.OpPrereqError, "Name of instance",
528       self.importer.Parse)
529
530   def testErrorNoOSNameOVF(self):
531     self.importer = ovf.OVFImporter(self.virtualbox_ovf, OPTS_EXPORT)
532     self.assertRaisesRegexp(errors.OpPrereqError, "OS name",
533       self.importer.Parse)
534
535   def testErrorNoDiskAndNoNetwork(self):
536     self.importer = ovf.OVFImporter(self.empty_ovf, OPTS_NONIC_NODISK)
537     self.assertRaisesRegexp(errors.OpPrereqError,
538       "Either disk specification or network"
539       " description", self.importer.Parse)
540
541
542 class TestOVFExporter(BetterUnitTest):
543   def setUp(self):
544     self.exporter = None
545     self.wrong_config_file = _GetFullFilename("wrong_config.ini")
546     self.unsafe_path_to_disk = _GetFullFilename("unsafe_path.ini")
547     self.disk_image_not_exist = _GetFullFilename("no_disk.ini")
548     self.empty_config = _GetFullFilename("empty.ini")
549     self.standard_export = _GetFullFilename("config.ini")
550     self.wrong_network_mode = self.disk_image_not_exist
551     self.no_memory = self.disk_image_not_exist
552     self.no_vcpus = self.disk_image_not_exist
553     self.no_os = _GetFullFilename("no_os.ini")
554     self.no_hypervisor = self.disk_image_not_exist
555
556   def tearDown(self):
557     if self.exporter:
558       self.exporter.Cleanup()
559     del_dir = os.path.abspath(OUTPUT_DIR)
560     try:
561       shutil.rmtree(del_dir)
562     except OSError:
563       pass
564
565   def testErrorWrongConfigFile(self):
566     self.assertRaisesRegexp(errors.OpPrereqError,
567       "Error when trying to read", ovf.OVFExporter,
568       self.wrong_config_file, EXP_OPTS)
569
570   def testErrorPathToTheDiskIncorrect(self):
571     self.exporter = ovf.OVFExporter(self.unsafe_path_to_disk, EXP_OPTS)
572     self.assertRaisesRegexp(errors.OpPrereqError, "contains a directory name",
573       self.exporter._ParseDisks)
574
575   def testErrorDiskImageNotExist(self):
576     self.exporter = ovf.OVFExporter(self.disk_image_not_exist, EXP_OPTS)
577     self.assertRaisesRegexp(errors.OpPrereqError, "Disk image does not exist",
578       self.exporter._ParseDisks)
579
580   def testParseNetworks(self):
581     self.exporter = ovf.OVFExporter(self.standard_export, EXP_OPTS)
582     results = self.exporter._ParseNetworks()
583     self.assertEqual(results, EXP_NETWORKS_LIST)
584
585   def testErrorWrongNetworkMode(self):
586     self.exporter = ovf.OVFExporter(self.wrong_network_mode, EXP_OPTS)
587     self.assertRaisesRegexp(errors.OpPrereqError,
588       "Network mode nic not recognized", self.exporter._ParseNetworks)
589
590   def testParseVCPusMem(self):
591     self.exporter = ovf.OVFExporter(self.standard_export, EXP_OPTS)
592     vcpus = self.exporter._ParseVCPUs()
593     memory = self.exporter._ParseMemory()
594     self.assertEqual(vcpus, EXP_VCPUS)
595     self.assertEqual(memory, EXP_MEMORY)
596
597   def testErrorNoVCPUs(self):
598     self.exporter = ovf.OVFExporter(self.no_vcpus, EXP_OPTS)
599     self.assertRaisesRegexp(errors.OpPrereqError, "No CPU information found",
600       self.exporter._ParseVCPUs)
601
602   def testErrorNoMemory(self):
603     self.exporter = ovf.OVFExporter(self.no_memory, EXP_OPTS)
604     self.assertRaisesRegexp(errors.OpPrereqError, "No memory information found",
605       self.exporter._ParseMemory)
606
607   def testParseGaneti(self):
608     self.exporter = ovf.OVFExporter(self.standard_export, EXP_OPTS)
609     results = self.exporter._ParseGaneti()
610     self.assertEqual(results, EXP_GANETI_DICT)
611
612   def testErrorNoHypervisor(self):
613     self.exporter = ovf.OVFExporter(self.no_hypervisor, EXP_OPTS)
614     self.assertRaisesRegexp(errors.OpPrereqError,
615       "No hypervisor information found", self.exporter._ParseGaneti)
616
617   def testErrorNoOS(self):
618     self.exporter = ovf.OVFExporter(self.no_os, EXP_OPTS)
619     self.assertRaisesRegexp(errors.OpPrereqError,
620       "No operating system information found", self.exporter._ParseGaneti)
621
622   def testErrorParseNoInstanceName(self):
623     self.exporter = ovf.OVFExporter(self.empty_config, EXP_OPTS)
624     self.assertRaisesRegexp(errors.OpPrereqError, "No instance name found",
625       self.exporter.Parse)
626
627
628 class TestOVFReader(BetterUnitTest):
629   def setUp(self):
630     self.wrong_xml_file = _GetFullFilename("wrong_xml.ovf")
631     self.ganeti_ovf = _GetFullFilename("ganeti.ovf")
632     self.virtualbox_ovf = _GetFullFilename("virtualbox.ovf")
633     self.corrupted_ovf = _GetFullFilename("corrupted_resources.ovf")
634     self.wrong_manifest_ovf = _GetFullFilename("wrong_manifest.ovf")
635     self.no_disk_in_ref_ovf = _GetFullFilename("no_disk_in_ref.ovf")
636     self.empty_ovf = _GetFullFilename("empty.ovf")
637     self.compressed_disk = _GetFullFilename("gzip_disk.ovf")
638
639   def tearDown(self):
640     pass
641
642   def testXMLParsingError(self):
643     self.assertRaisesRegexp(errors.OpPrereqError,
644       "Error while reading .ovf", ovf.OVFReader, self.wrong_xml_file)
645
646   def testFileInResourcesDoesNotExistError(self):
647     self.assertRaisesRegexp(errors.OpPrereqError, "does not exist",
648       ovf.OVFReader, self.corrupted_ovf)
649
650   def testWrongManifestChecksumError(self):
651     reader = ovf.OVFReader(self.wrong_manifest_ovf)
652     self.assertRaisesRegexp(errors.OpPrereqError,
653       "does not match the value in manifest file", reader.VerifyManifest)
654
655   def testGoodManifestChecksum(self):
656     reader = ovf.OVFReader(self.ganeti_ovf)
657     self.assertEqual(reader.VerifyManifest(), None)
658
659   def testGetDisksNamesOVFCorruptedError(self):
660     reader = ovf.OVFReader(self.no_disk_in_ref_ovf)
661     self.assertRaisesRegexp(errors.OpPrereqError,
662       "not found in references", reader.GetDisksNames)
663
664   def testGetDisksNamesVirtualbox(self):
665     reader = ovf.OVFReader(self.virtualbox_ovf)
666     disk_names = reader.GetDisksNames()
667     expected_names = [
668       ("new_disk.vmdk", None) ,
669       ("second_disk.vmdk", None),
670     ]
671     self.assertEqual(sorted(disk_names), sorted(expected_names))
672
673   def testGetDisksNamesEmpty(self):
674     reader = ovf.OVFReader(self.empty_ovf)
675     disk_names = reader.GetDisksNames()
676     self.assertEqual(disk_names, [])
677
678   def testGetDisksNamesCompressed(self):
679     reader = ovf.OVFReader(self.compressed_disk)
680     disk_names = reader.GetDisksNames()
681     self.assertEqual(disk_names, [("compr_disk.vmdk.gz", "gzip")])
682
683   def testGetNetworkDataGaneti(self):
684     reader = ovf.OVFReader(self.ganeti_ovf)
685     networks = reader.GetNetworkData()
686     self.assertEqual(networks, GANETI_NETWORKS)
687
688   def testGetNetworkDataVirtualbox(self):
689     reader = ovf.OVFReader(self.virtualbox_ovf)
690     networks = reader.GetNetworkData()
691     self.assertEqual(networks, VIRTUALBOX_NETWORKS)
692
693   def testGetNetworkDataEmpty(self):
694     reader = ovf.OVFReader(self.empty_ovf)
695     networks = reader.GetNetworkData()
696     self.assertEqual(networks, EMPTY_NETWORKS)
697
698   def testGetHypervisorDataGaneti(self):
699     reader = ovf.OVFReader(self.ganeti_ovf)
700     hypervisor = reader.GetHypervisorData()
701     self.assertEqual(hypervisor, GANETI_HYPERVISOR)
702
703   def testGetHypervisorDataEmptyOvf(self):
704     reader = ovf.OVFReader(self.empty_ovf)
705     hypervisor = reader.GetHypervisorData()
706     self.assertEqual(hypervisor, EMPTY_HYPERVISOR)
707
708   def testGetOSDataGaneti(self):
709     reader = ovf.OVFReader(self.ganeti_ovf)
710     osys = reader.GetOSData()
711     self.assertEqual(osys, GANETI_OS)
712
713   def testGetOSDataEmptyOvf(self):
714     reader = ovf.OVFReader(self.empty_ovf)
715     osys = reader.GetOSData()
716     self.assertEqual(osys, EMPTY_OS)
717
718   def testGetBackendDataGaneti(self):
719     reader = ovf.OVFReader(self.ganeti_ovf)
720     backend = reader.GetBackendData()
721     self.assertEqual(backend, GANETI_BACKEND)
722
723   def testGetBackendDataVirtualbox(self):
724     reader = ovf.OVFReader(self.virtualbox_ovf)
725     backend = reader.GetBackendData()
726     self.assertEqual(backend, VIRTUALBOX_BACKEND)
727
728   def testGetBackendDataEmptyOvf(self):
729     reader = ovf.OVFReader(self.empty_ovf)
730     backend = reader.GetBackendData()
731     self.assertEqual(backend, EMPTY_BACKEND)
732
733   def testGetInstanceNameGaneti(self):
734     reader = ovf.OVFReader(self.ganeti_ovf)
735     name = reader.GetInstanceName()
736     self.assertEqual(name, GANETI_NAME)
737
738   def testGetInstanceNameDataEmptyOvf(self):
739     reader = ovf.OVFReader(self.empty_ovf)
740     name = reader.GetInstanceName()
741     self.assertEqual(name, EMPTY_NAME)
742
743   def testGetDiskTemplateGaneti(self):
744     reader = ovf.OVFReader(self.ganeti_ovf)
745     name = reader.GetDiskTemplate()
746     self.assertEqual(name, GANETI_TEMPLATE)
747
748   def testGetDiskTemplateEmpty(self):
749     reader = ovf.OVFReader(self.empty_ovf)
750     name = reader.GetDiskTemplate()
751     self.assertEqual(name, EMPTY_TEMPLATE)
752
753   def testGetTagsGaneti(self):
754     reader = ovf.OVFReader(self.ganeti_ovf)
755     tags = reader.GetTagsData()
756     self.assertEqual(tags, GANETI_TAGS)
757
758   def testGetTagsEmpty(self):
759     reader = ovf.OVFReader(self.empty_ovf)
760     tags = reader.GetTagsData()
761     self.assertEqual(tags, EMPTY_TAGS)
762
763   def testGetVersionGaneti(self):
764     reader = ovf.OVFReader(self.ganeti_ovf)
765     version = reader.GetVersionData()
766     self.assertEqual(version, GANETI_VERSION)
767
768   def testGetVersionEmpty(self):
769     reader = ovf.OVFReader(self.empty_ovf)
770     version = reader.GetVersionData()
771     self.assertEqual(version, EMPTY_VERSION)
772
773
774 class TestOVFWriter(BetterUnitTest):
775   def setUp(self):
776     self.writer = ovf.OVFWriter(True)
777
778   def tearDown(self):
779     pass
780
781   def testOVFWriterInit(self):
782     result = ET.tostring(self.writer.tree)
783     self.assertTrue(EXPORT_EMPTY in result)
784
785   def testSaveDisksDataEmpty(self):
786     self.writer.SaveDisksData([])
787     result = ET.tostring(self.writer.tree)
788     self.assertTrue(EXPORT_DISKS_EMPTY in result)
789
790   def testSaveDisksData(self):
791     self.writer.SaveDisksData(EXP_DISKS_LIST)
792     result = ET.tostring(self.writer.tree)
793     self.assertTrue(EXPORT_DISKS in result)
794
795   def testSaveNetworkDataEmpty(self):
796     self.writer.SaveNetworksData([])
797     result = ET.tostring(self.writer.tree)
798     self.assertTrue(EXPORT_NETWORKS_EMPTY in result)
799
800   def testSaveNetworksData(self):
801     self.writer.SaveNetworksData(EXP_NETWORKS_LIST)
802     result = ET.tostring(self.writer.tree)
803     self.assertTrue(EXPORT_NETWORKS in result)
804
805   def testSaveGanetiDataIncomplete(self):
806     self.writer.SaveGanetiData(EXP_PARTIAL_GANETI_DICT, EXP_NETWORKS_LIST)
807     result = ET.tostring(self.writer.tree)
808     self.assertTrue(EXPORT_GANETI_INCOMPLETE in result)
809
810   def testSaveGanetiDataComplete(self):
811     self.writer.SaveGanetiData(EXP_GANETI_DICT, EXP_NETWORKS_LIST)
812     result = ET.tostring(self.writer.tree)
813     self.assertTrue(EXPORT_GANETI in result)
814
815   def testSaveVirtualSystem(self):
816     self.writer.SaveDisksData(EXP_DISKS_LIST)
817     self.writer.SaveNetworksData(EXP_NETWORKS_LIST)
818     self.writer.SaveVirtualSystemData(EXP_NAME, EXP_VCPUS, EXP_MEMORY)
819     result = ET.tostring(self.writer.tree)
820     self.assertTrue(EXPORT_SYSTEM in result)
821
822
823 if __name__ == "__main__":
824   testutils.GanetiTestProgram()