4 # Copyright (C) 2006, 2007, 2010, 2011, 2012 Google Inc.
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.
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.
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
22 """Script for unittesting the config module"""
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
44 from ganeti.config import TemporaryReservationManager
50 def _StubGetEntResolver():
51 return mocks.FakeGetentResolver()
54 class TestConfigRunner(unittest.TestCase):
55 """Testing case for HooksRunner"""
57 fd, self.cfg_file = tempfile.mkstemp()
59 self._init_cluster(self.cfg_file)
63 os.unlink(self.cfg_file)
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)
73 def _init_cluster(self, cfg):
74 """Initializes the cfg object"""
75 me = netutils.Hostname()
76 ip = constants.IP4_ADDRESS_LOCALHOST
78 cluster_config = objects.Cluster(
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],
90 master_ip="127.0.0.1",
91 master_netdev=constants.DEFAULT_BRIDGE,
92 cluster_name="cluster.local",
93 file_storage_dir="/tmp",
97 master_node_config = objects.Node(name=me.name,
101 master_candidate=True)
103 bootstrap.InitConfig(constants.CONFIG_VERSION,
104 cluster_config, master_node_config, self.cfg_file)
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())
114 """Test instantiate config object"""
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()))
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)
131 cl = cfg.GetClusterInfo()
132 # first pass, must not fail
134 # second pass, also must not fail (after the config has been written)
136 # but the fake_cl update should still fail
137 self.failUnlessRaises(errors.ConfigurationError, cfg.Update, fake_cl, None)
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,
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,
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,
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,
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
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: ""})
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)
200 def testGetNdParamsModifiedNode(self):
202 constants.ND_OOB_PROGRAM: "/bin/node-oob",
203 constants.ND_SPINDLE_COUNT: 1,
204 constants.ND_EXCLUSIVE_STORAGE: False,
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)
213 def testGetNdParamsInheritance(self):
215 constants.ND_OOB_PROGRAM: "/bin/node-oob",
218 constants.ND_SPINDLE_COUNT: 10,
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],
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)
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)
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)
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)
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)
264 self.assertRaises(errors.ConfigurationError,
265 cfg.AddNodeGroup, group, "my-job")
267 cfg.AddNodeGroup(group, "my-job", check_uuid=False) # Does not raise.
268 self.assertEqual(uuid, group.uuid)
270 def testAssignGroupNodes(self):
271 me = netutils.Hostname()
272 cfg = self._get_object()
275 grp1 = objects.NodeGroup(name="grp1", members=[],
276 uuid="2f2fadf7-2a70-4a23-9ab5-2568c252032c")
278 cfg.AddNodeGroup(grp1, "job")
280 grp2 = objects.NodeGroup(name="grp2", members=[],
281 uuid="798d0de3-680f-4a0e-b29a-0f54f693b3f1")
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]))
289 cluster_serial = cfg.GetClusterInfo().serial_no
290 cfg.AssignGroupNodes([])
294 node1 = objects.Node(name="node1", group=grp1.uuid, ndparams={})
296 node2 = objects.Node(name="node2", group=grp2.uuid, ndparams={})
298 cfg.AddNode(node1, "job")
299 cfg.AddNode(node2, "job")
301 self.assertEqual(set(cfg.GetNodeList()), set(["node1", "node2", me.name]))
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)
312 self.assertEqual(set(grp1.members), set(["node1"]))
313 self.assertEqual(set(grp2.members), set(["node2"]))
315 # Check invalid nodes and groups
316 self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
317 ("unknown.node.example.com", grp2.uuid),
319 self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
320 (node1.name, "unknown-uuid"),
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"]))
329 cfg.AssignGroupNodes([])
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),
339 self.assertEqual(node2.group, grp2.uuid)
341 self.assertEqual(set(grp1.members), set(["node1"]))
342 self.assertEqual(set(grp2.members), set(["node2"]))
344 # Assign node 2 to group 1
345 self.assertEqual(node2.group, grp2.uuid)
346 cfg.AssignGroupNodes([
347 (node2.name, grp1.uuid),
353 self.assertEqual(node2.group, grp1.uuid)
355 self.assertEqual(set(grp1.members), set(["node1", "node2"]))
356 self.assertFalse(grp2.members)
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),
371 self.assertEqual(node1.group, grp2.uuid)
372 self.assertEqual(node2.group, grp2.uuid)
374 self.assertFalse(grp1.members)
375 self.assertEqual(set(grp2.members), set(["node1", "node2"]))
378 orig_group = node2.group
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),
389 node2.group = orig_group
392 class TestTRM(unittest.TestCase):
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)
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"))
410 class TestCheckInstanceDiskIvNames(unittest.TestCase):
412 def _MakeDisks(names):
413 return [objects.Disk(iv_name=name) for name in names]
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), [])
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"),
429 cmdlib._UpdateIvNames(0, disks)
430 self.assertEqual(config._CheckInstanceDiskIvNames(disks), [])
433 if __name__ == "__main__":
434 testutils.GanetiTestProgram()