Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (14.2 kB)

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

    
4
# Copyright (C) 2006, 2007, 2010, 2011, 2012 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 a 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

    
78
    cluster_config = objects.Cluster(
79
      serial_no=1,
80
      rsahostkeypub="",
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="127.0.0.1",
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", disks=[], nics=[],
109
                            disk_template=constants.DT_DISKLESS,
110
                            primary_node=self._get_object().GetMasterNode())
111
    return inst
112

    
113
  def testEmpty(self):
114
    """Test instantiate config object"""
115
    self._get_object()
116

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

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

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

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

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

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

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

    
177
  def testNICParameterSyntaxCheck(self):
178
    """Test the NIC's CheckParameterSyntax function"""
179
    mode = constants.NIC_MODE
180
    link = constants.NIC_LINK
181
    m_bridged = constants.NIC_MODE_BRIDGED
182
    m_routed = constants.NIC_MODE_ROUTED
183
    CheckSyntax = objects.NIC.CheckParameterSyntax
184

    
185
    CheckSyntax(constants.NICC_DEFAULTS)
186
    CheckSyntax({mode: m_bridged, link: "br1"})
187
    CheckSyntax({mode: m_routed, link: "default"})
188
    self.assertRaises(errors.ConfigurationError,
189
                      CheckSyntax, {mode: "000invalid", link: "any"})
190
    self.assertRaises(errors.ConfigurationError,
191
                      CheckSyntax, {mode: m_bridged, link: None})
192
    self.assertRaises(errors.ConfigurationError,
193
                      CheckSyntax, {mode: m_bridged, link: ""})
194

    
195
  def testGetNdParamsDefault(self):
196
    cfg = self._get_object()
197
    node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
198
    self.assertEqual(cfg.GetNdParams(node), constants.NDC_DEFAULTS)
199

    
200
  def testGetNdParamsModifiedNode(self):
201
    my_ndparams = {
202
        constants.ND_OOB_PROGRAM: "/bin/node-oob",
203
        constants.ND_SPINDLE_COUNT: 1,
204
        constants.ND_EXCLUSIVE_STORAGE: False,
205
        }
206

    
207
    cfg = self._get_object()
208
    node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
209
    node.ndparams = my_ndparams
210
    cfg.Update(node, None)
211
    self.assertEqual(cfg.GetNdParams(node), my_ndparams)
212

    
213
  def testGetNdParamsInheritance(self):
214
    node_ndparams = {
215
      constants.ND_OOB_PROGRAM: "/bin/node-oob",
216
      }
217
    group_ndparams = {
218
      constants.ND_SPINDLE_COUNT: 10,
219
      }
220
    expected_ndparams = {
221
      constants.ND_OOB_PROGRAM: "/bin/node-oob",
222
      constants.ND_SPINDLE_COUNT: 10,
223
      constants.ND_EXCLUSIVE_STORAGE:
224
        constants.NDC_DEFAULTS[constants.ND_EXCLUSIVE_STORAGE],
225
      }
226
    cfg = self._get_object()
227
    node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
228
    node.ndparams = node_ndparams
229
    cfg.Update(node, None)
230
    group = cfg.GetNodeGroup(node.group)
231
    group.ndparams = group_ndparams
232
    cfg.Update(group, None)
233
    self.assertEqual(cfg.GetNdParams(node), expected_ndparams)
234

    
235
  def testAddGroupFillsFieldsIfMissing(self):
236
    cfg = self._get_object()
237
    group = objects.NodeGroup(name="test", members=[])
238
    cfg.AddNodeGroup(group, "my-job")
239
    self.assert_(utils.UUID_RE.match(group.uuid))
240
    self.assertEqual(constants.ALLOC_POLICY_PREFERRED, group.alloc_policy)
241

    
242
  def testAddGroupPreservesFields(self):
243
    cfg = self._get_object()
244
    group = objects.NodeGroup(name="test", members=[],
245
                              alloc_policy=constants.ALLOC_POLICY_LAST_RESORT)
246
    cfg.AddNodeGroup(group, "my-job")
247
    self.assertEqual(constants.ALLOC_POLICY_LAST_RESORT, group.alloc_policy)
