Statistics
| Branch: | Tag: | Revision:

root / test / py / ganeti.objects_unittest.py @ 93a968aa

History | View | Annotate | Download (27.3 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
    defaults = cl.GetHVDefaults(constants.HT_XEN_PVM,
97
                                          os_name="lenny-image")
98
    for param, value in cl.os_hvp["lenny-image"][constants.HT_XEN_PVM].items():
99
      self.assertEqual(value, defaults[param])
100

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

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

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

    
128
  def testFillHvInstParams(self):
129
    inst_hvparams = {
130
      "blah": "blubb",
131
      }
132
    fake_inst = objects.Instance(name="foobar",
133
                                 os="ubuntu-hardy",
134
                                 hypervisor=constants.HT_XEN_PVM,
135
                                 hvparams=inst_hvparams)
136
    filled_conf = self.fake_cl.FillHV(fake_inst)
137
    for param, value in constants.HVC_DEFAULTS[constants.HT_XEN_PVM].items():
138
      if param == "blah":
139
        value = "blubb"
140
      self.assertEqual(value, filled_conf[param])
141

    
142
  def testFillHvDefaultParams(self):
143
    fake_inst = objects.Instance(name="foobar",
144
                                 os="ubuntu-hardy",
145
                                 hypervisor=constants.HT_XEN_PVM,
146
                                 hvparams={})
147
    self.assertEqual(constants.HVC_DEFAULTS[constants.HT_XEN_PVM],
148
                     self.fake_cl.FillHV(fake_inst))
149

    
150
  def testFillHvPartialParams(self):
151
    os = "lenny-image"
152
    fake_inst = objects.Instance(name="foobar",
153
                                 os=os,
154
                                 hypervisor=constants.HT_XEN_PVM,
155
                                 hvparams={})
156
    filled_conf = self.fake_cl.FillHV(fake_inst)
157
    for param, value in self.fake_cl.os_hvp[os][constants.HT_XEN_PVM].items():
158
      self.assertEqual(value, filled_conf[param])
159

    
160
  def testFillNdParamsCluster(self):
161
    fake_node = objects.Node(name="test",
162
                             ndparams={},
163
                             group="testgroup")
164
    fake_group = objects.NodeGroup(name="testgroup",
165
                                   ndparams={})
166
    self.assertEqual(self.fake_cl.ndparams,
167
                     self.fake_cl.FillND(fake_node, fake_group))
168

    
169
  def testFillNdParamsNodeGroup(self):
170
    fake_node = objects.Node(name="test",
171
                             ndparams={},
172
                             group="testgroup")
173
    group_ndparams = {
174
        constants.ND_OOB_PROGRAM: "/bin/group-oob",
175
        constants.ND_SPINDLE_COUNT: 10,
176
        constants.ND_EXCLUSIVE_STORAGE: True,
177
        constants.ND_OVS: True,
178
        constants.ND_OVS_LINK: "eth2",
179
        constants.ND_OVS_NAME: "openvswitch",
180
        }
181
    fake_group = objects.NodeGroup(name="testgroup",
182
                                   ndparams=group_ndparams)
183
    self.assertEqual(group_ndparams,
184
                     self.fake_cl.FillND(fake_node, fake_group))
185

    
186
  def testFillNdParamsNode(self):
187
    node_ndparams = {
188
        constants.ND_OOB_PROGRAM: "/bin/node-oob",
189
        constants.ND_SPINDLE_COUNT: 2,
190
        constants.ND_EXCLUSIVE_STORAGE: True,
191
        constants.ND_OVS: True,
192
        constants.ND_OVS_LINK: "eth2",
193
        constants.ND_OVS_NAME: "openvswitch",
194
        }
195
    fake_node = objects.Node(name="test",
196
                             ndparams=node_ndparams,
197
                             group="testgroup")
198
    fake_group = objects.NodeGroup(name="testgroup",
199
                                   ndparams={})
200
    self.assertEqual(node_ndparams,
201
                     self.fake_cl.FillND(fake_node, fake_group))
202

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

    
224
  def testPrimaryHypervisor(self):
225
    assert self.fake_cl.enabled_hypervisors is None
226
    self.fake_cl.enabled_hypervisors = [constants.HT_XEN_HVM]
227
    self.assertEqual(self.fake_cl.primary_hypervisor, constants.HT_XEN_HVM)
228

    
229
    self.fake_cl.enabled_hypervisors = [constants.HT_XEN_PVM, constants.HT_KVM]
230
    self.assertEqual(self.fake_cl.primary_hypervisor, constants.HT_XEN_PVM)
231

    
232
    self.fake_cl.enabled_hypervisors = sorted(constants.HYPER_TYPES)
233
    self.assertEqual(self.fake_cl.primary_hypervisor, constants.HT_CHROOT)
234

    
235
  def testUpgradeConfig(self):
236
    # FIXME: This test is incomplete
237
    cluster = objects.Cluster()
238
    cluster.UpgradeConfig()
239
    cluster = objects.Cluster(ipolicy={"unknown_key": None})
240
    self.assertRaises(errors.ConfigurationError, cluster.UpgradeConfig)
241

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

    
269

    
270
class TestClusterObjectTcpUdpPortPool(unittest.TestCase):
271
  def testNewCluster(self):
272
    self.assertTrue(objects.Cluster().tcpudp_port_pool is None)
273

    
274
  def testSerializingEmpty(self):
275
    self.assertEqual(objects.Cluster().ToDict(), {
276
      "tcpudp_port_pool": [],
277
      })
278

    
279
  def testSerializing(self):
280
    cluster = objects.Cluster.FromDict({})
281
    self.assertEqual(cluster.tcpudp_port_pool, set())
282

    
283
    cluster.tcpudp_port_pool.add(3546)
284
    cluster.tcpudp_port_pool.add(62511)
285

    
286
    data = cluster.ToDict()
287
    self.assertEqual(data.keys(), ["tcpudp_port_pool"])
288
    self.assertEqual(sorted(data["tcpudp_port_pool"]), sorted([3546, 62511]))
289

    
290
  def testDeserializingEmpty(self):
291
    cluster = objects.Cluster.FromDict({})
292
    self.assertEqual(cluster.tcpudp_port_pool, set())
293

    
294
  def testDeserialize(self):
295
    cluster = objects.Cluster.FromDict({
296
      "tcpudp_port_pool": [26214, 10039, 267],
297
      })
298
    self.assertEqual(cluster.tcpudp_port_pool, set([26214, 10039, 267]))
299

    
300

    
301
class TestOS(unittest.TestCase):
302
  ALL_DATA = [
303
    "debootstrap",
304
    "debootstrap+default",
305
    "debootstrap++default",
306
    ]
307

    
308
  def testSplitNameVariant(self):
309
    for name in self.ALL_DATA:
310
      self.assertEqual(len(objects.OS.SplitNameVariant(name)), 2)
311

    
312
  def testVariant(self):
313
    self.assertEqual(objects.OS.GetVariant("debootstrap"), "")
314
    self.assertEqual(objects.OS.GetVariant("debootstrap+default"), "default")
315

    
316

    
317
class TestInstance(unittest.TestCase):
318
  def _GenericCheck(self, inst):
319
    for i in [inst.all_nodes, inst.secondary_nodes]:
320
      self.assertTrue(isinstance(inst.all_nodes, (list, tuple)),
321
                      msg="Data type doesn't guarantee order")
322

    
323
    self.assertTrue(inst.primary_node not in inst.secondary_nodes)
324
    self.assertEqual(inst.all_nodes[0], inst.primary_node,
325
                     msg="Primary node not first node in list")
326

    
327
  def testNodesNoDisks(self):
328
    inst = objects.Instance(name="fakeinst.example.com",
329
      primary_node="pnode.example.com",
330
      disks=[
331
        ])
332

    
333
    self._GenericCheck(inst)
334
    self.assertEqual(len(inst.secondary_nodes), 0)
335
    self.assertEqual(set(inst.all_nodes), set([inst.primary_node]))
336
    self.assertEqual(inst.MapLVsByNode(), {
337
      inst.primary_node: [],
338
      })
339

    
340
  def testNodesPlainDisks(self):
341
    inst = objects.Instance(name="fakeinstplain.example.com",
342
      primary_node="node3.example.com",
343
      disks=[
344
        objects.Disk(dev_type=constants.DT_PLAIN, size=128,
345
                     logical_id=("myxenvg", "disk25494")),
346
        objects.Disk(dev_type=constants.DT_PLAIN, size=512,
347
                     logical_id=("myxenvg", "disk29071")),
348
        ])
349

    
350
    self._GenericCheck(inst)
351
    self.assertEqual(len(inst.secondary_nodes), 0)
352
    self.assertEqual(set(inst.all_nodes), set([inst.primary_node]))
353
    self.assertEqual(inst.MapLVsByNode(), {
354
      inst.primary_node: ["myxenvg/disk25494", "myxenvg/disk29071"],
355
      })
356

    
357
  def testNodesDrbdDisks(self):
358
    inst = objects.Instance(name="fakeinstdrbd.example.com",
359
      primary_node="node20.example.com",
360
      disks=[
361
        objects.Disk(dev_type=constants.DT_DRBD8, size=786432,
362
          logical_id=("node20.example.com", "node15.example.com",
363
                      12300, 0, 0, "secret"),
364
          children=[
365
            objects.Disk(dev_type=constants.DT_PLAIN, size=786432,
366
                         logical_id=("myxenvg", "disk0")),
367
            objects.Disk(dev_type=constants.DT_PLAIN, size=128,
368
                         logical_id=("myxenvg", "meta0"))
369
          ],
370
          iv_name="disk/0")
371
        ])
372

    
373
    self._GenericCheck(inst)
374
    self.assertEqual(set(inst.secondary_nodes), set(["node15.example.com"]))
375
    self.assertEqual(set(inst.all_nodes),
376
                     set([inst.primary_node, "node15.example.com"]))
377
    self.assertEqual(inst.MapLVsByNode(), {
378
      inst.primary_node: ["myxenvg/disk0", "myxenvg/meta0"],
379
      "node15.example.com": ["myxenvg/disk0", "myxenvg/meta0"],
380
      })
381

    
382
    self.assertEqual(inst.FindDisk(0), inst.disks[0])
383
    self.assertRaises(errors.OpPrereqError, inst.FindDisk, "hello")
384
    self.assertRaises(errors.OpPrereqError, inst.FindDisk, 100)
385
    self.assertRaises(errors.OpPrereqError, inst.FindDisk, 1)
386

    
387

    
388
class TestNode(unittest.TestCase):
389
  def testEmpty(self):
390
    self.assertEqual(objects.Node().ToDict(), {})
391
    self.assertTrue(isinstance(objects.Node.FromDict({}), objects.Node))
392

    
393
  def testHvState(self):
394
    node = objects.Node(name="node18157.example.com", hv_state={
395
      constants.HT_XEN_HVM: objects.NodeHvState(cpu_total=64),
396
      constants.HT_KVM: objects.NodeHvState(cpu_node=1),
397
      })
398

    
399
    node2 = objects.Node.FromDict(node.ToDict())
400

    
401
    # Make sure nothing can reference it anymore
402
    del node
403

    
404
    self.assertEqual(node2.name, "node18157.example.com")
405
    self.assertEqual(frozenset(node2.hv_state), frozenset([
406
      constants.HT_XEN_HVM,
407
      constants.HT_KVM,
408
      ]))
409
    self.assertEqual(node2.hv_state[constants.HT_KVM].cpu_node, 1)
410
    self.assertEqual(node2.hv_state[constants.HT_XEN_HVM].cpu_total, 64)
411

    
412
  def testDiskState(self):
413
    node = objects.Node(name="node32087.example.com", disk_state={
414
      constants.DT_PLAIN: {
415
        "lv32352": objects.NodeDiskState(total=128),
416
        "lv2082": objects.NodeDiskState(total=512),
417
        },
418
      })
419

    
420
    node2 = objects.Node.FromDict(node.ToDict())
421

    
422
    # Make sure nothing can reference it anymore
423
    del node
424

    
425
    self.assertEqual(node2.name, "node32087.example.com")
426
    self.assertEqual(frozenset(node2.disk_state), frozenset([
427
      constants.DT_PLAIN,
428
      ]))
429
    self.assertEqual(frozenset(node2.disk_state[constants.DT_PLAIN]),
430
                     frozenset(["lv32352", "lv2082"]))
431
    self.assertEqual(node2.disk_state[constants.DT_PLAIN]["lv2082"].total, 512)
432
    self.assertEqual(node2.disk_state[constants.DT_PLAIN]["lv32352"].total, 128)
433

    
434
  def testFilterEsNdp(self):
435
    node1 = objects.Node(name="node11673.example.com", ndparams={
436
      constants.ND_EXCLUSIVE_STORAGE: True,
437
      })
438
    node2 = objects.Node(name="node11674.example.com", ndparams={
439
      constants.ND_SPINDLE_COUNT: 3,
440
      constants.ND_EXCLUSIVE_STORAGE: False,
441
      })
442
    self.assertTrue(constants.ND_EXCLUSIVE_STORAGE in node1.ndparams)
443
    node1.UpgradeConfig()
444
    self.assertFalse(constants.ND_EXCLUSIVE_STORAGE in node1.ndparams)
445
    self.assertTrue(constants.ND_EXCLUSIVE_STORAGE in node2.ndparams)
446
    self.assertTrue(constants.ND_SPINDLE_COUNT in node2.ndparams)
447
    node2.UpgradeConfig()
448
    self.assertFalse(constants.ND_EXCLUSIVE_STORAGE in node2.ndparams)
449
    self.assertTrue(constants.ND_SPINDLE_COUNT in node2.ndparams)
450

    
451

    
452
class TestInstancePolicy(unittest.TestCase):
453
  def setUp(self):
454
    # Policies are big, and we want to see the difference in case of an error
455
    self.maxDiff = None
456

    
457
  def _AssertIPolicyIsFull(self, policy):
458
    self.assertEqual(frozenset(policy.keys()), constants.IPOLICY_ALL_KEYS)
459
    self.assertTrue(len(policy[constants.ISPECS_MINMAX]) > 0)
460
    for minmax in policy[constants.ISPECS_MINMAX]:
461
      self.assertEqual(frozenset(minmax.keys()), constants.ISPECS_MINMAX_KEYS)
462
      for key in constants.ISPECS_MINMAX_KEYS:
463
        self.assertEqual(frozenset(minmax[key].keys()),
464
                         constants.ISPECS_PARAMETERS)
465
    self.assertEqual(frozenset(policy[constants.ISPECS_STD].keys()),
466
                     constants.ISPECS_PARAMETERS)
467

    
468
  def testDefaultIPolicy(self):
469
    objects.InstancePolicy.CheckParameterSyntax(constants.IPOLICY_DEFAULTS,
470
                                                True)
471
    self._AssertIPolicyIsFull(constants.IPOLICY_DEFAULTS)
472

    
473
  def _AssertPolicyIsBad(self, ipolicy, do_check_std=None):
474
    if do_check_std is None:
475
      check_std_vals = [False, True]
476
    else:
477
      check_std_vals = [do_check_std]
478
    for check_std in check_std_vals:
479
      self.assertRaises(errors.ConfigurationError,
480
                        objects.InstancePolicy.CheckISpecSyntax,
481
                        ipolicy, check_std)
482

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

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

    
571
    bad_ipolicy = copy.deepcopy(good_ipolicy)
572
    for minmax in bad_ipolicy[constants.ISPECS_MINMAX]:
573
      for (key, spec) in minmax.items():
574
        for param in spec:
575
          oldv = spec[param]
576
          del spec[param]
577
          self._AssertPolicyIsBad(bad_ipolicy)
578
          if key == constants.ISPECS_MIN:
579
            spec[param] = minmax[constants.ISPECS_MAX][param] + 1
580
          self._AssertPolicyIsBad(bad_ipolicy)
581
          spec[param] = oldv
582
    assert bad_ipolicy == good_ipolicy
583

    
584
    stdspec = bad_ipolicy[constants.ISPECS_STD]
585
    for param in stdspec:
586
      oldv = stdspec[param]
587
      del stdspec[param]
588
      self._AssertPolicyIsBad(bad_ipolicy, True)
589
      # Note that std spec is the same as a max spec
590
      stdspec[param] = oldv + 1
591
      self._AssertPolicyIsBad(bad_ipolicy, True)
592
      stdspec[param] = oldv
593
    assert bad_ipolicy == good_ipolicy
594

    
595
    for minmax in good_ipolicy[constants.ISPECS_MINMAX]:
596
      for spec in minmax.values():
597
        good_ipolicy[constants.ISPECS_STD] = spec
598
        objects.InstancePolicy.CheckISpecSyntax(good_ipolicy, True)
599

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

    
653
  def testCheckDiskTemplates(self):
654
    invalid = "this_is_not_a_good_template"
655
    for dt in constants.DISK_TEMPLATES:
656
      objects.InstancePolicy.CheckDiskTemplates([dt])
657
    objects.InstancePolicy.CheckDiskTemplates(list(constants.DISK_TEMPLATES))
658
    bad_examples = [
659
      [invalid],
660
      [constants.DT_DRBD8, invalid],
661
      list(constants.DISK_TEMPLATES) + [invalid],
662
      [],
663
      None,
664
      ]
665
    for dtl in bad_examples:
666
      self.assertRaises(errors.ConfigurationError,
667
                        objects.InstancePolicy.CheckDiskTemplates,
668
                        dtl)
669

    
670
  def testCheckParameterSyntax(self):
671
    invalid = "this_key_shouldnt_be_here"
672
    for check_std in [True, False]:
673
      objects.InstancePolicy.CheckParameterSyntax({}, check_std)
674
      policy = {invalid: None}
675
      self.assertRaises(errors.ConfigurationError,
676
                        objects.InstancePolicy.CheckParameterSyntax,
677
                        policy, check_std)
678
      for par in constants.IPOLICY_PARAMETERS:
679
        for val in ("blah", None, {}, [42]):
680
          policy = {par: val}
681
          self.assertRaises(errors.ConfigurationError,
682
                            objects.InstancePolicy.CheckParameterSyntax,
683
                            policy, check_std)
684

    
685
  def testFillIPolicyEmpty(self):
686
    policy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, {})
