Statistics
| Branch: | Tag: | Revision:

root / test / py / ganeti.objects_unittest.py @ 14933c17

History | View | Annotate | Download (27 kB)

1
#!/usr/bin/python
2
#
3

    
4
# Copyright (C) 2006, 2007, 2008, 2010, 2012, 2013 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 copy
26
import unittest
27

    
28
from ganeti import constants
29
from ganeti import objects
30
from ganeti import errors
31

    
32
import testutils
33

    
34

    
35
class SimpleObject(objects.ConfigObject):
36
  __slots__ = ["a", "b"]
37

    
38

    
39
class TestDictState(unittest.TestCase):
40
  """Simple dict tansformation tests"""
41

    
42
  def testSimpleObjectToDict(self):
43
    o1 = SimpleObject(a="1")
44
    self.assertEquals(o1.ToDict(), {"a": "1"})
45
    self.assertEquals(o1.__getstate__(), {"a": "1"})
46
    self.assertEquals(o1.__getstate__(), o1.ToDict())
47
    o1.a = 2
48
    o1.b = 5
49
    self.assertEquals(o1.ToDict(), {"a": 2, "b": 5})
50
    o2 = SimpleObject.FromDict(o1.ToDict())
51
    self.assertEquals(o1.ToDict(), {"a": 2, "b": 5})
52

    
53

    
54
class TestClusterObject(unittest.TestCase):
55
  """Tests done on a L{objects.Cluster}"""
56

    
57
  def setUp(self):
58
    hvparams = {
59
      constants.HT_FAKE: {
60
        "foo": "bar",
61
        "bar": "foo",
62
        "foobar": "barfoo",
63
        },
64
      }
65
    os_hvp = {
66
      "lenny-image": {
67
        constants.HT_FAKE: {
68
          "foo": "baz",
69
          "foobar": "foobar",
70
          "blah": "blibb",
71
          "blubb": "blah",
72
          },
73
        constants.HT_XEN_PVM: {
74
          "root_path": "/dev/sda5",
75
          "foo": "foobar",
76
          },
77
        },
78
      "ubuntu-hardy": {
79
        },
80
      }
81
    ndparams = {
82
        constants.ND_OOB_PROGRAM: "/bin/cluster-oob",
83
        constants.ND_SPINDLE_COUNT: 1,
84
        constants.ND_EXCLUSIVE_STORAGE: False,
85
        }
86

    
87
    self.fake_cl = objects.Cluster(hvparams=hvparams, os_hvp=os_hvp,
88
                                   ndparams=ndparams)
89
    self.fake_cl.UpgradeConfig()
90

    
91
  def testGetHVDefaults(self):
92
    cl = self.fake_cl
93
    self.failUnlessEqual(cl.GetHVDefaults(constants.HT_FAKE),
94
                         cl.hvparams[constants.HT_FAKE])
95
    self.failUnlessEqual(cl.GetHVDefaults(None), {})
96
    self.failUnlessEqual(cl.GetHVDefaults(constants.HT_XEN_PVM,
97
                                          os_name="lenny-image"),
98
                         cl.os_hvp["lenny-image"][constants.HT_XEN_PVM])
99

    
100
  def testFillHvFullMerge(self):
101
    inst_hvparams = {
102
      "blah": "blubb",
103
      }
104

    
105
    fake_dict = constants.HVC_DEFAULTS[constants.HT_FAKE].copy()
106
    fake_dict.update({
107
      "foo": "baz",
108
      "bar": "foo",
109
      "foobar": "foobar",
110
      "blah": "blubb",
111
      "blubb": "blah",
112
      })
113
    fake_inst = objects.Instance(name="foobar",
114
                                 os="lenny-image",
115
                                 hypervisor=constants.HT_FAKE,
116
                                 hvparams=inst_hvparams)
117
    self.assertEqual(fake_dict, self.fake_cl.FillHV(fake_inst))
118

    
119
  def testFillHvGlobalParams(self):
120
    fake_inst = objects.Instance(name="foobar",
121
                                 os="ubuntu-hardy",
122
                                 hypervisor=constants.HT_FAKE,
123
                                 hvparams={})
124
    self.assertEqual(self.fake_cl.hvparams[constants.HT_FAKE],
125
                     self.fake_cl.FillHV(fake_inst))
126

    
127
  def testFillHvInstParams(self):
