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._NODE_EVAC_RES1, rlib2._NODE_EVAC_RES1)
156 self.assertEqual(client._INST_NIC_PARAMS, constants.INIC_PARAMS)
157 self.assertEqual(client.JOB_STATUS_QUEUED, constants.JOB_STATUS_QUEUED)
158 self.assertEqual(client.JOB_STATUS_WAITLOCK, constants.JOB_STATUS_WAITLOCK)
159 self.assertEqual(client.JOB_STATUS_CANCELING,
160 constants.JOB_STATUS_CANCELING)
161 self.assertEqual(client.JOB_STATUS_RUNNING, constants.JOB_STATUS_RUNNING)
162 self.assertEqual(client.JOB_STATUS_CANCELED, constants.JOB_STATUS_CANCELED)
163 self.assertEqual(client.JOB_STATUS_SUCCESS, constants.JOB_STATUS_SUCCESS)
164 self.assertEqual(client.JOB_STATUS_ERROR, constants.JOB_STATUS_ERROR)
165 self.assertEqual(client.JOB_STATUS_FINALIZED, constants.JOBS_FINALIZED)
166 self.assertEqual(client.JOB_STATUS_ALL, constants.JOB_STATUS_ALL)
169 class RapiMockTest(unittest.TestCase):
173 self.assertEqual((404, None), rapi.FetchResponse("/foo", "GET", None))
174 self.assertEqual((501, "Method not implemented"),
175 rapi.FetchResponse("/version", "POST", None))
176 rapi.AddResponse("2")
177 code, response = rapi.FetchResponse("/version", "GET", None)
178 self.assertEqual(200, code)
179 self.assertEqual("2", response)
180 self.failUnless(isinstance(rapi.GetLastHandler(), rlib2.R_version))
183 def _FakeNoSslPycurlVersion():
184 # Note: incomplete version tuple
185 return (3, "7.16.0", 462848, "mysystem", 1581, None, 0)
188 def _FakeFancySslPycurlVersion():
189 # Note: incomplete version tuple
190 return (3, "7.16.0", 462848, "mysystem", 1581, "FancySSL/1.2.3", 0)
193 def _FakeOpenSslPycurlVersion():
194 # Note: incomplete version tuple
195 return (2, "7.15.5", 462597, "othersystem", 668, "OpenSSL/0.9.8c", 0)
198 def _FakeGnuTlsPycurlVersion():
199 # Note: incomplete version tuple
200 return (3, "7.18.0", 463360, "somesystem", 1581, "GnuTLS/2.0.4", 0)
203 class TestExtendedConfig(unittest.TestCase):
205 cl = client.GanetiRapiClient("master.example.com",
206 username="user", password="pw",
207 curl_factory=lambda: FakeCurl(RapiMock()))
209 curl = cl._CreateCurl()
210 self.assertEqual(curl.getopt(pycurl.HTTPAUTH), pycurl.HTTPAUTH_BASIC)
211 self.assertEqual(curl.getopt(pycurl.USERPWD), "user:pw")
213 def testInvalidAuth(self):
215 self.assertRaises(client.Error, client.GanetiRapiClient,
216 "master-a.example.com", password="pw")
218 self.assertRaises(client.Error, client.GanetiRapiClient,
219 "master-b.example.com", username="user")
221 def testCertVerifyInvalidCombinations(self):
222 self.assertRaises(client.Error, client.GenericCurlConfig,
223 use_curl_cabundle=True, cafile="cert1.pem")
224 self.assertRaises(client.Error, client.GenericCurlConfig,
225 use_curl_cabundle=True, capath="certs/")
226 self.assertRaises(client.Error, client.GenericCurlConfig,
227 use_curl_cabundle=True,
228 cafile="cert1.pem", capath="certs/")
230 def testProxySignalVerifyHostname(self):
231 for use_gnutls in [False, True]:
233 pcverfn = _FakeGnuTlsPycurlVersion
235 pcverfn = _FakeOpenSslPycurlVersion
237 for proxy in ["", "http://127.0.0.1:1234"]:
238 for use_signal in [False, True]:
239 for verify_hostname in [False, True]:
240 cfgfn = client.GenericCurlConfig(proxy=proxy, use_signal=use_signal,
241 verify_hostname=verify_hostname,
242 _pycurl_version_fn=pcverfn)
244 curl_factory = lambda: FakeCurl(RapiMock())
245 cl = client.GanetiRapiClient("master.example.com",
246 curl_config_fn=cfgfn,
247 curl_factory=curl_factory)
249 curl = cl._CreateCurl()
250 self.assertEqual(curl.getopt(pycurl.PROXY), proxy)
251 self.assertEqual(curl.getopt(pycurl.NOSIGNAL), not use_signal)
254 self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 2)
256 self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 0)
258 def testNoCertVerify(self):
259 cfgfn = client.GenericCurlConfig()
261 curl_factory = lambda: FakeCurl(RapiMock())
262 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
263 curl_factory=curl_factory)
265 curl = cl._CreateCurl()
266 self.assertFalse(curl.getopt(pycurl.SSL_VERIFYPEER))
267 self.assertFalse(curl.getopt(pycurl.CAINFO))
268 self.assertFalse(curl.getopt(pycurl.CAPATH))
270 def testCertVerifyCurlBundle(self):
271 cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
273 curl_factory = lambda: FakeCurl(RapiMock())
274 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
275 curl_factory=curl_factory)
277 curl = cl._CreateCurl()
278 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
279 self.assertFalse(curl.getopt(pycurl.CAINFO))
280 self.assertFalse(curl.getopt(pycurl.CAPATH))
282 def testCertVerifyCafile(self):
283 mycert = "/tmp/some/UNUSED/cert/file.pem"
284 cfgfn = client.GenericCurlConfig(cafile=mycert)
286 curl_factory = lambda: FakeCurl(RapiMock())
287 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
288 curl_factory=curl_factory)
290 curl = cl._CreateCurl()
291 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
292 self.assertEqual(curl.getopt(pycurl.CAINFO), mycert)
293 self.assertFalse(curl.getopt(pycurl.CAPATH))
295 def testCertVerifyCapath(self):
296 certdir = "/tmp/some/UNUSED/cert/directory"
297 pcverfn = _FakeOpenSslPycurlVersion
298 cfgfn = client.GenericCurlConfig(capath=certdir,
299 _pycurl_version_fn=pcverfn)
301 curl_factory = lambda: FakeCurl(RapiMock())
302 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
303 curl_factory=curl_factory)
305 curl = cl._CreateCurl()
306 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
307 self.assertEqual(curl.getopt(pycurl.CAPATH), certdir)
308 self.assertFalse(curl.getopt(pycurl.CAINFO))
310 def testCertVerifyCapathGnuTls(self):
311 certdir = "/tmp/some/UNUSED/cert/directory"
312 pcverfn = _FakeGnuTlsPycurlVersion
313 cfgfn = client.GenericCurlConfig(capath=certdir,
314 _pycurl_version_fn=pcverfn)
316 curl_factory = lambda: FakeCurl(RapiMock())
317 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
318 curl_factory=curl_factory)
320 self.assertRaises(client.Error, cl._CreateCurl)
322 def testCertVerifyNoSsl(self):
323 certdir = "/tmp/some/UNUSED/cert/directory"
324 pcverfn = _FakeNoSslPycurlVersion
325 cfgfn = client.GenericCurlConfig(capath=certdir,
326 _pycurl_version_fn=pcverfn)
328 curl_factory = lambda: FakeCurl(RapiMock())
329 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
330 curl_factory=curl_factory)
332 self.assertRaises(client.Error, cl._CreateCurl)
334 def testCertVerifyFancySsl(self):
335 certdir = "/tmp/some/UNUSED/cert/directory"
336 pcverfn = _FakeFancySslPycurlVersion
337 cfgfn = client.GenericCurlConfig(capath=certdir,
338 _pycurl_version_fn=pcverfn)
340 curl_factory = lambda: FakeCurl(RapiMock())
341 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
342 curl_factory=curl_factory)
344 self.assertRaises(NotImplementedError, cl._CreateCurl)
346 def testCertVerifyCapath(self):
347 for connect_timeout in [None, 1, 5, 10, 30, 60, 300]:
348 for timeout in [None, 1, 30, 60, 3600, 24 * 3600]:
349 cfgfn = client.GenericCurlConfig(connect_timeout=connect_timeout,
352 curl_factory = lambda: FakeCurl(RapiMock())
353 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
354 curl_factory=curl_factory)
356 curl = cl._CreateCurl()
357 self.assertEqual(curl.getopt(pycurl.CONNECTTIMEOUT), connect_timeout)
358 self.assertEqual(curl.getopt(pycurl.TIMEOUT), timeout)
361 class GanetiRapiClientTests(testutils.GanetiTestCase):
363 testutils.GanetiTestCase.setUp(self)
365 self.rapi = RapiMock()
366 self.curl = FakeCurl(self.rapi)
367 self.client = client.GanetiRapiClient("master.example.com",
368 curl_factory=lambda: self.curl)
370 def assertHandler(self, handler_cls):
371 self.failUnless(isinstance(self.rapi.GetLastHandler(), handler_cls))
373 def assertQuery(self, key, value):
374 self.assertEqual(value, self.rapi.GetLastHandler().queryargs.get(key, None))
376 def assertItems(self, items):
377 self.assertEqual(items, self.rapi.GetLastHandler().items)
379 def assertBulk(self):
380 self.assertTrue(self.rapi.GetLastHandler().useBulk())
382 def assertDryRun(self):
383 self.assertTrue(self.rapi.GetLastHandler().dryRun())
385 def assertUseForce(self):
386 self.assertTrue(self.rapi.GetLastHandler().useForce())
388 def testEncodeQuery(self):
405 self.assertEqualValues(self.client._EncodeQuery(query),
409 for i in [[1, 2, 3], {"moo": "boo"}, (1, 2, 3)]:
410 self.assertRaises(ValueError, self.client._EncodeQuery, [("x", i)])
412 def testCurlSettings(self):
413 self.rapi.AddResponse("2")
414 self.assertEqual(2, self.client.GetVersion())
415 self.assertHandler(rlib2.R_version)
417 # Signals should be disabled by default
418 self.assert_(self.curl.getopt(pycurl.NOSIGNAL))
420 # No auth and no proxy
421 self.assertFalse(self.curl.getopt(pycurl.USERPWD))
422 self.assert_(self.curl.getopt(pycurl.PROXY) is None)
424 # Content-type is required for requests
425 headers = self.curl.getopt(pycurl.HTTPHEADER)
426 self.assert_("Content-type: application/json" in headers)
428 def testHttpError(self):
429 self.rapi.AddResponse(None, code=404)
431 self.client.GetJobStatus(15140)
432 except client.GanetiApiError, err:
433 self.assertEqual(err.code, 404)
435 self.fail("Didn't raise exception")
437 def testGetVersion(self):
438 self.rapi.AddResponse("2")
439 self.assertEqual(2, self.client.GetVersion())
440 self.assertHandler(rlib2.R_version)
442 def testGetFeatures(self):
443 for features in [[], ["foo", "bar", "baz"]]:
444 self.rapi.AddResponse(serializer.DumpJson(features))
445 self.assertEqual(features, self.client.GetFeatures())
446 self.assertHandler(rlib2.R_2_features)
448 def testGetFeaturesNotFound(self):
449 self.rapi.AddResponse(None, code=404)
450 self.assertEqual([], self.client.GetFeatures())
452 def testGetOperatingSystems(self):
453 self.rapi.AddResponse("[\"beos\"]")
454 self.assertEqual(["beos"], self.client.GetOperatingSystems())
455 self.assertHandler(rlib2.R_2_os)
457 def testGetClusterTags(self):
458 self.rapi.AddResponse("[\"tag\"]")
459 self.assertEqual(["tag"], self.client.GetClusterTags())
460 self.assertHandler(rlib2.R_2_tags)
462 def testAddClusterTags(self):
463 self.rapi.AddResponse("1234")
464 self.assertEqual(1234,
465 self.client.AddClusterTags(["awesome"], dry_run=True))
466 self.assertHandler(rlib2.R_2_tags)
468 self.assertQuery("tag", ["awesome"])
470 def testDeleteClusterTags(self):
471 self.rapi.AddResponse("5107")
472 self.assertEqual(5107, self.client.DeleteClusterTags(["awesome"],
474 self.assertHandler(rlib2.R_2_tags)
476 self.assertQuery("tag", ["awesome"])
478 def testGetInfo(self):
479 self.rapi.AddResponse("{}")
480 self.assertEqual({}, self.client.GetInfo())
481 self.assertHandler(rlib2.R_2_info)
483 def testGetInstances(self):
484 self.rapi.AddResponse("[]")
485 self.assertEqual([], self.client.GetInstances(bulk=True))
486 self.assertHandler(rlib2.R_2_instances)
489 def testGetInstance(self):
490 self.rapi.AddResponse("[]")
491 self.assertEqual([], self.client.GetInstance("instance"))
492 self.assertHandler(rlib2.R_2_instances_name)
493 self.assertItems(["instance"])
495 def testGetInstanceInfo(self):
496 self.rapi.AddResponse("21291")
497 self.assertEqual(21291, self.client.GetInstanceInfo("inst3"))
498 self.assertHandler(rlib2.R_2_instances_name_info)
499 self.assertItems(["inst3"])
500 self.assertQuery("static", None)
502 self.rapi.AddResponse("3428")
503 self.assertEqual(3428, self.client.GetInstanceInfo("inst31", static=False))
504 self.assertHandler(rlib2.R_2_instances_name_info)
505 self.assertItems(["inst31"])
506 self.assertQuery("static", ["0"])
508 self.rapi.AddResponse("15665")
509 self.assertEqual(15665, self.client.GetInstanceInfo("inst32", static=True))
510 self.assertHandler(rlib2.R_2_instances_name_info)
511 self.assertItems(["inst32"])
512 self.assertQuery("static", ["1"])
514 def testCreateInstanceOldVersion(self):
515 # The old request format, version 0, is no longer supported
516 self.rapi.AddResponse(None, code=404)
517 self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
518 "create", "inst1.example.com", "plain", [], [])
519 self.assertEqual(self.rapi.CountPending(), 0)
521 def testCreateInstance(self):
522 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
523 self.rapi.AddResponse("23030")
524 job_id = self.client.CreateInstance("create", "inst1.example.com",
525 "plain", [], [], dry_run=True)
526 self.assertEqual(job_id, 23030)
527 self.assertHandler(rlib2.R_2_instances)
530 data = serializer.LoadJson(self.rapi.GetLastRequestData())
532 for field in ["dry_run", "beparams", "hvparams", "start"]:
533 self.assertFalse(field in data)
535 self.assertEqual(data["name"], "inst1.example.com")
536 self.assertEqual(data["disk_template"], "plain")
538 def testCreateInstance2(self):
539 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
540 self.rapi.AddResponse("24740")
541 job_id = self.client.CreateInstance("import", "inst2.example.com",
542 "drbd8", [{"size": 100,}],
543 [{}, {"bridge": "br1", }],
544 dry_run=False, start=True,
545 pnode="node1", snode="node9",
547 self.assertEqual(job_id, 24740)
548 self.assertHandler(rlib2.R_2_instances)
550 data = serializer.LoadJson(self.rapi.GetLastRequestData())
551 self.assertEqual(data[rlib2._REQ_DATA_VERSION], 1)
552 self.assertEqual(data["name"], "inst2.example.com")
553 self.assertEqual(data["disk_template"], "drbd8")
554 self.assertEqual(data["start"], True)
555 self.assertEqual(data["ip_check"], False)
556 self.assertEqualValues(data["disks"], [{"size": 100,}])
557 self.assertEqualValues(data["nics"], [{}, {"bridge": "br1", }])
559 def testDeleteInstance(self):
560 self.rapi.AddResponse("1234")
561 self.assertEqual(1234, self.client.DeleteInstance("instance", dry_run=True))
562 self.assertHandler(rlib2.R_2_instances_name)
563 self.assertItems(["instance"])
566 def testGetInstanceTags(self):
567 self.rapi.AddResponse("[]")
568 self.assertEqual([], self.client.GetInstanceTags("fooinstance"))
569 self.assertHandler(rlib2.R_2_instances_name_tags)
570 self.assertItems(["fooinstance"])
572 def testAddInstanceTags(self):
573 self.rapi.AddResponse("1234")
574 self.assertEqual(1234,
575 self.client.AddInstanceTags("fooinstance", ["awesome"], dry_run=True))
576 self.assertHandler(rlib2.R_2_instances_name_tags)
577 self.assertItems(["fooinstance"])
579 self.assertQuery("tag", ["awesome"])
581 def testDeleteInstanceTags(self):
582 self.rapi.AddResponse("25826")
583 self.assertEqual(25826, self.client.DeleteInstanceTags("foo", ["awesome"],
585 self.assertHandler(rlib2.R_2_instances_name_tags)
586 self.assertItems(["foo"])
588 self.assertQuery("tag", ["awesome"])
590 def testRebootInstance(self):
591 self.rapi.AddResponse("6146")
592 job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
593 ignore_secondaries=True, dry_run=True)
594 self.assertEqual(6146, job_id)
595 self.assertHandler(rlib2.R_2_instances_name_reboot)
596 self.assertItems(["i-bar"])
598 self.assertQuery("type", ["hard"])
599 self.assertQuery("ignore_secondaries", ["1"])
601 def testShutdownInstance(self):
602 self.rapi.AddResponse("1487")
603 self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
605 self.assertHandler(rlib2.R_2_instances_name_shutdown)
606 self.assertItems(["foo-instance"])
609 def testStartupInstance(self):
610 self.rapi.AddResponse("27149")
611 self.assertEqual(27149, self.client.StartupInstance("bar-instance",
613 self.assertHandler(rlib2.R_2_instances_name_startup)
614 self.assertItems(["bar-instance"])
617 def testReinstallInstance(self):
618 self.rapi.AddResponse(serializer.DumpJson([]))
619 self.rapi.AddResponse("19119")
620 self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
623 self.assertHandler(rlib2.R_2_instances_name_reinstall)
624 self.assertItems(["baz-instance"])
625 self.assertQuery("os", ["DOS"])
626 self.assertQuery("nostartup", ["1"])
627 self.assertEqual(self.rapi.CountPending(), 0)
629 def testReinstallInstanceNew(self):
630 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
631 self.rapi.AddResponse("25689")
632 self.assertEqual(25689, self.client.ReinstallInstance("moo-instance",
635 self.assertHandler(rlib2.R_2_instances_name_reinstall)
636 self.assertItems(["moo-instance"])
637 data = serializer.LoadJson(self.rapi.GetLastRequestData())
638 self.assertEqual(len(data), 2)
639 self.assertEqual(data["os"], "Debian")
640 self.assertEqual(data["start"], False)
641 self.assertEqual(self.rapi.CountPending(), 0)
643 def testReinstallInstanceWithOsparams1(self):
644 self.rapi.AddResponse(serializer.DumpJson([]))
645 self.assertRaises(client.GanetiApiError, self.client.ReinstallInstance,
646 "doo-instance", osparams={"x": "y"})
647 self.assertEqual(self.rapi.CountPending(), 0)
649 def testReinstallInstanceWithOsparams2(self):
654 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
655 self.rapi.AddResponse("1717")
656 self.assertEqual(1717, self.client.ReinstallInstance("zoo-instance",
658 self.assertHandler(rlib2.R_2_instances_name_reinstall)
659 self.assertItems(["zoo-instance"])
660 data = serializer.LoadJson(self.rapi.GetLastRequestData())
661 self.assertEqual(len(data), 2)
662 self.assertEqual(data["osparams"], osparams)
663 self.assertEqual(data["start"], True)
664 self.assertEqual(self.rapi.CountPending(), 0)
666 def testReplaceInstanceDisks(self):
667 self.rapi.AddResponse("999")
668 job_id = self.client.ReplaceInstanceDisks("instance-name",
669 disks=[0, 1], dry_run=True, iallocator="hail")
670 self.assertEqual(999, job_id)
671 self.assertHandler(rlib2.R_2_instances_name_replace_disks)
672 self.assertItems(["instance-name"])
673 self.assertQuery("disks", ["0,1"])
674 self.assertQuery("mode", ["replace_auto"])
675 self.assertQuery("iallocator", ["hail"])
678 self.rapi.AddResponse("1000")
679 job_id = self.client.ReplaceInstanceDisks("instance-bar",
680 disks=[1], mode="replace_on_secondary", remote_node="foo-node",
682 self.assertEqual(1000, job_id)
683 self.assertItems(["instance-bar"])
684 self.assertQuery("disks", ["1"])
685 self.assertQuery("remote_node", ["foo-node"])
688 self.rapi.AddResponse("5175")
689 self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
690 self.assertItems(["instance-moo"])
691 self.assertQuery("disks", None)
693 def testPrepareExport(self):
694 self.rapi.AddResponse("8326")
695 self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
696 self.assertHandler(rlib2.R_2_instances_name_prepare_export)
697 self.assertItems(["inst1"])
698 self.assertQuery("mode", ["local"])
700 def testExportInstance(self):
701 self.rapi.AddResponse("19695")
702 job_id = self.client.ExportInstance("inst2", "local", "nodeX",
704 self.assertEqual(job_id, 19695)
705 self.assertHandler(rlib2.R_2_instances_name_export)
706 self.assertItems(["inst2"])
708 data = serializer.LoadJson(self.rapi.GetLastRequestData())
709 self.assertEqual(data["mode"], "local")
710 self.assertEqual(data["destination"], "nodeX")
711 self.assertEqual(data["shutdown"], True)
713 def testMigrateInstanceDefaults(self):
714 self.rapi.AddResponse("24873")
715 job_id = self.client.MigrateInstance("inst91")
716 self.assertEqual(job_id, 24873)
717 self.assertHandler(rlib2.R_2_instances_name_migrate)
718 self.assertItems(["inst91"])
720 data = serializer.LoadJson(self.rapi.GetLastRequestData())
721 self.assertFalse(data)
723 def testMigrateInstance(self):
724 for mode in constants.HT_MIGRATION_MODES:
725 for cleanup in [False, True]:
726 self.rapi.AddResponse("31910")
727 job_id = self.client.MigrateInstance("inst289", mode=mode,
729 self.assertEqual(job_id, 31910)
730 self.assertHandler(rlib2.R_2_instances_name_migrate)
731 self.assertItems(["inst289"])
733 data = serializer.LoadJson(self.rapi.GetLastRequestData())
734 self.assertEqual(len(data), 2)
735 self.assertEqual(data["mode"], mode)
736 self.assertEqual(data["cleanup"], cleanup)
738 def testRenameInstanceDefaults(self):
739 new_name = "newnametha7euqu"
740 self.rapi.AddResponse("8791")
741 job_id = self.client.RenameInstance("inst18821", new_name)
742 self.assertEqual(job_id, 8791)
743 self.assertHandler(rlib2.R_2_instances_name_rename)
744 self.assertItems(["inst18821"])
746 data = serializer.LoadJson(self.rapi.GetLastRequestData())
747 self.assertEqualValues(data, {"new_name": new_name, })
749 def testRenameInstance(self):
750 new_name = "new-name-yiux1iin"
751 for ip_check in [False, True]:
752 for name_check in [False, True]:
753 self.rapi.AddResponse("24776")
754 job_id = self.client.RenameInstance("inst20967", new_name,
756 name_check=name_check)
757 self.assertEqual(job_id, 24776)
758 self.assertHandler(rlib2.R_2_instances_name_rename)
759 self.assertItems(["inst20967"])
761 data = serializer.LoadJson(self.rapi.GetLastRequestData())
762 self.assertEqual(len(data), 3)
763 self.assertEqual(data["new_name"], new_name)
764 self.assertEqual(data["ip_check"], ip_check)
765 self.assertEqual(data["name_check"], name_check)
767 def testGetJobs(self):
768 self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
769 ' { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
770 self.assertEqual([123, 124], self.client.GetJobs())
771 self.assertHandler(rlib2.R_2_jobs)
773 def testGetJobStatus(self):
774 self.rapi.AddResponse("{\"foo\": \"bar\"}")
775 self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
776 self.assertHandler(rlib2.R_2_jobs_id)
777 self.assertItems(["1234"])
779 def testWaitForJobChange(self):
780 fields = ["id", "summary"]
782 "job_info": [123, "something"],
786 self.rapi.AddResponse(serializer.DumpJson(expected))
787 result = self.client.WaitForJobChange(123, fields, [], -1)
788 self.assertEqualValues(expected, result)
789 self.assertHandler(rlib2.R_2_jobs_id_wait)
790 self.assertItems(["123"])
792 def testCancelJob(self):
793 self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
794 self.assertEqual([True, "Job 123 will be canceled"],
795 self.client.CancelJob(999, dry_run=True))
796 self.assertHandler(rlib2.R_2_jobs_id)
797 self.assertItems(["999"])
800 def testGetNodes(self):
801 self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
802 " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
803 self.assertEqual(["node1", "node2"], self.client.GetNodes())
804 self.assertHandler(rlib2.R_2_nodes)
806 self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
807 " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
808 self.assertEqual([{"id": "node1", "uri": "uri1"},
809 {"id": "node2", "uri": "uri2"}],
810 self.client.GetNodes(bulk=True))
811 self.assertHandler(rlib2.R_2_nodes)
814 def testGetNode(self):
815 self.rapi.AddResponse("{}")
816 self.assertEqual({}, self.client.GetNode("node-foo"))
817 self.assertHandler(rlib2.R_2_nodes_name)
818 self.assertItems(["node-foo"])
820 def testEvacuateNode(self):
821 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
822 self.rapi.AddResponse("9876")
823 job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
824 self.assertEqual(9876, job_id)
825 self.assertHandler(rlib2.R_2_nodes_name_evacuate)
826 self.assertItems(["node-1"])
827 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
828 { "remote_node": "node-2", })
829 self.assertEqual(self.rapi.CountPending(), 0)
831 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
832 self.rapi.AddResponse("8888")
833 job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True)
834 self.assertEqual(8888, job_id)
835 self.assertItems(["node-3"])
836 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
837 { "iallocator": "hail", })
840 self.assertRaises(client.GanetiApiError,
841 self.client.EvacuateNode,
842 "node-4", iallocator="hail", remote_node="node-5")
843 self.assertEqual(self.rapi.CountPending(), 0)
845 def testEvacuateNodeOldResponse(self):
846 self.rapi.AddResponse(serializer.DumpJson([]))
847 self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
848 "node-4", accept_old=False)
849 self.assertEqual(self.rapi.CountPending(), 0)
851 self.rapi.AddResponse(serializer.DumpJson([]))
852 self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
853 "node-4", accept_old=True)
854 self.assertEqual(self.rapi.CountPending(), 0)
856 self.rapi.AddResponse(serializer.DumpJson([]))
857 self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
858 "node-4", accept_old=True, primary=True)
859 self.assertEqual(self.rapi.CountPending(), 0)
861 self.rapi.AddResponse(serializer.DumpJson([]))
862 self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
863 "node-4", accept_old=True, secondary=False)
864 self.assertEqual(self.rapi.CountPending(), 0)
866 for sec in [True, None]:
867 self.rapi.AddResponse(serializer.DumpJson([]))
868 self.rapi.AddResponse(serializer.DumpJson([["res", "foo"]]))
869 result = self.client.EvacuateNode("node-3", iallocator="hail",
870 dry_run=True, accept_old=True,
871 primary=False, secondary=sec)
872 self.assertEqual(result, [["res", "foo"]])
873 self.assertItems(["node-3"])
874 self.assertQuery("iallocator", ["hail"])
875 self.assertFalse(self.rapi.GetLastRequestData())
877 self.assertEqual(self.rapi.CountPending(), 0)
879 def testMigrateNode(self):
880 self.rapi.AddResponse(serializer.DumpJson([]))
881 self.rapi.AddResponse("1111")
882 self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
883 self.assertHandler(rlib2.R_2_nodes_name_migrate)
884 self.assertItems(["node-a"])
885 self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
887 self.assertFalse(self.rapi.GetLastRequestData())
889 self.rapi.AddResponse(serializer.DumpJson([]))
890 self.rapi.AddResponse("1112")
891 self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
893 self.assertHandler(rlib2.R_2_nodes_name_migrate)
894 self.assertItems(["node-a"])
895 self.assertQuery("mode", ["live"])
897 self.assertFalse(self.rapi.GetLastRequestData())
899 self.rapi.AddResponse(serializer.DumpJson([]))
900 self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
901 "node-c", target_node="foonode")
902 self.assertEqual(self.rapi.CountPending(), 0)
904 def testMigrateNodeBodyData(self):
905 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
906 self.rapi.AddResponse("27539")
907 self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
909 self.assertHandler(rlib2.R_2_nodes_name_migrate)
910 self.assertItems(["node-a"])
911 self.assertFalse(self.rapi.GetLastHandler().queryargs)
912 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
915 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
916 self.rapi.AddResponse("14219")
917 self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
920 self.assertHandler(rlib2.R_2_nodes_name_migrate)
921 self.assertItems(["node-x"])
923 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
924 { "target_node": "node9", "iallocator": "ial", })
926 self.assertEqual(self.rapi.CountPending(), 0)
928 def testGetNodeRole(self):
929 self.rapi.AddResponse("\"master\"")
930 self.assertEqual("master", self.client.GetNodeRole("node-a"))
931 self.assertHandler(rlib2.R_2_nodes_name_role)
932 self.assertItems(["node-a"])
934 def testSetNodeRole(self):
935 self.rapi.AddResponse("789")
936 self.assertEqual(789,
937 self.client.SetNodeRole("node-foo", "master-candidate", force=True))
938 self.assertHandler(rlib2.R_2_nodes_name_role)
939 self.assertItems(["node-foo"])
940 self.assertQuery("force", ["1"])
941 self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
943 def testGetNodeStorageUnits(self):
944 self.rapi.AddResponse("42")
946 self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
947 self.assertHandler(rlib2.R_2_nodes_name_storage)
948 self.assertItems(["node-x"])
949 self.assertQuery("storage_type", ["lvm-pv"])
950 self.assertQuery("output_fields", ["fields"])
952 def testModifyNodeStorageUnits(self):
953 self.rapi.AddResponse("14")
955 self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
956 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
957 self.assertItems(["node-z"])
958 self.assertQuery("storage_type", ["lvm-pv"])
959 self.assertQuery("name", ["hda"])
960 self.assertQuery("allocatable", None)
962 for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
963 self.rapi.AddResponse("7205")
964 job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
965 allocatable=allocatable)
966 self.assertEqual(7205, job_id)
967 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
968 self.assertItems(["node-z"])
969 self.assertQuery("storage_type", ["lvm-pv"])
970 self.assertQuery("name", ["hda"])
971 self.assertQuery("allocatable", [query_allocatable])
973 def testRepairNodeStorageUnits(self):
974 self.rapi.AddResponse("99")
975 self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
977 self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
978 self.assertItems(["node-z"])
979 self.assertQuery("storage_type", ["lvm-pv"])
980 self.assertQuery("name", ["hda"])
982 def testGetNodeTags(self):
983 self.rapi.AddResponse("[\"fry\", \"bender\"]")
984 self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
985 self.assertHandler(rlib2.R_2_nodes_name_tags)
986 self.assertItems(["node-k"])
988 def testAddNodeTags(self):
989 self.rapi.AddResponse("1234")
990 self.assertEqual(1234,
991 self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
992 self.assertHandler(rlib2.R_2_nodes_name_tags)
993 self.assertItems(["node-v"])
995 self.assertQuery("tag", ["awesome"])
997 def testDeleteNodeTags(self):
998 self.rapi.AddResponse("16861")
999 self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1001 self.assertHandler(rlib2.R_2_nodes_name_tags)
1002 self.assertItems(["node-w"])
1004 self.assertQuery("tag", ["awesome"])
1006 def testGetGroups(self):
1007 groups = [{"name": "group1",
1008 "uri": "/2/groups/group1",
1011 "uri": "/2/groups/group2",
1014 self.rapi.AddResponse(serializer.DumpJson(groups))
1015 self.assertEqual(["group1", "group2"], self.client.GetGroups())
1016 self.assertHandler(rlib2.R_2_groups)
1018 def testGetGroupsBulk(self):
1019 groups = [{"name": "group1",
1020 "uri": "/2/groups/group1",
1022 "node_list": ["gnt1.test",
1027 "uri": "/2/groups/group2",
1029 "node_list": ["gnt3.test",
1033 self.rapi.AddResponse(serializer.DumpJson(groups))
1035 self.assertEqual(groups, self.client.GetGroups(bulk=True))
1036 self.assertHandler(rlib2.R_2_groups)
1039 def testGetGroup(self):
1040 group = {"ctime": None,
1043 self.rapi.AddResponse(serializer.DumpJson(group))
1044 self.assertEqual({"ctime": None, "name": "default"},
1045 self.client.GetGroup("default"))
1046 self.assertHandler(rlib2.R_2_groups_name)
1047 self.assertItems(["default"])
1049 def testCreateGroup(self):
1050 self.rapi.AddResponse("12345")
1051 job_id = self.client.CreateGroup("newgroup", dry_run=True)
1052 self.assertEqual(job_id, 12345)
1053 self.assertHandler(rlib2.R_2_groups)
1056 def testDeleteGroup(self):
1057 self.rapi.AddResponse("12346")
1058 job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1059 self.assertEqual(job_id, 12346)
1060 self.assertHandler(rlib2.R_2_groups_name)
1063 def testRenameGroup(self):
1064 self.rapi.AddResponse("12347")
1065 job_id = self.client.RenameGroup("oldname", "newname")
1066 self.assertEqual(job_id, 12347)
1067 self.assertHandler(rlib2.R_2_groups_name_rename)
1069 def testModifyGroup(self):
1070 self.rapi.AddResponse("12348")
1071 job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1072 self.assertEqual(job_id, 12348)
1073 self.assertHandler(rlib2.R_2_groups_name_modify)
1075 def testAssignGroupNodes(self):
1076 self.rapi.AddResponse("12349")
1077 job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1078 force=True, dry_run=True)
1079 self.assertEqual(job_id, 12349)
1080 self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1082 self.assertUseForce()
1084 def testModifyInstance(self):
1085 self.rapi.AddResponse("23681")
1086 job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1087 self.assertEqual(job_id, 23681)
1088 self.assertItems(["inst7210"])
1089 self.assertHandler(rlib2.R_2_instances_name_modify)
1090 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1091 { "os_name": "linux", })
1093 def testModifyCluster(self):
1094 for mnh in [None, False, True]:
1095 self.rapi.AddResponse("14470")
1096 self.assertEqual(14470,
1097 self.client.ModifyCluster(maintain_node_health=mnh))
1098 self.assertHandler(rlib2.R_2_cluster_modify)
1099 self.assertItems([])
1100 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1101 self.assertEqual(len(data), 1)
1102 self.assertEqual(data["maintain_node_health"], mnh)
1103 self.assertEqual(self.rapi.CountPending(), 0)
1105 def testRedistributeConfig(self):
1106 self.rapi.AddResponse("3364")
1107 job_id = self.client.RedistributeConfig()
1108 self.assertEqual(job_id, 3364)
1109 self.assertItems([])
1110 self.assertHandler(rlib2.R_2_redist_config)
1112 def testActivateInstanceDisks(self):
1113 self.rapi.AddResponse("23547")
1114 job_id = self.client.ActivateInstanceDisks("inst28204")
1115 self.assertEqual(job_id, 23547)
1116 self.assertItems(["inst28204"])
1117 self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1118 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1120 def testActivateInstanceDisksIgnoreSize(self):
1121 self.rapi.AddResponse("11044")
1122 job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1123 self.assertEqual(job_id, 11044)
1124 self.assertItems(["inst28204"])
1125 self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1126 self.assertQuery("ignore_size", ["1"])
1128 def testDeactivateInstanceDisks(self):
1129 self.rapi.AddResponse("14591")
1130 job_id = self.client.DeactivateInstanceDisks("inst28234")
1131 self.assertEqual(job_id, 14591)
1132 self.assertItems(["inst28234"])
1133 self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1134 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1136 def testGetInstanceConsole(self):
1137 self.rapi.AddResponse("26876")
1138 job_id = self.client.GetInstanceConsole("inst21491")
1139 self.assertEqual(job_id, 26876)
1140 self.assertItems(["inst21491"])
1141 self.assertHandler(rlib2.R_2_instances_name_console)
1142 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1143 self.assertFalse(self.rapi.GetLastRequestData())
1145 def testGrowInstanceDisk(self):
1146 for idx, wait_for_sync in enumerate([None, False, True]):
1147 amount = 128 + (512 * idx)
1148 self.assertEqual(self.rapi.CountPending(), 0)
1149 self.rapi.AddResponse("30783")
1150 self.assertEqual(30783,
1151 self.client.GrowInstanceDisk("eze8ch", idx, amount,
1152 wait_for_sync=wait_for_sync))
1153 self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1154 self.assertItems(["eze8ch", str(idx)])
1155 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1156 if wait_for_sync is None:
1157 self.assertEqual(len(data), 1)
1158 self.assert_("wait_for_sync" not in data)
1160 self.assertEqual(len(data), 2)
1161 self.assertEqual(data["wait_for_sync"], wait_for_sync)
1162 self.assertEqual(data["amount"], amount)
1163 self.assertEqual(self.rapi.CountPending(), 0)
1165 def testGetGroupTags(self):
1166 self.rapi.AddResponse("[]")
1167 self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1168 self.assertHandler(rlib2.R_2_groups_name_tags)
1169 self.assertItems(["fooGroup"])
1171 def testAddGroupTags(self):
1172 self.rapi.AddResponse("1234")
1173 self.assertEqual(1234,
1174 self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1175 self.assertHandler(rlib2.R_2_groups_name_tags)
1176 self.assertItems(["fooGroup"])
1178 self.assertQuery("tag", ["awesome"])
1180 def testDeleteGroupTags(self):
1181 self.rapi.AddResponse("25826")
1182 self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1184 self.assertHandler(rlib2.R_2_groups_name_tags)
1185 self.assertItems(["foo"])
1187 self.assertQuery("tag", ["awesome"])
1189 def testQuery(self):
1190 for idx, what in enumerate(constants.QR_VIA_RAPI):
1191 for idx2, filter_ in enumerate([None, ["?", "name"]]):
1192 job_id = 11010 + (idx << 4) + (idx2 << 16)
1193 fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1195 self.rapi.AddResponse(str(job_id))
1196 self.assertEqual(self.client.Query(what, fields, filter_=filter_),
1198 self.assertItems([what])
1199 self.assertHandler(rlib2.R_2_query)
1200 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1201 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1202 self.assertEqual(data["fields"], fields)
1204 self.assertTrue("filter" not in data)
1206 self.assertEqual(data["filter"], filter_)
1207 self.assertEqual(self.rapi.CountPending(), 0)
1209 def testQueryFields(self):
1210 exp_result = objects.QueryFieldsResponse(fields=[
1211 objects.QueryFieldDefinition(name="pnode", title="PNode",
1212 kind=constants.QFT_NUMBER),
1213 objects.QueryFieldDefinition(name="other", title="Other",
1214 kind=constants.QFT_BOOL),
1217 for what in constants.QR_VIA_RAPI:
1218 for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1219 self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1220 result = self.client.QueryFields(what, fields=fields)
1221 self.assertItems([what])
1222 self.assertHandler(rlib2.R_2_query_fields)
1223 self.assertFalse(self.rapi.GetLastRequestData())
1225 queryargs = self.rapi.GetLastHandler().queryargs
1227 self.assertFalse(queryargs)
1229 self.assertEqual(queryargs, {
1230 "fields": [",".join(fields)],
1233 self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1234 exp_result.ToDict())
1236 self.assertEqual(self.rapi.CountPending(), 0)
1238 def testWaitForJobCompletionNoChange(self):
1239 resp = serializer.DumpJson({
1240 "status": constants.JOB_STATUS_WAITLOCK,
1243 for retries in [1, 5, 25]:
1244 for _ in range(retries):
1245 self.rapi.AddResponse(resp)
1247 self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1249 self.assertHandler(rlib2.R_2_jobs_id)
1250 self.assertItems(["22789"])
1252 self.assertEqual(self.rapi.CountPending(), 0)
1254 def testWaitForJobCompletionAlreadyFinished(self):
1255 self.rapi.AddResponse(serializer.DumpJson({
1256 "status": constants.JOB_STATUS_SUCCESS,
1259 self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1261 self.assertHandler(rlib2.R_2_jobs_id)
1262 self.assertItems(["22793"])
1264 self.assertEqual(self.rapi.CountPending(), 0)
1266 def testWaitForJobCompletionEmptyResponse(self):
1267 self.rapi.AddResponse("{}")
1268 self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1270 self.assertHandler(rlib2.R_2_jobs_id)
1271 self.assertItems(["22793"])
1273 self.assertEqual(self.rapi.CountPending(), 0)
1275 def testWaitForJobCompletionOutOfRetries(self):
1276 for retries in [3, 10, 21]:
1277 for _ in range(retries):
1278 self.rapi.AddResponse(serializer.DumpJson({
1279 "status": constants.JOB_STATUS_RUNNING,
1282 self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1283 retries=retries - 1))
1284 self.assertHandler(rlib2.R_2_jobs_id)
1285 self.assertItems(["30948"])
1287 self.assertEqual(self.rapi.CountPending(), 1)
1288 self.rapi.ResetResponses()
1290 def testWaitForJobCompletionSuccessAndFailure(self):
1291 for retries in [1, 4, 13]:
1292 for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1293 (True, constants.JOB_STATUS_SUCCESS)]:
1294 for _ in range(retries):
1295 self.rapi.AddResponse(serializer.DumpJson({
1296 "status": constants.JOB_STATUS_RUNNING,
1299 self.rapi.AddResponse(serializer.DumpJson({
1300 "status": end_status,
1303 result = self.client.WaitForJobCompletion(3187, period=None,
1304 retries=retries + 1)
1305 self.assertEqual(result, success)
1306 self.assertHandler(rlib2.R_2_jobs_id)
1307 self.assertItems(["3187"])
1309 self.assertEqual(self.rapi.CountPending(), 0)
1312 class RapiTestRunner(unittest.TextTestRunner):
1313 def run(self, *args):
1314 global _used_handlers
1315 assert _used_handlers is None
1317 _used_handlers = set()
1320 result = unittest.TextTestRunner.run(self, *args)
1322 diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1325 raise AssertionError("The following RAPI resources were not used by the"
1326 " RAPI client: %r" % utils.CommaJoin(diff))
1328 # Reset global variable
1329 _used_handlers = None
1334 if __name__ == '__main__':
1335 client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)