Statistics
| Branch: | Tag: | Revision:

root / test / py / ganeti.config_unittest.py @ 64760879

History | View | Annotate | Download (20.5 kB)

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

    
4
# Copyright (C) 2006, 2007, 2010, 2011, 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 config module"""
23

    
24

    
25
import unittest
26
import os
27
import time
28
import tempfile
29
import os.path
30
import socket
31
import operator
32
import itertools
33

    
34
from ganeti import bootstrap
35
from ganeti import config
36
from ganeti import constants
37
from ganeti import errors
38
from ganeti import objects
39
from ganeti import utils
40
from ganeti import netutils
41
from ganeti import compat
42
from ganeti import cmdlib
43

    
44
from ganeti.config import TemporaryReservationManager
45

    
46
import testutils
47
import mocks
48

    
49

    
50
def _StubGetEntResolver():
51
  return mocks.FakeGetentResolver()
52

    
53

    
54
class TestConfigRunner(unittest.TestCase):
55
  """Testing case for HooksRunner"""
56
  def setUp(self):
57
    fd, self.cfg_file = tempfile.mkstemp()
58
    os.close(fd)
59
    self._init_cluster(self.cfg_file)
60

    
61
  def tearDown(self):
62
    try:
63
      os.unlink(self.cfg_file)
64
    except OSError:
65
      pass
66

    
67
  def _get_object(self):
68
    """Returns an instance of ConfigWriter"""
69
    cfg = config.ConfigWriter(cfg_file=self.cfg_file, offline=True,
70
                              _getents=_StubGetEntResolver)
71
    return cfg
72

    
73
  def _init_cluster(self, cfg):
74
    """Initializes the cfg object"""
75
    me = netutils.Hostname()
76
    ip = constants.IP4_ADDRESS_LOCALHOST
77
    # master_ip must not conflict with the node ip address
78
    master_ip = "127.0.0.2"
79

    
80
    cluster_config = objects.Cluster(
81
      serial_no=1,
82
      rsahostkeypub="",
83
      highest_used_port=(constants.FIRST_DRBD_PORT - 1),
84
      mac_prefix="aa:00:00",
85
      volume_group_name="xenvg",
86
      drbd_usermode_helper="/bin/true",
87
      nicparams={constants.PP_DEFAULT: constants.NICC_DEFAULTS},
88
      ndparams=constants.NDC_DEFAULTS,
89
      tcpudp_port_pool=set(),
90
      enabled_hypervisors=[constants.HT_FAKE],
91
      master_node=me.name,
92
      master_ip=master_ip,
93
      master_netdev=constants.DEFAULT_BRIDGE,
94
      cluster_name="cluster.local",
95
      file_storage_dir="/tmp",
96
      uid_pool=[],
97
      )
98

    
99
    master_node_config = objects.Node(name=me.name,
100
                                      primary_ip=me.ip,
101
                                      secondary_ip=ip,
102
                                      serial_no=1,
103
                                      master_candidate=True)
104

    
105
    bootstrap.InitConfig(constants.CONFIG_VERSION,
106
                         cluster_config, master_node_config, self.cfg_file)
107

    
108
  def _create_instance(self):
109
    """Create and return an instance object"""
110
    inst = objects.Instance(name="test.example.com", disks=[], nics=[],
111
                            disk_template=constants.DT_DISKLESS,
112
                            primary_node=self._get_object().GetMasterNode())
113
    return inst
114

    
115
  def testEmpty(self):
116
    """Test instantiate config object"""
117
    self._get_object()
118

    
119
  def testInit(self):
120
    """Test initialize the config file"""
121
    cfg = self._get_object()
122
    self.failUnlessEqual(1, len(cfg.GetNodeList()))
123
    self.failUnlessEqual(0, len(cfg.GetInstanceList()))
124

    
125
  def testUpdateCluster(self):
126
    """Test updates on the cluster object"""
127
    cfg = self._get_object()
128
    # construct a fake cluster object
129
    fake_cl = objects.Cluster()
130
    # fail if we didn't read the config
131
    self.failUnlessRaises(errors.ConfigurationError, cfg.Update, fake_cl, None)
132

    
133
    cl = cfg.GetClusterInfo()
134
    # first pass, must not fail
135
    cfg.Update(cl, None)
136
    # second pass, also must not fail (after the config has been written)
137
    cfg.Update(cl, None)
138
    # but the fake_cl update should still fail
