4 # Copyright (C) 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 RAPI client module"""
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
38 import ganeti.rapi.testutils
39 from ganeti.rapi import connector
40 from ganeti.rapi import rlib2
41 from ganeti.rapi import client
46 # List of resource handlers which aren't used by the RAPI client
52 # Global variable for collecting used handlers
56 class RapiMock(object):
58 self._mapper = connector.Mapper()
60 self._last_handler = None
61 self._last_req_data = None
63 def ResetResponses(self):
64 del self._responses[:]
66 def AddResponse(self, response, code=200):
67 self._responses.insert(0, (code, response))
69 def CountPending(self):
70 return len(self._responses)
72 def GetLastHandler(self):
73 return self._last_handler
75 def GetLastRequestData(self):
76 return self._last_req_data
78 def FetchResponse(self, path, method, headers, request_body):
79 self._last_req_data = request_body
82 (handler_cls, items, args) = self._mapper.getController(path)
84 # Record handler as used
85 _used_handlers.add(handler_cls)
87 self._last_handler = handler_cls(items, args, None)
88 if not hasattr(self._last_handler, method.upper()):
89 raise http.HttpNotImplemented(message="Method not implemented")
91 except http.HttpException, ex:
95 if not self._responses:
96 raise Exception("No responses")
98 (code, response) = self._responses.pop()
100 return (code, NotImplemented, response)
103 class TestConstants(unittest.TestCase):
105 self.assertEqual(client.GANETI_RAPI_PORT, constants.DEFAULT_RAPI_PORT)
106 self.assertEqual(client.GANETI_RAPI_VERSION, constants.RAPI_VERSION)
107 self.assertEqual(client.HTTP_APP_JSON, http.HTTP_APP_JSON)
108 self.assertEqual(client._REQ_DATA_VERSION_FIELD, rlib2._REQ_DATA_VERSION)
109 self.assertEqual(client.JOB_STATUS_QUEUED, constants.JOB_STATUS_QUEUED)
110 self.assertEqual(client.JOB_STATUS_WAITING, constants.JOB_STATUS_WAITING)
111 self.assertEqual(client.JOB_STATUS_CANCELING,
112 constants.JOB_STATUS_CANCELING)
113 self.assertEqual(client.JOB_STATUS_RUNNING, constants.JOB_STATUS_RUNNING)
114 self.assertEqual(client.JOB_STATUS_CANCELED, constants.JOB_STATUS_CANCELED)
115 self.assertEqual(client.JOB_STATUS_SUCCESS, constants.JOB_STATUS_SUCCESS)
116 self.assertEqual(client.JOB_STATUS_ERROR, constants.JOB_STATUS_ERROR)
117 self.assertEqual(client.JOB_STATUS_PENDING, constants.JOBS_PENDING)
118 self.assertEqual(client.JOB_STATUS_FINALIZED, constants.JOBS_FINALIZED)
119 self.assertEqual(client.JOB_STATUS_ALL, constants.JOB_STATUS_ALL)
122 self.assertEqual(client.NODE_EVAC_PRI, constants.NODE_EVAC_PRI)
123 self.assertEqual(client.NODE_EVAC_SEC, constants.NODE_EVAC_SEC)
124 self.assertEqual(client.NODE_EVAC_ALL, constants.NODE_EVAC_ALL)
127 self.assertEqual(client.JOB_STATUS_WAITLOCK, constants.JOB_STATUS_WAITING)
129 # RAPI feature strings
130 self.assertEqual(client._INST_CREATE_REQV1, rlib2._INST_CREATE_REQV1)
131 self.assertEqual(client.INST_CREATE_REQV1, rlib2._INST_CREATE_REQV1)
132 self.assertEqual(client._INST_REINSTALL_REQV1, rlib2._INST_REINSTALL_REQV1)
133 self.assertEqual(client.INST_REINSTALL_REQV1, rlib2._INST_REINSTALL_REQV1)
134 self.assertEqual(client._NODE_MIGRATE_REQV1, rlib2._NODE_MIGRATE_REQV1)
135 self.assertEqual(client.NODE_MIGRATE_REQV1, rlib2._NODE_MIGRATE_REQV1)
136 self.assertEqual(client._NODE_EVAC_RES1, rlib2._NODE_EVAC_RES1)
137 self.assertEqual(client.NODE_EVAC_RES1, rlib2._NODE_EVAC_RES1)
140 class RapiMockTest(unittest.TestCase):
142 (code, _, body) = RapiMock().FetchResponse("/foo", "GET", None, None)
143 self.assertEqual(code, 404)
144 self.assertTrue(body is None)
147 (code, _, body) = RapiMock().FetchResponse("/version", "POST", None, None)
148 self.assertEqual(code, 501)
149 self.assertEqual(body, "Method not implemented")
153 rapi.AddResponse("2")
154 (code, _, response) = rapi.FetchResponse("/version", "GET", None, None)
155 self.assertEqual(200, code)
156 self.assertEqual("2", response)
157 self.failUnless(isinstance(rapi.GetLastHandler(), rlib2.R_version))
160 def _FakeNoSslPycurlVersion():
161 # Note: incomplete version tuple
162 return (3, "7.16.0", 462848, "mysystem", 1581, None, 0)
165 def _FakeFancySslPycurlVersion():
166 # Note: incomplete version tuple
167 return (3, "7.16.0", 462848, "mysystem", 1581, "FancySSL/1.2.3", 0)
170 def _FakeOpenSslPycurlVersion():
171 # Note: incomplete version tuple
172 return (2, "7.15.5", 462597, "othersystem", 668, "OpenSSL/0.9.8c", 0)
175 def _FakeGnuTlsPycurlVersion():
176 # Note: incomplete version tuple
177 return (3, "7.18.0", 463360, "somesystem", 1581, "GnuTLS/2.0.4", 0)
180 class TestExtendedConfig(unittest.TestCase):
182 cl = client.GanetiRapiClient("master.example.com",
183 username="user", password="pw",
184 curl_factory=lambda: rapi.testutils.FakeCurl(RapiMock()))
186 curl = cl._CreateCurl()
187 self.assertEqual(curl.getopt(pycurl.HTTPAUTH), pycurl.HTTPAUTH_BASIC)
188 self.assertEqual(curl.getopt(pycurl.USERPWD), "user:pw")
190 def testInvalidAuth(self):
192 self.assertRaises(client.Error, client.GanetiRapiClient,
193 "master-a.example.com", password="pw")
195 self.assertRaises(client.Error, client.GanetiRapiClient,
196 "master-b.example.com", username="user")
198 def testCertVerifyInvalidCombinations(self):
199 self.assertRaises(client.Error, client.GenericCurlConfig,
200 use_curl_cabundle=True, cafile="cert1.pem")
201 self.assertRaises(client.Error, client.GenericCurlConfig,
202 use_curl_cabundle=True, capath="certs/")
203 self.assertRaises(client.Error, client.GenericCurlConfig,
204 use_curl_cabundle=True,
205 cafile="cert1.pem", capath="certs/")
207 def testProxySignalVerifyHostname(self):
208 for use_gnutls in [False, True]:
210 pcverfn = _FakeGnuTlsPycurlVersion
212 pcverfn = _FakeOpenSslPycurlVersion
214 for proxy in ["", "http://127.0.0.1:1234"]:
215 for use_signal in [False, True]:
216 for verify_hostname in [False, True]:
217 cfgfn = client.GenericCurlConfig(proxy=proxy, use_signal=use_signal,
218 verify_hostname=verify_hostname,
219 _pycurl_version_fn=pcverfn)
221 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
222 cl = client.GanetiRapiClient("master.example.com",
223 curl_config_fn=cfgfn,
224 curl_factory=curl_factory)
226 curl = cl._CreateCurl()
227 self.assertEqual(curl.getopt(pycurl.PROXY), proxy)
228 self.assertEqual(curl.getopt(pycurl.NOSIGNAL), not use_signal)
231 self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 2)
233 self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 0)
235 def testNoCertVerify(self):
236 cfgfn = client.GenericCurlConfig()
238 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
239 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
240 curl_factory=curl_factory)
242 curl = cl._CreateCurl()
243 self.assertFalse(curl.getopt(pycurl.SSL_VERIFYPEER))
244 self.assertFalse(curl.getopt(pycurl.CAINFO))
245 self.assertFalse(curl.getopt(pycurl.CAPATH))
247 def testCertVerifyCurlBundle(self):
248 cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
250 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
251 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
252 curl_factory=curl_factory)
254 curl = cl._CreateCurl()
255 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
256 self.assertFalse(curl.getopt(pycurl.CAINFO))
257 self.assertFalse(curl.getopt(pycurl.CAPATH))
259 def testCertVerifyCafile(self):
260 mycert = "/tmp/some/UNUSED/cert/file.pem"
261 cfgfn = client.GenericCurlConfig(cafile=mycert)
263 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
264 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
265 curl_factory=curl_factory)
267 curl = cl._CreateCurl()
268 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
269 self.assertEqual(curl.getopt(pycurl.CAINFO), mycert)
270 self.assertFalse(curl.getopt(pycurl.CAPATH))
272 def testCertVerifyCapath(self):
273 certdir = "/tmp/some/UNUSED/cert/directory"
274 pcverfn = _FakeOpenSslPycurlVersion
275 cfgfn = client.GenericCurlConfig(capath=certdir,
276 _pycurl_version_fn=pcverfn)
278 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
279 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
280 curl_factory=curl_factory)
282 curl = cl._CreateCurl()
283 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
284 self.assertEqual(curl.getopt(pycurl.CAPATH), certdir)
285 self.assertFalse(curl.getopt(pycurl.CAINFO))
287 def testCertVerifyCapathGnuTls(self):
288 certdir = "/tmp/some/UNUSED/cert/directory"
289 pcverfn = _FakeGnuTlsPycurlVersion
290 cfgfn = client.GenericCurlConfig(capath=certdir,
291 _pycurl_version_fn=pcverfn)
293 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
294 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
295 curl_factory=curl_factory)
297 self.assertRaises(client.Error, cl._CreateCurl)
299 def testCertVerifyNoSsl(self):
300 certdir = "/tmp/some/UNUSED/cert/directory"
301 pcverfn = _FakeNoSslPycurlVersion
302 cfgfn = client.GenericCurlConfig(capath=certdir,
303 _pycurl_version_fn=pcverfn)
305 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
306 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
307 curl_factory=curl_factory)
309 self.assertRaises(client.Error, cl._CreateCurl)
311 def testCertVerifyFancySsl(self):
312 certdir = "/tmp/some/UNUSED/cert/directory"
313 pcverfn = _FakeFancySslPycurlVersion
314 cfgfn = client.GenericCurlConfig(capath=certdir,
315 _pycurl_version_fn=pcverfn)
317 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
318 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
319 curl_factory=curl_factory)
321 self.assertRaises(NotImplementedError, cl._CreateCurl)
323 def testCertVerifyCapath(self):
324 for connect_timeout in [None, 1, 5, 10, 30, 60, 300]:
325 for timeout in [None, 1, 30, 60, 3600, 24 * 3600]:
326 cfgfn = client.GenericCurlConfig(connect_timeout=connect_timeout,
329 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
330 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
331 curl_factory=curl_factory)
333 curl = cl._CreateCurl()
334 self.assertEqual(curl.getopt(pycurl.CONNECTTIMEOUT), connect_timeout)
335 self.assertEqual(curl.getopt(pycurl.TIMEOUT), timeout)
338 class GanetiRapiClientTests(testutils.GanetiTestCase):
340 testutils.GanetiTestCase.setUp(self)
342 self.rapi = RapiMock()
343 self.curl = rapi.testutils.FakeCurl(self.rapi)
344 self.client = client.GanetiRapiClient("master.example.com",
345 curl_factory=lambda: self.curl)
347 def assertHandler(self, handler_cls):
348 self.failUnless(isinstance(self.rapi.GetLastHandler(), handler_cls))
350 def assertQuery(self, key, value):
351 self.assertEqual(value, self.rapi.GetLastHandler().queryargs.get(key, None))
353 def assertItems(self, items):
354 self.assertEqual(items, self.rapi.GetLastHandler().items)
356 def assertBulk(self):
357 self.assertTrue(self.rapi.GetLastHandler().useBulk())
359 def assertDryRun(self):
360 self.assertTrue(self.rapi.GetLastHandler().dryRun())
362 def assertUseForce(self):
363 self.assertTrue(self.rapi.GetLastHandler().useForce())
365 def testEncodeQuery(self):
382 self.assertEqualValues(self.client._EncodeQuery(query),
386 for i in [[1, 2, 3], {"moo": "boo"}, (1, 2, 3)]:
387 self.assertRaises(ValueError, self.client._EncodeQuery, [("x", i)])
389 def testCurlSettings(self):
390 self.rapi.AddResponse("2")
391 self.assertEqual(2, self.client.GetVersion())
392 self.assertHandler(rlib2.R_version)
394 # Signals should be disabled by default
395 self.assert_(self.curl.getopt(pycurl.NOSIGNAL))
397 # No auth and no proxy
398 self.assertFalse(self.curl.getopt(pycurl.USERPWD))
399 self.assert_(self.curl.getopt(pycurl.PROXY) is None)
401 # Content-type is required for requests
402 headers = self.curl.getopt(pycurl.HTTPHEADER)
403 self.assert_("Content-type: application/json" in headers)
405 def testHttpError(self):
406 self.rapi.AddResponse(None, code=404)
408 self.client.GetJobStatus(15140)
409 except client.GanetiApiError, err:
410 self.assertEqual(err.code, 404)
412 self.fail("Didn't raise exception")
414 def testGetVersion(self):
415 self.rapi.AddResponse("2")
416 self.assertEqual(2, self.client.GetVersion())
417 self.assertHandler(rlib2.R_version)
419 def testGetFeatures(self):
420 for features in [[], ["foo", "bar", "baz"]]:
421 self.rapi.AddResponse(serializer.DumpJson(features))
422 self.assertEqual(features, self.client.GetFeatures())
423 self.assertHandler(rlib2.R_2_features)
425 def testGetFeaturesNotFound(self):
426 self.rapi.AddResponse(None, code=404)
427 self.assertEqual([], self.client.GetFeatures())
429 def testGetOperatingSystems(self):
430 self.rapi.AddResponse("[\"beos\"]")
431 self.assertEqual(["beos"], self.client.GetOperatingSystems())
432 self.assertHandler(rlib2.R_2_os)
434 def testGetClusterTags(self):
435 self.rapi.AddResponse("[\"tag\"]")
436 self.assertEqual(["tag"], self.client.GetClusterTags())
437 self.assertHandler(rlib2.R_2_tags)
439 def testAddClusterTags(self):
440 self.rapi.AddResponse("1234")
441 self.assertEqual(1234,
442 self.client.AddClusterTags(["awesome"], dry_run=True))
443 self.assertHandler(rlib2.R_2_tags)
445 self.assertQuery("tag", ["awesome"])
447 def testDeleteClusterTags(self):
448 self.rapi.AddResponse("5107")
449 self.assertEqual(5107, self.client.DeleteClusterTags(["awesome"],
451 self.assertHandler(rlib2.R_2_tags)
453 self.assertQuery("tag", ["awesome"])
455 def testGetInfo(self):
456 self.rapi.AddResponse("{}")
457 self.assertEqual({}, self.client.GetInfo())
458 self.assertHandler(rlib2.R_2_info)
460 def testGetInstances(self):
461 self.rapi.AddResponse("[]")
462 self.assertEqual([], self.client.GetInstances(bulk=True))
463 self.assertHandler(rlib2.R_2_instances)
466 def testGetInstance(self):
467 self.rapi.AddResponse("[]")
468 self.assertEqual([], self.client.GetInstance("instance"))
469 self.assertHandler(rlib2.R_2_instances_name)
470 self.assertItems(["instance"])
472 def testGetInstanceInfo(self):
473 self.rapi.AddResponse("21291")
474 self.assertEqual(21291, self.client.GetInstanceInfo("inst3"))
475 self.assertHandler(rlib2.R_2_instances_name_info)
476 self.assertItems(["inst3"])
477 self.assertQuery("static", None)
479 self.rapi.AddResponse("3428")
480 self.assertEqual(3428, self.client.GetInstanceInfo("inst31", static=False))
481 self.assertHandler(rlib2.R_2_instances_name_info)
482 self.assertItems(["inst31"])
483 self.assertQuery("static", ["0"])
485 self.rapi.AddResponse("15665")
486 self.assertEqual(15665, self.client.GetInstanceInfo("inst32", static=True))
487 self.assertHandler(rlib2.R_2_instances_name_info)
488 self.assertItems(["inst32"])
489 self.assertQuery("static", ["1"])
491 def testInstancesMultiAlloc(self):
493 constants.JOB_IDS_KEY: ["23423"],
494 opcodes.OpInstanceMultiAlloc.ALLOCATABLE_KEY: ["foobar"],
495 opcodes.OpInstanceMultiAlloc.FAILED_KEY: ["foobar2"],
497 self.rapi.AddResponse(serializer.DumpJson(response))
498 insts = [self.client.InstanceAllocation("create", "foobar",
500 self.client.InstanceAllocation("create", "foobar2",
501 "drbd8", [{"size": 100}], [])]
502 resp = self.client.InstancesMultiAlloc(insts)
503 self.assertEqual(resp, response)
504 self.assertHandler(rlib2.R_2_instances_multi_alloc)
506 def testCreateInstanceOldVersion(self):
507 # The old request format, version 0, is no longer supported
508 self.rapi.AddResponse(None, code=404)
509 self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
510 "create", "inst1.example.com", "plain", [], [])
511 self.assertEqual(self.rapi.CountPending(), 0)
513 def testCreateInstance(self):
514 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
515 self.rapi.AddResponse("23030")
516 job_id = self.client.CreateInstance("create", "inst1.example.com",
517 "plain", [], [], dry_run=True)
518 self.assertEqual(job_id, 23030)
519 self.assertHandler(rlib2.R_2_instances)
522 data = serializer.LoadJson(self.rapi.GetLastRequestData())
524 for field in ["dry_run", "beparams", "hvparams", "start"]:
525 self.assertFalse(field in data)
527 self.assertEqual(data["name"], "inst1.example.com")
528 self.assertEqual(data["disk_template"], "plain")
530 def testCreateInstance2(self):
531 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
532 self.rapi.AddResponse("24740")
533 job_id = self.client.CreateInstance("import", "inst2.example.com",
534 "drbd8", [{"size": 100,}],
535 [{}, {"bridge": "br1", }],
536 dry_run=False, start=True,
537 pnode="node1", snode="node9",
539 self.assertEqual(job_id, 24740)
540 self.assertHandler(rlib2.R_2_instances)
542 data = serializer.LoadJson(self.rapi.GetLastRequestData())
543 self.assertEqual(data[rlib2._REQ_DATA_VERSION], 1)
544 self.assertEqual(data["name"], "inst2.example.com")
545 self.assertEqual(data["disk_template"], "drbd8")
546 self.assertEqual(data["start"], True)
547 self.assertEqual(data["ip_check"], False)
548 self.assertEqualValues(data["disks"], [{"size": 100,}])
549 self.assertEqualValues(data["nics"], [{}, {"bridge": "br1", }])
551 def testDeleteInstance(self):
552 self.rapi.AddResponse("1234")
553 self.assertEqual(1234, self.client.DeleteInstance("instance", dry_run=True))
554 self.assertHandler(rlib2.R_2_instances_name)
555 self.assertItems(["instance"])
558 def testGetInstanceTags(self):
559 self.rapi.AddResponse("[]")
560 self.assertEqual([], self.client.GetInstanceTags("fooinstance"))
561 self.assertHandler(rlib2.R_2_instances_name_tags)
562 self.assertItems(["fooinstance"])
564 def testAddInstanceTags(self):
565 self.rapi.AddResponse("1234")
566 self.assertEqual(1234,
567 self.client.AddInstanceTags("fooinstance", ["awesome"], dry_run=True))
568 self.assertHandler(rlib2.R_2_instances_name_tags)
569 self.assertItems(["fooinstance"])
571 self.assertQuery("tag", ["awesome"])
573 def testDeleteInstanceTags(self):
574 self.rapi.AddResponse("25826")
575 self.assertEqual(25826, self.client.DeleteInstanceTags("foo", ["awesome"],
577 self.assertHandler(rlib2.R_2_instances_name_tags)
578 self.assertItems(["foo"])
580 self.assertQuery("tag", ["awesome"])
582 def testRebootInstance(self):
583 self.rapi.AddResponse("6146")
584 job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
585 ignore_secondaries=True, dry_run=True)
586 self.assertEqual(6146, job_id)
587 self.assertHandler(rlib2.R_2_instances_name_reboot)
588 self.assertItems(["i-bar"])
590 self.assertQuery("type", ["hard"])
591 self.assertQuery("ignore_secondaries", ["1"])
593 def testShutdownInstance(self):
594 self.rapi.AddResponse("1487")
595 self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
597 self.assertHandler(rlib2.R_2_instances_name_shutdown)
598 self.assertItems(["foo-instance"])
601 def testStartupInstance(self):
602 self.rapi.AddResponse("27149")
603 self.assertEqual(27149, self.client.StartupInstance("bar-instance",
605 self.assertHandler(rlib2.R_2_instances_name_startup)
606 self.assertItems(["bar-instance"])
609 def testReinstallInstance(self):
610 self.rapi.AddResponse(serializer.DumpJson([]))
611 self.rapi.AddResponse("19119")
612 self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
615 self.assertHandler(rlib2.R_2_instances_name_reinstall)
616 self.assertItems(["baz-instance"])
617 self.assertQuery("os", ["DOS"])
618 self.assertQuery("nostartup", ["1"])
619 self.assertEqual(self.rapi.CountPending(), 0)
621 def testReinstallInstanceNew(self):
622 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
623 self.rapi.AddResponse("25689")
624 self.assertEqual(25689, self.client.ReinstallInstance("moo-instance",
627 self.assertHandler(rlib2.R_2_instances_name_reinstall)
628 self.assertItems(["moo-instance"])
629 data = serializer.LoadJson(self.rapi.GetLastRequestData())
630 self.assertEqual(len(data), 2)
631 self.assertEqual(data["os"], "Debian")
632 self.assertEqual(data["start"], False)
633 self.assertEqual(self.rapi.CountPending(), 0)
635 def testReinstallInstanceWithOsparams1(self):
636 self.rapi.AddResponse(serializer.DumpJson([]))
637 self.assertRaises(client.GanetiApiError, self.client.ReinstallInstance,
638 "doo-instance", osparams={"x": "y"})
639 self.assertEqual(self.rapi.CountPending(), 0)
641 def testReinstallInstanceWithOsparams2(self):
646 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
647 self.rapi.AddResponse("1717")
648 self.assertEqual(1717, self.client.ReinstallInstance("zoo-instance",
650 self.assertHandler(rlib2.R_2_instances_name_reinstall)
651 self.assertItems(["zoo-instance"])
652 data = serializer.LoadJson(self.rapi.GetLastRequestData())
653 self.assertEqual(len(data), 2)
654 self.assertEqual(data["osparams"], osparams)
655 self.assertEqual(data["start"], True)
656 self.assertEqual(self.rapi.CountPending(), 0)
658 def testReplaceInstanceDisks(self):
659 self.rapi.AddResponse("999")
660 job_id = self.client.ReplaceInstanceDisks("instance-name",
661 disks=[0, 1], iallocator="hail")
662 self.assertEqual(999, job_id)
663 self.assertHandler(rlib2.R_2_instances_name_replace_disks)
664 self.assertItems(["instance-name"])
665 self.assertQuery("disks", ["0,1"])
666 self.assertQuery("mode", ["replace_auto"])
667 self.assertQuery("iallocator", ["hail"])
669 self.rapi.AddResponse("1000")
670 job_id = self.client.ReplaceInstanceDisks("instance-bar",
671 disks=[1], mode="replace_on_secondary", remote_node="foo-node")
672 self.assertEqual(1000, job_id)
673 self.assertItems(["instance-bar"])
674 self.assertQuery("disks", ["1"])
675 self.assertQuery("remote_node", ["foo-node"])
677 self.rapi.AddResponse("5175")
678 self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
679 self.assertItems(["instance-moo"])
680 self.assertQuery("disks", None)
682 def testPrepareExport(self):
683 self.rapi.AddResponse("8326")
684 self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
685 self.assertHandler(rlib2.R_2_instances_name_prepare_export)
686 self.assertItems(["inst1"])
687 self.assertQuery("mode", ["local"])
689 def testExportInstance(self):
690 self.rapi.AddResponse("19695")
691 job_id = self.client.ExportInstance("inst2", "local", "nodeX",
693 self.assertEqual(job_id, 19695)
694 self.assertHandler(rlib2.R_2_instances_name_export)
695 self.assertItems(["inst2"])
697 data = serializer.LoadJson(self.rapi.GetLastRequestData())
698 self.assertEqual(data["mode"], "local")
699 self.assertEqual(data["destination"], "nodeX")
700 self.assertEqual(data["shutdown"], True)
702 def testMigrateInstanceDefaults(self):
703 self.rapi.AddResponse("24873")
704 job_id = self.client.MigrateInstance("inst91")
705 self.assertEqual(job_id, 24873)
706 self.assertHandler(rlib2.R_2_instances_name_migrate)
707 self.assertItems(["inst91"])
709 data = serializer.LoadJson(self.rapi.GetLastRequestData())
710 self.assertFalse(data)
712 def testMigrateInstance(self):
713 for mode in constants.HT_MIGRATION_MODES:
714 for cleanup in [False, True]:
715 self.rapi.AddResponse("31910")
716 job_id = self.client.MigrateInstance("inst289", mode=mode,
718 self.assertEqual(job_id, 31910)
719 self.assertHandler(rlib2.R_2_instances_name_migrate)
720 self.assertItems(["inst289"])
722 data = serializer.LoadJson(self.rapi.GetLastRequestData())
723 self.assertEqual(len(data), 2)
724 self.assertEqual(data["mode"], mode)
725 self.assertEqual(data["cleanup"], cleanup)
727 def testFailoverInstanceDefaults(self):
728 self.rapi.AddResponse("7639")
729 job_id = self.client.FailoverInstance("inst13579")
730 self.assertEqual(job_id, 7639)
731 self.assertHandler(rlib2.R_2_instances_name_failover)
732 self.assertItems(["inst13579"])
734 data = serializer.LoadJson(self.rapi.GetLastRequestData())
735 self.assertFalse(data)
737 def testFailoverInstance(self):
738 for iallocator in ["dumb", "hail"]:
739 for ignore_consistency in [False, True]:
740 for target_node in ["node-a", "node2"]:
741 self.rapi.AddResponse("19161")
743 self.client.FailoverInstance("inst251", iallocator=iallocator,
744 ignore_consistency=ignore_consistency,
745 target_node=target_node)
746 self.assertEqual(job_id, 19161)
747 self.assertHandler(rlib2.R_2_instances_name_failover)
748 self.assertItems(["inst251"])
750 data = serializer.LoadJson(self.rapi.GetLastRequestData())
751 self.assertEqual(len(data), 3)
752 self.assertEqual(data["iallocator"], iallocator)
753 self.assertEqual(data["ignore_consistency"], ignore_consistency)
754 self.assertEqual(data["target_node"], target_node)
755 self.assertEqual(self.rapi.CountPending(), 0)
757 def testRenameInstanceDefaults(self):
758 new_name = "newnametha7euqu"
759 self.rapi.AddResponse("8791")
760 job_id = self.client.RenameInstance("inst18821", new_name)
761 self.assertEqual(job_id, 8791)
762 self.assertHandler(rlib2.R_2_instances_name_rename)
763 self.assertItems(["inst18821"])
765 data = serializer.LoadJson(self.rapi.GetLastRequestData())
766 self.assertEqualValues(data, {"new_name": new_name, })
768 def testRenameInstance(self):
769 new_name = "new-name-yiux1iin"
770 for ip_check in [False, True]:
771 for name_check in [False, True]:
772 self.rapi.AddResponse("24776")
773 job_id = self.client.RenameInstance("inst20967", new_name,
775 name_check=name_check)
776 self.assertEqual(job_id, 24776)
777 self.assertHandler(rlib2.R_2_instances_name_rename)
778 self.assertItems(["inst20967"])
780 data = serializer.LoadJson(self.rapi.GetLastRequestData())
781 self.assertEqual(len(data), 3)
782 self.assertEqual(data["new_name"], new_name)
783 self.assertEqual(data["ip_check"], ip_check)
784 self.assertEqual(data["name_check"], name_check)
786 def testGetJobs(self):
787 self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
788 ' { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
789 self.assertEqual([123, 124], self.client.GetJobs())
790 self.assertHandler(rlib2.R_2_jobs)
792 def testGetJobStatus(self):
793 self.rapi.AddResponse("{\"foo\": \"bar\"}")
794 self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
795 self.assertHandler(rlib2.R_2_jobs_id)
796 self.assertItems(["1234"])
798 def testWaitForJobChange(self):
799 fields = ["id", "summary"]
801 "job_info": [123, "something"],
805 self.rapi.AddResponse(serializer.DumpJson(expected))
806 result = self.client.WaitForJobChange(123, fields, [], -1)
807 self.assertEqualValues(expected, result)
808 self.assertHandler(rlib2.R_2_jobs_id_wait)
809 self.assertItems(["123"])
811 def testCancelJob(self):
812 self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
813 self.assertEqual([True, "Job 123 will be canceled"],
814 self.client.CancelJob(999, dry_run=True))
815 self.assertHandler(rlib2.R_2_jobs_id)
816 self.assertItems(["999"])
819 def testGetNodes(self):
820 self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
821 " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
822 self.assertEqual(["node1", "node2"], self.client.GetNodes())
823 self.assertHandler(rlib2.R_2_nodes)
825 self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
826 " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
827 self.assertEqual([{"id": "node1", "uri": "uri1"},
828 {"id": "node2", "uri": "uri2"}],
829 self.client.GetNodes(bulk=True))
830 self.assertHandler(rlib2.R_2_nodes)
833 def testGetNode(self):
834 self.rapi.AddResponse("{}")
835 self.assertEqual({}, self.client.GetNode("node-foo"))
836 self.assertHandler(rlib2.R_2_nodes_name)
837 self.assertItems(["node-foo"])
839 def testEvacuateNode(self):
840 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
841 self.rapi.AddResponse("9876")
842 job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
843 self.assertEqual(9876, job_id)
844 self.assertHandler(rlib2.R_2_nodes_name_evacuate)
845 self.assertItems(["node-1"])
846 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
847 { "remote_node": "node-2", })
848 self.assertEqual(self.rapi.CountPending(), 0)
850 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
851 self.rapi.AddResponse("8888")
852 job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True,
853 mode=constants.NODE_EVAC_ALL,
855 self.assertEqual(8888, job_id)
856 self.assertItems(["node-3"])
857 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()), {
858 "iallocator": "hail",
860 "early_release": True,
864 self.assertRaises(client.GanetiApiError,
865 self.client.EvacuateNode,
866 "node-4", iallocator="hail", remote_node="node-5")
867 self.assertEqual(self.rapi.CountPending(), 0)
869 def testEvacuateNodeOldResponse(self):
870 self.rapi.AddResponse(serializer.DumpJson([]))
871 self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
872 "node-4", accept_old=False)
873 self.assertEqual(self.rapi.CountPending(), 0)
875 for mode in [client.NODE_EVAC_PRI, client.NODE_EVAC_ALL]:
876 self.rapi.AddResponse(serializer.DumpJson([]))
877 self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
878 "node-4", accept_old=True, mode=mode)
879 self.assertEqual(self.rapi.CountPending(), 0)
881 self.rapi.AddResponse(serializer.DumpJson([]))
882 self.rapi.AddResponse(serializer.DumpJson("21533"))
883 result = self.client.EvacuateNode("node-3", iallocator="hail",
884 dry_run=True, accept_old=True,
885 mode=client.NODE_EVAC_SEC,
887 self.assertEqual(result, "21533")
888 self.assertItems(["node-3"])
889 self.assertQuery("iallocator", ["hail"])
890 self.assertQuery("early_release", ["1"])
891 self.assertFalse(self.rapi.GetLastRequestData())
893 self.assertEqual(self.rapi.CountPending(), 0)
895 def testMigrateNode(self):
896 self.rapi.AddResponse(serializer.DumpJson([]))
897 self.rapi.AddResponse("1111")
898 self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
899 self.assertHandler(rlib2.R_2_nodes_name_migrate)
900 self.assertItems(["node-a"])
901 self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
903 self.assertFalse(self.rapi.GetLastRequestData())
905 self.rapi.AddResponse(serializer.DumpJson([]))
906 self.rapi.AddResponse("1112")
907 self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
909 self.assertHandler(rlib2.R_2_nodes_name_migrate)
910 self.assertItems(["node-a"])
911 self.assertQuery("mode", ["live"])
913 self.assertFalse(self.rapi.GetLastRequestData())
915 self.rapi.AddResponse(serializer.DumpJson([]))
916 self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
917 "node-c", target_node="foonode")
918 self.assertEqual(self.rapi.CountPending(), 0)
920 def testMigrateNodeBodyData(self):
921 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
922 self.rapi.AddResponse("27539")
923 self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
925 self.assertHandler(rlib2.R_2_nodes_name_migrate)
926 self.assertItems(["node-a"])
927 self.assertFalse(self.rapi.GetLastHandler().queryargs)
928 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
931 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
932 self.rapi.AddResponse("14219")
933 self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
936 self.assertHandler(rlib2.R_2_nodes_name_migrate)
937 self.assertItems(["node-x"])
939 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
940 { "target_node": "node9", "iallocator": "ial", })
942 self.assertEqual(self.rapi.CountPending(), 0)
944 def testGetNodeRole(self):
945 self.rapi.AddResponse("\"master\"")
946 self.assertEqual("master", self.client.GetNodeRole("node-a"))
947 self.assertHandler(rlib2.R_2_nodes_name_role)
948 self.assertItems(["node-a"])
950 def testSetNodeRole(self):
951 self.rapi.AddResponse("789")
952 self.assertEqual(789,
953 self.client.SetNodeRole("node-foo", "master-candidate", force=True))
954 self.assertHandler(rlib2.R_2_nodes_name_role)
955 self.assertItems(["node-foo"])
956 self.assertQuery("force", ["1"])
957 self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
959 def testPowercycleNode(self):
960 self.rapi.AddResponse("23051")
961 self.assertEqual(23051,
962 self.client.PowercycleNode("node5468", force=True))
963 self.assertHandler(rlib2.R_2_nodes_name_powercycle)
964 self.assertItems(["node5468"])
965 self.assertQuery("force", ["1"])
966 self.assertFalse(self.rapi.GetLastRequestData())
967 self.assertEqual(self.rapi.CountPending(), 0)
969 def testModifyNode(self):
970 self.rapi.AddResponse("3783")
971 job_id = self.client.ModifyNode("node16979.example.com", drained=True)
972 self.assertEqual(job_id, 3783)
973 self.assertHandler(rlib2.R_2_nodes_name_modify)
974 self.assertItems(["node16979.example.com"])
975 self.assertEqual(self.rapi.CountPending(), 0)
977 def testGetNodeStorageUnits(self):
978 self.rapi.AddResponse("42")
980 self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
981 self.assertHandler(rlib2.R_2_nodes_name_storage)
982 self.assertItems(["node-x"])
983 self.assertQuery("storage_type", ["lvm-pv"])
984 self.assertQuery("output_fields", ["fields"])
986 def testModifyNodeStorageUnits(self):
987 self.rapi.AddResponse("14")
989 self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
990 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
991 self.assertItems(["node-z"])
992 self.assertQuery("storage_type", ["lvm-pv"])
993 self.assertQuery("name", ["hda"])
994 self.assertQuery("allocatable", None)
996 for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
997 self.rapi.AddResponse("7205")
998 job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
999 allocatable=allocatable)
1000 self.assertEqual(7205, job_id)
1001 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1002 self.assertItems(["node-z"])
1003 self.assertQuery("storage_type", ["lvm-pv"])
1004 self.assertQuery("name", ["hda"])
1005 self.assertQuery("allocatable", [query_allocatable])
1007 def testRepairNodeStorageUnits(self):
1008 self.rapi.AddResponse("99")
1009 self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
1011 self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
1012 self.assertItems(["node-z"])
1013 self.assertQuery("storage_type", ["lvm-pv"])
1014 self.assertQuery("name", ["hda"])
1016 def testGetNodeTags(self):
1017 self.rapi.AddResponse("[\"fry\", \"bender\"]")
1018 self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
1019 self.assertHandler(rlib2.R_2_nodes_name_tags)
1020 self.assertItems(["node-k"])
1022 def testAddNodeTags(self):
1023 self.rapi.AddResponse("1234")
1024 self.assertEqual(1234,
1025 self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
1026 self.assertHandler(rlib2.R_2_nodes_name_tags)
1027 self.assertItems(["node-v"])
1029 self.assertQuery("tag", ["awesome"])
1031 def testDeleteNodeTags(self):
1032 self.rapi.AddResponse("16861")
1033 self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1035 self.assertHandler(rlib2.R_2_nodes_name_tags)
1036 self.assertItems(["node-w"])
1038 self.assertQuery("tag", ["awesome"])
1040 def testGetGroups(self):
1041 groups = [{"name": "group1",
1042 "uri": "/2/groups/group1",
1045 "uri": "/2/groups/group2",
1048 self.rapi.AddResponse(serializer.DumpJson(groups))
1049 self.assertEqual(["group1", "group2"], self.client.GetGroups())
1050 self.assertHandler(rlib2.R_2_groups)
1052 def testGetGroupsBulk(self):
1053 groups = [{"name": "group1",
1054 "uri": "/2/groups/group1",
1056 "node_list": ["gnt1.test",
1061 "uri": "/2/groups/group2",
1063 "node_list": ["gnt3.test",
1067 self.rapi.AddResponse(serializer.DumpJson(groups))
1069 self.assertEqual(groups, self.client.GetGroups(bulk=True))
1070 self.assertHandler(rlib2.R_2_groups)
1073 def testGetGroup(self):
1074 group = {"ctime": None,
1077 self.rapi.AddResponse(serializer.DumpJson(group))
1078 self.assertEqual({"ctime": None, "name": "default"},
1079 self.client.GetGroup("default"))
1080 self.assertHandler(rlib2.R_2_groups_name)
1081 self.assertItems(["default"])
1083 def testCreateGroup(self):
1084 self.rapi.AddResponse("12345")
1085 job_id = self.client.CreateGroup("newgroup", dry_run=True)
1086 self.assertEqual(job_id, 12345)
1087 self.assertHandler(rlib2.R_2_groups)
1090 def testDeleteGroup(self):
1091 self.rapi.AddResponse("12346")
1092 job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1093 self.assertEqual(job_id, 12346)
1094 self.assertHandler(rlib2.R_2_groups_name)
1097 def testRenameGroup(self):
1098 self.rapi.AddResponse("12347")
1099 job_id = self.client.RenameGroup("oldname", "newname")
1100 self.assertEqual(job_id, 12347)
1101 self.assertHandler(rlib2.R_2_groups_name_rename)
1103 def testModifyGroup(self):
1104 self.rapi.AddResponse("12348")
1105 job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1106 self.assertEqual(job_id, 12348)
1107 self.assertHandler(rlib2.R_2_groups_name_modify)
1109 def testAssignGroupNodes(self):
1110 self.rapi.AddResponse("12349")
1111 job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1112 force=True, dry_run=True)
1113 self.assertEqual(job_id, 12349)
1114 self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1116 self.assertUseForce()
1118 def testModifyInstance(self):
1119 self.rapi.AddResponse("23681")
1120 job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1121 self.assertEqual(job_id, 23681)
1122 self.assertItems(["inst7210"])
1123 self.assertHandler(rlib2.R_2_instances_name_modify)
1124 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1125 { "os_name": "linux", })
1127 def testModifyCluster(self):
1128 for mnh in [None, False, True]:
1129 self.rapi.AddResponse("14470")
1130 self.assertEqual(14470,
1131 self.client.ModifyCluster(maintain_node_health=mnh))
1132 self.assertHandler(rlib2.R_2_cluster_modify)
1133 self.assertItems([])
1134 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1135 self.assertEqual(len(data), 1)
1136 self.assertEqual(data["maintain_node_health"], mnh)
1137 self.assertEqual(self.rapi.CountPending(), 0)
1139 def testRedistributeConfig(self):
1140 self.rapi.AddResponse("3364")
1141 job_id = self.client.RedistributeConfig()
1142 self.assertEqual(job_id, 3364)
1143 self.assertItems([])
1144 self.assertHandler(rlib2.R_2_redist_config)
1146 def testActivateInstanceDisks(self):
1147 self.rapi.AddResponse("23547")
1148 job_id = self.client.ActivateInstanceDisks("inst28204")
1149 self.assertEqual(job_id, 23547)
1150 self.assertItems(["inst28204"])
1151 self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1152 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1154 def testActivateInstanceDisksIgnoreSize(self):
1155 self.rapi.AddResponse("11044")
1156 job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1157 self.assertEqual(job_id, 11044)
1158 self.assertItems(["inst28204"])
1159 self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1160 self.assertQuery("ignore_size", ["1"])
1162 def testDeactivateInstanceDisks(self):
1163 self.rapi.AddResponse("14591")
1164 job_id = self.client.DeactivateInstanceDisks("inst28234")
1165 self.assertEqual(job_id, 14591)
1166 self.assertItems(["inst28234"])
1167 self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1168 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1170 def testRecreateInstanceDisks(self):
1171 self.rapi.AddResponse("13553")
1172 job_id = self.client.RecreateInstanceDisks("inst23153")
1173 self.assertEqual(job_id, 13553)
1174 self.assertItems(["inst23153"])
1175 self.assertHandler(rlib2.R_2_instances_name_recreate_disks)
1176 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1178 def testGetInstanceConsole(self):
1179 self.rapi.AddResponse("26876")
1180 job_id = self.client.GetInstanceConsole("inst21491")
1181 self.assertEqual(job_id, 26876)
1182 self.assertItems(["inst21491"])
1183 self.assertHandler(rlib2.R_2_instances_name_console)
1184 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1185 self.assertFalse(self.rapi.GetLastRequestData())
1187 def testGrowInstanceDisk(self):
1188 for idx, wait_for_sync in enumerate([None, False, True]):
1189 amount = 128 + (512 * idx)
1190 self.assertEqual(self.rapi.CountPending(), 0)
1191 self.rapi.AddResponse("30783")
1192 self.assertEqual(30783,
1193 self.client.GrowInstanceDisk("eze8ch", idx, amount,
1194 wait_for_sync=wait_for_sync))
1195 self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1196 self.assertItems(["eze8ch", str(idx)])
1197 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1198 if wait_for_sync is None:
1199 self.assertEqual(len(data), 1)
1200 self.assert_("wait_for_sync" not in data)
1202 self.assertEqual(len(data), 2)
1203 self.assertEqual(data["wait_for_sync"], wait_for_sync)
1204 self.assertEqual(data["amount"], amount)
1205 self.assertEqual(self.rapi.CountPending(), 0)
1207 def testGetGroupTags(self):
1208 self.rapi.AddResponse("[]")
1209 self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1210 self.assertHandler(rlib2.R_2_groups_name_tags)
1211 self.assertItems(["fooGroup"])
1213 def testAddGroupTags(self):
1214 self.rapi.AddResponse("1234")
1215 self.assertEqual(1234,
1216 self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1217 self.assertHandler(rlib2.R_2_groups_name_tags)
1218 self.assertItems(["fooGroup"])
1220 self.assertQuery("tag", ["awesome"])
1222 def testDeleteGroupTags(self):
1223 self.rapi.AddResponse("25826")
1224 self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1226 self.assertHandler(rlib2.R_2_groups_name_tags)
1227 self.assertItems(["foo"])
1229 self.assertQuery("tag", ["awesome"])
1231 def testQuery(self):
1232 for idx, what in enumerate(constants.QR_VIA_RAPI):
1233 for idx2, qfilter in enumerate([None, ["?", "name"]]):
1234 job_id = 11010 + (idx << 4) + (idx2 << 16)
1235 fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1237 self.rapi.AddResponse(str(job_id))
1238 self.assertEqual(self.client.Query(what, fields, qfilter=qfilter),
1240 self.assertItems([what])
1241 self.assertHandler(rlib2.R_2_query)
1242 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1243 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1244 self.assertEqual(data["fields"], fields)
1246 self.assertTrue("qfilter" not in data)
1248 self.assertEqual(data["qfilter"], qfilter)
1249 self.assertEqual(self.rapi.CountPending(), 0)
1251 def testQueryFields(self):
1252 exp_result = objects.QueryFieldsResponse(fields=[
1253 objects.QueryFieldDefinition(name="pnode", title="PNode",
1254 kind=constants.QFT_NUMBER),
1255 objects.QueryFieldDefinition(name="other", title="Other",
1256 kind=constants.QFT_BOOL),
1259 for what in constants.QR_VIA_RAPI:
1260 for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1261 self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1262 result = self.client.QueryFields(what, fields=fields)
1263 self.assertItems([what])
1264 self.assertHandler(rlib2.R_2_query_fields)
1265 self.assertFalse(self.rapi.GetLastRequestData())
1267 queryargs = self.rapi.GetLastHandler().queryargs
1269 self.assertFalse(queryargs)
1271 self.assertEqual(queryargs, {
1272 "fields": [",".join(fields)],
1275 self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1276 exp_result.ToDict())
1278 self.assertEqual(self.rapi.CountPending(), 0)
1280 def testWaitForJobCompletionNoChange(self):
1281 resp = serializer.DumpJson({
1282 "status": constants.JOB_STATUS_WAITING,
1285 for retries in [1, 5, 25]:
1286 for _ in range(retries):
1287 self.rapi.AddResponse(resp)
1289 self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1291 self.assertHandler(rlib2.R_2_jobs_id)
1292 self.assertItems(["22789"])
1294 self.assertEqual(self.rapi.CountPending(), 0)
1296 def testWaitForJobCompletionAlreadyFinished(self):
1297 self.rapi.AddResponse(serializer.DumpJson({
1298 "status": constants.JOB_STATUS_SUCCESS,
1301 self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1303 self.assertHandler(rlib2.R_2_jobs_id)
1304 self.assertItems(["22793"])
1306 self.assertEqual(self.rapi.CountPending(), 0)
1308 def testWaitForJobCompletionEmptyResponse(self):
1309 self.rapi.AddResponse("{}")
1310 self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1312 self.assertHandler(rlib2.R_2_jobs_id)
1313 self.assertItems(["22793"])
1315 self.assertEqual(self.rapi.CountPending(), 0)
1317 def testWaitForJobCompletionOutOfRetries(self):
1318 for retries in [3, 10, 21]:
1319 for _ in range(retries):
1320 self.rapi.AddResponse(serializer.DumpJson({
1321 "status": constants.JOB_STATUS_RUNNING,
1324 self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1325 retries=retries - 1))
1326 self.assertHandler(rlib2.R_2_jobs_id)
1327 self.assertItems(["30948"])
1329 self.assertEqual(self.rapi.CountPending(), 1)
1330 self.rapi.ResetResponses()
1332 def testWaitForJobCompletionSuccessAndFailure(self):
1333 for retries in [1, 4, 13]:
1334 for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1335 (True, constants.JOB_STATUS_SUCCESS)]:
1336 for _ in range(retries):
1337 self.rapi.AddResponse(serializer.DumpJson({
1338 "status": constants.JOB_STATUS_RUNNING,
1341 self.rapi.AddResponse(serializer.DumpJson({
1342 "status": end_status,
1345 result = self.client.WaitForJobCompletion(3187, period=None,
1346 retries=retries + 1)
1347 self.assertEqual(result, success)
1348 self.assertHandler(rlib2.R_2_jobs_id)
1349 self.assertItems(["3187"])
1351 self.assertEqual(self.rapi.CountPending(), 0)
1354 class RapiTestRunner(unittest.TextTestRunner):
1355 def run(self, *args):
1356 global _used_handlers
1357 assert _used_handlers is None
1359 _used_handlers = set()
1362 result = unittest.TextTestRunner.run(self, *args)
1364 diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1367 raise AssertionError("The following RAPI resources were not used by the"
1368 " RAPI client: %r" % utils.CommaJoin(diff))
1370 # Reset global variable
1371 _used_handlers = None
1376 if __name__ == "__main__":
1377 client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)