4 # Copyright (C) 2006, 2007, 2010, 2011 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
43 from ganeti.config import TemporaryReservationManager
49 def _StubGetEntResolver():
50 return mocks.FakeGetentResolver()
53 class TestConfigRunner(unittest.TestCase):
54 """Testing case for HooksRunner"""
56 fd, self.cfg_file = tempfile.mkstemp()
58 self._init_cluster(self.cfg_file)
62 os.unlink(self.cfg_file)
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)
72 def _init_cluster(self, cfg):
73 """Initializes the cfg object"""
74 me = netutils.Hostname()
75 ip = constants.IP4_ADDRESS_LOCALHOST
77 cluster_config = objects.Cluster(
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],
89 master_ip="127.0.0.1",
90 master_netdev=constants.DEFAULT_BRIDGE,
91 cluster_name="cluster.local",
92 file_storage_dir="/tmp",
96 master_node_config = objects.Node(name=me.name,
100 master_candidate=True)
102 bootstrap.InitConfig(constants.CONFIG_VERSION,
103 cluster_config, master_node_config, self.cfg_file)
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())
113 """Test instantiate config object"""
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()))
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)
130 cl = cfg.GetClusterInfo()
131 # first pass, must not fail
133 # second pass, also must not fail (after the config has been written)
135 # but the fake_cl update should still fail
136 self.failUnlessRaises(errors.ConfigurationError, cfg.Update, fake_cl, None)
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,
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,
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,
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,
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
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: ''})
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)
199 def testGetNdParamsModifiedNode(self):
201 constants.ND_OOB_PROGRAM: "/bin/node-oob",
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)
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)
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)
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)
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)
239 self.assertRaises(errors.ConfigurationError,
240 cfg.AddNodeGroup, group, "my-job")
242 cfg.AddNodeGroup(group, "my-job", check_uuid=False) # Does not raise.
243 self.assertEqual(uuid, group.uuid)
245 def testAssignGroupNodes(self):
246 me = netutils.Hostname()
247 cfg = self._get_object()
250 grp1 = objects.NodeGroup(name="grp1", members=[],
251 uuid="2f2fadf7-2a70-4a23-9ab5-2568c252032c")
253 cfg.AddNodeGroup(grp1, "job")
255 grp2 = objects.NodeGroup(name="grp2", members=[],
256 uuid="798d0de3-680f-4a0e-b29a-0f54f693b3f1")
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]))
264 cluster_serial = cfg.GetClusterInfo().serial_no
265 cfg.AssignGroupNodes([])
269 node1 = objects.Node(name="node1", group=grp1.uuid, ndparams={})
271 node2 = objects.Node(name="node2", group=grp2.uuid, ndparams={})
273 cfg.AddNode(node1, "job")
274 cfg.AddNode(node2, "job")
276 self.assertEqual(set(cfg.GetNodeList()), set(["node1", "node2", me.name]))
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)
287 self.assertEqual(set(grp1.members), set(["node1"]))
288 self.assertEqual(set(grp2.members), set(["node2"]))
290 # Check invalid nodes and groups
291 self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
292 ("unknown.node.example.com", grp2.uuid),
294 self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
295 (node1.name, "unknown-uuid"),
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"]))
304 cfg.AssignGroupNodes([])
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),
314 self.assertEqual(node2.group, grp2.uuid)
316 self.assertEqual(set(grp1.members), set(["node1"]))
317 self.assertEqual(set(grp2.members), set(["node2"]))
319 # Assign node 2 to group 1
320 self.assertEqual(node2.group, grp2.uuid)
321 cfg.AssignGroupNodes([
322 (node2.name, grp1.uuid),
328 self.assertEqual(node2.group, grp1.uuid)
330 self.assertEqual(set(grp1.members), set(["node1", "node2"]))
331 self.assertFalse(grp2.members)
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),
346 self.assertEqual(node1.group, grp2.uuid)
347 self.assertEqual(node2.group, grp2.uuid)
349 self.assertFalse(grp1.members)
350 self.assertEqual(set(grp2.members), set(["node1", "node2"]))
353 orig_group = node2.group
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),
364 node2.group = orig_group
367 class TestTRM(unittest.TestCase):
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)
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"))
385 if __name__ == '__main__':
386 testutils.GanetiTestProgram()