139
    self.failUnlessRaises(errors.ConfigurationError, cfg.Update, fake_cl, None)
140

    
141
  def testUpdateNode(self):
142
    """Test updates on one node object"""
143
    cfg = self._get_object()
144
    # construct a fake node
145
    fake_node = objects.Node()
146
    # fail if we didn't read the config
147
    self.failUnlessRaises(errors.ConfigurationError, cfg.Update, fake_node,
148
                          None)
149

    
150
    node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
151
    # first pass, must not fail
152
    cfg.Update(node, None)
153
    # second pass, also must not fail (after the config has been written)
154
    cfg.Update(node, None)
155
    # but the fake_node update should still fail
156
    self.failUnlessRaises(errors.ConfigurationError, cfg.Update, fake_node,
157
                          None)
158

    
159
  def testUpdateInstance(self):
160
    """Test updates on one instance object"""
161
    cfg = self._get_object()
162
    # construct a fake instance
163
    inst = self._create_instance()
164
    fake_instance = objects.Instance()
165
    # fail if we didn't read the config
166
    self.failUnlessRaises(errors.ConfigurationError, cfg.Update, fake_instance,
167
                          None)
168

    
169
    cfg.AddInstance(inst, "my-job")
170
    instance = cfg.GetInstanceInfo(cfg.GetInstanceList()[0])
171
    # first pass, must not fail
172
    cfg.Update(instance, None)
173
    # second pass, also must not fail (after the config has been written)
174
    cfg.Update(instance, None)
175
    # but the fake_instance update should still fail
176
    self.failUnlessRaises(errors.ConfigurationError, cfg.Update, fake_instance,
177
                          None)
178

    
179
  def testUpgradeSave(self):
180
    """Test that any modification done during upgrading is saved back"""
181
    cfg = self._get_object()
182

    
183
    # Remove an element, run upgrade, and check if the element is
184
    # back and the file upgraded
185
    node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
186
    # For a ConfigObject, None is the same as a missing field
187
    node.ndparams = None
188
    oldsaved = utils.ReadFile(self.cfg_file)
189
    cfg._UpgradeConfig()
190
    self.assertTrue(node.ndparams is not None)
191
    newsaved = utils.ReadFile(self.cfg_file)
192
    # We rely on the fact that at least the serial number changes
193
    self.assertNotEqual(oldsaved, newsaved)
194

    
195
    # Add something that should not be there this time
196
    key = list(constants.NDC_GLOBALS)[0]
197
    node.ndparams[key] = constants.NDC_DEFAULTS[key]
198
    cfg._WriteConfig(None)
199
    oldsaved = utils.ReadFile(self.cfg_file)
200
    cfg._UpgradeConfig()
201
    self.assertTrue(node.ndparams.get(key) is None)
202
    newsaved = utils.ReadFile(self.cfg_file)
203
    self.assertNotEqual(oldsaved, newsaved)
204

    
205
    # Do the upgrade again, this time there should be no update
206
    oldsaved = newsaved
207
    cfg._UpgradeConfig()
208
    newsaved = utils.ReadFile(self.cfg_file)
209
    self.assertEqual(oldsaved, newsaved)
210

    
211
    # Reload the configuration again: it shouldn't change the file
212
    oldsaved = newsaved
213
    self._get_object()
214
    newsaved = utils.ReadFile(self.cfg_file)
215
    self.assertEqual(oldsaved, newsaved)
216

    
217
  def testNICParameterSyntaxCheck(self):
218
    """Test the NIC's CheckParameterSyntax function"""
219
    mode = constants.NIC_MODE
220
    link = constants.NIC_LINK
221
    m_bridged = constants.NIC_MODE_BRIDGED
222
    m_routed = constants.NIC_MODE_ROUTED
223
    CheckSyntax = objects.NIC.CheckParameterSyntax
224

    
225
    CheckSyntax(constants.NICC_DEFAULTS)
226
    CheckSyntax({mode: m_bridged, link: "br1"})
227
    CheckSyntax({mode: m_routed, link: "default"})
228
    self.assertRaises(errors.ConfigurationError,
229
                      CheckSyntax, {mode: "000invalid", link: "any"})
230
    self.assertRaises(errors.ConfigurationError,
231
                      CheckSyntax, {mode: m_bridged, link: None})
232
    self.assertRaises(errors.ConfigurationError,
233
                      CheckSyntax, {mode: m_bridged, link: ""})
234

    
235
  def testGetNdParamsDefault(self):
