Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.config_unittest.py @ 218f4c3d

History | View | Annotate | Download (12.7 kB)

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

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

    
43
from ganeti.config import TemporaryReservationManager
44

    
45
import testutils
46
import mocks
47

    
48

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

    
52

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

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

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

    
72
  def _init_cluster(self, cfg):
73
    """Initializes the cfg object"""
74
    me = netutils.Hostname()
75
    ip = constants.IP4_ADDRESS_LOCALHOST
76

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
199
  def testGetNdParamsModifiedNode(self):
200
    my_ndparams = {
201
        constants.ND_OOB_PROGRAM: "/bin/node-oob",
202
        }
203

    
204
    cfg = self._get_object()
205
    node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
206
    node.ndparams = my_ndparams
207
    cfg.Update(node, None)
208
    self.assertEqual(cfg.GetNdParams(node), my_ndparams)
209

    
210
  def testAddGroupFillsFieldsIfMissing(self):
211
    cfg = self._get_object()
212
    group = objects.NodeGroup(name="test", members=[])
213
    cfg.AddNodeGroup(group, "my-job")
214
    self.assert_(utils.UUID_RE.match(group.uuid))
215
    self.assertEqual(constants.ALLOC_POLICY_PREFERRED, group.alloc_policy)
216

    
217
  def testAddGroupPreservesFields(self):
218
    cfg = self._get_object()
219
    group = objects.NodeGroup(name="test", members=[],
220
                              alloc_policy=constants.ALLOC_POLICY_LAST_RESORT)
221
    cfg.AddNodeGroup(group, "my-job")
222
    self.assertEqual(constants.ALLOC_POLICY_LAST_RESORT, group.alloc_policy)
223

    
224
  def testAddGroupDoesNotPreserveFields(self):
225
    cfg = self._get_object()
226
    group = objects.NodeGroup(name="test", members=[],
227
                              serial_no=17, ctime=123, mtime=456)
228
    cfg.AddNodeGroup(group, "my-job")
229
    self.assertEqual(1, group.serial_no)
230
    self.assert_(group.ctime > 1200000000)
231
    self.assert_(group.mtime > 1200000000)
232

    
233
  def testAddGroupCanSkipUUIDCheck(self):
234
    cfg = self._get_object()
235
    uuid = cfg.GenerateUniqueID("my-job")
236
    group = objects.NodeGroup(name="test", members=[], uuid=uuid,
237
                              serial_no=17, ctime=123, mtime=456)
238

    
239
    self.assertRaises(errors.ConfigurationError,
240
                      cfg.AddNodeGroup, group, "my-job")
241

    
242
    cfg.AddNodeGroup(group, "my-job", check_uuid=False) # Does not raise.
243
    self.assertEqual(uuid, group.uuid)
244

    
245
  def testAssignGroupNodes(self):
246
    me = netutils.Hostname()
247
    cfg = self._get_object()
248

    
249
    # Create two groups
250
    grp1 = objects.NodeGroup(name="grp1", members=[],
251
                             uuid="2f2fadf7-2a70-4a23-9ab5-2568c252032c")
252
    grp1_serial = 1
253
    cfg.AddNodeGroup(grp1, "job")
254

    
255
    grp2 = objects.NodeGroup(name="grp2", members=[],
256
                             uuid="798d0de3-680f-4a0e-b29a-0f54f693b3f1")
257
    grp2_serial = 1
258
    cfg.AddNodeGroup(grp2, "job")
259
    self.assertEqual(set(map(operator.attrgetter("name"),
260
                             cfg.GetAllNodeGroupsInfo().values())),
261
                     set(["grp1", "grp2", constants.INITIAL_NODE_GROUP_NAME]))
262

    
263
    # No-op
264
    cluster_serial = cfg.GetClusterInfo().serial_no
265
    cfg.AssignGroupNodes([])
266
    cluster_serial += 1
267

    
268
    # Create two nodes
269
    node1 = objects.Node(name="node1", group=grp1.uuid, ndparams={})
270
    node1_serial = 1
271
    node2 = objects.Node(name="node2", group=grp2.uuid, ndparams={})
272
    node2_serial = 1
273
    cfg.AddNode(node1, "job")
274
    cfg.AddNode(node2, "job")
275
    cluster_serial += 2
276
    self.assertEqual(set(cfg.GetNodeList()), set(["node1", "node2", me.name]))
277

    
278
    def _VerifySerials():
279
      self.assertEqual(cfg.GetClusterInfo().serial_no, cluster_serial)
