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.JOB_STATUS_WAITLOCK, constants.JOB_STATUS_WAITING)
172 class RapiMockTest(unittest.TestCase):
176 self.assertEqual((404, None), rapi.FetchResponse("/foo", "GET", None))
177 self.assertEqual((501, "Method not implemented"),
178 rapi.FetchResponse("/version", "POST", None))
179 rapi.AddResponse("2")
180 code, response = rapi.FetchResponse("/version", "GET", None)
181 self.assertEqual(200, code)
182 self.assertEqual("2", response)
183 self.failUnless(isinstance(rapi.GetLastHandler(), rlib2.R_version))
186 def _FakeNoSslPycurlVersion():
187 # Note: incomplete version tuple
188 return (3, "7.16.0", 462848, "mysystem", 1581, None, 0)
191 def _FakeFancySslPycurlVersion():
192 # Note: incomplete version tuple
193 return (3, "7.16.0", 462848, "mysystem", 1581, "FancySSL/1.2.3", 0)
196 def _FakeOpenSslPycurlVersion():
197 # Note: incomplete version tuple
198 return (2, "7.15.5", 462597, "othersystem", 668, "OpenSSL/0.9.8c", 0)
201 def _FakeGnuTlsPycurlVersion():
202 # Note: incomplete version tuple
203 return (3, "7.18.0", 463360, "somesystem", 1581, "GnuTLS/2.0.4", 0)
206 class TestExtendedConfig(unittest.TestCase):
208 cl = client.GanetiRapiClient("master.example.com",
209 username="user", password="pw",
210 curl_factory=lambda: FakeCurl(RapiMock()))
212 curl = cl._CreateCurl()
213 self.assertEqual(curl.getopt(pycurl.HTTPAUTH), pycurl.HTTPAUTH_BASIC)
214 self.assertEqual(curl.getopt(pycurl.USERPWD), "user:pw")
216 def testInvalidAuth(self):
218 self.assertRaises(client.Error, client.GanetiRapiClient,
219 "master-a.example.com", password="pw")
221 self.assertRaises(client.Error, client.GanetiRapiClient,
222 "master-b.example.com", username="user")
224 def testCertVerifyInvalidCombinations(self):
225 self.assertRaises(client.Error, client.GenericCurlConfig,
226 use_curl_cabundle=True, cafile="cert1.pem")
227 self.assertRaises(client.Error, client.GenericCurlConfig,
228 use_curl_cabundle=True, capath="certs/")
229 self.assertRaises(client.Error, client.GenericCurlConfig,
230 use_curl_cabundle=True,
231 cafile="cert1.pem", capath="certs/")
233 def testProxySignalVerifyHostname(self):
234 for use_gnutls in [False, True]:
236 pcverfn = _FakeGnuTlsPycurlVersion
238 pcverfn = _FakeOpenSslPycurlVersion
240 for proxy in ["", "http://127.0.0.1:1234"]:
241 for use_signal in [False, True]:
242 for verify_hostname in [False, True]:
243 cfgfn = client.GenericCurlConfig(proxy=proxy, use_signal=use_signal,
244 verify_hostname=verify_hostname,
245 _pycurl_version_fn=pcverfn)
247 curl_factory = lambda: FakeCurl(RapiMock())
248 cl = client.GanetiRapiClient("master.example.com",
249 curl_config_fn=cfgfn,
250 curl_factory=curl_factory)
252 curl = cl._CreateCurl()
253 self.assertEqual(curl.getopt(pycurl.PROXY), proxy)
254 self.assertEqual(curl.getopt(pycurl.NOSIGNAL), not use_signal)
257 self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 2)
259 self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 0)
261 def testNoCertVerify(self):
262 cfgfn = client.GenericCurlConfig()
264 curl_factory = lambda: FakeCurl(RapiMock())
265 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
266 curl_factory=curl_factory)
268 curl = cl._CreateCurl()
269 self.assertFalse(curl.getopt(pycurl.SSL_VERIFYPEER))
270 self.assertFalse(curl.getopt(pycurl.CAINFO))
271 self.assertFalse(curl.getopt(pycurl.CAPATH))
273 def testCertVerifyCurlBundle(self):
274 cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
276 curl_factory = lambda: FakeCurl(RapiMock())
277 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
278 curl_factory=curl_factory)
280 curl = cl._CreateCurl()
281 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
282 self.assertFalse(curl.getopt(pycurl.CAINFO))
283 self.assertFalse(curl.getopt(pycurl.CAPATH))
285 def testCertVerifyCafile(self):
286 mycert = "/tmp/some/UNUSED/cert/file.pem"
287 cfgfn = client.GenericCurlConfig(cafile=mycert)
289 curl_factory = lambda: FakeCurl(RapiMock())
290 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
291 curl_factory=curl_factory)
293 curl = cl._CreateCurl()
294 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
295 self.assertEqual(curl.getopt(pycurl.CAINFO), mycert)
296 self.assertFalse(curl.getopt(pycurl.CAPATH))
298 def testCertVerifyCapath(self):
299 certdir = "/tmp/some/UNUSED/cert/directory"
300 pcverfn = _FakeOpenSslPycurlVersion
301 cfgfn = client.GenericCurlConfig(capath=certdir,
302 _pycurl_version_fn=pcverfn)
304 curl_factory = lambda: FakeCurl(RapiMock())
305 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
306 curl_factory=curl_factory)
308 curl = cl._CreateCurl()
309 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
310 self.assertEqual(curl.getopt(pycurl.CAPATH), certdir)
311 self.assertFalse(curl.getopt(pycurl.CAINFO))
313 def testCertVerifyCapathGnuTls(self):
314 certdir = "/tmp/some/UNUSED/cert/directory"
315 pcverfn = _FakeGnuTlsPycurlVersion
316 cfgfn = client.GenericCurlConfig(capath=certdir,
317 _pycurl_version_fn=pcverfn)
319 curl_factory = lambda: FakeCurl(RapiMock())
320 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
321 curl_factory=curl_factory)
323 self.assertRaises(client.Error, cl._CreateCurl)
325 def testCertVerifyNoSsl(self):
326 certdir = "/tmp/some/UNUSED/cert/directory"
327 pcverfn = _FakeNoSslPycurlVersion
328 cfgfn = client.GenericCurlConfig(capath=certdir,
329 _pycurl_version_fn=pcverfn)
331 curl_factory = lambda: FakeCurl(RapiMock())
332 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
333 curl_factory=curl_factory)
335 self.assertRaises(client.Error, cl._CreateCurl)
337 def testCertVerifyFancySsl(self):
338 certdir = "/tmp/some/UNUSED/cert/directory"
339 pcverfn = _FakeFancySslPycurlVersion
340 cfgfn = client.GenericCurlConfig(capath=certdir,
341 _pycurl_version_fn=pcverfn)
343 curl_factory = lambda: FakeCurl(RapiMock())
344 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
345 curl_factory=curl_factory)
347 self.assertRaises(NotImplementedError, cl._CreateCurl)
349 def testCertVerifyCapath(self):
350 for connect_timeout in [None, 1, 5, 10, 30, 60, 300]:
351 for timeout in [None, 1, 30, 60, 3600, 24 * 3600]:
352 cfgfn = client.GenericCurlConfig(connect_timeout=connect_timeout,
355 curl_factory = lambda: FakeCurl(RapiMock())
356 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
357 curl_factory=curl_factory)
359 curl = cl._CreateCurl()
360 self.assertEqual(curl.getopt(pycurl.CONNECTTIMEOUT), connect_timeout)
361 self.assertEqual(curl.getopt(pycurl.TIMEOUT), timeout)
364 class GanetiRapiClientTests(testutils.GanetiTestCase):
366 testutils.GanetiTestCase.setUp(self)
368 self.rapi = RapiMock()
369 self.curl = FakeCurl(self.rapi)
370 self.client = client.GanetiRapiClient("master.example.com",
371 curl_factory=lambda: self.curl)
373 def assertHandler(self, handler_cls):
374 self.failUnless(isinstance(self.rapi.GetLastHandler(), handler_cls))
376 def assertQuery(self, key, value):
377 self.assertEqual(value, self.rapi.GetLastHandler().queryargs.get(key, None))
379 def assertItems(self, items):
380 self.assertEqual(items, self.rapi.GetLastHandler().items)
382 def assertBulk(self):
383 self.assertTrue(self.rapi.GetLastHandler().useBulk())
385 def assertDryRun(self):
386 self.assertTrue(self.rapi.GetLastHandler().dryRun())
388 def assertUseForce(self):
389 self.assertTrue(self.rapi.GetLastHandler().useForce())
391 def testEncodeQuery(self):
408 self.assertEqualValues(self.client._EncodeQuery(query),
412 for i in [[1, 2, 3], {"moo": "boo"}, (1, 2, 3)]:
413 self.assertRaises(ValueError, self.client._EncodeQuery, [("x", i)])
415 def testCurlSettings(self):
416 self.rapi.AddResponse("2")
417 self.assertEqual(2, self.client.GetVersion())
418 self.assertHandler(rlib2.R_version)
420 # Signals should be disabled by default
421 self.assert_(self.curl.getopt(pycurl.NOSIGNAL))
423 # No auth and no proxy
424 self.assertFalse(self.curl.getopt(pycurl.USERPWD))
425 self.assert_(self.curl.getopt(pycurl.PROXY) is None)
427 # Content-type is required for requests
428 headers = self.curl.getopt(pycurl.HTTPHEADER)
429 self.assert_("Content-type: application/json" in headers)
431 def testHttpError(self):
432 self.rapi.AddResponse(None, code=404)
434 self.client.GetJobStatus(15140)
435 except client.GanetiApiError, err:
436 self.assertEqual(err.code, 404)
438 self.fail("Didn't raise exception")
440 def testGetVersion(self):
441 self.rapi.AddResponse("2")
442 self.assertEqual(2, self.client.GetVersion())
443 self.assertHandler(rlib2.R_version)
445 def testGetFeatures(self):
446 for features in [[], ["foo", "bar", "baz"]]:
447 self.rapi.AddResponse(serializer.DumpJson(features))
448 self.assertEqual(features, self.client.GetFeatures())
449 self.assertHandler(rlib2.R_2_features)
451 def testGetFeaturesNotFound(self):
452 self.rapi.AddResponse(None, code=404)
453 self.assertEqual([], self.client.GetFeatures())
455 def testGetOperatingSystems(self):
456 self.rapi.AddResponse("[\"beos\"]")
457 self.assertEqual(["beos"], self.client.GetOperatingSystems())
458 self.assertHandler(rlib2.R_2_os)
460 def testGetClusterTags(self):
461 self.rapi.AddResponse("[\"tag\"]")
462 self.assertEqual(["tag"], self.client.GetClusterTags())
463 self.assertHandler(rlib2.R_2_tags)
465 def testAddClusterTags(self):
466 self.rapi.AddResponse("1234")
467 self.assertEqual(1234,
468 self.client.AddClusterTags(["awesome"], dry_run=True))
469 self.assertHandler(rlib2.R_2_tags)
471 self.assertQuery("tag", ["awesome"])
473 def testDeleteClusterTags(self):
474 self.rapi.AddResponse("5107")
475 self.assertEqual(5107, self.client.DeleteClusterTags(["awesome"],
477 self.assertHandler(rlib2.R_2_tags)
479 self.assertQuery("tag", ["awesome"])
481 def testGetInfo(self):
482 self.rapi.AddResponse("{}")
483 self.assertEqual({}, self.client.GetInfo())
484 self.assertHandler(rlib2.R_2_info)
486 def testGetInstances(self):
487 self.rapi.AddResponse("[]")
488 self.assertEqual([], self.client.GetInstances(bulk=True))
489 self.assertHandler(rlib2.R_2_instances)
492 def testGetInstance(self):
493 self.rapi.AddResponse("[]")
494 self.assertEqual([], self.client.GetInstance("instance"))
495 self.assertHandler(rlib2.R_2_instances_name)
496 self.assertItems(["instance"])
498 def testGetInstanceInfo(self):
499 self.rapi.AddResponse("21291")
500 self.assertEqual(21291, self.client.GetInstanceInfo("inst3"))
501 self.assertHandler(rlib2.R_2_instances_name_info)
502 self.assertItems(["inst3"])
503 self.assertQuery("static", None)
505 self.rapi.AddResponse("3428")
506 self.assertEqual(3428, self.client.GetInstanceInfo("inst31", static=False))
507 self.assertHandler(rlib2.R_2_instances_name_info)
508 self.assertItems(["inst31"])
509 self.assertQuery("static", ["0"])
511 self.rapi.AddResponse("15665")
512 self.assertEqual(15665, self.client.GetInstanceInfo("inst32", static=True))
513 self.assertHandler(rlib2.R_2_instances_name_info)
514 self.assertItems(["inst32"])
515 self.assertQuery("static", ["1"])
517 def testCreateInstanceOldVersion(self):
518 # The old request format, version 0, is no longer supported
519 self.rapi.AddResponse(None, code=404)
520 self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
521 "create", "inst1.example.com", "plain", [], [])
522 self.assertEqual(self.rapi.CountPending(), 0)
524 def testCreateInstance(self):
525 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
526 self.rapi.AddResponse("23030")
527 job_id = self.client.CreateInstance("create", "inst1.example.com",
528 "plain", [], [], dry_run=True)
529 self.assertEqual(job_id, 23030)
530 self.assertHandler(rlib2.R_2_instances)
533 data = serializer.LoadJson(self.rapi.GetLastRequestData())
535 for field in ["dry_run", "beparams", "hvparams", "start"]:
536 self.assertFalse(field in data)
538 self.assertEqual(data["name"], "inst1.example.com")
539 self.assertEqual(data["disk_template"], "plain")
541 def testCreateInstance2(self):
542 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
543 self.rapi.AddResponse("24740")
544 job_id = self.client.CreateInstance("import", "inst2.example.com",
545 "drbd8", [{"size": 100,}],
546 [{}, {"bridge": "br1", }],
547 dry_run=False, start=True,
548 pnode="node1", snode="node9",
550 self.assertEqual(job_id, 24740)
551 self.assertHandler(rlib2.R_2_instances)
553 data = serializer.LoadJson(self.rapi.GetLastRequestData())
554 self.assertEqual(data[rlib2._REQ_DATA_VERSION], 1)
555 self.assertEqual(data["name"], "inst2.example.com")
556 self.assertEqual(data["disk_template"], "drbd8")
557 self.assertEqual(data["start"], True)
558 self.assertEqual(data["ip_check"], False)
559 self.assertEqualValues(data["disks"], [{"size": 100,}])
560 self.assertEqualValues(data["nics"], [{}, {"bridge": "br1", }])
562 def testDeleteInstance(self):
563 self.rapi.AddResponse("1234")
564 self.assertEqual(1234, self.client.DeleteInstance("instance", dry_run=True))
565 self.assertHandler(rlib2.R_2_instances_name)
566 self.assertItems(["instance"])
569 def testGetInstanceTags(self):
570 self.rapi.AddResponse("[]")
571 self.assertEqual([], self.client.GetInstanceTags("fooinstance"))
572 self.assertHandler(rlib2.R_2_instances_name_tags)
573 self.assertItems(["fooinstance"])
575 def testAddInstanceTags(self):
576 self.rapi.AddResponse("1234")
577 self.assertEqual(1234,
578 self.client.AddInstanceTags("fooinstance", ["awesome"], dry_run=True))
579 self.assertHandler(rlib2.R_2_instances_name_tags)
580 self.assertItems(["fooinstance"])
582 self.assertQuery("tag", ["awesome"])
584 def testDeleteInstanceTags(self):
585 self.rapi.AddResponse("25826")
586 self.assertEqual(25826, self.client.DeleteInstanceTags("foo", ["awesome"],
588 self.assertHandler(rlib2.R_2_instances_name_tags)
589 self.assertItems(["foo"])
591 self.assertQuery("tag", ["awesome"])
593 def testRebootInstance(self):
594 self.rapi.AddResponse("6146")
595 job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
596 ignore_secondaries=True, dry_run=True)
597 self.assertEqual(6146, job_id)
598 self.assertHandler(rlib2.R_2_instances_name_reboot)
599 self.assertItems(["i-bar"])
601 self.assertQuery("type", ["hard"])
602 self.assertQuery("ignore_secondaries", ["1"])
604 def testShutdownInstance(self):
605 self.rapi.AddResponse("1487")
606 self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
608 self.assertHandler(rlib2.R_2_instances_name_shutdown)
609 self.assertItems(["foo-instance"])
612 def testStartupInstance(self):
613 self.rapi.AddResponse("27149")
614 self.assertEqual(27149, self.client.StartupInstance("bar-instance",
616 self.assertHandler(rlib2.R_2_instances_name_startup)
617 self.assertItems(["bar-instance"])
620 def testReinstallInstance(self):
621 self.rapi.AddResponse(serializer.DumpJson([]))
622 self.rapi.AddResponse("19119")
623 self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
626 self.assertHandler(rlib2.R_2_instances_name_reinstall)
627 self.assertItems(["baz-instance"])
628 self.assertQuery("os", ["DOS"])
629 self.assertQuery("nostartup", ["1"])
630 self.assertEqual(self.rapi.CountPending(), 0)
632 def testReinstallInstanceNew(self):
633 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
634 self.rapi.AddResponse("25689")
635 self.assertEqual(25689, self.client.ReinstallInstance("moo-instance",
638 self.assertHandler(rlib2.R_2_instances_name_reinstall)
639 self.assertItems(["moo-instance"])
640 data = serializer.LoadJson(self.rapi.GetLastRequestData())
641 self.assertEqual(len(data), 2)
642 self.assertEqual(data["os"], "Debian")
643 self.assertEqual(data["start"], False)
644 self.assertEqual(self.rapi.CountPending(), 0)
646 def testReinstallInstanceWithOsparams1(self):
647 self.rapi.AddResponse(serializer.DumpJson([]))
648 self.assertRaises(client.GanetiApiError, self.client.ReinstallInstance,
649 "doo-instance", osparams={"x": "y"})
650 self.assertEqual(self.rapi.CountPending(), 0)
652 def testReinstallInstanceWithOsparams2(self):
657 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
658 self.rapi.AddResponse("1717")
659 self.assertEqual(1717, self.client.ReinstallInstance("zoo-instance",
661 self.assertHandler(rlib2.R_2_instances_name_reinstall)
662 self.assertItems(["zoo-instance"])
663 data = serializer.LoadJson(self.rapi.GetLastRequestData())
664 self.assertEqual(len(data), 2)
665 self.assertEqual(data["osparams"], osparams)
666 self.assertEqual(data["start"], True)
667 self.assertEqual(self.rapi.CountPending(), 0)
669 def testReplaceInstanceDisks(self):
670 self.rapi.AddResponse("999")
671 job_id = self.client.ReplaceInstanceDisks("instance-name",
672 disks=[0, 1], dry_run=True, iallocator="hail")
673 self.assertEqual(999, job_id)
674 self.assertHandler(rlib2.R_2_instances_name_replace_disks)
675 self.assertItems(["instance-name"])
676 self.assertQuery("disks", ["0,1"])
677 self.assertQuery("mode", ["replace_auto"])
678 self.assertQuery("iallocator", ["hail"])
681 self.rapi.AddResponse("1000")
682 job_id = self.client.ReplaceInstanceDisks("instance-bar",
683 disks=[1], mode="replace_on_secondary", remote_node="foo-node",
685 self.assertEqual(1000, job_id)
686 self.assertItems(["instance-bar"])
687 self.assertQuery("disks", ["1"])
688 self.assertQuery("remote_node", ["foo-node"])
691 self.rapi.AddResponse("5175")
692 self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
693 self.assertItems(["instance-moo"])
694 self.assertQuery("disks", None)
696 def testPrepareExport(self):
697 self.rapi.AddResponse("8326")
698 self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
699 self.assertHandler(rlib2.R_2_instances_name_prepare_export)
700 self.assertItems(["inst1"])
701 self.assertQuery("mode", ["local"])
703 def testExportInstance(self):
704 self.rapi.AddResponse("19695")
705 job_id = self.client.ExportInstance("inst2", "local", "nodeX",
707 self.assertEqual(job_id, 19695)
708 self.assertHandler(rlib2.R_2_instances_name_export)
709 self.assertItems(["inst2"])
711 data = serializer.LoadJson(self.rapi.GetLastRequestData())
712 self.assertEqual(data["mode"], "local")
713 self.assertEqual(data["destination"], "nodeX")
714 self.assertEqual(data["shutdown"], True)
716 def testMigrateInstanceDefaults(self):
717 self.rapi.AddResponse("24873")
718 job_id = self.client.MigrateInstance("inst91")
719 self.assertEqual(job_id, 24873)
720 self.assertHandler(rlib2.R_2_instances_name_migrate)
721 self.assertItems(["inst91"])
723 data = serializer.LoadJson(self.rapi.GetLastRequestData())
724 self.assertFalse(data)
726 def testMigrateInstance(self):
727 for mode in constants.HT_MIGRATION_MODES:
728 for cleanup in [False, True]:
729 self.rapi.AddResponse("31910")
730 job_id = self.client.MigrateInstance("inst289", mode=mode,
732 self.assertEqual(job_id, 31910)
733 self.assertHandler(rlib2.R_2_instances_name_migrate)
734 self.assertItems(["inst289"])
736 data = serializer.LoadJson(self.rapi.GetLastRequestData())
737 self.assertEqual(len(data), 2)
738 self.assertEqual(data["mode"], mode)
739 self.assertEqual(data["cleanup"], cleanup)
741 def testFailoverInstanceDefaults(self):
742 self.rapi.AddResponse("7639")
743 job_id = self.client.FailoverInstance("inst13579")
744 self.assertEqual(job_id, 7639)
745 self.assertHandler(rlib2.R_2_instances_name_failover)
746 self.assertItems(["inst13579"])
748 data = serializer.LoadJson(self.rapi.GetLastRequestData())
749 self.assertFalse(data)
751 def testFailoverInstance(self):
752 for iallocator in ["dumb", "hail"]:
753 for ignore_consistency in [False, True]:
754 for target_node in ["node-a", "node2"]:
755 self.rapi.AddResponse("19161")
757 self.client.FailoverInstance("inst251", iallocator=iallocator,
758 ignore_consistency=ignore_consistency,
759 target_node=target_node)
760 self.assertEqual(job_id, 19161)
761 self.assertHandler(rlib2.R_2_instances_name_failover)
762 self.assertItems(["inst251"])
764 data = serializer.LoadJson(self.rapi.GetLastRequestData())
765 self.assertEqual(len(data), 3)
766 self.assertEqual(data["iallocator"], iallocator)
767 self.assertEqual(data["ignore_consistency"], ignore_consistency)
768 self.assertEqual(data["target_node"], target_node)
769 self.assertEqual(self.rapi.CountPending(), 0)
771 def testRenameInstanceDefaults(self):
772 new_name = "newnametha7euqu"
773 self.rapi.AddResponse("8791")
774 job_id = self.client.RenameInstance("inst18821", new_name)
775 self.assertEqual(job_id, 8791)
776 self.assertHandler(rlib2.R_2_instances_name_rename)
777 self.assertItems(["inst18821"])
779 data = serializer.LoadJson(self.rapi.GetLastRequestData())
780 self.assertEqualValues(data, {"new_name": new_name, })
782 def testRenameInstance(self):
783 new_name = "new-name-yiux1iin"
784 for ip_check in [False, True]:
785 for name_check in [False, True]:
786 self.rapi.AddResponse("24776")
787 job_id = self.client.RenameInstance("inst20967", new_name,
789 name_check=name_check)
790 self.assertEqual(job_id, 24776)
791 self.assertHandler(rlib2.R_2_instances_name_rename)
792 self.assertItems(["inst20967"])
794 data = serializer.LoadJson(self.rapi.GetLastRequestData())
795 self.assertEqual(len(data), 3)
796 self.assertEqual(data["new_name"], new_name)
797 self.assertEqual(data["ip_check"], ip_check)
798 self.assertEqual(data["name_check"], name_check)
800 def testGetJobs(self):
801 self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
802 ' { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
803 self.assertEqual([123, 124], self.client.GetJobs())
804 self.assertHandler(rlib2.R_2_jobs)
806 def testGetJobStatus(self):
807 self.rapi.AddResponse("{\"foo\": \"bar\"}")
808 self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
809 self.assertHandler(rlib2.R_2_jobs_id)
810 self.assertItems(["1234"])
812 def testWaitForJobChange(self):
813 fields = ["id", "summary"]
815 "job_info": [123, "something"],
819 self.rapi.AddResponse(serializer.DumpJson(expected))
820 result = self.client.WaitForJobChange(123, fields, [], -1)
821 self.assertEqualValues(expected, result)
822 self.assertHandler(rlib2.R_2_jobs_id_wait)
823 self.assertItems(["123"])
825 def testCancelJob(self):
826 self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
827 self.assertEqual([True, "Job 123 will be canceled"],
828 self.client.CancelJob(999, dry_run=True))
829 self.assertHandler(rlib2.R_2_jobs_id)
830 self.assertItems(["999"])
833 def testGetNodes(self):
834 self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
835 " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
836 self.assertEqual(["node1", "node2"], self.client.GetNodes())
837 self.assertHandler(rlib2.R_2_nodes)
839 self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
840 " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
841 self.assertEqual([{"id": "node1", "uri": "uri1"},
842 {"id": "node2", "uri": "uri2"}],
843 self.client.GetNodes(bulk=True))
844 self.assertHandler(rlib2.R_2_nodes)
847 def testGetNode(self):
848 self.rapi.AddResponse("{}")
849 self.assertEqual({}, self.client.GetNode("node-foo"))
850 self.assertHandler(rlib2.R_2_nodes_name)
851 self.assertItems(["node-foo"])
853 def testEvacuateNode(self):
854 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
855 self.rapi.AddResponse("9876")
856 job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
857 self.assertEqual(9876, job_id)
858 self.assertHandler(rlib2.R_2_nodes_name_evacuate)
859 self.assertItems(["node-1"])
860 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
861 { "remote_node": "node-2", })
862 self.assertEqual(self.rapi.CountPending(), 0)
864 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
865 self.rapi.AddResponse("8888")
866 job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True)
867 self.assertEqual(8888, job_id)
868 self.assertItems(["node-3"])
869 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
870 { "iallocator": "hail", })
873 self.assertRaises(client.GanetiApiError,
874 self.client.EvacuateNode,
875 "node-4", iallocator="hail", remote_node="node-5")
876 self.assertEqual(self.rapi.CountPending(), 0)
878 def testEvacuateNodeOldResponse(self):
879 self.rapi.AddResponse(serializer.DumpJson([]))
880 self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
881 "node-4", accept_old=False)
882 self.assertEqual(self.rapi.CountPending(), 0)
884 self.rapi.AddResponse(serializer.DumpJson([]))
885 self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
886 "node-4", accept_old=True)
887 self.assertEqual(self.rapi.CountPending(), 0)
889 self.rapi.AddResponse(serializer.DumpJson([]))
890 self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
891 "node-4", accept_old=True, primary=True)
892 self.assertEqual(self.rapi.CountPending(), 0)
894 self.rapi.AddResponse(serializer.DumpJson([]))
895 self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
896 "node-4", accept_old=True, secondary=False)
897 self.assertEqual(self.rapi.CountPending(), 0)
899 for sec in [True, None]:
900 self.rapi.AddResponse(serializer.DumpJson([]))
901 self.rapi.AddResponse(serializer.DumpJson([["res", "foo"]]))
902 result = self.client.EvacuateNode("node-3", iallocator="hail",
903 dry_run=True, accept_old=True,
904 primary=False, secondary=sec)
905 self.assertEqual(result, [["res", "foo"]])
906 self.assertItems(["node-3"])
907 self.assertQuery("iallocator", ["hail"])
908 self.assertFalse(self.rapi.GetLastRequestData())
910 self.assertEqual(self.rapi.CountPending(), 0)
912 def testMigrateNode(self):
913 self.rapi.AddResponse(serializer.DumpJson([]))
914 self.rapi.AddResponse("1111")
915 self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
916 self.assertHandler(rlib2.R_2_nodes_name_migrate)
917 self.assertItems(["node-a"])
918 self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
920 self.assertFalse(self.rapi.GetLastRequestData())
922 self.rapi.AddResponse(serializer.DumpJson([]))
923 self.rapi.AddResponse("1112")
924 self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
926 self.assertHandler(rlib2.R_2_nodes_name_migrate)
927 self.assertItems(["node-a"])
928 self.assertQuery("mode", ["live"])
930 self.assertFalse(self.rapi.GetLastRequestData())
932 self.rapi.AddResponse(serializer.DumpJson([]))
933 self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
934 "node-c", target_node="foonode")
935 self.assertEqual(self.rapi.CountPending(), 0)
937 def testMigrateNodeBodyData(self):
938 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
939 self.rapi.AddResponse("27539")
940 self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
942 self.assertHandler(rlib2.R_2_nodes_name_migrate)
943 self.assertItems(["node-a"])
944 self.assertFalse(self.rapi.GetLastHandler().queryargs)
945 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
948 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
949 self.rapi.AddResponse("14219")
950 self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
953 self.assertHandler(rlib2.R_2_nodes_name_migrate)
954 self.assertItems(["node-x"])
956 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
957 { "target_node": "node9", "iallocator": "ial", })
959 self.assertEqual(self.rapi.CountPending(), 0)
961 def testGetNodeRole(self):
962 self.rapi.AddResponse("\"master\"")
963 self.assertEqual("master", self.client.GetNodeRole("node-a"))
964 self.assertHandler(rlib2.R_2_nodes_name_role)
965 self.assertItems(["node-a"])
967 def testSetNodeRole(self):
968 self.rapi.AddResponse("789")
969 self.assertEqual(789,
970 self.client.SetNodeRole("node-foo", "master-candidate", force=True))
971 self.assertHandler(rlib2.R_2_nodes_name_role)
972 self.assertItems(["node-foo"])
973 self.assertQuery("force", ["1"])
974 self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
976 def testPowercycleNode(self):
977 self.rapi.AddResponse("23051")
978 self.assertEqual(23051,
979 self.client.PowercycleNode("node5468", force=True))
980 self.assertHandler(rlib2.R_2_nodes_name_powercycle)
981 self.assertItems(["node5468"])
982 self.assertQuery("force", ["1"])
983 self.assertFalse(self.rapi.GetLastRequestData())
984 self.assertEqual(self.rapi.CountPending(), 0)
986 def testGetNodeStorageUnits(self):
987 self.rapi.AddResponse("42")
989 self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
990 self.assertHandler(rlib2.R_2_nodes_name_storage)
991 self.assertItems(["node-x"])
992 self.assertQuery("storage_type", ["lvm-pv"])
993 self.assertQuery("output_fields", ["fields"])
995 def testModifyNodeStorageUnits(self):
996 self.rapi.AddResponse("14")
998 self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
999 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1000 self.assertItems(["node-z"])
1001 self.assertQuery("storage_type", ["lvm-pv"])
1002 self.assertQuery("name", ["hda"])
1003 self.assertQuery("allocatable", None)
1005 for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
1006 self.rapi.AddResponse("7205")
1007 job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
1008 allocatable=allocatable)
1009 self.assertEqual(7205, job_id)
1010 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1011 self.assertItems(["node-z"])
1012 self.assertQuery("storage_type", ["lvm-pv"])
1013 self.assertQuery("name", ["hda"])
1014 self.assertQuery("allocatable", [query_allocatable])
1016 def testRepairNodeStorageUnits(self):
1017 self.rapi.AddResponse("99")
1018 self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
1020 self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
1021 self.assertItems(["node-z"])
1022 self.assertQuery("storage_type", ["lvm-pv"])
1023 self.assertQuery("name", ["hda"])
1025 def testGetNodeTags(self):
1026 self.rapi.AddResponse("[\"fry\", \"bender\"]")
1027 self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
1028 self.assertHandler(rlib2.R_2_nodes_name_tags)
1029 self.assertItems(["node-k"])
1031 def testAddNodeTags(self):
1032 self.rapi.AddResponse("1234")
1033 self.assertEqual(1234,
1034 self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
1035 self.assertHandler(rlib2.R_2_nodes_name_tags)
1036 self.assertItems(["node-v"])
1038 self.assertQuery("tag", ["awesome"])
1040 def testDeleteNodeTags(self):
1041 self.rapi.AddResponse("16861")
1042 self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1044 self.assertHandler(rlib2.R_2_nodes_name_tags)
1045 self.assertItems(["node-w"])
1047 self.assertQuery("tag", ["awesome"])
1049 def testGetGroups(self):
1050 groups = [{"name": "group1",
1051 "uri": "/2/groups/group1",
1054 "uri": "/2/groups/group2",
1057 self.rapi.AddResponse(serializer.DumpJson(groups))
1058 self.assertEqual(["group1", "group2"], self.client.GetGroups())
1059 self.assertHandler(rlib2.R_2_groups)
1061 def testGetGroupsBulk(self):
1062 groups = [{"name": "group1",
1063 "uri": "/2/groups/group1",
1065 "node_list": ["gnt1.test",
1070 "uri": "/2/groups/group2",
1072 "node_list": ["gnt3.test",
1076 self.rapi.AddResponse(serializer.DumpJson(groups))
1078 self.assertEqual(groups, self.client.GetGroups(bulk=True))
1079 self.assertHandler(rlib2.R_2_groups)
1082 def testGetGroup(self):
1083 group = {"ctime": None,
1086 self.rapi.AddResponse(serializer.DumpJson(group))
1087 self.assertEqual({"ctime": None, "name": "default"},
1088 self.client.GetGroup("default"))
1089 self.assertHandler(rlib2.R_2_groups_name)
1090 self.assertItems(["default"])
1092 def testCreateGroup(self):
1093 self.rapi.AddResponse("12345")
1094 job_id = self.client.CreateGroup("newgroup", dry_run=True)
1095 self.assertEqual(job_id, 12345)
1096 self.assertHandler(rlib2.R_2_groups)
1099 def testDeleteGroup(self):
1100 self.rapi.AddResponse("12346")
1101 job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1102 self.assertEqual(job_id, 12346)
1103 self.assertHandler(rlib2.R_2_groups_name)
1106 def testRenameGroup(self):
1107 self.rapi.AddResponse("12347")
1108 job_id = self.client.RenameGroup("oldname", "newname")
1109 self.assertEqual(job_id, 12347)
1110 self.assertHandler(rlib2.R_2_groups_name_rename)
1112 def testModifyGroup(self):
1113 self.rapi.AddResponse("12348")
1114 job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1115 self.assertEqual(job_id, 12348)
1116 self.assertHandler(rlib2.R_2_groups_name_modify)
1118 def testAssignGroupNodes(self):
1119 self.rapi.AddResponse("12349")
1120 job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1121 force=True, dry_run=True)
1122 self.assertEqual(job_id, 12349)
1123 self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1125 self.assertUseForce()
1127 def testModifyInstance(self):
1128 self.rapi.AddResponse("23681")
1129 job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1130 self.assertEqual(job_id, 23681)
1131 self.assertItems(["inst7210"])
1132 self.assertHandler(rlib2.R_2_instances_name_modify)
1133 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1134 { "os_name": "linux", })
1136 def testModifyCluster(self):
1137 for mnh in [None, False, True]:
1138 self.rapi.AddResponse("14470")
1139 self.assertEqual(14470,
1140 self.client.ModifyCluster(maintain_node_health=mnh))
1141 self.assertHandler(rlib2.R_2_cluster_modify)
1142 self.assertItems([])
1143 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1144 self.assertEqual(len(data), 1)
1145 self.assertEqual(data["maintain_node_health"], mnh)
1146 self.assertEqual(self.rapi.CountPending(), 0)
1148 def testRedistributeConfig(self):
1149 self.rapi.AddResponse("3364")
1150 job_id = self.client.RedistributeConfig()
1151 self.assertEqual(job_id, 3364)
1152 self.assertItems([])
1153 self.assertHandler(rlib2.R_2_redist_config)
1155 def testActivateInstanceDisks(self):
1156 self.rapi.AddResponse("23547")
1157 job_id = self.client.ActivateInstanceDisks("inst28204")
1158 self.assertEqual(job_id, 23547)
1159 self.assertItems(["inst28204"])
1160 self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1161 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1163 def testActivateInstanceDisksIgnoreSize(self):
1164 self.rapi.AddResponse("11044")
1165 job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1166 self.assertEqual(job_id, 11044)
1167 self.assertItems(["inst28204"])
1168 self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1169 self.assertQuery("ignore_size", ["1"])
1171 def testDeactivateInstanceDisks(self):
1172 self.rapi.AddResponse("14591")
1173 job_id = self.client.DeactivateInstanceDisks("inst28234")
1174 self.assertEqual(job_id, 14591)
1175 self.assertItems(["inst28234"])
1176 self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1177 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1179 def testRecreateInstanceDisks(self):
1180 self.rapi.AddResponse("13553")
1181 job_id = self.client.RecreateInstanceDisks("inst23153")
1182 self.assertEqual(job_id, 13553)
1183 self.assertItems(["inst23153"])
1184 self.assertHandler(rlib2.R_2_instances_name_recreate_disks)
1185 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1187 def testGetInstanceConsole(self):
1188 self.rapi.AddResponse("26876")
1189 job_id = self.client.GetInstanceConsole("inst21491")
1190 self.assertEqual(job_id, 26876)
1191 self.assertItems(["inst21491"])
1192 self.assertHandler(rlib2.R_2_instances_name_console)
1193 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1194 self.assertFalse(self.rapi.GetLastRequestData())
1196 def testGrowInstanceDisk(self):
1197 for idx, wait_for_sync in enumerate([None, False, True]):
1198 amount = 128 + (512 * idx)
1199 self.assertEqual(self.rapi.CountPending(), 0)
1200 self.rapi.AddResponse("30783")
1201 self.assertEqual(30783,
1202 self.client.GrowInstanceDisk("eze8ch", idx, amount,
1203 wait_for_sync=wait_for_sync))
1204 self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1205 self.assertItems(["eze8ch", str(idx)])
1206 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1207 if wait_for_sync is None:
1208 self.assertEqual(len(data), 1)
1209 self.assert_("wait_for_sync" not in data)
1211 self.assertEqual(len(data), 2)
1212 self.assertEqual(data["wait_for_sync"], wait_for_sync)
1213 self.assertEqual(data["amount"], amount)
1214 self.assertEqual(self.rapi.CountPending(), 0)
1216 def testGetGroupTags(self):
1217 self.rapi.AddResponse("[]")
1218 self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1219 self.assertHandler(rlib2.R_2_groups_name_tags)
1220 self.assertItems(["fooGroup"])
1222 def testAddGroupTags(self):
1223 self.rapi.AddResponse("1234")
1224 self.assertEqual(1234,
1225 self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1226 self.assertHandler(rlib2.R_2_groups_name_tags)
1227 self.assertItems(["fooGroup"])
1229 self.assertQuery("tag", ["awesome"])
1231 def testDeleteGroupTags(self):
1232 self.rapi.AddResponse("25826")
1233 self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1235 self.assertHandler(rlib2.R_2_groups_name_tags)
1236 self.assertItems(["foo"])
1238 self.assertQuery("tag", ["awesome"])
1240 def testQuery(self):
1241 for idx, what in enumerate(constants.QR_VIA_RAPI):
1242 for idx2, filter_ in enumerate([None, ["?", "name"]]):
1243 job_id = 11010 + (idx << 4) + (idx2 << 16)
1244 fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1246 self.rapi.AddResponse(str(job_id))
1247 self.assertEqual(self.client.Query(what, fields, filter_=filter_),
1249 self.assertItems([what])
1250 self.assertHandler(rlib2.R_2_query)
1251 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1252 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1253 self.assertEqual(data["fields"], fields)
1255 self.assertTrue("filter" not in data)
1257 self.assertEqual(data["filter"], filter_)
1258 self.assertEqual(self.rapi.CountPending(), 0)
1260 def testQueryFields(self):
1261 exp_result = objects.QueryFieldsResponse(fields=[
1262 objects.QueryFieldDefinition(name="pnode", title="PNode",
1263 kind=constants.QFT_NUMBER),
1264 objects.QueryFieldDefinition(name="other", title="Other",
1265 kind=constants.QFT_BOOL),
1268 for what in constants.QR_VIA_RAPI:
1269 for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1270 self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1271 result = self.client.QueryFields(what, fields=fields)
1272 self.assertItems([what])
1273 self.assertHandler(rlib2.R_2_query_fields)
1274 self.assertFalse(self.rapi.GetLastRequestData())
1276 queryargs = self.rapi.GetLastHandler().queryargs
1278 self.assertFalse(queryargs)
1280 self.assertEqual(queryargs, {
1281 "fields": [",".join(fields)],
1284 self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1285 exp_result.ToDict())
1287 self.assertEqual(self.rapi.CountPending(), 0)
1289 def testWaitForJobCompletionNoChange(self):
1290 resp = serializer.DumpJson({
1291 "status": constants.JOB_STATUS_WAITING,
1294 for retries in [1, 5, 25]:
1295 for _ in range(retries):
1296 self.rapi.AddResponse(resp)
1298 self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1300 self.assertHandler(rlib2.R_2_jobs_id)
1301 self.assertItems(["22789"])
1303 self.assertEqual(self.rapi.CountPending(), 0)
1305 def testWaitForJobCompletionAlreadyFinished(self):
1306 self.rapi.AddResponse(serializer.DumpJson({
1307 "status": constants.JOB_STATUS_SUCCESS,
1310 self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1312 self.assertHandler(rlib2.R_2_jobs_id)
1313 self.assertItems(["22793"])
1315 self.assertEqual(self.rapi.CountPending(), 0)
1317 def testWaitForJobCompletionEmptyResponse(self):
1318 self.rapi.AddResponse("{}")
1319 self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1321 self.assertHandler(rlib2.R_2_jobs_id)
1322 self.assertItems(["22793"])
1324 self.assertEqual(self.rapi.CountPending(), 0)
1326 def testWaitForJobCompletionOutOfRetries(self):
1327 for retries in [3, 10, 21]:
1328 for _ in range(retries):
1329 self.rapi.AddResponse(serializer.DumpJson({
1330 "status": constants.JOB_STATUS_RUNNING,
1333 self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1334 retries=retries - 1))
1335 self.assertHandler(rlib2.R_2_jobs_id)
1336 self.assertItems(["30948"])
1338 self.assertEqual(self.rapi.CountPending(), 1)
1339 self.rapi.ResetResponses()
1341 def testWaitForJobCompletionSuccessAndFailure(self):
1342 for retries in [1, 4, 13]:
1343 for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1344 (True, constants.JOB_STATUS_SUCCESS)]:
1345 for _ in range(retries):
1346 self.rapi.AddResponse(serializer.DumpJson({
1347 "status": constants.JOB_STATUS_RUNNING,
1350 self.rapi.AddResponse(serializer.DumpJson({
1351 "status": end_status,
1354 result = self.client.WaitForJobCompletion(3187, period=None,
1355 retries=retries + 1)
1356 self.assertEqual(result, success)
1357 self.assertHandler(rlib2.R_2_jobs_id)
1358 self.assertItems(["3187"])
1360 self.assertEqual(self.rapi.CountPending(), 0)
1363 class RapiTestRunner(unittest.TextTestRunner):
1364 def run(self, *args):
1365 global _used_handlers
1366 assert _used_handlers is None
1368 _used_handlers = set()
1371 result = unittest.TextTestRunner.run(self, *args)
1373 diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1376 raise AssertionError("The following RAPI resources were not used by the"
1377 " RAPI client: %r" % utils.CommaJoin(diff))
1379 # Reset global variable
1380 _used_handlers = None
1385 if __name__ == '__main__':
1386 client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)