Statistics
| Branch: | Tag: | Revision:

root / test / py / ganeti.config_unittest.py @ 5470b894

History | View | Annotate | Download (24.3 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 import serializer
39
from ganeti.cmdlib import instance
40

    
41
from ganeti.config import TemporaryReservationManager
42

    
43
import testutils
44
import mocks
45
import mock
46

    
47

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

    
51

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

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

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

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

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

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

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

    
107
  def _create_instance(self, cfg):
108
    """Create and return an instance object"""
109
    inst = objects.Instance(name="test.example.com",
110
                            uuid="test-uuid",
111
                            disks=[], nics=[],
112
                            disk_template=constants.DT_DISKLESS,
113
                            primary_node=cfg.GetMasterNode(),
114
                            osparams_private=serializer.PrivateDict())
115
    return inst
116

    
117
  def testEmpty(self):
118
    """Test instantiate config object"""
119
    self._get_object()
120

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
242
  def testGetNdParamsModifiedNode(self):
243
    my_ndparams = {
244
        constants.ND_OOB_PROGRAM: "/bin/node-oob",
245
        constants.ND_SPINDLE_COUNT: 1,
246
        constants.ND_EXCLUSIVE_STORAGE: False,
247
        constants.ND_OVS: True,
248
        constants.ND_OVS_NAME: "openvswitch",
249
        constants.ND_OVS_LINK: "eth1",
250
        constants.ND_SSH_PORT: 22,
251
        }
252

    
253
    cfg = self._get_object()
254
    node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
255
    node.ndparams = my_ndparams
256
    cfg.Update(node, None)
257
    self.assertEqual(cfg.GetNdParams(node), my_ndparams)
258

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

    
289
  def testAddGroupFillsFieldsIfMissing(self):
290
    cfg = self._get_object()
291
    group = objects.NodeGroup(name="test", members=[])
292
    cfg.AddNodeGroup(group, "my-job")
293
    self.assert_(utils.UUID_RE.match(group.uuid))
294
    self.assertEqual(constants.ALLOC_POLICY_PREFERRED, group.alloc_policy)
295

    
296
  def testAddGroupPreservesFields(self):
297
    cfg = self._get_object()
298
    group = objects.NodeGroup(name="test", members=[],
299
                              alloc_policy=constants.ALLOC_POLICY_LAST_RESORT)
300
    cfg.AddNodeGroup(group, "my-job")
301
    self.assertEqual(constants.ALLOC_POLICY_LAST_RESORT, group.alloc_policy)
302

    
303
  def testAddGroupDoesNotPreserveFields(self):
304
    cfg = self._get_object()
305
    group = objects.NodeGroup(name="test", members=[],
306
                              serial_no=17, ctime=123, mtime=456)
307
    cfg.AddNodeGroup(group, "my-job")
308
    self.assertEqual(1, group.serial_no)
309
    self.assert_(group.ctime > 1200000000)
310
    self.assert_(group.mtime > 1200000000)
311

    
312
  def testAddGroupCanSkipUUIDCheck(self):
313
    cfg = self._get_object()
314
    uuid = cfg.GenerateUniqueID("my-job")
315
    group = objects.NodeGroup(name="test", members=[], uuid=uuid,
316
                              serial_no=17, ctime=123, mtime=456)
317

    
318
    self.assertRaises(errors.ConfigurationError,
319
                      cfg.AddNodeGroup, group, "my-job")
320

    
321
    cfg.AddNodeGroup(group, "my-job", check_uuid=False) # Does not raise.
322
    self.assertEqual(uuid, group.uuid)
323

    
324
  def testAssignGroupNodes(self):
325
    me = netutils.Hostname()
326
    cfg = self._get_object()
327

    
328
    # Create two groups
329
    grp1 = objects.NodeGroup(name="grp1", members=[],
330
                             uuid="2f2fadf7-2a70-4a23-9ab5-2568c252032c")
331
    grp1_serial = 1
332
    cfg.AddNodeGroup(grp1, "job")
333

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

    
342
    # No-op
343
    cluster_serial = cfg.GetClusterInfo().serial_no
344
    cfg.AssignGroupNodes([])
345
    cluster_serial += 1
346

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

    
361
    def _VerifySerials():
362
      self.assertEqual(cfg.GetClusterInfo().serial_no, cluster_serial)
363
      self.assertEqual(node1.serial_no, node1_serial)
364
      self.assertEqual(node2.serial_no, node2_serial)
365
      self.assertEqual(grp1.serial_no, grp1_serial)
366
      self.assertEqual(grp2.serial_no, grp2_serial)
367

    
368
    _VerifySerials()
369

    
370
    self.assertEqual(set(grp1.members), set(["node1-uuid"]))
371
    self.assertEqual(set(grp2.members), set(["node2-uuid"]))
372

    
373
    # Check invalid nodes and groups
374
    self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
375
      ("unknown.node.example.com", grp2.uuid),
376
      ])
