Statistics
| Branch: | Tag: | Revision:

root / test / py / ganeti.objects_unittest.py @ cd3b4ff4

History | View | Annotate | Download (24.4 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
        }
171
    fake_group = objects.NodeGroup(name="testgroup",
172
                                   ndparams=group_ndparams)
173
    self.assertEqual(group_ndparams,
174
                     self.fake_cl.FillND(fake_node, fake_group))
175

    
176
  def testFillNdParamsNode(self):
177
    node_ndparams = {
178
        constants.ND_OOB_PROGRAM: "/bin/node-oob",
179
        constants.ND_SPINDLE_COUNT: 2,
180
        constants.ND_EXCLUSIVE_STORAGE: True,
181
        }
182
    fake_node = objects.Node(name="test",
183
                             ndparams=node_ndparams,
184
                             group="testgroup")
185
    fake_group = objects.NodeGroup(name="testgroup",
186
                                   ndparams={})
187
    self.assertEqual(node_ndparams,
188
                     self.fake_cl.FillND(fake_node, fake_group))
189

    
190
  def testFillNdParamsAll(self):
191
    node_ndparams = {
192
        constants.ND_OOB_PROGRAM: "/bin/node-oob",
193
        constants.ND_SPINDLE_COUNT: 5,
194
        constants.ND_EXCLUSIVE_STORAGE: True,
195
        }
196
    fake_node = objects.Node(name="test",
197
                             ndparams=node_ndparams,
198
                             group="testgroup")
199
    group_ndparams = {
200
        constants.ND_OOB_PROGRAM: "/bin/group-oob",
201
        constants.ND_SPINDLE_COUNT: 4,
202
        }
203
    fake_group = objects.NodeGroup(name="testgroup",
204
                                   ndparams=group_ndparams)
205
    self.assertEqual(node_ndparams,
206
                     self.fake_cl.FillND(fake_node, fake_group))
207

    
208
  def testPrimaryHypervisor(self):
209
    assert self.fake_cl.enabled_hypervisors is None
210
    self.fake_cl.enabled_hypervisors = [constants.HT_XEN_HVM]
211
    self.assertEqual(self.fake_cl.primary_hypervisor, constants.HT_XEN_HVM)
212

    
213
    self.fake_cl.enabled_hypervisors = [constants.HT_XEN_PVM, constants.HT_KVM]
214
    self.assertEqual(self.fake_cl.primary_hypervisor, constants.HT_XEN_PVM)
215

    
216
    self.fake_cl.enabled_hypervisors = sorted(constants.HYPER_TYPES)
217
    self.assertEqual(self.fake_cl.primary_hypervisor, constants.HT_CHROOT)
218

    
219
  def testUpgradeConfig(self):
220
    # FIXME: This test is incomplete
221
    cluster = objects.Cluster()
222
    cluster.UpgradeConfig()
223
    cluster = objects.Cluster(ipolicy={"unknown_key": None})
224
    self.assertRaises(errors.ConfigurationError, cluster.UpgradeConfig)
225

    
226

    
227
class TestClusterObjectTcpUdpPortPool(unittest.TestCase):
228
  def testNewCluster(self):
229
    self.assertTrue(objects.Cluster().tcpudp_port_pool is None)
230

    
231
  def testSerializingEmpty(self):
232
    self.assertEqual(objects.Cluster().ToDict(), {
233
      "tcpudp_port_pool": [],
234
      })
235

    
236
  def testSerializing(self):
237
    cluster = objects.Cluster.FromDict({})
238
    self.assertEqual(cluster.tcpudp_port_pool, set())
239

    
240
    cluster.tcpudp_port_pool.add(3546)
241
    cluster.tcpudp_port_pool.add(62511)
242

    
243
    data = cluster.ToDict()
244
    self.assertEqual(data.keys(), ["tcpudp_port_pool"])
245
    self.assertEqual(sorted(data["tcpudp_port_pool"]), sorted([3546, 62511]))
246

    
247
  def testDeserializingEmpty(self):
248
    cluster = objects.Cluster.FromDict({})
249
    self.assertEqual(cluster.tcpudp_port_pool, set())
250

    
251
  def testDeserialize(self):