128
    inst_hvparams = {
129
      "blah": "blubb",
130
      }
131
    fake_inst = objects.Instance(name="foobar",
132
                                 os="ubuntu-hardy",
133
                                 hypervisor=constants.HT_XEN_PVM,
134
                                 hvparams=inst_hvparams)
135
    self.assertEqual(inst_hvparams, self.fake_cl.FillHV(fake_inst))
136

    
137
  def testFillHvEmptyParams(self):
138
    fake_inst = objects.Instance(name="foobar",
139
                                 os="ubuntu-hardy",
140
                                 hypervisor=constants.HT_XEN_PVM,
141
                                 hvparams={})
142
    self.assertEqual({}, self.fake_cl.FillHV(fake_inst))
143

    
144
  def testFillHvPartialParams(self):
145
    os = "lenny-image"
146
    fake_inst = objects.Instance(name="foobar",
147
                                 os=os,
148
                                 hypervisor=constants.HT_XEN_PVM,
149
                                 hvparams={})
150
    self.assertEqual(self.fake_cl.os_hvp[os][constants.HT_XEN_PVM],
151
                     self.fake_cl.FillHV(fake_inst))
152

    
153
  def testFillNdParamsCluster(self):
154
    fake_node = objects.Node(name="test",
155
                             ndparams={},
156
                             group="testgroup")
157
    fake_group = objects.NodeGroup(name="testgroup",
158
                                   ndparams={})
159
    self.assertEqual(self.fake_cl.ndparams,
160
                     self.fake_cl.FillND(fake_node, fake_group))
161

    
162
  def testFillNdParamsNodeGroup(self):
163
    fake_node = objects.Node(name="test",
164
                             ndparams={},
165
                             group="testgroup")
166
    group_ndparams = {
167
        constants.ND_OOB_PROGRAM: "/bin/group-oob",
168
        constants.ND_SPINDLE_COUNT: 10,
169
        constants.ND_EXCLUSIVE_STORAGE: True,
170
        constants.ND_OVS: True,
171
        constants.ND_OVS_LINK: "eth2",
172
        constants.ND_OVS_NAME: "openvswitch",
173
        }
174
    fake_group = objects.NodeGroup(name="testgroup",
175
                                   ndparams=group_ndparams)
176
    self.assertEqual(group_ndparams,
177
                     self.fake_cl.FillND(fake_node, fake_group))
178

    
179
  def testFillNdParamsNode(self):
180
    node_ndparams = {
181
        constants.ND_OOB_PROGRAM: "/bin/node-oob",
182
        constants.ND_SPINDLE_COUNT: 2,
183
        constants.ND_EXCLUSIVE_STORAGE: True,
184
        constants.ND_OVS: True,
185
        constants.ND_OVS_LINK: "eth2",
186
        constants.ND_OVS_NAME: "openvswitch",
187
        }
188
    fake_node = objects.Node(name="test",
189
                             ndparams=node_ndparams,
190
                             group="testgroup")
191
    fake_group = objects.NodeGroup(name="testgroup",
192
                                   ndparams={})
193
    self.assertEqual(node_ndparams,
194
                     self.fake_cl.FillND(fake_node, fake_group))
195

    
196
  def testFillNdParamsAll(self):
197
    node_ndparams = {
198
        constants.ND_OOB_PROGRAM: "/bin/node-oob",
199
        constants.ND_SPINDLE_COUNT: 5,
200
        constants.ND_EXCLUSIVE_STORAGE: True,
201
        constants.ND_OVS: True,
202
        constants.ND_OVS_LINK: "eth2",
203
        constants.ND_OVS_NAME: "openvswitch",
204
        }
205
    fake_node = objects.Node(name="test",
206
                             ndparams=node_ndparams,
207
                             group="testgroup")
208
    group_ndparams = {
209
        constants.ND_OOB_PROGRAM: "/bin/group-oob",
210
        constants.ND_SPINDLE_COUNT: 4,
211
        }
212
    fake_group = objects.NodeGroup(name="testgroup",
213
                                   ndparams=group_ndparams)
214
    self.assertEqual(node_ndparams,
215
                     self.fake_cl.FillND(fake_node, fake_group))
216

    
217
  def testPrimaryHypervisor(self):
218
    assert self.fake_cl.enabled_hypervisors is None
219
    self.fake_cl.enabled_hypervisors = [constants.HT_XEN_HVM]
