Statistics
| Branch: | Tag: | Revision:

root / test / py / ganeti.objects_unittest.py @ 807d8853

History | View | Annotate | Download (24.7 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

    
236
class TestClusterObjectTcpUdpPortPool(unittest.TestCase):
237
  def testNewCluster(self):
238
    self.assertTrue(objects.Cluster().tcpudp_port_pool is None)
239

    
240
  def testSerializingEmpty(self):
241
    self.assertEqual(objects.Cluster().ToDict(), {
242
      "tcpudp_port_pool": [],
243
      })
244

    
245
  def testSerializing(self):
246
    cluster = objects.Cluster.FromDict({})
247
    self.assertEqual(cluster.tcpudp_port_pool, set())
248

    
249
    cluster.tcpudp_port_pool.add(3546)
250
    cluster.tcpudp_port_pool.add(62511)
251

    
252
    data = cluster.ToDict()
253
    self.assertEqual(data.keys(), ["tcpudp_port_pool"])
254
    self.assertEqual(sorted(data["tcpudp_port_pool"]), sorted([3546, 62511]))
255

    
256
  def testDeserializingEmpty(self):
257
    cluster = objects.Cluster.FromDict({})
258
    self.assertEqual(cluster.tcpudp_port_pool, set())
259

    
260
  def testDeserialize(self):
261
    cluster = objects.Cluster.FromDict({
262
      "tcpudp_port_pool": [26214, 10039, 267],
263
      })
264
    self.assertEqual(cluster.tcpudp_port_pool, set([26214, 10039, 267]))
265

    
266

    
267
class TestOS(unittest.TestCase):
268
  ALL_DATA = [
269
    "debootstrap",
270
    "debootstrap+default",
271
    "debootstrap++default",
272
    ]
273

    
274
  def testSplitNameVariant(self):
275
    for name in self.ALL_DATA:
276
      self.assertEqual(len(objects.OS.SplitNameVariant(name)), 2)
277

    
278
  def testVariant(self):
279
    self.assertEqual(objects.OS.GetVariant("debootstrap"), "")
280
    self.assertEqual(objects.OS.GetVariant("debootstrap+default"), "default")
281

    
282

    
283
class TestInstance(unittest.TestCase):
284
  def _GenericCheck(self, inst):
285
    for i in [inst.all_nodes, inst.secondary_nodes]:
286
      self.assertTrue(isinstance(inst.all_nodes, (list, tuple)),
287
                      msg="Data type doesn't guarantee order")
288

    
289
    self.assertTrue(inst.primary_node not in inst.secondary_nodes)
290
    self.assertEqual(inst.all_nodes[0], inst.primary_node,
291
                     msg="Primary node not first node in list")
292

    
293
  def testNodesNoDisks(self):
294
    inst = objects.Instance(name="fakeinst.example.com",
295
      primary_node="pnode.example.com",
296
      disks=[
297
        ])
298

    
299
    self._GenericCheck(inst)
300
    self.assertEqual(len(inst.secondary_nodes), 0)
301
    self.assertEqual(set(inst.all_nodes), set([inst.primary_node]))
302
    self.assertEqual(inst.MapLVsByNode(), {
303
      inst.primary_node: [],
304
      })
305

    
306
  def testNodesPlainDisks(self):
307
    inst = objects.Instance(name="fakeinstplain.example.com",
308
      primary_node="node3.example.com",
309
      disks=[
310
        objects.Disk(dev_type=constants.LD_LV, size=128,
311
                     logical_id=("myxenvg", "disk25494")),
312
        objects.Disk(dev_type=constants.LD_LV, size=512,
313
                     logical_id=("myxenvg", "disk29071")),
314
        ])
315

    
316
    self._GenericCheck(inst)
317
    self.assertEqual(len(inst.secondary_nodes), 0)
318
    self.assertEqual(set(inst.all_nodes), set([inst.primary_node]))
319
    self.assertEqual(inst.MapLVsByNode(), {
320
      inst.primary_node: ["myxenvg/disk25494", "myxenvg/disk29071"],
321
      })
322

    
323
  def testNodesDrbdDisks(self):
324
    inst = objects.Instance(name="fakeinstdrbd.example.com",
325
      primary_node="node10.example.com",
326
      disks=[
327
        objects.Disk(dev_type=constants.LD_DRBD8, size=786432,
328
          logical_id=("node10.example.com", "node15.example.com",
329
                      12300, 0, 0, "secret"),
330
          children=[
331
            objects.Disk(dev_type=constants.LD_LV, size=786432,
332
                         logical_id=("myxenvg", "disk0")),
333
            objects.Disk(dev_type=constants.LD_LV, size=128,
334
                         logical_id=("myxenvg", "meta0"))
335
          ],
336
          iv_name="disk/0")
337
        ])
338

    
339
    self._GenericCheck(inst)
340
    self.assertEqual(set(inst.secondary_nodes), set(["node15.example.com"]))
341
    self.assertEqual(set(inst.all_nodes),
342
                     set([inst.primary_node, "node15.example.com"]))
343
    self.assertEqual(inst.MapLVsByNode(), {
344
      inst.primary_node: ["myxenvg/disk0", "myxenvg/meta0"],
345
      "node15.example.com": ["myxenvg/disk0", "myxenvg/meta0"],
346
      })
347

    
348
    self.assertEqual(inst.FindDisk(0), inst.disks[0])
349
    self.assertRaises(errors.OpPrereqError, inst.FindDisk, "hello")
350
    self.assertRaises(errors.OpPrereqError, inst.FindDisk, 100)
351
    self.assertRaises(errors.OpPrereqError, inst.FindDisk, 1)
352

    
353

    
354
class TestNode(unittest.TestCase):
355
  def testEmpty(self):
356
    self.assertEqual(objects.Node().ToDict(), {})
357
    self.assertTrue(isinstance(objects.Node.FromDict({}), objects.Node))
358

    
359
  def testHvState(self):
360
    node = objects.Node(name="node18157.example.com", hv_state={
361
      constants.HT_XEN_HVM: objects.NodeHvState(cpu_total=64),
362
      constants.HT_KVM: objects.NodeHvState(cpu_node=1),
363
      })
364

    
365
    node2 = objects.Node.FromDict(node.ToDict())
366

    
367
    # Make sure nothing can reference it anymore
368
    del node
369

    
370
    self.assertEqual(node2.name, "node18157.example.com")
371
    self.assertEqual(frozenset(node2.hv_state), frozenset([
372
      constants.HT_XEN_HVM,
373
      constants.HT_KVM,
374
      ]))
375
    self.assertEqual(node2.hv_state[constants.HT_KVM].cpu_node, 1)
376
    self.assertEqual(node2.hv_state[constants.HT_XEN_HVM].cpu_total, 64)
377

    
378
  def testDiskState(self):
379
    node = objects.Node(name="node32087.example.com", disk_state={
380
      constants.LD_LV: {
381
        "lv32352": objects.NodeDiskState(total=128),
382
        "lv2082": objects.NodeDiskState(total=512),
383
        },
384
      })
385

    
386
    node2 = objects.Node.FromDict(node.ToDict())
387

    
388
    # Make sure nothing can reference it anymore
389
    del node
390

    
391
    self.assertEqual(node2.name, "node32087.example.com")
392
    self.assertEqual(frozenset(node2.disk_state), frozenset([
393
      constants.LD_LV,
394
      ]))
395
    self.assertEqual(frozenset(node2.disk_state[constants.LD_LV]), frozenset([
396
      "lv32352",
397
      "lv2082",
398
      ]))
399
    self.assertEqual(node2.disk_state[constants.LD_LV]["lv2082"].total, 512)
400
    self.assertEqual(node2.disk_state[constants.LD_LV]["lv32352"].total, 128)
401

    
402
  def testFilterEsNdp(self):
403
    node1 = objects.Node(name="node11673.example.com", ndparams={
404
      constants.ND_EXCLUSIVE_STORAGE: True,
405
      })
406
    node2 = objects.Node(name="node11674.example.com", ndparams={
407
      constants.ND_SPINDLE_COUNT: 3,
408
      constants.ND_EXCLUSIVE_STORAGE: False,
409
      })
410
    self.assertTrue(constants.ND_EXCLUSIVE_STORAGE in node1.ndparams)
411
    node1.UpgradeConfig()
412
    self.assertFalse(constants.ND_EXCLUSIVE_STORAGE in node1.ndparams)
413
    self.assertTrue(constants.ND_EXCLUSIVE_STORAGE in node2.ndparams)
414
    self.assertTrue(constants.ND_SPINDLE_COUNT in node2.ndparams)
415
    node2.UpgradeConfig()
416
    self.assertFalse(constants.ND_EXCLUSIVE_STORAGE in node2.ndparams)
417
    self.assertTrue(constants.ND_SPINDLE_COUNT in node2.ndparams)
418

    
419

    
420
class TestInstancePolicy(unittest.TestCase):
421
  def setUp(self):
422
    # Policies are big, and we want to see the difference in case of an error
423
    self.maxDiff = None
424

    
425
  def _AssertIPolicyIsFull(self, policy):
426
    self.assertEqual(frozenset(policy.keys()), constants.IPOLICY_ALL_KEYS)
427
    self.assertTrue(len(policy[constants.ISPECS_MINMAX]) > 0)
428
    for minmax in policy[constants.ISPECS_MINMAX]:
429
      self.assertEqual(frozenset(minmax.keys()), constants.ISPECS_MINMAX_KEYS)
430
      for key in constants.ISPECS_MINMAX_KEYS:
431
        self.assertEqual(frozenset(minmax[key].keys()),
432
                         constants.ISPECS_PARAMETERS)
433
    self.assertEqual(frozenset(policy[constants.ISPECS_STD].keys()),
434
                     constants.ISPECS_PARAMETERS)
435

    
436
  def testDefaultIPolicy(self):
437
    objects.InstancePolicy.CheckParameterSyntax(constants.IPOLICY_DEFAULTS,
438
                                                True)
439
    self._AssertIPolicyIsFull(constants.IPOLICY_DEFAULTS)
440

    
441
  def _AssertPolicyIsBad(self, ipolicy, do_check_std=None):
442
    if do_check_std is None:
443
      check_std_vals = [False, True]
444
    else:
445
      check_std_vals = [do_check_std]
446
    for check_std in check_std_vals:
447
      self.assertRaises(errors.ConfigurationError,
448
                        objects.InstancePolicy.CheckISpecSyntax,
449
                        ipolicy, check_std)
450

    
451
  def testCheckISpecSyntax(self):
452
    default_stdspec = constants.IPOLICY_DEFAULTS[constants.ISPECS_STD]
453
    incomplete_ipolicies = [
454
      {
455
         constants.ISPECS_MINMAX: [],
456
         constants.ISPECS_STD: default_stdspec,
457
         },
458
      {
459
         constants.ISPECS_MINMAX: [{}],
460
         constants.ISPECS_STD: default_stdspec,
461
         },
462
      {
463
        constants.ISPECS_MINMAX: [{
464
          constants.ISPECS_MIN: NotImplemented,
465
          }],
466
        constants.ISPECS_STD: default_stdspec,
467
        },
468
      {
469
        constants.ISPECS_MINMAX: [{
470
          constants.ISPECS_MAX: NotImplemented,
471
          }],
472
        constants.ISPECS_STD: default_stdspec,
473
        },
474
      {
475
        constants.ISPECS_MINMAX: [{
476
          constants.ISPECS_MIN: NotImplemented,
477
          constants.ISPECS_MAX: NotImplemented,
478
          }],
479
        },
480
      ]
481
    for ipol in incomplete_ipolicies:
482
      self.assertRaises(errors.ConfigurationError,
483
                        objects.InstancePolicy.CheckISpecSyntax,
484
                        ipol, True)
485
      oldminmax = ipol[constants.ISPECS_MINMAX]
486
      if oldminmax:
487
        # Prepending valid specs shouldn't change the error
488
        ipol[constants.ISPECS_MINMAX] = ([constants.ISPECS_MINMAX_DEFAULTS] +
489
                                         oldminmax)
490
        self.assertRaises(errors.ConfigurationError,
491
                          objects.InstancePolicy.CheckISpecSyntax,
492
                          ipol, True)
493

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

    
539
    bad_ipolicy = copy.deepcopy(good_ipolicy)
540
    for minmax in bad_ipolicy[constants.ISPECS_MINMAX]:
541
      for (key, spec) in minmax.items():
542
        for param in spec:
543
          oldv = spec[param]
544
          del spec[param]
545
          self._AssertPolicyIsBad(bad_ipolicy)
546
          if key == constants.ISPECS_MIN:
547
            spec[param] = minmax[constants.ISPECS_MAX][param] + 1
548
          self._AssertPolicyIsBad(bad_ipolicy)
549
          spec[param] = oldv
550
    assert bad_ipolicy == good_ipolicy
551

    
552
    stdspec = bad_ipolicy[constants.ISPECS_STD]
553
    for param in stdspec:
554
      oldv = stdspec[param]
555
      del stdspec[param]
556
      self._AssertPolicyIsBad(bad_ipolicy, True)
557
      # Note that std spec is the same as a max spec
558
      stdspec[param] = oldv + 1
559
      self._AssertPolicyIsBad(bad_ipolicy, True)
560
      stdspec[param] = oldv
561
    assert bad_ipolicy == good_ipolicy
562

    
563
    for minmax in good_ipolicy[constants.ISPECS_MINMAX]:
564
      for spec in minmax.values():
565
        good_ipolicy[constants.ISPECS_STD] = spec
566
        objects.InstancePolicy.CheckISpecSyntax(good_ipolicy, True)
567

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

    
621
  def testCheckDiskTemplates(self):
622
    invalid = "this_is_not_a_good_template"
623
    for dt in constants.DISK_TEMPLATES:
624
      objects.InstancePolicy.CheckDiskTemplates([dt])
625
    objects.InstancePolicy.CheckDiskTemplates(list(constants.DISK_TEMPLATES))
626
    bad_examples = [
627
      [invalid],
628
      [constants.DT_DRBD8, invalid],
629
      list(constants.DISK_TEMPLATES) + [invalid],
630
      [],
631
      None,
632
      ]
633
    for dtl in bad_examples:
634
      self.assertRaises(errors.ConfigurationError,
635
                        objects.InstancePolicy.CheckDiskTemplates,
636
                        dtl)
637

    
638
  def testCheckParameterSyntax(self):
639
    invalid = "this_key_shouldnt_be_here"
640
    for check_std in [True, False]:
641
      objects.InstancePolicy.CheckParameterSyntax({}, check_std)
642
      policy = {invalid: None}
643
      self.assertRaises(errors.ConfigurationError,
644
                        objects.InstancePolicy.CheckParameterSyntax,
645
                        policy, check_std)
646
      for par in constants.IPOLICY_PARAMETERS:
647
        for val in ("blah", None, {}, [42]):
648
          policy = {par: val}
649
          self.assertRaises(errors.ConfigurationError,
650
                            objects.InstancePolicy.CheckParameterSyntax,
651
                            policy, check_std)
652

    
653
  def testFillIPolicyEmpty(self):
654
    policy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, {})
