Statistics
| Branch: | Tag: | Revision:

root / test / py / ganeti.config_unittest.py @ 6b06efa7

History | View | Annotate | Download (23 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
        constants.ND_SSH_PORT: 22,
249
        }
250

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

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

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

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

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

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

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

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

    
322
  def testAssignGroupNodes(self):
323
    me = netutils.Hostname()
324
    cfg = self._get_object()
325

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

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

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

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

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

    
366
    _VerifySerials()
367

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
576
  def testVerifyConfig(self):
577
    cfg = self._get_object()
578

    
579
    errs = cfg.VerifyConfig()
580
    self.assertFalse(errs)
581

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

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

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

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

    
611
    result = cfg_writer._UnlockedGetHvparamsString(hvname)
612

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

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

    
622
    cfg_writer._ExtendByAllHvparamsStrings(ssconf_values, all_hvparams)
623

    
624
    expected_key = constants.SS_HVPARAMS_PREF + constants.HT_XEN_PVM
625
    self.assertTrue(expected_key in ssconf_values)
626

    
627

    
628
def _IsErrorInList(err_str, err_list):
629
  return any(map(lambda e: err_str in e, err_list))
630

    
631

    
632
class TestTRM(unittest.TestCase):
633
  EC_ID = 1
634

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

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

    
649

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

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

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

    
668
    # Fix names
669
    instance._UpdateIvNames(0, disks)
670
    self.assertEqual(config._CheckInstanceDiskIvNames(disks), [])
671

    
672

    
673
if __name__ == "__main__":
674
  testutils.GanetiTestProgram()