248

    
249
  def testAddGroupDoesNotPreserveFields(self):
250
    cfg = self._get_object()
251
    group = objects.NodeGroup(name="test", members=[],
252
                              serial_no=17, ctime=123, mtime=456)
253
    cfg.AddNodeGroup(group, "my-job")
254
    self.assertEqual(1, group.serial_no)
255
    self.assert_(group.ctime > 1200000000)
256
    self.assert_(group.mtime > 1200000000)
257

    
258
  def testAddGroupCanSkipUUIDCheck(self):
259
    cfg = self._get_object()
260
    uuid = cfg.GenerateUniqueID("my-job")
261
    group = objects.NodeGroup(name="test", members=[], uuid=uuid,
262
                              serial_no=17, ctime=123, mtime=456)
263

    
264
    self.assertRaises(errors.ConfigurationError,
265
                      cfg.AddNodeGroup, group, "my-job")
266

    
267
    cfg.AddNodeGroup(group, "my-job", check_uuid=False) # Does not raise.
268
    self.assertEqual(uuid, group.uuid)
269

    
270
  def testAssignGroupNodes(self):
271
    me = netutils.Hostname()
272
    cfg = self._get_object()
273

    
274
    # Create two groups
275
    grp1 = objects.NodeGroup(name="grp1", members=[],
276
                             uuid="2f2fadf7-2a70-4a23-9ab5-2568c252032c")
277
    grp1_serial = 1
278
    cfg.AddNodeGroup(grp1, "job")
279

    
280
    grp2 = objects.NodeGroup(name="grp2", members=[],
281
                             uuid="798d0de3-680f-4a0e-b29a-0f54f693b3f1")
282
    grp2_serial = 1
283
    cfg.AddNodeGroup(grp2, "job")
284
    self.assertEqual(set(map(operator.attrgetter("name"),
285
                             cfg.GetAllNodeGroupsInfo().values())),
286
                     set(["grp1", "grp2", constants.INITIAL_NODE_GROUP_NAME]))
287

    
288
    # No-op
289
    cluster_serial = cfg.GetClusterInfo().serial_no
290
    cfg.AssignGroupNodes([])
291
    cluster_serial += 1
292

    
293
    # Create two nodes
294
    node1 = objects.Node(name="node1", group=grp1.uuid, ndparams={})
295
    node1_serial = 1
296
    node2 = objects.Node(name="node2", group=grp2.uuid, ndparams={})
297
    node2_serial = 1
298
    cfg.AddNode(node1, "job")
299
    cfg.AddNode(node2, "job")
300
    cluster_serial += 2
301
    self.assertEqual(set(cfg.GetNodeList()), set(["node1", "node2", me.name]))
302

    
303
    def _VerifySerials():
304
      self.assertEqual(cfg.GetClusterInfo().serial_no, cluster_serial)
305
      self.assertEqual(node1.serial_no, node1_serial)
306
      self.assertEqual(node2.serial_no, node2_serial)
307
      self.assertEqual(grp1.serial_no, grp1_serial)
308
      self.assertEqual(grp2.serial_no, grp2_serial)
309

    
310
    _VerifySerials()
311

    
312
    self.assertEqual(set(grp1.members), set(["node1"]))
313
    self.assertEqual(set(grp2.members), set(["node2"]))
314

    
315
    # Check invalid nodes and groups
316
    self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
317
      ("unknown.node.example.com", grp2.uuid),
318
      ])
319
    self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
320
      (node1.name, "unknown-uuid"),
321
      ])
322

    
323
    self.assertEqual(node1.group, grp1.uuid)
324
    self.assertEqual(node2.group, grp2.uuid)
325
    self.assertEqual(set(grp1.members), set(["node1"]))
326
    self.assertEqual(set(grp2.members), set(["node2"]))
327

    
328
    # Another no-op
329
    cfg.AssignGroupNodes([])
330
    cluster_serial += 1
331
    _VerifySerials()
332

    
333
    # Assign to the same group (should be a no-op)
334
    self.assertEqual(node2.group, grp2.uuid)
335
    cfg.AssignGroupNodes([
336
      (node2.name, grp2.uuid),
337
      ])