377
    self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
378
      (node1.name, "unknown-uuid"),
379
      ])
380

    
381
    self.assertEqual(node1.group, grp1.uuid)
382
    self.assertEqual(node2.group, grp2.uuid)
383
    self.assertEqual(set(grp1.members), set(["node1-uuid"]))
384
    self.assertEqual(set(grp2.members), set(["node2-uuid"]))
385

    
386
    # Another no-op
387
    cfg.AssignGroupNodes([])
388
    cluster_serial += 1
389
    _VerifySerials()
390

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

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

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

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

    
449
  def _TestVerifyConfigIPolicy(self, ipolicy, ipowner, cfg, isgroup):
450
    INVALID_KEY = "this_key_cannot_exist"
451

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

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

    
480
    ispeclist = []
481
    if constants.ISPECS_MINMAX in ipolicy:
482
      for k in range(len(ipolicy[constants.ISPECS_MINMAX])):
483
        ispeclist.extend([
484
            (ipolicy[constants.ISPECS_MINMAX][k][constants.ISPECS_MIN],
485
             "%s[%s]/%s" % (constants.ISPECS_MINMAX, k, constants.ISPECS_MIN)),
486
            (ipolicy[constants.ISPECS_MINMAX][k][constants.ISPECS_MAX],
487
             "%s[%s]/%s" % (constants.ISPECS_MINMAX, k, constants.ISPECS_MAX)),
488
            ])
489
    if constants.ISPECS_STD in ipolicy:
490
      ispeclist.append((ipolicy[constants.ISPECS_STD], constants.ISPECS_STD))
491

    
492
    for (ispec, ispecpath) in ispeclist:
493
      ispec[INVALID_KEY] = None
494
      errs = cfg.VerifyConfig()
495
      self.assertTrue(len(errs) >= 1)
496
      self.assertTrue(_IsErrorInList(("%s has invalid ipolicy/%s" %
497
                                      (ipowner, ispecpath)), errs))
498
      del ispec[INVALID_KEY]
499
      errs = cfg.VerifyConfig()
500
      self.assertFalse(errs)
501

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

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

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

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

    
578
  def testVerifyConfig(self):
579
    cfg = self._get_object()
580

    
581
    errs = cfg.VerifyConfig()
582
    self.assertFalse(errs)
583

    
584
    node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
585
    key = list(constants.NDC_GLOBALS)[0]
586
    node.ndparams[key] = constants.NDC_DEFAULTS[key]
587
    errs = cfg.VerifyConfig()
588
    self.assertTrue(len(errs) >= 1)
589
    self.assertTrue(_IsErrorInList("has some global parameters set", errs))
590

    
591
    del node.ndparams[key]
592
    errs = cfg.VerifyConfig()
593
    self.assertFalse(errs)
594

    
595
    cluster = cfg.GetClusterInfo()
596
    nodegroup = cfg.GetNodeGroup(cfg.GetNodeGroupList()[0])
597
    self._TestVerifyConfigIPolicy(cluster.ipolicy, "cluster", cfg, False)
598
    self._TestVerifyConfigClusterIPolicy(cluster.ipolicy, cfg)
599
    self._TestVerifyConfigIPolicy(nodegroup.ipolicy, nodegroup.name, cfg, True)
600
    self._TestVerifyConfigGroupIPolicy(nodegroup, cfg)
601
    nodegroup.ipolicy = cluster.SimpleFillIPolicy(nodegroup.ipolicy)
602
    self._TestVerifyConfigIPolicy(nodegroup.ipolicy, nodegroup.name, cfg, True)
603

    
604
  # Tests for Ssconf helper functions
605
  def testUnlockedGetHvparamsString(self):
606
    hvparams = {"a": "A", "b": "B", "c": "C"}
607
    hvname = "myhv"
608
    cfg_writer = self._get_object()
609
    cfg_writer._config_data = mock.Mock()
610
    cfg_writer._config_data.cluster = mock.Mock()
611
    cfg_writer._config_data.cluster.hvparams = {hvname: hvparams}
612

    
613
    result = cfg_writer._UnlockedGetHvparamsString(hvname)