220
    self.assertEqual(self.fake_cl.primary_hypervisor, constants.HT_XEN_HVM)
221

    
222
    self.fake_cl.enabled_hypervisors = [constants.HT_XEN_PVM, constants.HT_KVM]
223
    self.assertEqual(self.fake_cl.primary_hypervisor, constants.HT_XEN_PVM)
224

    
225
    self.fake_cl.enabled_hypervisors = sorted(constants.HYPER_TYPES)
226
    self.assertEqual(self.fake_cl.primary_hypervisor, constants.HT_CHROOT)
227

    
228
  def testUpgradeConfig(self):
229
    # FIXME: This test is incomplete
230
    cluster = objects.Cluster()
231
    cluster.UpgradeConfig()
232
    cluster = objects.Cluster(ipolicy={"unknown_key": None})
233
    self.assertRaises(errors.ConfigurationError, cluster.UpgradeConfig)
234

    
235
  def testUpgradeEnabledDiskTemplates(self):
236
    cfg = objects.ConfigData()
237
    cfg.cluster = objects.Cluster()
238
    cfg.cluster.volume_group_name = "myvg"
239
    instance1 = objects.Instance()
240
    instance1.disk_template = constants.DT_DISKLESS
241
    instance2 = objects.Instance()
242
    instance2.disk_template = constants.DT_RBD
243
    cfg.instances = { "myinstance1": instance1, "myinstance2": instance2 }
244
    nodegroup = objects.NodeGroup()
245
    nodegroup.ipolicy = {}
246
    nodegroup.ipolicy[constants.IPOLICY_DTS] = [instance1.disk_template, \
247
      constants.DT_BLOCK]
248
    cfg.cluster.ipolicy = {}
249
    cfg.cluster.ipolicy[constants.IPOLICY_DTS] = \
250
      [constants.DT_EXT, constants.DT_DISKLESS]
251
    cfg.nodegroups = { "mynodegroup": nodegroup }
252
    cfg._UpgradeEnabledDiskTemplates()
253
    expected_disk_templates = [constants.DT_DRBD8,
254
                               constants.DT_PLAIN,
255
                               instance1.disk_template,
256
                               instance2.disk_template]
257
    self.assertEqual(set(expected_disk_templates),
258
                     set(cfg.cluster.enabled_disk_templates))
259
    self.assertEqual(set([instance1.disk_template]),
260
                     set(cfg.cluster.ipolicy[constants.IPOLICY_DTS]))
261

    
262

    
263
class TestClusterObjectTcpUdpPortPool(unittest.TestCase):
264
  def testNewCluster(self):
265
    self.assertTrue(objects.Cluster().tcpudp_port_pool is None)
266

    
267
  def testSerializingEmpty(self):
268
    self.assertEqual(objects.Cluster().ToDict(), {
269
      "tcpudp_port_pool": [],
270
      })
271

    
272
  def testSerializing(self):
273
    cluster = objects.Cluster.FromDict({})
274
    self.assertEqual(cluster.tcpudp_port_pool, set())
275

    
276
    cluster.tcpudp_port_pool.add(3546)
277
    cluster.tcpudp_port_pool.add(62511)
278

    
279
    data = cluster.ToDict()
280
    self.assertEqual(data.keys(), ["tcpudp_port_pool"])
281
    self.assertEqual(sorted(data["tcpudp_port_pool"]), sorted([3546, 62511]))
282

    
283
  def testDeserializingEmpty(self):
284
    cluster = objects.Cluster.FromDict({})
285
    self.assertEqual(cluster.tcpudp_port_pool, set())
286

    
287
  def testDeserialize(self):
288
    cluster = objects.Cluster.FromDict({
289
      "tcpudp_port_pool": [26214, 10039, 267],
290
      })
291
    self.assertEqual(cluster.tcpudp_port_pool, set([26214, 10039, 267]))
292

    
293

    
294
class TestOS(unittest.TestCase):
295
  ALL_DATA = [
296
    "debootstrap",
297
    "debootstrap+default",
298
    "debootstrap++default",
299
    ]
300

    
301
  def testSplitNameVariant(self):
302
    for name in self.ALL_DATA:
303
      self.assertEqual(len(objects.OS.SplitNameVariant(name)), 2)
304

    
305
  def testVariant(self):
306
    self.assertEqual(objects.OS.GetVariant("debootstrap"), "")
