4 # Copyright (C) 2010, 2011 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 """Script for unittesting the RAPI client module"""
29 from ganeti import constants
30 from ganeti import http
31 from ganeti import serializer
32 from ganeti import utils
33 from ganeti import query
34 from ganeti import objects
35 from ganeti import rapi
37 import ganeti.rapi.testutils
38 from ganeti.rapi import connector
39 from ganeti.rapi import rlib2
40 from ganeti.rapi import client
45 # List of resource handlers which aren't used by the RAPI client
51 # Global variable for collecting used handlers
55 class RapiMock(object):
57 self._mapper = connector.Mapper()
59 self._last_handler = None
60 self._last_req_data = None
62 def ResetResponses(self):
63 del self._responses[:]
65 def AddResponse(self, response, code=200):
66 self._responses.insert(0, (code, response))
68 def CountPending(self):
69 return len(self._responses)
71 def GetLastHandler(self):
72 return self._last_handler
74 def GetLastRequestData(self):
75 return self._last_req_data
77 def FetchResponse(self, path, method, headers, request_body):
78 self._last_req_data = request_body
81 (handler_cls, items, args) = self._mapper.getController(path)
83 # Record handler as used
84 _used_handlers.add(handler_cls)
86 self._last_handler = handler_cls(items, args, None)
87 if not hasattr(self._last_handler, method.upper()):
88 raise http.HttpNotImplemented(message="Method not implemented")
90 except http.HttpException, ex:
94 if not self._responses:
95 raise Exception("No responses")
97 (code, response) = self._responses.pop()
102 class TestConstants(unittest.TestCase):
104 self.assertEqual(client.GANETI_RAPI_PORT, constants.DEFAULT_RAPI_PORT)
105 self.assertEqual(client.GANETI_RAPI_VERSION, constants.RAPI_VERSION)
106 self.assertEqual(client.HTTP_APP_JSON, http.HTTP_APP_JSON)
107 self.assertEqual(client._REQ_DATA_VERSION_FIELD, rlib2._REQ_DATA_VERSION)
108 self.assertEqual(client.JOB_STATUS_QUEUED, constants.JOB_STATUS_QUEUED)
109 self.assertEqual(client.JOB_STATUS_WAITING, constants.JOB_STATUS_WAITING)
110 self.assertEqual(client.JOB_STATUS_CANCELING,
111 constants.JOB_STATUS_CANCELING)
112 self.assertEqual(client.JOB_STATUS_RUNNING, constants.JOB_STATUS_RUNNING)
113 self.assertEqual(client.JOB_STATUS_CANCELED, constants.JOB_STATUS_CANCELED)
114 self.assertEqual(client.JOB_STATUS_SUCCESS, constants.JOB_STATUS_SUCCESS)
115 self.assertEqual(client.JOB_STATUS_ERROR, constants.JOB_STATUS_ERROR)
116 self.assertEqual(client.JOB_STATUS_FINALIZED, constants.JOBS_FINALIZED)
117 self.assertEqual(client.JOB_STATUS_ALL, constants.JOB_STATUS_ALL)
120 self.assertEqual(client.NODE_EVAC_PRI, constants.NODE_EVAC_PRI)
121 self.assertEqual(client.NODE_EVAC_SEC, constants.NODE_EVAC_SEC)
122 self.assertEqual(client.NODE_EVAC_ALL, constants.NODE_EVAC_ALL)
125 self.assertEqual(client.JOB_STATUS_WAITLOCK, constants.JOB_STATUS_WAITING)
127 # RAPI feature strings
128 self.assertEqual(client._INST_CREATE_REQV1, rlib2._INST_CREATE_REQV1)
129 self.assertEqual(client.INST_CREATE_REQV1, rlib2._INST_CREATE_REQV1)
130 self.assertEqual(client._INST_REINSTALL_REQV1, rlib2._INST_REINSTALL_REQV1)
131 self.assertEqual(client.INST_REINSTALL_REQV1, rlib2._INST_REINSTALL_REQV1)
132 self.assertEqual(client._NODE_MIGRATE_REQV1, rlib2._NODE_MIGRATE_REQV1)
133 self.assertEqual(client.NODE_MIGRATE_REQV1, rlib2._NODE_MIGRATE_REQV1)
134 self.assertEqual(client._NODE_EVAC_RES1, rlib2._NODE_EVAC_RES1)
135 self.assertEqual(client.NODE_EVAC_RES1, rlib2._NODE_EVAC_RES1)
138 class RapiMockTest(unittest.TestCase):
142 self.assertEqual((404, None), rapi.FetchResponse("/foo", "GET", None, None))
143 self.assertEqual((501, "Method not implemented"),
144 rapi.FetchResponse("/version", "POST", None, None))
145 rapi.AddResponse("2")
146 code, response = rapi.FetchResponse("/version", "GET", None, None)
147 self.assertEqual(200, code)
148 self.assertEqual("2", response)
149 self.failUnless(isinstance(rapi.GetLastHandler(), rlib2.R_version))
152 def _FakeNoSslPycurlVersion():
153 # Note: incomplete version tuple
154 return (3, "7.16.0", 462848, "mysystem", 1581, None, 0)
157 def _FakeFancySslPycurlVersion():
158 # Note: incomplete version tuple
159 return (3, "7.16.0", 462848, "mysystem", 1581, "FancySSL/1.2.3", 0)
162 def _FakeOpenSslPycurlVersion():
163 # Note: incomplete version tuple
164 return (2, "7.15.5", 462597, "othersystem", 668, "OpenSSL/0.9.8c", 0)
167 def _FakeGnuTlsPycurlVersion():
168 # Note: incomplete version tuple
169 return (3, "7.18.0", 463360, "somesystem", 1581, "GnuTLS/2.0.4", 0)
172 class TestExtendedConfig(unittest.TestCase):
174 cl = client.GanetiRapiClient("master.example.com",
175 username="user", password="pw",
176 curl_factory=lambda: rapi.testutils.FakeCurl(RapiMock()))
178 curl = cl._CreateCurl()
179 self.assertEqual(curl.getopt(pycurl.HTTPAUTH), pycurl.HTTPAUTH_BASIC)
180 self.assertEqual(curl.getopt(pycurl.USERPWD), "user:pw")
182 def testInvalidAuth(self):
184 self.assertRaises(client.Error, client.GanetiRapiClient,
185 "master-a.example.com", password="pw")
187 self.assertRaises(client.Error, client.GanetiRapiClient,
188 "master-b.example.com", username="user")
190 def testCertVerifyInvalidCombinations(self):
191 self.assertRaises(client.Error, client.GenericCurlConfig,
192 use_curl_cabundle=True, cafile="cert1.pem")
193 self.assertRaises(client.Error, client.GenericCurlConfig,
194 use_curl_cabundle=True, capath="certs/")
195 self.assertRaises(client.Error, client.GenericCurlConfig,
196 use_curl_cabundle=True,
197 cafile="cert1.pem", capath="certs/")
199 def testProxySignalVerifyHostname(self):
200 for use_gnutls in [False, True]:
202 pcverfn = _FakeGnuTlsPycurlVersion
204 pcverfn = _FakeOpenSslPycurlVersion
206 for proxy in ["", "http://127.0.0.1:1234"]:
207 for use_signal in [False, True]:
208 for verify_hostname in [False, True]:
209 cfgfn = client.GenericCurlConfig(proxy=proxy, use_signal=use_signal,
210 verify_hostname=verify_hostname,
211 _pycurl_version_fn=pcverfn)
213 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
214 cl = client.GanetiRapiClient("master.example.com",
215 curl_config_fn=cfgfn,
216 curl_factory=curl_factory)
218 curl = cl._CreateCurl()
219 self.assertEqual(curl.getopt(pycurl.PROXY), proxy)
220 self.assertEqual(curl.getopt(pycurl.NOSIGNAL), not use_signal)
223 self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 2)
225 self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 0)
227 def testNoCertVerify(self):
228 cfgfn = client.GenericCurlConfig()
230 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
231 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
232 curl_factory=curl_factory)
234 curl = cl._CreateCurl()
235 self.assertFalse(curl.getopt(pycurl.SSL_VERIFYPEER))
236 self.assertFalse(curl.getopt(pycurl.CAINFO))
237 self.assertFalse(curl.getopt(pycurl.CAPATH))
239 def testCertVerifyCurlBundle(self):
240 cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
242 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
243 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
244 curl_factory=curl_factory)
246 curl = cl._CreateCurl()
247 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
248 self.assertFalse(curl.getopt(pycurl.CAINFO))
249 self.assertFalse(curl.getopt(pycurl.CAPATH))
251 def testCertVerifyCafile(self):
252 mycert = "/tmp/some/UNUSED/cert/file.pem"
253 cfgfn = client.GenericCurlConfig(cafile=mycert)
255 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
256 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
257 curl_factory=curl_factory)
259 curl = cl._CreateCurl()
260 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
261 self.assertEqual(curl.getopt(pycurl.CAINFO), mycert)
262 self.assertFalse(curl.getopt(pycurl.CAPATH))
264 def testCertVerifyCapath(self):
265 certdir = "/tmp/some/UNUSED/cert/directory"
266 pcverfn = _FakeOpenSslPycurlVersion
267 cfgfn = client.GenericCurlConfig(capath=certdir,
268 _pycurl_version_fn=pcverfn)
270 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
271 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
272 curl_factory=curl_factory)
274 curl = cl._CreateCurl()
275 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
276 self.assertEqual(curl.getopt(pycurl.CAPATH), certdir)
277 self.assertFalse(curl.getopt(pycurl.CAINFO))
279 def testCertVerifyCapathGnuTls(self):
280 certdir = "/tmp/some/UNUSED/cert/directory"
281 pcverfn = _FakeGnuTlsPycurlVersion
282 cfgfn = client.GenericCurlConfig(capath=certdir,
283 _pycurl_version_fn=pcverfn)
285 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
286 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
287 curl_factory=curl_factory)
289 self.assertRaises(client.Error, cl._CreateCurl)
291 def testCertVerifyNoSsl(self):
292 certdir = "/tmp/some/UNUSED/cert/directory"
293 pcverfn = _FakeNoSslPycurlVersion
294 cfgfn = client.GenericCurlConfig(capath=certdir,
295 _pycurl_version_fn=pcverfn)
297 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
298 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
299 curl_factory=curl_factory)
301 self.assertRaises(client.Error, cl._CreateCurl)
303 def testCertVerifyFancySsl(self):
304 certdir = "/tmp/some/UNUSED/cert/directory"
305 pcverfn = _FakeFancySslPycurlVersion
306 cfgfn = client.GenericCurlConfig(capath=certdir,
307 _pycurl_version_fn=pcverfn)
309 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
310 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
311 curl_factory=curl_factory)
313 self.assertRaises(NotImplementedError, cl._CreateCurl)
315 def testCertVerifyCapath(self):
316 for connect_timeout in [None, 1, 5, 10, 30, 60, 300]:
317 for timeout in [None, 1, 30, 60, 3600, 24 * 3600]:
318 cfgfn = client.GenericCurlConfig(connect_timeout=connect_timeout,
321 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
322 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
323 curl_factory=curl_factory)
325 curl = cl._CreateCurl()
326 self.assertEqual(curl.getopt(pycurl.CONNECTTIMEOUT), connect_timeout)
327 self.assertEqual(curl.getopt(pycurl.TIMEOUT), timeout)
330 class GanetiRapiClientTests(testutils.GanetiTestCase):
332 testutils.GanetiTestCase.setUp(self)
334 self.rapi = RapiMock()
335 self.curl = rapi.testutils.FakeCurl(self.rapi)
336 self.client = client.GanetiRapiClient("master.example.com",
337 curl_factory=lambda: self.curl)
339 def assertHandler(self, handler_cls):
340 self.failUnless(isinstance(self.rapi.GetLastHandler(), handler_cls))
342 def assertQuery(self, key, value):
343 self.assertEqual(value, self.rapi.GetLastHandler().queryargs.get(key, None))
345 def assertItems(self, items):
346 self.assertEqual(items, self.rapi.GetLastHandler().items)
348 def assertBulk(self):
349 self.assertTrue(self.rapi.GetLastHandler().useBulk())
351 def assertDryRun(self):
352 self.assertTrue(self.rapi.GetLastHandler().dryRun())
354 def assertUseForce(self):
355 self.assertTrue(self.rapi.GetLastHandler().useForce())
357 def testEncodeQuery(self):
374 self.assertEqualValues(self.client._EncodeQuery(query),
378 for i in [[1, 2, 3], {"moo": "boo"}, (1, 2, 3)]:
379 self.assertRaises(ValueError, self.client._EncodeQuery, [("x", i)])
381 def testCurlSettings(self):
382 self.rapi.AddResponse("2")
383 self.assertEqual(2, self.client.GetVersion())
384 self.assertHandler(rlib2.R_version)
386 # Signals should be disabled by default
387 self.assert_(self.curl.getopt(pycurl.NOSIGNAL))
389 # No auth and no proxy
390 self.assertFalse(self.curl.getopt(pycurl.USERPWD))
391 self.assert_(self.curl.getopt(pycurl.PROXY) is None)
393 # Content-type is required for requests
394 headers = self.curl.getopt(pycurl.HTTPHEADER)
395 self.assert_("Content-type: application/json" in headers)
397 def testHttpError(self):
398 self.rapi.AddResponse(None, code=404)
400 self.client.GetJobStatus(15140)
401 except client.GanetiApiError, err:
402 self.assertEqual(err.code, 404)
404 self.fail("Didn't raise exception")
406 def testGetVersion(self):
407 self.rapi.AddResponse("2")
408 self.assertEqual(2, self.client.GetVersion())
409 self.assertHandler(rlib2.R_version)
411 def testGetFeatures(self):
412 for features in [[], ["foo", "bar", "baz"]]:
413 self.rapi.AddResponse(serializer.DumpJson(features))
414 self.assertEqual(features, self.client.GetFeatures())
415 self.assertHandler(rlib2.R_2_features)
417 def testGetFeaturesNotFound(self):
418 self.rapi.AddResponse(None, code=404)
419 self.assertEqual([], self.client.GetFeatures())
421 def testGetOperatingSystems(self):
422 self.rapi.AddResponse("[\"beos\"]")
423 self.assertEqual(["beos"], self.client.GetOperatingSystems())
424 self.assertHandler(rlib2.R_2_os)
426 def testGetClusterTags(self):
427 self.rapi.AddResponse("[\"tag\"]")
428 self.assertEqual(["tag"], self.client.GetClusterTags())
429 self.assertHandler(rlib2.R_2_tags)
431 def testAddClusterTags(self):
432 self.rapi.AddResponse("1234")
433 self.assertEqual(1234,
434 self.client.AddClusterTags(["awesome"], dry_run=True))
435 self.assertHandler(rlib2.R_2_tags)
437 self.assertQuery("tag", ["awesome"])
439 def testDeleteClusterTags(self):
440 self.rapi.AddResponse("5107")
441 self.assertEqual(5107, self.client.DeleteClusterTags(["awesome"],
443 self.assertHandler(rlib2.R_2_tags)
445 self.assertQuery("tag", ["awesome"])
447 def testGetInfo(self):
448 self.rapi.AddResponse("{}")
449 self.assertEqual({}, self.client.GetInfo())
450 self.assertHandler(rlib2.R_2_info)
452 def testGetInstances(self):
453 self.rapi.AddResponse("[]")
454 self.assertEqual([], self.client.GetInstances(bulk=True))
455 self.assertHandler(rlib2.R_2_instances)
458 def testGetInstance(self):
459 self.rapi.AddResponse("[]")
460 self.assertEqual([], self.client.GetInstance("instance"))
461 self.assertHandler(rlib2.R_2_instances_name)
462 self.assertItems(["instance"])
464 def testGetInstanceInfo(self):
465 self.rapi.AddResponse("21291")
466 self.assertEqual(21291, self.client.GetInstanceInfo("inst3"))
467 self.assertHandler(rlib2.R_2_instances_name_info)
468 self.assertItems(["inst3"])
469 self.assertQuery("static", None)
471 self.rapi.AddResponse("3428")
472 self.assertEqual(3428, self.client.GetInstanceInfo("inst31", static=False))
473 self.assertHandler(rlib2.R_2_instances_name_info)
474 self.assertItems(["inst31"])
475 self.assertQuery("static", ["0"])
477 self.rapi.AddResponse("15665")
478 self.assertEqual(15665, self.client.GetInstanceInfo("inst32", static=True))
479 self.assertHandler(rlib2.R_2_instances_name_info)
480 self.assertItems(["inst32"])
481 self.assertQuery("static", ["1"])
483 def testCreateInstanceOldVersion(self):
484 # The old request format, version 0, is no longer supported
485 self.rapi.AddResponse(None, code=404)
486 self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
487 "create", "inst1.example.com", "plain", [], [])
488 self.assertEqual(self.rapi.CountPending(), 0)
490 def testCreateInstance(self):
491 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
492 self.rapi.AddResponse("23030")
493 job_id = self.client.CreateInstance("create", "inst1.example.com",
494 "plain", [], [], dry_run=True)
495 self.assertEqual(job_id, 23030)
496 self.assertHandler(rlib2.R_2_instances)
499 data = serializer.LoadJson(self.rapi.GetLastRequestData())
501 for field in ["dry_run", "beparams", "hvparams", "start"]:
502 self.assertFalse(field in data)
504 self.assertEqual(data["name"], "inst1.example.com")
505 self.assertEqual(data["disk_template"], "plain")
507 def testCreateInstance2(self):
508 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
509 self.rapi.AddResponse("24740")
510 job_id = self.client.CreateInstance("import", "inst2.example.com",
511 "drbd8", [{"size": 100,}],
512 [{}, {"bridge": "br1", }],
513 dry_run=False, start=True,
514 pnode="node1", snode="node9",
516 self.assertEqual(job_id, 24740)
517 self.assertHandler(rlib2.R_2_instances)
519 data = serializer.LoadJson(self.rapi.GetLastRequestData())
520 self.assertEqual(data[rlib2._REQ_DATA_VERSION], 1)
521 self.assertEqual(data["name"], "inst2.example.com")
522 self.assertEqual(data["disk_template"], "drbd8")
523 self.assertEqual(data["start"], True)
524 self.assertEqual(data["ip_check"], False)
525 self.assertEqualValues(data["disks"], [{"size": 100,}])
526 self.assertEqualValues(data["nics"], [{}, {"bridge": "br1", }])
528 def testDeleteInstance(self):
529 self.rapi.AddResponse("1234")
530 self.assertEqual(1234, self.client.DeleteInstance("instance", dry_run=True))
531 self.assertHandler(rlib2.R_2_instances_name)
532 self.assertItems(["instance"])
535 def testGetInstanceTags(self):
536 self.rapi.AddResponse("[]")
537 self.assertEqual([], self.client.GetInstanceTags("fooinstance"))
538 self.assertHandler(rlib2.R_2_instances_name_tags)
539 self.assertItems(["fooinstance"])
541 def testAddInstanceTags(self):
542 self.rapi.AddResponse("1234")
543 self.assertEqual(1234,
544 self.client.AddInstanceTags("fooinstance", ["awesome"], dry_run=True))
545 self.assertHandler(rlib2.R_2_instances_name_tags)
546 self.assertItems(["fooinstance"])
548 self.assertQuery("tag", ["awesome"])
550 def testDeleteInstanceTags(self):
551 self.rapi.AddResponse("25826")
552 self.assertEqual(25826, self.client.DeleteInstanceTags("foo", ["awesome"],
554 self.assertHandler(rlib2.R_2_instances_name_tags)
555 self.assertItems(["foo"])
557 self.assertQuery("tag", ["awesome"])
559 def testRebootInstance(self):
560 self.rapi.AddResponse("6146")
561 job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
562 ignore_secondaries=True, dry_run=True)
563 self.assertEqual(6146, job_id)
564 self.assertHandler(rlib2.R_2_instances_name_reboot)
565 self.assertItems(["i-bar"])
567 self.assertQuery("type", ["hard"])
568 self.assertQuery("ignore_secondaries", ["1"])
570 def testShutdownInstance(self):
571 self.rapi.AddResponse("1487")
572 self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
574 self.assertHandler(rlib2.R_2_instances_name_shutdown)
575 self.assertItems(["foo-instance"])
578 def testStartupInstance(self):
579 self.rapi.AddResponse("27149")
580 self.assertEqual(27149, self.client.StartupInstance("bar-instance",
582 self.assertHandler(rlib2.R_2_instances_name_startup)
583 self.assertItems(["bar-instance"])
586 def testReinstallInstance(self):
587 self.rapi.AddResponse(serializer.DumpJson([]))
588 self.rapi.AddResponse("19119")
589 self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
592 self.assertHandler(rlib2.R_2_instances_name_reinstall)
593 self.assertItems(["baz-instance"])
594 self.assertQuery("os", ["DOS"])
595 self.assertQuery("nostartup", ["1"])
596 self.assertEqual(self.rapi.CountPending(), 0)
598 def testReinstallInstanceNew(self):
599 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
600 self.rapi.AddResponse("25689")
601 self.assertEqual(25689, self.client.ReinstallInstance("moo-instance",
604 self.assertHandler(rlib2.R_2_instances_name_reinstall)
605 self.assertItems(["moo-instance"])
606 data = serializer.LoadJson(self.rapi.GetLastRequestData())
607 self.assertEqual(len(data), 2)
608 self.assertEqual(data["os"], "Debian")
609 self.assertEqual(data["start"], False)
610 self.assertEqual(self.rapi.CountPending(), 0)
612 def testReinstallInstanceWithOsparams1(self):
613 self.rapi.AddResponse(serializer.DumpJson([]))
614 self.assertRaises(client.GanetiApiError, self.client.ReinstallInstance,
615 "doo-instance", osparams={"x": "y"})
616 self.assertEqual(self.rapi.CountPending(), 0)
618 def testReinstallInstanceWithOsparams2(self):
623 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
624 self.rapi.AddResponse("1717")
625 self.assertEqual(1717, self.client.ReinstallInstance("zoo-instance",
627 self.assertHandler(rlib2.R_2_instances_name_reinstall)
628 self.assertItems(["zoo-instance"])
629 data = serializer.LoadJson(self.rapi.GetLastRequestData())
630 self.assertEqual(len(data), 2)
631 self.assertEqual(data["osparams"], osparams)
632 self.assertEqual(data["start"], True)
633 self.assertEqual(self.rapi.CountPending(), 0)
635 def testReplaceInstanceDisks(self):
636 self.rapi.AddResponse("999")
637 job_id = self.client.ReplaceInstanceDisks("instance-name",
638 disks=[0, 1], iallocator="hail")
639 self.assertEqual(999, job_id)
640 self.assertHandler(rlib2.R_2_instances_name_replace_disks)
641 self.assertItems(["instance-name"])
642 self.assertQuery("disks", ["0,1"])
643 self.assertQuery("mode", ["replace_auto"])
644 self.assertQuery("iallocator", ["hail"])
646 self.rapi.AddResponse("1000")
647 job_id = self.client.ReplaceInstanceDisks("instance-bar",
648 disks=[1], mode="replace_on_secondary", remote_node="foo-node")
649 self.assertEqual(1000, job_id)
650 self.assertItems(["instance-bar"])
651 self.assertQuery("disks", ["1"])
652 self.assertQuery("remote_node", ["foo-node"])
654 self.rapi.AddResponse("5175")
655 self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
656 self.assertItems(["instance-moo"])
657 self.assertQuery("disks", None)
659 def testPrepareExport(self):
660 self.rapi.AddResponse("8326")
661 self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
662 self.assertHandler(rlib2.R_2_instances_name_prepare_export)
663 self.assertItems(["inst1"])
664 self.assertQuery("mode", ["local"])
666 def testExportInstance(self):
667 self.rapi.AddResponse("19695")
668 job_id = self.client.ExportInstance("inst2", "local", "nodeX",
670 self.assertEqual(job_id, 19695)
671 self.assertHandler(rlib2.R_2_instances_name_export)
672 self.assertItems(["inst2"])
674 data = serializer.LoadJson(self.rapi.GetLastRequestData())
675 self.assertEqual(data["mode"], "local")
676 self.assertEqual(data["destination"], "nodeX")
677 self.assertEqual(data["shutdown"], True)
679 def testMigrateInstanceDefaults(self):
680 self.rapi.AddResponse("24873")
681 job_id = self.client.MigrateInstance("inst91")
682 self.assertEqual(job_id, 24873)
683 self.assertHandler(rlib2.R_2_instances_name_migrate)
684 self.assertItems(["inst91"])
686 data = serializer.LoadJson(self.rapi.GetLastRequestData())
687 self.assertFalse(data)
689 def testMigrateInstance(self):
690 for mode in constants.HT_MIGRATION_MODES:
691 for cleanup in [False, True]:
692 self.rapi.AddResponse("31910")
693 job_id = self.client.MigrateInstance("inst289", mode=mode,
695 self.assertEqual(job_id, 31910)
696 self.assertHandler(rlib2.R_2_instances_name_migrate)
697 self.assertItems(["inst289"])
699 data = serializer.LoadJson(self.rapi.GetLastRequestData())
700 self.assertEqual(len(data), 2)
701 self.assertEqual(data["mode"], mode)
702 self.assertEqual(data["cleanup"], cleanup)
704 def testFailoverInstanceDefaults(self):
705 self.rapi.AddResponse("7639")
706 job_id = self.client.FailoverInstance("inst13579")
707 self.assertEqual(job_id, 7639)
708 self.assertHandler(rlib2.R_2_instances_name_failover)
709 self.assertItems(["inst13579"])
711 data = serializer.LoadJson(self.rapi.GetLastRequestData())
712 self.assertFalse(data)
714 def testFailoverInstance(self):
715 for iallocator in ["dumb", "hail"]:
716 for ignore_consistency in [False, True]:
717 for target_node in ["node-a", "node2"]:
718 self.rapi.AddResponse("19161")
720 self.client.FailoverInstance("inst251", iallocator=iallocator,
721 ignore_consistency=ignore_consistency,
722 target_node=target_node)
723 self.assertEqual(job_id, 19161)
724 self.assertHandler(rlib2.R_2_instances_name_failover)
725 self.assertItems(["inst251"])
727 data = serializer.LoadJson(self.rapi.GetLastRequestData())
728 self.assertEqual(len(data), 3)
729 self.assertEqual(data["iallocator"], iallocator)
730 self.assertEqual(data["ignore_consistency"], ignore_consistency)
731 self.assertEqual(data["target_node"], target_node)
732 self.assertEqual(self.rapi.CountPending(), 0)
734 def testRenameInstanceDefaults(self):
735 new_name = "newnametha7euqu"
736 self.rapi.AddResponse("8791")
737 job_id = self.client.RenameInstance("inst18821", new_name)
738 self.assertEqual(job_id, 8791)
739 self.assertHandler(rlib2.R_2_instances_name_rename)
740 self.assertItems(["inst18821"])
742 data = serializer.LoadJson(self.rapi.GetLastRequestData())
743 self.assertEqualValues(data, {"new_name": new_name, })
745 def testRenameInstance(self):
746 new_name = "new-name-yiux1iin"
747 for ip_check in [False, True]:
748 for name_check in [False, True]:
749 self.rapi.AddResponse("24776")
750 job_id = self.client.RenameInstance("inst20967", new_name,
752 name_check=name_check)
753 self.assertEqual(job_id, 24776)
754 self.assertHandler(rlib2.R_2_instances_name_rename)
755 self.assertItems(["inst20967"])
757 data = serializer.LoadJson(self.rapi.GetLastRequestData())
758 self.assertEqual(len(data), 3)
759 self.assertEqual(data["new_name"], new_name)
760 self.assertEqual(data["ip_check"], ip_check)
761 self.assertEqual(data["name_check"], name_check)
763 def testGetJobs(self):
764 self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
765 ' { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
766 self.assertEqual([123, 124], self.client.GetJobs())
767 self.assertHandler(rlib2.R_2_jobs)
769 def testGetJobStatus(self):
770 self.rapi.AddResponse("{\"foo\": \"bar\"}")
771 self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
772 self.assertHandler(rlib2.R_2_jobs_id)
773 self.assertItems(["1234"])
775 def testWaitForJobChange(self):
776 fields = ["id", "summary"]
778 "job_info": [123, "something"],
782 self.rapi.AddResponse(serializer.DumpJson(expected))
783 result = self.client.WaitForJobChange(123, fields, [], -1)
784 self.assertEqualValues(expected, result)
785 self.assertHandler(rlib2.R_2_jobs_id_wait)
786 self.assertItems(["123"])
788 def testCancelJob(self):
789 self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
790 self.assertEqual([True, "Job 123 will be canceled"],
791 self.client.CancelJob(999, dry_run=True))
792 self.assertHandler(rlib2.R_2_jobs_id)
793 self.assertItems(["999"])
796 def testGetNodes(self):
797 self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
798 " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
799 self.assertEqual(["node1", "node2"], self.client.GetNodes())
800 self.assertHandler(rlib2.R_2_nodes)
802 self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
803 " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
804 self.assertEqual([{"id": "node1", "uri": "uri1"},
805 {"id": "node2", "uri": "uri2"}],
806 self.client.GetNodes(bulk=True))
807 self.assertHandler(rlib2.R_2_nodes)
810 def testGetNode(self):
811 self.rapi.AddResponse("{}")
812 self.assertEqual({}, self.client.GetNode("node-foo"))
813 self.assertHandler(rlib2.R_2_nodes_name)
814 self.assertItems(["node-foo"])
816 def testEvacuateNode(self):
817 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
818 self.rapi.AddResponse("9876")
819 job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
820 self.assertEqual(9876, job_id)
821 self.assertHandler(rlib2.R_2_nodes_name_evacuate)
822 self.assertItems(["node-1"])
823 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
824 { "remote_node": "node-2", })
825 self.assertEqual(self.rapi.CountPending(), 0)
827 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
828 self.rapi.AddResponse("8888")
829 job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True,
830 mode=constants.NODE_EVAC_ALL,
832 self.assertEqual(8888, job_id)
833 self.assertItems(["node-3"])
834 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()), {
835 "iallocator": "hail",
837 "early_release": True,
841 self.assertRaises(client.GanetiApiError,
842 self.client.EvacuateNode,
843 "node-4", iallocator="hail", remote_node="node-5")
844 self.assertEqual(self.rapi.CountPending(), 0)
846 def testEvacuateNodeOldResponse(self):
847 self.rapi.AddResponse(serializer.DumpJson([]))
848 self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
849 "node-4", accept_old=False)
850 self.assertEqual(self.rapi.CountPending(), 0)
852 for mode in [client.NODE_EVAC_PRI, client.NODE_EVAC_ALL]:
853 self.rapi.AddResponse(serializer.DumpJson([]))
854 self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
855 "node-4", accept_old=True, mode=mode)
856 self.assertEqual(self.rapi.CountPending(), 0)
858 self.rapi.AddResponse(serializer.DumpJson([]))
859 self.rapi.AddResponse(serializer.DumpJson("21533"))
860 result = self.client.EvacuateNode("node-3", iallocator="hail",
861 dry_run=True, accept_old=True,
862 mode=client.NODE_EVAC_SEC,
864 self.assertEqual(result, "21533")
865 self.assertItems(["node-3"])
866 self.assertQuery("iallocator", ["hail"])
867 self.assertQuery("early_release", ["1"])
868 self.assertFalse(self.rapi.GetLastRequestData())
870 self.assertEqual(self.rapi.CountPending(), 0)
872 def testMigrateNode(self):
873 self.rapi.AddResponse(serializer.DumpJson([]))
874 self.rapi.AddResponse("1111")
875 self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
876 self.assertHandler(rlib2.R_2_nodes_name_migrate)
877 self.assertItems(["node-a"])
878 self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
880 self.assertFalse(self.rapi.GetLastRequestData())
882 self.rapi.AddResponse(serializer.DumpJson([]))
883 self.rapi.AddResponse("1112")
884 self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
886 self.assertHandler(rlib2.R_2_nodes_name_migrate)
887 self.assertItems(["node-a"])
888 self.assertQuery("mode", ["live"])
890 self.assertFalse(self.rapi.GetLastRequestData())
892 self.rapi.AddResponse(serializer.DumpJson([]))
893 self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
894 "node-c", target_node="foonode")
895 self.assertEqual(self.rapi.CountPending(), 0)
897 def testMigrateNodeBodyData(self):
898 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
899 self.rapi.AddResponse("27539")
900 self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
902 self.assertHandler(rlib2.R_2_nodes_name_migrate)
903 self.assertItems(["node-a"])
904 self.assertFalse(self.rapi.GetLastHandler().queryargs)
905 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
908 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
909 self.rapi.AddResponse("14219")
910 self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
913 self.assertHandler(rlib2.R_2_nodes_name_migrate)
914 self.assertItems(["node-x"])
916 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
917 { "target_node": "node9", "iallocator": "ial", })
919 self.assertEqual(self.rapi.CountPending(), 0)
921 def testGetNodeRole(self):
922 self.rapi.AddResponse("\"master\"")
923 self.assertEqual("master", self.client.GetNodeRole("node-a"))
924 self.assertHandler(rlib2.R_2_nodes_name_role)
925 self.assertItems(["node-a"])
927 def testSetNodeRole(self):
928 self.rapi.AddResponse("789")
929 self.assertEqual(789,
930 self.client.SetNodeRole("node-foo", "master-candidate", force=True))
931 self.assertHandler(rlib2.R_2_nodes_name_role)
932 self.assertItems(["node-foo"])
933 self.assertQuery("force", ["1"])
934 self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
936 def testPowercycleNode(self):
937 self.rapi.AddResponse("23051")
938 self.assertEqual(23051,
939 self.client.PowercycleNode("node5468", force=True))
940 self.assertHandler(rlib2.R_2_nodes_name_powercycle)
941 self.assertItems(["node5468"])
942 self.assertQuery("force", ["1"])
943 self.assertFalse(self.rapi.GetLastRequestData())
944 self.assertEqual(self.rapi.CountPending(), 0)
946 def testModifyNode(self):
947 self.rapi.AddResponse("3783")
948 job_id = self.client.ModifyNode("node16979.example.com", drained=True)
949 self.assertEqual(job_id, 3783)
950 self.assertHandler(rlib2.R_2_nodes_name_modify)
951 self.assertItems(["node16979.example.com"])
952 self.assertEqual(self.rapi.CountPending(), 0)
954 def testGetNodeStorageUnits(self):
955 self.rapi.AddResponse("42")
957 self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
958 self.assertHandler(rlib2.R_2_nodes_name_storage)
959 self.assertItems(["node-x"])
960 self.assertQuery("storage_type", ["lvm-pv"])
961 self.assertQuery("output_fields", ["fields"])
963 def testModifyNodeStorageUnits(self):
964 self.rapi.AddResponse("14")
966 self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
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", None)
973 for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
974 self.rapi.AddResponse("7205")
975 job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
976 allocatable=allocatable)
977 self.assertEqual(7205, job_id)
978 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
979 self.assertItems(["node-z"])
980 self.assertQuery("storage_type", ["lvm-pv"])
981 self.assertQuery("name", ["hda"])
982 self.assertQuery("allocatable", [query_allocatable])
984 def testRepairNodeStorageUnits(self):
985 self.rapi.AddResponse("99")
986 self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
988 self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
989 self.assertItems(["node-z"])
990 self.assertQuery("storage_type", ["lvm-pv"])
991 self.assertQuery("name", ["hda"])
993 def testGetNodeTags(self):
994 self.rapi.AddResponse("[\"fry\", \"bender\"]")
995 self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
996 self.assertHandler(rlib2.R_2_nodes_name_tags)
997 self.assertItems(["node-k"])
999 def testAddNodeTags(self):
1000 self.rapi.AddResponse("1234")
1001 self.assertEqual(1234,
1002 self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
1003 self.assertHandler(rlib2.R_2_nodes_name_tags)
1004 self.assertItems(["node-v"])
1006 self.assertQuery("tag", ["awesome"])
1008 def testDeleteNodeTags(self):
1009 self.rapi.AddResponse("16861")
1010 self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1012 self.assertHandler(rlib2.R_2_nodes_name_tags)
1013 self.assertItems(["node-w"])
1015 self.assertQuery("tag", ["awesome"])
1017 def testGetGroups(self):
1018 groups = [{"name": "group1",
1019 "uri": "/2/groups/group1",
1022 "uri": "/2/groups/group2",
1025 self.rapi.AddResponse(serializer.DumpJson(groups))
1026 self.assertEqual(["group1", "group2"], self.client.GetGroups())
1027 self.assertHandler(rlib2.R_2_groups)
1029 def testGetGroupsBulk(self):
1030 groups = [{"name": "group1",
1031 "uri": "/2/groups/group1",
1033 "node_list": ["gnt1.test",
1038 "uri": "/2/groups/group2",
1040 "node_list": ["gnt3.test",
1044 self.rapi.AddResponse(serializer.DumpJson(groups))
1046 self.assertEqual(groups, self.client.GetGroups(bulk=True))
1047 self.assertHandler(rlib2.R_2_groups)
1050 def testGetGroup(self):
1051 group = {"ctime": None,
1054 self.rapi.AddResponse(serializer.DumpJson(group))
1055 self.assertEqual({"ctime": None, "name": "default"},
1056 self.client.GetGroup("default"))
1057 self.assertHandler(rlib2.R_2_groups_name)
1058 self.assertItems(["default"])
1060 def testCreateGroup(self):
1061 self.rapi.AddResponse("12345")
1062 job_id = self.client.CreateGroup("newgroup", dry_run=True)
1063 self.assertEqual(job_id, 12345)
1064 self.assertHandler(rlib2.R_2_groups)
1067 def testDeleteGroup(self):
1068 self.rapi.AddResponse("12346")
1069 job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1070 self.assertEqual(job_id, 12346)
1071 self.assertHandler(rlib2.R_2_groups_name)
1074 def testRenameGroup(self):
1075 self.rapi.AddResponse("12347")
1076 job_id = self.client.RenameGroup("oldname", "newname")
1077 self.assertEqual(job_id, 12347)
1078 self.assertHandler(rlib2.R_2_groups_name_rename)
1080 def testModifyGroup(self):
1081 self.rapi.AddResponse("12348")
1082 job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1083 self.assertEqual(job_id, 12348)
1084 self.assertHandler(rlib2.R_2_groups_name_modify)
1086 def testAssignGroupNodes(self):
1087 self.rapi.AddResponse("12349")
1088 job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1089 force=True, dry_run=True)
1090 self.assertEqual(job_id, 12349)
1091 self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1093 self.assertUseForce()
1095 def testModifyInstance(self):
1096 self.rapi.AddResponse("23681")
1097 job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1098 self.assertEqual(job_id, 23681)
1099 self.assertItems(["inst7210"])
1100 self.assertHandler(rlib2.R_2_instances_name_modify)
1101 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1102 { "os_name": "linux", })
1104 def testModifyCluster(self):
1105 for mnh in [None, False, True]:
1106 self.rapi.AddResponse("14470")
1107 self.assertEqual(14470,
1108 self.client.ModifyCluster(maintain_node_health=mnh))
1109 self.assertHandler(rlib2.R_2_cluster_modify)
1110 self.assertItems([])
1111 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1112 self.assertEqual(len(data), 1)
1113 self.assertEqual(data["maintain_node_health"], mnh)
1114 self.assertEqual(self.rapi.CountPending(), 0)
1116 def testRedistributeConfig(self):
1117 self.rapi.AddResponse("3364")
1118 job_id = self.client.RedistributeConfig()
1119 self.assertEqual(job_id, 3364)
1120 self.assertItems([])
1121 self.assertHandler(rlib2.R_2_redist_config)
1123 def testActivateInstanceDisks(self):
1124 self.rapi.AddResponse("23547")
1125 job_id = self.client.ActivateInstanceDisks("inst28204")
1126 self.assertEqual(job_id, 23547)
1127 self.assertItems(["inst28204"])
1128 self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1129 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1131 def testActivateInstanceDisksIgnoreSize(self):
1132 self.rapi.AddResponse("11044")
1133 job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1134 self.assertEqual(job_id, 11044)
1135 self.assertItems(["inst28204"])
1136 self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1137 self.assertQuery("ignore_size", ["1"])
1139 def testDeactivateInstanceDisks(self):
1140 self.rapi.AddResponse("14591")
1141 job_id = self.client.DeactivateInstanceDisks("inst28234")
1142 self.assertEqual(job_id, 14591)
1143 self.assertItems(["inst28234"])
1144 self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1145 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1147 def testRecreateInstanceDisks(self):
1148 self.rapi.AddResponse("13553")
1149 job_id = self.client.RecreateInstanceDisks("inst23153")
1150 self.assertEqual(job_id, 13553)
1151 self.assertItems(["inst23153"])
1152 self.assertHandler(rlib2.R_2_instances_name_recreate_disks)
1153 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1155 def testGetInstanceConsole(self):
1156 self.rapi.AddResponse("26876")
1157 job_id = self.client.GetInstanceConsole("inst21491")
1158 self.assertEqual(job_id, 26876)
1159 self.assertItems(["inst21491"])
1160 self.assertHandler(rlib2.R_2_instances_name_console)
1161 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1162 self.assertFalse(self.rapi.GetLastRequestData())
1164 def testGrowInstanceDisk(self):
1165 for idx, wait_for_sync in enumerate([None, False, True]):
1166 amount = 128 + (512 * idx)
1167 self.assertEqual(self.rapi.CountPending(), 0)
1168 self.rapi.AddResponse("30783")
1169 self.assertEqual(30783,
1170 self.client.GrowInstanceDisk("eze8ch", idx, amount,
1171 wait_for_sync=wait_for_sync))
1172 self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1173 self.assertItems(["eze8ch", str(idx)])
1174 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1175 if wait_for_sync is None:
1176 self.assertEqual(len(data), 1)
1177 self.assert_("wait_for_sync" not in data)
1179 self.assertEqual(len(data), 2)
1180 self.assertEqual(data["wait_for_sync"], wait_for_sync)
1181 self.assertEqual(data["amount"], amount)
1182 self.assertEqual(self.rapi.CountPending(), 0)
1184 def testGetGroupTags(self):
1185 self.rapi.AddResponse("[]")
1186 self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1187 self.assertHandler(rlib2.R_2_groups_name_tags)
1188 self.assertItems(["fooGroup"])
1190 def testAddGroupTags(self):
1191 self.rapi.AddResponse("1234")
1192 self.assertEqual(1234,
1193 self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1194 self.assertHandler(rlib2.R_2_groups_name_tags)
1195 self.assertItems(["fooGroup"])
1197 self.assertQuery("tag", ["awesome"])
1199 def testDeleteGroupTags(self):
1200 self.rapi.AddResponse("25826")
1201 self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1203 self.assertHandler(rlib2.R_2_groups_name_tags)
1204 self.assertItems(["foo"])
1206 self.assertQuery("tag", ["awesome"])
1208 def testQuery(self):
1209 for idx, what in enumerate(constants.QR_VIA_RAPI):
1210 for idx2, qfilter in enumerate([None, ["?", "name"]]):
1211 job_id = 11010 + (idx << 4) + (idx2 << 16)
1212 fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1214 self.rapi.AddResponse(str(job_id))
1215 self.assertEqual(self.client.Query(what, fields, qfilter=qfilter),
1217 self.assertItems([what])
1218 self.assertHandler(rlib2.R_2_query)
1219 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1220 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1221 self.assertEqual(data["fields"], fields)
1223 self.assertTrue("qfilter" not in data)
1225 self.assertEqual(data["qfilter"], qfilter)
1226 self.assertEqual(self.rapi.CountPending(), 0)
1228 def testQueryFields(self):
1229 exp_result = objects.QueryFieldsResponse(fields=[
1230 objects.QueryFieldDefinition(name="pnode", title="PNode",
1231 kind=constants.QFT_NUMBER),
1232 objects.QueryFieldDefinition(name="other", title="Other",
1233 kind=constants.QFT_BOOL),
1236 for what in constants.QR_VIA_RAPI:
1237 for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1238 self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1239 result = self.client.QueryFields(what, fields=fields)
1240 self.assertItems([what])
1241 self.assertHandler(rlib2.R_2_query_fields)
1242 self.assertFalse(self.rapi.GetLastRequestData())
1244 queryargs = self.rapi.GetLastHandler().queryargs
1246 self.assertFalse(queryargs)
1248 self.assertEqual(queryargs, {
1249 "fields": [",".join(fields)],
1252 self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1253 exp_result.ToDict())
1255 self.assertEqual(self.rapi.CountPending(), 0)
1257 def testWaitForJobCompletionNoChange(self):
1258 resp = serializer.DumpJson({
1259 "status": constants.JOB_STATUS_WAITING,
1262 for retries in [1, 5, 25]:
1263 for _ in range(retries):
1264 self.rapi.AddResponse(resp)
1266 self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1268 self.assertHandler(rlib2.R_2_jobs_id)
1269 self.assertItems(["22789"])
1271 self.assertEqual(self.rapi.CountPending(), 0)
1273 def testWaitForJobCompletionAlreadyFinished(self):
1274 self.rapi.AddResponse(serializer.DumpJson({
1275 "status": constants.JOB_STATUS_SUCCESS,
1278 self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1280 self.assertHandler(rlib2.R_2_jobs_id)
1281 self.assertItems(["22793"])
1283 self.assertEqual(self.rapi.CountPending(), 0)
1285 def testWaitForJobCompletionEmptyResponse(self):
1286 self.rapi.AddResponse("{}")
1287 self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1289 self.assertHandler(rlib2.R_2_jobs_id)
1290 self.assertItems(["22793"])
1292 self.assertEqual(self.rapi.CountPending(), 0)
1294 def testWaitForJobCompletionOutOfRetries(self):
1295 for retries in [3, 10, 21]:
1296 for _ in range(retries):
1297 self.rapi.AddResponse(serializer.DumpJson({
1298 "status": constants.JOB_STATUS_RUNNING,
1301 self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1302 retries=retries - 1))
1303 self.assertHandler(rlib2.R_2_jobs_id)
1304 self.assertItems(["30948"])
1306 self.assertEqual(self.rapi.CountPending(), 1)
1307 self.rapi.ResetResponses()
1309 def testWaitForJobCompletionSuccessAndFailure(self):
1310 for retries in [1, 4, 13]:
1311 for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1312 (True, constants.JOB_STATUS_SUCCESS)]:
1313 for _ in range(retries):
1314 self.rapi.AddResponse(serializer.DumpJson({
1315 "status": constants.JOB_STATUS_RUNNING,
1318 self.rapi.AddResponse(serializer.DumpJson({
1319 "status": end_status,
1322 result = self.client.WaitForJobCompletion(3187, period=None,
1323 retries=retries + 1)
1324 self.assertEqual(result, success)
1325 self.assertHandler(rlib2.R_2_jobs_id)
1326 self.assertItems(["3187"])
1328 self.assertEqual(self.rapi.CountPending(), 0)
1331 class RapiTestRunner(unittest.TextTestRunner):
1332 def run(self, *args):
1333 global _used_handlers
1334 assert _used_handlers is None
1336 _used_handlers = set()
1339 result = unittest.TextTestRunner.run(self, *args)
1341 diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1344 raise AssertionError("The following RAPI resources were not used by the"
1345 " RAPI client: %r" % utils.CommaJoin(diff))
1347 # Reset global variable
1348 _used_handlers = None
1353 if __name__ == '__main__':
1354 client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)