4 # Copyright (C) 2010 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"""
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
37 from ganeti.rapi import connector
38 from ganeti.rapi import rlib2
39 from ganeti.rapi import client
44 _URI_RE = re.compile(r"https://(?P<host>.*):(?P<port>\d+)(?P<path>/.*)")
46 # List of resource handlers which aren't used by the RAPI client
52 # Global variable for collecting used handlers
56 def _GetPathFromUri(uri):
57 """Gets the path and query from a URI.
60 match = _URI_RE.match(uri)
62 return match.groupdict()["path"]
68 def __init__(self, rapi):
73 def setopt(self, opt, value):
74 self._opts[opt] = value
76 def getopt(self, opt):
77 return self._opts.get(opt)
79 def unsetopt(self, opt):
80 self._opts.pop(opt, None)
82 def getinfo(self, info):
83 return self._info[info]
86 method = self._opts[pycurl.CUSTOMREQUEST]
87 url = self._opts[pycurl.URL]
88 request_body = self._opts[pycurl.POSTFIELDS]
89 writefn = self._opts[pycurl.WRITEFUNCTION]
91 path = _GetPathFromUri(url)
92 (code, resp_body) = self._rapi.FetchResponse(path, method, request_body)
94 self._info[pycurl.RESPONSE_CODE] = code
95 if resp_body is not None:
99 class RapiMock(object):
101 self._mapper = connector.Mapper()
103 self._last_handler = None
104 self._last_req_data = None
106 def ResetResponses(self):
107 del self._responses[:]
109 def AddResponse(self, response, code=200):
110 self._responses.insert(0, (code, response))
112 def CountPending(self):
113 return len(self._responses)
115 def GetLastHandler(self):
116 return self._last_handler
118 def GetLastRequestData(self):
119 return self._last_req_data
121 def FetchResponse(self, path, method, request_body):
122 self._last_req_data = request_body
125 (handler_cls, items, args) = self._mapper.getController(path)
127 # Record handler as used
128 _used_handlers.add(handler_cls)
130 self._last_handler = handler_cls(items, args, None)
131 if not hasattr(self._last_handler, method.upper()):
132 raise http.HttpNotImplemented(message="Method not implemented")
134 except http.HttpException, ex:
136 response = ex.message
138 if not self._responses:
139 raise Exception("No responses")
141 (code, response) = self._responses.pop()
143 return code, response
146 class TestConstants(unittest.TestCase):
148 self.assertEqual(client.GANETI_RAPI_PORT, constants.DEFAULT_RAPI_PORT)
149 self.assertEqual(client.GANETI_RAPI_VERSION, constants.RAPI_VERSION)
150 self.assertEqual(client.HTTP_APP_JSON, http.HTTP_APP_JSON)
151 self.assertEqual(client._REQ_DATA_VERSION_FIELD, rlib2._REQ_DATA_VERSION)
152 self.assertEqual(client._INST_CREATE_REQV1, rlib2._INST_CREATE_REQV1)
153 self.assertEqual(client._INST_REINSTALL_REQV1, rlib2._INST_REINSTALL_REQV1)
154 self.assertEqual(client._NODE_MIGRATE_REQV1, rlib2._NODE_MIGRATE_REQV1)
155 self.assertEqual(client._INST_NIC_PARAMS, constants.INIC_PARAMS)
156 self.assertEqual(client.JOB_STATUS_QUEUED, constants.JOB_STATUS_QUEUED)
157 self.assertEqual(client.JOB_STATUS_WAITLOCK, constants.JOB_STATUS_WAITLOCK)
158 self.assertEqual(client.JOB_STATUS_CANCELING,
159 constants.JOB_STATUS_CANCELING)
160 self.assertEqual(client.JOB_STATUS_RUNNING, constants.JOB_STATUS_RUNNING)
161 self.assertEqual(client.JOB_STATUS_CANCELED, constants.JOB_STATUS_CANCELED)
162 self.assertEqual(client.JOB_STATUS_SUCCESS, constants.JOB_STATUS_SUCCESS)
163 self.assertEqual(client.JOB_STATUS_ERROR, constants.JOB_STATUS_ERROR)
164 self.assertEqual(client.JOB_STATUS_FINALIZED, constants.JOBS_FINALIZED)
165 self.assertEqual(client.JOB_STATUS_ALL, constants.JOB_STATUS_ALL)
168 class RapiMockTest(unittest.TestCase):
172 self.assertEqual((404, None), rapi.FetchResponse("/foo", "GET", None))
173 self.assertEqual((501, "Method not implemented"),
174 rapi.FetchResponse("/version", "POST", None))
175 rapi.AddResponse("2")
176 code, response = rapi.FetchResponse("/version", "GET", None)
177 self.assertEqual(200, code)
178 self.assertEqual("2", response)
179 self.failUnless(isinstance(rapi.GetLastHandler(), rlib2.R_version))
182 def _FakeNoSslPycurlVersion():
183 # Note: incomplete version tuple
184 return (3, "7.16.0", 462848, "mysystem", 1581, None, 0)
187 def _FakeFancySslPycurlVersion():
188 # Note: incomplete version tuple
189 return (3, "7.16.0", 462848, "mysystem", 1581, "FancySSL/1.2.3", 0)
192 def _FakeOpenSslPycurlVersion():
193 # Note: incomplete version tuple
194 return (2, "7.15.5", 462597, "othersystem", 668, "OpenSSL/0.9.8c", 0)
197 def _FakeGnuTlsPycurlVersion():
198 # Note: incomplete version tuple
199 return (3, "7.18.0", 463360, "somesystem", 1581, "GnuTLS/2.0.4", 0)
202 class TestExtendedConfig(unittest.TestCase):
204 cl = client.GanetiRapiClient("master.example.com",
205 username="user", password="pw",
206 curl_factory=lambda: FakeCurl(RapiMock()))
208 curl = cl._CreateCurl()
209 self.assertEqual(curl.getopt(pycurl.HTTPAUTH), pycurl.HTTPAUTH_BASIC)
210 self.assertEqual(curl.getopt(pycurl.USERPWD), "user:pw")
212 def testInvalidAuth(self):
214 self.assertRaises(client.Error, client.GanetiRapiClient,
215 "master-a.example.com", password="pw")
217 self.assertRaises(client.Error, client.GanetiRapiClient,
218 "master-b.example.com", username="user")
220 def testCertVerifyInvalidCombinations(self):
221 self.assertRaises(client.Error, client.GenericCurlConfig,
222 use_curl_cabundle=True, cafile="cert1.pem")
223 self.assertRaises(client.Error, client.GenericCurlConfig,
224 use_curl_cabundle=True, capath="certs/")
225 self.assertRaises(client.Error, client.GenericCurlConfig,
226 use_curl_cabundle=True,
227 cafile="cert1.pem", capath="certs/")
229 def testProxySignalVerifyHostname(self):
230 for use_gnutls in [False, True]:
232 pcverfn = _FakeGnuTlsPycurlVersion
234 pcverfn = _FakeOpenSslPycurlVersion
236 for proxy in ["", "http://127.0.0.1:1234"]:
237 for use_signal in [False, True]:
238 for verify_hostname in [False, True]:
239 cfgfn = client.GenericCurlConfig(proxy=proxy, use_signal=use_signal,
240 verify_hostname=verify_hostname,
241 _pycurl_version_fn=pcverfn)
243 curl_factory = lambda: FakeCurl(RapiMock())
244 cl = client.GanetiRapiClient("master.example.com",
245 curl_config_fn=cfgfn,
246 curl_factory=curl_factory)
248 curl = cl._CreateCurl()
249 self.assertEqual(curl.getopt(pycurl.PROXY), proxy)
250 self.assertEqual(curl.getopt(pycurl.NOSIGNAL), not use_signal)
253 self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 2)
255 self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 0)
257 def testNoCertVerify(self):
258 cfgfn = client.GenericCurlConfig()
260 curl_factory = lambda: FakeCurl(RapiMock())
261 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
262 curl_factory=curl_factory)
264 curl = cl._CreateCurl()
265 self.assertFalse(curl.getopt(pycurl.SSL_VERIFYPEER))
266 self.assertFalse(curl.getopt(pycurl.CAINFO))
267 self.assertFalse(curl.getopt(pycurl.CAPATH))
269 def testCertVerifyCurlBundle(self):
270 cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
272 curl_factory = lambda: FakeCurl(RapiMock())
273 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
274 curl_factory=curl_factory)
276 curl = cl._CreateCurl()
277 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
278 self.assertFalse(curl.getopt(pycurl.CAINFO))
279 self.assertFalse(curl.getopt(pycurl.CAPATH))
281 def testCertVerifyCafile(self):
282 mycert = "/tmp/some/UNUSED/cert/file.pem"
283 cfgfn = client.GenericCurlConfig(cafile=mycert)
285 curl_factory = lambda: FakeCurl(RapiMock())
286 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
287 curl_factory=curl_factory)
289 curl = cl._CreateCurl()
290 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
291 self.assertEqual(curl.getopt(pycurl.CAINFO), mycert)
292 self.assertFalse(curl.getopt(pycurl.CAPATH))
294 def testCertVerifyCapath(self):
295 certdir = "/tmp/some/UNUSED/cert/directory"
296 pcverfn = _FakeOpenSslPycurlVersion
297 cfgfn = client.GenericCurlConfig(capath=certdir,
298 _pycurl_version_fn=pcverfn)
300 curl_factory = lambda: FakeCurl(RapiMock())
301 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
302 curl_factory=curl_factory)
304 curl = cl._CreateCurl()
305 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
306 self.assertEqual(curl.getopt(pycurl.CAPATH), certdir)
307 self.assertFalse(curl.getopt(pycurl.CAINFO))
309 def testCertVerifyCapathGnuTls(self):
310 certdir = "/tmp/some/UNUSED/cert/directory"
311 pcverfn = _FakeGnuTlsPycurlVersion
312 cfgfn = client.GenericCurlConfig(capath=certdir,
313 _pycurl_version_fn=pcverfn)
315 curl_factory = lambda: FakeCurl(RapiMock())
316 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
317 curl_factory=curl_factory)
319 self.assertRaises(client.Error, cl._CreateCurl)
321 def testCertVerifyNoSsl(self):
322 certdir = "/tmp/some/UNUSED/cert/directory"
323 pcverfn = _FakeNoSslPycurlVersion
324 cfgfn = client.GenericCurlConfig(capath=certdir,
325 _pycurl_version_fn=pcverfn)
327 curl_factory = lambda: FakeCurl(RapiMock())
328 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
329 curl_factory=curl_factory)
331 self.assertRaises(client.Error, cl._CreateCurl)
333 def testCertVerifyFancySsl(self):
334 certdir = "/tmp/some/UNUSED/cert/directory"
335 pcverfn = _FakeFancySslPycurlVersion
336 cfgfn = client.GenericCurlConfig(capath=certdir,
337 _pycurl_version_fn=pcverfn)
339 curl_factory = lambda: FakeCurl(RapiMock())
340 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
341 curl_factory=curl_factory)
343 self.assertRaises(NotImplementedError, cl._CreateCurl)
345 def testCertVerifyCapath(self):
346 for connect_timeout in [None, 1, 5, 10, 30, 60, 300]:
347 for timeout in [None, 1, 30, 60, 3600, 24 * 3600]:
348 cfgfn = client.GenericCurlConfig(connect_timeout=connect_timeout,
351 curl_factory = lambda: FakeCurl(RapiMock())
352 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
353 curl_factory=curl_factory)
355 curl = cl._CreateCurl()
356 self.assertEqual(curl.getopt(pycurl.CONNECTTIMEOUT), connect_timeout)
357 self.assertEqual(curl.getopt(pycurl.TIMEOUT), timeout)
360 class GanetiRapiClientTests(testutils.GanetiTestCase):
362 testutils.GanetiTestCase.setUp(self)
364 self.rapi = RapiMock()
365 self.curl = FakeCurl(self.rapi)
366 self.client = client.GanetiRapiClient("master.example.com",
367 curl_factory=lambda: self.curl)
369 def assertHandler(self, handler_cls):
370 self.failUnless(isinstance(self.rapi.GetLastHandler(), handler_cls))
372 def assertQuery(self, key, value):
373 self.assertEqual(value, self.rapi.GetLastHandler().queryargs.get(key, None))
375 def assertItems(self, items):
376 self.assertEqual(items, self.rapi.GetLastHandler().items)
378 def assertBulk(self):
379 self.assertTrue(self.rapi.GetLastHandler().useBulk())
381 def assertDryRun(self):
382 self.assertTrue(self.rapi.GetLastHandler().dryRun())
384 def assertUseForce(self):
385 self.assertTrue(self.rapi.GetLastHandler().useForce())
387 def testEncodeQuery(self):
404 self.assertEqualValues(self.client._EncodeQuery(query),
408 for i in [[1, 2, 3], {"moo": "boo"}, (1, 2, 3)]:
409 self.assertRaises(ValueError, self.client._EncodeQuery, [("x", i)])
411 def testCurlSettings(self):
412 self.rapi.AddResponse("2")
413 self.assertEqual(2, self.client.GetVersion())
414 self.assertHandler(rlib2.R_version)
416 # Signals should be disabled by default
417 self.assert_(self.curl.getopt(pycurl.NOSIGNAL))
419 # No auth and no proxy
420 self.assertFalse(self.curl.getopt(pycurl.USERPWD))
421 self.assert_(self.curl.getopt(pycurl.PROXY) is None)
423 # Content-type is required for requests
424 headers = self.curl.getopt(pycurl.HTTPHEADER)
425 self.assert_("Content-type: application/json" in headers)
427 def testHttpError(self):
428 self.rapi.AddResponse(None, code=404)
430 self.client.GetJobStatus(15140)
431 except client.GanetiApiError, err:
432 self.assertEqual(err.code, 404)
434 self.fail("Didn't raise exception")
436 def testGetVersion(self):
437 self.rapi.AddResponse("2")
438 self.assertEqual(2, self.client.GetVersion())
439 self.assertHandler(rlib2.R_version)
441 def testGetFeatures(self):
442 for features in [[], ["foo", "bar", "baz"]]:
443 self.rapi.AddResponse(serializer.DumpJson(features))
444 self.assertEqual(features, self.client.GetFeatures())
445 self.assertHandler(rlib2.R_2_features)
447 def testGetFeaturesNotFound(self):
448 self.rapi.AddResponse(None, code=404)
449 self.assertEqual([], self.client.GetFeatures())
451 def testGetOperatingSystems(self):
452 self.rapi.AddResponse("[\"beos\"]")
453 self.assertEqual(["beos"], self.client.GetOperatingSystems())
454 self.assertHandler(rlib2.R_2_os)
456 def testGetClusterTags(self):
457 self.rapi.AddResponse("[\"tag\"]")
458 self.assertEqual(["tag"], self.client.GetClusterTags())
459 self.assertHandler(rlib2.R_2_tags)
461 def testAddClusterTags(self):
462 self.rapi.AddResponse("1234")
463 self.assertEqual(1234,
464 self.client.AddClusterTags(["awesome"], dry_run=True))
465 self.assertHandler(rlib2.R_2_tags)
467 self.assertQuery("tag", ["awesome"])
469 def testDeleteClusterTags(self):
470 self.rapi.AddResponse("5107")
471 self.assertEqual(5107, self.client.DeleteClusterTags(["awesome"],
473 self.assertHandler(rlib2.R_2_tags)
475 self.assertQuery("tag", ["awesome"])
477 def testGetInfo(self):
478 self.rapi.AddResponse("{}")
479 self.assertEqual({}, self.client.GetInfo())
480 self.assertHandler(rlib2.R_2_info)
482 def testGetInstances(self):
483 self.rapi.AddResponse("[]")
484 self.assertEqual([], self.client.GetInstances(bulk=True))
485 self.assertHandler(rlib2.R_2_instances)
488 def testGetInstance(self):
489 self.rapi.AddResponse("[]")
490 self.assertEqual([], self.client.GetInstance("instance"))
491 self.assertHandler(rlib2.R_2_instances_name)
492 self.assertItems(["instance"])
494 def testGetInstanceInfo(self):
495 self.rapi.AddResponse("21291")
496 self.assertEqual(21291, self.client.GetInstanceInfo("inst3"))
497 self.assertHandler(rlib2.R_2_instances_name_info)
498 self.assertItems(["inst3"])
499 self.assertQuery("static", None)
501 self.rapi.AddResponse("3428")
502 self.assertEqual(3428, self.client.GetInstanceInfo("inst31", static=False))
503 self.assertHandler(rlib2.R_2_instances_name_info)
504 self.assertItems(["inst31"])
505 self.assertQuery("static", ["0"])
507 self.rapi.AddResponse("15665")
508 self.assertEqual(15665, self.client.GetInstanceInfo("inst32", static=True))
509 self.assertHandler(rlib2.R_2_instances_name_info)
510 self.assertItems(["inst32"])
511 self.assertQuery("static", ["1"])
513 def testCreateInstanceOldVersion(self):
514 # The old request format, version 0, is no longer supported
515 self.rapi.AddResponse(None, code=404)
516 self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
517 "create", "inst1.example.com", "plain", [], [])
518 self.assertEqual(self.rapi.CountPending(), 0)
520 def testCreateInstance(self):
521 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
522 self.rapi.AddResponse("23030")
523 job_id = self.client.CreateInstance("create", "inst1.example.com",
524 "plain", [], [], dry_run=True)
525 self.assertEqual(job_id, 23030)
526 self.assertHandler(rlib2.R_2_instances)
529 data = serializer.LoadJson(self.rapi.GetLastRequestData())
531 for field in ["dry_run", "beparams", "hvparams", "start"]:
532 self.assertFalse(field in data)
534 self.assertEqual(data["name"], "inst1.example.com")
535 self.assertEqual(data["disk_template"], "plain")
537 def testCreateInstance2(self):
538 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
539 self.rapi.AddResponse("24740")
540 job_id = self.client.CreateInstance("import", "inst2.example.com",
541 "drbd8", [{"size": 100,}],
542 [{}, {"bridge": "br1", }],
543 dry_run=False, start=True,
544 pnode="node1", snode="node9",
546 self.assertEqual(job_id, 24740)
547 self.assertHandler(rlib2.R_2_instances)
549 data = serializer.LoadJson(self.rapi.GetLastRequestData())
550 self.assertEqual(data[rlib2._REQ_DATA_VERSION], 1)
551 self.assertEqual(data["name"], "inst2.example.com")
552 self.assertEqual(data["disk_template"], "drbd8")
553 self.assertEqual(data["start"], True)
554 self.assertEqual(data["ip_check"], False)
555 self.assertEqualValues(data["disks"], [{"size": 100,}])
556 self.assertEqualValues(data["nics"], [{}, {"bridge": "br1", }])
558 def testDeleteInstance(self):
559 self.rapi.AddResponse("1234")
560 self.assertEqual(1234, self.client.DeleteInstance("instance", dry_run=True))
561 self.assertHandler(rlib2.R_2_instances_name)
562 self.assertItems(["instance"])
565 def testGetInstanceTags(self):
566 self.rapi.AddResponse("[]")
567 self.assertEqual([], self.client.GetInstanceTags("fooinstance"))
568 self.assertHandler(rlib2.R_2_instances_name_tags)
569 self.assertItems(["fooinstance"])
571 def testAddInstanceTags(self):
572 self.rapi.AddResponse("1234")
573 self.assertEqual(1234,
574 self.client.AddInstanceTags("fooinstance", ["awesome"], dry_run=True))
575 self.assertHandler(rlib2.R_2_instances_name_tags)
576 self.assertItems(["fooinstance"])
578 self.assertQuery("tag", ["awesome"])
580 def testDeleteInstanceTags(self):
581 self.rapi.AddResponse("25826")
582 self.assertEqual(25826, self.client.DeleteInstanceTags("foo", ["awesome"],
584 self.assertHandler(rlib2.R_2_instances_name_tags)
585 self.assertItems(["foo"])
587 self.assertQuery("tag", ["awesome"])
589 def testRebootInstance(self):
590 self.rapi.AddResponse("6146")
591 job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
592 ignore_secondaries=True, dry_run=True)
593 self.assertEqual(6146, job_id)
594 self.assertHandler(rlib2.R_2_instances_name_reboot)
595 self.assertItems(["i-bar"])
597 self.assertQuery("type", ["hard"])
598 self.assertQuery("ignore_secondaries", ["1"])
600 def testShutdownInstance(self):
601 self.rapi.AddResponse("1487")
602 self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
604 self.assertHandler(rlib2.R_2_instances_name_shutdown)
605 self.assertItems(["foo-instance"])
608 def testStartupInstance(self):
609 self.rapi.AddResponse("27149")
610 self.assertEqual(27149, self.client.StartupInstance("bar-instance",
612 self.assertHandler(rlib2.R_2_instances_name_startup)
613 self.assertItems(["bar-instance"])
616 def testReinstallInstance(self):
617 self.rapi.AddResponse(serializer.DumpJson([]))
618 self.rapi.AddResponse("19119")
619 self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
622 self.assertHandler(rlib2.R_2_instances_name_reinstall)
623 self.assertItems(["baz-instance"])
624 self.assertQuery("os", ["DOS"])
625 self.assertQuery("nostartup", ["1"])
626 self.assertEqual(self.rapi.CountPending(), 0)
628 def testReinstallInstanceNew(self):
629 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
630 self.rapi.AddResponse("25689")
631 self.assertEqual(25689, self.client.ReinstallInstance("moo-instance",
634 self.assertHandler(rlib2.R_2_instances_name_reinstall)
635 self.assertItems(["moo-instance"])
636 data = serializer.LoadJson(self.rapi.GetLastRequestData())
637 self.assertEqual(len(data), 2)
638 self.assertEqual(data["os"], "Debian")
639 self.assertEqual(data["start"], False)
640 self.assertEqual(self.rapi.CountPending(), 0)
642 def testReinstallInstanceWithOsparams1(self):
643 self.rapi.AddResponse(serializer.DumpJson([]))
644 self.assertRaises(client.GanetiApiError, self.client.ReinstallInstance,
645 "doo-instance", osparams={"x": "y"})
646 self.assertEqual(self.rapi.CountPending(), 0)
648 def testReinstallInstanceWithOsparams2(self):
653 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
654 self.rapi.AddResponse("1717")
655 self.assertEqual(1717, self.client.ReinstallInstance("zoo-instance",
657 self.assertHandler(rlib2.R_2_instances_name_reinstall)
658 self.assertItems(["zoo-instance"])
659 data = serializer.LoadJson(self.rapi.GetLastRequestData())
660 self.assertEqual(len(data), 2)
661 self.assertEqual(data["osparams"], osparams)
662 self.assertEqual(data["start"], True)
663 self.assertEqual(self.rapi.CountPending(), 0)
665 def testReplaceInstanceDisks(self):
666 self.rapi.AddResponse("999")
667 job_id = self.client.ReplaceInstanceDisks("instance-name",
668 disks=[0, 1], dry_run=True, iallocator="hail")
669 self.assertEqual(999, job_id)
670 self.assertHandler(rlib2.R_2_instances_name_replace_disks)
671 self.assertItems(["instance-name"])
672 self.assertQuery("disks", ["0,1"])
673 self.assertQuery("mode", ["replace_auto"])
674 self.assertQuery("iallocator", ["hail"])
677 self.rapi.AddResponse("1000")
678 job_id = self.client.ReplaceInstanceDisks("instance-bar",
679 disks=[1], mode="replace_on_secondary", remote_node="foo-node",
681 self.assertEqual(1000, job_id)
682 self.assertItems(["instance-bar"])
683 self.assertQuery("disks", ["1"])
684 self.assertQuery("remote_node", ["foo-node"])
687 self.rapi.AddResponse("5175")
688 self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
689 self.assertItems(["instance-moo"])
690 self.assertQuery("disks", None)
692 def testPrepareExport(self):
693 self.rapi.AddResponse("8326")
694 self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
695 self.assertHandler(rlib2.R_2_instances_name_prepare_export)
696 self.assertItems(["inst1"])
697 self.assertQuery("mode", ["local"])
699 def testExportInstance(self):
700 self.rapi.AddResponse("19695")
701 job_id = self.client.ExportInstance("inst2", "local", "nodeX",
703 self.assertEqual(job_id, 19695)
704 self.assertHandler(rlib2.R_2_instances_name_export)
705 self.assertItems(["inst2"])
707 data = serializer.LoadJson(self.rapi.GetLastRequestData())
708 self.assertEqual(data["mode"], "local")
709 self.assertEqual(data["destination"], "nodeX")
710 self.assertEqual(data["shutdown"], True)
712 def testMigrateInstanceDefaults(self):
713 self.rapi.AddResponse("24873")
714 job_id = self.client.MigrateInstance("inst91")
715 self.assertEqual(job_id, 24873)
716 self.assertHandler(rlib2.R_2_instances_name_migrate)
717 self.assertItems(["inst91"])
719 data = serializer.LoadJson(self.rapi.GetLastRequestData())
720 self.assertFalse(data)
722 def testMigrateInstance(self):
723 for mode in constants.HT_MIGRATION_MODES:
724 for cleanup in [False, True]:
725 self.rapi.AddResponse("31910")
726 job_id = self.client.MigrateInstance("inst289", mode=mode,
728 self.assertEqual(job_id, 31910)
729 self.assertHandler(rlib2.R_2_instances_name_migrate)
730 self.assertItems(["inst289"])
732 data = serializer.LoadJson(self.rapi.GetLastRequestData())
733 self.assertEqual(len(data), 2)
734 self.assertEqual(data["mode"], mode)
735 self.assertEqual(data["cleanup"], cleanup)
737 def testRenameInstanceDefaults(self):
738 new_name = "newnametha7euqu"
739 self.rapi.AddResponse("8791")
740 job_id = self.client.RenameInstance("inst18821", new_name)
741 self.assertEqual(job_id, 8791)
742 self.assertHandler(rlib2.R_2_instances_name_rename)
743 self.assertItems(["inst18821"])
745 data = serializer.LoadJson(self.rapi.GetLastRequestData())
746 self.assertEqualValues(data, {"new_name": new_name, })
748 def testRenameInstance(self):
749 new_name = "new-name-yiux1iin"
750 for ip_check in [False, True]:
751 for name_check in [False, True]:
752 self.rapi.AddResponse("24776")
753 job_id = self.client.RenameInstance("inst20967", new_name,
755 name_check=name_check)
756 self.assertEqual(job_id, 24776)
757 self.assertHandler(rlib2.R_2_instances_name_rename)
758 self.assertItems(["inst20967"])
760 data = serializer.LoadJson(self.rapi.GetLastRequestData())
761 self.assertEqual(len(data), 3)
762 self.assertEqual(data["new_name"], new_name)
763 self.assertEqual(data["ip_check"], ip_check)
764 self.assertEqual(data["name_check"], name_check)
766 def testGetJobs(self):
767 self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
768 ' { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
769 self.assertEqual([123, 124], self.client.GetJobs())
770 self.assertHandler(rlib2.R_2_jobs)
772 def testGetJobStatus(self):
773 self.rapi.AddResponse("{\"foo\": \"bar\"}")
774 self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
775 self.assertHandler(rlib2.R_2_jobs_id)
776 self.assertItems(["1234"])
778 def testWaitForJobChange(self):
779 fields = ["id", "summary"]
781 "job_info": [123, "something"],
785 self.rapi.AddResponse(serializer.DumpJson(expected))
786 result = self.client.WaitForJobChange(123, fields, [], -1)
787 self.assertEqualValues(expected, result)
788 self.assertHandler(rlib2.R_2_jobs_id_wait)
789 self.assertItems(["123"])
791 def testCancelJob(self):
792 self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
793 self.assertEqual([True, "Job 123 will be canceled"],
794 self.client.CancelJob(999, dry_run=True))
795 self.assertHandler(rlib2.R_2_jobs_id)
796 self.assertItems(["999"])
799 def testGetNodes(self):
800 self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
801 " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
802 self.assertEqual(["node1", "node2"], self.client.GetNodes())
803 self.assertHandler(rlib2.R_2_nodes)
805 self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
806 " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
807 self.assertEqual([{"id": "node1", "uri": "uri1"},
808 {"id": "node2", "uri": "uri2"}],
809 self.client.GetNodes(bulk=True))
810 self.assertHandler(rlib2.R_2_nodes)
813 def testGetNode(self):
814 self.rapi.AddResponse("{}")
815 self.assertEqual({}, self.client.GetNode("node-foo"))
816 self.assertHandler(rlib2.R_2_nodes_name)
817 self.assertItems(["node-foo"])
819 def testEvacuateNode(self):
820 self.rapi.AddResponse("9876")
821 job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
822 self.assertEqual(9876, job_id)
823 self.assertHandler(rlib2.R_2_nodes_name_evacuate)
824 self.assertItems(["node-1"])
825 self.assertQuery("remote_node", ["node-2"])
827 self.rapi.AddResponse("8888")
828 job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True)
829 self.assertEqual(8888, job_id)
830 self.assertItems(["node-3"])
831 self.assertQuery("iallocator", ["hail"])
834 self.assertRaises(client.GanetiApiError,
835 self.client.EvacuateNode,
836 "node-4", iallocator="hail", remote_node="node-5")
838 def testMigrateNode(self):
839 self.rapi.AddResponse(serializer.DumpJson([]))
840 self.rapi.AddResponse("1111")
841 self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
842 self.assertHandler(rlib2.R_2_nodes_name_migrate)
843 self.assertItems(["node-a"])
844 self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
846 self.assertFalse(self.rapi.GetLastRequestData())
848 self.rapi.AddResponse(serializer.DumpJson([]))
849 self.rapi.AddResponse("1112")
850 self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
852 self.assertHandler(rlib2.R_2_nodes_name_migrate)
853 self.assertItems(["node-a"])
854 self.assertQuery("mode", ["live"])
856 self.assertFalse(self.rapi.GetLastRequestData())
858 self.rapi.AddResponse(serializer.DumpJson([]))
859 self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
860 "node-c", target_node="foonode")
861 self.assertEqual(self.rapi.CountPending(), 0)
863 def testMigrateNodeBodyData(self):
864 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
865 self.rapi.AddResponse("27539")
866 self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
868 self.assertHandler(rlib2.R_2_nodes_name_migrate)
869 self.assertItems(["node-a"])
870 self.assertFalse(self.rapi.GetLastHandler().queryargs)
871 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
874 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
875 self.rapi.AddResponse("14219")
876 self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
879 self.assertHandler(rlib2.R_2_nodes_name_migrate)
880 self.assertItems(["node-x"])
882 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
883 { "target_node": "node9", "iallocator": "ial", })
885 self.assertEqual(self.rapi.CountPending(), 0)
887 def testGetNodeRole(self):
888 self.rapi.AddResponse("\"master\"")
889 self.assertEqual("master", self.client.GetNodeRole("node-a"))
890 self.assertHandler(rlib2.R_2_nodes_name_role)
891 self.assertItems(["node-a"])
893 def testSetNodeRole(self):
894 self.rapi.AddResponse("789")
895 self.assertEqual(789,
896 self.client.SetNodeRole("node-foo", "master-candidate", force=True))
897 self.assertHandler(rlib2.R_2_nodes_name_role)
898 self.assertItems(["node-foo"])
899 self.assertQuery("force", ["1"])
900 self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
902 def testGetNodeStorageUnits(self):
903 self.rapi.AddResponse("42")
905 self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
906 self.assertHandler(rlib2.R_2_nodes_name_storage)
907 self.assertItems(["node-x"])
908 self.assertQuery("storage_type", ["lvm-pv"])
909 self.assertQuery("output_fields", ["fields"])
911 def testModifyNodeStorageUnits(self):
912 self.rapi.AddResponse("14")
914 self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
915 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
916 self.assertItems(["node-z"])
917 self.assertQuery("storage_type", ["lvm-pv"])
918 self.assertQuery("name", ["hda"])
919 self.assertQuery("allocatable", None)
921 for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
922 self.rapi.AddResponse("7205")
923 job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
924 allocatable=allocatable)
925 self.assertEqual(7205, job_id)
926 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
927 self.assertItems(["node-z"])
928 self.assertQuery("storage_type", ["lvm-pv"])
929 self.assertQuery("name", ["hda"])
930 self.assertQuery("allocatable", [query_allocatable])
932 def testRepairNodeStorageUnits(self):
933 self.rapi.AddResponse("99")
934 self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
936 self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
937 self.assertItems(["node-z"])
938 self.assertQuery("storage_type", ["lvm-pv"])
939 self.assertQuery("name", ["hda"])
941 def testGetNodeTags(self):
942 self.rapi.AddResponse("[\"fry\", \"bender\"]")
943 self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
944 self.assertHandler(rlib2.R_2_nodes_name_tags)
945 self.assertItems(["node-k"])
947 def testAddNodeTags(self):
948 self.rapi.AddResponse("1234")
949 self.assertEqual(1234,
950 self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
951 self.assertHandler(rlib2.R_2_nodes_name_tags)
952 self.assertItems(["node-v"])
954 self.assertQuery("tag", ["awesome"])
956 def testDeleteNodeTags(self):
957 self.rapi.AddResponse("16861")
958 self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
960 self.assertHandler(rlib2.R_2_nodes_name_tags)
961 self.assertItems(["node-w"])
963 self.assertQuery("tag", ["awesome"])
965 def testGetGroups(self):
966 groups = [{"name": "group1",
967 "uri": "/2/groups/group1",
970 "uri": "/2/groups/group2",
973 self.rapi.AddResponse(serializer.DumpJson(groups))
974 self.assertEqual(["group1", "group2"], self.client.GetGroups())
975 self.assertHandler(rlib2.R_2_groups)
977 def testGetGroupsBulk(self):
978 groups = [{"name": "group1",
979 "uri": "/2/groups/group1",
981 "node_list": ["gnt1.test",
986 "uri": "/2/groups/group2",
988 "node_list": ["gnt3.test",
992 self.rapi.AddResponse(serializer.DumpJson(groups))
994 self.assertEqual(groups, self.client.GetGroups(bulk=True))
995 self.assertHandler(rlib2.R_2_groups)
998 def testGetGroup(self):
999 group = {"ctime": None,
1002 self.rapi.AddResponse(serializer.DumpJson(group))
1003 self.assertEqual({"ctime": None, "name": "default"},
1004 self.client.GetGroup("default"))
1005 self.assertHandler(rlib2.R_2_groups_name)
1006 self.assertItems(["default"])
1008 def testCreateGroup(self):
1009 self.rapi.AddResponse("12345")
1010 job_id = self.client.CreateGroup("newgroup", dry_run=True)
1011 self.assertEqual(job_id, 12345)
1012 self.assertHandler(rlib2.R_2_groups)
1015 def testDeleteGroup(self):
1016 self.rapi.AddResponse("12346")
1017 job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1018 self.assertEqual(job_id, 12346)
1019 self.assertHandler(rlib2.R_2_groups_name)
1022 def testRenameGroup(self):
1023 self.rapi.AddResponse("12347")
1024 job_id = self.client.RenameGroup("oldname", "newname")
1025 self.assertEqual(job_id, 12347)
1026 self.assertHandler(rlib2.R_2_groups_name_rename)
1028 def testModifyGroup(self):
1029 self.rapi.AddResponse("12348")
1030 job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1031 self.assertEqual(job_id, 12348)
1032 self.assertHandler(rlib2.R_2_groups_name_modify)
1034 def testAssignGroupNodes(self):
1035 self.rapi.AddResponse("12349")
1036 job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1037 force=True, dry_run=True)
1038 self.assertEqual(job_id, 12349)
1039 self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1041 self.assertUseForce()
1043 def testModifyInstance(self):
1044 self.rapi.AddResponse("23681")
1045 job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1046 self.assertEqual(job_id, 23681)
1047 self.assertItems(["inst7210"])
1048 self.assertHandler(rlib2.R_2_instances_name_modify)
1049 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1050 { "os_name": "linux", })
1052 def testModifyCluster(self):
1053 for mnh in [None, False, True]:
1054 self.rapi.AddResponse("14470")
1055 self.assertEqual(14470,
1056 self.client.ModifyCluster(maintain_node_health=mnh))
1057 self.assertHandler(rlib2.R_2_cluster_modify)
1058 self.assertItems([])
1059 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1060 self.assertEqual(len(data), 1)
1061 self.assertEqual(data["maintain_node_health"], mnh)
1062 self.assertEqual(self.rapi.CountPending(), 0)
1064 def testRedistributeConfig(self):
1065 self.rapi.AddResponse("3364")
1066 job_id = self.client.RedistributeConfig()
1067 self.assertEqual(job_id, 3364)
1068 self.assertItems([])
1069 self.assertHandler(rlib2.R_2_redist_config)
1071 def testActivateInstanceDisks(self):
1072 self.rapi.AddResponse("23547")
1073 job_id = self.client.ActivateInstanceDisks("inst28204")
1074 self.assertEqual(job_id, 23547)
1075 self.assertItems(["inst28204"])
1076 self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1077 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1079 def testActivateInstanceDisksIgnoreSize(self):
1080 self.rapi.AddResponse("11044")
1081 job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1082 self.assertEqual(job_id, 11044)
1083 self.assertItems(["inst28204"])
1084 self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1085 self.assertQuery("ignore_size", ["1"])
1087 def testDeactivateInstanceDisks(self):
1088 self.rapi.AddResponse("14591")
1089 job_id = self.client.DeactivateInstanceDisks("inst28234")
1090 self.assertEqual(job_id, 14591)
1091 self.assertItems(["inst28234"])
1092 self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1093 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1095 def testGetInstanceConsole(self):
1096 self.rapi.AddResponse("26876")
1097 job_id = self.client.GetInstanceConsole("inst21491")
1098 self.assertEqual(job_id, 26876)
1099 self.assertItems(["inst21491"])
1100 self.assertHandler(rlib2.R_2_instances_name_console)
1101 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1102 self.assertFalse(self.rapi.GetLastRequestData())
1104 def testGrowInstanceDisk(self):
1105 for idx, wait_for_sync in enumerate([None, False, True]):
1106 amount = 128 + (512 * idx)
1107 self.assertEqual(self.rapi.CountPending(), 0)
1108 self.rapi.AddResponse("30783")
1109 self.assertEqual(30783,
1110 self.client.GrowInstanceDisk("eze8ch", idx, amount,
1111 wait_for_sync=wait_for_sync))
1112 self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1113 self.assertItems(["eze8ch", str(idx)])
1114 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1115 if wait_for_sync is None:
1116 self.assertEqual(len(data), 1)
1117 self.assert_("wait_for_sync" not in data)
1119 self.assertEqual(len(data), 2)
1120 self.assertEqual(data["wait_for_sync"], wait_for_sync)
1121 self.assertEqual(data["amount"], amount)
1122 self.assertEqual(self.rapi.CountPending(), 0)
1124 def testGetGroupTags(self):
1125 self.rapi.AddResponse("[]")
1126 self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1127 self.assertHandler(rlib2.R_2_groups_name_tags)
1128 self.assertItems(["fooGroup"])
1130 def testAddGroupTags(self):
1131 self.rapi.AddResponse("1234")
1132 self.assertEqual(1234,
1133 self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1134 self.assertHandler(rlib2.R_2_groups_name_tags)
1135 self.assertItems(["fooGroup"])
1137 self.assertQuery("tag", ["awesome"])
1139 def testDeleteGroupTags(self):
1140 self.rapi.AddResponse("25826")
1141 self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1143 self.assertHandler(rlib2.R_2_groups_name_tags)
1144 self.assertItems(["foo"])
1146 self.assertQuery("tag", ["awesome"])
1148 def testQuery(self):
1149 for idx, what in enumerate(constants.QR_VIA_RAPI):
1150 for idx2, filter_ in enumerate([None, ["?", "name"]]):
1151 job_id = 11010 + (idx << 4) + (idx2 << 16)
1152 fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1154 self.rapi.AddResponse(str(job_id))
1155 self.assertEqual(self.client.Query(what, fields, filter_=filter_),
1157 self.assertItems([what])
1158 self.assertHandler(rlib2.R_2_query)
1159 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1160 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1161 self.assertEqual(data["fields"], fields)
1163 self.assertTrue("filter" not in data)
1165 self.assertEqual(data["filter"], filter_)
1166 self.assertEqual(self.rapi.CountPending(), 0)
1168 def testQueryFields(self):
1169 exp_result = objects.QueryFieldsResponse(fields=[
1170 objects.QueryFieldDefinition(name="pnode", title="PNode",
1171 kind=constants.QFT_NUMBER),
1172 objects.QueryFieldDefinition(name="other", title="Other",
1173 kind=constants.QFT_BOOL),
1176 for what in constants.QR_VIA_RAPI:
1177 for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1178 self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1179 result = self.client.QueryFields(what, fields=fields)
1180 self.assertItems([what])
1181 self.assertHandler(rlib2.R_2_query_fields)
1182 self.assertFalse(self.rapi.GetLastRequestData())
1184 queryargs = self.rapi.GetLastHandler().queryargs
1186 self.assertFalse(queryargs)
1188 self.assertEqual(queryargs, {
1189 "fields": [",".join(fields)],
1192 self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1193 exp_result.ToDict())
1195 self.assertEqual(self.rapi.CountPending(), 0)
1197 def testWaitForJobCompletionNoChange(self):
1198 resp = serializer.DumpJson({
1199 "status": constants.JOB_STATUS_WAITLOCK,
1202 for retries in [1, 5, 25]:
1203 for _ in range(retries):
1204 self.rapi.AddResponse(resp)
1206 self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1208 self.assertHandler(rlib2.R_2_jobs_id)
1209 self.assertItems(["22789"])
1211 self.assertEqual(self.rapi.CountPending(), 0)
1213 def testWaitForJobCompletionAlreadyFinished(self):
1214 self.rapi.AddResponse(serializer.DumpJson({
1215 "status": constants.JOB_STATUS_SUCCESS,
1218 self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1220 self.assertHandler(rlib2.R_2_jobs_id)
1221 self.assertItems(["22793"])
1223 self.assertEqual(self.rapi.CountPending(), 0)
1225 def testWaitForJobCompletionEmptyResponse(self):
1226 self.rapi.AddResponse("{}")
1227 self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1229 self.assertHandler(rlib2.R_2_jobs_id)
1230 self.assertItems(["22793"])
1232 self.assertEqual(self.rapi.CountPending(), 0)
1234 def testWaitForJobCompletionOutOfRetries(self):
1235 for retries in [3, 10, 21]:
1236 for _ in range(retries):
1237 self.rapi.AddResponse(serializer.DumpJson({
1238 "status": constants.JOB_STATUS_RUNNING,
1241 self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1242 retries=retries - 1))
1243 self.assertHandler(rlib2.R_2_jobs_id)
1244 self.assertItems(["30948"])
1246 self.assertEqual(self.rapi.CountPending(), 1)
1247 self.rapi.ResetResponses()
1249 def testWaitForJobCompletionSuccessAndFailure(self):
1250 for retries in [1, 4, 13]:
1251 for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1252 (True, constants.JOB_STATUS_SUCCESS)]:
1253 for _ in range(retries):
1254 self.rapi.AddResponse(serializer.DumpJson({
1255 "status": constants.JOB_STATUS_RUNNING,
1258 self.rapi.AddResponse(serializer.DumpJson({
1259 "status": end_status,
1262 result = self.client.WaitForJobCompletion(3187, period=None,
1263 retries=retries + 1)
1264 self.assertEqual(result, success)
1265 self.assertHandler(rlib2.R_2_jobs_id)
1266 self.assertItems(["3187"])
1268 self.assertEqual(self.rapi.CountPending(), 0)
1271 class RapiTestRunner(unittest.TextTestRunner):
1272 def run(self, *args):
1273 global _used_handlers
1274 assert _used_handlers is None
1276 _used_handlers = set()
1279 result = unittest.TextTestRunner.run(self, *args)
1281 diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1284 raise AssertionError("The following RAPI resources were not used by the"
1285 " RAPI client: %r" % utils.CommaJoin(diff))
1287 # Reset global variable
1288 _used_handlers = None
1293 if __name__ == '__main__':
1294 client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)