Statistics
| Branch: | Tag: | Revision:

root / test / py / ganeti.config_unittest.py @ 5859dad6

History | View | Annotate | Download (22.9 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 tempfile
28
import operator
29

    
30
from ganeti import bootstrap
31
from ganeti import config
32
from ganeti import constants
33
from ganeti import errors
34
from ganeti import objects
35
from ganeti import utils
36
from ganeti import netutils
37
from ganeti import compat
38
from ganeti.cmdlib import instance
39

    
40
from ganeti.config import TemporaryReservationManager
41

    
42
import testutils
43
import mocks
44
import mock
45

    
46

    
47
def _StubGetEntResolver():
48
  return mocks.FakeGetentResolver()
49

    
50

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

    
58
  def tearDown(self):
59
    try:
60
      os.unlink(self.cfg_file)
61
    except OSError:
62
      pass
63

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

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

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

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

    
103
    bootstrap.InitConfig(constants.CONFIG_VERSION,
104
                         cluster_config, master_node_config, self.cfg_file)
105

    
106
  def _create_instance(self):
107
    """Create and return an instance object"""
108
    inst = objects.Instance(name="test.example.com",
109
                            uuid="test-uuid",
110
                            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
        constants.ND_OVS: True,
246
        constants.ND_OVS_NAME: "openvswitch",
247
        constants.ND_OVS_LINK: "eth1"
248
        }
249

    
250
    cfg = self._get_object()
251
    node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
252
    node.ndparams = my_ndparams
253
    cfg.Update(node, None)
254
    self.assertEqual(cfg.GetNdParams(node), my_ndparams)
255

    
256
  def testGetNdParamsInheritance(self):
257
    node_ndparams = {
258
      constants.ND_OOB_PROGRAM: "/bin/node-oob",
259
      constants.ND_OVS_LINK: "eth3"
260
      }
261
    group_ndparams = {
262
      constants.ND_SPINDLE_COUNT: 10,
263
      constants.ND_OVS: True,
264
      constants.ND_OVS_NAME: "openvswitch",
265
      }
266
    expected_ndparams = {
267
      constants.ND_OOB_PROGRAM: "/bin/node-oob",
268
      constants.ND_SPINDLE_COUNT: 10,
269
      constants.ND_EXCLUSIVE_STORAGE:
270
        constants.NDC_DEFAULTS[constants.ND_EXCLUSIVE_STORAGE],
271
      constants.ND_OVS: True,
272
      constants.ND_OVS_NAME: "openvswitch",
273
      constants.ND_OVS_LINK: "eth3"
274
      }
275
    cfg = self._get_object()
276
    node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
277
    node.ndparams = node_ndparams
278
    cfg.Update(node, None)
279
    group = cfg.GetNodeGroup(node.group)
280
    group.ndparams = group_ndparams
281
    cfg.Update(group, None)
282
    self.assertEqual(cfg.GetNdParams(node), expected_ndparams)
283

    
284
  def testAddGroupFillsFieldsIfMissing(self):
285
    cfg = self._get_object()
286
    group = objects.NodeGroup(name="test", members=[])
287
    cfg.AddNodeGroup(group, "my-job")
288
    self.assert_(utils.UUID_RE.match(group.uuid))
289
    self.assertEqual(constants.ALLOC_POLICY_PREFERRED, group.alloc_policy)
290

    
291
  def testAddGroupPreservesFields(self):
292
    cfg = self._get_object()
293
    group = objects.NodeGroup(name="test", members=[],
294
                              alloc_policy=constants.ALLOC_POLICY_LAST_RESORT)
295
    cfg.AddNodeGroup(group, "my-job")
296
    self.assertEqual(constants.ALLOC_POLICY_LAST_RESORT, group.alloc_policy)
297

    
298
  def testAddGroupDoesNotPreserveFields(self):
299
    cfg = self._get_object()
300
    group = objects.NodeGroup(name="test", members=[],
301
                              serial_no=17, ctime=123, mtime=456)
302
    cfg.AddNodeGroup(group, "my-job")
303
    self.assertEqual(1, group.serial_no)
304
    self.assert_(group.ctime > 1200000000)
305
    self.assert_(group.mtime > 1200000000)
306

    
307
  def testAddGroupCanSkipUUIDCheck(self):
308
    cfg = self._get_object()
309
    uuid = cfg.GenerateUniqueID("my-job")
310
    group = objects.NodeGroup(name="test", members=[], uuid=uuid,
311
                              serial_no=17, ctime=123, mtime=456)
312

    
313
    self.assertRaises(errors.ConfigurationError,
314
                      cfg.AddNodeGroup, group, "my-job")
315

    
316
    cfg.AddNodeGroup(group, "my-job", check_uuid=False) # Does not raise.
317
    self.assertEqual(uuid, group.uuid)
318

    
319
  def testAssignGroupNodes(self):
320
    me = netutils.Hostname()
321
    cfg = self._get_object()
322

    
323
    # Create two groups
324
    grp1 = objects.NodeGroup(name="grp1", members=[],
325
                             uuid="2f2fadf7-2a70-4a23-9ab5-2568c252032c")
326
    grp1_serial = 1
327
    cfg.AddNodeGroup(grp1, "job")
328

    
329
    grp2 = objects.NodeGroup(name="grp2", members=[],
330
                             uuid="798d0de3-680f-4a0e-b29a-0f54f693b3f1")
331
    grp2_serial = 1
332
    cfg.AddNodeGroup(grp2, "job")
333
    self.assertEqual(set(map(operator.attrgetter("name"),
334
                             cfg.GetAllNodeGroupsInfo().values())),
335
                     set(["grp1", "grp2", constants.INITIAL_NODE_GROUP_NAME]))
336

    
337
    # No-op
338
    cluster_serial = cfg.GetClusterInfo().serial_no
339
    cfg.AssignGroupNodes([])
340
    cluster_serial += 1
341

    
342
    # Create two nodes
343
    node1 = objects.Node(name="node1", group=grp1.uuid, ndparams={},
344
                         uuid="node1-uuid")
345
    node1_serial = 1
346
    node2 = objects.Node(name="node2", group=grp2.uuid, ndparams={},
347
                         uuid="node2-uuid")
348
    node2_serial = 1
349
    cfg.AddNode(node1, "job")
350
    cfg.AddNode(node2, "job")
351
    cluster_serial += 2
352
    self.assertEqual(set(cfg.GetNodeList()),
353
                     set(["node1-uuid", "node2-uuid",
354
                          cfg.GetNodeInfoByName(me.name).uuid]))
355

    
356
    def _VerifySerials():
357
      self.assertEqual(cfg.GetClusterInfo().serial_no, cluster_serial)
358
      self.assertEqual(node1.serial_no, node1_serial)
359
      self.assertEqual(node2.serial_no, node2_serial)
360
      self.assertEqual(grp1.serial_no, grp1_serial)
361
      self.assertEqual(grp2.serial_no, grp2_serial)
362

    
363
    _VerifySerials()
364

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

    
368
    # Check invalid nodes and groups
369
    self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
370
      ("unknown.node.example.com", grp2.uuid),
371
      ])