280
      self.assertEqual(node1.serial_no, node1_serial)
281
      self.assertEqual(node2.serial_no, node2_serial)
282
      self.assertEqual(grp1.serial_no, grp1_serial)
283
      self.assertEqual(grp2.serial_no, grp2_serial)
284

    
285
    _VerifySerials()
286

    
287
    self.assertEqual(set(grp1.members), set(["node1"]))
288
    self.assertEqual(set(grp2.members), set(["node2"]))
289

    
290
    # Check invalid nodes and groups
291
    self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
292
      ("unknown.node.example.com", grp2.uuid),
293
      ])
294
    self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
295
      (node1.name, "unknown-uuid"),
296
      ])
297

    
298
    self.assertEqual(node1.group, grp1.uuid)
299
    self.assertEqual(node2.group, grp2.uuid)
300
    self.assertEqual(set(grp1.members), set(["node1"]))
301
    self.assertEqual(set(grp2.members), set(["node2"]))
302

    
303
    # Another no-op
304
    cfg.AssignGroupNodes([])
305
    cluster_serial += 1
306
    _VerifySerials()
307

    
308
    # Assign to the same group (should be a no-op)
309
    self.assertEqual(node2.group, grp2.uuid)
310
    cfg.AssignGroupNodes([
311
      (node2.name, grp2.uuid),
312
      ])
313
    cluster_serial += 1
314
    self.assertEqual(node2.group, grp2.uuid)
315
    _VerifySerials()
316
    self.assertEqual(set(grp1.members), set(["node1"]))
317
    self.assertEqual(set(grp2.members), set(["node2"]))
318

    
319
    # Assign node 2 to group 1
320
    self.assertEqual(node2.group, grp2.uuid)
321
    cfg.AssignGroupNodes([
322
      (node2.name, grp1.uuid),
323
      ])
324
    cluster_serial += 1
325
    node2_serial += 1
326
    grp1_serial += 1
327
    grp2_serial += 1
328
    self.assertEqual(node2.group, grp1.uuid)
329
    _VerifySerials()
330
    self.assertEqual(set(grp1.members), set(["node1", "node2"]))
331
    self.assertFalse(grp2.members)
332

    
333
    # And assign both nodes to group 2
334
    self.assertEqual(node1.group, grp1.uuid)
335
    self.assertEqual(node2.group, grp1.uuid)
336
    self.assertNotEqual(grp1.uuid, grp2.uuid)
337
    cfg.AssignGroupNodes([
338
      (node1.name, grp2.uuid),
339
      (node2.name, grp2.uuid),
340
      ])
341
    cluster_serial += 1
342
    node1_serial += 1
343
    node2_serial += 1
344
    grp1_serial += 1
345
    grp2_serial += 1
346
    self.assertEqual(node1.group, grp2.uuid)
347
    self.assertEqual(node2.group, grp2.uuid)
348
    _VerifySerials()
349
    self.assertFalse(grp1.members)
350
    self.assertEqual(set(grp2.members), set(["node1", "node2"]))
351

    
352
    # Destructive tests
353
    orig_group = node2.group
354
    try:
355
      other_uuid = "68b3d087-6ea5-491c-b81f-0a47d90228c5"
356
      assert compat.all(node.group != other_uuid
357
                        for node in cfg.GetAllNodesInfo().values())
358
      node2.group = "68b3d087-6ea5-491c-b81f-0a47d90228c5"
359
      self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
360
        ("node2", grp2.uuid),
361
        ])
362
      _VerifySerials()
363
    finally:
364
      node2.group = orig_group
365

    
366

    
367
class TestTRM(unittest.TestCase):
368
  EC_ID = 1
369

    
370
  def testEmpty(self):
371
    t = TemporaryReservationManager()
372
    t.Reserve(self.EC_ID, "a")
373
    self.assertFalse(t.Reserved(self.EC_ID))
374
    self.assertTrue(t.Reserved("a"))
375
    self.assertEqual(len(t.GetReserved()), 1)
376

    
377
  def testDuplicate(self):
378
    t = TemporaryReservationManager()
379
    t.Reserve(self.EC_ID, "a")
380
    self.assertRaises(errors.ReservationError, t.Reserve, 2, "a")
381
    t.DropECReservations(self.EC_ID)
382
    self.assertFalse(t.Reserved("a"))
383

    
384

    
385
if __name__ == '__main__':
386
  testutils.GanetiTestProgram()