236
    cfg = self._get_object()
237
    node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
238
    self.assertEqual(cfg.GetNdParams(node), constants.NDC_DEFAULTS)
239

    
240
  def testGetNdParamsModifiedNode(self):
241
    my_ndparams = {
242
        constants.ND_OOB_PROGRAM: "/bin/node-oob",
243
        constants.ND_SPINDLE_COUNT: 1,
244
        constants.ND_EXCLUSIVE_STORAGE: False,
245
        }
246

    
247
    cfg = self._get_object()
248
    node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
249
    node.ndparams = my_ndparams
250
    cfg.Update(node, None)
251
    self.assertEqual(cfg.GetNdParams(node), my_ndparams)
252

    
253
  def testGetNdParamsInheritance(self):
254
    node_ndparams = {
255
      constants.ND_OOB_PROGRAM: "/bin/node-oob",
256
      }
257
    group_ndparams = {
258
      constants.ND_SPINDLE_COUNT: 10,
259
      }
260
    expected_ndparams = {
261
      constants.ND_OOB_PROGRAM: "/bin/node-oob",
262
      constants.ND_SPINDLE_COUNT: 10,
263
      constants.ND_EXCLUSIVE_STORAGE:
264
        constants.NDC_DEFAULTS[constants.ND_EXCLUSIVE_STORAGE],
265
      }
266
    cfg = self._get_object()
267
    node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
268
    node.ndparams = node_ndparams
269
    cfg.Update(node, None)
270
    group = cfg.GetNodeGroup(node.group)
271
    group.ndparams = group_ndparams
272
    cfg.Update(group, None)
273
    self.assertEqual(cfg.GetNdParams(node), expected_ndparams)
274

    
275
  def testAddGroupFillsFieldsIfMissing(self):
276
    cfg = self._get_object()
277
    group = objects.NodeGroup(name="test", members=[])
278
    cfg.AddNodeGroup(group, "my-job")
279
    self.assert_(utils.UUID_RE.match(group.uuid))
280
    self.assertEqual(constants.ALLOC_POLICY_PREFERRED, group.alloc_policy)
281

    
282
  def testAddGroupPreservesFields(self):
283
    cfg = self._get_object()
284
    group = objects.NodeGroup(name="test", members=[],
285
                              alloc_policy=constants.ALLOC_POLICY_LAST_RESORT)
286
    cfg.AddNodeGroup(group, "my-job")
287
    self.assertEqual(constants.ALLOC_POLICY_LAST_RESORT, group.alloc_policy)
288

    
289
  def testAddGroupDoesNotPreserveFields(self):
290
    cfg = self._get_object()
291
    group = objects.NodeGroup(name="test", members=[],
292
                              serial_no=17, ctime=123, mtime=456)
293
    cfg.AddNodeGroup(group, "my-job")
294
    self.assertEqual(1, group.serial_no)
295
    self.assert_(group.ctime > 1200000000)
296
    self.assert_(group.mtime > 1200000000)
297

    
298
  def testAddGroupCanSkipUUIDCheck(self):
299
    cfg = self._get_object()
300
    uuid = cfg.GenerateUniqueID("my-job")
301
    group = objects.NodeGroup(name="test", members=[], uuid=uuid,
302
                              serial_no=17, ctime=123, mtime=456)
303

    
304
    self.assertRaises(errors.ConfigurationError,
305
                      cfg.AddNodeGroup, group, "my-job")
306

    
307
    cfg.AddNodeGroup(group, "my-job", check_uuid=False) # Does not raise.
308
    self.assertEqual(uuid, group.uuid)
309

    
310
  def testAssignGroupNodes(self):
311
    me = netutils.Hostname()
312
    cfg = self._get_object()
313

    
314
    # Create two groups
315
    grp1 = objects.NodeGroup(name="grp1", members=[],
316
                             uuid="2f2fadf7-2a70-4a23-9ab5-2568c252032c")
317
    grp1_serial = 1
318
    cfg.AddNodeGroup(grp1, "job")
319

    
320
    grp2 = objects.NodeGroup(name="grp2", members=[],
321
                             uuid="798d0de3-680f-4a0e-b29a-0f54f693b3f1")
322
    grp2_serial = 1
323
    cfg.AddNodeGroup(grp2, "job")
324
    self.assertEqual(set(map(operator.attrgetter("name"),
325
                             cfg.GetAllNodeGroupsInfo().values())),
326
                     set(["grp1", "grp2", constants.INITIAL_NODE_GROUP_NAME]))