372
    self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
373
      (node1.name, "unknown-uuid"),
374
      ])
375

    
376
    self.assertEqual(node1.group, grp1.uuid)
377
    self.assertEqual(node2.group, grp2.uuid)
378
    self.assertEqual(set(grp1.members), set(["node1-uuid"]))
379
    self.assertEqual(set(grp2.members), set(["node2-uuid"]))
380

    
381
    # Another no-op
382
    cfg.AssignGroupNodes([])
383
    cluster_serial += 1
384
    _VerifySerials()
385

    
386
    # Assign to the same group (should be a no-op)
387
    self.assertEqual(node2.group, grp2.uuid)
388
    cfg.AssignGroupNodes([
389
      (node2.uuid, grp2.uuid),
390
      ])
391
    cluster_serial += 1
392
    self.assertEqual(node2.group, grp2.uuid)
393
    _VerifySerials()
394
    self.assertEqual(set(grp1.members), set(["node1-uuid"]))
395
    self.assertEqual(set(grp2.members), set(["node2-uuid"]))
396

    
397
    # Assign node 2 to group 1
398
    self.assertEqual(node2.group, grp2.uuid)
399
    cfg.AssignGroupNodes([
400
      (node2.uuid, grp1.uuid),
401
      ])
402
    cluster_serial += 1