338
    cluster_serial += 1
339
    self.assertEqual(node2.group, grp2.uuid)
340
    _VerifySerials()
341
    self.assertEqual(set(grp1.members), set(["node1"]))
342
    self.assertEqual(set(grp2.members), set(["node2"]))
343

    
344
    # Assign node 2 to group 1
345
    self.assertEqual(node2.group, grp2.uuid)
346
    cfg.AssignGroupNodes([
347
      (node2.name, grp1.uuid),
348
      ])
349
    cluster_serial += 1
350
    node2_serial += 1
351
    grp1_serial += 1
352
    grp2_serial += 1
353
    self.assertEqual(node2.group, grp1.uuid)
354
    _VerifySerials()
355
    self.assertEqual(set(grp1.members), set(["node1", "node2"]))
356
    self.assertFalse(grp2.members)
357

    
358
    # And assign both nodes to group 2
359
    self.assertEqual(node1.group, grp1.uuid)
360
    self.assertEqual(node2.group, grp1.uuid)
361
    self.assertNotEqual(grp1.uuid, grp2.uuid)
362
    cfg.AssignGroupNodes([
363
      (node1.name, grp2.uuid),
364
      (node2.name, grp2.uuid),
365
      ])
366
    cluster_serial += 1
367
    node1_serial += 1
368
    node2_serial += 1
369
    grp1_serial += 1
370
    grp2_serial += 1
371
    self.assertEqual(node1.group, grp2.uuid)
372
    self.assertEqual(node2.group, grp2.uuid)
373
    _VerifySerials()
374
    self.assertFalse(grp1.members)
375
    self.assertEqual(set(grp2.members), set(["node1", "node2"]))
376

    
377
    # Destructive tests
378
    orig_group = node2.group
379
    try:
380
      other_uuid = "68b3d087-6ea5-491c-b81f-0a47d90228c5"
381
      assert compat.all(node.group != other_uuid
382
                        for node in cfg.GetAllNodesInfo().values())
383
      node2.group = "68b3d087-6ea5-491c-b81f-0a47d90228c5"
384
      self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
385
        ("node2", grp2.uuid),
386
        ])
387
      _VerifySerials()
388
    finally:
389
      node2.group = orig_group
390

    
391

    
392
class TestTRM(unittest.TestCase):
393
  EC_ID = 1
394

    
395
  def testEmpty(self):
396
    t = TemporaryReservationManager()
397
    t.Reserve(self.EC_ID, "a")
398
    self.assertFalse(t.Reserved(self.EC_ID))
399
    self.assertTrue(t.Reserved("a"))
400
    self.assertEqual(len(t.GetReserved()), 1)
401

    
402
  def testDuplicate(self):
403
    t = TemporaryReservationManager()
404
    t.Reserve(self.EC_ID, "a")
405
    self.assertRaises(errors.ReservationError, t.Reserve, 2, "a")
406
    t.DropECReservations(self.EC_ID)
407
    self.assertFalse(t.Reserved("a"))
408

    
409

    
410
class TestCheckInstanceDiskIvNames(unittest.TestCase):
411
  @staticmethod
412
  def _MakeDisks(names):
413
    return [objects.Disk(iv_name=name) for name in names]
414

    
415
  def testNoError(self):
416
    disks = self._MakeDisks(["disk/0", "disk/1"])
417
    self.assertEqual(config._CheckInstanceDiskIvNames(disks), [])
418
    cmdlib._UpdateIvNames(0, disks)
419
    self.assertEqual(config._CheckInstanceDiskIvNames(disks), [])
420

    
421
  def testWrongNames(self):
422
    disks = self._MakeDisks(["disk/1", "disk/3", "disk/2"])
423
    self.assertEqual(config._CheckInstanceDiskIvNames(disks), [
424
      (0, "disk/0", "disk/1"),
425
      (1, "disk/1", "disk/3"),
426
      ])
427

    
428
    # Fix names
429
    cmdlib._UpdateIvNames(0, disks)
430
    self.assertEqual(config._CheckInstanceDiskIvNames(disks), [])
431

    
432

    
433
if __name__ == "__main__":
434
  testutils.GanetiTestProgram()