327

    
328
    # No-op
329
    cluster_serial = cfg.GetClusterInfo().serial_no
330
    cfg.AssignGroupNodes([])
331
    cluster_serial += 1
332

    
333
    # Create two nodes
334
    node1 = objects.Node(name="node1", group=grp1.uuid, ndparams={})
335
    node1_serial = 1
336
    node2 = objects.Node(name="node2", group=grp2.uuid, ndparams={})
337
    node2_serial = 1
338
    cfg.AddNode(node1, "job")
339
    cfg.AddNode(node2, "job")
340
    cluster_serial += 2
341
    self.assertEqual(set(cfg.GetNodeList()), set(["node1", "node2", me.name]))
342

    
343
    def _VerifySerials():
344
      self.assertEqual(cfg.GetClusterInfo().serial_no, cluster_serial)
345
      self.assertEqual(node1.serial_no, node1_serial)
346
      self.assertEqual(node2.serial_no, node2_serial)
347
      self.assertEqual(grp1.serial_no, grp1_serial)
348
      self.assertEqual(grp2.serial_no, grp2_serial)
349

    
350
    _VerifySerials()
351

    
352
    self.assertEqual(set(grp1.members), set(["node1"]))
353
    self.assertEqual(set(grp2.members), set(["node2"]))
354

    
355
    # Check invalid nodes and groups
356
    self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
357
      ("unknown.node.example.com", grp2.uuid),
358
      ])
359
    self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
360
      (node1.name, "unknown-uuid"),
361
      ])
362

    
363
    self.assertEqual(node1.group, grp1.uuid)
364
    self.assertEqual(node2.group, grp2.uuid)
365
    self.assertEqual(set(grp1.members), set(["node1"]))
366
    self.assertEqual(set(grp2.members), set(["node2"]))
367

    
368
    # Another no-op
369
    cfg.AssignGroupNodes([])
370
    cluster_serial += 1
371
    _VerifySerials()
372

    
373
    # Assign to the same group (should be a no-op)
374
    self.assertEqual(node2.group, grp2.uuid)
375
    cfg.AssignGroupNodes([
376
      (node2.name, grp2.uuid),
377
      ])
378
    cluster_serial += 1
379
    self.assertEqual(node2.group, grp2.uuid)
380
    _VerifySerials()
381
    self.assertEqual(set(grp1.members), set(["node1"]))
382
    self.assertEqual(set(grp2.members), set(["node2"]))
383

    
384
    # Assign node 2 to group 1
385
    self.assertEqual(node2.group, grp2.uuid)
386
    cfg.AssignGroupNodes([
387
      (node2.name, grp1.uuid),
388
      ])
389
    cluster_serial += 1
390
    node2_serial += 1
391
    grp1_serial += 1
392
    grp2_serial += 1
393
    self.assertEqual(node2.group, grp1.uuid)
394
    _VerifySerials()
395
    self.assertEqual(set(grp1.members), set(["node1", "node2"]))
396
    self.assertFalse(grp2.members)
397

    
398
    # And assign both nodes to group 2
399
    self.assertEqual(node1.group, grp1.uuid)
400
    self.assertEqual(node2.group, grp1.uuid)
401
    self.assertNotEqual(grp1.uuid, grp2.uuid)
402
    cfg.AssignGroupNodes([
403
      (node1.name, grp2.uuid),
404
      (node2.name, grp2.uuid),
405
      ])
406
    cluster_serial += 1
407
    node1_serial += 1
408
    node2_serial += 1
409
    grp1_serial += 1
410
    grp2_serial += 1
411
    self.assertEqual(node1.group, grp2.uuid)
412
    self.assertEqual(node2.group, grp2.uuid)
413
    _VerifySerials()
414
    self.assertFalse(grp1.members)
415
    self.assertEqual(set(grp2.members), set(["node1", "node2"]))
416

    
417
    # Destructive tests
418
    orig_group = node2.group
419
    try:
420
      other_uuid = "68b3d087-6ea5-491c-b81f-0a47d90228c5"
421
      assert compat.all(node.group != other_uuid
422
                        for node in cfg.GetAllNodesInfo().values())
423
      node2.group = "68b3d087-6ea5-491c-b81f-0a47d90228c5"
424
      self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
425
        ("node2", grp2.uuid),
426
        ])
427
      _VerifySerials()
428
    finally:
429
      node2.group = orig_group
430

    
431
  def _TestVerifyConfigIPolicy(self, ipolicy, ipowner, cfg, isgroup):
432
    INVALID_KEY = "this_key_cannot_exist"
433

    
434
    ipolicy[INVALID_KEY] = None
435
    # A call to cluster.SimpleFillIPolicy causes different kinds of error
436
    # depending on the owner (cluster or group)
437
    if isgroup:
438
      errs = cfg.VerifyConfig()
439
      # FIXME: A bug in FillIPolicy (issue 401) makes this test fail, so we
440
      # invert the assertions for the time being
441
      self.assertFalse(len(errs) >= 1)
442
      errstr = "%s has invalid instance policy" % ipowner
443
      self.assertFalse(_IsErrorInList(errstr, errs))
444
    else:
445
      self.assertRaises(AssertionError, cfg.VerifyConfig)
446
    del ipolicy[INVALID_KEY]
447
    errs = cfg.VerifyConfig()
448
    self.assertFalse(errs)
449

    
450
    key = list(constants.IPOLICY_PARAMETERS)[0]
451
    hasoldv = (key in ipolicy)
452
    if hasoldv:
453
      oldv = ipolicy[key]
454
    ipolicy[key] = "blah"
455
    errs = cfg.VerifyConfig()
456
    self.assertTrue(len(errs) >= 1)
457
    self.assertTrue(_IsErrorInList("%s has invalid instance policy" % ipowner,
458
                                   errs))
459
    if hasoldv:
460
      ipolicy[key] = oldv
461
    else:
462
      del ipolicy[key]
463

    
464
    ispeclist = [
465
      (ipolicy[constants.ISPECS_MINMAX][constants.ISPECS_MIN],
466
       "%s/%s" % (constants.ISPECS_MINMAX, constants.ISPECS_MIN)),
467
      (ipolicy[constants.ISPECS_MINMAX][constants.ISPECS_MAX],
468
       "%s/%s" % (constants.ISPECS_MINMAX, constants.ISPECS_MAX)),
469
      (ipolicy[constants.ISPECS_STD], constants.ISPECS_STD),
470
      ]
471
    for (ispec, ispecpath) in ispeclist:
472
      ispec[INVALID_KEY] = None
473
      errs = cfg.VerifyConfig()
474
      self.assertTrue(len(errs) >= 1)
475
      self.assertTrue(_IsErrorInList(("%s has invalid ipolicy/%s" %
476
                                      (ipowner, ispecpath)), errs))
477
      del ispec[INVALID_KEY]
478
      errs = cfg.VerifyConfig()
479
      self.assertFalse(errs)
480

    
481
      for par in constants.ISPECS_PARAMETERS:
482
        hasoldv = par in ispec
483
        if hasoldv:
484
          oldv = ispec[par]
485
        ispec[par] = "blah"
486
        errs = cfg.VerifyConfig()
487
        self.assertTrue(len(errs) >= 1)
488
        self.assertTrue(_IsErrorInList(("%s has invalid ipolicy/%s" %
489
                                        (ipowner, ispecpath)), errs))
490
        if hasoldv:
491
          ispec[par] = oldv
492
        else:
493
          del ispec[par]
494
        errs = cfg.VerifyConfig()
495
        self.assertFalse(errs)
496

    
497
  def _TestVerifyConfigGroupIPolicy(self, groupinfo, cfg):
498
    old_ipolicy = groupinfo.ipolicy
499
    ipolicy = cfg.GetClusterInfo().SimpleFillIPolicy({})
500
    groupinfo.ipolicy = ipolicy
501
    # Test partial policies
502
    for key in constants.IPOLICY_ALL_KEYS:
503
      self.assertTrue(key in ipolicy)
504
      oldv = ipolicy[key]
505
      del ipolicy[key]
506
      errs = cfg.VerifyConfig()
507
      self.assertFalse(errs)
508
      ipolicy[key] = oldv
509
    # Test partial minmax specs
510
    minmax = ipolicy[constants.ISPECS_MINMAX]
511
    for ispec_key in minmax.keys():
512
      ispec = minmax[ispec_key]
513
      for par in constants.ISPECS_PARAMETERS:
514
        oldv = ispec[par]
515
        del ispec[par]
516
        errs = cfg.VerifyConfig()
517
        self.assertFalse(errs)
518
        ispec[par] = oldv
519
    groupinfo.ipolicy = old_ipolicy