403
    node2_serial += 1
404
    grp1_serial += 1
405
    grp2_serial += 1
406
    self.assertEqual(node2.group, grp1.uuid)
407
    _VerifySerials()
408
    self.assertEqual(set(grp1.members), set(["node1-uuid", "node2-uuid"]))
409
    self.assertFalse(grp2.members)
410

    
411
    # And assign both nodes to group 2
412
    self.assertEqual(node1.group, grp1.uuid)
413
    self.assertEqual(node2.group, grp1.uuid)
414
    self.assertNotEqual(grp1.uuid, grp2.uuid)
415
    cfg.AssignGroupNodes([
416
      (node1.uuid, grp2.uuid),
417
      (node2.uuid, grp2.uuid),
418
      ])
419
    cluster_serial += 1
420
    node1_serial += 1
421
    node2_serial += 1
422
    grp1_serial += 1
423
    grp2_serial += 1
424
    self.assertEqual(node1.group, grp2.uuid)
425
    self.assertEqual(node2.group, grp2.uuid)
426
    _VerifySerials()
427
    self.assertFalse(grp1.members)
428
    self.assertEqual(set(grp2.members), set(["node1-uuid", "node2-uuid"]))
429

    
430
    # Destructive tests
431
    orig_group = node2.group
432
    try:
433
      other_uuid = "68b3d087-6ea5-491c-b81f-0a47d90228c5"
434
      assert compat.all(node.group != other_uuid
435
                        for node in cfg.GetAllNodesInfo().values())
436
      node2.group = "68b3d087-6ea5-491c-b81f-0a47d90228c5"
437
      self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
438
        (node2.uuid, grp2.uuid),
439
        ])
440
      _VerifySerials()
441
    finally:
442
      node2.group = orig_group
443

    
444
  def _TestVerifyConfigIPolicy(self, ipolicy, ipowner, cfg, isgroup):
445
    INVALID_KEY = "this_key_cannot_exist"
446

    
447
    ipolicy[INVALID_KEY] = None
448
    # A call to cluster.SimpleFillIPolicy causes different kinds of error
449
    # depending on the owner (cluster or group)
450
    if isgroup:
451
      errs = cfg.VerifyConfig()
452
      self.assertTrue(len(errs) >= 1)
453
      errstr = "%s has invalid instance policy" % ipowner
454
      self.assertTrue(_IsErrorInList(errstr, errs))
455
    else:
456
      self.assertRaises(AssertionError, cfg.VerifyConfig)
457
    del ipolicy[INVALID_KEY]
458
    errs = cfg.VerifyConfig()
459
    self.assertFalse(errs)
460

    
461
    key = list(constants.IPOLICY_PARAMETERS)[0]
462
    hasoldv = (key in ipolicy)
463
    if hasoldv:
464
      oldv = ipolicy[key]
465
    ipolicy[key] = "blah"
466
    errs = cfg.VerifyConfig()
467
    self.assertTrue(len(errs) >= 1)
468
    self.assertTrue(_IsErrorInList("%s has invalid instance policy" % ipowner,
469
                                   errs))
470
    if hasoldv:
471
      ipolicy[key] = oldv
472
    else:
473
      del ipolicy[key]
474

    
475
    ispeclist = []
476
    if constants.ISPECS_MINMAX in ipolicy:
477
      for k in range(len(ipolicy[constants.ISPECS_MINMAX])):
478
        ispeclist.extend([
479
            (ipolicy[constants.ISPECS_MINMAX][k][constants.ISPECS_MIN],
480
             "%s[%s]/%s" % (constants.ISPECS_MINMAX, k, constants.ISPECS_MIN)),
481
            (ipolicy[constants.ISPECS_MINMAX][k][constants.ISPECS_MAX],
482
             "%s[%s]/%s" % (constants.ISPECS_MINMAX, k, constants.ISPECS_MAX)),
483
            ])
484
    if constants.ISPECS_STD in ipolicy:
485
      ispeclist.append((ipolicy[constants.ISPECS_STD], constants.ISPECS_STD))
486

    
487
    for (ispec, ispecpath) in ispeclist:
488
      ispec[INVALID_KEY] = None
489
      errs = cfg.VerifyConfig()
490
      self.assertTrue(len(errs) >= 1)
