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)
50 constants.QR_INSTANCE: rlib2.I_FIELDS,
51 constants.QR_NODE: rlib2.N_FIELDS,
52 constants.QR_GROUP: rlib2.G_FIELDS,
55 for (qr, fields) in checks.items():
56 self.assertFalse(set(fields) - set(query.ALL_FIELDS[qr].keys()))
59 class TestParseInstanceCreateRequestVersion1(testutils.GanetiTestCase):
61 testutils.GanetiTestCase.setUp(self)
63 self.Parse = rlib2._ParseInstanceCreateRequestVersion1
71 [{"size": 5, }, {"size": 100, }],
74 [{"size": 123, "mode": constants.DISK_RDWR, }],
86 { "ip": "192.0.2.6", "mode": constants.NIC_MODE_ROUTED,
87 "mac": "01:23:45:67:68:9A",
89 { "mode": constants.NIC_MODE_BRIDGED, "link": "br1" },
96 { constants.BE_VCPUS: 2, },
97 { constants.BE_MEMORY: 123, },
98 { constants.BE_VCPUS: 2,
99 constants.BE_MEMORY: 1024,
100 constants.BE_AUTO_BALANCE: True, }
105 { constants.HV_BOOT_ORDER: "anc", },
106 { constants.HV_KERNEL_PATH: "/boot/fookernel",
107 constants.HV_ROOT_PATH: "/dev/hda1", },
110 for mode in [constants.INSTANCE_CREATE, constants.INSTANCE_IMPORT]:
111 for nics in nic_variants:
112 for disk_template in constants.DISK_TEMPLATES:
113 for disks in disk_variants:
114 for beparams in beparam_variants:
115 for hvparams in hvparam_variants:
117 "name": "inst1.example.com",
118 "hypervisor": constants.HT_FAKE,
122 "disk_template": disk_template,
126 if beparams is not None:
127 data["beparams"] = beparams
129 if hvparams is not None:
130 data["hvparams"] = hvparams
132 for dry_run in [False, True]:
133 op = self.Parse(data, dry_run)
134 self.assert_(isinstance(op, opcodes.OpInstanceCreate))
135 self.assertEqual(op.mode, mode)
136 self.assertEqual(op.disk_template, disk_template)
137 self.assertEqual(op.dry_run, dry_run)
138 self.assertEqual(len(op.disks), len(disks))
139 self.assertEqual(len(op.nics), len(nics))
141 for opdisk, disk in zip(op.disks, disks):
142 for key in constants.IDISK_PARAMS:
143 self.assertEqual(opdisk.get(key), disk.get(key))
144 self.assertFalse("unknown" in opdisk)
146 for opnic, nic in zip(op.nics, nics):
147 for key in constants.INIC_PARAMS:
148 self.assertEqual(opnic.get(key), nic.get(key))
149 self.assertFalse("unknown" in opnic)
150 self.assertFalse("foobar" in opnic)
153 self.assertFalse(hasattr(op, "beparams"))
155 self.assertEqualValues(op.beparams, beparams)
158 self.assertFalse(hasattr(op, "hvparams"))
160 self.assertEqualValues(op.hvparams, hvparams)
162 def testLegacyName(self):
163 name = "inst29128.example.com"
168 "mode": constants.INSTANCE_CREATE,
169 "disk_template": constants.DT_PLAIN,
171 op = self.Parse(data, False)
172 self.assert_(isinstance(op, opcodes.OpInstanceCreate))
173 self.assertEqual(op.instance_name, name)
174 self.assertFalse(hasattr(op, "name"))
179 "instance_name": "other.example.com",
182 "mode": constants.INSTANCE_CREATE,
183 "disk_template": constants.DT_PLAIN,
185 self.assertRaises(http.HttpBadRequest, self.Parse, data, False)
187 def testLegacyOs(self):
188 name = "inst4673.example.com"
195 "mode": constants.INSTANCE_CREATE,
196 "disk_template": constants.DT_PLAIN,
198 op = self.Parse(data, False)
199 self.assert_(isinstance(op, opcodes.OpInstanceCreate))
200 self.assertEqual(op.instance_name, name)
201 self.assertEqual(op.os_type, os)
202 self.assertFalse(hasattr(op, "os"))
206 "instance_name": name,
208 "os_type": "linux9584",
211 "mode": constants.INSTANCE_CREATE,
212 "disk_template": constants.DT_PLAIN,
214 self.assertRaises(http.HttpBadRequest, self.Parse, data, False)
216 def testErrors(self):
217 # Test all required fields
219 "name": "inst1.example.com",
222 "mode": constants.INSTANCE_CREATE,
223 "disk_template": constants.DT_PLAIN,
226 for name in reqfields.keys():
227 self.assertRaises(http.HttpBadRequest, self.Parse,
228 dict(i for i in reqfields.iteritems() if i[0] != name),
231 # Invalid disks and nics
232 for field in ["disks", "nics"]:
233 invalid_values = [None, 1, "", {}, [1, 2, 3], ["hda1", "hda2"],
234 [{"_unknown_": 999, }]]
236 for invvalue in invalid_values:
237 data = reqfields.copy()
238 data[field] = invvalue
239 self.assertRaises(http.HttpBadRequest, self.Parse, data, False)
242 class TestParseExportInstanceRequest(testutils.GanetiTestCase):
244 testutils.GanetiTestCase.setUp(self)
246 self.Parse = rlib2._ParseExportInstanceRequest
251 "mode": constants.EXPORT_MODE_REMOTE,
252 "destination": [(1, 2, 3), (99, 99, 99)],
254 "remove_instance": True,
255 "x509_key_name": ["name", "hash"],
256 "destination_x509_ca": "---cert---"
258 op = self.Parse(name, data)
259 self.assert_(isinstance(op, opcodes.OpBackupExport))
260 self.assertEqual(op.instance_name, name)
261 self.assertEqual(op.mode, constants.EXPORT_MODE_REMOTE)
262 self.assertEqual(op.shutdown, True)
263 self.assertEqual(op.remove_instance, True)
264 self.assertEqualValues(op.x509_key_name, ("name", "hash"))
265 self.assertEqual(op.destination_x509_ca, "---cert---")
267 def testDefaults(self):
270 "destination": "node2",
273 op = self.Parse(name, data)
274 self.assert_(isinstance(op, opcodes.OpBackupExport))
275 self.assertEqual(op.instance_name, name)
276 self.assertEqual(op.target_node, "node2")
277 self.assertFalse(hasattr(op, "mode"))
278 self.assertFalse(hasattr(op, "remove_instance"))
279 self.assertFalse(hasattr(op, "destination"))
281 def testErrors(self):
282 self.assertRaises(http.HttpBadRequest, self.Parse, "err1",
283 { "remove_instance": "True", })
284 self.assertRaises(http.HttpBadRequest, self.Parse, "err1",
285 { "remove_instance": "False", })
288 class TestParseMigrateInstanceRequest(testutils.GanetiTestCase):
290 testutils.GanetiTestCase.setUp(self)
292 self.Parse = rlib2._ParseMigrateInstanceRequest
295 name = "instYooho6ek"
297 for cleanup in [False, True]:
298 for mode in constants.HT_MIGRATION_MODES:
303 op = self.Parse(name, data)
304 self.assert_(isinstance(op, opcodes.OpInstanceMigrate))
305 self.assertEqual(op.instance_name, name)
306 self.assertEqual(op.mode, mode)
307 self.assertEqual(op.cleanup, cleanup)
309 def testDefaults(self):
310 name = "instnohZeex0"
312 op = self.Parse(name, {})
313 self.assert_(isinstance(op, opcodes.OpInstanceMigrate))
314 self.assertEqual(op.instance_name, name)
315 self.assertFalse(hasattr(op, "mode"))
316 self.assertFalse(hasattr(op, "cleanup"))
319 class TestParseRenameInstanceRequest(testutils.GanetiTestCase):
321 testutils.GanetiTestCase.setUp(self)
323 self.Parse = rlib2._ParseRenameInstanceRequest
326 name = "instij0eeph7"
328 for new_name in ["ua0aiyoo", "fai3ongi"]:
329 for ip_check in [False, True]:
330 for name_check in [False, True]:
332 "new_name": new_name,
333 "ip_check": ip_check,
334 "name_check": name_check,
337 op = self.Parse(name, data)
338 self.assert_(isinstance(op, opcodes.OpInstanceRename))
339 self.assertEqual(op.instance_name, name)
340 self.assertEqual(op.new_name, new_name)
341 self.assertEqual(op.ip_check, ip_check)
342 self.assertEqual(op.name_check, name_check)
344 def testDefaults(self):
345 name = "instahchie3t"
347 for new_name in ["thag9mek", "quees7oh"]:
349 "new_name": new_name,
352 op = self.Parse(name, data)
353 self.assert_(isinstance(op, opcodes.OpInstanceRename))
354 self.assertEqual(op.instance_name, name)
355 self.assertEqual(op.new_name, new_name)
356 self.assertFalse(hasattr(op, "ip_check"))
357 self.assertFalse(hasattr(op, "name_check"))
360 class TestParseModifyInstanceRequest(testutils.GanetiTestCase):
362 testutils.GanetiTestCase.setUp(self)
364 self.Parse = rlib2._ParseModifyInstanceRequest
371 [(1, { constants.IDISK_MODE: constants.DISK_RDWR, })],
374 for osparams in [{}, { "some": "value", "other": "Hello World", }]:
375 for hvparams in [{}, { constants.HV_KERNEL_PATH: "/some/kernel", }]:
376 for beparams in [{}, { constants.BE_MEMORY: 128, }]:
377 for force in [False, True]:
378 for nics in [[], [(0, { constants.INIC_IP: "192.0.2.1", })]]:
379 for disks in test_disks:
380 for disk_template in constants.DISK_TEMPLATES:
382 "osparams": osparams,
383 "hvparams": hvparams,
384 "beparams": beparams,
388 "disk_template": disk_template,
391 op = self.Parse(name, data)
392 self.assert_(isinstance(op, opcodes.OpInstanceSetParams))
393 self.assertEqual(op.instance_name, name)
394 self.assertEqual(op.hvparams, hvparams)
395 self.assertEqual(op.beparams, beparams)
396 self.assertEqual(op.osparams, osparams)
397 self.assertEqual(op.force, force)
398 self.assertEqual(op.nics, nics)
399 self.assertEqual(op.disks, disks)
400 self.assertEqual(op.disk_template, disk_template)
401 self.assertFalse(hasattr(op, "remote_node"))
402 self.assertFalse(hasattr(op, "os_name"))
403 self.assertFalse(hasattr(op, "force_variant"))
405 def testDefaults(self):
406 name = "instir8aish31"
408 op = self.Parse(name, {})
409 self.assert_(isinstance(op, opcodes.OpInstanceSetParams))
410 self.assertEqual(op.instance_name, name)
411 for i in ["hvparams", "beparams", "osparams", "force", "nics", "disks",
412 "disk_template", "remote_node", "os_name", "force_variant"]:
413 self.assertFalse(hasattr(op, i))
416 class TestParseInstanceReinstallRequest(testutils.GanetiTestCase):
418 testutils.GanetiTestCase.setUp(self)
420 self.Parse = rlib2._ParseInstanceReinstallRequest
422 def _Check(self, ops, name):
424 opcodes.OpInstanceShutdown,
425 opcodes.OpInstanceReinstall,
426 opcodes.OpInstanceStartup,
429 self.assert_(compat.all(isinstance(op, exp)
430 for op, exp in zip(ops, expcls)))
431 self.assert_(compat.all(op.instance_name == name for op in ops))
434 name = "shoo0tihohma"
436 ops = self.Parse(name, {"os": "sys1", "start": True,})
437 self.assertEqual(len(ops), 3)
438 self._Check(ops, name)
439 self.assertEqual(ops[1].os_type, "sys1")
440 self.assertFalse(ops[1].osparams)
442 ops = self.Parse(name, {"os": "sys2", "start": False,})
443 self.assertEqual(len(ops), 2)
444 self._Check(ops, name)
445 self.assertEqual(ops[1].os_type, "sys2")
450 ops = self.Parse(name, {"os": "sys4035", "start": True,
451 "osparams": osparams,})
452 self.assertEqual(len(ops), 3)
453 self._Check(ops, name)
454 self.assertEqual(ops[1].os_type, "sys4035")
455 self.assertEqual(ops[1].osparams, osparams)
457 def testDefaults(self):
460 ops = self.Parse(name, {"os": "linux1"})
461 self.assertEqual(len(ops), 3)
462 self._Check(ops, name)
463 self.assertEqual(ops[1].os_type, "linux1")
464 self.assertFalse(ops[1].osparams)
467 class TestParseRenameGroupRequest(testutils.GanetiTestCase):
469 testutils.GanetiTestCase.setUp(self)
471 self.Parse = rlib2._ParseRenameGroupRequest
474 name = "instij0eeph7"
476 "new_name": "ua0aiyoo",
479 op = self.Parse(name, data, False)
481 self.assert_(isinstance(op, opcodes.OpGroupRename))
482 self.assertEqual(op.group_name, name)
483 self.assertEqual(op.new_name, "ua0aiyoo")
484 self.assertFalse(op.dry_run)
486 def testDryRun(self):
487 name = "instij0eeph7"
489 "new_name": "ua0aiyoo",
492 op = self.Parse(name, data, True)
494 self.assert_(isinstance(op, opcodes.OpGroupRename))
495 self.assertEqual(op.group_name, name)
496 self.assertEqual(op.new_name, "ua0aiyoo")
497 self.assert_(op.dry_run)
500 class TestParseInstanceReplaceDisksRequest(unittest.TestCase):
502 self.Parse = rlib2._ParseInstanceReplaceDisksRequest
507 for disks in [range(1, 4), "1,2,3", "1, 2, 3"]:
509 "mode": constants.REPLACE_DISK_SEC,
511 "iallocator": "myalloc",
514 op = self.Parse(name, data)
515 self.assert_(isinstance(op, opcodes.OpInstanceReplaceDisks))
516 self.assertEqual(op.mode, constants.REPLACE_DISK_SEC)
517 self.assertEqual(op.disks, [1, 2, 3])
518 self.assertEqual(op.iallocator, "myalloc")
520 def testDefaults(self):
523 "mode": constants.REPLACE_DISK_AUTO,
526 op = self.Parse(name, data)
527 self.assert_(isinstance(op, opcodes.OpInstanceReplaceDisks))
528 self.assertEqual(op.mode, constants.REPLACE_DISK_AUTO)
529 self.assertFalse(hasattr(op, "iallocator"))
530 self.assertFalse(hasattr(op, "disks"))
533 self.assertRaises(http.HttpBadRequest, self.Parse, "inst",
534 { "mode": constants.REPLACE_DISK_AUTO,
535 "disks": "hello world",
539 class TestParseModifyGroupRequest(unittest.TestCase):
541 self.Parse = rlib2._ParseModifyGroupRequest
546 for policy in constants.VALID_ALLOC_POLICIES:
548 "alloc_policy": policy,
551 op = self.Parse(name, data)
552 self.assert_(isinstance(op, opcodes.OpGroupSetParams))
553 self.assertEqual(op.group_name, name)
554 self.assertEqual(op.alloc_policy, policy)
556 def testUnknownPolicy(self):
558 "alloc_policy": "_unknown_policy_",
561 self.assertRaises(http.HttpBadRequest, self.Parse, "name", data)
563 def testDefaults(self):
567 op = self.Parse(name, data)
568 self.assert_(isinstance(op, opcodes.OpGroupSetParams))
569 self.assertEqual(op.group_name, name)
570 self.assertFalse(hasattr(op, "alloc_policy"))
573 class TestParseCreateGroupRequest(unittest.TestCase):
575 self.Parse = rlib2._ParseCreateGroupRequest
580 for policy in constants.VALID_ALLOC_POLICIES:
583 "alloc_policy": policy,
586 op = self.Parse(data, False)
587 self.assert_(isinstance(op, opcodes.OpGroupAdd))
588 self.assertEqual(op.group_name, name)
589 self.assertEqual(op.alloc_policy, policy)
590 self.assertFalse(op.dry_run)
592 def testUnknownPolicy(self):
594 "alloc_policy": "_unknown_policy_",
597 self.assertRaises(http.HttpBadRequest, self.Parse, "name", data)
599 def testDefaults(self):
605 op = self.Parse(data, True)
606 self.assert_(isinstance(op, opcodes.OpGroupAdd))
607 self.assertEqual(op.group_name, name)
608 self.assertFalse(hasattr(op, "alloc_policy"))
609 self.assertTrue(op.dry_run)
611 def testLegacyName(self):
617 op = self.Parse(data, True)
618 self.assert_(isinstance(op, opcodes.OpGroupAdd))
619 self.assertEqual(op.group_name, name)
622 if __name__ == '__main__':
623 testutils.GanetiTestProgram()