4 # Copyright (C) 2010 Google Inc.
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.
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.
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
22 """Script for unittesting the RAPI rlib2 module
30 from ganeti import constants
31 from ganeti import opcodes
32 from ganeti import compat
33 from ganeti import http
34 from ganeti import query
36 from ganeti.rapi import rlib2
41 class TestConstants(unittest.TestCase):
42 def testConsole(self):
43 # Exporting the console field without authentication might expose
45 assert "console" in query.INSTANCE_FIELDS
46 self.assertTrue("console" not in rlib2.I_FIELDS)
49 class TestParseInstanceCreateRequestVersion1(testutils.GanetiTestCase):
51 testutils.GanetiTestCase.setUp(self)
53 self.Parse = rlib2._ParseInstanceCreateRequestVersion1
61 [{"size": 5, }, {"size": 100, }],
64 [{"size": 123, "mode": constants.DISK_RDWR, }],
76 { "ip": "192.0.2.6", "mode": constants.NIC_MODE_ROUTED,
77 "mac": "01:23:45:67:68:9A",
79 { "mode": constants.NIC_MODE_BRIDGED, "link": "br1" },
86 { constants.BE_VCPUS: 2, },
87 { constants.BE_MEMORY: 123, },
88 { constants.BE_VCPUS: 2,
89 constants.BE_MEMORY: 1024,
90 constants.BE_AUTO_BALANCE: True, }
95 { constants.HV_BOOT_ORDER: "anc", },
96 { constants.HV_KERNEL_PATH: "/boot/fookernel",
97 constants.HV_ROOT_PATH: "/dev/hda1", },
100 for mode in [constants.INSTANCE_CREATE, constants.INSTANCE_IMPORT]:
101 for nics in nic_variants:
102 for disk_template in constants.DISK_TEMPLATES:
103 for disks in disk_variants:
104 for beparams in beparam_variants:
105 for hvparams in hvparam_variants:
107 "name": "inst1.example.com",
108 "hypervisor": constants.HT_FAKE,
112 "disk_template": disk_template,
116 if beparams is not None:
117 data["beparams"] = beparams
119 if hvparams is not None:
120 data["hvparams"] = hvparams
122 for dry_run in [False, True]:
123 op = self.Parse(data, dry_run)
124 self.assert_(isinstance(op, opcodes.OpInstanceCreate))
125 self.assertEqual(op.mode, mode)
126 self.assertEqual(op.disk_template, disk_template)
127 self.assertEqual(op.dry_run, dry_run)
128 self.assertEqual(len(op.disks), len(disks))
129 self.assertEqual(len(op.nics), len(nics))
131 for opdisk, disk in zip(op.disks, disks):
132 for key in constants.IDISK_PARAMS:
133 self.assertEqual(opdisk.get(key), disk.get(key))
134 self.assertFalse("unknown" in opdisk)
136 for opnic, nic in zip(op.nics, nics):
137 for key in constants.INIC_PARAMS:
138 self.assertEqual(opnic.get(key), nic.get(key))
139 self.assertFalse("unknown" in opnic)
140 self.assertFalse("foobar" in opnic)
143 self.assertFalse(hasattr(op, "beparams"))
145 self.assertEqualValues(op.beparams, beparams)
148 self.assertFalse(hasattr(op, "hvparams"))
150 self.assertEqualValues(op.hvparams, hvparams)
152 def testLegacyName(self):
153 name = "inst29128.example.com"
158 "mode": constants.INSTANCE_CREATE,
159 "disk_template": constants.DT_PLAIN,
161 op = self.Parse(data, False)
162 self.assert_(isinstance(op, opcodes.OpInstanceCreate))
163 self.assertEqual(op.instance_name, name)
164 self.assertFalse(hasattr(op, "name"))
169 "instance_name": "other.example.com",
172 "mode": constants.INSTANCE_CREATE,
173 "disk_template": constants.DT_PLAIN,
175 self.assertRaises(http.HttpBadRequest, self.Parse, data, False)
177 def testLegacyOs(self):
178 name = "inst4673.example.com"
185 "mode": constants.INSTANCE_CREATE,
186 "disk_template": constants.DT_PLAIN,
188 op = self.Parse(data, False)
189 self.assert_(isinstance(op, opcodes.OpInstanceCreate))
190 self.assertEqual(op.instance_name, name)
191 self.assertEqual(op.os_type, os)
192 self.assertFalse(hasattr(op, "os"))
196 "instance_name": name,
198 "os_type": "linux9584",
201 "mode": constants.INSTANCE_CREATE,
202 "disk_template": constants.DT_PLAIN,
204 self.assertRaises(http.HttpBadRequest, self.Parse, data, False)
206 def testErrors(self):
207 # Test all required fields
209 "name": "inst1.example.com",
212 "mode": constants.INSTANCE_CREATE,
213 "disk_template": constants.DT_PLAIN,
216 for name in reqfields.keys():
217 self.assertRaises(http.HttpBadRequest, self.Parse,
218 dict(i for i in reqfields.iteritems() if i[0] != name),
221 # Invalid disks and nics
222 for field in ["disks", "nics"]:
223 invalid_values = [None, 1, "", {}, [1, 2, 3], ["hda1", "hda2"],
224 [{"_unknown_": 999, }]]
226 for invvalue in invalid_values:
227 data = reqfields.copy()
228 data[field] = invvalue
229 self.assertRaises(http.HttpBadRequest, self.Parse, data, False)
232 class TestParseExportInstanceRequest(testutils.GanetiTestCase):
234 testutils.GanetiTestCase.setUp(self)
236 self.Parse = rlib2._ParseExportInstanceRequest
241 "mode": constants.EXPORT_MODE_REMOTE,
242 "destination": [(1, 2, 3), (99, 99, 99)],
244 "remove_instance": True,
245 "x509_key_name": ["name", "hash"],
246 "destination_x509_ca": "---cert---"
248 op = self.Parse(name, data)
249 self.assert_(isinstance(op, opcodes.OpBackupExport))
250 self.assertEqual(op.instance_name, name)
251 self.assertEqual(op.mode, constants.EXPORT_MODE_REMOTE)
252 self.assertEqual(op.shutdown, True)
253 self.assertEqual(op.remove_instance, True)
254 self.assertEqualValues(op.x509_key_name, ("name", "hash"))
255 self.assertEqual(op.destination_x509_ca, "---cert---")
257 def testDefaults(self):
260 "destination": "node2",
263 op = self.Parse(name, data)
264 self.assert_(isinstance(op, opcodes.OpBackupExport))
265 self.assertEqual(op.instance_name, name)
266 self.assertEqual(op.target_node, "node2")
267 self.assertFalse(hasattr(op, "mode"))
268 self.assertFalse(hasattr(op, "remove_instance"))
269 self.assertFalse(hasattr(op, "destination"))
271 def testErrors(self):
272 self.assertRaises(http.HttpBadRequest, self.Parse, "err1",
273 { "remove_instance": "True", })
274 self.assertRaises(http.HttpBadRequest, self.Parse, "err1",
275 { "remove_instance": "False", })
278 class TestParseMigrateInstanceRequest(testutils.GanetiTestCase):
280 testutils.GanetiTestCase.setUp(self)
282 self.Parse = rlib2._ParseMigrateInstanceRequest
285 name = "instYooho6ek"
287 for cleanup in [False, True]:
288 for mode in constants.HT_MIGRATION_MODES:
293 op = self.Parse(name, data)
294 self.assert_(isinstance(op, opcodes.OpInstanceMigrate))
295 self.assertEqual(op.instance_name, name)
296 self.assertEqual(op.mode, mode)
297 self.assertEqual(op.cleanup, cleanup)
299 def testDefaults(self):
300 name = "instnohZeex0"
302 op = self.Parse(name, {})
303 self.assert_(isinstance(op, opcodes.OpInstanceMigrate))
304 self.assertEqual(op.instance_name, name)
305 self.assertFalse(hasattr(op, "mode"))
306 self.assertFalse(hasattr(op, "cleanup"))
309 class TestParseRenameInstanceRequest(testutils.GanetiTestCase):
311 testutils.GanetiTestCase.setUp(self)
313 self.Parse = rlib2._ParseRenameInstanceRequest
316 name = "instij0eeph7"
318 for new_name in ["ua0aiyoo", "fai3ongi"]:
319 for ip_check in [False, True]:
320 for name_check in [False, True]:
322 "new_name": new_name,
323 "ip_check": ip_check,
324 "name_check": name_check,
327 op = self.Parse(name, data)
328 self.assert_(isinstance(op, opcodes.OpInstanceRename))
329 self.assertEqual(op.instance_name, name)
330 self.assertEqual(op.new_name, new_name)
331 self.assertEqual(op.ip_check, ip_check)
332 self.assertEqual(op.name_check, name_check)
334 def testDefaults(self):
335 name = "instahchie3t"
337 for new_name in ["thag9mek", "quees7oh"]:
339 "new_name": new_name,
342 op = self.Parse(name, data)
343 self.assert_(isinstance(op, opcodes.OpInstanceRename))
344 self.assertEqual(op.instance_name, name)
345 self.assertEqual(op.new_name, new_name)
346 self.assertFalse(hasattr(op, "ip_check"))
347 self.assertFalse(hasattr(op, "name_check"))
350 class TestParseModifyInstanceRequest(testutils.GanetiTestCase):
352 testutils.GanetiTestCase.setUp(self)
354 self.Parse = rlib2._ParseModifyInstanceRequest
361 [(1, { constants.IDISK_MODE: constants.DISK_RDWR, })],
364 for osparams in [{}, { "some": "value", "other": "Hello World", }]:
365 for hvparams in [{}, { constants.HV_KERNEL_PATH: "/some/kernel", }]:
366 for beparams in [{}, { constants.BE_MEMORY: 128, }]:
367 for force in [False, True]:
368 for nics in [[], [(0, { constants.INIC_IP: "192.0.2.1", })]]:
369 for disks in test_disks:
370 for disk_template in constants.DISK_TEMPLATES:
372 "osparams": osparams,
373 "hvparams": hvparams,
374 "beparams": beparams,
378 "disk_template": disk_template,
381 op = self.Parse(name, data)
382 self.assert_(isinstance(op, opcodes.OpInstanceSetParams))
383 self.assertEqual(op.instance_name, name)
384 self.assertEqual(op.hvparams, hvparams)
385 self.assertEqual(op.beparams, beparams)
386 self.assertEqual(op.osparams, osparams)
387 self.assertEqual(op.force, force)
388 self.assertEqual(op.nics, nics)
389 self.assertEqual(op.disks, disks)
390 self.assertEqual(op.disk_template, disk_template)
391 self.assertFalse(hasattr(op, "remote_node"))
392 self.assertFalse(hasattr(op, "os_name"))
393 self.assertFalse(hasattr(op, "force_variant"))
395 def testDefaults(self):
396 name = "instir8aish31"
398 op = self.Parse(name, {})
399 self.assert_(isinstance(op, opcodes.OpInstanceSetParams))
400 self.assertEqual(op.instance_name, name)
401 for i in ["hvparams", "beparams", "osparams", "force", "nics", "disks",
402 "disk_template", "remote_node", "os_name", "force_variant"]:
403 self.assertFalse(hasattr(op, i))
406 class TestParseInstanceReinstallRequest(testutils.GanetiTestCase):
408 testutils.GanetiTestCase.setUp(self)
410 self.Parse = rlib2._ParseInstanceReinstallRequest
412 def _Check(self, ops, name):
414 opcodes.OpInstanceShutdown,
415 opcodes.OpInstanceReinstall,
416 opcodes.OpInstanceStartup,
419 self.assert_(compat.all(isinstance(op, exp)
420 for op, exp in zip(ops, expcls)))
421 self.assert_(compat.all(op.instance_name == name for op in ops))
424 name = "shoo0tihohma"
426 ops = self.Parse(name, {"os": "sys1", "start": True,})
427 self.assertEqual(len(ops), 3)
428 self._Check(ops, name)
429 self.assertEqual(ops[1].os_type, "sys1")
430 self.assertFalse(ops[1].osparams)
432 ops = self.Parse(name, {"os": "sys2", "start": False,})
433 self.assertEqual(len(ops), 2)
434 self._Check(ops, name)
435 self.assertEqual(ops[1].os_type, "sys2")
440 ops = self.Parse(name, {"os": "sys4035", "start": True,
441 "osparams": osparams,})
442 self.assertEqual(len(ops), 3)
443 self._Check(ops, name)
444 self.assertEqual(ops[1].os_type, "sys4035")
445 self.assertEqual(ops[1].osparams, osparams)
447 def testDefaults(self):
450 ops = self.Parse(name, {"os": "linux1"})
451 self.assertEqual(len(ops), 3)
452 self._Check(ops, name)
453 self.assertEqual(ops[1].os_type, "linux1")
454 self.assertFalse(ops[1].osparams)
457 class TestParseRenameGroupRequest(testutils.GanetiTestCase):
459 testutils.GanetiTestCase.setUp(self)
461 self.Parse = rlib2._ParseRenameGroupRequest
464 name = "instij0eeph7"
466 "new_name": "ua0aiyoo",
469 op = self.Parse(name, data, False)
471 self.assert_(isinstance(op, opcodes.OpGroupRename))
472 self.assertEqual(op.group_name, name)
473 self.assertEqual(op.new_name, "ua0aiyoo")
474 self.assertFalse(op.dry_run)
476 def testDryRun(self):
477 name = "instij0eeph7"
479 "new_name": "ua0aiyoo",
482 op = self.Parse(name, data, True)
484 self.assert_(isinstance(op, opcodes.OpGroupRename))
485 self.assertEqual(op.group_name, name)
486 self.assertEqual(op.new_name, "ua0aiyoo")
487 self.assert_(op.dry_run)
490 class TestParseInstanceReplaceDisksRequest(unittest.TestCase):
492 self.Parse = rlib2._ParseInstanceReplaceDisksRequest
497 for disks in [range(1, 4), "1,2,3", "1, 2, 3"]:
499 "mode": constants.REPLACE_DISK_SEC,
501 "iallocator": "myalloc",
504 op = self.Parse(name, data)
505 self.assert_(isinstance(op, opcodes.OpInstanceReplaceDisks))
506 self.assertEqual(op.mode, constants.REPLACE_DISK_SEC)
507 self.assertEqual(op.disks, [1, 2, 3])
508 self.assertEqual(op.iallocator, "myalloc")
510 def testDefaults(self):
513 "mode": constants.REPLACE_DISK_AUTO,
516 op = self.Parse(name, data)
517 self.assert_(isinstance(op, opcodes.OpInstanceReplaceDisks))
518 self.assertEqual(op.mode, constants.REPLACE_DISK_AUTO)
519 self.assertFalse(hasattr(op, "iallocator"))
520 self.assertFalse(hasattr(op, "disks"))
523 self.assertRaises(http.HttpBadRequest, self.Parse, "inst",
524 { "mode": constants.REPLACE_DISK_AUTO,
525 "disks": "hello world",
529 class TestParseModifyGroupRequest(unittest.TestCase):
531 self.Parse = rlib2._ParseModifyGroupRequest
536 for policy in constants.VALID_ALLOC_POLICIES:
538 "alloc_policy": policy,
541 op = self.Parse(name, data)
542 self.assert_(isinstance(op, opcodes.OpGroupSetParams))
543 self.assertEqual(op.group_name, name)
544 self.assertEqual(op.alloc_policy, policy)
546 def testUnknownPolicy(self):
548 "alloc_policy": "_unknown_policy_",
551 self.assertRaises(http.HttpBadRequest, self.Parse, "name", data)
553 def testDefaults(self):
557 op = self.Parse(name, data)
558 self.assert_(isinstance(op, opcodes.OpGroupSetParams))
559 self.assertEqual(op.group_name, name)
560 self.assertFalse(hasattr(op, "alloc_policy"))
563 class TestParseCreateGroupRequest(unittest.TestCase):
565 self.Parse = rlib2._ParseCreateGroupRequest
570 for policy in constants.VALID_ALLOC_POLICIES:
573 "alloc_policy": policy,
576 op = self.Parse(data, False)
577 self.assert_(isinstance(op, opcodes.OpGroupAdd))
578 self.assertEqual(op.group_name, name)
579 self.assertEqual(op.alloc_policy, policy)
580 self.assertFalse(op.dry_run)
582 def testUnknownPolicy(self):
584 "alloc_policy": "_unknown_policy_",
587 self.assertRaises(http.HttpBadRequest, self.Parse, "name", data)
589 def testDefaults(self):
595 op = self.Parse(data, True)
596 self.assert_(isinstance(op, opcodes.OpGroupAdd))
597 self.assertEqual(op.group_name, name)
598 self.assertFalse(hasattr(op, "alloc_policy"))
599 self.assertTrue(op.dry_run)
601 def testLegacyName(self):
607 op = self.Parse(data, True)
608 self.assert_(isinstance(op, opcodes.OpGroupAdd))
609 self.assertEqual(op.group_name, name)
612 if __name__ == '__main__':
613 testutils.GanetiTestProgram()