252
    cluster = objects.Cluster.FromDict({
253
      "tcpudp_port_pool": [26214, 10039, 267],
254
      })
255
    self.assertEqual(cluster.tcpudp_port_pool, set([26214, 10039, 267]))
256

    
257

    
258
class TestOS(unittest.TestCase):
259
  ALL_DATA = [
260
    "debootstrap",
261
    "debootstrap+default",
262
    "debootstrap++default",
263
    ]
264

    
265
  def testSplitNameVariant(self):
266
    for name in self.ALL_DATA:
267
      self.assertEqual(len(objects.OS.SplitNameVariant(name)), 2)
268

    
269
  def testVariant(self):
270
    self.assertEqual(objects.OS.GetVariant("debootstrap"), "")
271
    self.assertEqual(objects.OS.GetVariant("debootstrap+default"), "default")
272

    
273

    
274
class TestInstance(unittest.TestCase):
275
  def _GenericCheck(self, inst):
276
    for i in [inst.all_nodes, inst.secondary_nodes]:
277
      self.assertTrue(isinstance(inst.all_nodes, (list, tuple)),
278
                      msg="Data type doesn't guarantee order")
279

    
280
    self.assertTrue(inst.primary_node not in inst.secondary_nodes)
281
    self.assertEqual(inst.all_nodes[0], inst.primary_node,
282
                     msg="Primary node not first node in list")
283

    
284
  def testNodesNoDisks(self):
285
    inst = objects.Instance(name="fakeinst.example.com",
286
      primary_node="pnode.example.com",
287
      disks=[
288
        ])
289

    
290
    self._GenericCheck(inst)
291
    self.assertEqual(len(inst.secondary_nodes), 0)
292
    self.assertEqual(set(inst.all_nodes), set([inst.primary_node]))
293
    self.assertEqual(inst.MapLVsByNode(), {
294
      inst.primary_node: [],
295
      })
296

    
297
  def testNodesPlainDisks(self):
298
    inst = objects.Instance(name="fakeinstplain.example.com",
299
      primary_node="node3.example.com",
300
      disks=[
301
        objects.Disk(dev_type=constants.DT_PLAIN, size=128,
302
                     logical_id=("myxenvg", "disk25494")),
303
        objects.Disk(dev_type=constants.DT_PLAIN, size=512,
304
                     logical_id=("myxenvg", "disk29071")),
305
        ])
306

    
307
    self._GenericCheck(inst)
308
    self.assertEqual(len(inst.secondary_nodes), 0)
309
    self.assertEqual(set(inst.all_nodes), set([inst.primary_node]))
310
    self.assertEqual(inst.MapLVsByNode(), {
311
      inst.primary_node: ["myxenvg/disk25494", "myxenvg/disk29071"],
312
      })
313

    
314
  def testNodesDrbdDisks(self):
315
    inst = objects.Instance(name="fakeinstdrbd.example.com",
316
      primary_node="node10.example.com",
317
      disks=[
318
        objects.Disk(dev_type=constants.DT_DRBD8, size=786432,
319
          logical_id=("node10.example.com", "node15.example.com",
320
                      12300, 0, 0, "secret"),
321
          children=[
322
            objects.Disk(dev_type=constants.DT_PLAIN, size=786432,
323
                         logical_id=("myxenvg", "disk0")),
324
            objects.Disk(dev_type=constants.DT_PLAIN, size=128,
325
                         logical_id=("myxenvg", "meta0"))
326
          ],
327
          iv_name="disk/0")
328
        ])
329

    
330
    self._GenericCheck(inst)
331
    self.assertEqual(set(inst.secondary_nodes), set(["node15.example.com"]))
332
    self.assertEqual(set(inst.all_nodes),
333
                     set([inst.primary_node, "node15.example.com"]))
334
    self.assertEqual(inst.MapLVsByNode(), {
335
      inst.primary_node: ["myxenvg/disk0", "myxenvg/meta0"],
336
      "node15.example.com": ["myxenvg/disk0", "myxenvg/meta0"],
337
      })
338

    
339
    self.assertEqual(inst.FindDisk(0), inst.disks[0])
340
    self.assertRaises(errors.OpPrereqError, inst.FindDisk, "hello")
341
    self.assertRaises(errors.OpPrereqError, inst.FindDisk, 100)
