4 # Copyright (C) 2010 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 """Script for unittesting the RAPI client module"""
30 from ganeti import constants
31 from ganeti import http
32 from ganeti import serializer
33 from ganeti import utils
34 from ganeti import query
35 from ganeti import objects
37 from ganeti.rapi import connector
38 from ganeti.rapi import rlib2
39 from ganeti.rapi import client
44 _URI_RE = re.compile(r"https://(?P<host>.*):(?P<port>\d+)(?P<path>/.*)")
46 # List of resource handlers which aren't used by the RAPI client
52 # Global variable for collecting used handlers
56 def _GetPathFromUri(uri):
57 """Gets the path and query from a URI.
60 match = _URI_RE.match(uri)
62 return match.groupdict()["path"]
68 def __init__(self, rapi):
73 def setopt(self, opt, value):
74 self._opts[opt] = value
76 def getopt(self, opt):
77 return self._opts.get(opt)
79 def unsetopt(self, opt):
80 self._opts.pop(opt, None)
82 def getinfo(self, info):
83 return self._info[info]
86 method = self._opts[pycurl.CUSTOMREQUEST]
87 url = self._opts[pycurl.URL]
88 request_body = self._opts[pycurl.POSTFIELDS]
89 writefn = self._opts[pycurl.WRITEFUNCTION]
91 path = _GetPathFromUri(url)
92 (code, resp_body) = self._rapi.FetchResponse(path, method, request_body)
94 self._info[pycurl.RESPONSE_CODE] = code
95 if resp_body is not None:
99 class RapiMock(object):
101 self._mapper = connector.Mapper()
103 self._last_handler = None
104 self._last_req_data = None
106 def ResetResponses(self):
107 del self._responses[:]
109 def AddResponse(self, response, code=200):
110 self._responses.insert(0, (code, response))
112 def CountPending(self):
113 return len(self._responses)
115 def GetLastHandler(self):
116 return self._last_handler
118 def GetLastRequestData(self):
119 return self._last_req_data
121 def FetchResponse(self, path, method, request_body):
122 self._last_req_data = request_body
125 (handler_cls, items, args) = self._mapper.getController(path)
127 # Record handler as used
128 _used_handlers.add(handler_cls)
130 self._last_handler = handler_cls(items, args, None)
131 if not hasattr(self._last_handler, method.upper()):
132 raise http.HttpNotImplemented(message="Method not implemented")
134 except http.HttpException, ex:
136 response = ex.message
138 if not self._responses:
139 raise Exception("No responses")
141 (code, response) = self._responses.pop()
143 return code, response
146 class TestConstants(unittest.TestCase):
148 self.assertEqual(client.GANETI_RAPI_PORT, constants.DEFAULT_RAPI_PORT)
149 self.assertEqual(client.GANETI_RAPI_VERSION, constants.RAPI_VERSION)
150 self.assertEqual(client.HTTP_APP_JSON, http.HTTP_APP_JSON)
151 self.assertEqual(client._REQ_DATA_VERSION_FIELD, rlib2._REQ_DATA_VERSION)
152 self.assertEqual(client._INST_CREATE_REQV1, rlib2._INST_CREATE_REQV1)
153 self.assertEqual(client._INST_REINSTALL_REQV1, rlib2._INST_REINSTALL_REQV1)
154 self.assertEqual(client._NODE_MIGRATE_REQV1, rlib2._NODE_MIGRATE_REQV1)
155 self.assertEqual(client._NODE_EVAC_RES1, rlib2._NODE_EVAC_RES1)
156 self.assertEqual(client._INST_NIC_PARAMS, constants.INIC_PARAMS)
157 self.assertEqual(client.JOB_STATUS_QUEUED, constants.JOB_STATUS_QUEUED)
158 self.assertEqual(client.JOB_STATUS_WAITING, constants.JOB_STATUS_WAITING)
159 self.assertEqual(client.JOB_STATUS_CANCELING,
160 constants.JOB_STATUS_CANCELING)
161 self.assertEqual(client.JOB_STATUS_RUNNING, constants.JOB_STATUS_RUNNING)
162 self.assertEqual(client.JOB_STATUS_CANCELED, constants.JOB_STATUS_CANCELED)
163 self.assertEqual(client.JOB_STATUS_SUCCESS, constants.JOB_STATUS_SUCCESS)
164 self.assertEqual(client.JOB_STATUS_ERROR, constants.JOB_STATUS_ERROR)
165 self.assertEqual(client.JOB_STATUS_FINALIZED, constants.JOBS_FINALIZED)
166 self.assertEqual(client.JOB_STATUS_ALL, constants.JOB_STATUS_ALL)
169 self.assertEqual(client.NODE_EVAC_PRI, constants.IALLOCATOR_NEVAC_PRI)
170 self.assertEqual(client.NODE_EVAC_SEC, constants.IALLOCATOR_NEVAC_SEC)
171 self.assertEqual(client.NODE_EVAC_ALL, constants.IALLOCATOR_NEVAC_ALL)
174 self.assertEqual(client.JOB_STATUS_WAITLOCK, constants.JOB_STATUS_WAITING)
177 class RapiMockTest(unittest.TestCase):
181 self.assertEqual((404, None), rapi.FetchResponse("/foo", "GET", None))
182 self.assertEqual((501, "Method not implemented"),
183 rapi.FetchResponse("/version", "POST", None))
184 rapi.AddResponse("2")
185 code, response = rapi.FetchResponse("/version", "GET", None)
186 self.assertEqual(200, code)
187 self.assertEqual("2", response)
188 self.failUnless(isinstance(rapi.GetLastHandler(), rlib2.R_version))
191 def _FakeNoSslPycurlVersion():
192 # Note: incomplete version tuple
193 return (3, "7.16.0", 462848, "mysystem", 1581, None, 0)
196 def _FakeFancySslPycurlVersion():
197 # Note: incomplete version tuple
198 return (3, "7.16.0", 462848, "mysystem", 1581, "FancySSL/1.2.3", 0)
201 def _FakeOpenSslPycurlVersion():
202 # Note: incomplete version tuple
203 return (2, "7.15.5", 462597, "othersystem", 668, "OpenSSL/0.9.8c", 0)
206 def _FakeGnuTlsPycurlVersion():
207 # Note: incomplete version tuple
208 return (3, "7.18.0", 463360, "somesystem", 1581, "GnuTLS/2.0.4", 0)
211 class TestExtendedConfig(unittest.TestCase):
213 cl = client.GanetiRapiClient("master.example.com",
214 username="user", password="pw",
215 curl_factory=lambda: FakeCurl(RapiMock()))
217 curl = cl._CreateCurl()
218 self.assertEqual(curl.getopt(pycurl.HTTPAUTH), pycurl.HTTPAUTH_BASIC)
219 self.assertEqual(curl.getopt(pycurl.USERPWD), "user:pw")
221 def testInvalidAuth(self):
223 self.assertRaises(client.Error, client.GanetiRapiClient,
224 "master-a.example.com", password="pw")
226 self.assertRaises(client.Error, client.GanetiRapiClient,
227 "master-b.example.com", username="user")
229 def testCertVerifyInvalidCombinations(self):
230 self.assertRaises(client.Error, client.GenericCurlConfig,
231 use_curl_cabundle=True, cafile="cert1.pem")
232 self.assertRaises(client.Error, client.GenericCurlConfig,
233 use_curl_cabundle=True, capath="certs/")
234 self.assertRaises(client.Error, client.GenericCurlConfig,
235 use_curl_cabundle=True,
236 cafile="cert1.pem", capath="certs/")
238 def testProxySignalVerifyHostname(self):
239 for use_gnutls in [False, True]:
241 pcverfn = _FakeGnuTlsPycurlVersion
243 pcverfn = _FakeOpenSslPycurlVersion
245 for proxy in ["", "http://127.0.0.1:1234"]:
246 for use_signal in [False, True]:
247 for verify_hostname in [False, True]:
248 cfgfn = client.GenericCurlConfig(proxy=proxy, use_signal=use_signal,
249 verify_hostname=verify_hostname,
250 _pycurl_version_fn=pcverfn)
252 curl_factory = lambda: FakeCurl(RapiMock())
253 cl = client.GanetiRapiClient("master.example.com",
254 curl_config_fn=cfgfn,
255 curl_factory=curl_factory)
257 curl = cl._CreateCurl()
258 self.assertEqual(curl.getopt(pycurl.PROXY), proxy)
259 self.assertEqual(curl.getopt(pycurl.NOSIGNAL), not use_signal)
262 self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 2)
264 self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 0)
266 def testNoCertVerify(self):
267 cfgfn = client.GenericCurlConfig()
269 curl_factory = lambda: FakeCurl(RapiMock())
270 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
271 curl_factory=curl_factory)
273 curl = cl._CreateCurl()
274 self.assertFalse(curl.getopt(pycurl.SSL_VERIFYPEER))
275 self.assertFalse(curl.getopt(pycurl.CAINFO))
276 self.assertFalse(curl.getopt(pycurl.CAPATH))
278 def testCertVerifyCurlBundle(self):
279 cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
281 curl_factory = lambda: FakeCurl(RapiMock())
282 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
283 curl_factory=curl_factory)
285 curl = cl._CreateCurl()
286 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
287 self.assertFalse(curl.getopt(pycurl.CAINFO))
288 self.assertFalse(curl.getopt(pycurl.CAPATH))
290 def testCertVerifyCafile(self):
291 mycert = "/tmp/some/UNUSED/cert/file.pem"
292 cfgfn = client.GenericCurlConfig(cafile=mycert)
294 curl_factory = lambda: FakeCurl(RapiMock())
295 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
296 curl_factory=curl_factory)
298 curl = cl._CreateCurl()
299 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
300 self.assertEqual(curl.getopt(pycurl.CAINFO), mycert)
301 self.assertFalse(curl.getopt(pycurl.CAPATH))
303 def testCertVerifyCapath(self):
304 certdir = "/tmp/some/UNUSED/cert/directory"
305 pcverfn = _FakeOpenSslPycurlVersion
306 cfgfn = client.GenericCurlConfig(capath=certdir,
307 _pycurl_version_fn=pcverfn)
309 curl_factory = lambda: FakeCurl(RapiMock())
310 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
311 curl_factory=curl_factory)
313 curl = cl._CreateCurl()
314 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
315 self.assertEqual(curl.getopt(pycurl.CAPATH), certdir)
316 self.assertFalse(curl.getopt(pycurl.CAINFO))
318 def testCertVerifyCapathGnuTls(self):
319 certdir = "/tmp/some/UNUSED/cert/directory"
320 pcverfn = _FakeGnuTlsPycurlVersion
321 cfgfn = client.GenericCurlConfig(capath=certdir,
322 _pycurl_version_fn=pcverfn)
324 curl_factory = lambda: FakeCurl(RapiMock())
325 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
326 curl_factory=curl_factory)
328 self.assertRaises(client.Error, cl._CreateCurl)
330 def testCertVerifyNoSsl(self):
331 certdir = "/tmp/some/UNUSED/cert/directory"
332 pcverfn = _FakeNoSslPycurlVersion
333 cfgfn = client.GenericCurlConfig(capath=certdir,
334 _pycurl_version_fn=pcverfn)
336 curl_factory = lambda: FakeCurl(RapiMock())
337 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
338 curl_factory=curl_factory)
340 self.assertRaises(client.Error, cl._CreateCurl)
342 def testCertVerifyFancySsl(self):
343 certdir = "/tmp/some/UNUSED/cert/directory"
344 pcverfn = _FakeFancySslPycurlVersion
345 cfgfn = client.GenericCurlConfig(capath=certdir,
346 _pycurl_version_fn=pcverfn)
348 curl_factory = lambda: FakeCurl(RapiMock())
349 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
350 curl_factory=curl_factory)
352 self.assertRaises(NotImplementedError, cl._CreateCurl)
354 def testCertVerifyCapath(self):
355 for connect_timeout in [None, 1, 5, 10, 30, 60, 300]:
356 for timeout in [None, 1, 30, 60, 3600, 24 * 3600]:
357 cfgfn = client.GenericCurlConfig(connect_timeout=connect_timeout,
360 curl_factory = lambda: FakeCurl(RapiMock())
361 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
362 curl_factory=curl_factory)
364 curl = cl._CreateCurl()
365 self.assertEqual(curl.getopt(pycurl.CONNECTTIMEOUT), connect_timeout)
366 self.assertEqual(curl.getopt(pycurl.TIMEOUT), timeout)
369 class GanetiRapiClientTests(testutils.GanetiTestCase):
371 testutils.GanetiTestCase.setUp(self)
373 self.rapi = RapiMock()
374 self.curl = FakeCurl(self.rapi)
375 self.client = client.GanetiRapiClient("master.example.com",
376 curl_factory=lambda: self.curl)
378 def assertHandler(self, handler_cls):
379 self.failUnless(isinstance(self.rapi.GetLastHandler(), handler_cls))
381 def assertQuery(self, key, value):
382 self.assertEqual(value, self.rapi.GetLastHandler().queryargs.get(key, None))
384 def assertItems(self, items):
385 self.assertEqual(items, self.rapi.GetLastHandler().items)
387 def assertBulk(self):
388 self.assertTrue(self.rapi.GetLastHandler().useBulk())
390 def assertDryRun(self):
391 self.assertTrue(self.rapi.GetLastHandler().dryRun())
393 def assertUseForce(self):
394 self.assertTrue(self.rapi.GetLastHandler().useForce())
396 def testEncodeQuery(self):
413 self.assertEqualValues(self.client._EncodeQuery(query),
417 for i in [[1, 2, 3], {"moo": "boo"}, (1, 2, 3)]:
418 self.assertRaises(ValueError, self.client._EncodeQuery, [("x", i)])
420 def testCurlSettings(self):
421 self.rapi.AddResponse("2")
422 self.assertEqual(2, self.client.GetVersion())
423 self.assertHandler(rlib2.R_version)
425 # Signals should be disabled by default
426 self.assert_(self.curl.getopt(pycurl.NOSIGNAL))
428 # No auth and no proxy
429 self.assertFalse(self.curl.getopt(pycurl.USERPWD))
430 self.assert_(self.curl.getopt(pycurl.PROXY) is None)
432 # Content-type is required for requests
433 headers = self.curl.getopt(pycurl.HTTPHEADER)
434 self.assert_("Content-type: application/json" in headers)
436 def testHttpError(self):
437 self.rapi.AddResponse(None, code=404)
439 self.client.GetJobStatus(15140)
440 except client.GanetiApiError, err:
441 self.assertEqual(err.code, 404)
443 self.fail("Didn't raise exception")
445 def testGetVersion(self):
446 self.rapi.AddResponse("2")
447 self.assertEqual(2, self.client.GetVersion())
448 self.assertHandler(rlib2.R_version)
450 def testGetFeatures(self):
451 for features in [[], ["foo", "bar", "baz"]]:
452 self.rapi.AddResponse(serializer.DumpJson(features))
453 self.assertEqual(features, self.client.GetFeatures())
454 self.assertHandler(rlib2.R_2_features)
456 def testGetFeaturesNotFound(self):
457 self.rapi.AddResponse(None, code=404)
458 self.assertEqual([], self.client.GetFeatures())
460 def testGetOperatingSystems(self):
461 self.rapi.AddResponse("[\"beos\"]")
462 self.assertEqual(["beos"], self.client.GetOperatingSystems())
463 self.assertHandler(rlib2.R_2_os)
465 def testGetClusterTags(self):
466 self.rapi.AddResponse("[\"tag\"]")
467 self.assertEqual(["tag"], self.client.GetClusterTags())
468 self.assertHandler(rlib2.R_2_tags)
470 def testAddClusterTags(self):
471 self.rapi.AddResponse("1234")
472 self.assertEqual(1234,
473 self.client.AddClusterTags(["awesome"], dry_run=True))
474 self.assertHandler(rlib2.R_2_tags)
476 self.assertQuery("tag", ["awesome"])
478 def testDeleteClusterTags(self):
479 self.rapi.AddResponse("5107")
480 self.assertEqual(5107, self.client.DeleteClusterTags(["awesome"],
482 self.assertHandler(rlib2.R_2_tags)
484 self.assertQuery("tag", ["awesome"])
486 def testGetInfo(self):
487 self.rapi.AddResponse("{}")
488 self.assertEqual({}, self.client.GetInfo())
489 self.assertHandler(rlib2.R_2_info)
491 def testGetInstances(self):
492 self.rapi.AddResponse("[]")
493 self.assertEqual([], self.client.GetInstances(bulk=True))
494 self.assertHandler(rlib2.R_2_instances)
497 def testGetInstance(self):
498 self.rapi.AddResponse("[]")
499 self.assertEqual([], self.client.GetInstance("instance"))
500 self.assertHandler(rlib2.R_2_instances_name)
501 self.assertItems(["instance"])
503 def testGetInstanceInfo(self):
504 self.rapi.AddResponse("21291")
505 self.assertEqual(21291, self.client.GetInstanceInfo("inst3"))
506 self.assertHandler(rlib2.R_2_instances_name_info)
507 self.assertItems(["inst3"])
508 self.assertQuery("static", None)
510 self.rapi.AddResponse("3428")
511 self.assertEqual(3428, self.client.GetInstanceInfo("inst31", static=False))
512 self.assertHandler(rlib2.R_2_instances_name_info)
513 self.assertItems(["inst31"])
514 self.assertQuery("static", ["0"])
516 self.rapi.AddResponse("15665")
517 self.assertEqual(15665, self.client.GetInstanceInfo("inst32", static=True))
518 self.assertHandler(rlib2.R_2_instances_name_info)
519 self.assertItems(["inst32"])
520 self.assertQuery("static", ["1"])
522 def testCreateInstanceOldVersion(self):
523 # The old request format, version 0, is no longer supported
524 self.rapi.AddResponse(None, code=404)
525 self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
526 "create", "inst1.example.com", "plain", [], [])
527 self.assertEqual(self.rapi.CountPending(), 0)
529 def testCreateInstance(self):
530 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
531 self.rapi.AddResponse("23030")
532 job_id = self.client.CreateInstance("create", "inst1.example.com",
533 "plain", [], [], dry_run=True)
534 self.assertEqual(job_id, 23030)
535 self.assertHandler(rlib2.R_2_instances)
538 data = serializer.LoadJson(self.rapi.GetLastRequestData())
540 for field in ["dry_run", "beparams", "hvparams", "start"]:
541 self.assertFalse(field in data)
543 self.assertEqual(data["name"], "inst1.example.com")
544 self.assertEqual(data["disk_template"], "plain")
546 def testCreateInstance2(self):
547 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
548 self.rapi.AddResponse("24740")
549 job_id = self.client.CreateInstance("import", "inst2.example.com",
550 "drbd8", [{"size": 100,}],
551 [{}, {"bridge": "br1", }],
552 dry_run=False, start=True,
553 pnode="node1", snode="node9",
555 self.assertEqual(job_id, 24740)
556 self.assertHandler(rlib2.R_2_instances)
558 data = serializer.LoadJson(self.rapi.GetLastRequestData())
559 self.assertEqual(data[rlib2._REQ_DATA_VERSION], 1)
560 self.assertEqual(data["name"], "inst2.example.com")
561 self.assertEqual(data["disk_template"], "drbd8")
562 self.assertEqual(data["start"], True)
563 self.assertEqual(data["ip_check"], False)
564 self.assertEqualValues(data["disks"], [{"size": 100,}])
565 self.assertEqualValues(data["nics"], [{}, {"bridge": "br1", }])
567 def testDeleteInstance(self):
568 self.rapi.AddResponse("1234")
569 self.assertEqual(1234, self.client.DeleteInstance("instance", dry_run=True))
570 self.assertHandler(rlib2.R_2_instances_name)
571 self.assertItems(["instance"])
574 def testGetInstanceTags(self):
575 self.rapi.AddResponse("[]")
576 self.assertEqual([], self.client.GetInstanceTags("fooinstance"))
577 self.assertHandler(rlib2.R_2_instances_name_tags)
578 self.assertItems(["fooinstance"])
580 def testAddInstanceTags(self):
581 self.rapi.AddResponse("1234")
582 self.assertEqual(1234,
583 self.client.AddInstanceTags("fooinstance", ["awesome"], dry_run=True))
584 self.assertHandler(rlib2.R_2_instances_name_tags)
585 self.assertItems(["fooinstance"])
587 self.assertQuery("tag", ["awesome"])
589 def testDeleteInstanceTags(self):
590 self.rapi.AddResponse("25826")
591 self.assertEqual(25826, self.client.DeleteInstanceTags("foo", ["awesome"],
593 self.assertHandler(rlib2.R_2_instances_name_tags)
594 self.assertItems(["foo"])
596 self.assertQuery("tag", ["awesome"])
598 def testRebootInstance(self):
599 self.rapi.AddResponse("6146")
600 job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
601 ignore_secondaries=True, dry_run=True)
602 self.assertEqual(6146, job_id)
603 self.assertHandler(rlib2.R_2_instances_name_reboot)
604 self.assertItems(["i-bar"])
606 self.assertQuery("type", ["hard"])
607 self.assertQuery("ignore_secondaries", ["1"])
609 def testShutdownInstance(self):
610 self.rapi.AddResponse("1487")
611 self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
613 self.assertHandler(rlib2.R_2_instances_name_shutdown)
614 self.assertItems(["foo-instance"])
617 def testStartupInstance(self):
618 self.rapi.AddResponse("27149")
619 self.assertEqual(27149, self.client.StartupInstance("bar-instance",
621 self.assertHandler(rlib2.R_2_instances_name_startup)
622 self.assertItems(["bar-instance"])
625 def testReinstallInstance(self):
626 self.rapi.AddResponse(serializer.DumpJson([]))
627 self.rapi.AddResponse("19119")
628 self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
631 self.assertHandler(rlib2.R_2_instances_name_reinstall)
632 self.assertItems(["baz-instance"])
633 self.assertQuery("os", ["DOS"])
634 self.assertQuery("nostartup", ["1"])
635 self.assertEqual(self.rapi.CountPending(), 0)
637 def testReinstallInstanceNew(self):
638 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
639 self.rapi.AddResponse("25689")
640 self.assertEqual(25689, self.client.ReinstallInstance("moo-instance",
643 self.assertHandler(rlib2.R_2_instances_name_reinstall)
644 self.assertItems(["moo-instance"])
645 data = serializer.LoadJson(self.rapi.GetLastRequestData())
646 self.assertEqual(len(data), 2)
647 self.assertEqual(data["os"], "Debian")
648 self.assertEqual(data["start"], False)
649 self.assertEqual(self.rapi.CountPending(), 0)
651 def testReinstallInstanceWithOsparams1(self):
652 self.rapi.AddResponse(serializer.DumpJson([]))
653 self.assertRaises(client.GanetiApiError, self.client.ReinstallInstance,
654 "doo-instance", osparams={"x": "y"})
655 self.assertEqual(self.rapi.CountPending(), 0)
657 def testReinstallInstanceWithOsparams2(self):
662 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
663 self.rapi.AddResponse("1717")
664 self.assertEqual(1717, self.client.ReinstallInstance("zoo-instance",
666 self.assertHandler(rlib2.R_2_instances_name_reinstall)
667 self.assertItems(["zoo-instance"])
668 data = serializer.LoadJson(self.rapi.GetLastRequestData())
669 self.assertEqual(len(data), 2)
670 self.assertEqual(data["osparams"], osparams)
671 self.assertEqual(data["start"], True)
672 self.assertEqual(self.rapi.CountPending(), 0)
674 def testReplaceInstanceDisks(self):
675 self.rapi.AddResponse("999")
676 job_id = self.client.ReplaceInstanceDisks("instance-name",
677 disks=[0, 1], iallocator="hail")
678 self.assertEqual(999, job_id)
679 self.assertHandler(rlib2.R_2_instances_name_replace_disks)
680 self.assertItems(["instance-name"])
681 self.assertQuery("disks", ["0,1"])
682 self.assertQuery("mode", ["replace_auto"])
683 self.assertQuery("iallocator", ["hail"])
685 self.rapi.AddResponse("1000")
686 job_id = self.client.ReplaceInstanceDisks("instance-bar",
687 disks=[1], mode="replace_on_secondary", remote_node="foo-node")
688 self.assertEqual(1000, job_id)
689 self.assertItems(["instance-bar"])
690 self.assertQuery("disks", ["1"])
691 self.assertQuery("remote_node", ["foo-node"])
693 self.rapi.AddResponse("5175")
694 self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
695 self.assertItems(["instance-moo"])
696 self.assertQuery("disks", None)
698 def testPrepareExport(self):
699 self.rapi.AddResponse("8326")
700 self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
701 self.assertHandler(rlib2.R_2_instances_name_prepare_export)
702 self.assertItems(["inst1"])
703 self.assertQuery("mode", ["local"])
705 def testExportInstance(self):
706 self.rapi.AddResponse("19695")
707 job_id = self.client.ExportInstance("inst2", "local", "nodeX",
709 self.assertEqual(job_id, 19695)
710 self.assertHandler(rlib2.R_2_instances_name_export)
711 self.assertItems(["inst2"])
713 data = serializer.LoadJson(self.rapi.GetLastRequestData())
714 self.assertEqual(data["mode"], "local")
715 self.assertEqual(data["destination"], "nodeX")
716 self.assertEqual(data["shutdown"], True)
718 def testMigrateInstanceDefaults(self):
719 self.rapi.AddResponse("24873")
720 job_id = self.client.MigrateInstance("inst91")
721 self.assertEqual(job_id, 24873)
722 self.assertHandler(rlib2.R_2_instances_name_migrate)
723 self.assertItems(["inst91"])
725 data = serializer.LoadJson(self.rapi.GetLastRequestData())
726 self.assertFalse(data)
728 def testMigrateInstance(self):
729 for mode in constants.HT_MIGRATION_MODES:
730 for cleanup in [False, True]:
731 self.rapi.AddResponse("31910")
732 job_id = self.client.MigrateInstance("inst289", mode=mode,
734 self.assertEqual(job_id, 31910)
735 self.assertHandler(rlib2.R_2_instances_name_migrate)
736 self.assertItems(["inst289"])
738 data = serializer.LoadJson(self.rapi.GetLastRequestData())
739 self.assertEqual(len(data), 2)
740 self.assertEqual(data["mode"], mode)
741 self.assertEqual(data["cleanup"], cleanup)
743 def testFailoverInstanceDefaults(self):
744 self.rapi.AddResponse("7639")
745 job_id = self.client.FailoverInstance("inst13579")
746 self.assertEqual(job_id, 7639)
747 self.assertHandler(rlib2.R_2_instances_name_failover)
748 self.assertItems(["inst13579"])
750 data = serializer.LoadJson(self.rapi.GetLastRequestData())
751 self.assertFalse(data)
753 def testFailoverInstance(self):
754 for iallocator in ["dumb", "hail"]:
755 for ignore_consistency in [False, True]:
756 for target_node in ["node-a", "node2"]:
757 self.rapi.AddResponse("19161")
759 self.client.FailoverInstance("inst251", iallocator=iallocator,
760 ignore_consistency=ignore_consistency,
761 target_node=target_node)
762 self.assertEqual(job_id, 19161)
763 self.assertHandler(rlib2.R_2_instances_name_failover)
764 self.assertItems(["inst251"])
766 data = serializer.LoadJson(self.rapi.GetLastRequestData())
767 self.assertEqual(len(data), 3)
768 self.assertEqual(data["iallocator"], iallocator)
769 self.assertEqual(data["ignore_consistency"], ignore_consistency)
770 self.assertEqual(data["target_node"], target_node)
771 self.assertEqual(self.rapi.CountPending(), 0)
773 def testRenameInstanceDefaults(self):
774 new_name = "newnametha7euqu"
775 self.rapi.AddResponse("8791")
776 job_id = self.client.RenameInstance("inst18821", new_name)
777 self.assertEqual(job_id, 8791)
778 self.assertHandler(rlib2.R_2_instances_name_rename)
779 self.assertItems(["inst18821"])
781 data = serializer.LoadJson(self.rapi.GetLastRequestData())
782 self.assertEqualValues(data, {"new_name": new_name, })
784 def testRenameInstance(self):
785 new_name = "new-name-yiux1iin"
786 for ip_check in [False, True]:
787 for name_check in [False, True]:
788 self.rapi.AddResponse("24776")
789 job_id = self.client.RenameInstance("inst20967", new_name,
791 name_check=name_check)
792 self.assertEqual(job_id, 24776)
793 self.assertHandler(rlib2.R_2_instances_name_rename)
794 self.assertItems(["inst20967"])
796 data = serializer.LoadJson(self.rapi.GetLastRequestData())
797 self.assertEqual(len(data), 3)
798 self.assertEqual(data["new_name"], new_name)
799 self.assertEqual(data["ip_check"], ip_check)
800 self.assertEqual(data["name_check"], name_check)
802 def testGetJobs(self):
803 self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
804 ' { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
805 self.assertEqual([123, 124], self.client.GetJobs())
806 self.assertHandler(rlib2.R_2_jobs)
808 def testGetJobStatus(self):
809 self.rapi.AddResponse("{\"foo\": \"bar\"}")
810 self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
811 self.assertHandler(rlib2.R_2_jobs_id)
812 self.assertItems(["1234"])
814 def testWaitForJobChange(self):
815 fields = ["id", "summary"]
817 "job_info": [123, "something"],
821 self.rapi.AddResponse(serializer.DumpJson(expected))
822 result = self.client.WaitForJobChange(123, fields, [], -1)
823 self.assertEqualValues(expected, result)
824 self.assertHandler(rlib2.R_2_jobs_id_wait)
825 self.assertItems(["123"])
827 def testCancelJob(self):
828 self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
829 self.assertEqual([True, "Job 123 will be canceled"],
830 self.client.CancelJob(999, dry_run=True))
831 self.assertHandler(rlib2.R_2_jobs_id)
832 self.assertItems(["999"])
835 def testGetNodes(self):
836 self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
837 " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
838 self.assertEqual(["node1", "node2"], self.client.GetNodes())
839 self.assertHandler(rlib2.R_2_nodes)
841 self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
842 " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
843 self.assertEqual([{"id": "node1", "uri": "uri1"},
844 {"id": "node2", "uri": "uri2"}],
845 self.client.GetNodes(bulk=True))
846 self.assertHandler(rlib2.R_2_nodes)
849 def testGetNode(self):
850 self.rapi.AddResponse("{}")
851 self.assertEqual({}, self.client.GetNode("node-foo"))
852 self.assertHandler(rlib2.R_2_nodes_name)
853 self.assertItems(["node-foo"])
855 def testEvacuateNode(self):
856 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
857 self.rapi.AddResponse("9876")
858 job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
859 self.assertEqual(9876, job_id)
860 self.assertHandler(rlib2.R_2_nodes_name_evacuate)
861 self.assertItems(["node-1"])
862 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
863 { "remote_node": "node-2", })
864 self.assertEqual(self.rapi.CountPending(), 0)
866 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
867 self.rapi.AddResponse("8888")
868 job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True,
869 mode=constants.IALLOCATOR_NEVAC_ALL,
871 self.assertEqual(8888, job_id)
872 self.assertItems(["node-3"])
873 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()), {
874 "iallocator": "hail",
876 "early_release": True,
880 self.assertRaises(client.GanetiApiError,
881 self.client.EvacuateNode,
882 "node-4", iallocator="hail", remote_node="node-5")
883 self.assertEqual(self.rapi.CountPending(), 0)
885 def testEvacuateNodeOldResponse(self):
886 self.rapi.AddResponse(serializer.DumpJson([]))
887 self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
888 "node-4", accept_old=False)
889 self.assertEqual(self.rapi.CountPending(), 0)
891 for mode in [client.NODE_EVAC_PRI, client.NODE_EVAC_ALL]:
892 self.rapi.AddResponse(serializer.DumpJson([]))
893 self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
894 "node-4", accept_old=True, mode=mode)
895 self.assertEqual(self.rapi.CountPending(), 0)
897 self.rapi.AddResponse(serializer.DumpJson([]))
898 self.rapi.AddResponse(serializer.DumpJson("21533"))
899 result = self.client.EvacuateNode("node-3", iallocator="hail",
900 dry_run=True, accept_old=True,
901 mode=client.NODE_EVAC_SEC,
903 self.assertEqual(result, "21533")
904 self.assertItems(["node-3"])
905 self.assertQuery("iallocator", ["hail"])
906 self.assertQuery("early_release", ["1"])
907 self.assertFalse(self.rapi.GetLastRequestData())
909 self.assertEqual(self.rapi.CountPending(), 0)
911 def testMigrateNode(self):
912 self.rapi.AddResponse(serializer.DumpJson([]))
913 self.rapi.AddResponse("1111")
914 self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
915 self.assertHandler(rlib2.R_2_nodes_name_migrate)
916 self.assertItems(["node-a"])
917 self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
919 self.assertFalse(self.rapi.GetLastRequestData())
921 self.rapi.AddResponse(serializer.DumpJson([]))
922 self.rapi.AddResponse("1112")
923 self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
925 self.assertHandler(rlib2.R_2_nodes_name_migrate)
926 self.assertItems(["node-a"])
927 self.assertQuery("mode", ["live"])
929 self.assertFalse(self.rapi.GetLastRequestData())
931 self.rapi.AddResponse(serializer.DumpJson([]))
932 self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
933 "node-c", target_node="foonode")
934 self.assertEqual(self.rapi.CountPending(), 0)
936 def testMigrateNodeBodyData(self):
937 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
938 self.rapi.AddResponse("27539")
939 self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
941 self.assertHandler(rlib2.R_2_nodes_name_migrate)
942 self.assertItems(["node-a"])
943 self.assertFalse(self.rapi.GetLastHandler().queryargs)
944 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
947 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
948 self.rapi.AddResponse("14219")
949 self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
952 self.assertHandler(rlib2.R_2_nodes_name_migrate)
953 self.assertItems(["node-x"])
955 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
956 { "target_node": "node9", "iallocator": "ial", })
958 self.assertEqual(self.rapi.CountPending(), 0)
960 def testGetNodeRole(self):
961 self.rapi.AddResponse("\"master\"")
962 self.assertEqual("master", self.client.GetNodeRole("node-a"))
963 self.assertHandler(rlib2.R_2_nodes_name_role)
964 self.assertItems(["node-a"])
966 def testSetNodeRole(self):
967 self.rapi.AddResponse("789")
968 self.assertEqual(789,
969 self.client.SetNodeRole("node-foo", "master-candidate", force=True))
970 self.assertHandler(rlib2.R_2_nodes_name_role)
971 self.assertItems(["node-foo"])
972 self.assertQuery("force", ["1"])
973 self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
975 def testModifyNode(self):
976 self.rapi.AddResponse("3783")
977 job_id = self.client.ModifyNode("node16979.example.com", drained=True)
978 self.assertEqual(job_id, 3783)
979 self.assertHandler(rlib2.R_2_nodes_name_modify)
980 self.assertItems(["node16979.example.com"])
981 self.assertEqual(self.rapi.CountPending(), 0)
983 def testGetNodeStorageUnits(self):
984 self.rapi.AddResponse("42")
986 self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
987 self.assertHandler(rlib2.R_2_nodes_name_storage)
988 self.assertItems(["node-x"])
989 self.assertQuery("storage_type", ["lvm-pv"])
990 self.assertQuery("output_fields", ["fields"])
992 def testModifyNodeStorageUnits(self):
993 self.rapi.AddResponse("14")
995 self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
996 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
997 self.assertItems(["node-z"])
998 self.assertQuery("storage_type", ["lvm-pv"])
999 self.assertQuery("name", ["hda"])
1000 self.assertQuery("allocatable", None)
1002 for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
1003 self.rapi.AddResponse("7205")
1004 job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
1005 allocatable=allocatable)
1006 self.assertEqual(7205, job_id)
1007 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1008 self.assertItems(["node-z"])
1009 self.assertQuery("storage_type", ["lvm-pv"])
1010 self.assertQuery("name", ["hda"])
1011 self.assertQuery("allocatable", [query_allocatable])
1013 def testRepairNodeStorageUnits(self):
1014 self.rapi.AddResponse("99")
1015 self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
1017 self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
1018 self.assertItems(["node-z"])
1019 self.assertQuery("storage_type", ["lvm-pv"])
1020 self.assertQuery("name", ["hda"])
1022 def testGetNodeTags(self):
1023 self.rapi.AddResponse("[\"fry\", \"bender\"]")
1024 self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
1025 self.assertHandler(rlib2.R_2_nodes_name_tags)
1026 self.assertItems(["node-k"])
1028 def testAddNodeTags(self):
1029 self.rapi.AddResponse("1234")
1030 self.assertEqual(1234,
1031 self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
1032 self.assertHandler(rlib2.R_2_nodes_name_tags)
1033 self.assertItems(["node-v"])
1035 self.assertQuery("tag", ["awesome"])
1037 def testDeleteNodeTags(self):
1038 self.rapi.AddResponse("16861")
1039 self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1041 self.assertHandler(rlib2.R_2_nodes_name_tags)
1042 self.assertItems(["node-w"])
1044 self.assertQuery("tag", ["awesome"])
1046 def testGetGroups(self):
1047 groups = [{"name": "group1",
1048 "uri": "/2/groups/group1",
1051 "uri": "/2/groups/group2",
1054 self.rapi.AddResponse(serializer.DumpJson(groups))
1055 self.assertEqual(["group1", "group2"], self.client.GetGroups())
1056 self.assertHandler(rlib2.R_2_groups)
1058 def testGetGroupsBulk(self):
1059 groups = [{"name": "group1",
1060 "uri": "/2/groups/group1",
1062 "node_list": ["gnt1.test",
1067 "uri": "/2/groups/group2",
1069 "node_list": ["gnt3.test",
1073 self.rapi.AddResponse(serializer.DumpJson(groups))
1075 self.assertEqual(groups, self.client.GetGroups(bulk=True))
1076 self.assertHandler(rlib2.R_2_groups)
1079 def testGetGroup(self):
1080 group = {"ctime": None,
1083 self.rapi.AddResponse(serializer.DumpJson(group))
1084 self.assertEqual({"ctime": None, "name": "default"},
1085 self.client.GetGroup("default"))
1086 self.assertHandler(rlib2.R_2_groups_name)
1087 self.assertItems(["default"])
1089 def testCreateGroup(self):
1090 self.rapi.AddResponse("12345")
1091 job_id = self.client.CreateGroup("newgroup", dry_run=True)
1092 self.assertEqual(job_id, 12345)
1093 self.assertHandler(rlib2.R_2_groups)
1096 def testDeleteGroup(self):
1097 self.rapi.AddResponse("12346")
1098 job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1099 self.assertEqual(job_id, 12346)
1100 self.assertHandler(rlib2.R_2_groups_name)
1103 def testRenameGroup(self):
1104 self.rapi.AddResponse("12347")
1105 job_id = self.client.RenameGroup("oldname", "newname")
1106 self.assertEqual(job_id, 12347)
1107 self.assertHandler(rlib2.R_2_groups_name_rename)
1109 def testModifyGroup(self):
1110 self.rapi.AddResponse("12348")
1111 job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1112 self.assertEqual(job_id, 12348)
1113 self.assertHandler(rlib2.R_2_groups_name_modify)
1115 def testAssignGroupNodes(self):
1116 self.rapi.AddResponse("12349")
1117 job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1118 force=True, dry_run=True)
1119 self.assertEqual(job_id, 12349)
1120 self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1122 self.assertUseForce()
1124 def testModifyInstance(self):
1125 self.rapi.AddResponse("23681")
1126 job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1127 self.assertEqual(job_id, 23681)
1128 self.assertItems(["inst7210"])
1129 self.assertHandler(rlib2.R_2_instances_name_modify)
1130 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1131 { "os_name": "linux", })
1133 def testModifyCluster(self):
1134 for mnh in [None, False, True]:
1135 self.rapi.AddResponse("14470")
1136 self.assertEqual(14470,
1137 self.client.ModifyCluster(maintain_node_health=mnh))
1138 self.assertHandler(rlib2.R_2_cluster_modify)
1139 self.assertItems([])
1140 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1141 self.assertEqual(len(data), 1)
1142 self.assertEqual(data["maintain_node_health"], mnh)
1143 self.assertEqual(self.rapi.CountPending(), 0)
1145 def testRedistributeConfig(self):
1146 self.rapi.AddResponse("3364")
1147 job_id = self.client.RedistributeConfig()
1148 self.assertEqual(job_id, 3364)
1149 self.assertItems([])
1150 self.assertHandler(rlib2.R_2_redist_config)
1152 def testActivateInstanceDisks(self):
1153 self.rapi.AddResponse("23547")
1154 job_id = self.client.ActivateInstanceDisks("inst28204")
1155 self.assertEqual(job_id, 23547)
1156 self.assertItems(["inst28204"])
1157 self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1158 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1160 def testActivateInstanceDisksIgnoreSize(self):
1161 self.rapi.AddResponse("11044")
1162 job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1163 self.assertEqual(job_id, 11044)
1164 self.assertItems(["inst28204"])
1165 self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1166 self.assertQuery("ignore_size", ["1"])
1168 def testDeactivateInstanceDisks(self):
1169 self.rapi.AddResponse("14591")
1170 job_id = self.client.DeactivateInstanceDisks("inst28234")
1171 self.assertEqual(job_id, 14591)
1172 self.assertItems(["inst28234"])
1173 self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1174 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1176 def testGetInstanceConsole(self):
1177 self.rapi.AddResponse("26876")
1178 job_id = self.client.GetInstanceConsole("inst21491")
1179 self.assertEqual(job_id, 26876)
1180 self.assertItems(["inst21491"])
1181 self.assertHandler(rlib2.R_2_instances_name_console)
1182 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1183 self.assertFalse(self.rapi.GetLastRequestData())
1185 def testGrowInstanceDisk(self):
1186 for idx, wait_for_sync in enumerate([None, False, True]):
1187 amount = 128 + (512 * idx)
1188 self.assertEqual(self.rapi.CountPending(), 0)
1189 self.rapi.AddResponse("30783")
1190 self.assertEqual(30783,
1191 self.client.GrowInstanceDisk("eze8ch", idx, amount,
1192 wait_for_sync=wait_for_sync))
1193 self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1194 self.assertItems(["eze8ch", str(idx)])
1195 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1196 if wait_for_sync is None:
1197 self.assertEqual(len(data), 1)
1198 self.assert_("wait_for_sync" not in data)
1200 self.assertEqual(len(data), 2)
1201 self.assertEqual(data["wait_for_sync"], wait_for_sync)
1202 self.assertEqual(data["amount"], amount)
1203 self.assertEqual(self.rapi.CountPending(), 0)
1205 def testGetGroupTags(self):
1206 self.rapi.AddResponse("[]")
1207 self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1208 self.assertHandler(rlib2.R_2_groups_name_tags)
1209 self.assertItems(["fooGroup"])
1211 def testAddGroupTags(self):
1212 self.rapi.AddResponse("1234")
1213 self.assertEqual(1234,
1214 self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1215 self.assertHandler(rlib2.R_2_groups_name_tags)
1216 self.assertItems(["fooGroup"])
1218 self.assertQuery("tag", ["awesome"])
1220 def testDeleteGroupTags(self):
1221 self.rapi.AddResponse("25826")
1222 self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1224 self.assertHandler(rlib2.R_2_groups_name_tags)
1225 self.assertItems(["foo"])
1227 self.assertQuery("tag", ["awesome"])
1229 def testQuery(self):
1230 for idx, what in enumerate(constants.QR_VIA_RAPI):
1231 for idx2, filter_ in enumerate([None, ["?", "name"]]):
1232 job_id = 11010 + (idx << 4) + (idx2 << 16)
1233 fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1235 self.rapi.AddResponse(str(job_id))
1236 self.assertEqual(self.client.Query(what, fields, filter_=filter_),
1238 self.assertItems([what])
1239 self.assertHandler(rlib2.R_2_query)
1240 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1241 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1242 self.assertEqual(data["fields"], fields)
1244 self.assertTrue("filter" not in data)
1246 self.assertEqual(data["filter"], filter_)
1247 self.assertEqual(self.rapi.CountPending(), 0)
1249 def testQueryFields(self):
1250 exp_result = objects.QueryFieldsResponse(fields=[
1251 objects.QueryFieldDefinition(name="pnode", title="PNode",
1252 kind=constants.QFT_NUMBER),
1253 objects.QueryFieldDefinition(name="other", title="Other",
1254 kind=constants.QFT_BOOL),
1257 for what in constants.QR_VIA_RAPI:
1258 for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1259 self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1260 result = self.client.QueryFields(what, fields=fields)
1261 self.assertItems([what])
1262 self.assertHandler(rlib2.R_2_query_fields)
1263 self.assertFalse(self.rapi.GetLastRequestData())
1265 queryargs = self.rapi.GetLastHandler().queryargs
1267 self.assertFalse(queryargs)
1269 self.assertEqual(queryargs, {
1270 "fields": [",".join(fields)],
1273 self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1274 exp_result.ToDict())
1276 self.assertEqual(self.rapi.CountPending(), 0)
1278 def testWaitForJobCompletionNoChange(self):
1279 resp = serializer.DumpJson({
1280 "status": constants.JOB_STATUS_WAITING,
1283 for retries in [1, 5, 25]:
1284 for _ in range(retries):
1285 self.rapi.AddResponse(resp)
1287 self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1289 self.assertHandler(rlib2.R_2_jobs_id)
1290 self.assertItems(["22789"])
1292 self.assertEqual(self.rapi.CountPending(), 0)
1294 def testWaitForJobCompletionAlreadyFinished(self):
1295 self.rapi.AddResponse(serializer.DumpJson({
1296 "status": constants.JOB_STATUS_SUCCESS,
1299 self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1301 self.assertHandler(rlib2.R_2_jobs_id)
1302 self.assertItems(["22793"])
1304 self.assertEqual(self.rapi.CountPending(), 0)
1306 def testWaitForJobCompletionEmptyResponse(self):
1307 self.rapi.AddResponse("{}")
1308 self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1310 self.assertHandler(rlib2.R_2_jobs_id)
1311 self.assertItems(["22793"])
1313 self.assertEqual(self.rapi.CountPending(), 0)
1315 def testWaitForJobCompletionOutOfRetries(self):
1316 for retries in [3, 10, 21]:
1317 for _ in range(retries):
1318 self.rapi.AddResponse(serializer.DumpJson({
1319 "status": constants.JOB_STATUS_RUNNING,
1322 self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1323 retries=retries - 1))
1324 self.assertHandler(rlib2.R_2_jobs_id)
1325 self.assertItems(["30948"])
1327 self.assertEqual(self.rapi.CountPending(), 1)
1328 self.rapi.ResetResponses()
1330 def testWaitForJobCompletionSuccessAndFailure(self):
1331 for retries in [1, 4, 13]:
1332 for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1333 (True, constants.JOB_STATUS_SUCCESS)]:
1334 for _ in range(retries):
1335 self.rapi.AddResponse(serializer.DumpJson({
1336 "status": constants.JOB_STATUS_RUNNING,
1339 self.rapi.AddResponse(serializer.DumpJson({
1340 "status": end_status,
1343 result = self.client.WaitForJobCompletion(3187, period=None,
1344 retries=retries + 1)
1345 self.assertEqual(result, success)
1346 self.assertHandler(rlib2.R_2_jobs_id)
1347 self.assertItems(["3187"])
1349 self.assertEqual(self.rapi.CountPending(), 0)
1352 class RapiTestRunner(unittest.TextTestRunner):
1353 def run(self, *args):
1354 global _used_handlers
1355 assert _used_handlers is None
1357 _used_handlers = set()
1360 result = unittest.TextTestRunner.run(self, *args)
1362 diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1365 raise AssertionError("The following RAPI resources were not used by the"
1366 " RAPI client: %r" % utils.CommaJoin(diff))
1368 # Reset global variable
1369 _used_handlers = None
1374 if __name__ == '__main__':
1375 client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)