4 # Copyright (C) 2006, 2007, 2008, 2010, 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 objects module"""
27 from ganeti import constants
28 from ganeti import objects
29 from ganeti import errors
34 class SimpleObject(objects.ConfigObject):
35 __slots__ = ["a", "b"]
38 class TestDictState(unittest.TestCase):
39 """Simple dict tansformation tests"""
41 def testSimpleObjectToDict(self):
42 o1 = SimpleObject(a="1")
43 self.assertEquals(o1.ToDict(), {"a": "1"})
44 self.assertEquals(o1.__getstate__(), {"a": "1"})
45 self.assertEquals(o1.__getstate__(), o1.ToDict())
48 self.assertEquals(o1.ToDict(), {"a": 2, "b": 5})
49 o2 = SimpleObject.FromDict(o1.ToDict())
50 self.assertEquals(o1.ToDict(), {"a": 2, "b": 5})
53 class TestClusterObject(unittest.TestCase):
54 """Tests done on a L{objects.Cluster}"""
72 constants.HT_XEN_PVM: {
73 "root_path": "/dev/sda5",
81 constants.ND_OOB_PROGRAM: "/bin/cluster-oob",
82 constants.ND_SPINDLE_COUNT: 1,
83 constants.ND_EXCLUSIVE_STORAGE: False,
86 self.fake_cl = objects.Cluster(hvparams=hvparams, os_hvp=os_hvp,
88 self.fake_cl.UpgradeConfig()
90 def testGetHVDefaults(self):
92 self.failUnlessEqual(cl.GetHVDefaults(constants.HT_FAKE),
93 cl.hvparams[constants.HT_FAKE])
94 self.failUnlessEqual(cl.GetHVDefaults(None), {})
95 self.failUnlessEqual(cl.GetHVDefaults(constants.HT_XEN_PVM,
96 os_name="lenny-image"),
97 cl.os_hvp["lenny-image"][constants.HT_XEN_PVM])
100 def testFillHvFullMerge(self):
112 fake_inst = objects.Instance(name="foobar",
114 hypervisor=constants.HT_FAKE,
115 hvparams=inst_hvparams)
116 self.assertEqual(fake_dict, self.fake_cl.FillHV(fake_inst))
118 def testFillHvGlobalParams(self):
119 fake_inst = objects.Instance(name="foobar",
121 hypervisor=constants.HT_FAKE,
123 self.assertEqual(self.fake_cl.hvparams[constants.HT_FAKE],
124 self.fake_cl.FillHV(fake_inst))
126 def testFillHvInstParams(self):
130 fake_inst = objects.Instance(name="foobar",
132 hypervisor=constants.HT_XEN_PVM,
133 hvparams=inst_hvparams)
134 self.assertEqual(inst_hvparams, self.fake_cl.FillHV(fake_inst))
136 def testFillHvEmptyParams(self):
137 fake_inst = objects.Instance(name="foobar",
139 hypervisor=constants.HT_XEN_PVM,
141 self.assertEqual({}, self.fake_cl.FillHV(fake_inst))
143 def testFillHvPartialParams(self):
145 fake_inst = objects.Instance(name="foobar",
147 hypervisor=constants.HT_XEN_PVM,
149 self.assertEqual(self.fake_cl.os_hvp[os][constants.HT_XEN_PVM],
150 self.fake_cl.FillHV(fake_inst))
152 def testFillNdParamsCluster(self):
153 fake_node = objects.Node(name="test",
156 fake_group = objects.NodeGroup(name="testgroup",
158 self.assertEqual(self.fake_cl.ndparams,
159 self.fake_cl.FillND(fake_node, fake_group))
161 def testFillNdParamsNodeGroup(self):
162 fake_node = objects.Node(name="test",
166 constants.ND_OOB_PROGRAM: "/bin/group-oob",
167 constants.ND_SPINDLE_COUNT: 10,
168 constants.ND_EXCLUSIVE_STORAGE: True,
170 fake_group = objects.NodeGroup(name="testgroup",
171 ndparams=group_ndparams)
172 self.assertEqual(group_ndparams,
173 self.fake_cl.FillND(fake_node, fake_group))
175 def testFillNdParamsNode(self):
177 constants.ND_OOB_PROGRAM: "/bin/node-oob",
178 constants.ND_SPINDLE_COUNT: 2,
179 constants.ND_EXCLUSIVE_STORAGE: True,
181 fake_node = objects.Node(name="test",
182 ndparams=node_ndparams,
184 fake_group = objects.NodeGroup(name="testgroup",
186 self.assertEqual(node_ndparams,
187 self.fake_cl.FillND(fake_node, fake_group))
189 def testFillNdParamsAll(self):
191 constants.ND_OOB_PROGRAM: "/bin/node-oob",
192 constants.ND_SPINDLE_COUNT: 5,
193 constants.ND_EXCLUSIVE_STORAGE: True,
195 fake_node = objects.Node(name="test",
196 ndparams=node_ndparams,
199 constants.ND_OOB_PROGRAM: "/bin/group-oob",
200 constants.ND_SPINDLE_COUNT: 4,
202 fake_group = objects.NodeGroup(name="testgroup",
203 ndparams=group_ndparams)
204 self.assertEqual(node_ndparams,
205 self.fake_cl.FillND(fake_node, fake_group))
207 def testPrimaryHypervisor(self):
208 assert self.fake_cl.enabled_hypervisors is None
209 self.fake_cl.enabled_hypervisors = [constants.HT_XEN_HVM]
210 self.assertEqual(self.fake_cl.primary_hypervisor, constants.HT_XEN_HVM)
212 self.fake_cl.enabled_hypervisors = [constants.HT_XEN_PVM, constants.HT_KVM]
213 self.assertEqual(self.fake_cl.primary_hypervisor, constants.HT_XEN_PVM)
215 self.fake_cl.enabled_hypervisors = sorted(constants.HYPER_TYPES)
216 self.assertEqual(self.fake_cl.primary_hypervisor, constants.HT_CHROOT)
218 def testUpgradeConfig(self):
219 # FIXME: This test is incomplete
220 cluster = objects.Cluster()
221 cluster.UpgradeConfig()
222 cluster = objects.Cluster(ipolicy={"unknown_key": None})
223 self.assertRaises(errors.ConfigurationError, cluster.UpgradeConfig)
226 class TestOS(unittest.TestCase):
229 "debootstrap+default",
230 "debootstrap++default",
233 def testSplitNameVariant(self):
234 for name in self.ALL_DATA:
235 self.assertEqual(len(objects.OS.SplitNameVariant(name)), 2)
237 def testVariant(self):
238 self.assertEqual(objects.OS.GetVariant("debootstrap"), "")
239 self.assertEqual(objects.OS.GetVariant("debootstrap+default"), "default")
242 class TestInstance(unittest.TestCase):
243 def _GenericCheck(self, inst):
244 for i in [inst.all_nodes, inst.secondary_nodes]:
245 self.assertTrue(isinstance(inst.all_nodes, (list, tuple)),
246 msg="Data type doesn't guarantee order")
248 self.assertTrue(inst.primary_node not in inst.secondary_nodes)
249 self.assertEqual(inst.all_nodes[0], inst.primary_node,
250 msg="Primary node not first node in list")
252 def testNodesNoDisks(self):
253 inst = objects.Instance(name="fakeinst.example.com",
254 primary_node="pnode.example.com",
258 self._GenericCheck(inst)
259 self.assertEqual(len(inst.secondary_nodes), 0)
260 self.assertEqual(set(inst.all_nodes), set([inst.primary_node]))
261 self.assertEqual(inst.MapLVsByNode(), {
262 inst.primary_node: [],
265 def testNodesPlainDisks(self):
266 inst = objects.Instance(name="fakeinstplain.example.com",
267 primary_node="node3.example.com",
269 objects.Disk(dev_type=constants.LD_LV, size=128,
270 logical_id=("myxenvg", "disk25494")),
271 objects.Disk(dev_type=constants.LD_LV, size=512,
272 logical_id=("myxenvg", "disk29071")),
275 self._GenericCheck(inst)
276 self.assertEqual(len(inst.secondary_nodes), 0)
277 self.assertEqual(set(inst.all_nodes), set([inst.primary_node]))
278 self.assertEqual(inst.MapLVsByNode(), {
279 inst.primary_node: ["myxenvg/disk25494", "myxenvg/disk29071"],
282 def testNodesDrbdDisks(self):
283 inst = objects.Instance(name="fakeinstdrbd.example.com",
284 primary_node="node10.example.com",
286 objects.Disk(dev_type=constants.LD_DRBD8, size=786432,
287 logical_id=("node10.example.com", "node15.example.com",
288 12300, 0, 0, "secret"),
290 objects.Disk(dev_type=constants.LD_LV, size=786432,
291 logical_id=("myxenvg", "disk0")),
292 objects.Disk(dev_type=constants.LD_LV, size=128,
293 logical_id=("myxenvg", "meta0"))
298 self._GenericCheck(inst)
299 self.assertEqual(set(inst.secondary_nodes), set(["node15.example.com"]))
300 self.assertEqual(set(inst.all_nodes),
301 set([inst.primary_node, "node15.example.com"]))
302 self.assertEqual(inst.MapLVsByNode(), {
303 inst.primary_node: ["myxenvg/disk0", "myxenvg/meta0"],
304 "node15.example.com": ["myxenvg/disk0", "myxenvg/meta0"],
307 self.assertEqual(inst.FindDisk(0), inst.disks[0])
308 self.assertRaises(errors.OpPrereqError, inst.FindDisk, "hello")
309 self.assertRaises(errors.OpPrereqError, inst.FindDisk, 100)
310 self.assertRaises(errors.OpPrereqError, inst.FindDisk, 1)
313 class TestNode(unittest.TestCase):
315 self.assertEqual(objects.Node().ToDict(), {})
316 self.assertTrue(isinstance(objects.Node.FromDict({}), objects.Node))
318 def testHvState(self):
319 node = objects.Node(name="node18157.example.com", hv_state={
320 constants.HT_XEN_HVM: objects.NodeHvState(cpu_total=64),
321 constants.HT_KVM: objects.NodeHvState(cpu_node=1),
324 node2 = objects.Node.FromDict(node.ToDict())
326 # Make sure nothing can reference it anymore
329 self.assertEqual(node2.name, "node18157.example.com")
330 self.assertEqual(frozenset(node2.hv_state), frozenset([
331 constants.HT_XEN_HVM,
334 self.assertEqual(node2.hv_state[constants.HT_KVM].cpu_node, 1)
335 self.assertEqual(node2.hv_state[constants.HT_XEN_HVM].cpu_total, 64)
337 def testDiskState(self):
338 node = objects.Node(name="node32087.example.com", disk_state={
340 "lv32352": objects.NodeDiskState(total=128),
341 "lv2082": objects.NodeDiskState(total=512),
345 node2 = objects.Node.FromDict(node.ToDict())
347 # Make sure nothing can reference it anymore
350 self.assertEqual(node2.name, "node32087.example.com")
351 self.assertEqual(frozenset(node2.disk_state), frozenset([
354 self.assertEqual(frozenset(node2.disk_state[constants.LD_LV]), frozenset([
358 self.assertEqual(node2.disk_state[constants.LD_LV]["lv2082"].total, 512)
359 self.assertEqual(node2.disk_state[constants.LD_LV]["lv32352"].total, 128)
361 def testFilterEsNdp(self):
362 node1 = objects.Node(name="node11673.example.com", ndparams={
363 constants.ND_EXCLUSIVE_STORAGE: True,
365 node2 = objects.Node(name="node11674.example.com", ndparams={
366 constants.ND_SPINDLE_COUNT: 3,
367 constants.ND_EXCLUSIVE_STORAGE: False,
369 self.assertTrue(constants.ND_EXCLUSIVE_STORAGE in node1.ndparams)
370 node1.UpgradeConfig()
371 self.assertFalse(constants.ND_EXCLUSIVE_STORAGE in node1.ndparams)
372 self.assertTrue(constants.ND_EXCLUSIVE_STORAGE in node2.ndparams)
373 self.assertTrue(constants.ND_SPINDLE_COUNT in node2.ndparams)
374 node2.UpgradeConfig()
375 self.assertFalse(constants.ND_EXCLUSIVE_STORAGE in node2.ndparams)
376 self.assertTrue(constants.ND_SPINDLE_COUNT in node2.ndparams)
379 class TestInstancePolicy(unittest.TestCase):
381 # Policies are big, and we want to see the difference in case of an error
384 def _AssertIPolicyIsFull(self, policy):
385 self.assertEqual(frozenset(policy.keys()), constants.IPOLICY_ALL_KEYS)
386 for key in constants.IPOLICY_ISPECS:
388 self.assertEqual(frozenset(spec.keys()), constants.ISPECS_PARAMETERS)
390 def testDefaultIPolicy(self):
391 objects.InstancePolicy.CheckParameterSyntax(constants.IPOLICY_DEFAULTS,
393 self._AssertIPolicyIsFull(constants.IPOLICY_DEFAULTS)
395 def testCheckISpecSyntax(self):
397 for check_std in [True, False]:
399 allkeys = constants.IPOLICY_ISPECS
401 allkeys = constants.IPOLICY_ISPECS - frozenset([constants.ISPECS_STD])
402 # Only one policy limit
404 policy = dict((k, {}) for k in allkeys)
405 policy[key][par] = 11
406 objects.InstancePolicy.CheckISpecSyntax(policy, par, check_std)
408 good_values = [(11, 11), (11, 40), (0, 0)]
409 for (mn, mx) in good_values:
410 policy = dict((k, {}) for k in allkeys)
411 policy[constants.ISPECS_MIN][par] = mn
412 policy[constants.ISPECS_MAX][par] = mx
413 objects.InstancePolicy.CheckISpecSyntax(policy, par, check_std)
414 policy = dict((k, {}) for k in allkeys)
415 policy[constants.ISPECS_MIN][par] = 11
416 policy[constants.ISPECS_MAX][par] = 5
417 self.assertRaises(errors.ConfigurationError,
418 objects.InstancePolicy.CheckISpecSyntax,
419 policy, par, check_std)
426 for (mn, st, mx) in good_values:
428 constants.ISPECS_MIN: {par: mn},
429 constants.ISPECS_STD: {par: st},
430 constants.ISPECS_MAX: {par: mx},
432 objects.InstancePolicy.CheckISpecSyntax(policy, par, True)
441 for (mn, st, mx) in bad_values:
443 constants.ISPECS_MIN: {par: mn},
444 constants.ISPECS_STD: {par: st},
445 constants.ISPECS_MAX: {par: mx},
447 self.assertRaises(errors.ConfigurationError,
448 objects.InstancePolicy.CheckISpecSyntax,
451 def testCheckDiskTemplates(self):
452 invalid = "this_is_not_a_good_template"
453 for dt in constants.DISK_TEMPLATES:
454 objects.InstancePolicy.CheckDiskTemplates([dt])
455 objects.InstancePolicy.CheckDiskTemplates(list(constants.DISK_TEMPLATES))
458 [constants.DT_DRBD8, invalid],
459 list(constants.DISK_TEMPLATES) + [invalid],
463 for dtl in bad_examples:
464 self.assertRaises(errors.ConfigurationError,
465 objects.InstancePolicy.CheckDiskTemplates,
468 def testCheckParameterSyntax(self):
469 invalid = "this_key_shouldnt_be_here"
470 for check_std in [True, False]:
471 self.assertRaises(KeyError,
472 objects.InstancePolicy.CheckParameterSyntax,
474 policy = objects.MakeEmptyIPolicy()
475 policy[invalid] = None
476 self.assertRaises(errors.ConfigurationError,
477 objects.InstancePolicy.CheckParameterSyntax,
479 for par in constants.IPOLICY_PARAMETERS:
480 policy = objects.MakeEmptyIPolicy()
481 for val in ("blah", None, {}, [42]):
483 self.assertRaises(errors.ConfigurationError,
484 objects.InstancePolicy.CheckParameterSyntax,
487 def testFillIPolicyEmpty(self):
488 policy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, {})
489 objects.InstancePolicy.CheckParameterSyntax(policy, True)
490 self.assertEqual(policy, constants.IPOLICY_DEFAULTS)
492 def _AssertISpecsMerged(self, default_spec, diff_spec, merged_spec):
493 for (param, value) in merged_spec.items():
494 if param in diff_spec:
495 self.assertEqual(value, diff_spec[param])
497 self.assertEqual(value, default_spec[param])
499 def _AssertIPolicyMerged(self, default_pol, diff_pol, merged_pol):
500 for (key, value) in merged_pol.items():
502 if key in constants.IPOLICY_ISPECS:
503 self._AssertISpecsMerged(default_pol[key], diff_pol[key], value)
505 self.assertEqual(value, diff_pol[key])
507 self.assertEqual(value, default_pol[key])
509 def testFillIPolicy(self):
511 {constants.IPOLICY_VCPU_RATIO: 3.14},
512 {constants.IPOLICY_SPINDLE_RATIO: 2.72},
513 {constants.IPOLICY_DTS: [constants.DT_FILE]},
515 for diff_pol in partial_policies:
516 policy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, diff_pol)
517 objects.InstancePolicy.CheckParameterSyntax(policy, True)
518 self._AssertIPolicyIsFull(policy)
519 self._AssertIPolicyMerged(constants.IPOLICY_DEFAULTS, diff_pol, policy)
521 def testFillIPolicySpecs(self):
523 {constants.ISPECS_MIN: {constants.ISPEC_MEM_SIZE: 32},
524 constants.ISPECS_MAX: {constants.ISPEC_CPU_COUNT: 1024}},
525 {constants.ISPECS_STD: {constants.ISPEC_DISK_SIZE: 2048},
526 constants.ISPECS_MAX: {
527 constants.ISPEC_DISK_COUNT: constants.MAX_DISKS - 1,
528 constants.ISPEC_NIC_COUNT: constants.MAX_NICS - 1,
530 {constants.ISPECS_STD: {constants.ISPEC_SPINDLE_USE: 3}},
532 for diff_pol in partial_policies:
533 policy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, diff_pol)
534 objects.InstancePolicy.CheckParameterSyntax(policy, True)
535 self._AssertIPolicyIsFull(policy)
536 self._AssertIPolicyMerged(constants.IPOLICY_DEFAULTS, diff_pol, policy)
539 if __name__ == "__main__":
540 testutils.GanetiTestProgram()