342
    self.assertRaises(errors.OpPrereqError, inst.FindDisk, 1)
343

    
344

    
345
class TestNode(unittest.TestCase):
346
  def testEmpty(self):
347
    self.assertEqual(objects.Node().ToDict(), {})
348
    self.assertTrue(isinstance(objects.Node.FromDict({}), objects.Node))
349

    
350
  def testHvState(self):
351
    node = objects.Node(name="node18157.example.com", hv_state={
352
      constants.HT_XEN_HVM: objects.NodeHvState(cpu_total=64),
353
      constants.HT_KVM: objects.NodeHvState(cpu_node=1),
354
      })
355

    
356
    node2 = objects.Node.FromDict(node.ToDict())
357

    
358
    # Make sure nothing can reference it anymore
359
    del node
360

    
361
    self.assertEqual(node2.name, "node18157.example.com")
362
    self.assertEqual(frozenset(node2.hv_state), frozenset([
363
      constants.HT_XEN_HVM,
364
      constants.HT_KVM,
365
      ]))
366
    self.assertEqual(node2.hv_state[constants.HT_KVM].cpu_node, 1)
367
    self.assertEqual(node2.hv_state[constants.HT_XEN_HVM].cpu_total, 64)
368

    
369
  def testDiskState(self):
370
    node = objects.Node(name="node32087.example.com", disk_state={
371
      constants.DT_PLAIN: {
372
        "lv32352": objects.NodeDiskState(total=128),
373
        "lv2082": objects.NodeDiskState(total=512),
374
        },
375
      })
376

    
377
    node2 = objects.Node.FromDict(node.ToDict())
378

    
379
    # Make sure nothing can reference it anymore
380
    del node
381

    
382
    self.assertEqual(node2.name, "node32087.example.com")
383
    self.assertEqual(frozenset(node2.disk_state), frozenset([
384
      constants.DT_PLAIN,
385
      ]))
386
    self.assertEqual(frozenset(node2.disk_state[constants.DT_PLAIN]),
387
                     frozenset(["lv32352", "lv2082"]))
388
    self.assertEqual(node2.disk_state[constants.DT_PLAIN]["lv2082"].total, 512)
389
    self.assertEqual(node2.disk_state[constants.DT_PLAIN]["lv32352"].total, 128)
390

    
391
  def testFilterEsNdp(self):
392
    node1 = objects.Node(name="node11673.example.com", ndparams={
393
      constants.ND_EXCLUSIVE_STORAGE: True,
394
      })
395
    node2 = objects.Node(name="node11674.example.com", ndparams={
396
      constants.ND_SPINDLE_COUNT: 3,
397
      constants.ND_EXCLUSIVE_STORAGE: False,
398
      })
399
    self.assertTrue(constants.ND_EXCLUSIVE_STORAGE in node1.ndparams)
400
    node1.UpgradeConfig()
401
    self.assertFalse(constants.ND_EXCLUSIVE_STORAGE in node1.ndparams)
402
    self.assertTrue(constants.ND_EXCLUSIVE_STORAGE in node2.ndparams)
403
    self.assertTrue(constants.ND_SPINDLE_COUNT in node2.ndparams)
404
    node2.UpgradeConfig()
405
    self.assertFalse(constants.ND_EXCLUSIVE_STORAGE in node2.ndparams)
406
    self.assertTrue(constants.ND_SPINDLE_COUNT in node2.ndparams)
407

    
408

    
409
class TestInstancePolicy(unittest.TestCase):
410
  def setUp(self):
411
    # Policies are big, and we want to see the difference in case of an error
412
    self.maxDiff = None
413

    
414
  def _AssertIPolicyIsFull(self, policy):
415
    self.assertEqual(frozenset(policy.keys()), constants.IPOLICY_ALL_KEYS)
416
    self.assertTrue(len(policy[constants.ISPECS_MINMAX]) > 0)
417
    for minmax in policy[constants.ISPECS_MINMAX]:
418
      self.assertEqual(frozenset(minmax.keys()), constants.ISPECS_MINMAX_KEYS)
419
      for key in constants.ISPECS_MINMAX_KEYS:
420
        self.assertEqual(frozenset(minmax[key].keys()),
421
                         constants.ISPECS_PARAMETERS)