491
      self.assertTrue(_IsErrorInList(("%s has invalid ipolicy/%s" %
492
                                      (ipowner, ispecpath)), errs))
493
      del ispec[INVALID_KEY]
494
      errs = cfg.VerifyConfig()
495
      self.assertFalse(errs)
496

    
497
      for par in constants.ISPECS_PARAMETERS:
498
        hasoldv = par in ispec
499
        if hasoldv:
500
          oldv = ispec[par]
501
        ispec[par] = "blah"
502
        errs = cfg.VerifyConfig()
503
        self.assertTrue(len(errs) >= 1)
504
        self.assertTrue(_IsErrorInList(("%s has invalid ipolicy/%s" %
505
                                        (ipowner, ispecpath)), errs))
506
        if hasoldv:
507
          ispec[par] = oldv
508
        else:
509
          del ispec[par]
510
        errs = cfg.VerifyConfig()
511
        self.assertFalse(errs)
512

    
513
    if constants.ISPECS_MINMAX in ipolicy:
514
      # Test partial minmax specs
515
      for minmax in ipolicy[constants.ISPECS_MINMAX]:
516
        for key in constants.ISPECS_MINMAX_KEYS:
517
          self.assertTrue(key in minmax)
518
          ispec = minmax[key]
519
          del minmax[key]
520
          errs = cfg.VerifyConfig()
521
          self.assertTrue(len(errs) >= 1)
522
          self.assertTrue(_IsErrorInList("Missing instance specification",
523
                                         errs))
524
          minmax[key] = ispec
525
          for par in constants.ISPECS_PARAMETERS:
526
            oldv = ispec[par]
527
            del ispec[par]
528
            errs = cfg.VerifyConfig()
529
            self.assertTrue(len(errs) >= 1)
530
            self.assertTrue(_IsErrorInList("Missing instance specs parameters",
531
                                           errs))
532
            ispec[par] = oldv
533
      errs = cfg.VerifyConfig()
534
      self.assertFalse(errs)
535

    
536
  def _TestVerifyConfigGroupIPolicy(self, groupinfo, cfg):
537
    old_ipolicy = groupinfo.ipolicy
538
    ipolicy = cfg.GetClusterInfo().SimpleFillIPolicy({})
539
    groupinfo.ipolicy = ipolicy
540
    # Test partial policies
541
    for key in constants.IPOLICY_ALL_KEYS:
542
      self.assertTrue(key in ipolicy)
543
      oldv = ipolicy[key]
544
      del ipolicy[key]
545
      errs = cfg.VerifyConfig()
546
      self.assertFalse(errs)
547
      ipolicy[key] = oldv
548
    groupinfo.ipolicy = old_ipolicy
549

    
550
  def _TestVerifyConfigClusterIPolicy(self, ipolicy, cfg):
551
    # Test partial policies
552
    for key in constants.IPOLICY_ALL_KEYS:
553
      self.assertTrue(key in ipolicy)
554
      oldv = ipolicy[key]
555
      del ipolicy[key]
556
      self.assertRaises(AssertionError, cfg.VerifyConfig)
557
      ipolicy[key] = oldv
558
    errs = cfg.VerifyConfig()
559
    self.assertFalse(errs)
560
    # Partial standard specs
561
    ispec = ipolicy[constants.ISPECS_STD]
562
    for par in constants.ISPECS_PARAMETERS:
563
      oldv = ispec[par]
564
      del ispec[par]
565
      errs = cfg.VerifyConfig()
566
      self.assertTrue(len(errs) >= 1)
567
      self.assertTrue(_IsErrorInList("Missing instance specs parameters",
568
                                     errs))
569
      ispec[par] = oldv
570
    errs = cfg.VerifyConfig()
571
    self.assertFalse(errs)
572

    
573
  def testVerifyConfig(self):
574
    cfg = self._get_object()
575

    
576
    errs = cfg.VerifyConfig()
577
    self.assertFalse(errs)
578

    
579
    node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
580
    key = list(constants.NDC_GLOBALS)[0]
581
    node.ndparams[key] = constants.NDC_DEFAULTS[key]
582
    errs = cfg.VerifyConfig()
583
    self.assertTrue(len(errs) >= 1)
584
    self.assertTrue(_IsErrorInList("has some global parameters set", errs))