687
    objects.InstancePolicy.CheckParameterSyntax(policy, True)
688
    self.assertEqual(policy, constants.IPOLICY_DEFAULTS)
689

    
690
  def _AssertISpecsMerged(self, default_spec, diff_spec, merged_spec):
691
    for (param, value) in merged_spec.items():
692
      if param in diff_spec:
693
        self.assertEqual(value, diff_spec[param])
694
      else:
695
        self.assertEqual(value, default_spec[param])
696

    
697
  def _AssertIPolicyMerged(self, default_pol, diff_pol, merged_pol):
698
    for (key, value) in merged_pol.items():
699
      if key in diff_pol:
700
        if key == constants.ISPECS_STD:
701
          self._AssertISpecsMerged(default_pol[key], diff_pol[key], value)
702
        else:
703
          self.assertEqual(value, diff_pol[key])
704
      else:
705
        self.assertEqual(value, default_pol[key])
706

    
707
  def testFillIPolicy(self):
708
    partial_policies = [
709
      {constants.IPOLICY_VCPU_RATIO: 3.14},
710
      {constants.IPOLICY_SPINDLE_RATIO: 2.72},
711
      {constants.IPOLICY_DTS: [constants.DT_FILE]},
712
      {constants.ISPECS_STD: {constants.ISPEC_DISK_COUNT: 3}},
713
      {constants.ISPECS_MINMAX: [constants.ISPECS_MINMAX_DEFAULTS,
714
                                 constants.ISPECS_MINMAX_DEFAULTS]}
715
      ]