614

    
615
    self.assertTrue("a=A" in result)
616
    lines = [line for line in result.split('\n') if line != '']
617
    self.assertEqual(len(hvparams.keys()), len(lines))
618

    
619
  def testExtendByAllHvparamsStrings(self):
620
    all_hvparams = {constants.HT_XEN_PVM: "foo"}
621
    ssconf_values = {}
622
    cfg_writer = self._get_object()
623

    
624
    cfg_writer._ExtendByAllHvparamsStrings(ssconf_values, all_hvparams)
625

    
626
    expected_key = constants.SS_HVPARAMS_PREF + constants.HT_XEN_PVM
627
    self.assertTrue(expected_key in ssconf_values)
628

    
629
  def testAddAndRemoveCerts(self):
630
    cfg = self._get_object()
631
    self.assertEqual(0, len(cfg.GetCandidateCerts()))
632

    
633
    node_uuid = "1234"
634
    cert_digest = "foobar"
635
    cfg.AddNodeToCandidateCerts(node_uuid, cert_digest,
636
                                warn_fn=None, info_fn=None)
637
    self.assertEqual(1, len(cfg.GetCandidateCerts()))
638

    
639
    # Try adding the same cert again
640
    cfg.AddNodeToCandidateCerts(node_uuid, cert_digest,
641
                                warn_fn=None, info_fn=None)
642
    self.assertEqual(1, len(cfg.GetCandidateCerts()))
643
    self.assertTrue(cfg.GetCandidateCerts()[node_uuid] == cert_digest)
644

    
645
    # Overriding cert
646
    other_digest = "barfoo"
647
    cfg.AddNodeToCandidateCerts(node_uuid, other_digest,
648
                                warn_fn=None, info_fn=None)
649
    self.assertEqual(1, len(cfg.GetCandidateCerts()))
650
    self.assertTrue(cfg.GetCandidateCerts()[node_uuid] == other_digest)
651

    
652
    # Try removing a certificate from a node that is not in the list
653
    other_node_uuid = "5678"
654
    cfg.RemoveNodeFromCandidateCerts(other_node_uuid, warn_fn=None)
655
    self.assertEqual(1, len(cfg.GetCandidateCerts()))
656

    
657
    # Remove a certificate from a node that is in the list
658
    cfg.RemoveNodeFromCandidateCerts(node_uuid, warn_fn=None)
659
    self.assertEqual(0, len(cfg.GetCandidateCerts()))
660

    
661

    
662
def _IsErrorInList(err_str, err_list):
663
  return any(map(lambda e: err_str in e, err_list))
664

    
665

    
666
class TestTRM(unittest.TestCase):
667
  EC_ID = 1
668

    
669
  def testEmpty(self):
670
    t = TemporaryReservationManager()
671
    t.Reserve(self.EC_ID, "a")
672
    self.assertFalse(t.Reserved(self.EC_ID))
673
    self.assertTrue(t.Reserved("a"))
674
    self.assertEqual(len(t.GetReserved()), 1)
675

    
676
  def testDuplicate(self):
677
    t = TemporaryReservationManager()
678
    t.Reserve(self.EC_ID, "a")
679
    self.assertRaises(errors.ReservationError, t.Reserve, 2, "a")
680
    t.DropECReservations(self.EC_ID)
681
    self.assertFalse(t.Reserved("a"))
682

    
683

    
684
class TestCheckInstanceDiskIvNames(unittest.TestCase):
685
  @staticmethod
686
  def _MakeDisks(names):
687
    return [objects.Disk(iv_name=name) for name in names]
688

    
689
  def testNoError(self):
690
    disks = self._MakeDisks(["disk/0", "disk/1"])
691
    self.assertEqual(config._CheckInstanceDiskIvNames(disks), [])
692
    instance._UpdateIvNames(0, disks)
693
    self.assertEqual(config._CheckInstanceDiskIvNames(disks), [])
694

    
695
  def testWrongNames(self):
696
    disks = self._MakeDisks(["disk/1", "disk/3", "disk/2"])
697
    self.assertEqual(config._CheckInstanceDiskIvNames(disks), [
698
      (0, "disk/0", "disk/1"),
699
      (1, "disk/1", "disk/3"),
700
      ])
701

    
702
    # Fix names
703
    instance._UpdateIvNames(0, disks)
704
    self.assertEqual(config._CheckInstanceDiskIvNames(disks), [])
705

    
706

    
707
if __name__ == "__main__":
708
  testutils.GanetiTestProgram()