422
    self.assertEqual(frozenset(policy[constants.ISPECS_STD].keys()),
423
                     constants.ISPECS_PARAMETERS)
424

    
425
  def testDefaultIPolicy(self):
426
    objects.InstancePolicy.CheckParameterSyntax(constants.IPOLICY_DEFAULTS,
427
                                                True)
428
    self._AssertIPolicyIsFull(constants.IPOLICY_DEFAULTS)
429

    
430
  def _AssertPolicyIsBad(self, ipolicy, do_check_std=None):
431
    if do_check_std is None:
432
      check_std_vals = [False, True]
433
    else:
434
      check_std_vals = [do_check_std]
435
    for check_std in check_std_vals:
436
      self.assertRaises(errors.ConfigurationError,
437
                        objects.InstancePolicy.CheckISpecSyntax,
438
                        ipolicy, check_std)
439

    
440
  def testCheckISpecSyntax(self):
441
    default_stdspec = constants.IPOLICY_DEFAULTS[constants.ISPECS_STD]
442
    incomplete_ipolicies = [
443
      {
444
         constants.ISPECS_MINMAX: [],
445
         constants.ISPECS_STD: default_stdspec,
446
         },
447
      {
448
         constants.ISPECS_MINMAX: [{}],
449
         constants.ISPECS_STD: default_stdspec,
450
         },
451
      {
452
        constants.ISPECS_MINMAX: [{
453
          constants.ISPECS_MIN: NotImplemented,
454
          }],
455
        constants.ISPECS_STD: default_stdspec,
456
        },
457
      {
458
        constants.ISPECS_MINMAX: [{
459
          constants.ISPECS_MAX: NotImplemented,
460
          }],
461
        constants.ISPECS_STD: default_stdspec,
462
        },
463
      {
464
        constants.ISPECS_MINMAX: [{
465
          constants.ISPECS_MIN: NotImplemented,
466
          constants.ISPECS_MAX: NotImplemented,
467
          }],
468
        },
469
      ]
470
    for ipol in incomplete_ipolicies:
471
      self.assertRaises(errors.ConfigurationError,
472
                        objects.InstancePolicy.CheckISpecSyntax,
473
                        ipol, True)
474
      oldminmax = ipol[constants.ISPECS_MINMAX]
475
      if oldminmax:
476
        # Prepending valid specs shouldn't change the error
477
        ipol[constants.ISPECS_MINMAX] = ([constants.ISPECS_MINMAX_DEFAULTS] +
478
                                         oldminmax)
479
        self.assertRaises(errors.ConfigurationError,
480
                          objects.InstancePolicy.CheckISpecSyntax,
481
                          ipol, True)
482

    
483
    good_ipolicy = {
484
      constants.ISPECS_MINMAX: [
485
        {
486
          constants.ISPECS_MIN: {
487
            constants.ISPEC_MEM_SIZE: 64,
488
            constants.ISPEC_CPU_COUNT: 1,
489
            constants.ISPEC_DISK_COUNT: 2,
490
            constants.ISPEC_DISK_SIZE: 64,
491
            constants.ISPEC_NIC_COUNT: 1,
492
            constants.ISPEC_SPINDLE_USE: 1,
493
            },
494
          constants.ISPECS_MAX: {
495
            constants.ISPEC_MEM_SIZE: 16384,
496
            constants.ISPEC_CPU_COUNT: 5,
497
            constants.ISPEC_DISK_COUNT: 12,
498
            constants.ISPEC_DISK_SIZE: 1024,
499
            constants.ISPEC_NIC_COUNT: 9,
500
            constants.ISPEC_SPINDLE_USE: 18,
501
            },
502
          },
503
        {
504
          constants.ISPECS_MIN: {
505
            constants.ISPEC_MEM_SIZE: 32768,
506
            constants.ISPEC_CPU_COUNT: 8,
507
            constants.ISPEC_DISK_COUNT: 1,
508
            constants.ISPEC_DISK_SIZE: 1024,
509
            constants.ISPEC_NIC_COUNT: 1,
510
            constants.ISPEC_SPINDLE_USE: 1,
511
            },
512
          constants.ISPECS_MAX: {
513
            constants.ISPEC_MEM_SIZE: 65536,
514
            constants.ISPEC_CPU_COUNT: 10,
515
            constants.ISPEC_DISK_COUNT: 5,
516
            constants.ISPEC_DISK_SIZE: 1024 * 1024,
517
            constants.ISPEC_NIC_COUNT: 3,
518
            constants.ISPEC_SPINDLE_USE: 12,
519
            },
520
          },
521
        ],
522
      }