307
    self.assertEqual(objects.OS.GetVariant("debootstrap+default"), "default")
308

    
309

    
310
class TestInstance(unittest.TestCase):
311
  def _GenericCheck(self, inst):
312
    for i in [inst.all_nodes, inst.secondary_nodes]:
313
      self.assertTrue(isinstance(inst.all_nodes, (list, tuple)),
314
                      msg="Data type doesn't guarantee order")
315

    
316
    self.assertTrue(inst.primary_node not in inst.secondary_nodes)
317
    self.assertEqual(inst.all_nodes[0], inst.primary_node,
318
                     msg="Primary node not first node in list")
319

    
320
  def testNodesNoDisks(self):
321
    inst = objects.Instance(name="fakeinst.example.com",
322
      primary_node="pnode.example.com",
323
      disks=[
324
        ])
325

    
326
    self._GenericCheck(inst)
327
    self.assertEqual(len(inst.secondary_nodes), 0)
328
    self.assertEqual(set(inst.all_nodes), set([inst.primary_node]))
329
    self.assertEqual(inst.MapLVsByNode(), {
330
      inst.primary_node: [],
331
      })
332

    
333
  def testNodesPlainDisks(self):
334
    inst = objects.Instance(name="fakeinstplain.example.com",
335
      primary_node="node3.example.com",
336
      disks=[
337
        objects.Disk(dev_type=constants.DT_PLAIN, size=128,
338
                     logical_id=("myxenvg", "disk25494")),
339
        objects.Disk(dev_type=constants.DT_PLAIN, size=512,
340
                     logical_id=("myxenvg", "disk29071")),
341
        ])
342

    
343
    self._GenericCheck(inst)
344
    self.assertEqual(len(inst.secondary_nodes), 0)
345
    self.assertEqual(set(inst.all_nodes), set([inst.primary_node]))
346
    self.assertEqual(inst.MapLVsByNode(), {
347
      inst.primary_node: ["myxenvg/disk25494", "myxenvg/disk29071"],
348
      })
349

    
350
  def testNodesDrbdDisks(self):
351
    inst = objects.Instance(name="fakeinstdrbd.example.com",
352
      primary_node="node10.example.com",
353
      disks=[
354
        objects.Disk(dev_type=constants.DT_DRBD8, size=786432,
355
          logical_id=("node10.example.com", "node15.example.com",
356
                      12300, 0, 0, "secret"),
357
          children=[
358
            objects.Disk(dev_type=constants.DT_PLAIN, size=786432,
359
                         logical_id=("myxenvg", "disk0")),
360
            objects.Disk(dev_type=constants.DT_PLAIN, size=128,
361
                         logical_id=("myxenvg", "meta0"))
362
          ],
363
          iv_name="disk/0")
364
        ])
365

    
366
    self._GenericCheck(inst)
367
    self.assertEqual(set(inst.secondary_nodes), set(["node15.example.com"]))
368
    self.assertEqual(set(inst.all_nodes),
369
                     set([inst.primary_node, "node15.example.com"]))
370
    self.assertEqual(inst.MapLVsByNode(), {
371
      inst.primary_node: ["myxenvg/disk0", "myxenvg/meta0"],
372
      "node15.example.com": ["myxenvg/disk0", "myxenvg/meta0"],
373
      })
374

    
375
    self.assertEqual(inst.FindDisk(0), inst.disks[0])
376
    self.assertRaises(errors.OpPrereqError, inst.FindDisk, "hello")
377
    self.assertRaises(errors.OpPrereqError, inst.FindDisk, 100)
378
    self.assertRaises(errors.OpPrereqError, inst.FindDisk, 1)
379

    
380

    
381
class TestNode(unittest.TestCase):
382
  def testEmpty(self):
383
    self.assertEqual(objects.Node().ToDict(), {})
384
    self.assertTrue(isinstance(objects.Node.FromDict({}), objects.Node))
385

    
386
  def testHvState(self):
387
    node = objects.Node(name="node18157.example.com", hv_state={
388
      constants.HT_XEN_HVM: objects.NodeHvState(cpu_total=64),
389
      constants.HT_KVM: objects.NodeHvState(cpu_node=1),
390
      })
391

    
392
    node2 = objects.Node.FromDict(node.ToDict())
393

    
394
    # Make sure nothing can reference it anymore
395
    del node