655
    objects.InstancePolicy.CheckParameterSyntax(policy, True)
656
    self.assertEqual(policy, constants.IPOLICY_DEFAULTS)
657

    
658
  def _AssertISpecsMerged(self, default_spec, diff_spec, merged_spec):
659
    for (param, value) in merged_spec.items():
660
      if param in diff_spec:
661
        self.assertEqual(value, diff_spec[param])
662
      else:
663
        self.assertEqual(value, default_spec[param])
664

    
665
  def _AssertIPolicyMerged(self, default_pol, diff_pol, merged_pol):
666
    for (key, value) in merged_pol.items():
667
      if key in diff_pol:
668
        if key == constants.ISPECS_STD:
669
          self._AssertISpecsMerged(default_pol[key], diff_pol[key], value)
670
        else:
671
          self.assertEqual(value, diff_pol[key])
672
      else:
673
        self.assertEqual(value, default_pol[key])
674

    
675
  def testFillIPolicy(self):
676
    partial_policies = [
677
      {constants.IPOLICY_VCPU_RATIO: 3.14},
678
      {constants.IPOLICY_SPINDLE_RATIO: 2.72},
679
      {constants.IPOLICY_DTS: [constants.DT_FILE]},
680
      {constants.ISPECS_STD: {constants.ISPEC_DISK_COUNT: 3}},
681
      {constants.ISPECS_MINMAX: [constants.ISPECS_MINMAX_DEFAULTS,
682
                                 constants.ISPECS_MINMAX_DEFAULTS]}
683
      ]
684
    for diff_pol in partial_policies:
685
      policy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, diff_pol)
686
      objects.InstancePolicy.CheckParameterSyntax(policy, True)
687
      self._AssertIPolicyIsFull(policy)
688
      self._AssertIPolicyMerged(constants.IPOLICY_DEFAULTS, diff_pol, policy)
689

    
690
  def testFillIPolicyKeepsUnknown(self):
691
    INVALID_KEY = "invalid_ipolicy_key"
692
    diff_pol = {
693
      INVALID_KEY: None,
694
      }
695
    policy = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, diff_pol)
696
    self.assertTrue(INVALID_KEY in policy)
697

    
698

    
699
if __name__ == "__main__":
700
  testutils.GanetiTestProgram()