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_WAITING, constants.JOB_STATUS_WAITING)
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 self.assertEqual(client.NODE_EVAC_PRI, constants.IALLOCATOR_NEVAC_PRI)
170 self.assertEqual(client.NODE_EVAC_SEC, constants.IALLOCATOR_NEVAC_SEC)
171 self.assertEqual(client.NODE_EVAC_ALL, constants.IALLOCATOR_NEVAC_ALL)
174 self.assertEqual(client.JOB_STATUS_WAITLOCK, constants.JOB_STATUS_WAITING)
177 class RapiMockTest(unittest.TestCase):
181 self.assertEqual((404, None), rapi.FetchResponse("/foo", "GET", None))
182 self.assertEqual((501, "Method not implemented"),
183 rapi.FetchResponse("/version", "POST", None))
184 rapi.AddResponse("2")
185 code, response = rapi.FetchResponse("/version", "GET", None)
186 self.assertEqual(200, code)
187 self.assertEqual("2", response)
188 self.failUnless(isinstance(rapi.GetLastHandler(), rlib2.R_version))
191 def _FakeNoSslPycurlVersion():
192 # Note: incomplete version tuple
193 return (3, "7.16.0", 462848, "mysystem", 1581, None, 0)
196 def _FakeFancySslPycurlVersion():
197 # Note: incomplete version tuple
198 return (3, "7.16.0", 462848, "mysystem", 1581, "FancySSL/1.2.3", 0)
201 def _FakeOpenSslPycurlVersion():
202 # Note: incomplete version tuple
203 return (2, "7.15.5", 462597, "othersystem", 668, "OpenSSL/0.9.8c", 0)
206 def _FakeGnuTlsPycurlVersion():
207 # Note: incomplete version tuple
208 return (3, "7.18.0", 463360, "somesystem", 1581, "GnuTLS/2.0.4", 0)
211 class TestExtendedConfig(unittest.TestCase):
213 cl = client.GanetiRapiClient("master.example.com",
214 username="user", password="pw",
215 curl_factory=lambda: FakeCurl(RapiMock()))
217 curl = cl._CreateCurl()
218 self.assertEqual(curl.getopt(pycurl.HTTPAUTH), pycurl.HTTPAUTH_BASIC)
219 self.assertEqual(curl.getopt(pycurl.USERPWD), "user:pw")
221 def testInvalidAuth(self):
223 self.assertRaises(client.Error, client.GanetiRapiClient,
224 "master-a.example.com", password="pw")
226 self.assertRaises(client.Error, client.GanetiRapiClient,
227 "master-b.example.com", username="user")
229 def testCertVerifyInvalidCombinations(self):
230 self.assertRaises(client.Error, client.GenericCurlConfig,
231 use_curl_cabundle=True, cafile="cert1.pem")
232 self.assertRaises(client.Error, client.GenericCurlConfig,
233 use_curl_cabundle=True, capath="certs/")
234 self.assertRaises(client.Error, client.GenericCurlConfig,
235 use_curl_cabundle=True,
236 cafile="cert1.pem", capath="certs/")
238 def testProxySignalVerifyHostname(self):
239 for use_gnutls in [False, True]:
241 pcverfn = _FakeGnuTlsPycurlVersion
243 pcverfn = _FakeOpenSslPycurlVersion
245 for proxy in ["", "http://127.0.0.1:1234"]:
246 for use_signal in [False, True]:
247 for verify_hostname in [False, True]:
248 cfgfn = client.GenericCurlConfig(proxy=proxy, use_signal=use_signal,
249 verify_hostname=verify_hostname,
250 _pycurl_version_fn=pcverfn)
252 curl_factory = lambda: FakeCurl(RapiMock())
253 cl = client.GanetiRapiClient("master.example.com",
254 curl_config_fn=cfgfn,
255 curl_factory=curl_factory)
257 curl = cl._CreateCurl()
258 self.assertEqual(curl.getopt(pycurl.PROXY), proxy)
259 self.assertEqual(curl.getopt(pycurl.NOSIGNAL), not use_signal)
262 self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 2)
264 self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 0)
266 def testNoCertVerify(self):
267 cfgfn = client.GenericCurlConfig()
269 curl_factory = lambda: FakeCurl(RapiMock())
270 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
271 curl_factory=curl_factory)
273 curl = cl._CreateCurl()
274 self.assertFalse(curl.getopt(pycurl.SSL_VERIFYPEER))
275 self.assertFalse(curl.getopt(pycurl.CAINFO))
276 self.assertFalse(curl.getopt(pycurl.CAPATH))
278 def testCertVerifyCurlBundle(self):
279 cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
281 curl_factory = lambda: FakeCurl(RapiMock())
282 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
283 curl_factory=curl_factory)
285 curl = cl._CreateCurl()
286 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
287 self.assertFalse(curl.getopt(pycurl.CAINFO))
288 self.assertFalse(curl.getopt(pycurl.CAPATH))
290 def testCertVerifyCafile(self):
291 mycert = "/tmp/some/UNUSED/cert/file.pem"
292 cfgfn = client.GenericCurlConfig(cafile=mycert)
294 curl_factory = lambda: FakeCurl(RapiMock())
295 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
296 curl_factory=curl_factory)
298 curl = cl._CreateCurl()
299 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
300 self.assertEqual(curl.getopt(pycurl.CAINFO), mycert)
301 self.assertFalse(curl.getopt(pycurl.CAPATH))
303 def testCertVerifyCapath(self):
304 certdir = "/tmp/some/UNUSED/cert/directory"
305 pcverfn = _FakeOpenSslPycurlVersion
306 cfgfn = client.GenericCurlConfig(capath=certdir,
307 _pycurl_version_fn=pcverfn)
309 curl_factory = lambda: FakeCurl(RapiMock())
310 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
311 curl_factory=curl_factory)
313 curl = cl._CreateCurl()
314 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
315 self.assertEqual(curl.getopt(pycurl.CAPATH), certdir)
316 self.assertFalse(curl.getopt(pycurl.CAINFO))
318 def testCertVerifyCapathGnuTls(self):
319 certdir = "/tmp/some/UNUSED/cert/directory"
320 pcverfn = _FakeGnuTlsPycurlVersion
321 cfgfn = client.GenericCurlConfig(capath=certdir,
322 _pycurl_version_fn=pcverfn)
324 curl_factory = lambda: FakeCurl(RapiMock())
325 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
326 curl_factory=curl_factory)
328 self.assertRaises(client.Error, cl._CreateCurl)
330 def testCertVerifyNoSsl(self):
331 certdir = "/tmp/some/UNUSED/cert/directory"
332 pcverfn = _FakeNoSslPycurlVersion
333 cfgfn = client.GenericCurlConfig(capath=certdir,
334 _pycurl_version_fn=pcverfn)
336 curl_factory = lambda: FakeCurl(RapiMock())
337 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
338 curl_factory=curl_factory)
340 self.assertRaises(client.Error, cl._CreateCurl)
342 def testCertVerifyFancySsl(self):
343 certdir = "/tmp/some/UNUSED/cert/directory"
344 pcverfn = _FakeFancySslPycurlVersion
345 cfgfn = client.GenericCurlConfig(capath=certdir,
346 _pycurl_version_fn=pcverfn)
348 curl_factory = lambda: FakeCurl(RapiMock())
349 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
350 curl_factory=curl_factory)
352 self.assertRaises(NotImplementedError, cl._CreateCurl)
354 def testCertVerifyCapath(self):
355 for connect_timeout in [None, 1, 5, 10, 30, 60, 300]:
356 for timeout in [None, 1, 30, 60, 3600, 24 * 3600]:
357 cfgfn = client.GenericCurlConfig(connect_timeout=connect_timeout,
360 curl_factory = lambda: FakeCurl(RapiMock())
361 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
362 curl_factory=curl_factory)
364 curl = cl._CreateCurl()
365 self.assertEqual(curl.getopt(pycurl.CONNECTTIMEOUT), connect_timeout)
366 self.assertEqual(curl.getopt(pycurl.TIMEOUT), timeout)
369 class GanetiRapiClientTests(testutils.GanetiTestCase):
371 testutils.GanetiTestCase.setUp(self)
373 self.rapi = RapiMock()
374 self.curl = FakeCurl(self.rapi)
375 self.client = client.GanetiRapiClient("master.example.com",
376 curl_factory=lambda: self.curl)
378 def assertHandler(self, handler_cls):
379 self.failUnless(isinstance(self.rapi.GetLastHandler(), handler_cls))
381 def assertQuery(self, key, value):
382 self.assertEqual(value, self.rapi.GetLastHandler().queryargs.get(key, None))
384 def assertItems(self, items):
385 self.assertEqual(items, self.rapi.GetLastHandler().items)
387 def assertBulk(self):
388 self.assertTrue(self.rapi.GetLastHandler().useBulk())
390 def assertDryRun(self):
391 self.assertTrue(self.rapi.GetLastHandler().dryRun())
393 def assertUseForce(self):
394 self.assertTrue(self.rapi.GetLastHandler().useForce())
396 def testEncodeQuery(self):
413 self.assertEqualValues(self.client._EncodeQuery(query),
417 for i in [[1, 2, 3], {"moo": "boo"}, (1, 2, 3)]:
418 self.assertRaises(ValueError, self.client._EncodeQuery, [("x", i)])
420 def testCurlSettings(self):
421 self.rapi.AddResponse("2")
422 self.assertEqual(2, self.client.GetVersion())
423 self.assertHandler(rlib2.R_version)
425 # Signals should be disabled by default
426 self.assert_(self.curl.getopt(pycurl.NOSIGNAL))
428 # No auth and no proxy
429 self.assertFalse(self.curl.getopt(pycurl.USERPWD))
430 self.assert_(self.curl.getopt(pycurl.PROXY) is None)
432 # Content-type is required for requests
433 headers = self.curl.getopt(pycurl.HTTPHEADER)
434 self.assert_("Content-type: application/json" in headers)
436 def testHttpError(self):
437 self.rapi.AddResponse(None, code=404)
439 self.client.GetJobStatus(15140)
440 except client.GanetiApiError, err:
441 self.assertEqual(err.code, 404)
443 self.fail("Didn't raise exception")
445 def testGetVersion(self):
446 self.rapi.AddResponse("2")
447 self.assertEqual(2, self.client.GetVersion())
448 self.assertHandler(rlib2.R_version)
450 def testGetFeatures(self):
451 for features in [[], ["foo", "bar", "baz"]]:
452 self.rapi.AddResponse(serializer.DumpJson(features))
453 self.assertEqual(features, self.client.GetFeatures())
454 self.assertHandler(rlib2.R_2_features)
456 def testGetFeaturesNotFound(self):
457 self.rapi.AddResponse(None, code=404)
458 self.assertEqual([], self.client.GetFeatures())
460 def testGetOperatingSystems(self):
461 self.rapi.AddResponse("[\"beos\"]")
462 self.assertEqual(["beos"], self.client.GetOperatingSystems())
463 self.assertHandler(rlib2.R_2_os)
465 def testGetClusterTags(self):
466 self.rapi.AddResponse("[\"tag\"]")
467 self.assertEqual(["tag"], self.client.GetClusterTags())
468 self.assertHandler(rlib2.R_2_tags)
470 def testAddClusterTags(self):
471 self.rapi.AddResponse("1234")
472 self.assertEqual(1234,
473 self.client.AddClusterTags(["awesome"], dry_run=True))
474 self.assertHandler(rlib2.R_2_tags)
476 self.assertQuery("tag", ["awesome"])
478 def testDeleteClusterTags(self):
479 self.rapi.AddResponse("5107")
480 self.assertEqual(5107, self.client.DeleteClusterTags(["awesome"],
482 self.assertHandler(rlib2.R_2_tags)
484 self.assertQuery("tag", ["awesome"])
486 def testGetInfo(self):
487 self.rapi.AddResponse("{}")
488 self.assertEqual({}, self.client.GetInfo())
489 self.assertHandler(rlib2.R_2_info)
491 def testGetInstances(self):
492 self.rapi.AddResponse("[]")
493 self.assertEqual([], self.client.GetInstances(bulk=True))
494 self.assertHandler(rlib2.R_2_instances)
497 def testGetInstance(self):
498 self.rapi.AddResponse("[]")
499 self.assertEqual([], self.client.GetInstance("instance"))
500 self.assertHandler(rlib2.R_2_instances_name)
501 self.assertItems(["instance"])
503 def testGetInstanceInfo(self):
504 self.rapi.AddResponse("21291")
505 self.assertEqual(21291, self.client.GetInstanceInfo("inst3"))
506 self.assertHandler(rlib2.R_2_instances_name_info)
507 self.assertItems(["inst3"])
508 self.assertQuery("static", None)
510 self.rapi.AddResponse("3428")
511 self.assertEqual(3428, self.client.GetInstanceInfo("inst31", static=False))
512 self.assertHandler(rlib2.R_2_instances_name_info)
513 self.assertItems(["inst31"])
514 self.assertQuery("static", ["0"])
516 self.rapi.AddResponse("15665")
517 self.assertEqual(15665, self.client.GetInstanceInfo("inst32", static=True))
518 self.assertHandler(rlib2.R_2_instances_name_info)
519 self.assertItems(["inst32"])
520 self.assertQuery("static", ["1"])
522 def testCreateInstanceOldVersion(self):
523 # The old request format, version 0, is no longer supported
524 self.rapi.AddResponse(None, code=404)
525 self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
526 "create", "inst1.example.com", "plain", [], [])
527 self.assertEqual(self.rapi.CountPending(), 0)
529 def testCreateInstance(self):
530 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
531 self.rapi.AddResponse("23030")
532 job_id = self.client.CreateInstance("create", "inst1.example.com",
533 "plain", [], [], dry_run=True)
534 self.assertEqual(job_id, 23030)
535 self.assertHandler(rlib2.R_2_instances)
538 data = serializer.LoadJson(self.rapi.GetLastRequestData())
540 for field in ["dry_run", "beparams", "hvparams", "start"]:
541 self.assertFalse(field in data)
543 self.assertEqual(data["name"], "inst1.example.com")
544 self.assertEqual(data["disk_template"], "plain")
546 def testCreateInstance2(self):
547 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
548 self.rapi.AddResponse("24740")
549 job_id = self.client.CreateInstance("import", "inst2.example.com",
550 "drbd8", [{"size": 100,}],
551 [{}, {"bridge": "br1", }],
552 dry_run=False, start=True,
553 pnode="node1", snode="node9",
555 self.assertEqual(job_id, 24740)
556 self.assertHandler(rlib2.R_2_instances)
558 data = serializer.LoadJson(self.rapi.GetLastRequestData())
559 self.assertEqual(data[rlib2._REQ_DATA_VERSION], 1)
560 self.assertEqual(data["name"], "inst2.example.com")
561 self.assertEqual(data["disk_template"], "drbd8")
562 self.assertEqual(data["start"], True)
563 self.assertEqual(data["ip_check"], False)
564 self.assertEqualValues(data["disks"], [{"size": 100,}])
565 self.assertEqualValues(data["nics"], [{}, {"bridge": "br1", }])
567 def testDeleteInstance(self):
568 self.rapi.AddResponse("1234")
569 self.assertEqual(1234, self.client.DeleteInstance("instance", dry_run=True))
570 self.assertHandler(rlib2.R_2_instances_name)
571 self.assertItems(["instance"])
574 def testGetInstanceTags(self):
575 self.rapi.AddResponse("[]")
576 self.assertEqual([], self.client.GetInstanceTags("fooinstance"))
577 self.assertHandler(rlib2.R_2_instances_name_tags)
578 self.assertItems(["fooinstance"])
580 def testAddInstanceTags(self):
581 self.rapi.AddResponse("1234")
582 self.assertEqual(1234,
583 self.client.AddInstanceTags("fooinstance", ["awesome"], dry_run=True))
584 self.assertHandler(rlib2.R_2_instances_name_tags)
585 self.assertItems(["fooinstance"])
587 self.assertQuery("tag", ["awesome"])
589 def testDeleteInstanceTags(self):
590 self.rapi.AddResponse("25826")
591 self.assertEqual(25826, self.client.DeleteInstanceTags("foo", ["awesome"],
593 self.assertHandler(rlib2.R_2_instances_name_tags)
594 self.assertItems(["foo"])
596 self.assertQuery("tag", ["awesome"])
598 def testRebootInstance(self):
599 self.rapi.AddResponse("6146")
600 job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
601 ignore_secondaries=True, dry_run=True)
602 self.assertEqual(6146, job_id)
603 self.assertHandler(rlib2.R_2_instances_name_reboot)
604 self.assertItems(["i-bar"])
606 self.assertQuery("type", ["hard"])
607 self.assertQuery("ignore_secondaries", ["1"])
609 def testShutdownInstance(self):
610 self.rapi.AddResponse("1487")
611 self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
613 self.assertHandler(rlib2.R_2_instances_name_shutdown)
614 self.assertItems(["foo-instance"])
617 def testStartupInstance(self):
618 self.rapi.AddResponse("27149")
619 self.assertEqual(27149, self.client.StartupInstance("bar-instance",
621 self.assertHandler(rlib2.R_2_instances_name_startup)
622 self.assertItems(["bar-instance"])
625 def testReinstallInstance(self):
626 self.rapi.AddResponse(serializer.DumpJson([]))
627 self.rapi.AddResponse("19119")
628 self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
631 self.assertHandler(rlib2.R_2_instances_name_reinstall)
632 self.assertItems(["baz-instance"])
633 self.assertQuery("os", ["DOS"])
634 self.assertQuery("nostartup", ["1"])
635 self.assertEqual(self.rapi.CountPending(), 0)
637 def testReinstallInstanceNew(self):
638 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
639 self.rapi.AddResponse("25689")
640 self.assertEqual(25689, self.client.ReinstallInstance("moo-instance",
643 self.assertHandler(rlib2.R_2_instances_name_reinstall)
644 self.assertItems(["moo-instance"])
645 data = serializer.LoadJson(self.rapi.GetLastRequestData())
646 self.assertEqual(len(data), 2)
647 self.assertEqual(data["os"], "Debian")
648 self.assertEqual(data["start"], False)
649 self.assertEqual(self.rapi.CountPending(), 0)
651 def testReinstallInstanceWithOsparams1(self):
652 self.rapi.AddResponse(serializer.DumpJson([]))
653 self.assertRaises(client.GanetiApiError, self.client.ReinstallInstance,
654 "doo-instance", osparams={"x": "y"})
655 self.assertEqual(self.rapi.CountPending(), 0)
657 def testReinstallInstanceWithOsparams2(self):
662 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
663 self.rapi.AddResponse("1717")
664 self.assertEqual(1717, self.client.ReinstallInstance("zoo-instance",
666 self.assertHandler(rlib2.R_2_instances_name_reinstall)
667 self.assertItems(["zoo-instance"])
668 data = serializer.LoadJson(self.rapi.GetLastRequestData())
669 self.assertEqual(len(data), 2)
670 self.assertEqual(data["osparams"], osparams)
671 self.assertEqual(data["start"], True)
672 self.assertEqual(self.rapi.CountPending(), 0)
674 def testReplaceInstanceDisks(self):
675 self.rapi.AddResponse("999")
676 job_id = self.client.ReplaceInstanceDisks("instance-name",
677 disks=[0, 1], iallocator="hail")
678 self.assertEqual(999, job_id)
679 self.assertHandler(rlib2.R_2_instances_name_replace_disks)
680 self.assertItems(["instance-name"])
681 self.assertQuery("disks", ["0,1"])
682 self.assertQuery("mode", ["replace_auto"])
683 self.assertQuery("iallocator", ["hail"])
685 self.rapi.AddResponse("1000")
686 job_id = self.client.ReplaceInstanceDisks("instance-bar",
687 disks=[1], mode="replace_on_secondary", remote_node="foo-node")
688 self.assertEqual(1000, job_id)
689 self.assertItems(["instance-bar"])
690 self.assertQuery("disks", ["1"])
691 self.assertQuery("remote_node", ["foo-node"])
693 self.rapi.AddResponse("5175")
694 self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
695 self.assertItems(["instance-moo"])
696 self.assertQuery("disks", None)
698 def testPrepareExport(self):
699 self.rapi.AddResponse("8326")
700 self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
701 self.assertHandler(rlib2.R_2_instances_name_prepare_export)
702 self.assertItems(["inst1"])
703 self.assertQuery("mode", ["local"])
705 def testExportInstance(self):
706 self.rapi.AddResponse("19695")
707 job_id = self.client.ExportInstance("inst2", "local", "nodeX",
709 self.assertEqual(job_id, 19695)
710 self.assertHandler(rlib2.R_2_instances_name_export)
711 self.assertItems(["inst2"])
713 data = serializer.LoadJson(self.rapi.GetLastRequestData())
714 self.assertEqual(data["mode"], "local")
715 self.assertEqual(data["destination"], "nodeX")
716 self.assertEqual(data["shutdown"], True)
718 def testMigrateInstanceDefaults(self):
719 self.rapi.AddResponse("24873")
720 job_id = self.client.MigrateInstance("inst91")
721 self.assertEqual(job_id, 24873)
722 self.assertHandler(rlib2.R_2_instances_name_migrate)
723 self.assertItems(["inst91"])
725 data = serializer.LoadJson(self.rapi.GetLastRequestData())
726 self.assertFalse(data)
728 def testMigrateInstance(self):
729 for mode in constants.HT_MIGRATION_MODES:
730 for cleanup in [False, True]:
731 self.rapi.AddResponse("31910")
732 job_id = self.client.MigrateInstance("inst289", mode=mode,
734 self.assertEqual(job_id, 31910)
735 self.assertHandler(rlib2.R_2_instances_name_migrate)
736 self.assertItems(["inst289"])
738 data = serializer.LoadJson(self.rapi.GetLastRequestData())
739 self.assertEqual(len(data), 2)
740 self.assertEqual(data["mode"], mode)
741 self.assertEqual(data["cleanup"], cleanup)
743 def testFailoverInstanceDefaults(self):
744 self.rapi.AddResponse("7639")
745 job_id = self.client.FailoverInstance("inst13579")
746 self.assertEqual(job_id, 7639)
747 self.assertHandler(rlib2.R_2_instances_name_failover)
748 self.assertItems(["inst13579"])
750 data = serializer.LoadJson(self.rapi.GetLastRequestData())
751 self.assertFalse(data)
753 def testFailoverInstance(self):
754 for iallocator in ["dumb", "hail"]:
755 for ignore_consistency in [False, True]:
756 for target_node in ["node-a", "node2"]:
757 self.rapi.AddResponse("19161")
759 self.client.FailoverInstance("inst251", iallocator=iallocator,
760 ignore_consistency=ignore_consistency,
761 target_node=target_node)
762 self.assertEqual(job_id, 19161)
763 self.assertHandler(rlib2.R_2_instances_name_failover)
764 self.assertItems(["inst251"])
766 data = serializer.LoadJson(self.rapi.GetLastRequestData())
767 self.assertEqual(len(data), 3)
768 self.assertEqual(data["iallocator"], iallocator)
769 self.assertEqual(data["ignore_consistency"], ignore_consistency)
770 self.assertEqual(data["target_node"], target_node)
771 self.assertEqual(self.rapi.CountPending(), 0)
773 def testRenameInstanceDefaults(self):
774 new_name = "newnametha7euqu"
775 self.rapi.AddResponse("8791")
776 job_id = self.client.RenameInstance("inst18821", new_name)
777 self.assertEqual(job_id, 8791)
778 self.assertHandler(rlib2.R_2_instances_name_rename)
779 self.assertItems(["inst18821"])
781 data = serializer.LoadJson(self.rapi.GetLastRequestData())
782 self.assertEqualValues(data, {"new_name": new_name, })
784 def testRenameInstance(self):
785 new_name = "new-name-yiux1iin"
786 for ip_check in [False, True]:
787 for name_check in [False, True]:
788 self.rapi.AddResponse("24776")
789 job_id = self.client.RenameInstance("inst20967", new_name,
791 name_check=name_check)
792 self.assertEqual(job_id, 24776)
793 self.assertHandler(rlib2.R_2_instances_name_rename)
794 self.assertItems(["inst20967"])
796 data = serializer.LoadJson(self.rapi.GetLastRequestData())
797 self.assertEqual(len(data), 3)
798 self.assertEqual(data["new_name"], new_name)
799 self.assertEqual(data["ip_check"], ip_check)
800 self.assertEqual(data["name_check"], name_check)
802 def testGetJobs(self):
803 self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
804 ' { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
805 self.assertEqual([123, 124], self.client.GetJobs())
806 self.assertHandler(rlib2.R_2_jobs)
808 def testGetJobStatus(self):
809 self.rapi.AddResponse("{\"foo\": \"bar\"}")
810 self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
811 self.assertHandler(rlib2.R_2_jobs_id)
812 self.assertItems(["1234"])
814 def testWaitForJobChange(self):
815 fields = ["id", "summary"]
817 "job_info": [123, "something"],
821 self.rapi.AddResponse(serializer.DumpJson(expected))
822 result = self.client.WaitForJobChange(123, fields, [], -1)
823 self.assertEqualValues(expected, result)
824 self.assertHandler(rlib2.R_2_jobs_id_wait)
825 self.assertItems(["123"])
827 def testCancelJob(self):
828 self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
829 self.assertEqual([True, "Job 123 will be canceled"],
830 self.client.CancelJob(999, dry_run=True))
831 self.assertHandler(rlib2.R_2_jobs_id)
832 self.assertItems(["999"])
835 def testGetNodes(self):
836 self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
837 " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
838 self.assertEqual(["node1", "node2"], self.client.GetNodes())
839 self.assertHandler(rlib2.R_2_nodes)
841 self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
842 " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
843 self.assertEqual([{"id": "node1", "uri": "uri1"},
844 {"id": "node2", "uri": "uri2"}],
845 self.client.GetNodes(bulk=True))
846 self.assertHandler(rlib2.R_2_nodes)
849 def testGetNode(self):
850 self.rapi.AddResponse("{}")
851 self.assertEqual({}, self.client.GetNode("node-foo"))
852 self.assertHandler(rlib2.R_2_nodes_name)
853 self.assertItems(["node-foo"])
855 def testEvacuateNode(self):
856 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
857 self.rapi.AddResponse("9876")
858 job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
859 self.assertEqual(9876, job_id)
860 self.assertHandler(rlib2.R_2_nodes_name_evacuate)
861 self.assertItems(["node-1"])
862 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
863 { "remote_node": "node-2", })
864 self.assertEqual(self.rapi.CountPending(), 0)
866 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
867 self.rapi.AddResponse("8888")
868 job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True,
869 mode=constants.IALLOCATOR_NEVAC_ALL,
871 self.assertEqual(8888, job_id)
872 self.assertItems(["node-3"])
873 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()), {
874 "iallocator": "hail",
876 "early_release": True,
880 self.assertRaises(client.GanetiApiError,
881 self.client.EvacuateNode,
882 "node-4", iallocator="hail", remote_node="node-5")
883 self.assertEqual(self.rapi.CountPending(), 0)
885 def testEvacuateNodeOldResponse(self):
886 self.rapi.AddResponse(serializer.DumpJson([]))
887 self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
888 "node-4", accept_old=False)
889 self.assertEqual(self.rapi.CountPending(), 0)
891 for mode in [client.NODE_EVAC_PRI, client.NODE_EVAC_ALL]:
892 self.rapi.AddResponse(serializer.DumpJson([]))
893 self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
894 "node-4", accept_old=True, mode=mode)
895 self.assertEqual(self.rapi.CountPending(), 0)
897 self.rapi.AddResponse(serializer.DumpJson([]))
898 self.rapi.AddResponse(serializer.DumpJson("21533"))
899 result = self.client.EvacuateNode("node-3", iallocator="hail",
900 dry_run=True, accept_old=True,
901 mode=client.NODE_EVAC_SEC,
903 self.assertEqual(result, "21533")
904 self.assertItems(["node-3"])
905 self.assertQuery("iallocator", ["hail"])
906 self.assertQuery("early_release", ["1"])
907 self.assertFalse(self.rapi.GetLastRequestData())
909 self.assertEqual(self.rapi.CountPending(), 0)
911 def testMigrateNode(self):
912 self.rapi.AddResponse(serializer.DumpJson([]))
913 self.rapi.AddResponse("1111")
914 self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
915 self.assertHandler(rlib2.R_2_nodes_name_migrate)
916 self.assertItems(["node-a"])
917 self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
919 self.assertFalse(self.rapi.GetLastRequestData())
921 self.rapi.AddResponse(serializer.DumpJson([]))
922 self.rapi.AddResponse("1112")
923 self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
925 self.assertHandler(rlib2.R_2_nodes_name_migrate)
926 self.assertItems(["node-a"])
927 self.assertQuery("mode", ["live"])
929 self.assertFalse(self.rapi.GetLastRequestData())
931 self.rapi.AddResponse(serializer.DumpJson([]))
932 self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
933 "node-c", target_node="foonode")
934 self.assertEqual(self.rapi.CountPending(), 0)
936 def testMigrateNodeBodyData(self):
937 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
938 self.rapi.AddResponse("27539")
939 self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
941 self.assertHandler(rlib2.R_2_nodes_name_migrate)
942 self.assertItems(["node-a"])
943 self.assertFalse(self.rapi.GetLastHandler().queryargs)
944 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
947 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
948 self.rapi.AddResponse("14219")
949 self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
952 self.assertHandler(rlib2.R_2_nodes_name_migrate)
953 self.assertItems(["node-x"])
955 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
956 { "target_node": "node9", "iallocator": "ial", })
958 self.assertEqual(self.rapi.CountPending(), 0)
960 def testGetNodeRole(self):
961 self.rapi.AddResponse("\"master\"")
962 self.assertEqual("master", self.client.GetNodeRole("node-a"))
963 self.assertHandler(rlib2.R_2_nodes_name_role)
964 self.assertItems(["node-a"])
966 def testSetNodeRole(self):
967 self.rapi.AddResponse("789")
968 self.assertEqual(789,
969 self.client.SetNodeRole("node-foo", "master-candidate", force=True))
970 self.assertHandler(rlib2.R_2_nodes_name_role)
971 self.assertItems(["node-foo"])
972 self.assertQuery("force", ["1"])
973 self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
975 def testGetNodeStorageUnits(self):
976 self.rapi.AddResponse("42")
978 self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
979 self.assertHandler(rlib2.R_2_nodes_name_storage)
980 self.assertItems(["node-x"])
981 self.assertQuery("storage_type", ["lvm-pv"])
982 self.assertQuery("output_fields", ["fields"])
984 def testModifyNodeStorageUnits(self):
985 self.rapi.AddResponse("14")
987 self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
988 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
989 self.assertItems(["node-z"])
990 self.assertQuery("storage_type", ["lvm-pv"])
991 self.assertQuery("name", ["hda"])
992 self.assertQuery("allocatable", None)
994 for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
995 self.rapi.AddResponse("7205")
996 job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
997 allocatable=allocatable)
998 self.assertEqual(7205, job_id)
999 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1000 self.assertItems(["node-z"])
1001 self.assertQuery("storage_type", ["lvm-pv"])
1002 self.assertQuery("name", ["hda"])
1003 self.assertQuery("allocatable", [query_allocatable])
1005 def testRepairNodeStorageUnits(self):
1006 self.rapi.AddResponse("99")
1007 self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
1009 self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
1010 self.assertItems(["node-z"])
1011 self.assertQuery("storage_type", ["lvm-pv"])
1012 self.assertQuery("name", ["hda"])
1014 def testGetNodeTags(self):
1015 self.rapi.AddResponse("[\"fry\", \"bender\"]")
1016 self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
1017 self.assertHandler(rlib2.R_2_nodes_name_tags)
1018 self.assertItems(["node-k"])
1020 def testAddNodeTags(self):
1021 self.rapi.AddResponse("1234")
1022 self.assertEqual(1234,
1023 self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
1024 self.assertHandler(rlib2.R_2_nodes_name_tags)
1025 self.assertItems(["node-v"])
1027 self.assertQuery("tag", ["awesome"])
1029 def testDeleteNodeTags(self):
1030 self.rapi.AddResponse("16861")
1031 self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1033 self.assertHandler(rlib2.R_2_nodes_name_tags)
1034 self.assertItems(["node-w"])
1036 self.assertQuery("tag", ["awesome"])
1038 def testGetGroups(self):
1039 groups = [{"name": "group1",
1040 "uri": "/2/groups/group1",
1043 "uri": "/2/groups/group2",
1046 self.rapi.AddResponse(serializer.DumpJson(groups))
1047 self.assertEqual(["group1", "group2"], self.client.GetGroups())
1048 self.assertHandler(rlib2.R_2_groups)
1050 def testGetGroupsBulk(self):
1051 groups = [{"name": "group1",
1052 "uri": "/2/groups/group1",
1054 "node_list": ["gnt1.test",
1059 "uri": "/2/groups/group2",
1061 "node_list": ["gnt3.test",
1065 self.rapi.AddResponse(serializer.DumpJson(groups))
1067 self.assertEqual(groups, self.client.GetGroups(bulk=True))
1068 self.assertHandler(rlib2.R_2_groups)
1071 def testGetGroup(self):
1072 group = {"ctime": None,
1075 self.rapi.AddResponse(serializer.DumpJson(group))
1076 self.assertEqual({"ctime": None, "name": "default"},
1077 self.client.GetGroup("default"))
1078 self.assertHandler(rlib2.R_2_groups_name)
1079 self.assertItems(["default"])
1081 def testCreateGroup(self):
1082 self.rapi.AddResponse("12345")
1083 job_id = self.client.CreateGroup("newgroup", dry_run=True)
1084 self.assertEqual(job_id, 12345)
1085 self.assertHandler(rlib2.R_2_groups)
1088 def testDeleteGroup(self):
1089 self.rapi.AddResponse("12346")
1090 job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1091 self.assertEqual(job_id, 12346)
1092 self.assertHandler(rlib2.R_2_groups_name)
1095 def testRenameGroup(self):
1096 self.rapi.AddResponse("12347")
1097 job_id = self.client.RenameGroup("oldname", "newname")
1098 self.assertEqual(job_id, 12347)
1099 self.assertHandler(rlib2.R_2_groups_name_rename)
1101 def testModifyGroup(self):
1102 self.rapi.AddResponse("12348")
1103 job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1104 self.assertEqual(job_id, 12348)
1105 self.assertHandler(rlib2.R_2_groups_name_modify)
1107 def testAssignGroupNodes(self):
1108 self.rapi.AddResponse("12349")
1109 job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1110 force=True, dry_run=True)
1111 self.assertEqual(job_id, 12349)
1112 self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1114 self.assertUseForce()
1116 def testModifyInstance(self):
1117 self.rapi.AddResponse("23681")
1118 job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1119 self.assertEqual(job_id, 23681)
1120 self.assertItems(["inst7210"])
1121 self.assertHandler(rlib2.R_2_instances_name_modify)
1122 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1123 { "os_name": "linux", })
1125 def testModifyCluster(self):
1126 for mnh in [None, False, True]:
1127 self.rapi.AddResponse("14470")
1128 self.assertEqual(14470,
1129 self.client.ModifyCluster(maintain_node_health=mnh))
1130 self.assertHandler(rlib2.R_2_cluster_modify)
1131 self.assertItems([])
1132 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1133 self.assertEqual(len(data), 1)
1134 self.assertEqual(data["maintain_node_health"], mnh)
1135 self.assertEqual(self.rapi.CountPending(), 0)
1137 def testRedistributeConfig(self):
1138 self.rapi.AddResponse("3364")
1139 job_id = self.client.RedistributeConfig()
1140 self.assertEqual(job_id, 3364)
1141 self.assertItems([])
1142 self.assertHandler(rlib2.R_2_redist_config)
1144 def testActivateInstanceDisks(self):
1145 self.rapi.AddResponse("23547")
1146 job_id = self.client.ActivateInstanceDisks("inst28204")
1147 self.assertEqual(job_id, 23547)
1148 self.assertItems(["inst28204"])
1149 self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1150 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1152 def testActivateInstanceDisksIgnoreSize(self):
1153 self.rapi.AddResponse("11044")
1154 job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1155 self.assertEqual(job_id, 11044)
1156 self.assertItems(["inst28204"])
1157 self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1158 self.assertQuery("ignore_size", ["1"])
1160 def testDeactivateInstanceDisks(self):
1161 self.rapi.AddResponse("14591")
1162 job_id = self.client.DeactivateInstanceDisks("inst28234")
1163 self.assertEqual(job_id, 14591)
1164 self.assertItems(["inst28234"])
1165 self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1166 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1168 def testGetInstanceConsole(self):
1169 self.rapi.AddResponse("26876")
1170 job_id = self.client.GetInstanceConsole("inst21491")
1171 self.assertEqual(job_id, 26876)
1172 self.assertItems(["inst21491"])
1173 self.assertHandler(rlib2.R_2_instances_name_console)
1174 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1175 self.assertFalse(self.rapi.GetLastRequestData())
1177 def testGrowInstanceDisk(self):
1178 for idx, wait_for_sync in enumerate([None, False, True]):
1179 amount = 128 + (512 * idx)
1180 self.assertEqual(self.rapi.CountPending(), 0)
1181 self.rapi.AddResponse("30783")
1182 self.assertEqual(30783,
1183 self.client.GrowInstanceDisk("eze8ch", idx, amount,
1184 wait_for_sync=wait_for_sync))
1185 self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1186 self.assertItems(["eze8ch", str(idx)])
1187 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1188 if wait_for_sync is None:
1189 self.assertEqual(len(data), 1)
1190 self.assert_("wait_for_sync" not in data)
1192 self.assertEqual(len(data), 2)
1193 self.assertEqual(data["wait_for_sync"], wait_for_sync)
1194 self.assertEqual(data["amount"], amount)
1195 self.assertEqual(self.rapi.CountPending(), 0)
1197 def testGetGroupTags(self):
1198 self.rapi.AddResponse("[]")
1199 self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1200 self.assertHandler(rlib2.R_2_groups_name_tags)
1201 self.assertItems(["fooGroup"])
1203 def testAddGroupTags(self):
1204 self.rapi.AddResponse("1234")
1205 self.assertEqual(1234,
1206 self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1207 self.assertHandler(rlib2.R_2_groups_name_tags)
1208 self.assertItems(["fooGroup"])
1210 self.assertQuery("tag", ["awesome"])
1212 def testDeleteGroupTags(self):
1213 self.rapi.AddResponse("25826")
1214 self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1216 self.assertHandler(rlib2.R_2_groups_name_tags)
1217 self.assertItems(["foo"])
1219 self.assertQuery("tag", ["awesome"])
1221 def testQuery(self):
1222 for idx, what in enumerate(constants.QR_VIA_RAPI):
1223 for idx2, filter_ in enumerate([None, ["?", "name"]]):
1224 job_id = 11010 + (idx << 4) + (idx2 << 16)
1225 fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1227 self.rapi.AddResponse(str(job_id))
1228 self.assertEqual(self.client.Query(what, fields, filter_=filter_),
1230 self.assertItems([what])
1231 self.assertHandler(rlib2.R_2_query)
1232 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1233 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1234 self.assertEqual(data["fields"], fields)
1236 self.assertTrue("filter" not in data)
1238 self.assertEqual(data["filter"], filter_)
1239 self.assertEqual(self.rapi.CountPending(), 0)
1241 def testQueryFields(self):
1242 exp_result = objects.QueryFieldsResponse(fields=[
1243 objects.QueryFieldDefinition(name="pnode", title="PNode",
1244 kind=constants.QFT_NUMBER),
1245 objects.QueryFieldDefinition(name="other", title="Other",
1246 kind=constants.QFT_BOOL),
1249 for what in constants.QR_VIA_RAPI:
1250 for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1251 self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1252 result = self.client.QueryFields(what, fields=fields)
1253 self.assertItems([what])
1254 self.assertHandler(rlib2.R_2_query_fields)
1255 self.assertFalse(self.rapi.GetLastRequestData())
1257 queryargs = self.rapi.GetLastHandler().queryargs
1259 self.assertFalse(queryargs)
1261 self.assertEqual(queryargs, {
1262 "fields": [",".join(fields)],
1265 self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1266 exp_result.ToDict())
1268 self.assertEqual(self.rapi.CountPending(), 0)
1270 def testWaitForJobCompletionNoChange(self):
1271 resp = serializer.DumpJson({
1272 "status": constants.JOB_STATUS_WAITING,
1275 for retries in [1, 5, 25]:
1276 for _ in range(retries):
1277 self.rapi.AddResponse(resp)
1279 self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1281 self.assertHandler(rlib2.R_2_jobs_id)
1282 self.assertItems(["22789"])
1284 self.assertEqual(self.rapi.CountPending(), 0)
1286 def testWaitForJobCompletionAlreadyFinished(self):
1287 self.rapi.AddResponse(serializer.DumpJson({
1288 "status": constants.JOB_STATUS_SUCCESS,
1291 self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1293 self.assertHandler(rlib2.R_2_jobs_id)
1294 self.assertItems(["22793"])
1296 self.assertEqual(self.rapi.CountPending(), 0)
1298 def testWaitForJobCompletionEmptyResponse(self):
1299 self.rapi.AddResponse("{}")
1300 self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1302 self.assertHandler(rlib2.R_2_jobs_id)
1303 self.assertItems(["22793"])
1305 self.assertEqual(self.rapi.CountPending(), 0)
1307 def testWaitForJobCompletionOutOfRetries(self):
1308 for retries in [3, 10, 21]:
1309 for _ in range(retries):
1310 self.rapi.AddResponse(serializer.DumpJson({
1311 "status": constants.JOB_STATUS_RUNNING,
1314 self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1315 retries=retries - 1))
1316 self.assertHandler(rlib2.R_2_jobs_id)
1317 self.assertItems(["30948"])
1319 self.assertEqual(self.rapi.CountPending(), 1)
1320 self.rapi.ResetResponses()
1322 def testWaitForJobCompletionSuccessAndFailure(self):
1323 for retries in [1, 4, 13]:
1324 for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1325 (True, constants.JOB_STATUS_SUCCESS)]:
1326 for _ in range(retries):
1327 self.rapi.AddResponse(serializer.DumpJson({
1328 "status": constants.JOB_STATUS_RUNNING,
1331 self.rapi.AddResponse(serializer.DumpJson({
1332 "status": end_status,
1335 result = self.client.WaitForJobCompletion(3187, period=None,
1336 retries=retries + 1)
1337 self.assertEqual(result, success)
1338 self.assertHandler(rlib2.R_2_jobs_id)
1339 self.assertItems(["3187"])
1341 self.assertEqual(self.rapi.CountPending(), 0)
1344 class RapiTestRunner(unittest.TextTestRunner):
1345 def run(self, *args):
1346 global _used_handlers
1347 assert _used_handlers is None
1349 _used_handlers = set()
1352 result = unittest.TextTestRunner.run(self, *args)
1354 diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1357 raise AssertionError("The following RAPI resources were not used by the"
1358 " RAPI client: %r" % utils.CommaJoin(diff))
1360 # Reset global variable
1361 _used_handlers = None
1366 if __name__ == '__main__':
1367 client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)