4 # Copyright (C) 2010, 2011 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 """Script for unittesting the RAPI client module"""
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.NODE_EVAC_PRI)
170 self.assertEqual(client.NODE_EVAC_SEC, constants.NODE_EVAC_SEC)
171 self.assertEqual(client.NODE_EVAC_ALL, constants.NODE_EVAC_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.NODE_EVAC_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 testPowercycleNode(self):
976 self.rapi.AddResponse("23051")
977 self.assertEqual(23051,
978 self.client.PowercycleNode("node5468", force=True))
979 self.assertHandler(rlib2.R_2_nodes_name_powercycle)
980 self.assertItems(["node5468"])
981 self.assertQuery("force", ["1"])
982 self.assertFalse(self.rapi.GetLastRequestData())
983 self.assertEqual(self.rapi.CountPending(), 0)
985 def testModifyNode(self):
986 self.rapi.AddResponse("3783")
987 job_id = self.client.ModifyNode("node16979.example.com", drained=True)
988 self.assertEqual(job_id, 3783)
989 self.assertHandler(rlib2.R_2_nodes_name_modify)
990 self.assertItems(["node16979.example.com"])
991 self.assertEqual(self.rapi.CountPending(), 0)
993 def testGetNodeStorageUnits(self):
994 self.rapi.AddResponse("42")
996 self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
997 self.assertHandler(rlib2.R_2_nodes_name_storage)
998 self.assertItems(["node-x"])
999 self.assertQuery("storage_type", ["lvm-pv"])
1000 self.assertQuery("output_fields", ["fields"])
1002 def testModifyNodeStorageUnits(self):
1003 self.rapi.AddResponse("14")
1004 self.assertEqual(14,
1005 self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
1006 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1007 self.assertItems(["node-z"])
1008 self.assertQuery("storage_type", ["lvm-pv"])
1009 self.assertQuery("name", ["hda"])
1010 self.assertQuery("allocatable", None)
1012 for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
1013 self.rapi.AddResponse("7205")
1014 job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
1015 allocatable=allocatable)
1016 self.assertEqual(7205, job_id)
1017 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1018 self.assertItems(["node-z"])
1019 self.assertQuery("storage_type", ["lvm-pv"])
1020 self.assertQuery("name", ["hda"])
1021 self.assertQuery("allocatable", [query_allocatable])
1023 def testRepairNodeStorageUnits(self):
1024 self.rapi.AddResponse("99")
1025 self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
1027 self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
1028 self.assertItems(["node-z"])
1029 self.assertQuery("storage_type", ["lvm-pv"])
1030 self.assertQuery("name", ["hda"])
1032 def testGetNodeTags(self):
1033 self.rapi.AddResponse("[\"fry\", \"bender\"]")
1034 self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
1035 self.assertHandler(rlib2.R_2_nodes_name_tags)
1036 self.assertItems(["node-k"])
1038 def testAddNodeTags(self):
1039 self.rapi.AddResponse("1234")
1040 self.assertEqual(1234,
1041 self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
1042 self.assertHandler(rlib2.R_2_nodes_name_tags)
1043 self.assertItems(["node-v"])
1045 self.assertQuery("tag", ["awesome"])
1047 def testDeleteNodeTags(self):
1048 self.rapi.AddResponse("16861")
1049 self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1051 self.assertHandler(rlib2.R_2_nodes_name_tags)
1052 self.assertItems(["node-w"])
1054 self.assertQuery("tag", ["awesome"])
1056 def testGetGroups(self):
1057 groups = [{"name": "group1",
1058 "uri": "/2/groups/group1",
1061 "uri": "/2/groups/group2",
1064 self.rapi.AddResponse(serializer.DumpJson(groups))
1065 self.assertEqual(["group1", "group2"], self.client.GetGroups())
1066 self.assertHandler(rlib2.R_2_groups)
1068 def testGetGroupsBulk(self):
1069 groups = [{"name": "group1",
1070 "uri": "/2/groups/group1",
1072 "node_list": ["gnt1.test",
1077 "uri": "/2/groups/group2",
1079 "node_list": ["gnt3.test",
1083 self.rapi.AddResponse(serializer.DumpJson(groups))
1085 self.assertEqual(groups, self.client.GetGroups(bulk=True))
1086 self.assertHandler(rlib2.R_2_groups)
1089 def testGetGroup(self):
1090 group = {"ctime": None,
1093 self.rapi.AddResponse(serializer.DumpJson(group))
1094 self.assertEqual({"ctime": None, "name": "default"},
1095 self.client.GetGroup("default"))
1096 self.assertHandler(rlib2.R_2_groups_name)
1097 self.assertItems(["default"])
1099 def testCreateGroup(self):
1100 self.rapi.AddResponse("12345")
1101 job_id = self.client.CreateGroup("newgroup", dry_run=True)
1102 self.assertEqual(job_id, 12345)
1103 self.assertHandler(rlib2.R_2_groups)
1106 def testDeleteGroup(self):
1107 self.rapi.AddResponse("12346")
1108 job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1109 self.assertEqual(job_id, 12346)
1110 self.assertHandler(rlib2.R_2_groups_name)
1113 def testRenameGroup(self):
1114 self.rapi.AddResponse("12347")
1115 job_id = self.client.RenameGroup("oldname", "newname")
1116 self.assertEqual(job_id, 12347)
1117 self.assertHandler(rlib2.R_2_groups_name_rename)
1119 def testModifyGroup(self):
1120 self.rapi.AddResponse("12348")
1121 job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1122 self.assertEqual(job_id, 12348)
1123 self.assertHandler(rlib2.R_2_groups_name_modify)
1125 def testAssignGroupNodes(self):
1126 self.rapi.AddResponse("12349")
1127 job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1128 force=True, dry_run=True)
1129 self.assertEqual(job_id, 12349)
1130 self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1132 self.assertUseForce()
1134 def testModifyInstance(self):
1135 self.rapi.AddResponse("23681")
1136 job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1137 self.assertEqual(job_id, 23681)
1138 self.assertItems(["inst7210"])
1139 self.assertHandler(rlib2.R_2_instances_name_modify)
1140 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1141 { "os_name": "linux", })
1143 def testModifyCluster(self):
1144 for mnh in [None, False, True]:
1145 self.rapi.AddResponse("14470")
1146 self.assertEqual(14470,
1147 self.client.ModifyCluster(maintain_node_health=mnh))
1148 self.assertHandler(rlib2.R_2_cluster_modify)
1149 self.assertItems([])
1150 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1151 self.assertEqual(len(data), 1)
1152 self.assertEqual(data["maintain_node_health"], mnh)
1153 self.assertEqual(self.rapi.CountPending(), 0)
1155 def testRedistributeConfig(self):
1156 self.rapi.AddResponse("3364")
1157 job_id = self.client.RedistributeConfig()
1158 self.assertEqual(job_id, 3364)
1159 self.assertItems([])
1160 self.assertHandler(rlib2.R_2_redist_config)
1162 def testActivateInstanceDisks(self):
1163 self.rapi.AddResponse("23547")
1164 job_id = self.client.ActivateInstanceDisks("inst28204")
1165 self.assertEqual(job_id, 23547)
1166 self.assertItems(["inst28204"])
1167 self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1168 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1170 def testActivateInstanceDisksIgnoreSize(self):
1171 self.rapi.AddResponse("11044")
1172 job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1173 self.assertEqual(job_id, 11044)
1174 self.assertItems(["inst28204"])
1175 self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1176 self.assertQuery("ignore_size", ["1"])
1178 def testDeactivateInstanceDisks(self):
1179 self.rapi.AddResponse("14591")
1180 job_id = self.client.DeactivateInstanceDisks("inst28234")
1181 self.assertEqual(job_id, 14591)
1182 self.assertItems(["inst28234"])
1183 self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1184 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1186 def testRecreateInstanceDisks(self):
1187 self.rapi.AddResponse("13553")
1188 job_id = self.client.RecreateInstanceDisks("inst23153")
1189 self.assertEqual(job_id, 13553)
1190 self.assertItems(["inst23153"])
1191 self.assertHandler(rlib2.R_2_instances_name_recreate_disks)
1192 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1194 def testGetInstanceConsole(self):
1195 self.rapi.AddResponse("26876")
1196 job_id = self.client.GetInstanceConsole("inst21491")
1197 self.assertEqual(job_id, 26876)
1198 self.assertItems(["inst21491"])
1199 self.assertHandler(rlib2.R_2_instances_name_console)
1200 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1201 self.assertFalse(self.rapi.GetLastRequestData())
1203 def testGrowInstanceDisk(self):
1204 for idx, wait_for_sync in enumerate([None, False, True]):
1205 amount = 128 + (512 * idx)
1206 self.assertEqual(self.rapi.CountPending(), 0)
1207 self.rapi.AddResponse("30783")
1208 self.assertEqual(30783,
1209 self.client.GrowInstanceDisk("eze8ch", idx, amount,
1210 wait_for_sync=wait_for_sync))
1211 self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1212 self.assertItems(["eze8ch", str(idx)])
1213 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1214 if wait_for_sync is None:
1215 self.assertEqual(len(data), 1)
1216 self.assert_("wait_for_sync" not in data)
1218 self.assertEqual(len(data), 2)
1219 self.assertEqual(data["wait_for_sync"], wait_for_sync)
1220 self.assertEqual(data["amount"], amount)
1221 self.assertEqual(self.rapi.CountPending(), 0)
1223 def testGetGroupTags(self):
1224 self.rapi.AddResponse("[]")
1225 self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1226 self.assertHandler(rlib2.R_2_groups_name_tags)
1227 self.assertItems(["fooGroup"])
1229 def testAddGroupTags(self):
1230 self.rapi.AddResponse("1234")
1231 self.assertEqual(1234,
1232 self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1233 self.assertHandler(rlib2.R_2_groups_name_tags)
1234 self.assertItems(["fooGroup"])
1236 self.assertQuery("tag", ["awesome"])
1238 def testDeleteGroupTags(self):
1239 self.rapi.AddResponse("25826")
1240 self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1242 self.assertHandler(rlib2.R_2_groups_name_tags)
1243 self.assertItems(["foo"])
1245 self.assertQuery("tag", ["awesome"])
1247 def testQuery(self):
1248 for idx, what in enumerate(constants.QR_VIA_RAPI):
1249 for idx2, qfilter in enumerate([None, ["?", "name"]]):
1250 job_id = 11010 + (idx << 4) + (idx2 << 16)
1251 fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1253 self.rapi.AddResponse(str(job_id))
1254 self.assertEqual(self.client.Query(what, fields, qfilter=qfilter),
1256 self.assertItems([what])
1257 self.assertHandler(rlib2.R_2_query)
1258 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1259 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1260 self.assertEqual(data["fields"], fields)
1262 self.assertTrue("qfilter" not in data)
1264 self.assertEqual(data["qfilter"], qfilter)
1265 self.assertEqual(self.rapi.CountPending(), 0)
1267 def testQueryFields(self):
1268 exp_result = objects.QueryFieldsResponse(fields=[
1269 objects.QueryFieldDefinition(name="pnode", title="PNode",
1270 kind=constants.QFT_NUMBER),
1271 objects.QueryFieldDefinition(name="other", title="Other",
1272 kind=constants.QFT_BOOL),
1275 for what in constants.QR_VIA_RAPI:
1276 for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1277 self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1278 result = self.client.QueryFields(what, fields=fields)
1279 self.assertItems([what])
1280 self.assertHandler(rlib2.R_2_query_fields)
1281 self.assertFalse(self.rapi.GetLastRequestData())
1283 queryargs = self.rapi.GetLastHandler().queryargs
1285 self.assertFalse(queryargs)
1287 self.assertEqual(queryargs, {
1288 "fields": [",".join(fields)],
1291 self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1292 exp_result.ToDict())
1294 self.assertEqual(self.rapi.CountPending(), 0)
1296 def testWaitForJobCompletionNoChange(self):
1297 resp = serializer.DumpJson({
1298 "status": constants.JOB_STATUS_WAITING,
1301 for retries in [1, 5, 25]:
1302 for _ in range(retries):
1303 self.rapi.AddResponse(resp)
1305 self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1307 self.assertHandler(rlib2.R_2_jobs_id)
1308 self.assertItems(["22789"])
1310 self.assertEqual(self.rapi.CountPending(), 0)
1312 def testWaitForJobCompletionAlreadyFinished(self):
1313 self.rapi.AddResponse(serializer.DumpJson({
1314 "status": constants.JOB_STATUS_SUCCESS,
1317 self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1319 self.assertHandler(rlib2.R_2_jobs_id)
1320 self.assertItems(["22793"])
1322 self.assertEqual(self.rapi.CountPending(), 0)
1324 def testWaitForJobCompletionEmptyResponse(self):
1325 self.rapi.AddResponse("{}")
1326 self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1328 self.assertHandler(rlib2.R_2_jobs_id)
1329 self.assertItems(["22793"])
1331 self.assertEqual(self.rapi.CountPending(), 0)
1333 def testWaitForJobCompletionOutOfRetries(self):
1334 for retries in [3, 10, 21]:
1335 for _ in range(retries):
1336 self.rapi.AddResponse(serializer.DumpJson({
1337 "status": constants.JOB_STATUS_RUNNING,
1340 self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1341 retries=retries - 1))
1342 self.assertHandler(rlib2.R_2_jobs_id)
1343 self.assertItems(["30948"])
1345 self.assertEqual(self.rapi.CountPending(), 1)
1346 self.rapi.ResetResponses()
1348 def testWaitForJobCompletionSuccessAndFailure(self):
1349 for retries in [1, 4, 13]:
1350 for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1351 (True, constants.JOB_STATUS_SUCCESS)]:
1352 for _ in range(retries):
1353 self.rapi.AddResponse(serializer.DumpJson({
1354 "status": constants.JOB_STATUS_RUNNING,
1357 self.rapi.AddResponse(serializer.DumpJson({
1358 "status": end_status,
1361 result = self.client.WaitForJobCompletion(3187, period=None,
1362 retries=retries + 1)
1363 self.assertEqual(result, success)
1364 self.assertHandler(rlib2.R_2_jobs_id)
1365 self.assertItems(["3187"])
1367 self.assertEqual(self.rapi.CountPending(), 0)
1370 class RapiTestRunner(unittest.TextTestRunner):
1371 def run(self, *args):
1372 global _used_handlers
1373 assert _used_handlers is None
1375 _used_handlers = set()
1378 result = unittest.TextTestRunner.run(self, *args)
1380 diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1383 raise AssertionError("The following RAPI resources were not used by the"
1384 " RAPI client: %r" % utils.CommaJoin(diff))
1386 # Reset global variable
1387 _used_handlers = None
1392 if __name__ == '__main__':
1393 client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)