32 |
32 |
import tempfile
|
33 |
33 |
import unittest
|
34 |
34 |
|
|
35 |
try:
|
|
36 |
import xml.etree.ElementTree as ET
|
|
37 |
except ImportError:
|
|
38 |
import elementtree.ElementTree as ET
|
|
39 |
|
35 |
40 |
from ganeti import constants
|
36 |
41 |
from ganeti import errors
|
37 |
42 |
from ganeti import ovf
|
... | ... | |
143 |
148 |
"nics": [],
|
144 |
149 |
"disks": [],
|
145 |
150 |
"name": "test-instance",
|
|
151 |
"ova_package": False,
|
|
152 |
"ext_usage": False,
|
|
153 |
"disk_format": "cow",
|
|
154 |
"compression": False,
|
146 |
155 |
}
|
147 |
156 |
ARGS_EXPORT_DIR = dict(ARGS_EMPTY, **{
|
148 |
157 |
"output_dir": OUTPUT_DIR,
|
... | ... | |
177 |
186 |
"osparams": {},
|
178 |
187 |
})
|
179 |
188 |
|
|
189 |
EXP_ARGS_COMPRESSED = dict(ARGS_EXPORT_DIR, **{
|
|
190 |
"compression": True,
|
|
191 |
})
|
|
192 |
|
|
193 |
EXP_DISKS_LIST = [
|
|
194 |
{
|
|
195 |
"format": "vmdk",
|
|
196 |
"compression": "gzip",
|
|
197 |
"virt-size": 90000,
|
|
198 |
"real-size": 203,
|
|
199 |
"path": "new_disk.cow.gz",
|
|
200 |
},
|
|
201 |
{
|
|
202 |
"format": "cow",
|
|
203 |
"virt-size": 15,
|
|
204 |
"real-size": 15,
|
|
205 |
"path": "new_disk.cow",
|
|
206 |
},
|
|
207 |
]
|
|
208 |
EXP_NETWORKS_LIST = [
|
|
209 |
{"mac": "aa:00:00:d8:2c:1e", "ip":"None", "link":"br0","mode":"routed"},
|
|
210 |
]
|
|
211 |
EXP_PARTIAL_GANETI_DICT = {
|
|
212 |
"hypervisor": {"name": "xen-kvm"},
|
|
213 |
"os": {"name": "lenny-image"},
|
|
214 |
"auto_balance": "True",
|
|
215 |
"version": "0",
|
|
216 |
}
|
|
217 |
EXP_GANETI_DICT = {
|
|
218 |
'tags': None,
|
|
219 |
'auto_balance': 'False',
|
|
220 |
'hypervisor': {
|
|
221 |
'root-path': '/dev/sda',
|
|
222 |
'name': 'xen-pvm',
|
|
223 |
'kernel_args': 'ro'
|
|
224 |
},
|
|
225 |
'version': '0',
|
|
226 |
'disk_template': None,
|
|
227 |
'os': {'name': 'lenny-image'}
|
|
228 |
}
|
|
229 |
EXP_NAME ="xen-dev-i1"
|
|
230 |
EXP_VCPUS = 1
|
|
231 |
EXP_MEMORY = 512
|
|
232 |
|
|
233 |
EXPORT_EMPTY = ("<Envelope xml:lang=\"en-US\" xmlns=\"http://schemas.dmtf.org/"
|
|
234 |
"ovf/envelope/1\" xmlns:gnt=\"http://ganeti\" xmlns:ovf=\""
|
|
235 |
"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:rasd=\""
|
|
236 |
"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_Resource"
|
|
237 |
"AllocationSettingData\" xmlns:vssd=\"http://schemas.dmtf.org"
|
|
238 |
"/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData\""
|
|
239 |
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" />")
|
|
240 |
EXPORT_DISKS_EMPTY = "<References /><DiskSection />"
|
|
241 |
EXPORT_DISKS = ("<References><File ovf:compression=\"gzip\" ovf:href=\"new_disk"
|
|
242 |
".cow.gz\" ovf:id=\"file0\" ovf:size=\"203\" /><File ovf:href="
|
|
243 |
"\"new_disk.cow\" ovf:id=\"file1\" ovf:size=\"15\" />"
|
|
244 |
"</References><DiskSection><Disk ovf:capacity=\"90000\""
|
|
245 |
" ovf:diskId=\"disk0\" ovf:fileRef=\"file0\" ovf:format=\"http"
|
|
246 |
"://www.vmware.com/interfaces/specifications/vmdk.html"
|
|
247 |
"#monolithicSparse\" /><Disk ovf:capacity=\"15\" ovf:diskId="
|
|
248 |
"\"disk1\" ovf:fileRef=\"file1\" ovf:format=\"http://www.gnome"
|
|
249 |
".org/~markmc/qcow-image-format.html\" /></DiskSection>")
|
|
250 |
EXPORT_NETWORKS_EMPTY = "<NetworkSection />"
|
|
251 |
EXPORT_NETWORKS = ("<NetworkSection><Network ovf:name=\"routed0\" />"
|
|
252 |
"</NetworkSection>")
|
|
253 |
EXPORT_GANETI_INCOMPLETE = ("<gnt:GanetiSection><gnt:Version>0</gnt:Version>"
|
|
254 |
"<gnt:AutoBalance>True</gnt:AutoBalance><gnt:"
|
|
255 |
"OperatingSystem><gnt:Name>lenny-image</gnt:Name>"
|
|
256 |
"<gnt:Parameters /></gnt:OperatingSystem><gnt:"
|
|
257 |
"Hypervisor><gnt:Name>xen-kvm</gnt:Name><gnt:"
|
|
258 |
"Parameters /></gnt:Hypervisor><gnt:Network><gnt:"
|
|
259 |
"Nic ovf:name=\"routed0\"><gnt:Mode>routed</gnt:"
|
|
260 |
"Mode><gnt:MACAddress>aa:00:00:d8:2c:1e</gnt:"
|
|
261 |
"MACAddress><gnt:IPAddress>None</gnt:IPAddress>"
|
|
262 |
"<gnt:Link>br0</gnt:Link></gnt:Nic></gnt:Network>"
|
|
263 |
"</gnt:GanetiSection>")
|
|
264 |
EXPORT_GANETI = ("<gnt:GanetiSection><gnt:Version>0</gnt:Version><gnt:"
|
|
265 |
"AutoBalance>False</gnt:AutoBalance><gnt:OperatingSystem>"
|
|
266 |
"<gnt:Name>lenny-image</gnt:Name><gnt:Parameters /></gnt:"
|
|
267 |
"OperatingSystem><gnt:Hypervisor><gnt:Name>xen-pvm</gnt:Name>"
|
|
268 |
"<gnt:Parameters><gnt:root-path>/dev/sda</gnt:root-path><gnt:"
|
|
269 |
"kernel_args>ro</gnt:kernel_args></gnt:Parameters></gnt:"
|
|
270 |
"Hypervisor><gnt:Network><gnt:Nic ovf:name=\"routed0\"><gnt:"
|
|
271 |
"Mode>routed</gnt:Mode><gnt:MACAddress>aa:00:00:d8:2c:1e</gnt:"
|
|
272 |
"MACAddress><gnt:IPAddress>None</gnt:IPAddress><gnt:Link>br0"
|
|
273 |
"</gnt:Link></gnt:Nic></gnt:Network></gnt:GanetiSection>")
|
|
274 |
EXPORT_SYSTEM = ("<References><File ovf:compression=\"gzip\" ovf:href=\"new_"
|
|
275 |
"disk.cow.gz\" ovf:id=\"file0\" ovf:size=\"203\" /><File ovf:"
|
|
276 |
"href=\"new_disk.cow\" ovf:id=\"file1\" ovf:size=\"15\" />"
|
|
277 |
"</References><DiskSection><Disk ovf:capacity=\"90000\" ovf:"
|
|
278 |
"diskId=\"disk0\" ovf:fileRef=\"file0\" ovf:format=\"http://"
|
|
279 |
"www.vmware.com/interfaces/specifications/vmdk.html#monolithic"
|
|
280 |
"Sparse\" /><Disk ovf:capacity=\"15\" ovf:diskId=\"disk1\""
|
|
281 |
" ovf:fileRef=\"file1\" ovf:format=\"http://www.gnome.org/"
|
|
282 |
"~markmc/qcow-image-format.html\" /></DiskSection><Network"
|
|
283 |
"Section><Network ovf:name=\"routed0\" /></NetworkSection>"
|
|
284 |
"<VirtualSystem ovf:id=\"xen-dev-i1\"><Name>xen-dev-i1</Name>"
|
|
285 |
"<OperatingSystemSection ovf:id=\"0\" /><VirtualHardware"
|
|
286 |
"Section><System><vssd:ElementName>Virtual Hardware Family"
|
|
287 |
"</vssd:ElementName><vssd:InstanceId>0</vssd:InstanceId><vssd:"
|
|
288 |
"VirtualSystemIdentifier>xen-dev-i1</vssd:VirtualSystem"
|
|
289 |
"Identifier><vssd:VirtualSystemType>ganeti-ovf</vssd:Virtual"
|
|
290 |
"SystemType></System><Item><rasd:ElementName>1 virtual CPU(s)"
|
|
291 |
"</rasd:ElementName><rasd:InstanceID>1</rasd:InstanceID><rasd:"
|
|
292 |
"ResourceType>3</rasd:ResourceType><rasd:VirtualQuantity>1"
|
|
293 |
"</rasd:VirtualQuantity></Item><Item><rasd:AllocationUnits>"
|
|
294 |
"byte * 2^20</rasd:AllocationUnits><rasd:ElementName>512MB of"
|
|
295 |
" memory</rasd:ElementName><rasd:InstanceID>2</rasd:"
|
|
296 |
"InstanceID><rasd:ResourceType>4</rasd:ResourceType><rasd:"
|
|
297 |
"VirtualQuantity>512</rasd:VirtualQuantity></Item><Item>"
|
|
298 |
"<rasd:Address>0</rasd:Address><rasd:ElementName>scsi"
|
|
299 |
"_controller0</rasd:ElementName><rasd:ResourceType>6</rasd"
|
|
300 |
":ResourceType><rasd:InstanceId>3</rasd:InstanceId></Item>"
|
|
301 |
"<Item><rasd:ElementName>disk0</rasd:ElementName><rasd:"
|
|
302 |
"ResourceType>17</rasd:ResourceType><rasd:HostResource>ovf:/"
|
|
303 |
"disk/disk0</rasd:HostResource><rasd:Parent>3</rasd:Parent>"
|
|
304 |
"<rasd:InstanceID>4</rasd:InstanceID></Item><Item><rasd:"
|
|
305 |
"ElementName>disk1</rasd:ElementName><rasd:ResourceType>17"
|
|
306 |
"</rasd:ResourceType><rasd:HostResource>ovf:/disk/disk1</rasd:"
|
|
307 |
"HostResource><rasd:Parent>3</rasd:Parent><rasd:InstanceID>5"
|
|
308 |
"</rasd:InstanceID></Item><Item><rasd:ElementName>routed0"
|
|
309 |
"</rasd:ElementName><rasd:ResourceType>10</rasd:ResourceType>"
|
|
310 |
"<rasd:Connection>routed0</rasd:Connection><rasd:Address>aa:00"
|
|
311 |
":00:d8:2c:1e</rasd:Address><rasd:InstanceID>6</rasd:Instance"
|
|
312 |
"ID></Item></VirtualHardwareSection></VirtualSystem>")
|
|
313 |
|
180 |
314 |
|
181 |
315 |
def _GetArgs(args, with_name=False):
|
182 |
316 |
options = optparse.Values()
|
... | ... | |
190 |
324 |
OPTS_EMPTY = _GetArgs(ARGS_EMPTY)
|
191 |
325 |
OPTS_EXPORT_NO_NAME = _GetArgs(ARGS_EXPORT_DIR)
|
192 |
326 |
OPTS_EXPORT = _GetArgs(ARGS_EXPORT_DIR, with_name=True)
|
|
327 |
|
|
328 |
EXP_OPTS = OPTS_EXPORT_NO_NAME
|
|
329 |
EXP_OPTS_COMPRESSED = _GetArgs(EXP_ARGS_COMPRESSED)
|
|
330 |
|
193 |
331 |
OPTS_VBOX = _GetArgs(ARGS_VBOX)
|
194 |
332 |
OPTS_COMPLETE = _GetArgs(ARGS_COMPLETE)
|
195 |
333 |
OPTS_NONIC_NODISK = _GetArgs(ARGS_BROKEN)
|
... | ... | |
386 |
524 |
" description", self.importer.Parse)
|
387 |
525 |
|
388 |
526 |
|
|
527 |
class TestOVFExporter(BetterUnitTest):
|
|
528 |
def setUp(self):
|
|
529 |
self.exporter = None
|
|
530 |
self.wrong_config_file = _GetFullFilename("wrong_config.ini")
|
|
531 |
self.unsafe_path_to_disk = _GetFullFilename("unsafe_path.ini")
|
|
532 |
self.disk_image_not_exist = _GetFullFilename("no_disk.ini")
|
|
533 |
self.empty_config = _GetFullFilename("empty.ini")
|
|
534 |
self.standard_export = _GetFullFilename("config.ini")
|
|
535 |
self.wrong_network_mode = self.disk_image_not_exist
|
|
536 |
self.no_memory = self.disk_image_not_exist
|
|
537 |
self.no_vcpus = self.disk_image_not_exist
|
|
538 |
self.no_os = _GetFullFilename("no_os.ini")
|
|
539 |
self.no_hypervisor = self.disk_image_not_exist
|
|
540 |
|
|
541 |
def tearDown(self):
|
|
542 |
if self.exporter:
|
|
543 |
self.exporter.Cleanup()
|
|
544 |
del_dir = os.path.abspath(OUTPUT_DIR)
|
|
545 |
try:
|
|
546 |
shutil.rmtree(del_dir)
|
|
547 |
except OSError:
|
|
548 |
pass
|
|
549 |
|
|
550 |
def testErrorWrongConfigFile(self):
|
|
551 |
self.assertRaisesRegexp(errors.OpPrereqError,
|
|
552 |
"Error when trying to read", ovf.OVFExporter,
|
|
553 |
self.wrong_config_file, EXP_OPTS)
|
|
554 |
|
|
555 |
def testErrorPathToTheDiskIncorrect(self):
|
|
556 |
self.exporter = ovf.OVFExporter(self.unsafe_path_to_disk, EXP_OPTS)
|
|
557 |
self.assertRaisesRegexp(errors.OpPrereqError, "contains a directory name",
|
|
558 |
self.exporter._ParseDisks)
|
|
559 |
|
|
560 |
def testErrorDiskImageNotExist(self):
|
|
561 |
self.exporter = ovf.OVFExporter(self.disk_image_not_exist, EXP_OPTS)
|
|
562 |
self.assertRaisesRegexp(errors.OpPrereqError, "Disk image does not exist",
|
|
563 |
self.exporter._ParseDisks)
|
|
564 |
|
|
565 |
def testParseNetworks(self):
|
|
566 |
self.exporter = ovf.OVFExporter(self.standard_export, EXP_OPTS)
|
|
567 |
results = self.exporter._ParseNetworks()
|
|
568 |
self.assertEqual(results, EXP_NETWORKS_LIST)
|
|
569 |
|
|
570 |
def testErrorWrongNetworkMode(self):
|
|
571 |
self.exporter = ovf.OVFExporter(self.wrong_network_mode, EXP_OPTS)
|
|
572 |
self.assertRaisesRegexp(errors.OpPrereqError,
|
|
573 |
"Network mode nic not recognized", self.exporter._ParseNetworks)
|
|
574 |
|
|
575 |
def testParseVCPusMem(self):
|
|
576 |
self.exporter = ovf.OVFExporter(self.standard_export, EXP_OPTS)
|
|
577 |
vcpus = self.exporter._ParseVCPUs()
|
|
578 |
memory = self.exporter._ParseMemory()
|
|
579 |
self.assertEqual(vcpus, EXP_VCPUS)
|
|
580 |
self.assertEqual(memory, EXP_MEMORY)
|
|
581 |
|
|
582 |
def testErrorNoVCPUs(self):
|
|
583 |
self.exporter = ovf.OVFExporter(self.no_vcpus, EXP_OPTS)
|
|
584 |
self.assertRaisesRegexp(errors.OpPrereqError, "No CPU information found",
|
|
585 |
self.exporter._ParseVCPUs)
|
|
586 |
|
|
587 |
def testErrorNoMemory(self):
|
|
588 |
self.exporter = ovf.OVFExporter(self.no_memory, EXP_OPTS)
|
|
589 |
self.assertRaisesRegexp(errors.OpPrereqError, "No memory information found",
|
|
590 |
self.exporter._ParseMemory)
|
|
591 |
|
|
592 |
def testParseGaneti(self):
|
|
593 |
self.exporter = ovf.OVFExporter(self.standard_export, EXP_OPTS)
|
|
594 |
results = self.exporter._ParseGaneti()
|
|
595 |
self.assertEqual(results, EXP_GANETI_DICT)
|
|
596 |
|
|
597 |
def testErrorNoHypervisor(self):
|
|
598 |
self.exporter = ovf.OVFExporter(self.no_hypervisor, EXP_OPTS)
|
|
599 |
self.assertRaisesRegexp(errors.OpPrereqError,
|
|
600 |
"No hypervisor information found", self.exporter._ParseGaneti)
|
|
601 |
|
|
602 |
def testErrorNoOS(self):
|
|
603 |
self.exporter = ovf.OVFExporter(self.no_os, EXP_OPTS)
|
|
604 |
self.assertRaisesRegexp(errors.OpPrereqError,
|
|
605 |
"No operating system information found", self.exporter._ParseGaneti)
|
|
606 |
|
|
607 |
def testErrorParseNoInstanceName(self):
|
|
608 |
self.exporter = ovf.OVFExporter(self.empty_config, EXP_OPTS)
|
|
609 |
self.assertRaisesRegexp(errors.OpPrereqError, "No instance name found",
|
|
610 |
self.exporter.Parse)
|
|
611 |
|
|
612 |
|
389 |
613 |
class TestOVFReader(BetterUnitTest):
|
390 |
614 |
def setUp(self):
|
391 |
615 |
self.wrong_xml_file = _GetFullFilename("wrong_xml.ovf")
|
... | ... | |
532 |
756 |
self.assertEqual(version, EMPTY_VERSION)
|
533 |
757 |
|
534 |
758 |
|
|
759 |
class TestOVFWriter(BetterUnitTest):
|
|
760 |
def setUp(self):
|
|
761 |
self.writer = ovf.OVFWriter(True)
|
|
762 |
|
|
763 |
def tearDown(self):
|
|
764 |
pass
|
|
765 |
|
|
766 |
def testOVFWriterInit(self):
|
|
767 |
result = ET.tostring(self.writer.tree)
|
|
768 |
self.assertTrue(EXPORT_EMPTY in result)
|
|
769 |
|
|
770 |
def testSaveDisksDataEmpty(self):
|
|
771 |
self.writer.SaveDisksData([])
|
|
772 |
result = ET.tostring(self.writer.tree)
|
|
773 |
self.assertTrue(EXPORT_DISKS_EMPTY in result)
|
|
774 |
|
|
775 |
def testSaveDisksData(self):
|
|
776 |
self.writer.SaveDisksData(EXP_DISKS_LIST)
|
|
777 |
result = ET.tostring(self.writer.tree)
|
|
778 |
self.assertTrue(EXPORT_DISKS in result)
|
|
779 |
|
|
780 |
def testSaveNetworkDataEmpty(self):
|
|
781 |
self.writer.SaveNetworksData([])
|
|
782 |
result = ET.tostring(self.writer.tree)
|
|
783 |
self.assertTrue(EXPORT_NETWORKS_EMPTY in result)
|
|
784 |
|
|
785 |
def testSaveNetworksData(self):
|
|
786 |
self.writer.SaveNetworksData(EXP_NETWORKS_LIST)
|
|
787 |
result = ET.tostring(self.writer.tree)
|
|
788 |
self.assertTrue(EXPORT_NETWORKS in result)
|
|
789 |
|
|
790 |
def testSaveGanetiDataIncomplete(self):
|
|
791 |
self.writer.SaveGanetiData(EXP_PARTIAL_GANETI_DICT, EXP_NETWORKS_LIST)
|
|
792 |
result = ET.tostring(self.writer.tree)
|
|
793 |
self.assertTrue(EXPORT_GANETI_INCOMPLETE in result)
|
|
794 |
|
|
795 |
def testSaveGanetiDataComplete(self):
|
|
796 |
self.writer.SaveGanetiData(EXP_GANETI_DICT, EXP_NETWORKS_LIST)
|
|
797 |
result = ET.tostring(self.writer.tree)
|
|
798 |
self.assertTrue(EXPORT_GANETI in result)
|
|
799 |
|
|
800 |
def testSaveVirtualSystem(self):
|
|
801 |
self.writer.SaveDisksData(EXP_DISKS_LIST)
|
|
802 |
self.writer.SaveNetworksData(EXP_NETWORKS_LIST)
|
|
803 |
self.writer.SaveVirtualSystemData(EXP_NAME, EXP_VCPUS, EXP_MEMORY)
|
|
804 |
result = ET.tostring(self.writer.tree)
|
|
805 |
self.assertTrue(EXPORT_SYSTEM in result)
|
|
806 |
|
|
807 |
|
535 |
808 |
if __name__ == "__main__":
|
536 |
809 |
testutils.GanetiTestProgram()
|