396

    
397
    self.assertEqual(node2.name, "node18157.example.com")
398
    self.assertEqual(frozenset(node2.hv_state), frozenset([
399
      constants.HT_XEN_HVM,
400
      constants.HT_KVM,
401
      ]))
402
    self.assertEqual(node2.hv_state[constants.HT_KVM].cpu_node, 1)
403
    self.assertEqual(node2.hv_state[constants.HT_XEN_HVM].cpu_total, 64)
404

    
405
  def testDiskState(self):
406
    node = objects.Node(name="node32087.example.com", disk_state={
407
      constants.DT_PLAIN: {
408
        "lv32352": objects.NodeDiskState(total=128),
409
        "lv2082": objects.NodeDiskState(total=512),
410
        },
411
      })
412

    
413
    node2 = objects.Node.FromDict(node.ToDict())
414

    
415
    # Make sure nothing can reference it anymore
416
    del node
417

    
418
    self.assertEqual(node2.name, "node32087.example.com")
419
    self.assertEqual(frozenset(node2.disk_state), frozenset([
420
      constants.DT_PLAIN,
421
      ]))
422
    self.assertEqual(frozenset(node2.disk_state[constants.DT_PLAIN]),
423
                     frozenset(["lv32352", "lv2082"]))
424
    self.assertEqual(node2.disk_state[constants.DT_PLAIN]["lv2082"].total, 512)
425
    self.assertEqual(node2.disk_state[constants.DT_PLAIN]["lv32352"].total, 128)
426

    
427
  def testFilterEsNdp(self):
428
    node1 = objects.Node(name="node11673.example.com", ndparams={
429
      constants.ND_EXCLUSIVE_STORAGE: True,
430
      })
431
    node2 = objects.Node(name="node11674.example.com", ndparams={
432
      constants.ND_SPINDLE_COUNT: 3,
433
      constants.ND_EXCLUSIVE_STORAGE: False,
434
      })
435
    self.assertTrue(constants.ND_EXCLUSIVE_STORAGE in node1.ndparams)
436
    node1.UpgradeConfig()
437
    self.assertFalse(constants.ND_EXCLUSIVE_STORAGE in node1.ndparams)
438
    self.assertTrue(constants.ND_EXCLUSIVE_STORAGE in node2.ndparams)
439
    self.assertTrue(constants.ND_SPINDLE_COUNT in node2.ndparams)
440
    node2.UpgradeConfig()
441
    self.assertFalse(constants.ND_EXCLUSIVE_STORAGE in node2.ndparams)
442
    self.assertTrue(constants.ND_SPINDLE_COUNT in node2.ndparams)
443

    
444

    
445
class TestInstancePolicy(unittest.TestCase):
446
  def setUp(self):
447
    # Policies are big, and we want to see the difference in case of an error
448
    self.maxDiff = None
449

    
450
  def _AssertIPolicyIsFull(self, policy):
451
    self.assertEqual(frozenset(policy.keys()), constants.IPOLICY_ALL_KEYS)
452
    self.assertTrue(len(policy[constants.ISPECS_MINMAX]) > 0)
453
    for minmax in policy[constants.ISPECS_MINMAX]:
454
      self.assertEqual(frozenset(minmax.keys()), constants.ISPECS_MINMAX_KEYS)
455
      for key in constants.ISPECS_MINMAX_KEYS:
456
        self.assertEqual(frozenset(minmax[key].keys()),
457
                         constants.ISPECS_PARAMETERS)
458
    self.assertEqual(frozenset(policy[constants.ISPECS_STD].keys()),
459
                     constants.ISPECS_PARAMETERS)
460

    
461
  def testDefaultIPolicy(self):
462
    objects.InstancePolicy.CheckParameterSyntax(constants.IPOLICY_DEFAULTS,
463
                                                True)
464
    self._AssertIPolicyIsFull(constants.IPOLICY_DEFAULTS)
465

    
466
  def _AssertPolicyIsBad(self, ipolicy, do_check_std=None):
467
    if do_check_std is None:
468
      check_std_vals = [False, True]
469
    else:
470
      check_std_vals = [do_check_std]
471
    for check_std in check_std_vals:
472
      self.assertRaises(errors.ConfigurationError,
473
                        objects.InstancePolicy.CheckISpecSyntax,
474
                        ipolicy, check_std)
475

    
476
  def testCheckISpecSyntax(self):