585

    
586
    del node.ndparams[key]
587
    errs = cfg.VerifyConfig()
588
    self.assertFalse(errs)
589

    
590
    cluster = cfg.GetClusterInfo()
591
    nodegroup = cfg.GetNodeGroup(cfg.GetNodeGroupList()[0])
592
    self._TestVerifyConfigIPolicy(cluster.ipolicy, "cluster", cfg, False)
593
    self._TestVerifyConfigClusterIPolicy(cluster.ipolicy, cfg)
594
    self._TestVerifyConfigIPolicy(nodegroup.ipolicy, nodegroup.name, cfg, True)
595
    self._TestVerifyConfigGroupIPolicy(nodegroup, cfg)
596
    nodegroup.ipolicy = cluster.SimpleFillIPolicy(nodegroup.ipolicy)
597
    self._TestVerifyConfigIPolicy(nodegroup.ipolicy, nodegroup.name, cfg, True)
598

    
599
  # Tests for Ssconf helper functions
600
  def testUnlockedGetHvparamsString(self):
601
    hvparams = {"a": "A", "b": "B", "c": "C"}
602
    hvname = "myhv"
603
    cfg_writer = self._get_object()
604
    cfg_writer._config_data = mock.Mock()
605
    cfg_writer._config_data.cluster = mock.Mock()
606
    cfg_writer._config_data.cluster.hvparams = {hvname: hvparams}
607

    
608
    result = cfg_writer._UnlockedGetHvparamsString(hvname)
609

    
610
    self.assertTrue("a=A" in result)
611
    lines = [line for line in result.split('\n') if line != '']
612
    self.assertEqual(len(hvparams.keys()), len(lines))
613

    
614
  def testExtendByAllHvparamsStrings(self):
615
    all_hvparams = {constants.HT_XEN_PVM: "foo"}
616
    ssconf_values = {}
617
    cfg_writer = self._get_object()
618

    
619
    cfg_writer._ExtendByAllHvparamsStrings(ssconf_values, all_hvparams)
620

    
621
    expected_key = constants.SS_HVPARAMS_PREF + constants.HT_XEN_PVM
622
    self.assertTrue(expected_key in ssconf_values)
623

    
624

    
625
def _IsErrorInList(err_str, err_list):
626
  return any(map(lambda e: err_str in e, err_list))
627

    
628

    
629
class TestTRM(unittest.TestCase):
630
  EC_ID = 1
631

    
632
  def testEmpty(self):
633
    t = TemporaryReservationManager()
634
    t.Reserve(self.EC_ID, "a")
635
    self.assertFalse(t.Reserved(self.EC_ID))
636
    self.assertTrue(t.Reserved("a"))
637
    self.assertEqual(len(t.GetReserved()), 1)
638

    
639
  def testDuplicate(self):
640
    t = TemporaryReservationManager()
641
    t.Reserve(self.EC_ID, "a")
642
    self.assertRaises(errors.ReservationError, t.Reserve, 2, "a")
643
    t.DropECReservations(self.EC_ID)
644
    self.assertFalse(t.Reserved("a"))
645

    
646

    
647
class TestCheckInstanceDiskIvNames(unittest.TestCase):
648
  @staticmethod
649
  def _MakeDisks(names):
650
    return [objects.Disk(iv_name=name) for name in names]
651

    
652
  def testNoError(self):
653
    disks = self._MakeDisks(["disk/0", "disk/1"])
654
    self.assertEqual(config._CheckInstanceDiskIvNames(disks), [])
655
    instance._UpdateIvNames(0, disks)
656
    self.assertEqual(config._CheckInstanceDiskIvNames(disks), [])
657

    
658
  def testWrongNames(self):
659
    disks = self._MakeDisks(["disk/1", "disk/3", "disk/2"])
660
    self.assertEqual(config._CheckInstanceDiskIvNames(disks), [
661
      (0, "disk/0", "disk/1"),
662
      (1, "disk/1", "disk/3"),
663
      ])
664

    
665
    # Fix names
666
    instance._UpdateIvNames(0, disks)
667
    self.assertEqual(config._CheckInstanceDiskIvNames(disks), [])
668

    
669

    
670
if __name__ == "__main__":
671
  testutils.GanetiTestProgram()