4 # Copyright (C) 2008, 2011, 2012 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 cmdlib module"""
34 from ganeti import constants
35 from ganeti import mcpu
36 from ganeti import cmdlib
37 from ganeti import opcodes
38 from ganeti import errors
39 from ganeti import utils
40 from ganeti import luxi
42 from ganeti import objects
43 from ganeti import compat
44 from ganeti import rpc
45 from ganeti import pathutils
46 from ganeti.masterd import iallocator
47 from ganeti.hypervisor import hv_xen
53 class TestCertVerification(testutils.GanetiTestCase):
55 testutils.GanetiTestCase.setUp(self)
57 self.tmpdir = tempfile.mkdtemp()
60 shutil.rmtree(self.tmpdir)
62 def testVerifyCertificate(self):
63 cmdlib._VerifyCertificate(self._TestDataFilename("cert1.pem"))
65 nonexist_filename = os.path.join(self.tmpdir, "does-not-exist")
67 (errcode, msg) = cmdlib._VerifyCertificate(nonexist_filename)
68 self.assertEqual(errcode, cmdlib.LUClusterVerifyConfig.ETYPE_ERROR)
70 # Try to load non-certificate file
71 invalid_cert = self._TestDataFilename("bdev-net.txt")
72 (errcode, msg) = cmdlib._VerifyCertificate(invalid_cert)
73 self.assertEqual(errcode, cmdlib.LUClusterVerifyConfig.ETYPE_ERROR)
76 class TestOpcodeParams(testutils.GanetiTestCase):
77 def testParamsStructures(self):
78 for op in sorted(mcpu.Processor.DISPATCH_TABLE):
79 lu = mcpu.Processor.DISPATCH_TABLE[op]
81 self.failIf(hasattr(lu, "_OP_REQP"),
82 msg=("LU '%s' has old-style _OP_REQP" % lu_name))
83 self.failIf(hasattr(lu, "_OP_DEFS"),
84 msg=("LU '%s' has old-style _OP_DEFS" % lu_name))
85 self.failIf(hasattr(lu, "_OP_PARAMS"),
86 msg=("LU '%s' has old-style _OP_PARAMS" % lu_name))
89 class TestIAllocatorChecks(testutils.GanetiTestCase):
90 def testFunction(self):
92 def __init__(self, opcode):
93 self.cfg = mocks.FakeConfig()
96 class OpTest(opcodes.OpCode):
98 ("iallocator", None, ht.NoType, None),
99 ("node", None, ht.NoType, None),
102 default_iallocator = mocks.FakeConfig().GetDefaultIAllocator()
103 other_iallocator = default_iallocator + "_not"
108 c_i = lambda: cmdlib._CheckIAllocatorOrNode(lu, "iallocator", "node")
110 # Neither node nor iallocator given
115 self.assertEqual(lu.op.iallocator, default_iallocator)
116 self.assertEqual(lu.op.node, n)
118 # Both, iallocator and node given
119 for a in ("test", constants.DEFAULT_IALLOCATOR_SHORTCUT):
122 self.assertRaises(errors.OpPrereqError, c_i)
124 # Only iallocator given
126 op.iallocator = other_iallocator
129 self.assertEqual(lu.op.iallocator, other_iallocator)
130 self.assertEqual(lu.op.node, n)
136 self.assertEqual(lu.op.iallocator, None)
137 self.assertEqual(lu.op.node, "node")
139 # Asked for default iallocator, no node given
140 op.iallocator = constants.DEFAULT_IALLOCATOR_SHORTCUT
143 self.assertEqual(lu.op.iallocator, default_iallocator)
144 self.assertEqual(lu.op.node, None)
146 # No node, iallocator or default iallocator
149 lu.cfg.GetDefaultIAllocator = lambda: None
150 self.assertRaises(errors.OpPrereqError, c_i)
153 class TestLUTestJqueue(unittest.TestCase):
155 self.assert_(cmdlib.LUTestJqueue._CLIENT_CONNECT_TIMEOUT <
156 (luxi.WFJC_TIMEOUT * 0.75),
157 msg=("Client timeout too high, might not notice bugs"
158 " in WaitForJobChange"))
161 class TestLUQuery(unittest.TestCase):
163 self.assertEqual(sorted(cmdlib._QUERY_IMPL.keys()),
164 sorted(constants.QR_VIA_OP))
166 assert constants.QR_NODE in constants.QR_VIA_OP
167 assert constants.QR_INSTANCE in constants.QR_VIA_OP
169 for i in constants.QR_VIA_OP:
170 self.assert_(cmdlib._GetQueryImplementation(i))
172 self.assertRaises(errors.OpPrereqError, cmdlib._GetQueryImplementation, "")
173 self.assertRaises(errors.OpPrereqError, cmdlib._GetQueryImplementation,
177 class TestLUGroupAssignNodes(unittest.TestCase):
179 def testCheckAssignmentForSplitInstances(self):
180 node_data = dict((name, objects.Node(name=name, group=group))
181 for (name, group) in [("n1a", "g1"), ("n1b", "g1"),
182 ("n2a", "g2"), ("n2b", "g2"),
183 ("n3a", "g3"), ("n3b", "g3"),
187 def Instance(name, pnode, snode):
190 disk_template = constants.DT_DISKLESS
192 disks = [objects.Disk(dev_type=constants.LD_DRBD8,
193 logical_id=[pnode, snode, 1, 17, 17])]
194 disk_template = constants.DT_DRBD8
196 return objects.Instance(name=name, primary_node=pnode, disks=disks,
197 disk_template=disk_template)
199 instance_data = dict((name, Instance(name, pnode, snode))
200 for name, pnode, snode in [("inst1a", "n1a", "n1b"),
201 ("inst1b", "n1b", "n1a"),
202 ("inst2a", "n2a", "n2b"),
203 ("inst3a", "n3a", None),
204 ("inst3b", "n3b", "n1b"),
205 ("inst3c", "n3b", "n2b"),
208 # Test first with the existing state.
210 cmdlib.LUGroupAssignNodes.CheckAssignmentForSplitInstances([],
214 self.assertEqual([], new)
215 self.assertEqual(set(["inst3b", "inst3c"]), set(prev))
217 # And now some changes.
219 cmdlib.LUGroupAssignNodes.CheckAssignmentForSplitInstances([("n1b",
224 self.assertEqual(set(["inst1a", "inst1b"]), set(new))
225 self.assertEqual(set(["inst3c"]), set(prev))
228 class TestClusterVerifySsh(unittest.TestCase):
229 def testMultipleGroups(self):
230 fn = cmdlib.LUClusterVerifyGroup._SelectSshCheckNodes
232 objects.Node(name="node20", group="my", offline=False),
233 objects.Node(name="node21", group="my", offline=False),
234 objects.Node(name="node22", group="my", offline=False),
235 objects.Node(name="node23", group="my", offline=False),
236 objects.Node(name="node24", group="my", offline=False),
237 objects.Node(name="node25", group="my", offline=False),
238 objects.Node(name="node26", group="my", offline=True),
241 objects.Node(name="node1", group="g1", offline=True),
242 objects.Node(name="node2", group="g1", offline=False),
243 objects.Node(name="node3", group="g1", offline=False),
244 objects.Node(name="node4", group="g1", offline=True),
245 objects.Node(name="node5", group="g1", offline=False),
246 objects.Node(name="node10", group="xyz", offline=False),
247 objects.Node(name="node11", group="xyz", offline=False),
248 objects.Node(name="node40", group="alloff", offline=True),
249 objects.Node(name="node41", group="alloff", offline=True),
250 objects.Node(name="node50", group="aaa", offline=False),
252 assert not utils.FindDuplicates(map(operator.attrgetter("name"), nodes))
254 (online, perhost) = fn(mygroupnodes, "my", nodes)
255 self.assertEqual(online, ["node%s" % i for i in range(20, 26)])
256 self.assertEqual(set(perhost.keys()), set(online))
258 self.assertEqual(perhost, {
259 "node20": ["node10", "node2", "node50"],
260 "node21": ["node11", "node3", "node50"],
261 "node22": ["node10", "node5", "node50"],
262 "node23": ["node11", "node2", "node50"],
263 "node24": ["node10", "node3", "node50"],
264 "node25": ["node11", "node5", "node50"],
267 def testSingleGroup(self):
268 fn = cmdlib.LUClusterVerifyGroup._SelectSshCheckNodes
270 objects.Node(name="node1", group="default", offline=True),
271 objects.Node(name="node2", group="default", offline=False),
272 objects.Node(name="node3", group="default", offline=False),
273 objects.Node(name="node4", group="default", offline=True),
275 assert not utils.FindDuplicates(map(operator.attrgetter("name"), nodes))
277 (online, perhost) = fn(nodes, "default", nodes)
278 self.assertEqual(online, ["node2", "node3"])
279 self.assertEqual(set(perhost.keys()), set(online))
281 self.assertEqual(perhost, {
287 class TestClusterVerifyFiles(unittest.TestCase):
289 def _FakeErrorIf(errors, cond, ecode, item, msg, *args, **kwargs):
290 assert ((ecode == constants.CV_ENODEFILECHECK and
291 ht.TNonEmptyString(item)) or
292 (ecode == constants.CV_ECLUSTERFILECHECK and
299 errors.append((item, msg))
301 _VerifyFiles = cmdlib.LUClusterVerifyGroup._VerifyFiles
305 master_name = "master.example.com"
307 objects.Node(name=master_name, offline=False, vm_capable=True),
308 objects.Node(name="node2.example.com", offline=False, vm_capable=True),
309 objects.Node(name="node3.example.com", master_candidate=True,
311 objects.Node(name="node4.example.com", offline=False, vm_capable=True),
312 objects.Node(name="nodata.example.com", offline=False, vm_capable=True),
313 objects.Node(name="offline.example.com", offline=True),
315 cluster = objects.Cluster(modify_etc_hosts=True,
316 enabled_hypervisors=[constants.HT_XEN_HVM])
318 pathutils.CLUSTER_DOMAIN_SECRET_FILE,
319 pathutils.RAPI_CERT_FILE,
320 pathutils.RAPI_USERS_FILE,
323 pathutils.RAPI_USERS_FILE,
324 hv_xen.XL_CONFIG_FILE,
325 pathutils.VNC_PASSWORD_FILE,
328 pathutils.CLUSTER_CONF_FILE,
331 hv_xen.XEND_CONFIG_FILE,
332 hv_xen.XL_CONFIG_FILE,
333 pathutils.VNC_PASSWORD_FILE,
336 master_name: rpc.RpcResult(data=(True, {
337 constants.NV_FILELIST: {
338 pathutils.CLUSTER_CONF_FILE: "82314f897f38b35f9dab2f7c6b1593e0",
339 pathutils.RAPI_CERT_FILE: "babbce8f387bc082228e544a2146fee4",
340 pathutils.CLUSTER_DOMAIN_SECRET_FILE: "cds-47b5b3f19202936bb4",
341 hv_xen.XEND_CONFIG_FILE: "b4a8a824ab3cac3d88839a9adeadf310",
342 hv_xen.XL_CONFIG_FILE: "77935cee92afd26d162f9e525e3d49b9"
344 "node2.example.com": rpc.RpcResult(data=(True, {
345 constants.NV_FILELIST: {
346 pathutils.RAPI_CERT_FILE: "97f0356500e866387f4b84233848cc4a",
347 hv_xen.XEND_CONFIG_FILE: "b4a8a824ab3cac3d88839a9adeadf310",
350 "node3.example.com": rpc.RpcResult(data=(True, {
351 constants.NV_FILELIST: {
352 pathutils.RAPI_CERT_FILE: "97f0356500e866387f4b84233848cc4a",
353 pathutils.CLUSTER_DOMAIN_SECRET_FILE: "cds-47b5b3f19202936bb4",
356 "node4.example.com": rpc.RpcResult(data=(True, {
357 constants.NV_FILELIST: {
358 pathutils.RAPI_CERT_FILE: "97f0356500e866387f4b84233848cc4a",
359 pathutils.CLUSTER_CONF_FILE: "conf-a6d4b13e407867f7a7b4f0f232a8f527",
360 pathutils.CLUSTER_DOMAIN_SECRET_FILE: "cds-47b5b3f19202936bb4",
361 pathutils.RAPI_USERS_FILE: "rapiusers-ea3271e8d810ef3",
362 hv_xen.XL_CONFIG_FILE: "77935cee92afd26d162f9e525e3d49b9"
365 "nodata.example.com": rpc.RpcResult(data=(True, {})),
366 "offline.example.com": rpc.RpcResult(offline=True),
368 assert set(nvinfo.keys()) == set(map(operator.attrgetter("name"), nodeinfo))
370 self._VerifyFiles(compat.partial(self._FakeErrorIf, errors), nodeinfo,
372 (files_all, files_opt, files_mc, files_vm))
373 self.assertEqual(sorted(errors), sorted([
374 (None, ("File %s found with 2 different checksums (variant 1 on"
375 " node2.example.com, node3.example.com, node4.example.com;"
376 " variant 2 on master.example.com)" % pathutils.RAPI_CERT_FILE)),
377 (None, ("File %s is missing from node(s) node2.example.com" %
378 pathutils.CLUSTER_DOMAIN_SECRET_FILE)),
379 (None, ("File %s should not exist on node(s) node4.example.com" %
380 pathutils.CLUSTER_CONF_FILE)),
381 (None, ("File %s is missing from node(s) node4.example.com" %
382 hv_xen.XEND_CONFIG_FILE)),
383 (None, ("File %s is missing from node(s) node3.example.com" %
384 pathutils.CLUSTER_CONF_FILE)),
385 (None, ("File %s found with 2 different checksums (variant 1 on"
386 " master.example.com; variant 2 on node4.example.com)" %
387 pathutils.CLUSTER_CONF_FILE)),
388 (None, ("File %s is optional, but it must exist on all or no nodes (not"
389 " found on master.example.com, node2.example.com,"
390 " node3.example.com)" % pathutils.RAPI_USERS_FILE)),
391 (None, ("File %s is optional, but it must exist on all or no nodes (not"
392 " found on node2.example.com)" % hv_xen.XL_CONFIG_FILE)),
393 ("nodata.example.com", "Node did not return file checksum data"),
398 def __init__(self, cfg=NotImplemented, proc=NotImplemented,
400 self.warning_log = []
406 def LogWarning(self, text, *args):
407 self.warning_log.append((text, args))
409 def LogInfo(self, text, *args):
410 self.info_log.append((text, args))
413 class TestLoadNodeEvacResult(unittest.TestCase):
414 def testSuccess(self):
416 ("inst20153.example.com", "grp2", ["nodeA4509", "nodeB2912"]),
418 for early_release in [False, True]:
419 for use_nodes in [False, True]:
421 [opcodes.OpInstanceReplaceDisks().__getstate__()],
422 [opcodes.OpInstanceMigrate().__getstate__()],
425 alloc_result = (moved, [], jobs)
426 assert iallocator._NEVAC_RESULT(alloc_result)
429 result = cmdlib._LoadNodeEvacResult(lu, alloc_result,
430 early_release, use_nodes)
433 (_, (info_args, )) = lu.info_log.pop(0)
434 for (instname, instgroup, instnodes) in moved:
435 self.assertTrue(instname in info_args)
438 self.assertTrue(i in info_args)
440 self.assertTrue(instgroup in info_args)
442 self.assertFalse(lu.info_log)
443 self.assertFalse(lu.warning_log)
445 for op in itertools.chain(*result):
446 if hasattr(op.__class__, "early_release"):
447 self.assertEqual(op.early_release, early_release)
449 self.assertFalse(hasattr(op, "early_release"))
451 def testFailed(self):
452 alloc_result = ([], [
453 ("inst5191.example.com", "errormsg21178"),
455 assert iallocator._NEVAC_RESULT(alloc_result)
458 self.assertRaises(errors.OpExecError, cmdlib._LoadNodeEvacResult,
459 lu, alloc_result, False, False)
460 self.assertFalse(lu.info_log)
461 (_, (args, )) = lu.warning_log.pop(0)
462 self.assertTrue("inst5191.example.com" in args)
463 self.assertTrue("errormsg21178" in args)
464 self.assertFalse(lu.warning_log)
467 class TestUpdateAndVerifySubDict(unittest.TestCase):
470 "a": constants.VTYPE_INT,
471 "b": constants.VTYPE_STRING,
472 "c": constants.VTYPE_BOOL,
473 "d": constants.VTYPE_STRING,
520 verified = cmdlib._UpdateAndVerifySubDict(old_test, test, self.type_check)
521 self.assertEqual(verified, mv)
537 self.assertRaises(errors.TypeEnforcementError,
538 cmdlib._UpdateAndVerifySubDict, {}, test, self.type_check)
541 class TestHvStateHelper(unittest.TestCase):
542 def testWithoutOpData(self):
543 self.assertEqual(cmdlib._MergeAndVerifyHvState(None, NotImplemented), None)
545 def testWithoutOldData(self):
547 constants.HT_XEN_PVM: {
548 constants.HVST_MEMORY_TOTAL: 4096,
551 self.assertEqual(cmdlib._MergeAndVerifyHvState(new, None), new)
553 def testWithWrongHv(self):
556 constants.HVST_MEMORY_TOTAL: 4096,
559 self.assertRaises(errors.OpPrereqError, cmdlib._MergeAndVerifyHvState, new,
562 class TestDiskStateHelper(unittest.TestCase):
563 def testWithoutOpData(self):
564 self.assertEqual(cmdlib._MergeAndVerifyDiskState(None, NotImplemented),
567 def testWithoutOldData(self):
571 constants.DS_DISK_RESERVED: 1024,
575 self.assertEqual(cmdlib._MergeAndVerifyDiskState(new, None), new)
577 def testWithWrongStorageType(self):
581 constants.DS_DISK_RESERVED: 1024,
585 self.assertRaises(errors.OpPrereqError, cmdlib._MergeAndVerifyDiskState,
589 class TestComputeMinMaxSpec(unittest.TestCase):
592 constants.ISPECS_MAX: {
593 constants.ISPEC_MEM_SIZE: 512,
594 constants.ISPEC_DISK_SIZE: 1024,
596 constants.ISPECS_MIN: {
597 constants.ISPEC_MEM_SIZE: 128,
598 constants.ISPEC_DISK_COUNT: 1,
602 def testNoneValue(self):
603 self.assertTrue(cmdlib._ComputeMinMaxSpec(constants.ISPEC_MEM_SIZE, None,
604 self.ipolicy, None) is None)
606 def testAutoValue(self):
607 self.assertTrue(cmdlib._ComputeMinMaxSpec(constants.ISPEC_MEM_SIZE, None,
609 constants.VALUE_AUTO) is None)
611 def testNotDefined(self):
612 self.assertTrue(cmdlib._ComputeMinMaxSpec(constants.ISPEC_NIC_COUNT, None,
613 self.ipolicy, 3) is None)
615 def testNoMinDefined(self):
616 self.assertTrue(cmdlib._ComputeMinMaxSpec(constants.ISPEC_DISK_SIZE, None,
617 self.ipolicy, 128) is None)
619 def testNoMaxDefined(self):
620 self.assertTrue(cmdlib._ComputeMinMaxSpec(constants.ISPEC_DISK_COUNT, None,
621 self.ipolicy, 16) is None)
623 def testOutOfRange(self):
624 for (name, val) in ((constants.ISPEC_MEM_SIZE, 64),
625 (constants.ISPEC_MEM_SIZE, 768),
626 (constants.ISPEC_DISK_SIZE, 4096),
627 (constants.ISPEC_DISK_COUNT, 0)):
628 min_v = self.ipolicy[constants.ISPECS_MIN].get(name, val)
629 max_v = self.ipolicy[constants.ISPECS_MAX].get(name, val)
630 self.assertEqual(cmdlib._ComputeMinMaxSpec(name, None,
632 "%s value %s is not in range [%s, %s]" %
633 (name, val,min_v, max_v))
634 self.assertEqual(cmdlib._ComputeMinMaxSpec(name, "1",
636 "%s/1 value %s is not in range [%s, %s]" %
637 (name, val,min_v, max_v))
640 for (name, val) in ((constants.ISPEC_MEM_SIZE, 256),
641 (constants.ISPEC_MEM_SIZE, 128),
642 (constants.ISPEC_MEM_SIZE, 512),
643 (constants.ISPEC_DISK_SIZE, 1024),
644 (constants.ISPEC_DISK_SIZE, 0),
645 (constants.ISPEC_DISK_COUNT, 1),
646 (constants.ISPEC_DISK_COUNT, 5)):
647 self.assertTrue(cmdlib._ComputeMinMaxSpec(name, None, self.ipolicy, val)
651 def _ValidateComputeMinMaxSpec(name, *_):
652 assert name in constants.ISPECS_PARAMETERS
657 def __init__(self, spec):
660 def ComputeMinMaxSpec(self, *args):
661 return self.spec.pop(0)
664 class TestComputeIPolicySpecViolation(unittest.TestCase):
666 compute_fn = _ValidateComputeMinMaxSpec
667 ret = cmdlib._ComputeIPolicySpecViolation(NotImplemented, 1024, 1, 1, 1,
668 [1024], 1, _compute_fn=compute_fn)
669 self.assertEqual(ret, [])
671 def testInvalidArguments(self):
672 self.assertRaises(AssertionError, cmdlib._ComputeIPolicySpecViolation,
673 NotImplemented, 1024, 1, 1, 1, [], 1)
675 def testInvalidSpec(self):
676 spec = _SpecWrapper([None, False, "foo", None, "bar", None])
677 compute_fn = spec.ComputeMinMaxSpec
678 ret = cmdlib._ComputeIPolicySpecViolation(NotImplemented, 1024, 1, 1, 1,
679 [1024], 1, _compute_fn=compute_fn)
680 self.assertEqual(ret, ["foo", "bar"])
681 self.assertFalse(spec.spec)
684 class _StubComputeIPolicySpecViolation:
685 def __init__(self, mem_size, cpu_count, disk_count, nic_count, disk_sizes,
687 self.mem_size = mem_size
688 self.cpu_count = cpu_count
689 self.disk_count = disk_count
690 self.nic_count = nic_count
691 self.disk_sizes = disk_sizes
692 self.spindle_use = spindle_use
694 def __call__(self, _, mem_size, cpu_count, disk_count, nic_count, disk_sizes,
696 assert self.mem_size == mem_size
697 assert self.cpu_count == cpu_count
698 assert self.disk_count == disk_count
699 assert self.nic_count == nic_count
700 assert self.disk_sizes == disk_sizes
701 assert self.spindle_use == spindle_use
706 class TestComputeIPolicyInstanceViolation(unittest.TestCase):
709 constants.BE_MAXMEM: 2048,
710 constants.BE_VCPUS: 2,
711 constants.BE_SPINDLE_USE: 4,
713 disks = [objects.Disk(size=512)]
714 instance = objects.Instance(beparams=beparams, disks=disks, nics=[])
715 stub = _StubComputeIPolicySpecViolation(2048, 2, 1, 0, [512], 4)
716 ret = cmdlib._ComputeIPolicyInstanceViolation(NotImplemented, instance,
718 self.assertEqual(ret, [])
721 class TestComputeIPolicyInstanceSpecViolation(unittest.TestCase):
724 constants.ISPEC_MEM_SIZE: 2048,
725 constants.ISPEC_CPU_COUNT: 2,
726 constants.ISPEC_DISK_COUNT: 1,
727 constants.ISPEC_DISK_SIZE: [512],
728 constants.ISPEC_NIC_COUNT: 0,
729 constants.ISPEC_SPINDLE_USE: 1,
731 stub = _StubComputeIPolicySpecViolation(2048, 2, 1, 0, [512], 1)
732 ret = cmdlib._ComputeIPolicyInstanceSpecViolation(NotImplemented, ispec,
734 self.assertEqual(ret, [])
738 def __init__(self, return_value=None):
740 self.return_value = return_value
742 def __call__(self, *args):
744 return self.return_value
747 class TestComputeIPolicyNodeViolation(unittest.TestCase):
749 self.recorder = _CallRecorder(return_value=[])
751 def testSameGroup(self):
752 ret = cmdlib._ComputeIPolicyNodeViolation(NotImplemented, NotImplemented,
754 _compute_fn=self.recorder)
755 self.assertFalse(self.recorder.called)
756 self.assertEqual(ret, [])
758 def testDifferentGroup(self):
759 ret = cmdlib._ComputeIPolicyNodeViolation(NotImplemented, NotImplemented,
761 _compute_fn=self.recorder)
762 self.assertTrue(self.recorder.called)
763 self.assertEqual(ret, [])
766 class _FakeConfigForTargetNodeIPolicy:
767 def __init__(self, node_info=NotImplemented):
768 self._node_info = node_info
770 def GetNodeInfo(self, _):
771 return self._node_info
774 class TestCheckTargetNodeIPolicy(unittest.TestCase):
776 self.instance = objects.Instance(primary_node="blubb")
777 self.target_node = objects.Node(group="bar")
778 node_info = objects.Node(group="foo")
779 fake_cfg = _FakeConfigForTargetNodeIPolicy(node_info=node_info)
780 self.lu = _FakeLU(cfg=fake_cfg)
782 def testNoViolation(self):
783 compute_recoder = _CallRecorder(return_value=[])
784 cmdlib._CheckTargetNodeIPolicy(self.lu, NotImplemented, self.instance,
786 _compute_fn=compute_recoder)
787 self.assertTrue(compute_recoder.called)
788 self.assertEqual(self.lu.warning_log, [])
790 def testNoIgnore(self):
791 compute_recoder = _CallRecorder(return_value=["mem_size not in range"])
792 self.assertRaises(errors.OpPrereqError, cmdlib._CheckTargetNodeIPolicy,
793 self.lu, NotImplemented, self.instance, self.target_node,
794 _compute_fn=compute_recoder)
795 self.assertTrue(compute_recoder.called)
796 self.assertEqual(self.lu.warning_log, [])
798 def testIgnoreViolation(self):
799 compute_recoder = _CallRecorder(return_value=["mem_size not in range"])
800 cmdlib._CheckTargetNodeIPolicy(self.lu, NotImplemented, self.instance,
801 self.target_node, ignore=True,
802 _compute_fn=compute_recoder)
803 self.assertTrue(compute_recoder.called)
804 msg = ("Instance does not meet target node group's (bar) instance policy:"
805 " mem_size not in range")
806 self.assertEqual(self.lu.warning_log, [(msg, ())])
809 class TestApplyContainerMods(unittest.TestCase):
810 def testEmptyContainer(self):
813 cmdlib.ApplyContainerMods("test", container, chgdesc, [], None, None, None)
814 self.assertEqual(container, [])
815 self.assertEqual(chgdesc, [])
820 mods = cmdlib.PrepareContainerMods([
821 (constants.DDM_ADD, -1, "Hello"),
822 (constants.DDM_ADD, -1, "World"),
823 (constants.DDM_ADD, 0, "Start"),
824 (constants.DDM_ADD, -1, "End"),
826 cmdlib.ApplyContainerMods("test", container, chgdesc, mods,
828 self.assertEqual(container, ["Start", "Hello", "World", "End"])
829 self.assertEqual(chgdesc, [])
831 mods = cmdlib.PrepareContainerMods([
832 (constants.DDM_ADD, 0, "zero"),
833 (constants.DDM_ADD, 3, "Added"),
834 (constants.DDM_ADD, 5, "four"),
835 (constants.DDM_ADD, 7, "xyz"),
837 cmdlib.ApplyContainerMods("test", container, chgdesc, mods,
839 self.assertEqual(container,
840 ["zero", "Start", "Hello", "Added", "World", "four",
842 self.assertEqual(chgdesc, [])
844 for idx in [-2, len(container) + 1]:
845 mods = cmdlib.PrepareContainerMods([
846 (constants.DDM_ADD, idx, "error"),
848 self.assertRaises(IndexError, cmdlib.ApplyContainerMods,
849 "test", container, None, mods, None, None, None)
851 def testRemoveError(self):
852 for idx in [0, 1, 2, 100, -1, -4]:
853 mods = cmdlib.PrepareContainerMods([
854 (constants.DDM_REMOVE, idx, None),
856 self.assertRaises(IndexError, cmdlib.ApplyContainerMods,
857 "test", [], None, mods, None, None, None)
859 mods = cmdlib.PrepareContainerMods([
860 (constants.DDM_REMOVE, 0, object()),
862 self.assertRaises(AssertionError, cmdlib.ApplyContainerMods,
863 "test", [""], None, mods, None, None, None)
865 def testAddError(self):
866 for idx in range(-100, -1) + [100]:
867 mods = cmdlib.PrepareContainerMods([
868 (constants.DDM_ADD, idx, None),
870 self.assertRaises(IndexError, cmdlib.ApplyContainerMods,
871 "test", [], None, mods, None, None, None)
873 def testRemove(self):
874 container = ["item 1", "item 2"]
875 mods = cmdlib.PrepareContainerMods([
876 (constants.DDM_ADD, -1, "aaa"),
877 (constants.DDM_REMOVE, -1, None),
878 (constants.DDM_ADD, -1, "bbb"),
881 cmdlib.ApplyContainerMods("test", container, chgdesc, mods,
883 self.assertEqual(container, ["item 1", "item 2", "bbb"])
884 self.assertEqual(chgdesc, [
885 ("test/2", "remove"),
888 def testModify(self):
889 container = ["item 1", "item 2"]
890 mods = cmdlib.PrepareContainerMods([
891 (constants.DDM_MODIFY, -1, "a"),
892 (constants.DDM_MODIFY, 0, "b"),
893 (constants.DDM_MODIFY, 1, "c"),
896 cmdlib.ApplyContainerMods("test", container, chgdesc, mods,
898 self.assertEqual(container, ["item 1", "item 2"])
899 self.assertEqual(chgdesc, [])
901 for idx in [-2, len(container) + 1]:
902 mods = cmdlib.PrepareContainerMods([
903 (constants.DDM_MODIFY, idx, "error"),
905 self.assertRaises(IndexError, cmdlib.ApplyContainerMods,
906 "test", container, None, mods, None, None, None)
913 def _CreateTestFn(idx, params, private):
914 private.data = ("add", idx, params)
915 return ((100 * idx, params), [
916 ("test/%s" % idx, hex(idx)),
920 def _ModifyTestFn(idx, item, params, private):
921 private.data = ("modify", idx, params)
923 ("test/%s" % idx, "modify %s" % params),
927 def _RemoveTestFn(idx, item, private):
928 private.data = ("remove", idx, item)
930 def testAddWithCreateFunction(self):
933 mods = cmdlib.PrepareContainerMods([
934 (constants.DDM_ADD, -1, "Hello"),
935 (constants.DDM_ADD, -1, "World"),
936 (constants.DDM_ADD, 0, "Start"),
937 (constants.DDM_ADD, -1, "End"),
938 (constants.DDM_REMOVE, 2, None),
939 (constants.DDM_MODIFY, -1, "foobar"),
940 (constants.DDM_REMOVE, 2, None),
941 (constants.DDM_ADD, 1, "More"),
942 ], self._PrivateData)
943 cmdlib.ApplyContainerMods("test", container, chgdesc, mods,
944 self._CreateTestFn, self._ModifyTestFn, self._RemoveTestFn)
945 self.assertEqual(container, [
950 self.assertEqual(chgdesc, [
955 ("test/2", "remove"),
956 ("test/2", "modify foobar"),
957 ("test/2", "remove"),
960 self.assertTrue(compat.all(op == private.data[0]
961 for (op, _, _, private) in mods))
962 self.assertEqual([private.data for (op, _, _, private) in mods], [
967 ("remove", 2, (100, "World")),
968 ("modify", 2, "foobar"),
969 ("remove", 2, (300, "End")),
974 class _FakeConfigForGenDiskTemplate:
976 self._unique_id = itertools.count()
977 self._drbd_minor = itertools.count(20)
978 self._port = itertools.count(constants.FIRST_DRBD_PORT)
979 self._secret = itertools.count()
984 def GenerateUniqueID(self, ec_id):
985 return "ec%s-uq%s" % (ec_id, self._unique_id.next())
987 def AllocateDRBDMinor(self, nodes, instance):
988 return [self._drbd_minor.next()
991 def AllocatePort(self):
992 return self._port.next()
994 def GenerateDRBDSecret(self, ec_id):
995 return "ec%s-secret%s" % (ec_id, self._secret.next())
997 def GetInstanceInfo(self, _):
1001 class _FakeProcForGenDiskTemplate:
1006 class TestGenerateDiskTemplate(unittest.TestCase):
1008 nodegroup = objects.NodeGroup(name="ng")
1009 nodegroup.UpgradeConfig()
1011 cfg = _FakeConfigForGenDiskTemplate()
1012 proc = _FakeProcForGenDiskTemplate()
1014 self.lu = _FakeLU(cfg=cfg, proc=proc)
1015 self.nodegroup = nodegroup
1018 def GetDiskParams():
1019 return copy.deepcopy(constants.DISK_DT_DEFAULTS)
1021 def testWrongDiskTemplate(self):
1022 gdt = cmdlib._GenerateDiskTemplate
1023 disk_template = "##unknown##"
1025 assert disk_template not in constants.DISK_TEMPLATES
1027 self.assertRaises(errors.ProgrammerError, gdt, self.lu, disk_template,
1028 "inst26831.example.com", "node30113.example.com", [], [],
1029 NotImplemented, NotImplemented, 0, self.lu.LogInfo,
1030 self.GetDiskParams())
1032 def testDiskless(self):
1033 gdt = cmdlib._GenerateDiskTemplate
1035 result = gdt(self.lu, constants.DT_DISKLESS, "inst27734.example.com",
1036 "node30113.example.com", [], [],
1037 NotImplemented, NotImplemented, 0, self.lu.LogInfo,
1038 self.GetDiskParams())
1039 self.assertEqual(result, [])
1041 def _TestTrivialDisk(self, template, disk_info, base_index, exp_dev_type,
1042 file_storage_dir=NotImplemented,
1043 file_driver=NotImplemented,
1044 req_file_storage=NotImplemented,
1045 req_shr_file_storage=NotImplemented):
1046 gdt = cmdlib._GenerateDiskTemplate
1048 map(lambda params: utils.ForceDictType(params,
1049 constants.IDISK_PARAMS_TYPES),
1052 # Check if non-empty list of secondaries is rejected
1053 self.assertRaises(errors.ProgrammerError, gdt, self.lu,
1054 template, "inst25088.example.com",
1055 "node185.example.com", ["node323.example.com"], [],
1056 NotImplemented, NotImplemented, base_index,
1057 self.lu.LogInfo, self.GetDiskParams(),
1058 _req_file_storage=req_file_storage,
1059 _req_shr_file_storage=req_shr_file_storage)
1061 result = gdt(self.lu, template, "inst21662.example.com",
1062 "node21741.example.com", [],
1063 disk_info, file_storage_dir, file_driver, base_index,
1064 self.lu.LogInfo, self.GetDiskParams(),
1065 _req_file_storage=req_file_storage,
1066 _req_shr_file_storage=req_shr_file_storage)
1068 for (idx, disk) in enumerate(result):
1069 self.assertTrue(isinstance(disk, objects.Disk))
1070 self.assertEqual(disk.dev_type, exp_dev_type)
1071 self.assertEqual(disk.size, disk_info[idx][constants.IDISK_SIZE])
1072 self.assertEqual(disk.mode, disk_info[idx][constants.IDISK_MODE])
1073 self.assertTrue(disk.children is None)
1075 self._CheckIvNames(result, base_index, base_index + len(disk_info))
1076 cmdlib._UpdateIvNames(base_index, result)
1077 self._CheckIvNames(result, base_index, base_index + len(disk_info))
1081 def _CheckIvNames(self, disks, base_index, end_index):
1082 self.assertEqual(map(operator.attrgetter("iv_name"), disks),
1083 ["disk/%s" % i for i in range(base_index, end_index)])
1085 def testPlain(self):
1087 constants.IDISK_SIZE: 1024,
1088 constants.IDISK_MODE: constants.DISK_RDWR,
1090 constants.IDISK_SIZE: 4096,
1091 constants.IDISK_VG: "othervg",
1092 constants.IDISK_MODE: constants.DISK_RDWR,
1095 result = self._TestTrivialDisk(constants.DT_PLAIN, disk_info, 3,
1098 self.assertEqual(map(operator.attrgetter("logical_id"), result), [
1099 ("testvg", "ec0-uq0.disk3"),
1100 ("othervg", "ec0-uq1.disk4"),
1104 def _AllowFileStorage():
1108 def _ForbidFileStorage():
1109 raise errors.OpPrereqError("Disallowed in test")
1112 self.assertRaises(errors.OpPrereqError, self._TestTrivialDisk,
1113 constants.DT_FILE, [], 0, NotImplemented,
1114 req_file_storage=self._ForbidFileStorage)
1115 self.assertRaises(errors.OpPrereqError, self._TestTrivialDisk,
1116 constants.DT_SHARED_FILE, [], 0, NotImplemented,
1117 req_shr_file_storage=self._ForbidFileStorage)
1119 for disk_template in [constants.DT_FILE, constants.DT_SHARED_FILE]:
1121 constants.IDISK_SIZE: 80 * 1024,
1122 constants.IDISK_MODE: constants.DISK_RDONLY,
1124 constants.IDISK_SIZE: 4096,
1125 constants.IDISK_MODE: constants.DISK_RDWR,
1127 constants.IDISK_SIZE: 6 * 1024,
1128 constants.IDISK_MODE: constants.DISK_RDWR,
1131 result = self._TestTrivialDisk(disk_template, disk_info, 2,
1132 constants.LD_FILE, file_storage_dir="/tmp",
1133 file_driver=constants.FD_BLKTAP,
1134 req_file_storage=self._AllowFileStorage,
1135 req_shr_file_storage=self._AllowFileStorage)
1137 self.assertEqual(map(operator.attrgetter("logical_id"), result), [
1138 (constants.FD_BLKTAP, "/tmp/disk2"),
1139 (constants.FD_BLKTAP, "/tmp/disk3"),
1140 (constants.FD_BLKTAP, "/tmp/disk4"),
1143 def testBlock(self):
1145 constants.IDISK_SIZE: 8 * 1024,
1146 constants.IDISK_MODE: constants.DISK_RDWR,
1147 constants.IDISK_ADOPT: "/tmp/some/block/dev",
1150 result = self._TestTrivialDisk(constants.DT_BLOCK, disk_info, 10,
1151 constants.LD_BLOCKDEV)
1153 self.assertEqual(map(operator.attrgetter("logical_id"), result), [
1154 (constants.BLOCKDEV_DRIVER_MANUAL, "/tmp/some/block/dev"),
1159 constants.IDISK_SIZE: 8 * 1024,
1160 constants.IDISK_MODE: constants.DISK_RDONLY,
1162 constants.IDISK_SIZE: 100 * 1024,
1163 constants.IDISK_MODE: constants.DISK_RDWR,
1166 result = self._TestTrivialDisk(constants.DT_RBD, disk_info, 0,
1169 self.assertEqual(map(operator.attrgetter("logical_id"), result), [
1170 ("rbd", "ec0-uq0.rbd.disk0"),
1171 ("rbd", "ec0-uq1.rbd.disk1"),
1174 def testDrbd8(self):
1175 gdt = cmdlib._GenerateDiskTemplate
1176 drbd8_defaults = constants.DISK_LD_DEFAULTS[constants.LD_DRBD8]
1177 drbd8_default_metavg = drbd8_defaults[constants.LDP_DEFAULT_METAVG]
1180 constants.IDISK_SIZE: 1024,
1181 constants.IDISK_MODE: constants.DISK_RDWR,
1183 constants.IDISK_SIZE: 100 * 1024,
1184 constants.IDISK_MODE: constants.DISK_RDONLY,
1185 constants.IDISK_METAVG: "metavg",
1187 constants.IDISK_SIZE: 4096,
1188 constants.IDISK_MODE: constants.DISK_RDWR,
1189 constants.IDISK_VG: "vgxyz",
1193 exp_logical_ids = [[
1194 (self.lu.cfg.GetVGName(), "ec0-uq0.disk0_data"),
1195 (drbd8_default_metavg, "ec0-uq0.disk0_meta"),
1197 (self.lu.cfg.GetVGName(), "ec0-uq1.disk1_data"),
1198 ("metavg", "ec0-uq1.disk1_meta"),
1200 ("vgxyz", "ec0-uq2.disk2_data"),
1201 (drbd8_default_metavg, "ec0-uq2.disk2_meta"),
1204 assert len(exp_logical_ids) == len(disk_info)
1206 map(lambda params: utils.ForceDictType(params,
1207 constants.IDISK_PARAMS_TYPES),
1210 # Check if empty list of secondaries is rejected
1211 self.assertRaises(errors.ProgrammerError, gdt, self.lu, constants.DT_DRBD8,
1212 "inst827.example.com", "node1334.example.com", [],
1213 disk_info, NotImplemented, NotImplemented, 0,
1214 self.lu.LogInfo, self.GetDiskParams())
1216 result = gdt(self.lu, constants.DT_DRBD8, "inst827.example.com",
1217 "node1334.example.com", ["node12272.example.com"],
1218 disk_info, NotImplemented, NotImplemented, 0, self.lu.LogInfo,
1219 self.GetDiskParams())
1221 for (idx, disk) in enumerate(result):
1222 self.assertTrue(isinstance(disk, objects.Disk))
1223 self.assertEqual(disk.dev_type, constants.LD_DRBD8)
1224 self.assertEqual(disk.size, disk_info[idx][constants.IDISK_SIZE])
1225 self.assertEqual(disk.mode, disk_info[idx][constants.IDISK_MODE])
1227 for child in disk.children:
1228 self.assertTrue(isinstance(disk, objects.Disk))
1229 self.assertEqual(child.dev_type, constants.LD_LV)
1230 self.assertTrue(child.children is None)
1232 self.assertEqual(map(operator.attrgetter("logical_id"), disk.children),
1233 exp_logical_ids[idx])
1235 self.assertEqual(len(disk.children), 2)
1236 self.assertEqual(disk.children[0].size, disk.size)
1237 self.assertEqual(disk.children[1].size, constants.DRBD_META_SIZE)
1239 self._CheckIvNames(result, 0, len(disk_info))
1240 cmdlib._UpdateIvNames(0, result)
1241 self._CheckIvNames(result, 0, len(disk_info))
1243 self.assertEqual(map(operator.attrgetter("logical_id"), result), [
1244 ("node1334.example.com", "node12272.example.com",
1245 constants.FIRST_DRBD_PORT, 20, 21, "ec0-secret0"),
1246 ("node1334.example.com", "node12272.example.com",
1247 constants.FIRST_DRBD_PORT + 1, 22, 23, "ec0-secret1"),
1248 ("node1334.example.com", "node12272.example.com",
1249 constants.FIRST_DRBD_PORT + 2, 24, 25, "ec0-secret2"),
1253 class _ConfigForDiskWipe:
1254 def __init__(self, exp_node):
1255 self._exp_node = exp_node
1257 def SetDiskID(self, device, node):
1258 assert isinstance(device, objects.Disk)
1259 assert node == self._exp_node
1262 class _RpcForDiskWipe:
1263 def __init__(self, exp_node, pause_cb, wipe_cb):
1264 self._exp_node = exp_node
1265 self._pause_cb = pause_cb
1266 self._wipe_cb = wipe_cb
1268 def call_blockdev_pause_resume_sync(self, node, disks, pause):
1269 assert node == self._exp_node
1270 return rpc.RpcResult(data=self._pause_cb(disks, pause))
1272 def call_blockdev_wipe(self, node, bdev, offset, size):
1273 assert node == self._exp_node
1274 return rpc.RpcResult(data=self._wipe_cb(bdev, offset, size))
1277 class _DiskPauseTracker:
1281 def __call__(self, (disks, instance), pause):
1282 assert not (set(disks) - set(instance.disks))
1284 self.history.extend((i.logical_id, i.size, pause)
1287 return (True, [True] * len(disks))
1290 class _DiskWipeProgressTracker:
1291 def __init__(self, start_offset):
1292 self._start_offset = start_offset
1295 def __call__(self, (disk, _), offset, size):
1296 assert isinstance(offset, (long, int))
1297 assert isinstance(size, (long, int))
1299 max_chunk_size = (disk.size / 100.0 * constants.MIN_WIPE_CHUNK_PERCENT)
1301 assert offset >= self._start_offset
1302 assert (offset + size) <= disk.size
1305 assert size <= constants.MAX_WIPE_CHUNK
1306 assert size <= max_chunk_size
1308 assert offset == self._start_offset or disk.logical_id in self.progress
1310 # Keep track of progress
1311 cur_progress = self.progress.setdefault(disk.logical_id, self._start_offset)
1313 assert cur_progress == offset
1316 self.progress[disk.logical_id] += size
1321 class TestWipeDisks(unittest.TestCase):
1322 def _FailingPauseCb(self, (disks, _), pause):
1323 self.assertEqual(len(disks), 3)
1324 self.assertTrue(pause)
1325 # Simulate an RPC error
1326 return (False, "error")
1328 def testPauseFailure(self):
1329 node_name = "node1372.example.com"
1331 lu = _FakeLU(rpc=_RpcForDiskWipe(node_name, self._FailingPauseCb,
1333 cfg=_ConfigForDiskWipe(node_name))
1336 objects.Disk(dev_type=constants.LD_LV),
1337 objects.Disk(dev_type=constants.LD_LV),
1338 objects.Disk(dev_type=constants.LD_LV),
1341 instance = objects.Instance(name="inst21201",
1342 primary_node=node_name,
1343 disk_template=constants.DT_PLAIN,
1346 self.assertRaises(errors.OpExecError, cmdlib._WipeDisks, lu, instance)
1348 def _FailingWipeCb(self, (disk, _), offset, size):
1349 # This should only ever be called for the first disk
1350 self.assertEqual(disk.logical_id, "disk0")
1351 return (False, None)
1353 def testFailingWipe(self):
1354 node_name = "node13445.example.com"
1355 pt = _DiskPauseTracker()
1357 lu = _FakeLU(rpc=_RpcForDiskWipe(node_name, pt, self._FailingWipeCb),
1358 cfg=_ConfigForDiskWipe(node_name))
1361 objects.Disk(dev_type=constants.LD_LV, logical_id="disk0",
1363 objects.Disk(dev_type=constants.LD_LV, logical_id="disk1",
1365 objects.Disk(dev_type=constants.LD_LV, logical_id="disk2", size=256),
1368 instance = objects.Instance(name="inst562",
1369 primary_node=node_name,
1370 disk_template=constants.DT_PLAIN,
1374 cmdlib._WipeDisks(lu, instance)
1375 except errors.OpExecError, err:
1376 self.assertTrue(str(err), "Could not wipe disk 0 at offset 0 ")
1378 self.fail("Did not raise exception")
1380 # Check if all disks were paused and resumed
1381 self.assertEqual(pt.history, [
1382 ("disk0", 100 * 1024, True),
1383 ("disk1", 500 * 1024, True),
1384 ("disk2", 256, True),
1385 ("disk0", 100 * 1024, False),
1386 ("disk1", 500 * 1024, False),
1387 ("disk2", 256, False),
1390 def _PrepareWipeTest(self, start_offset, disks):
1391 node_name = "node-with-offset%s.example.com" % start_offset
1392 pauset = _DiskPauseTracker()
1393 progresst = _DiskWipeProgressTracker(start_offset)
1395 lu = _FakeLU(rpc=_RpcForDiskWipe(node_name, pauset, progresst),
1396 cfg=_ConfigForDiskWipe(node_name))
1398 instance = objects.Instance(name="inst3560",
1399 primary_node=node_name,
1400 disk_template=constants.DT_PLAIN,
1403 return (lu, instance, pauset, progresst)
1405 def testNormalWipe(self):
1407 objects.Disk(dev_type=constants.LD_LV, logical_id="disk0", size=1024),
1408 objects.Disk(dev_type=constants.LD_LV, logical_id="disk1",
1410 objects.Disk(dev_type=constants.LD_LV, logical_id="disk2", size=128),
1411 objects.Disk(dev_type=constants.LD_LV, logical_id="disk3",
1412 size=constants.MAX_WIPE_CHUNK),
1415 (lu, instance, pauset, progresst) = self._PrepareWipeTest(0, disks)
1417 cmdlib._WipeDisks(lu, instance)
1419 self.assertEqual(pauset.history, [
1420 ("disk0", 1024, True),
1421 ("disk1", 500 * 1024, True),
1422 ("disk2", 128, True),
1423 ("disk3", constants.MAX_WIPE_CHUNK, True),
1424 ("disk0", 1024, False),
1425 ("disk1", 500 * 1024, False),
1426 ("disk2", 128, False),
1427 ("disk3", constants.MAX_WIPE_CHUNK, False),
1430 # Ensure the complete disk has been wiped
1431 self.assertEqual(progresst.progress,
1432 dict((i.logical_id, i.size) for i in disks))
1434 def testWipeWithStartOffset(self):
1435 for start_offset in [0, 280, 8895, 1563204]:
1437 objects.Disk(dev_type=constants.LD_LV, logical_id="disk0",
1439 objects.Disk(dev_type=constants.LD_LV, logical_id="disk1",
1440 size=start_offset + (100 * 1024)),
1443 (lu, instance, pauset, progresst) = \
1444 self._PrepareWipeTest(start_offset, disks)
1446 # Test start offset with only one disk
1447 cmdlib._WipeDisks(lu, instance,
1448 disks=[(1, disks[1], start_offset)])
1450 # Only the second disk may have been paused and wiped
1451 self.assertEqual(pauset.history, [
1452 ("disk1", start_offset + (100 * 1024), True),
1453 ("disk1", start_offset + (100 * 1024), False),
1455 self.assertEqual(progresst.progress, {
1456 "disk1": disks[1].size,
1460 class TestDiskSizeInBytesToMebibytes(unittest.TestCase):
1461 def testLessThanOneMebibyte(self):
1462 for i in [1, 2, 7, 512, 1000, 1023]:
1464 result = cmdlib._DiskSizeInBytesToMebibytes(lu, i)
1465 self.assertEqual(result, 1)
1466 self.assertEqual(len(lu.warning_log), 1)
1467 self.assertEqual(len(lu.warning_log[0]), 2)
1468 (_, (warnsize, )) = lu.warning_log[0]
1469 self.assertEqual(warnsize, (1024 * 1024) - i)
1472 for i in [1, 2, 7, 512, 1000, 1023]:
1474 result = cmdlib._DiskSizeInBytesToMebibytes(lu, i * 1024 * 1024)
1475 self.assertEqual(result, i)
1476 self.assertFalse(lu.warning_log)
1478 def testLargeNumber(self):
1479 for i in [1, 2, 7, 512, 1000, 1023, 2724, 12420]:
1480 for j in [1, 2, 486, 326, 986, 1023]:
1482 size = (1024 * 1024 * i) + j
1483 result = cmdlib._DiskSizeInBytesToMebibytes(lu, size)
1484 self.assertEqual(result, i + 1, msg="Amount was not rounded up")
1485 self.assertEqual(len(lu.warning_log), 1)
1486 self.assertEqual(len(lu.warning_log[0]), 2)
1487 (_, (warnsize, )) = lu.warning_log[0]
1488 self.assertEqual(warnsize, (1024 * 1024) - j)
1491 if __name__ == "__main__":
1492 testutils.GanetiTestProgram()