477
    default_stdspec = constants.IPOLICY_DEFAULTS[constants.ISPECS_STD]
478
    incomplete_ipolicies = [
479
      {
480
         constants.ISPECS_MINMAX: [],
481
         constants.ISPECS_STD: default_stdspec,
482
         },
483
      {
484
         constants.ISPECS_MINMAX: [{}],
485
         constants.ISPECS_STD: default_stdspec,
486
         },
487
      {
488
        constants.ISPECS_MINMAX: [{
489
          constants.ISPECS_MIN: NotImplemented,
490
          }],
491
        constants.ISPECS_STD: default_stdspec,
492
        },
493
      {
494
        constants.ISPECS_MINMAX: [{
495
          constants.ISPECS_MAX: NotImplemented,
496
          }],
497
        constants.ISPECS_STD: default_stdspec,
498
        },
499
      {
500
        constants.ISPECS_MINMAX: [{
501
          constants.ISPECS_MIN: NotImplemented,
502
          constants.ISPECS_MAX: NotImplemented,
503
          }],
504
        },
505
      ]
506
    for ipol in incomplete_ipolicies:
507
      self.assertRaises(errors.ConfigurationError,
508
                        objects.InstancePolicy.CheckISpecSyntax,
509
                        ipol, True)
510
      oldminmax = ipol[constants.ISPECS_MINMAX]
511
      if oldminmax:
512
        # Prepending valid specs shouldn't change the error
513
        ipol[constants.ISPECS_MINMAX] = ([constants.ISPECS_MINMAX_DEFAULTS] +
514
                                         oldminmax)
515
        self.assertRaises(errors.ConfigurationError,
516
                          objects.InstancePolicy.CheckISpecSyntax,
517
                          ipol, True)
518

    
519
    good_ipolicy = {
520
      constants.ISPECS_MINMAX: [
521
        {
522
          constants.ISPECS_MIN: {
523
            constants.ISPEC_MEM_SIZE: 64,
524
            constants.ISPEC_CPU_COUNT: 1,
525
            constants.ISPEC_DISK_COUNT: 2,
526
            constants.ISPEC_DISK_SIZE: 64,
527
            constants.ISPEC_NIC_COUNT: 1,
528
            constants.ISPEC_SPINDLE_USE: 1,
529
            },
530
          constants.ISPECS_MAX: {
531
            constants.ISPEC_MEM_SIZE: 16384,
532
            constants.ISPEC_CPU_COUNT: 5,
533
            constants.ISPEC_DISK_COUNT: 12,
534
            constants.ISPEC_DISK_SIZE: 1024,
535
            constants.ISPEC_NIC_COUNT: 9,
536
            constants.ISPEC_SPINDLE_USE: 18,
537
            },
538
          },
539
        {
540
          constants.ISPECS_MIN: {
541
            constants.ISPEC_MEM_SIZE: 32768,
542
            constants.ISPEC_CPU_COUNT: 8,
543
            constants.ISPEC_DISK_COUNT: 1,
544
            constants.ISPEC_DISK_SIZE: 1024,
545
            constants.ISPEC_NIC_COUNT: 1,
546
            constants.ISPEC_SPINDLE_USE: 1,
547
            },
548
          constants.ISPECS_MAX: {
549
            constants.ISPEC_MEM_SIZE: 65536,
550
            constants.ISPEC_CPU_COUNT: 10,
551
            constants.ISPEC_DISK_COUNT: 5,
552
            constants.ISPEC_DISK_SIZE: 1024 * 1024,
553
            constants.ISPEC_NIC_COUNT: 3,
554
            constants.ISPEC_SPINDLE_USE: 12,
555
            },
556
          },
557
        ],
558
      }
559
    good_ipolicy[constants.ISPECS_STD] = copy.deepcopy(
560
      good_ipolicy[constants.ISPECS_MINMAX][0][constants.ISPECS_MAX])
561
    # Check that it's really good before making it bad
562
    objects.InstancePolicy.CheckISpecSyntax(good_ipolicy, True)
563

    
564
    bad_ipolicy = copy.deepcopy(good_ipolicy)
565
    for minmax in bad_ipolicy[constants.ISPECS_MINMAX]:
566
      for (key, spec) in minmax.items():
567
        for param in spec:
568
          oldv = spec[param]
569
          del spec[param]
570
          self._AssertPolicyIsBad(bad_ipolicy)
