Update the license statement
[ganeti-github.git] / test / py / ganeti.client.gnt_cluster_unittest.py
1 #!/usr/bin/python
2 #
3
4 # Copyright (C) 2011 Google Inc.
5 # All rights reserved.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions are
9 # met:
10 #
11 # 1. Redistributions of source code must retain the above copyright notice,
12 # this list of conditions and the following disclaimer.
13 #
14 # 2. Redistributions in binary form must reproduce the above copyright
15 # notice, this list of conditions and the following disclaimer in the
16 # documentation and/or other materials provided with the distribution.
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
19 # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30
31 """Script for testing ganeti.client.gnt_cluster"""
32
33 import unittest
34 import optparse
35
36 from ganeti import errors
37 from ganeti.client import gnt_cluster
38 from ganeti import utils
39 from ganeti import compat
40 from ganeti import constants
41
42 import mock
43 import testutils
44
45
46 class TestEpoUtilities(unittest.TestCase):
47 def setUp(self):
48 self.nodes2ip = dict(("node%s" % i, "192.0.2.%s" % i) for i in range(1, 10))
49 self.nodes = set(self.nodes2ip.keys())
50 self.ips2node = dict((v, k) for (k, v) in self.nodes2ip.items())
51
52 def _FakeAction(*args):
53 return True
54
55 def _FakePing(ip, port, live_port_needed=False):
56 self.assert_(live_port_needed)
57 self.assertEqual(port, 0)
58 return True
59
60 def _FakeSleep(secs):
61 self.assert_(secs >= 0 and secs <= 5)
62 return
63
64 def _NoopFeedback(self, text):
65 return
66
67 def testPingFnRemoveHostsUp(self):
68 seen = set()
69 def _FakeSeenPing(ip, *args, **kwargs):
70 node = self.ips2node[ip]
71 self.assertFalse(node in seen)
72 seen.add(node)
73 return True
74
75 helper = gnt_cluster._RunWhenNodesReachableHelper(self.nodes,
76 self._FakeAction,
77 self.nodes2ip, 0,
78 self._NoopFeedback,
79 _ping_fn=_FakeSeenPing,
80 _sleep_fn=self._FakeSleep)
81
82 nodes_len = len(self.nodes)
83 for (num, _) in enumerate(self.nodes):
84 helper.Wait(5)
85 if num < nodes_len - 1:
86 self.assertRaises(utils.RetryAgain, helper)
87 else:
88 helper()
89
90 self.assertEqual(seen, self.nodes)
91 self.assertFalse(helper.down)
92 self.assertEqual(helper.up, self.nodes)
93
94 def testActionReturnFalseSetsHelperFalse(self):
95 called = False
96 def _FalseAction(*args):
97 return called
98
99 helper = gnt_cluster._RunWhenNodesReachableHelper(self.nodes, _FalseAction,
100 self.nodes2ip, 0,
101 self._NoopFeedback,
102 _ping_fn=self._FakePing,
103 _sleep_fn=self._FakeSleep)
104 for _ in self.nodes:
105 try:
106 helper()
107 except utils.RetryAgain:
108 called = True
109
110 self.assertFalse(helper.success)
111
112 def testMaybeInstanceStartup(self):
113 instances_arg = []
114 def _FakeInstanceStart(opts, instances, start):
115 instances_arg.append(set(instances))
116 return None
117
118 inst_map = {
119 "inst1": set(["node1", "node2"]),
120 "inst2": set(["node1", "node3"]),
121 "inst3": set(["node2", "node1"]),
122 "inst4": set(["node2", "node1", "node3"]),
123 "inst5": set(["node4"]),
124 }
125
126 fn = _FakeInstanceStart
127 self.assert_(gnt_cluster._MaybeInstanceStartup(None, inst_map, set(),
128 _instance_start_fn=fn))
129 self.assertFalse(instances_arg)
130 result = gnt_cluster._MaybeInstanceStartup(None, inst_map, set(["node1"]),
131 _instance_start_fn=fn)
132 self.assert_(result)
133 self.assertFalse(instances_arg)
134 result = gnt_cluster._MaybeInstanceStartup(None, inst_map,
135 set(["node1", "node3"]),
136 _instance_start_fn=fn)
137 self.assert_(result is None)
138 self.assertEqual(instances_arg.pop(0), set(["inst2"]))
139 self.assertFalse("inst2" in inst_map)
140 result = gnt_cluster._MaybeInstanceStartup(None, inst_map,
141 set(["node1", "node3"]),
142 _instance_start_fn=fn)
143 self.assert_(result)
144 self.assertFalse(instances_arg)
145 result = gnt_cluster._MaybeInstanceStartup(None, inst_map,
146 set(["node1", "node3", "node2"]),
147 _instance_start_fn=fn)
148 self.assertEqual(instances_arg.pop(0), set(["inst1", "inst3", "inst4"]))
149 self.assert_(result is None)
150 result = gnt_cluster._MaybeInstanceStartup(None, inst_map,
151 set(["node1", "node3", "node2",
152 "node4"]),
153 _instance_start_fn=fn)
154 self.assert_(result is None)
155 self.assertEqual(instances_arg.pop(0), set(["inst5"]))
156 self.assertFalse(inst_map)
157
158
159 class _ClientForEpo:
160 def __init__(self, groups, nodes):
161 self._groups = groups
162 self._nodes = nodes
163
164 def QueryGroups(self, names, fields, use_locking):
165 assert not use_locking
166 assert fields == ["node_list"]
167 return self._groups
168
169 def QueryNodes(self, names, fields, use_locking):
170 assert not use_locking
171 assert fields == ["name", "master", "pinst_list", "sinst_list", "powered",
172 "offline"]
173 return self._nodes
174
175
176 class TestEpo(unittest.TestCase):
177 _ON_EXITCODE = 253
178 _OFF_EXITCODE = 254
179
180 def _ConfirmForce(self, *args):
181 self.fail("Shouldn't need confirmation")
182
183 def _Confirm(self, exp_names, result, names, ltype, text):
184 self.assertEqual(names, exp_names)
185 self.assertFalse(result is NotImplemented)
186 return result
187
188 def _Off(self, exp_node_list, opts, node_list, inst_map):
189 self.assertEqual(node_list, exp_node_list)
190 self.assertFalse(inst_map)
191 return self._OFF_EXITCODE
192
193 def _Test(self, *args, **kwargs):
194 defaults = dict(cl=NotImplemented, _on_fn=NotImplemented,
195 _off_fn=NotImplemented,
196 _stdout_fn=lambda *args: None,
197 _stderr_fn=lambda *args: None)
198 defaults.update(kwargs)
199 return gnt_cluster.Epo(*args, **defaults)
200
201 def testShowAllWithGroups(self):
202 opts = optparse.Values(dict(groups=True, show_all=True))
203 result = self._Test(opts, NotImplemented)
204 self.assertEqual(result, constants.EXIT_FAILURE)
205
206 def testShowAllWithArgs(self):
207 opts = optparse.Values(dict(groups=False, show_all=True))
208 result = self._Test(opts, ["a", "b", "c"])
209 self.assertEqual(result, constants.EXIT_FAILURE)
210
211 def testNoArgumentsNoParameters(self):
212 for (force, confirm_result) in [(True, NotImplemented), (False, False),
213 (False, True)]:
214 opts = optparse.Values(dict(groups=False, show_all=False, force=force,
215 on=False))
216 client = _ClientForEpo(NotImplemented, [
217 ("node1.example.com", False, [], [], True, False),
218 ])
219
220 if force:
221 confirm_fn = self._ConfirmForce
222 else:
223 confirm_fn = compat.partial(self._Confirm, ["node1.example.com"],
224 confirm_result)
225
226 off_fn = compat.partial(self._Off, ["node1.example.com"])
227
228 result = self._Test(opts, [], cl=client, _off_fn=off_fn,
229 _confirm_fn=confirm_fn)
230 if force or confirm_result:
231 self.assertEqual(result, self._OFF_EXITCODE)
232 else:
233 self.assertEqual(result, constants.EXIT_FAILURE)
234
235 def testPowerOn(self):
236 for master in [False, True]:
237 opts = optparse.Values(dict(groups=False, show_all=True,
238 force=True, on=True))
239 client = _ClientForEpo(NotImplemented, [
240 ("node1.example.com", False, [], [], True, False),
241 ("node2.example.com", False, [], [], False, False),
242 ("node3.example.com", False, [], [], True, True),
243 ("node4.example.com", False, [], [], None, True),
244 ("node5.example.com", master, [], [], False, False),
245 ])
246
247 def _On(_, all_nodes, node_list, inst_map):
248 self.assertEqual(all_nodes,
249 ["node%s.example.com" % i for i in range(1, 6)])
250 if master:
251 self.assertEqual(node_list, ["node2.example.com"])
252 else:
253 self.assertEqual(node_list, ["node2.example.com",
254 "node5.example.com"])
255 self.assertFalse(inst_map)
256 return self._ON_EXITCODE
257
258 result = self._Test(opts, [], cl=client, _on_fn=_On,
259 _confirm_fn=self._ConfirmForce)
260 self.assertEqual(result, self._ON_EXITCODE)
261
262 def testMasterWithoutShowAll(self):
263 opts = optparse.Values(dict(groups=False, show_all=False,
264 force=True, on=False))
265 client = _ClientForEpo(NotImplemented, [
266 ("node1.example.com", True, [], [], True, False),
267 ])
268 result = self._Test(opts, [], cl=client, _confirm_fn=self._ConfirmForce)
269 self.assertEqual(result, constants.EXIT_FAILURE)
270
271
272 class DrbdHelperTestCase(unittest.TestCase):
273
274 def setUp(self):
275 unittest.TestCase.setUp(self)
276 self.enabled_disk_templates = []
277
278 def enableDrbd(self):
279 self.enabled_disk_templates = [constants.DT_DRBD8]
280
281 def disableDrbd(self):
282 self.enabled_disk_templates = [constants.DT_DISKLESS]
283
284
285 class InitDrbdHelper(DrbdHelperTestCase):
286
287 def testNoDrbdNoHelper(self):
288 opts = mock.Mock()
289 opts.drbd_helper = None
290 self.disableDrbd()
291 helper = gnt_cluster._InitDrbdHelper(opts, self.enabled_disk_templates)
292 self.assertEquals(None, helper)
293
294 def testNoDrbdHelper(self):
295 opts = mock.Mock()
296 self.disableDrbd()
297 opts.drbd_helper = "/bin/true"
298 helper = gnt_cluster._InitDrbdHelper(opts, self.enabled_disk_templates)
299 self.assertEquals(opts.drbd_helper, helper)
300
301 def testDrbdHelperNone(self):
302 opts = mock.Mock()
303 self.enableDrbd()
304 opts.drbd_helper = None
305 helper = gnt_cluster._InitDrbdHelper(opts, self.enabled_disk_templates)
306 self.assertEquals(constants.DEFAULT_DRBD_HELPER, helper)
307
308 def testDrbdHelperEmpty(self):
309 opts = mock.Mock()
310 self.enableDrbd()
311 opts.drbd_helper = ''
312 self.assertRaises(errors.OpPrereqError, gnt_cluster._InitDrbdHelper, opts,
313 self.enabled_disk_templates)
314
315 def testDrbdHelper(self):
316 opts = mock.Mock()
317 self.enableDrbd()
318 opts.drbd_helper = "/bin/true"
319 helper = gnt_cluster._InitDrbdHelper(opts, self.enabled_disk_templates)
320 self.assertEquals(opts.drbd_helper, helper)
321
322
323 class GetDrbdHelper(DrbdHelperTestCase):
324
325 def testNoDrbdNoHelper(self):
326 opts = mock.Mock()
327 self.disableDrbd()
328 opts.drbd_helper = None
329 helper = gnt_cluster._GetDrbdHelper(opts, self.enabled_disk_templates)
330 self.assertEquals(None, helper)
331
332 def testNoTemplateInfoNoHelper(self):
333 opts = mock.Mock()
334 opts.drbd_helper = None
335 helper = gnt_cluster._GetDrbdHelper(opts, None)
336 self.assertEquals(None, helper)
337
338 def testNoTemplateInfoHelper(self):
339 opts = mock.Mock()
340 opts.drbd_helper = "/bin/true"
341 helper = gnt_cluster._GetDrbdHelper(opts, None)
342 self.assertEquals(opts.drbd_helper, helper)
343
344 def testNoDrbdHelper(self):
345 opts = mock.Mock()
346 self.disableDrbd()
347 opts.drbd_helper = "/bin/true"
348 helper = gnt_cluster._GetDrbdHelper(opts, None)
349 self.assertEquals(opts.drbd_helper, helper)
350
351 def testDrbdNoHelper(self):
352 opts = mock.Mock()
353 self.enableDrbd()
354 opts.drbd_helper = None
355 helper = gnt_cluster._GetDrbdHelper(opts, self.enabled_disk_templates)
356 self.assertEquals(None, helper)
357
358 def testDrbdHelper(self):
359 opts = mock.Mock()
360 self.enableDrbd()
361 opts.drbd_helper = "/bin/true"
362 helper = gnt_cluster._GetDrbdHelper(opts, self.enabled_disk_templates)
363 self.assertEquals(opts.drbd_helper, helper)
364
365
366 if __name__ == "__main__":
367 testutils.GanetiTestProgram()