"exclusive_storage" cannot be changed on single nodes
[ganeti-local] / test / py / ganeti.objects_unittest.py
1 #!/usr/bin/python
2 #
3
4 # Copyright (C) 2006, 2007, 2008, 2010, 2012 Google Inc.
5 #
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.
10 #
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.
15 #
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
19 # 02110-1301, USA.
20
21
22 """Script for unittesting the objects module"""
23
24
25 import unittest
26
27 from ganeti import constants
28 from ganeti import objects
29 from ganeti import errors
30
31 import testutils
32
33
34 class SimpleObject(objects.ConfigObject):
35   __slots__ = ["a", "b"]
36
37
38 class TestDictState(unittest.TestCase):
39   """Simple dict tansformation tests"""
40
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())
46     o1.a = 2
47     o1.b = 5
48     self.assertEquals(o1.ToDict(), {"a": 2, "b": 5})
49     o2 = SimpleObject.FromDict(o1.ToDict())
50     self.assertEquals(o1.ToDict(), {"a": 2, "b": 5})
51
52
53 class TestClusterObject(unittest.TestCase):
54   """Tests done on a L{objects.Cluster}"""
55
56   def setUp(self):
57     hvparams = {
58       constants.HT_FAKE: {
59         "foo": "bar",
60         "bar": "foo",
61         "foobar": "barfoo",
62         },
63       }
64     os_hvp = {
65       "lenny-image": {
66         constants.HT_FAKE: {
67           "foo": "baz",
68           "foobar": "foobar",
69           "blah": "blibb",
70           "blubb": "blah",
71           },
72         constants.HT_XEN_PVM: {
73           "root_path": "/dev/sda5",
74           "foo": "foobar",
75           },
76         },
77       "ubuntu-hardy": {
78         },
79       }
80     ndparams = {
81         constants.ND_OOB_PROGRAM: "/bin/cluster-oob",
82         constants.ND_SPINDLE_COUNT: 1,
83         constants.ND_EXCLUSIVE_STORAGE: False,
84         }
85
86     self.fake_cl = objects.Cluster(hvparams=hvparams, os_hvp=os_hvp,
87                                    ndparams=ndparams)
88     self.fake_cl.UpgradeConfig()
89
90   def testGetHVDefaults(self):
91     cl = self.fake_cl
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])
98
99
100   def testFillHvFullMerge(self):
101     inst_hvparams = {
102       "blah": "blubb",
103       }
104
105     fake_dict = {
106       "foo": "baz",
107       "bar": "foo",
108       "foobar": "foobar",
109       "blah": "blubb",
110       "blubb": "blah",
111       }
112     fake_inst = objects.Instance(name="foobar",
113                                  os="lenny-image",
114                                  hypervisor=constants.HT_FAKE,
115                                  hvparams=inst_hvparams)
116     self.assertEqual(fake_dict, self.fake_cl.FillHV(fake_inst))
117
118   def testFillHvGlobalParams(self):
119     fake_inst = objects.Instance(name="foobar",
120                                  os="ubuntu-hardy",
121                                  hypervisor=constants.HT_FAKE,
122                                  hvparams={})
123     self.assertEqual(self.fake_cl.hvparams[constants.HT_FAKE],
124                      self.fake_cl.FillHV(fake_inst))
125
126   def testFillHvInstParams(self):
127     inst_hvparams = {
128       "blah": "blubb",
129       }
130     fake_inst = objects.Instance(name="foobar",
131                                  os="ubuntu-hardy",
132                                  hypervisor=constants.HT_XEN_PVM,
133                                  hvparams=inst_hvparams)
134     self.assertEqual(inst_hvparams, self.fake_cl.FillHV(fake_inst))
135
136   def testFillHvEmptyParams(self):
137     fake_inst = objects.Instance(name="foobar",
138                                  os="ubuntu-hardy",
139                                  hypervisor=constants.HT_XEN_PVM,
140                                  hvparams={})
141     self.assertEqual({}, self.fake_cl.FillHV(fake_inst))
142
143   def testFillHvPartialParams(self):
144     os = "lenny-image"
145     fake_inst = objects.Instance(name="foobar",
146                                  os=os,
147                                  hypervisor=constants.HT_XEN_PVM,
148                                  hvparams={})
149     self.assertEqual(self.fake_cl.os_hvp[os][constants.HT_XEN_PVM],
150                      self.fake_cl.FillHV(fake_inst))
151
152   def testFillNdParamsCluster(self):
153     fake_node = objects.Node(name="test",
154                              ndparams={},
155                              group="testgroup")
156     fake_group = objects.NodeGroup(name="testgroup",
157                                    ndparams={})
158     self.assertEqual(self.fake_cl.ndparams,
159                      self.fake_cl.FillND(fake_node, fake_group))
160
161   def testFillNdParamsNodeGroup(self):
162     fake_node = objects.Node(name="test",
163                              ndparams={},
164                              group="testgroup")
165     group_ndparams = {
166         constants.ND_OOB_PROGRAM: "/bin/group-oob",
167         constants.ND_SPINDLE_COUNT: 10,
168         constants.ND_EXCLUSIVE_STORAGE: True,
169         }
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))
174
175   def testFillNdParamsNode(self):
176     node_ndparams = {
177         constants.ND_OOB_PROGRAM: "/bin/node-oob",
178         constants.ND_SPINDLE_COUNT: 2,
179         constants.ND_EXCLUSIVE_STORAGE: True,
180         }
181     fake_node = objects.Node(name="test",
182                              ndparams=node_ndparams,
183                              group="testgroup")
184     fake_group = objects.NodeGroup(name="testgroup",
185                                    ndparams={})
186     self.assertEqual(node_ndparams,
187                      self.fake_cl.FillND(fake_node, fake_group))
188
189   def testFillNdParamsAll(self):
190     node_ndparams = {
191         constants.ND_OOB_PROGRAM: "/bin/node-oob",
192         constants.ND_SPINDLE_COUNT: 5,
193         constants.ND_EXCLUSIVE_STORAGE: True,
194         }
195     fake_node = objects.Node(name="test",
196                              ndparams=node_ndparams,
197                              group="testgroup")
198     group_ndparams = {
199         constants.ND_OOB_PROGRAM: "/bin/group-oob",
200         constants.ND_SPINDLE_COUNT: 4,
201         }
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))
206
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)
211
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)
214
215     self.fake_cl.enabled_hypervisors = sorted(constants.HYPER_TYPES)
216     self.assertEqual(self.fake_cl.primary_hypervisor, constants.HT_CHROOT)
217
218
219 class TestOS(unittest.TestCase):
220   ALL_DATA = [
221     "debootstrap",
222     "debootstrap+default",
223     "debootstrap++default",
224     ]
225
226   def testSplitNameVariant(self):
227     for name in self.ALL_DATA:
228       self.assertEqual(len(objects.OS.SplitNameVariant(name)), 2)
229
230   def testVariant(self):
231     self.assertEqual(objects.OS.GetVariant("debootstrap"), "")
232     self.assertEqual(objects.OS.GetVariant("debootstrap+default"), "default")
233
234
235 class TestInstance(unittest.TestCase):
236   def _GenericCheck(self, inst):
237     for i in [inst.all_nodes, inst.secondary_nodes]:
238       self.assertTrue(isinstance(inst.all_nodes, (list, tuple)),
239                       msg="Data type doesn't guarantee order")
240
241     self.assertTrue(inst.primary_node not in inst.secondary_nodes)
242     self.assertEqual(inst.all_nodes[0], inst.primary_node,
243                      msg="Primary node not first node in list")
244
245   def testNodesNoDisks(self):
246     inst = objects.Instance(name="fakeinst.example.com",
247       primary_node="pnode.example.com",
248       disks=[
249         ])
250
251     self._GenericCheck(inst)
252     self.assertEqual(len(inst.secondary_nodes), 0)
253     self.assertEqual(set(inst.all_nodes), set([inst.primary_node]))
254     self.assertEqual(inst.MapLVsByNode(), {
255       inst.primary_node: [],
256       })
257
258   def testNodesPlainDisks(self):
259     inst = objects.Instance(name="fakeinstplain.example.com",
260       primary_node="node3.example.com",
261       disks=[
262         objects.Disk(dev_type=constants.LD_LV, size=128,
263                      logical_id=("myxenvg", "disk25494")),
264         objects.Disk(dev_type=constants.LD_LV, size=512,
265                      logical_id=("myxenvg", "disk29071")),
266         ])
267
268     self._GenericCheck(inst)
269     self.assertEqual(len(inst.secondary_nodes), 0)
270     self.assertEqual(set(inst.all_nodes), set([inst.primary_node]))
271     self.assertEqual(inst.MapLVsByNode(), {
272       inst.primary_node: ["myxenvg/disk25494", "myxenvg/disk29071"],
273       })
274
275   def testNodesDrbdDisks(self):
276     inst = objects.Instance(name="fakeinstdrbd.example.com",
277       primary_node="node10.example.com",
278       disks=[
279         objects.Disk(dev_type=constants.LD_DRBD8, size=786432,
280           logical_id=("node10.example.com", "node15.example.com",
281                       12300, 0, 0, "secret"),
282           children=[
283             objects.Disk(dev_type=constants.LD_LV, size=786432,
284                          logical_id=("myxenvg", "disk0")),
285             objects.Disk(dev_type=constants.LD_LV, size=128,
286                          logical_id=("myxenvg", "meta0"))
287           ],
288           iv_name="disk/0")
289         ])
290
291     self._GenericCheck(inst)
292     self.assertEqual(set(inst.secondary_nodes), set(["node15.example.com"]))
293     self.assertEqual(set(inst.all_nodes),
294                      set([inst.primary_node, "node15.example.com"]))
295     self.assertEqual(inst.MapLVsByNode(), {
296       inst.primary_node: ["myxenvg/disk0", "myxenvg/meta0"],
297       "node15.example.com": ["myxenvg/disk0", "myxenvg/meta0"],
298       })
299
300     self.assertEqual(inst.FindDisk(0), inst.disks[0])
301     self.assertRaises(errors.OpPrereqError, inst.FindDisk, "hello")
302     self.assertRaises(errors.OpPrereqError, inst.FindDisk, 100)
303     self.assertRaises(errors.OpPrereqError, inst.FindDisk, 1)
304
305
306 class TestNode(unittest.TestCase):
307   def testEmpty(self):
308     self.assertEqual(objects.Node().ToDict(), {})
309     self.assertTrue(isinstance(objects.Node.FromDict({}), objects.Node))
310
311   def testHvState(self):
312     node = objects.Node(name="node18157.example.com", hv_state={
313       constants.HT_XEN_HVM: objects.NodeHvState(cpu_total=64),
314       constants.HT_KVM: objects.NodeHvState(cpu_node=1),
315       })
316
317     node2 = objects.Node.FromDict(node.ToDict())
318
319     # Make sure nothing can reference it anymore
320     del node
321
322     self.assertEqual(node2.name, "node18157.example.com")
323     self.assertEqual(frozenset(node2.hv_state), frozenset([
324       constants.HT_XEN_HVM,
325       constants.HT_KVM,
326       ]))
327     self.assertEqual(node2.hv_state[constants.HT_KVM].cpu_node, 1)
328     self.assertEqual(node2.hv_state[constants.HT_XEN_HVM].cpu_total, 64)
329
330   def testDiskState(self):
331     node = objects.Node(name="node32087.example.com", disk_state={
332       constants.LD_LV: {
333         "lv32352": objects.NodeDiskState(total=128),
334         "lv2082": objects.NodeDiskState(total=512),
335         },
336       })
337
338     node2 = objects.Node.FromDict(node.ToDict())
339
340     # Make sure nothing can reference it anymore
341     del node
342
343     self.assertEqual(node2.name, "node32087.example.com")
344     self.assertEqual(frozenset(node2.disk_state), frozenset([
345       constants.LD_LV,
346       ]))
347     self.assertEqual(frozenset(node2.disk_state[constants.LD_LV]), frozenset([
348       "lv32352",
349       "lv2082",
350       ]))
351     self.assertEqual(node2.disk_state[constants.LD_LV]["lv2082"].total, 512)
352     self.assertEqual(node2.disk_state[constants.LD_LV]["lv32352"].total, 128)
353
354   def testFilterEsNdp(self):
355     node1 = objects.Node(name="node11673.example.com", ndparams={
356       constants.ND_EXCLUSIVE_STORAGE: True,
357       })
358     node2 = objects.Node(name="node11674.example.com", ndparams={
359       constants.ND_SPINDLE_COUNT: 3,
360       constants.ND_EXCLUSIVE_STORAGE: False,
361       })
362     self.assertTrue(constants.ND_EXCLUSIVE_STORAGE in node1.ndparams)
363     node1.UpgradeConfig()
364     self.assertFalse(constants.ND_EXCLUSIVE_STORAGE in node1.ndparams)
365     self.assertTrue(constants.ND_EXCLUSIVE_STORAGE in node2.ndparams)
366     self.assertTrue(constants.ND_SPINDLE_COUNT in node2.ndparams)
367     node2.UpgradeConfig()
368     self.assertFalse(constants.ND_EXCLUSIVE_STORAGE in node2.ndparams)
369     self.assertTrue(constants.ND_SPINDLE_COUNT in node2.ndparams)
370
371
372 if __name__ == "__main__":
373   testutils.GanetiTestProgram()