571
          if key == constants.ISPECS_MIN:
572
            spec[param] = minmax[constants.ISPECS_MAX][param] + 1
573
          self._AssertPolicyIsBad(bad_ipolicy)
574
          spec[param] = oldv
575
    assert bad_ipolicy == good_ipolicy
576

    
577
    stdspec = bad_ipolicy[constants.ISPECS_STD]
578
    for param in stdspec:
579
      oldv = stdspec[param]
580
      del stdspec[param]
581
      self._AssertPolicyIsBad(bad_ipolicy, True)
582
      # Note that std spec is the same as a max spec
583
      stdspec[param] = oldv + 1
584
      self._AssertPolicyIsBad(bad_ipolicy, True)
585
      stdspec[param] = oldv
586
    assert bad_ipolicy == good_ipolicy
587

    
588
    for minmax in good_ipolicy[constants.ISPECS_MINMAX]:
589
      for spec in minmax.values():
590
        good_ipolicy[constants.ISPECS_STD] = spec
591
        objects.InstancePolicy.CheckISpecSyntax(good_ipolicy, True)
592

    
593
  def testCheckISpecParamSyntax(self):
594
    par = "my_parameter"
595
    for check_std in [True, False]:
596
      # Min and max only
597
      good_values = [(11, 11), (11, 40), (0, 0)]
598
      for (mn, mx) in good_values:
599
        minmax = dict((k, {}) for k in constants.ISPECS_MINMAX_KEYS)
600
        minmax[constants.ISPECS_MIN][par] = mn
601
        minmax[constants.ISPECS_MAX][par] = mx
602
        objects.InstancePolicy._CheckISpecParamSyntax(minmax, {}, par,
603
                                                     check_std)
604
      minmax = dict((k, {}) for k in constants.ISPECS_MINMAX_KEYS)
605
      minmax[constants.ISPECS_MIN][par] = 11
606
      minmax[constants.ISPECS_MAX][par] = 5
607
      self.assertRaises(errors.ConfigurationError,
608
                        objects.InstancePolicy._CheckISpecParamSyntax,
609
                        minmax, {}, par, check_std)
610
    # Min, std, max
611
    good_values = [
612
      (11, 11, 11),
613
      (11, 11, 40),
614
      (11, 40, 40),
615
      ]
616
    for (mn, st, mx) in good_values:
617
      minmax = {
618
        constants.ISPECS_MIN: {par: mn},
619
        constants.ISPECS_MAX: {par: mx},
620
        }
621
      stdspec = {par: st}
622
      objects.InstancePolicy._CheckISpecParamSyntax(minmax, stdspec, par, True)
623
    bad_values = [
624
      (11, 11,  5, True),
625
      (40, 11, 11, True),
626
      (11, 80, 40, False),
627
      (11,  5, 40, False,),
628
      (11,  5,  5, True),
629
      (40, 40, 11, True),
630
      ]
631
    for (mn, st, mx, excp) in bad_values:
632
      minmax = {
633
        constants.ISPECS_MIN: {par: mn},
634
        constants.ISPECS_MAX: {par: mx},
635
        }
636
      stdspec = {par: st}
637
      if excp:
638
        self.assertRaises(errors.ConfigurationError,
639
                          objects.InstancePolicy._CheckISpecParamSyntax,
640
                          minmax, stdspec, par, True)
641
      else:
642
        ret = objects.InstancePolicy._CheckISpecParamSyntax(minmax, stdspec,
643
                                                            par, True)
644
        self.assertFalse(ret)
645

    
646
  def testCheckDiskTemplates(self):
647
    invalid = "this_is_not_a_good_template"
648
    for dt in constants.DISK_TEMPLATES:
649
      objects.InstancePolicy.CheckDiskTemplates([dt])
650
    objects.InstancePolicy.CheckDiskTemplates(list(constants.DISK_TEMPLATES))
651
    bad_examples = [
652
      [invalid],
653
      [constants.DT_DRBD8, invalid],
654
      list(constants.DISK_TEMPLATES) + [invalid],
655
      [],
656
      None,
657
      ]
658
    for dtl in bad_examples:
659
      self.assertRaises(errors.ConfigurationError,
660
                        objects.InstancePolicy.CheckDiskTemplates,
661
                        dtl)
662

    
663
  def testCheckParameterSyntax(self):