520

    
521
  def _TestVerifyConfigClusterIPolicy(self, ipolicy, cfg):
522
    # Test partial policies
523
    for key in constants.IPOLICY_ALL_KEYS:
524
      self.assertTrue(key in ipolicy)
525
      oldv = ipolicy[key]
526
      del ipolicy[key]
527
      self.assertRaises(AssertionError, cfg.VerifyConfig)
528
      ipolicy[key] = oldv
529
    # Test partial minmax specs
530
    minmax = ipolicy[constants.ISPECS_MINMAX]
531
    for key in constants.ISPECS_MINMAX_KEYS:
532
      self.assertTrue(key in minmax)
533
      oldv = minmax[key]
534
      del minmax[key]
535
      self.assertRaises(AssertionError, cfg.VerifyConfig)
536
      minmax[key] = oldv
537
    errs = cfg.VerifyConfig()
538
    self.assertFalse(errs)
539

    
540
  def testVerifyConfig(self):
541
    cfg = self._get_object()
542

    
543
    errs = cfg.VerifyConfig()
544
    self.assertFalse(errs)
545

    
546
    node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
547
    key = list(constants.NDC_GLOBALS)[0]
548
    node.ndparams[key] = constants.NDC_DEFAULTS[key]
549
    errs = cfg.VerifyConfig()
550
    self.assertTrue(len(errs) >= 1)
551
    self.assertTrue(_IsErrorInList("has some global parameters set", errs))
552

    
553
    del node.ndparams[key]
554
    errs = cfg.VerifyConfig()
555
    self.assertFalse(errs)
556

    
557
    cluster = cfg.GetClusterInfo()
558
    nodegroup = cfg.GetNodeGroup(cfg.GetNodeGroupList()[0])
559
    self._TestVerifyConfigIPolicy(cluster.ipolicy, "cluster", cfg, False)
560
    self._TestVerifyConfigClusterIPolicy(cluster.ipolicy, cfg)
561
    self._TestVerifyConfigIPolicy(nodegroup.ipolicy, nodegroup.name, cfg, True)
562
    self._TestVerifyConfigGroupIPolicy(nodegroup, cfg)
563
    nodegroup.ipolicy = cluster.SimpleFillIPolicy(nodegroup.ipolicy)
564
    self._TestVerifyConfigIPolicy(nodegroup.ipolicy, nodegroup.name, cfg, True)
565

    
566

    
567
def _IsErrorInList(err_str, err_list):
568
  return any(map(lambda e: err_str in e, err_list))
569

    
570

    
571
class TestTRM(unittest.TestCase):
572
  EC_ID = 1
573

    
574
  def testEmpty(self):
575
    t = TemporaryReservationManager()
576
    t.Reserve(self.EC_ID, "a")
577
    self.assertFalse(t.Reserved(self.EC_ID))
578
    self.assertTrue(t.Reserved("a"))
579
    self.assertEqual(len(t.GetReserved()), 1)
580

    
581
  def testDuplicate(self):
582
    t = TemporaryReservationManager()
583
    t.Reserve(self.EC_ID, "a")
584
    self.assertRaises(errors.ReservationError, t.Reserve, 2, "a")
585
    t.DropECReservations(self.EC_ID)
586
    self.assertFalse(t.Reserved("a"))
587

    
588

    
589
class TestCheckInstanceDiskIvNames(unittest.TestCase):
590
  @staticmethod
591
  def _MakeDisks(names):
592
    return [objects.Disk(iv_name=name) for name in names]
593

    
594
  def testNoError(self):
595
    disks = self._MakeDisks(["disk/0", "disk/1"])
596
    self.assertEqual(config._CheckInstanceDiskIvNames(disks), [])
597
    cmdlib._UpdateIvNames(0, disks)
598
    self.assertEqual(config._CheckInstanceDiskIvNames(disks), [])
599

    
600
  def testWrongNames(self):
601
    disks = self._MakeDisks(["disk/1", "disk/3", "disk/2"])
602
    self.assertEqual(config._CheckInstanceDiskIvNames(disks), [
603
      (0, "disk/0", "disk/1"),
604
      (1, "disk/1", "disk/3"),
605
      ])
606

    
607
    # Fix names
608
    cmdlib._UpdateIvNames(0, disks)
609
    self.assertEqual(config._CheckInstanceDiskIvNames(disks), [])
610

    
611

    
612
if __name__ == "__main__":
613
  testutils.GanetiTestProgram()