Add reason parameter to RAPI client functions
[ganeti-github.git] / test / py / ganeti.rapi.client_unittest.py
1 #!/usr/bin/python
2 #
3
4 # Copyright (C) 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 RAPI client module"""
23
24
25 import unittest
26 import warnings
27 import pycurl
28
29 from ganeti import opcodes
30 from ganeti import constants
31 from ganeti import http
32 from ganeti import serializer
33 from ganeti import utils
34 from ganeti import query
35 from ganeti import objects
36 from ganeti import rapi
37 from ganeti import errors
38
39 import ganeti.rapi.testutils
40 from ganeti.rapi import connector
41 from ganeti.rapi import rlib2
42 from ganeti.rapi import client
43
44 import testutils
45
46
47 # List of resource handlers which aren't used by the RAPI client
48 _KNOWN_UNUSED = set([
49 rlib2.R_root,
50 rlib2.R_2,
51 ])
52
53 # Global variable for collecting used handlers
54 _used_handlers = None
55
56
57 class RapiMock(object):
58 def __init__(self):
59 self._mapper = connector.Mapper()
60 self._responses = []
61 self._last_handler = None
62 self._last_req_data = None
63
64 def ResetResponses(self):
65 del self._responses[:]
66
67 def AddResponse(self, response, code=200):
68 self._responses.insert(0, (code, response))
69
70 def CountPending(self):
71 return len(self._responses)
72
73 def GetLastHandler(self):
74 return self._last_handler
75
76 def GetLastRequestData(self):
77 return self._last_req_data
78
79 def FetchResponse(self, path, method, headers, request_body):
80 self._last_req_data = request_body
81
82 try:
83 (handler_cls, items, args) = self._mapper.getController(path)
84
85 # Record handler as used
86 _used_handlers.add(handler_cls)
87
88 self._last_handler = handler_cls(items, args, None)
89 if not hasattr(self._last_handler, method.upper()):
90 raise http.HttpNotImplemented(message="Method not implemented")
91
92 except http.HttpException, ex:
93 code = ex.code
94 response = ex.message
95 else:
96 if not self._responses:
97 raise Exception("No responses")
98
99 (code, response) = self._responses.pop()
100
101 return (code, NotImplemented, response)
102
103
104 class TestConstants(unittest.TestCase):
105 def test(self):
106 self.assertEqual(client.GANETI_RAPI_PORT, constants.DEFAULT_RAPI_PORT)
107 self.assertEqual(client.GANETI_RAPI_VERSION, constants.RAPI_VERSION)
108 self.assertEqual(client.HTTP_APP_JSON, http.HTTP_APP_JSON)
109 self.assertEqual(client._REQ_DATA_VERSION_FIELD, rlib2._REQ_DATA_VERSION)
110 self.assertEqual(client.JOB_STATUS_QUEUED, constants.JOB_STATUS_QUEUED)
111 self.assertEqual(client.JOB_STATUS_WAITING, constants.JOB_STATUS_WAITING)
112 self.assertEqual(client.JOB_STATUS_CANCELING,
113 constants.JOB_STATUS_CANCELING)
114 self.assertEqual(client.JOB_STATUS_RUNNING, constants.JOB_STATUS_RUNNING)
115 self.assertEqual(client.JOB_STATUS_CANCELED, constants.JOB_STATUS_CANCELED)
116 self.assertEqual(client.JOB_STATUS_SUCCESS, constants.JOB_STATUS_SUCCESS)
117 self.assertEqual(client.JOB_STATUS_ERROR, constants.JOB_STATUS_ERROR)
118 self.assertEqual(client.JOB_STATUS_PENDING, constants.JOBS_PENDING)
119 self.assertEqual(client.JOB_STATUS_FINALIZED, constants.JOBS_FINALIZED)
120 self.assertEqual(client.JOB_STATUS_ALL, constants.JOB_STATUS_ALL)
121
122 # Node evacuation
123 self.assertEqual(client.NODE_EVAC_PRI, constants.NODE_EVAC_PRI)
124 self.assertEqual(client.NODE_EVAC_SEC, constants.NODE_EVAC_SEC)
125 self.assertEqual(client.NODE_EVAC_ALL, constants.NODE_EVAC_ALL)
126
127 # Legacy name
128 self.assertEqual(client.JOB_STATUS_WAITLOCK, constants.JOB_STATUS_WAITING)
129
130 # RAPI feature strings
131 self.assertEqual(client._INST_CREATE_REQV1, rlib2._INST_CREATE_REQV1)
132 self.assertEqual(client.INST_CREATE_REQV1, rlib2._INST_CREATE_REQV1)
133 self.assertEqual(client._INST_REINSTALL_REQV1, rlib2._INST_REINSTALL_REQV1)
134 self.assertEqual(client.INST_REINSTALL_REQV1, rlib2._INST_REINSTALL_REQV1)
135 self.assertEqual(client._NODE_MIGRATE_REQV1, rlib2._NODE_MIGRATE_REQV1)
136 self.assertEqual(client.NODE_MIGRATE_REQV1, rlib2._NODE_MIGRATE_REQV1)
137 self.assertEqual(client._NODE_EVAC_RES1, rlib2._NODE_EVAC_RES1)
138 self.assertEqual(client.NODE_EVAC_RES1, rlib2._NODE_EVAC_RES1)
139
140 def testErrors(self):
141 self.assertEqual(client.ECODE_ALL, errors.ECODE_ALL)
142
143 # Make sure all error codes are in both RAPI client and errors module
144 for name in filter(lambda s: (s.startswith("ECODE_") and s != "ECODE_ALL"),
145 dir(client)):
146 value = getattr(client, name)
147 self.assertEqual(value, getattr(errors, name))
148 self.assertTrue(value in client.ECODE_ALL)
149 self.assertTrue(value in errors.ECODE_ALL)
150
151
152 class RapiMockTest(unittest.TestCase):
153 def test404(self):
154 (code, _, body) = RapiMock().FetchResponse("/foo", "GET", None, None)
155 self.assertEqual(code, 404)
156 self.assertTrue(body is None)
157
158 def test501(self):
159 (code, _, body) = RapiMock().FetchResponse("/version", "POST", None, None)
160 self.assertEqual(code, 501)
161 self.assertEqual(body, "Method not implemented")
162
163 def test200(self):
164 rapi = RapiMock()
165 rapi.AddResponse("2")
166 (code, _, response) = rapi.FetchResponse("/version", "GET", None, None)
167 self.assertEqual(200, code)
168 self.assertEqual("2", response)
169 self.failUnless(isinstance(rapi.GetLastHandler(), rlib2.R_version))
170
171
172 def _FakeNoSslPycurlVersion():
173 # Note: incomplete version tuple
174 return (3, "7.16.0", 462848, "mysystem", 1581, None, 0)
175
176
177 def _FakeFancySslPycurlVersion():
178 # Note: incomplete version tuple
179 return (3, "7.16.0", 462848, "mysystem", 1581, "FancySSL/1.2.3", 0)
180
181
182 def _FakeOpenSslPycurlVersion():
183 # Note: incomplete version tuple
184 return (2, "7.15.5", 462597, "othersystem", 668, "OpenSSL/0.9.8c", 0)
185
186
187 def _FakeGnuTlsPycurlVersion():
188 # Note: incomplete version tuple
189 return (3, "7.18.0", 463360, "somesystem", 1581, "GnuTLS/2.0.4", 0)
190
191
192 class TestExtendedConfig(unittest.TestCase):
193 def testAuth(self):
194 cl = client.GanetiRapiClient("master.example.com",
195 username="user", password="pw",
196 curl_factory=lambda: rapi.testutils.FakeCurl(RapiMock()))
197
198 curl = cl._CreateCurl()
199 self.assertEqual(curl.getopt(pycurl.HTTPAUTH), pycurl.HTTPAUTH_BASIC)
200 self.assertEqual(curl.getopt(pycurl.USERPWD), "user:pw")
201
202 def testInvalidAuth(self):
203 # No username
204 self.assertRaises(client.Error, client.GanetiRapiClient,
205 "master-a.example.com", password="pw")
206 # No password
207 self.assertRaises(client.Error, client.GanetiRapiClient,
208 "master-b.example.com", username="user")
209
210 def testCertVerifyInvalidCombinations(self):
211 self.assertRaises(client.Error, client.GenericCurlConfig,
212 use_curl_cabundle=True, cafile="cert1.pem")
213 self.assertRaises(client.Error, client.GenericCurlConfig,
214 use_curl_cabundle=True, capath="certs/")
215 self.assertRaises(client.Error, client.GenericCurlConfig,
216 use_curl_cabundle=True,
217 cafile="cert1.pem", capath="certs/")
218
219 def testProxySignalVerifyHostname(self):
220 for use_gnutls in [False, True]:
221 if use_gnutls:
222 pcverfn = _FakeGnuTlsPycurlVersion
223 else:
224 pcverfn = _FakeOpenSslPycurlVersion
225
226 for proxy in ["", "http://127.0.0.1:1234"]:
227 for use_signal in [False, True]:
228 for verify_hostname in [False, True]:
229 cfgfn = client.GenericCurlConfig(proxy=proxy, use_signal=use_signal,
230 verify_hostname=verify_hostname,
231 _pycurl_version_fn=pcverfn)
232
233 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
234 cl = client.GanetiRapiClient("master.example.com",
235 curl_config_fn=cfgfn,
236 curl_factory=curl_factory)
237
238 curl = cl._CreateCurl()
239 self.assertEqual(curl.getopt(pycurl.PROXY), proxy)
240 self.assertEqual(curl.getopt(pycurl.NOSIGNAL), not use_signal)
241
242 if verify_hostname:
243 self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 2)
244 else:
245 self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 0)
246
247 def testNoCertVerify(self):
248 cfgfn = client.GenericCurlConfig()
249
250 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
251 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
252 curl_factory=curl_factory)
253
254 curl = cl._CreateCurl()
255 self.assertFalse(curl.getopt(pycurl.SSL_VERIFYPEER))
256 self.assertFalse(curl.getopt(pycurl.CAINFO))
257 self.assertFalse(curl.getopt(pycurl.CAPATH))
258
259 def testCertVerifyCurlBundle(self):
260 cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
261
262 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
263 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
264 curl_factory=curl_factory)
265
266 curl = cl._CreateCurl()
267 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
268 self.assertFalse(curl.getopt(pycurl.CAINFO))
269 self.assertFalse(curl.getopt(pycurl.CAPATH))
270
271 def testCertVerifyCafile(self):
272 mycert = "/tmp/some/UNUSED/cert/file.pem"
273 cfgfn = client.GenericCurlConfig(cafile=mycert)
274
275 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
276 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
277 curl_factory=curl_factory)
278
279 curl = cl._CreateCurl()
280 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
281 self.assertEqual(curl.getopt(pycurl.CAINFO), mycert)
282 self.assertFalse(curl.getopt(pycurl.CAPATH))
283
284 def testCertVerifyCapath(self):
285 certdir = "/tmp/some/UNUSED/cert/directory"
286 pcverfn = _FakeOpenSslPycurlVersion
287 cfgfn = client.GenericCurlConfig(capath=certdir,
288 _pycurl_version_fn=pcverfn)
289
290 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
291 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
292 curl_factory=curl_factory)
293
294 curl = cl._CreateCurl()
295 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
296 self.assertEqual(curl.getopt(pycurl.CAPATH), certdir)
297 self.assertFalse(curl.getopt(pycurl.CAINFO))
298
299 def testCertVerifyCapathGnuTls(self):
300 certdir = "/tmp/some/UNUSED/cert/directory"
301 pcverfn = _FakeGnuTlsPycurlVersion
302 cfgfn = client.GenericCurlConfig(capath=certdir,
303 _pycurl_version_fn=pcverfn)
304
305 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
306 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
307 curl_factory=curl_factory)
308
309 self.assertRaises(client.Error, cl._CreateCurl)
310
311 def testCertVerifyNoSsl(self):
312 certdir = "/tmp/some/UNUSED/cert/directory"
313 pcverfn = _FakeNoSslPycurlVersion
314 cfgfn = client.GenericCurlConfig(capath=certdir,
315 _pycurl_version_fn=pcverfn)
316
317 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
318 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
319 curl_factory=curl_factory)
320
321 self.assertRaises(client.Error, cl._CreateCurl)
322
323 def testCertVerifyFancySsl(self):
324 certdir = "/tmp/some/UNUSED/cert/directory"
325 pcverfn = _FakeFancySslPycurlVersion
326 cfgfn = client.GenericCurlConfig(capath=certdir,
327 _pycurl_version_fn=pcverfn)
328
329 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
330 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
331 curl_factory=curl_factory)
332
333 self.assertRaises(NotImplementedError, cl._CreateCurl)
334
335 def testCertVerifyCapath(self):
336 for connect_timeout in [None, 1, 5, 10, 30, 60, 300]:
337 for timeout in [None, 1, 30, 60, 3600, 24 * 3600]:
338 cfgfn = client.GenericCurlConfig(connect_timeout=connect_timeout,
339 timeout=timeout)
340
341 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
342 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
343 curl_factory=curl_factory)
344
345 curl = cl._CreateCurl()
346 self.assertEqual(curl.getopt(pycurl.CONNECTTIMEOUT), connect_timeout)
347 self.assertEqual(curl.getopt(pycurl.TIMEOUT), timeout)
348
349
350 class GanetiRapiClientTests(testutils.GanetiTestCase):
351 def setUp(self):
352 testutils.GanetiTestCase.setUp(self)
353
354 self.rapi = RapiMock()
355 self.curl = rapi.testutils.FakeCurl(self.rapi)
356 self.client = client.GanetiRapiClient("master.example.com",
357 curl_factory=lambda: self.curl)
358
359 def assertHandler(self, handler_cls):
360 self.failUnless(isinstance(self.rapi.GetLastHandler(), handler_cls))
361
362 def assertQuery(self, key, value):
363 self.assertEqual(value, self.rapi.GetLastHandler().queryargs.get(key, None))
364
365 def assertItems(self, items):
366 self.assertEqual(items, self.rapi.GetLastHandler().items)
367
368 def assertBulk(self):
369 self.assertTrue(self.rapi.GetLastHandler().useBulk())
370
371 def assertDryRun(self):
372 self.assertTrue(self.rapi.GetLastHandler().dryRun())
373
374 def assertUseForce(self):
375 self.assertTrue(self.rapi.GetLastHandler().useForce())
376
377 def testEncodeQuery(self):
378 query = [
379 ("a", None),
380 ("b", 1),
381 ("c", 2),
382 ("d", "Foo"),
383 ("e", True),
384 ]
385
386 expected = [
387 ("a", ""),
388 ("b", 1),
389 ("c", 2),
390 ("d", "Foo"),
391 ("e", 1),
392 ]
393
394 self.assertEqualValues(self.client._EncodeQuery(query),
395 expected)
396
397 # invalid types
398 for i in [[1, 2, 3], {"moo": "boo"}, (1, 2, 3)]:
399 self.assertRaises(ValueError, self.client._EncodeQuery, [("x", i)])
400
401 def testCurlSettings(self):
402 self.rapi.AddResponse("2")
403 self.assertEqual(2, self.client.GetVersion())
404 self.assertHandler(rlib2.R_version)
405
406 # Signals should be disabled by default
407 self.assert_(self.curl.getopt(pycurl.NOSIGNAL))
408
409 # No auth and no proxy
410 self.assertFalse(self.curl.getopt(pycurl.USERPWD))
411 self.assert_(self.curl.getopt(pycurl.PROXY) is None)
412
413 # Content-type is required for requests
414 headers = self.curl.getopt(pycurl.HTTPHEADER)
415 self.assert_("Content-type: application/json" in headers)
416
417 def testHttpError(self):
418 self.rapi.AddResponse(None, code=404)
419 try:
420 self.client.GetJobStatus(15140)
421 except client.GanetiApiError, err:
422 self.assertEqual(err.code, 404)
423 else:
424 self.fail("Didn't raise exception")
425
426 def testGetVersion(self):
427 self.rapi.AddResponse("2")
428 self.assertEqual(2, self.client.GetVersion())
429 self.assertHandler(rlib2.R_version)
430
431 def testGetFeatures(self):
432 for features in [[], ["foo", "bar", "baz"]]:
433 self.rapi.AddResponse(serializer.DumpJson(features))
434 self.assertEqual(features, self.client.GetFeatures())
435 self.assertHandler(rlib2.R_2_features)
436
437 def testGetFeaturesNotFound(self):
438 self.rapi.AddResponse(None, code=404)
439 self.assertEqual([], self.client.GetFeatures())
440
441 def testGetOperatingSystems(self):
442 self.rapi.AddResponse("[\"beos\"]")
443 self.assertEqual(["beos"], self.client.GetOperatingSystems())
444 self.assertHandler(rlib2.R_2_os)
445
446 def testGetClusterTags(self):
447 self.rapi.AddResponse("[\"tag\"]")
448 self.assertEqual(["tag"], self.client.GetClusterTags())
449 self.assertHandler(rlib2.R_2_tags)
450
451 def testAddClusterTags(self):
452 self.rapi.AddResponse("1234")
453 self.assertEqual(1234,
454 self.client.AddClusterTags(["awesome"], dry_run=True))
455 self.assertHandler(rlib2.R_2_tags)
456 self.assertDryRun()
457 self.assertQuery("tag", ["awesome"])
458
459 def testDeleteClusterTags(self):
460 self.rapi.AddResponse("5107")
461 self.assertEqual(5107, self.client.DeleteClusterTags(["awesome"],
462 dry_run=True))
463 self.assertHandler(rlib2.R_2_tags)
464 self.assertDryRun()
465 self.assertQuery("tag", ["awesome"])
466
467 def testGetInfo(self):
468 self.rapi.AddResponse("{}")
469 self.assertEqual({}, self.client.GetInfo())
470 self.assertHandler(rlib2.R_2_info)
471
472 def testGetInstances(self):
473 self.rapi.AddResponse("[]")
474 self.assertEqual([], self.client.GetInstances(bulk=True))
475 self.assertHandler(rlib2.R_2_instances)
476 self.assertBulk()
477
478 def testGetInstance(self):
479 self.rapi.AddResponse("[]")
480 self.assertEqual([], self.client.GetInstance("instance"))
481 self.assertHandler(rlib2.R_2_instances_name)
482 self.assertItems(["instance"])
483
484 def testGetInstanceInfo(self):
485 self.rapi.AddResponse("21291")
486 self.assertEqual(21291, self.client.GetInstanceInfo("inst3"))
487 self.assertHandler(rlib2.R_2_instances_name_info)
488 self.assertItems(["inst3"])
489 self.assertQuery("static", None)
490
491 self.rapi.AddResponse("3428")
492 self.assertEqual(3428, self.client.GetInstanceInfo("inst31", static=False))
493 self.assertHandler(rlib2.R_2_instances_name_info)
494 self.assertItems(["inst31"])
495 self.assertQuery("static", ["0"])
496
497 self.rapi.AddResponse("15665")
498 self.assertEqual(15665, self.client.GetInstanceInfo("inst32", static=True))
499 self.assertHandler(rlib2.R_2_instances_name_info)
500 self.assertItems(["inst32"])
501 self.assertQuery("static", ["1"])
502
503 def testInstancesMultiAlloc(self):
504 response = {
505 constants.JOB_IDS_KEY: ["23423"],
506 opcodes.OpInstanceMultiAlloc.ALLOCATABLE_KEY: ["foobar"],
507 opcodes.OpInstanceMultiAlloc.FAILED_KEY: ["foobar2"],
508 }
509 self.rapi.AddResponse(serializer.DumpJson(response))
510 insts = [self.client.InstanceAllocation("create", "foobar",
511 "plain", [], []),
512 self.client.InstanceAllocation("create", "foobar2",
513 "drbd8", [{"size": 100}], [])]
514 resp = self.client.InstancesMultiAlloc(insts)
515 self.assertEqual(resp, response)
516 self.assertHandler(rlib2.R_2_instances_multi_alloc)
517
518 def testCreateInstanceOldVersion(self):
519 # The old request format, version 0, is no longer supported
520 self.rapi.AddResponse(None, code=404)
521 self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
522 "create", "inst1.example.com", "plain", [], [])
523 self.assertEqual(self.rapi.CountPending(), 0)
524
525 def testCreateInstance(self):
526 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
527 self.rapi.AddResponse("23030")
528 job_id = self.client.CreateInstance("create", "inst1.example.com",
529 "plain", [], [], dry_run=True)
530 self.assertEqual(job_id, 23030)
531 self.assertHandler(rlib2.R_2_instances)
532 self.assertDryRun()
533
534 data = serializer.LoadJson(self.rapi.GetLastRequestData())
535
536 for field in ["dry_run", "beparams", "hvparams", "start"]:
537 self.assertFalse(field in data)
538
539 self.assertEqual(data["name"], "inst1.example.com")
540 self.assertEqual(data["disk_template"], "plain")
541
542 def testCreateInstance2(self):
543 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
544 self.rapi.AddResponse("24740")
545 job_id = self.client.CreateInstance("import", "inst2.example.com",
546 "drbd8", [{"size": 100,}],
547 [{}, {"bridge": "br1", }],
548 dry_run=False, start=True,
549 pnode="node1", snode="node9",
550 ip_check=False)
551 self.assertEqual(job_id, 24740)
552 self.assertHandler(rlib2.R_2_instances)
553
554 data = serializer.LoadJson(self.rapi.GetLastRequestData())
555 self.assertEqual(data[rlib2._REQ_DATA_VERSION], 1)
556 self.assertEqual(data["name"], "inst2.example.com")
557 self.assertEqual(data["disk_template"], "drbd8")
558 self.assertEqual(data["start"], True)
559 self.assertEqual(data["ip_check"], False)
560 self.assertEqualValues(data["disks"], [{"size": 100,}])
561 self.assertEqualValues(data["nics"], [{}, {"bridge": "br1", }])
562
563 def testDeleteInstance(self):
564 self.rapi.AddResponse("1234")
565 self.assertEqual(1234, self.client.DeleteInstance("instance", dry_run=True))
566 self.assertHandler(rlib2.R_2_instances_name)
567 self.assertItems(["instance"])
568 self.assertDryRun()
569
570 def testGetInstanceTags(self):
571 self.rapi.AddResponse("[]")
572 self.assertEqual([], self.client.GetInstanceTags("fooinstance"))
573 self.assertHandler(rlib2.R_2_instances_name_tags)
574 self.assertItems(["fooinstance"])
575
576 def testAddInstanceTags(self):
577 self.rapi.AddResponse("1234")
578 self.assertEqual(1234,
579 self.client.AddInstanceTags("fooinstance", ["awesome"], dry_run=True))
580 self.assertHandler(rlib2.R_2_instances_name_tags)
581 self.assertItems(["fooinstance"])
582 self.assertDryRun()
583 self.assertQuery("tag", ["awesome"])
584
585 def testDeleteInstanceTags(self):
586 self.rapi.AddResponse("25826")
587 self.assertEqual(25826, self.client.DeleteInstanceTags("foo", ["awesome"],
588 dry_run=True))
589 self.assertHandler(rlib2.R_2_instances_name_tags)
590 self.assertItems(["foo"])
591 self.assertDryRun()
592 self.assertQuery("tag", ["awesome"])
593
594 def testRebootInstance(self):
595 self.rapi.AddResponse("6146")
596 job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
597 ignore_secondaries=True, dry_run=True,
598 reason="Updates")
599 self.assertEqual(6146, job_id)
600 self.assertHandler(rlib2.R_2_instances_name_reboot)
601 self.assertItems(["i-bar"])
602 self.assertDryRun()
603 self.assertQuery("type", ["hard"])
604 self.assertQuery("ignore_secondaries", ["1"])
605 self.assertQuery("reason", ["Updates"])
606
607 def testRebootInstanceDefaultReason(self):
608 self.rapi.AddResponse("6146")
609 job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
610 ignore_secondaries=True, dry_run=True)
611 self.assertEqual(6146, job_id)
612 self.assertHandler(rlib2.R_2_instances_name_reboot)
613 self.assertItems(["i-bar"])
614 self.assertDryRun()
615 self.assertQuery("type", ["hard"])
616 self.assertQuery("ignore_secondaries", ["1"])
617 self.assertQuery("reason", None)
618
619 def testShutdownInstance(self):
620 self.rapi.AddResponse("1487")
621 self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
622 dry_run=True,
623 reason="NoMore"))
624 self.assertHandler(rlib2.R_2_instances_name_shutdown)
625 self.assertItems(["foo-instance"])
626 self.assertDryRun()
627 self.assertQuery("reason", ["NoMore"])
628
629 def testShutdownInstanceDefaultReason(self):
630 self.rapi.AddResponse("1487")
631 self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
632 dry_run=True))
633 self.assertHandler(rlib2.R_2_instances_name_shutdown)
634 self.assertItems(["foo-instance"])
635 self.assertDryRun()
636 self.assertQuery("reason", None)
637
638 def testStartupInstance(self):
639 self.rapi.AddResponse("27149")
640 self.assertEqual(27149, self.client.StartupInstance("bar-instance",
641 dry_run=True,
642 reason="New"))
643 self.assertHandler(rlib2.R_2_instances_name_startup)
644 self.assertItems(["bar-instance"])
645 self.assertDryRun()
646 self.assertQuery("reason", ["New"])
647
648 def testStartupInstanceDefaultReason(self):
649 self.rapi.AddResponse("27149")
650 self.assertEqual(27149, self.client.StartupInstance("bar-instance",
651 dry_run=True))
652 self.assertHandler(rlib2.R_2_instances_name_startup)
653 self.assertItems(["bar-instance"])
654 self.assertDryRun()
655 self.assertQuery("reason", None)
656
657 def testReinstallInstance(self):
658 self.rapi.AddResponse(serializer.DumpJson([]))
659 self.rapi.AddResponse("19119")
660 self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
661 os="DOS",
662 no_startup=True))
663 self.assertHandler(rlib2.R_2_instances_name_reinstall)
664 self.assertItems(["baz-instance"])
665 self.assertQuery("os", ["DOS"])
666 self.assertQuery("nostartup", ["1"])
667 self.assertEqual(self.rapi.CountPending(), 0)
668
669 def testReinstallInstanceNew(self):
670 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
671 self.rapi.AddResponse("25689")
672 self.assertEqual(25689, self.client.ReinstallInstance("moo-instance",
673 os="Debian",
674 no_startup=True))
675 self.assertHandler(rlib2.R_2_instances_name_reinstall)
676 self.assertItems(["moo-instance"])
677 data = serializer.LoadJson(self.rapi.GetLastRequestData())
678 self.assertEqual(len(data), 2)
679 self.assertEqual(data["os"], "Debian")
680 self.assertEqual(data["start"], False)
681 self.assertEqual(self.rapi.CountPending(), 0)
682
683 def testReinstallInstanceWithOsparams1(self):
684 self.rapi.AddResponse(serializer.DumpJson([]))
685 self.assertRaises(client.GanetiApiError, self.client.ReinstallInstance,
686 "doo-instance", osparams={"x": "y"})
687 self.assertEqual(self.rapi.CountPending(), 0)
688
689 def testReinstallInstanceWithOsparams2(self):
690 osparams = {
691 "Hello": "World",
692 "foo": "bar",
693 }
694 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
695 self.rapi.AddResponse("1717")
696 self.assertEqual(1717, self.client.ReinstallInstance("zoo-instance",
697 osparams=osparams))
698 self.assertHandler(rlib2.R_2_instances_name_reinstall)
699 self.assertItems(["zoo-instance"])
700 data = serializer.LoadJson(self.rapi.GetLastRequestData())
701 self.assertEqual(len(data), 2)
702 self.assertEqual(data["osparams"], osparams)
703 self.assertEqual(data["start"], True)
704 self.assertEqual(self.rapi.CountPending(), 0)
705
706 def testReplaceInstanceDisks(self):
707 self.rapi.AddResponse("999")
708 job_id = self.client.ReplaceInstanceDisks("instance-name",
709 disks=[0, 1], iallocator="hail")
710 self.assertEqual(999, job_id)
711 self.assertHandler(rlib2.R_2_instances_name_replace_disks)
712 self.assertItems(["instance-name"])
713 self.assertQuery("disks", ["0,1"])
714 self.assertQuery("mode", ["replace_auto"])
715 self.assertQuery("iallocator", ["hail"])
716
717 self.rapi.AddResponse("1000")
718 job_id = self.client.ReplaceInstanceDisks("instance-bar",
719 disks=[1], mode="replace_on_secondary", remote_node="foo-node")
720 self.assertEqual(1000, job_id)
721 self.assertItems(["instance-bar"])
722 self.assertQuery("disks", ["1"])
723 self.assertQuery("remote_node", ["foo-node"])
724
725 self.rapi.AddResponse("5175")
726 self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
727 self.assertItems(["instance-moo"])
728 self.assertQuery("disks", None)
729
730 def testPrepareExport(self):
731 self.rapi.AddResponse("8326")
732 self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
733 self.assertHandler(rlib2.R_2_instances_name_prepare_export)
734 self.assertItems(["inst1"])
735 self.assertQuery("mode", ["local"])
736
737 def testExportInstance(self):
738 self.rapi.AddResponse("19695")
739 job_id = self.client.ExportInstance("inst2", "local", "nodeX",
740 shutdown=True)
741 self.assertEqual(job_id, 19695)
742 self.assertHandler(rlib2.R_2_instances_name_export)
743 self.assertItems(["inst2"])
744
745 data = serializer.LoadJson(self.rapi.GetLastRequestData())
746 self.assertEqual(data["mode"], "local")
747 self.assertEqual(data["destination"], "nodeX")
748 self.assertEqual(data["shutdown"], True)
749
750 def testMigrateInstanceDefaults(self):
751 self.rapi.AddResponse("24873")
752 job_id = self.client.MigrateInstance("inst91")
753 self.assertEqual(job_id, 24873)
754 self.assertHandler(rlib2.R_2_instances_name_migrate)
755 self.assertItems(["inst91"])
756
757 data = serializer.LoadJson(self.rapi.GetLastRequestData())
758 self.assertFalse(data)
759
760 def testMigrateInstance(self):
761 for mode in constants.HT_MIGRATION_MODES:
762 for cleanup in [False, True]:
763 self.rapi.AddResponse("31910")
764 job_id = self.client.MigrateInstance("inst289", mode=mode,
765 cleanup=cleanup)
766 self.assertEqual(job_id, 31910)
767 self.assertHandler(rlib2.R_2_instances_name_migrate)
768 self.assertItems(["inst289"])
769
770 data = serializer.LoadJson(self.rapi.GetLastRequestData())
771 self.assertEqual(len(data), 2)
772 self.assertEqual(data["mode"], mode)
773 self.assertEqual(data["cleanup"], cleanup)
774
775 def testFailoverInstanceDefaults(self):
776 self.rapi.AddResponse("7639")
777 job_id = self.client.FailoverInstance("inst13579")
778 self.assertEqual(job_id, 7639)
779 self.assertHandler(rlib2.R_2_instances_name_failover)
780 self.assertItems(["inst13579"])
781
782 data = serializer.LoadJson(self.rapi.GetLastRequestData())
783 self.assertFalse(data)
784
785 def testFailoverInstance(self):
786 for iallocator in ["dumb", "hail"]:
787 for ignore_consistency in [False, True]:
788 for target_node in ["node-a", "node2"]:
789 self.rapi.AddResponse("19161")
790 job_id = \
791 self.client.FailoverInstance("inst251", iallocator=iallocator,
792 ignore_consistency=ignore_consistency,
793 target_node=target_node)
794 self.assertEqual(job_id, 19161)
795 self.assertHandler(rlib2.R_2_instances_name_failover)
796 self.assertItems(["inst251"])
797
798 data = serializer.LoadJson(self.rapi.GetLastRequestData())
799 self.assertEqual(len(data), 3)
800 self.assertEqual(data["iallocator"], iallocator)
801 self.assertEqual(data["ignore_consistency"], ignore_consistency)
802 self.assertEqual(data["target_node"], target_node)
803 self.assertEqual(self.rapi.CountPending(), 0)
804
805 def testRenameInstanceDefaults(self):
806 new_name = "newnametha7euqu"
807 self.rapi.AddResponse("8791")
808 job_id = self.client.RenameInstance("inst18821", new_name)
809 self.assertEqual(job_id, 8791)
810 self.assertHandler(rlib2.R_2_instances_name_rename)
811 self.assertItems(["inst18821"])
812
813 data = serializer.LoadJson(self.rapi.GetLastRequestData())
814 self.assertEqualValues(data, {"new_name": new_name, })
815
816 def testRenameInstance(self):
817 new_name = "new-name-yiux1iin"
818 for ip_check in [False, True]:
819 for name_check in [False, True]:
820 self.rapi.AddResponse("24776")
821 job_id = self.client.RenameInstance("inst20967", new_name,
822 ip_check=ip_check,
823 name_check=name_check)
824 self.assertEqual(job_id, 24776)
825 self.assertHandler(rlib2.R_2_instances_name_rename)
826 self.assertItems(["inst20967"])
827
828 data = serializer.LoadJson(self.rapi.GetLastRequestData())
829 self.assertEqual(len(data), 3)
830 self.assertEqual(data["new_name"], new_name)
831 self.assertEqual(data["ip_check"], ip_check)
832 self.assertEqual(data["name_check"], name_check)
833
834 def testGetJobs(self):
835 self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
836 ' { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
837 self.assertEqual([123, 124], self.client.GetJobs())
838 self.assertHandler(rlib2.R_2_jobs)
839
840 self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
841 ' { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
842 self.assertEqual([{"id": "123", "uri": "/2/jobs/123"},
843 {"id": "124", "uri": "/2/jobs/124"}],
844 self.client.GetJobs(bulk=True))
845 self.assertHandler(rlib2.R_2_jobs)
846 self.assertBulk()
847
848 def testGetJobStatus(self):
849 self.rapi.AddResponse("{\"foo\": \"bar\"}")
850 self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
851 self.assertHandler(rlib2.R_2_jobs_id)
852 self.assertItems(["1234"])
853
854 def testWaitForJobChange(self):
855 fields = ["id", "summary"]
856 expected = {
857 "job_info": [123, "something"],
858 "log_entries": [],
859 }
860
861 self.rapi.AddResponse(serializer.DumpJson(expected))
862 result = self.client.WaitForJobChange(123, fields, [], -1)
863 self.assertEqualValues(expected, result)
864 self.assertHandler(rlib2.R_2_jobs_id_wait)
865 self.assertItems(["123"])
866
867 def testCancelJob(self):
868 self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
869 self.assertEqual([True, "Job 123 will be canceled"],
870 self.client.CancelJob(999, dry_run=True))
871 self.assertHandler(rlib2.R_2_jobs_id)
872 self.assertItems(["999"])
873 self.assertDryRun()
874
875 def testGetNodes(self):
876 self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
877 " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
878 self.assertEqual(["node1", "node2"], self.client.GetNodes())
879 self.assertHandler(rlib2.R_2_nodes)
880
881 self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
882 " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
883 self.assertEqual([{"id": "node1", "uri": "uri1"},
884 {"id": "node2", "uri": "uri2"}],
885 self.client.GetNodes(bulk=True))
886 self.assertHandler(rlib2.R_2_nodes)
887 self.assertBulk()
888
889 def testGetNode(self):
890 self.rapi.AddResponse("{}")
891 self.assertEqual({}, self.client.GetNode("node-foo"))
892 self.assertHandler(rlib2.R_2_nodes_name)
893 self.assertItems(["node-foo"])
894
895 def testEvacuateNode(self):
896 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
897 self.rapi.AddResponse("9876")
898 job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
899 self.assertEqual(9876, job_id)
900 self.assertHandler(rlib2.R_2_nodes_name_evacuate)
901 self.assertItems(["node-1"])
902 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
903 { "remote_node": "node-2", })
904 self.assertEqual(self.rapi.CountPending(), 0)
905
906 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
907 self.rapi.AddResponse("8888")
908 job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True,
909 mode=constants.NODE_EVAC_ALL,
910 early_release=True)
911 self.assertEqual(8888, job_id)
912 self.assertItems(["node-3"])
913 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()), {
914 "iallocator": "hail",
915 "mode": "all",
916 "early_release": True,
917 })
918 self.assertDryRun()
919
920 self.assertRaises(client.GanetiApiError,
921 self.client.EvacuateNode,
922 "node-4", iallocator="hail", remote_node="node-5")
923 self.assertEqual(self.rapi.CountPending(), 0)
924
925 def testEvacuateNodeOldResponse(self):
926 self.rapi.AddResponse(serializer.DumpJson([]))
927 self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
928 "node-4", accept_old=False)
929 self.assertEqual(self.rapi.CountPending(), 0)
930
931 for mode in [client.NODE_EVAC_PRI, client.NODE_EVAC_ALL]:
932 self.rapi.AddResponse(serializer.DumpJson([]))
933 self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
934 "node-4", accept_old=True, mode=mode)
935 self.assertEqual(self.rapi.CountPending(), 0)
936
937 self.rapi.AddResponse(serializer.DumpJson([]))
938 self.rapi.AddResponse(serializer.DumpJson("21533"))
939 result = self.client.EvacuateNode("node-3", iallocator="hail",
940 dry_run=True, accept_old=True,
941 mode=client.NODE_EVAC_SEC,
942 early_release=True)
943 self.assertEqual(result, "21533")
944 self.assertItems(["node-3"])
945 self.assertQuery("iallocator", ["hail"])
946 self.assertQuery("early_release", ["1"])
947 self.assertFalse(self.rapi.GetLastRequestData())
948 self.assertDryRun()
949 self.assertEqual(self.rapi.CountPending(), 0)
950
951 def testMigrateNode(self):
952 self.rapi.AddResponse(serializer.DumpJson([]))
953 self.rapi.AddResponse("1111")
954 self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
955 self.assertHandler(rlib2.R_2_nodes_name_migrate)
956 self.assertItems(["node-a"])
957 self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
958 self.assertDryRun()
959 self.assertFalse(self.rapi.GetLastRequestData())
960
961 self.rapi.AddResponse(serializer.DumpJson([]))
962 self.rapi.AddResponse("1112")
963 self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
964 mode="live"))
965 self.assertHandler(rlib2.R_2_nodes_name_migrate)
966 self.assertItems(["node-a"])
967 self.assertQuery("mode", ["live"])
968 self.assertDryRun()
969 self.assertFalse(self.rapi.GetLastRequestData())
970
971 self.rapi.AddResponse(serializer.DumpJson([]))
972 self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
973 "node-c", target_node="foonode")
974 self.assertEqual(self.rapi.CountPending(), 0)
975
976 def testMigrateNodeBodyData(self):
977 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
978 self.rapi.AddResponse("27539")
979 self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
980 mode="live"))
981 self.assertHandler(rlib2.R_2_nodes_name_migrate)
982 self.assertItems(["node-a"])
983 self.assertFalse(self.rapi.GetLastHandler().queryargs)
984 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
985 { "mode": "live", })
986
987 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
988 self.rapi.AddResponse("14219")
989 self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
990 target_node="node9",
991 iallocator="ial"))
992 self.assertHandler(rlib2.R_2_nodes_name_migrate)
993 self.assertItems(["node-x"])
994 self.assertDryRun()
995 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
996 { "target_node": "node9", "iallocator": "ial", })
997
998 self.assertEqual(self.rapi.CountPending(), 0)
999
1000 def testGetNodeRole(self):
1001 self.rapi.AddResponse("\"master\"")
1002 self.assertEqual("master", self.client.GetNodeRole("node-a"))
1003 self.assertHandler(rlib2.R_2_nodes_name_role)
1004 self.assertItems(["node-a"])
1005
1006 def testSetNodeRole(self):
1007 self.rapi.AddResponse("789")
1008 self.assertEqual(789,
1009 self.client.SetNodeRole("node-foo", "master-candidate", force=True))
1010 self.assertHandler(rlib2.R_2_nodes_name_role)
1011 self.assertItems(["node-foo"])
1012 self.assertQuery("force", ["1"])
1013 self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
1014
1015 def testPowercycleNode(self):
1016 self.rapi.AddResponse("23051")
1017 self.assertEqual(23051,
1018 self.client.PowercycleNode("node5468", force=True))
1019 self.assertHandler(rlib2.R_2_nodes_name_powercycle)
1020 self.assertItems(["node5468"])
1021 self.assertQuery("force", ["1"])
1022 self.assertFalse(self.rapi.GetLastRequestData())
1023 self.assertEqual(self.rapi.CountPending(), 0)
1024
1025 def testModifyNode(self):
1026 self.rapi.AddResponse("3783")
1027 job_id = self.client.ModifyNode("node16979.example.com", drained=True)
1028 self.assertEqual(job_id, 3783)
1029 self.assertHandler(rlib2.R_2_nodes_name_modify)
1030 self.assertItems(["node16979.example.com"])
1031 self.assertEqual(self.rapi.CountPending(), 0)
1032
1033 def testGetNodeStorageUnits(self):
1034 self.rapi.AddResponse("42")
1035 self.assertEqual(42,
1036 self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
1037 self.assertHandler(rlib2.R_2_nodes_name_storage)
1038 self.assertItems(["node-x"])
1039 self.assertQuery("storage_type", ["lvm-pv"])
1040 self.assertQuery("output_fields", ["fields"])
1041
1042 def testModifyNodeStorageUnits(self):
1043 self.rapi.AddResponse("14")
1044 self.assertEqual(14,
1045 self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
1046 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1047 self.assertItems(["node-z"])
1048 self.assertQuery("storage_type", ["lvm-pv"])
1049 self.assertQuery("name", ["hda"])
1050 self.assertQuery("allocatable", None)
1051
1052 for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
1053 self.rapi.AddResponse("7205")
1054 job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
1055 allocatable=allocatable)
1056 self.assertEqual(7205, job_id)
1057 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1058 self.assertItems(["node-z"])
1059 self.assertQuery("storage_type", ["lvm-pv"])
1060 self.assertQuery("name", ["hda"])
1061 self.assertQuery("allocatable", [query_allocatable])
1062
1063 def testRepairNodeStorageUnits(self):
1064 self.rapi.AddResponse("99")
1065 self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
1066 "hda"))
1067 self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
1068 self.assertItems(["node-z"])
1069 self.assertQuery("storage_type", ["lvm-pv"])
1070 self.assertQuery("name", ["hda"])
1071
1072 def testGetNodeTags(self):
1073 self.rapi.AddResponse("[\"fry\", \"bender\"]")
1074 self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
1075 self.assertHandler(rlib2.R_2_nodes_name_tags)
1076 self.assertItems(["node-k"])
1077
1078 def testAddNodeTags(self):
1079 self.rapi.AddResponse("1234")
1080 self.assertEqual(1234,
1081 self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
1082 self.assertHandler(rlib2.R_2_nodes_name_tags)
1083 self.assertItems(["node-v"])
1084 self.assertDryRun()
1085 self.assertQuery("tag", ["awesome"])
1086
1087 def testDeleteNodeTags(self):
1088 self.rapi.AddResponse("16861")
1089 self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1090 dry_run=True))
1091 self.assertHandler(rlib2.R_2_nodes_name_tags)
1092 self.assertItems(["node-w"])
1093 self.assertDryRun()
1094 self.assertQuery("tag", ["awesome"])
1095
1096 def testGetGroups(self):
1097 groups = [{"name": "group1",
1098 "uri": "/2/groups/group1",
1099 },
1100 {"name": "group2",
1101 "uri": "/2/groups/group2",
1102 },
1103 ]
1104 self.rapi.AddResponse(serializer.DumpJson(groups))
1105 self.assertEqual(["group1", "group2"], self.client.GetGroups())
1106 self.assertHandler(rlib2.R_2_groups)
1107
1108 def testGetGroupsBulk(self):
1109 groups = [{"name": "group1",
1110 "uri": "/2/groups/group1",
1111 "node_cnt": 2,
1112 "node_list": ["gnt1.test",
1113 "gnt2.test",
1114 ],
1115 },
1116 {"name": "group2",
1117 "uri": "/2/groups/group2",
1118 "node_cnt": 1,
1119 "node_list": ["gnt3.test",
1120 ],
1121 },
1122 ]
1123 self.rapi.AddResponse(serializer.DumpJson(groups))
1124
1125 self.assertEqual(groups, self.client.GetGroups(bulk=True))
1126 self.assertHandler(rlib2.R_2_groups)
1127 self.assertBulk()
1128
1129 def testGetGroup(self):
1130 group = {"ctime": None,
1131 "name": "default",
1132 }
1133 self.rapi.AddResponse(serializer.DumpJson(group))
1134 self.assertEqual({"ctime": None, "name": "default"},
1135 self.client.GetGroup("default"))
1136 self.assertHandler(rlib2.R_2_groups_name)
1137 self.assertItems(["default"])
1138
1139 def testCreateGroup(self):
1140 self.rapi.AddResponse("12345")
1141 job_id = self.client.CreateGroup("newgroup", dry_run=True)
1142 self.assertEqual(job_id, 12345)
1143 self.assertHandler(rlib2.R_2_groups)
1144 self.assertDryRun()
1145
1146 def testDeleteGroup(self):
1147 self.rapi.AddResponse("12346")
1148 job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1149 self.assertEqual(job_id, 12346)
1150 self.assertHandler(rlib2.R_2_groups_name)
1151 self.assertDryRun()
1152
1153 def testRenameGroup(self):
1154 self.rapi.AddResponse("12347")
1155 job_id = self.client.RenameGroup("oldname", "newname")
1156 self.assertEqual(job_id, 12347)
1157 self.assertHandler(rlib2.R_2_groups_name_rename)
1158
1159 def testModifyGroup(self):
1160 self.rapi.AddResponse("12348")
1161 job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1162 self.assertEqual(job_id, 12348)
1163 self.assertHandler(rlib2.R_2_groups_name_modify)
1164
1165 def testAssignGroupNodes(self):
1166 self.rapi.AddResponse("12349")
1167 job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1168 force=True, dry_run=True)
1169 self.assertEqual(job_id, 12349)
1170 self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1171 self.assertDryRun()
1172 self.assertUseForce()
1173
1174 def testGetNetworksBulk(self):
1175 networks = [{"name": "network1",
1176 "uri": "/2/networks/network1",
1177 "network": "192.168.0.0/24",
1178 },
1179 {"name": "network2",
1180 "uri": "/2/networks/network2",
1181 "network": "192.168.0.0/24",
1182 },
1183 ]
1184 self.rapi.AddResponse(serializer.DumpJson(networks))
1185
1186 self.assertEqual(networks, self.client.GetNetworks(bulk=True))
1187 self.assertHandler(rlib2.R_2_networks)
1188 self.assertBulk()
1189
1190 def testGetNetwork(self):
1191 network = {"ctime": None,
1192 "name": "network1",
1193 }
1194 self.rapi.AddResponse(serializer.DumpJson(network))
1195 self.assertEqual({"ctime": None, "name": "network1"},
1196 self.client.GetNetwork("network1"))
1197 self.assertHandler(rlib2.R_2_networks_name)
1198 self.assertItems(["network1"])
1199
1200 def testCreateNetwork(self):
1201 self.rapi.AddResponse("12345")
1202 job_id = self.client.CreateNetwork("newnetwork", network="192.168.0.0/24",
1203 dry_run=True)
1204 self.assertEqual(job_id, 12345)
1205 self.assertHandler(rlib2.R_2_networks)
1206 self.assertDryRun()
1207
1208 def testModifyNetwork(self):
1209 self.rapi.AddResponse("12346")
1210 job_id = self.client.ModifyNetwork("mynetwork", gateway="192.168.0.10",
1211 dry_run=True)
1212 self.assertEqual(job_id, 12346)
1213 self.assertHandler(rlib2.R_2_networks_name_modify)
1214
1215 def testDeleteNetwork(self):
1216 self.rapi.AddResponse("12347")
1217 job_id = self.client.DeleteNetwork("newnetwork", dry_run=True)
1218 self.assertEqual(job_id, 12347)
1219 self.assertHandler(rlib2.R_2_networks_name)
1220 self.assertDryRun()
1221
1222 def testConnectNetwork(self):
1223 self.rapi.AddResponse("12348")
1224 job_id = self.client.ConnectNetwork("mynetwork", "default",
1225 "bridged", "br0", dry_run=True)
1226 self.assertEqual(job_id, 12348)
1227 self.assertHandler(rlib2.R_2_networks_name_connect)
1228 self.assertDryRun()
1229
1230 def testDisconnectNetwork(self):
1231 self.rapi.AddResponse("12349")
1232 job_id = self.client.DisconnectNetwork("mynetwork", "default", dry_run=True)
1233 self.assertEqual(job_id, 12349)
1234 self.assertHandler(rlib2.R_2_networks_name_disconnect)
1235 self.assertDryRun()
1236
1237 def testGetNetworkTags(self):
1238 self.rapi.AddResponse("[]")
1239 self.assertEqual([], self.client.GetNetworkTags("fooNetwork"))
1240 self.assertHandler(rlib2.R_2_networks_name_tags)
1241 self.assertItems(["fooNetwork"])
1242
1243 def testAddNetworkTags(self):
1244 self.rapi.AddResponse("1234")
1245 self.assertEqual(1234,
1246 self.client.AddNetworkTags("fooNetwork", ["awesome"], dry_run=True))
1247 self.assertHandler(rlib2.R_2_networks_name_tags)
1248 self.assertItems(["fooNetwork"])
1249 self.assertDryRun()
1250 self.assertQuery("tag", ["awesome"])
1251
1252 def testDeleteNetworkTags(self):
1253 self.rapi.AddResponse("25826")
1254 self.assertEqual(25826, self.client.DeleteNetworkTags("foo", ["awesome"],
1255 dry_run=True))
1256 self.assertHandler(rlib2.R_2_networks_name_tags)
1257 self.assertItems(["foo"])
1258 self.assertDryRun()
1259 self.assertQuery("tag", ["awesome"])
1260
1261 def testModifyInstance(self):
1262 self.rapi.AddResponse("23681")
1263 job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1264 self.assertEqual(job_id, 23681)
1265 self.assertItems(["inst7210"])
1266 self.assertHandler(rlib2.R_2_instances_name_modify)
1267 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1268 { "os_name": "linux", })
1269
1270 def testModifyCluster(self):
1271 for mnh in [None, False, True]:
1272 self.rapi.AddResponse("14470")
1273 self.assertEqual(14470,
1274 self.client.ModifyCluster(maintain_node_health=mnh,
1275 reason="PinkBunniesInvasion"))
1276 self.assertHandler(rlib2.R_2_cluster_modify)
1277 self.assertItems([])
1278 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1279 self.assertEqual(len(data), 1)
1280 self.assertEqual(data["maintain_node_health"], mnh)
1281 self.assertEqual(self.rapi.CountPending(), 0)
1282 self.assertQuery("reason", ["PinkBunniesInvasion"])
1283
1284 def testRedistributeConfig(self):
1285 self.rapi.AddResponse("3364")
1286 job_id = self.client.RedistributeConfig()
1287 self.assertEqual(job_id, 3364)
1288 self.assertItems([])
1289 self.assertHandler(rlib2.R_2_redist_config)
1290
1291 def testActivateInstanceDisks(self):
1292 self.rapi.AddResponse("23547")
1293 job_id = self.client.ActivateInstanceDisks("inst28204")
1294 self.assertEqual(job_id, 23547)
1295 self.assertItems(["inst28204"])
1296 self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1297 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1298
1299 def testActivateInstanceDisksIgnoreSize(self):
1300 self.rapi.AddResponse("11044")
1301 job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1302 self.assertEqual(job_id, 11044)
1303 self.assertItems(["inst28204"])
1304 self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1305 self.assertQuery("ignore_size", ["1"])
1306
1307 def testDeactivateInstanceDisks(self):
1308 self.rapi.AddResponse("14591")
1309 job_id = self.client.DeactivateInstanceDisks("inst28234")
1310 self.assertEqual(job_id, 14591)
1311 self.assertItems(["inst28234"])
1312 self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1313 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1314
1315 def testRecreateInstanceDisks(self):
1316 self.rapi.AddResponse("13553")
1317 job_id = self.client.RecreateInstanceDisks("inst23153")
1318 self.assertEqual(job_id, 13553)
1319 self.assertItems(["inst23153"])
1320 self.assertHandler(rlib2.R_2_instances_name_recreate_disks)
1321 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1322
1323 def testGetInstanceConsole(self):
1324 self.rapi.AddResponse("26876")
1325 job_id = self.client.GetInstanceConsole("inst21491")
1326 self.assertEqual(job_id, 26876)
1327 self.assertItems(["inst21491"])
1328 self.assertHandler(rlib2.R_2_instances_name_console)
1329 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1330 self.assertFalse(self.rapi.GetLastRequestData())
1331
1332 def testGrowInstanceDisk(self):
1333 for idx, wait_for_sync in enumerate([None, False, True]):
1334 amount = 128 + (512 * idx)
1335 self.assertEqual(self.rapi.CountPending(), 0)
1336 self.rapi.AddResponse("30783")
1337 self.assertEqual(30783,
1338 self.client.GrowInstanceDisk("eze8ch", idx, amount,
1339 wait_for_sync=wait_for_sync))
1340 self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1341 self.assertItems(["eze8ch", str(idx)])
1342 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1343 if wait_for_sync is None:
1344 self.assertEqual(len(data), 1)
1345 self.assert_("wait_for_sync" not in data)
1346 else:
1347 self.assertEqual(len(data), 2)
1348 self.assertEqual(data["wait_for_sync"], wait_for_sync)
1349 self.assertEqual(data["amount"], amount)
1350 self.assertEqual(self.rapi.CountPending(), 0)
1351
1352 def testGetGroupTags(self):
1353 self.rapi.AddResponse("[]")
1354 self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1355 self.assertHandler(rlib2.R_2_groups_name_tags)
1356 self.assertItems(["fooGroup"])
1357
1358 def testAddGroupTags(self):
1359 self.rapi.AddResponse("1234")
1360 self.assertEqual(1234,
1361 self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1362 self.assertHandler(rlib2.R_2_groups_name_tags)
1363 self.assertItems(["fooGroup"])
1364 self.assertDryRun()
1365 self.assertQuery("tag", ["awesome"])
1366
1367 def testDeleteGroupTags(self):
1368 self.rapi.AddResponse("25826")
1369 self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1370 dry_run=True))
1371 self.assertHandler(rlib2.R_2_groups_name_tags)
1372 self.assertItems(["foo"])
1373 self.assertDryRun()
1374 self.assertQuery("tag", ["awesome"])
1375
1376 def testQuery(self):
1377 for idx, what in enumerate(constants.QR_VIA_RAPI):
1378 for idx2, qfilter in enumerate([None, ["?", "name"]]):
1379 job_id = 11010 + (idx << 4) + (idx2 << 16)
1380 fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1381
1382 self.rapi.AddResponse(str(job_id))
1383 self.assertEqual(self.client.Query(what, fields, qfilter=qfilter),
1384 job_id)
1385 self.assertItems([what])
1386 self.assertHandler(rlib2.R_2_query)
1387 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1388 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1389 self.assertEqual(data["fields"], fields)
1390 if qfilter is None:
1391 self.assertTrue("qfilter" not in data)
1392 else:
1393 self.assertEqual(data["qfilter"], qfilter)
1394 self.assertEqual(self.rapi.CountPending(), 0)
1395
1396 def testQueryFields(self):
1397 exp_result = objects.QueryFieldsResponse(fields=[
1398 objects.QueryFieldDefinition(name="pnode", title="PNode",
1399 kind=constants.QFT_NUMBER),
1400 objects.QueryFieldDefinition(name="other", title="Other",
1401 kind=constants.QFT_BOOL),
1402 ])
1403
1404 for what in constants.QR_VIA_RAPI:
1405 for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1406 self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1407 result = self.client.QueryFields(what, fields=fields)
1408 self.assertItems([what])
1409 self.assertHandler(rlib2.R_2_query_fields)
1410 self.assertFalse(self.rapi.GetLastRequestData())
1411
1412 queryargs = self.rapi.GetLastHandler().queryargs
1413 if fields is None:
1414 self.assertFalse(queryargs)
1415 else:
1416 self.assertEqual(queryargs, {
1417 "fields": [",".join(fields)],
1418 })
1419
1420 self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1421 exp_result.ToDict())
1422
1423 self.assertEqual(self.rapi.CountPending(), 0)
1424
1425 def testWaitForJobCompletionNoChange(self):
1426 resp = serializer.DumpJson({
1427 "status": constants.JOB_STATUS_WAITING,
1428 })
1429
1430 for retries in [1, 5, 25]:
1431 for _ in range(retries):
1432 self.rapi.AddResponse(resp)
1433
1434 self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1435 retries=retries))
1436 self.assertHandler(rlib2.R_2_jobs_id)
1437 self.assertItems(["22789"])
1438
1439 self.assertEqual(self.rapi.CountPending(), 0)
1440
1441 def testWaitForJobCompletionAlreadyFinished(self):
1442 self.rapi.AddResponse(serializer.DumpJson({
1443 "status": constants.JOB_STATUS_SUCCESS,
1444 }))
1445
1446 self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1447 retries=1))
1448 self.assertHandler(rlib2.R_2_jobs_id)
1449 self.assertItems(["22793"])
1450
1451 self.assertEqual(self.rapi.CountPending(), 0)
1452
1453 def testWaitForJobCompletionEmptyResponse(self):
1454 self.rapi.AddResponse("{}")
1455 self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1456 retries=10))
1457 self.assertHandler(rlib2.R_2_jobs_id)
1458 self.assertItems(["22793"])
1459
1460 self.assertEqual(self.rapi.CountPending(), 0)
1461
1462 def testWaitForJobCompletionOutOfRetries(self):
1463 for retries in [3, 10, 21]:
1464 for _ in range(retries):
1465 self.rapi.AddResponse(serializer.DumpJson({
1466 "status": constants.JOB_STATUS_RUNNING,
1467 }))
1468
1469 self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1470 retries=retries - 1))
1471 self.assertHandler(rlib2.R_2_jobs_id)
1472 self.assertItems(["30948"])
1473
1474 self.assertEqual(self.rapi.CountPending(), 1)
1475 self.rapi.ResetResponses()
1476
1477 def testWaitForJobCompletionSuccessAndFailure(self):
1478 for retries in [1, 4, 13]:
1479 for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1480 (True, constants.JOB_STATUS_SUCCESS)]:
1481 for _ in range(retries):
1482 self.rapi.AddResponse(serializer.DumpJson({
1483 "status": constants.JOB_STATUS_RUNNING,
1484 }))
1485
1486 self.rapi.AddResponse(serializer.DumpJson({
1487 "status": end_status,
1488 }))
1489
1490 result = self.client.WaitForJobCompletion(3187, period=None,
1491 retries=retries + 1)
1492 self.assertEqual(result, success)
1493 self.assertHandler(rlib2.R_2_jobs_id)
1494 self.assertItems(["3187"])
1495
1496 self.assertEqual(self.rapi.CountPending(), 0)
1497
1498
1499 class RapiTestRunner(unittest.TextTestRunner):
1500 def run(self, *args):
1501 global _used_handlers
1502 assert _used_handlers is None
1503
1504 _used_handlers = set()
1505 try:
1506 # Run actual tests
1507 result = unittest.TextTestRunner.run(self, *args)
1508
1509 diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1510 _KNOWN_UNUSED)
1511 if diff:
1512 raise AssertionError("The following RAPI resources were not used by the"
1513 " RAPI client: %r" % utils.CommaJoin(diff))
1514 finally:
1515 # Reset global variable
1516 _used_handlers = None
1517
1518 return result
1519
1520
1521 if __name__ == "__main__":
1522 client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)