Statistics
| Branch: | Tag: | Revision:

root / test / py / ganeti.objects_unittest.py @ 6ee8fdd3

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
    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
        }
178
    fake_group = objects.NodeGroup(name="testgroup",
179
                                   ndparams=group_ndparams)
180
    self.assertEqual(group_ndparams,
181
                     self.fake_cl.FillND(fake_node, fake_group))
182

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

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

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

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

    
223
    self.fake_cl.enabled_hypervisors = sorted(constants.HYPER_TYPES)
224
    self.assertEqual(self.fake_cl.primary_hypervisor, constants.HT_CHROOT)
225

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

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

    
260

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

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

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

    
274
    cluster.tcpudp_port_pool.add(3546)
275
    cluster.tcpudp_port_pool.add(62511)
276

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

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

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

    
291

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

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

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

    
307

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

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

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

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

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

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

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

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

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

    
378

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

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

    
390
    node2 = objects.Node.FromDict(node.ToDict())
391

    
392
    # Make sure nothing can reference it anymore
393
    del node
394

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

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

    
411
    node2 = objects.Node.FromDict(node.ToDict())
412

    
413
    # Make sure nothing can reference it anymore
414
    del node
415

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

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

    
442

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
721

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

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

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

    
752

    
753
if __name__ == "__main__":
754
  testutils.GanetiTestProgram()