523
    good_ipolicy[constants.ISPECS_STD] = copy.deepcopy(
524
      good_ipolicy[constants.ISPECS_MINMAX][0][constants.ISPECS_MAX])
525
    # Check that it's really good before making it bad
526
    objects.InstancePolicy.CheckISpecSyntax(good_ipolicy, True)
527

    
528
    bad_ipolicy = copy.deepcopy(good_ipolicy)
529
    for minmax in bad_ipolicy[constants.ISPECS_MINMAX]:
530
      for (key, spec) in minmax.items():
531
        for param in spec:
532
          oldv = spec[param]
533
          del spec[param]
534
          self._AssertPolicyIsBad(bad_ipolicy)
535
          if key == constants.ISPECS_MIN:
536
            spec[param] = minmax[constants.ISPECS_MAX][param] + 1
537
          self._AssertPolicyIsBad(bad_ipolicy)
538
          spec[param] = oldv
539
    assert bad_ipolicy == good_ipolicy
540

    
541
    stdspec = bad_ipolicy[constants.ISPECS_STD]
542
    for param in stdspec:
543
      oldv = stdspec[param]
544
      del stdspec[param]
545
      self._AssertPolicyIsBad(bad_ipolicy, True)
546
      # Note that std spec is the same as a max spec
547
      stdspec[param] = oldv + 1
548
      self._AssertPolicyIsBad(bad_ipolicy, True)
549
      stdspec[param] = oldv
550
    assert bad_ipolicy == good_ipolicy
551

    
552
    for minmax in good_ipolicy[constants.ISPECS_MINMAX]:
553
      for spec in minmax.values():
554
        good_ipolicy[constants.ISPECS_STD] = spec
555
        objects.InstancePolicy.CheckISpecSyntax(good_ipolicy, True)
556

    
557
  def testCheckISpecParamSyntax(self):
558
    par = "my_parameter"
559
    for check_std in [True, False]:
560
      # Min and max only
561
      good_values = [(11, 11), (11, 40), (0, 0)]
562
      for (mn, mx) in good_values:
563
        minmax = dict((k, {}) for k in constants.ISPECS_MINMAX_KEYS)
564
        minmax[constants.ISPECS_MIN][par] = mn
565
        minmax[constants.ISPECS_MAX][par] = mx
566
        objects.InstancePolicy._CheckISpecParamSyntax(minmax, {}, par,
567
                                                     check_std)
568
      minmax = dict((k, {}) for k in constants.ISPECS_MINMAX_KEYS)
569
      minmax[constants.ISPECS_MIN][par] = 11
570
      minmax[constants.ISPECS_MAX][par] = 5
571
      self.assertRaises(errors.ConfigurationError,
572
                        objects.InstancePolicy._CheckISpecParamSyntax,
573
                        minmax, {}, par, check_std)
574
    # Min, std, max
575
    good_values = [
576
      (11, 11, 11),
577
      (11, 11, 40),
578
      (11, 40, 40),
579
      ]
580
    for (mn, st, mx) in good_values:
581
      minmax = {
582
        constants.ISPECS_MIN: {par: mn},
583
        constants.ISPECS_MAX: {par: mx},
584
        }
585
      stdspec = {par: st}
586
      objects.InstancePolicy._CheckISpecParamSyntax(minmax, stdspec, par, True)
587
    bad_values = [
588
      (11, 11,  5, True),
589
      (40, 11, 11, True),
590
      (11, 80, 40, False),
591
      (11,  5, 40, False,),
592
      (11,  5,  5, True),
593
      (40, 40, 11, True),
594
      ]
595
    for (mn, st, mx, excp) in bad_values:
596
      minmax = {
597
        constants.ISPECS_MIN: {par: mn},
598
        constants.ISPECS_MAX: {par: mx},
599
        }
600
      stdspec = {par: st}