664
    invalid = "this_key_shouldnt_be_here"
665
    for check_std in [True, False]:
666
      objects.InstancePolicy.CheckParameterSyntax({}, check_std)
667
      policy = {invalid: None}
668
      self.assertRaises(errors.ConfigurationError,
669
                        objects.InstancePolicy.CheckParameterSyntax,
670
                        policy, check_std)
671
      for par in constants.IPOLICY_PARAMETERS:
672
        for val in ("blah", None, {}, [42]):
673
          policy = {par: val}
674
          self.assertRaises(errors.ConfigurationError,
675
                            objects.InstancePolicy.CheckParameterSyntax,
676
                            policy, check_std)
677

    
678
  def testFillIPolicyEmpty(self):
679
    policy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, {})
680
    objects.InstancePolicy.CheckParameterSyntax(policy, True)
681
    self.assertEqual(policy, constants.IPOLICY_DEFAULTS)
682

    
683
  def _AssertISpecsMerged(self, default_spec, diff_spec, merged_spec):
684
    for (param, value) in merged_spec.items():
685
      if param in diff_spec:
686
        self.assertEqual(value, diff_spec[param])
687
      else:
688
        self.assertEqual(value, default_spec[param])
689

    
690
  def _AssertIPolicyMerged(self, default_pol, diff_pol, merged_pol):
691
    for (key, value) in merged_pol.items():
692
      if key in diff_pol:
693
        if key == constants.ISPECS_STD:
694
          self._AssertISpecsMerged(default_pol[key], diff_pol[key], value)
695
        else:
696
          self.assertEqual(value, diff_pol[key])
697
      else:
698
        self.assertEqual(value, default_pol[key])
699

    
700
  def testFillIPolicy(self):
701
    partial_policies = [
702
      {constants.IPOLICY_VCPU_RATIO: 3.14},
703
      {constants.IPOLICY_SPINDLE_RATIO: 2.72},
704
      {constants.IPOLICY_DTS: [constants.DT_FILE]},
705
      {constants.ISPECS_STD: {constants.ISPEC_DISK_COUNT: 3}},
706
      {constants.ISPECS_MINMAX: [constants.ISPECS_MINMAX_DEFAULTS,
707
                                 constants.ISPECS_MINMAX_DEFAULTS]}
708
      ]
709
    for diff_pol in partial_policies:
710
      policy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, diff_pol)
711
      objects.InstancePolicy.CheckParameterSyntax(policy, True)
712
      self._AssertIPolicyIsFull(policy)
713
      self._AssertIPolicyMerged(constants.IPOLICY_DEFAULTS, diff_pol, policy)
714

    
715
  def testFillIPolicyKeepsUnknown(self):
716
    INVALID_KEY = "invalid_ipolicy_key"
717
    diff_pol = {
718
      INVALID_KEY: None,
719
      }
720
    policy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, diff_pol)
721
    self.assertTrue(INVALID_KEY in policy)
722

    
723

    
724
class TestDisk(unittest.TestCase):
725
  def addChild(self, disk):
726
    """Adds a child of the same device type as the parent."""
727
    disk.children = []
728
    child = objects.Disk()
729
    child.dev_type = disk.dev_type
730
    disk.children.append(child)
731

    
732
  def testUpgradeConfigDevTypeLegacy(self):
733
    for old, new in [("drbd8", constants.DT_DRBD8),
734
                     ("lvm", constants.DT_PLAIN)]:
735
      disk = objects.Disk()
736
      disk.dev_type = old
737
      self.addChild(disk)
738
      disk.UpgradeConfig()
739
      self.assertEqual(new, disk.dev_type)
740
      self.assertEqual(new, disk.children[0].dev_type)
741

    
742
  def testUpgradeConfigDevTypeLegacyUnchanged(self):
743
    dev_types = [constants.DT_FILE, constants.DT_SHARED_FILE,
744
                 constants.DT_BLOCK, constants.DT_EXT,
745
                 constants.DT_RBD]
746
    for dev_type in dev_types:
747
      disk = objects.Disk()
748
      disk.dev_type = dev_type
749
      self.addChild(disk)
750
      disk.UpgradeConfig()
751
      self.assertEqual(dev_type, disk.dev_type)
752
      self.assertEqual(dev_type, disk.children[0].dev_type)
753

    
754

    
755
if __name__ == "__main__":
756
  testutils.GanetiTestProgram()