716
    for diff_pol in partial_policies:
717
      policy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, diff_pol)
718
      objects.InstancePolicy.CheckParameterSyntax(policy, True)
719
      self._AssertIPolicyIsFull(policy)
720
      self._AssertIPolicyMerged(constants.IPOLICY_DEFAULTS, diff_pol, policy)
721

    
722
  def testFillIPolicyKeepsUnknown(self):
723
    INVALID_KEY = "invalid_ipolicy_key"
724
    diff_pol = {
725
      INVALID_KEY: None,
726
      }
727
    policy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, diff_pol)
728
    self.assertTrue(INVALID_KEY in policy)
729

    
730

    
731
class TestDisk(unittest.TestCase):
732
  def addChild(self, disk):
733
    """Adds a child of the same device type as the parent."""
734
    disk.children = []
735
    child = objects.Disk()
736
    child.dev_type = disk.dev_type
737
    disk.children.append(child)
738

    
739
  def testUpgradeConfigDevTypeLegacy(self):
740
    for old, new in [("drbd8", constants.DT_DRBD8),
741
                     ("lvm", constants.DT_PLAIN)]:
742
      disk = objects.Disk()
743
      disk.dev_type = old
744
      self.addChild(disk)
745
      disk.UpgradeConfig()
746
      self.assertEqual(new, disk.dev_type)
747
      self.assertEqual(new, disk.children[0].dev_type)
748

    
749
  def testUpgradeConfigDevTypeLegacyUnchanged(self):
750
    dev_types = [constants.DT_FILE, constants.DT_SHARED_FILE,
751
                 constants.DT_BLOCK, constants.DT_EXT,
752
                 constants.DT_RBD]
753
    for dev_type in dev_types:
754
      disk = objects.Disk()
755
      disk.dev_type = dev_type
756
      self.addChild(disk)
757
      disk.UpgradeConfig()
758
      self.assertEqual(dev_type, disk.dev_type)
759
      self.assertEqual(dev_type, disk.children[0].dev_type)
760

    
761

    
762
if __name__ == "__main__":
763
  testutils.GanetiTestProgram()