601
      if excp:
602
        self.assertRaises(errors.ConfigurationError,
603
                          objects.InstancePolicy._CheckISpecParamSyntax,
604
                          minmax, stdspec, par, True)
605
      else:
606
        ret = objects.InstancePolicy._CheckISpecParamSyntax(minmax, stdspec,
607
                                                            par, True)
608
        self.assertFalse(ret)
609

    
610
  def testCheckDiskTemplates(self):
611
    invalid = "this_is_not_a_good_template"
612
    for dt in constants.DISK_TEMPLATES:
613
      objects.InstancePolicy.CheckDiskTemplates([dt])
614
    objects.InstancePolicy.CheckDiskTemplates(list(constants.DISK_TEMPLATES))
615
    bad_examples = [
616
      [invalid],
617
      [constants.DT_DRBD8, invalid],
618
      list(constants.DISK_TEMPLATES) + [invalid],
619
      [],
620
      None,
621
      ]
622
    for dtl in bad_examples:
623
      self.assertRaises(errors.ConfigurationError,
624
                        objects.InstancePolicy.CheckDiskTemplates,
625
                        dtl)
626

    
627
  def testCheckParameterSyntax(self):
628
    invalid = "this_key_shouldnt_be_here"
629
    for check_std in [True, False]:
630
      objects.InstancePolicy.CheckParameterSyntax({}, check_std)
631
      policy = {invalid: None}
632
      self.assertRaises(errors.ConfigurationError,
633
                        objects.InstancePolicy.CheckParameterSyntax,
634
                        policy, check_std)
635
      for par in constants.IPOLICY_PARAMETERS:
636
        for val in ("blah", None, {}, [42]):
637
          policy = {par: val}
638
          self.assertRaises(errors.ConfigurationError,
639
                            objects.InstancePolicy.CheckParameterSyntax,
640
                            policy, check_std)
641

    
642
  def testFillIPolicyEmpty(self):
643
    policy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, {})
644
    objects.InstancePolicy.CheckParameterSyntax(policy, True)
645
    self.assertEqual(policy, constants.IPOLICY_DEFAULTS)
646

    
647
  def _AssertISpecsMerged(self, default_spec, diff_spec, merged_spec):
648
    for (param, value) in merged_spec.items():
649
      if param in diff_spec:
650
        self.assertEqual(value, diff_spec[param])
651
      else:
652
        self.assertEqual(value, default_spec[param])
653

    
654
  def _AssertIPolicyMerged(self, default_pol, diff_pol, merged_pol):
655
    for (key, value) in merged_pol.items():
656
      if key in diff_pol:
657
        if key == constants.ISPECS_STD:
658
          self._AssertISpecsMerged(default_pol[key], diff_pol[key], value)
659
        else:
660
          self.assertEqual(value, diff_pol[key])
661
      else:
662
        self.assertEqual(value, default_pol[key])
663

    
664
  def testFillIPolicy(self):
665
    partial_policies = [
666
      {constants.IPOLICY_VCPU_RATIO: 3.14},
667
      {constants.IPOLICY_SPINDLE_RATIO: 2.72},
668
      {constants.IPOLICY_DTS: [constants.DT_FILE]},
669
      {constants.ISPECS_STD: {constants.ISPEC_DISK_COUNT: 3}},
670
      {constants.ISPECS_MINMAX: [constants.ISPECS_MINMAX_DEFAULTS,
671
                                 constants.ISPECS_MINMAX_DEFAULTS]}
672
      ]
673
    for diff_pol in partial_policies:
674
      policy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, diff_pol)
675
      objects.InstancePolicy.CheckParameterSyntax(policy, True)
676
      self._AssertIPolicyIsFull(policy)
677
      self._AssertIPolicyMerged(constants.IPOLICY_DEFAULTS, diff_pol, policy)
678

    
679
  def testFillIPolicyKeepsUnknown(self):
680
    INVALID_KEY = "invalid_ipolicy_key"
681
    diff_pol = {
682
      INVALID_KEY: None,
683
      }
684
    policy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, diff_pol)
685
    self.assertTrue(INVALID_KEY in policy)
686

    
687

    
688
if __name__ == "__main__":
689
  testutils.GanetiTestProgram()