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 opcodes
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
36 from ganeti import rapi
37 from ganeti import errors
39 import ganeti.rapi.testutils
40 from ganeti.rapi import connector
41 from ganeti.rapi import rlib2
42 from ganeti.rapi import client
47 # List of resource handlers which aren't used by the RAPI client
53 # Global variable for collecting used handlers
57 class RapiMock(object):
59 self._mapper = connector.Mapper()
61 self._last_handler = None
62 self._last_req_data = None
64 def ResetResponses(self):
65 del self._responses[:]
67 def AddResponse(self, response, code=200):
68 self._responses.insert(0, (code, response))
70 def CountPending(self):
71 return len(self._responses)
73 def GetLastHandler(self):
74 return self._last_handler
76 def GetLastRequestData(self):
77 return self._last_req_data
79 def FetchResponse(self, path, method, headers, request_body):
80 self._last_req_data = request_body
83 (handler_cls, items, args) = self._mapper.getController(path)
85 # Record handler as used
86 _used_handlers.add(handler_cls)
88 self._last_handler = handler_cls(items, args, None)
89 if not hasattr(self._last_handler, method.upper()):
90 raise http.HttpNotImplemented(message="Method not implemented")
92 except http.HttpException, ex:
96 if not self._responses:
97 raise Exception("No responses")
99 (code, response) = self._responses.pop()
101 return (code, NotImplemented, response)
104 class TestConstants(unittest.TestCase):
106 self.assertEqual(client.GANETI_RAPI_PORT, constants.DEFAULT_RAPI_PORT)
107 self.assertEqual(client.GANETI_RAPI_VERSION, constants.RAPI_VERSION)
108 self.assertEqual(client.HTTP_APP_JSON, http.HTTP_APP_JSON)
109 self.assertEqual(client._REQ_DATA_VERSION_FIELD, rlib2._REQ_DATA_VERSION)
110 self.assertEqual(client.JOB_STATUS_QUEUED, constants.JOB_STATUS_QUEUED)
111 self.assertEqual(client.JOB_STATUS_WAITING, constants.JOB_STATUS_WAITING)
112 self.assertEqual(client.JOB_STATUS_CANCELING,
113 constants.JOB_STATUS_CANCELING)
114 self.assertEqual(client.JOB_STATUS_RUNNING, constants.JOB_STATUS_RUNNING)
115 self.assertEqual(client.JOB_STATUS_CANCELED, constants.JOB_STATUS_CANCELED)
116 self.assertEqual(client.JOB_STATUS_SUCCESS, constants.JOB_STATUS_SUCCESS)
117 self.assertEqual(client.JOB_STATUS_ERROR, constants.JOB_STATUS_ERROR)
118 self.assertEqual(client.JOB_STATUS_PENDING, constants.JOBS_PENDING)
119 self.assertEqual(client.JOB_STATUS_FINALIZED, constants.JOBS_FINALIZED)
120 self.assertEqual(client.JOB_STATUS_ALL, constants.JOB_STATUS_ALL)
123 self.assertEqual(client.NODE_EVAC_PRI, constants.NODE_EVAC_PRI)
124 self.assertEqual(client.NODE_EVAC_SEC, constants.NODE_EVAC_SEC)
125 self.assertEqual(client.NODE_EVAC_ALL, constants.NODE_EVAC_ALL)
128 self.assertEqual(client.JOB_STATUS_WAITLOCK, constants.JOB_STATUS_WAITING)
130 # RAPI feature strings
131 self.assertEqual(client._INST_CREATE_REQV1, rlib2._INST_CREATE_REQV1)
132 self.assertEqual(client.INST_CREATE_REQV1, rlib2._INST_CREATE_REQV1)
133 self.assertEqual(client._INST_REINSTALL_REQV1, rlib2._INST_REINSTALL_REQV1)
134 self.assertEqual(client.INST_REINSTALL_REQV1, rlib2._INST_REINSTALL_REQV1)
135 self.assertEqual(client._NODE_MIGRATE_REQV1, rlib2._NODE_MIGRATE_REQV1)
136 self.assertEqual(client.NODE_MIGRATE_REQV1, rlib2._NODE_MIGRATE_REQV1)
137 self.assertEqual(client._NODE_EVAC_RES1, rlib2._NODE_EVAC_RES1)
138 self.assertEqual(client.NODE_EVAC_RES1, rlib2._NODE_EVAC_RES1)
140 def testErrors(self):
141 self.assertEqual(client.ECODE_ALL, errors.ECODE_ALL)
143 # Make sure all error codes are in both RAPI client and errors module
144 for name in filter(lambda s: (s.startswith("ECODE_") and s != "ECODE_ALL"),
146 value = getattr(client, name)
147 self.assertEqual(value, getattr(errors, name))
148 self.assertTrue(value in client.ECODE_ALL)
149 self.assertTrue(value in errors.ECODE_ALL)
152 class RapiMockTest(unittest.TestCase):
154 (code, _, body) = RapiMock().FetchResponse("/foo", "GET", None, None)
155 self.assertEqual(code, 404)
156 self.assertTrue(body is None)
159 (code, _, body) = RapiMock().FetchResponse("/version", "POST", None, None)
160 self.assertEqual(code, 501)
161 self.assertEqual(body, "Method not implemented")
165 rapi.AddResponse("2")
166 (code, _, response) = rapi.FetchResponse("/version", "GET", None, None)
167 self.assertEqual(200, code)
168 self.assertEqual("2", response)
169 self.failUnless(isinstance(rapi.GetLastHandler(), rlib2.R_version))
172 def _FakeNoSslPycurlVersion():
173 # Note: incomplete version tuple
174 return (3, "7.16.0", 462848, "mysystem", 1581, None, 0)
177 def _FakeFancySslPycurlVersion():
178 # Note: incomplete version tuple
179 return (3, "7.16.0", 462848, "mysystem", 1581, "FancySSL/1.2.3", 0)
182 def _FakeOpenSslPycurlVersion():
183 # Note: incomplete version tuple
184 return (2, "7.15.5", 462597, "othersystem", 668, "OpenSSL/0.9.8c", 0)
187 def _FakeGnuTlsPycurlVersion():
188 # Note: incomplete version tuple
189 return (3, "7.18.0", 463360, "somesystem", 1581, "GnuTLS/2.0.4", 0)
192 class TestExtendedConfig(unittest.TestCase):
194 cl = client.GanetiRapiClient("master.example.com",
195 username="user", password="pw",
196 curl_factory=lambda: rapi.testutils.FakeCurl(RapiMock()))
198 curl = cl._CreateCurl()
199 self.assertEqual(curl.getopt(pycurl.HTTPAUTH), pycurl.HTTPAUTH_BASIC)
200 self.assertEqual(curl.getopt(pycurl.USERPWD), "user:pw")
202 def testInvalidAuth(self):
204 self.assertRaises(client.Error, client.GanetiRapiClient,
205 "master-a.example.com", password="pw")
207 self.assertRaises(client.Error, client.GanetiRapiClient,
208 "master-b.example.com", username="user")
210 def testCertVerifyInvalidCombinations(self):
211 self.assertRaises(client.Error, client.GenericCurlConfig,
212 use_curl_cabundle=True, cafile="cert1.pem")
213 self.assertRaises(client.Error, client.GenericCurlConfig,
214 use_curl_cabundle=True, capath="certs/")
215 self.assertRaises(client.Error, client.GenericCurlConfig,
216 use_curl_cabundle=True,
217 cafile="cert1.pem", capath="certs/")
219 def testProxySignalVerifyHostname(self):
220 for use_gnutls in [False, True]:
222 pcverfn = _FakeGnuTlsPycurlVersion
224 pcverfn = _FakeOpenSslPycurlVersion
226 for proxy in ["", "http://127.0.0.1:1234"]:
227 for use_signal in [False, True]:
228 for verify_hostname in [False, True]:
229 cfgfn = client.GenericCurlConfig(proxy=proxy, use_signal=use_signal,
230 verify_hostname=verify_hostname,
231 _pycurl_version_fn=pcverfn)
233 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
234 cl = client.GanetiRapiClient("master.example.com",
235 curl_config_fn=cfgfn,
236 curl_factory=curl_factory)
238 curl = cl._CreateCurl()
239 self.assertEqual(curl.getopt(pycurl.PROXY), proxy)
240 self.assertEqual(curl.getopt(pycurl.NOSIGNAL), not use_signal)
243 self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 2)
245 self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 0)
247 def testNoCertVerify(self):
248 cfgfn = client.GenericCurlConfig()
250 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
251 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
252 curl_factory=curl_factory)
254 curl = cl._CreateCurl()
255 self.assertFalse(curl.getopt(pycurl.SSL_VERIFYPEER))
256 self.assertFalse(curl.getopt(pycurl.CAINFO))
257 self.assertFalse(curl.getopt(pycurl.CAPATH))
259 def testCertVerifyCurlBundle(self):
260 cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
262 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
263 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
264 curl_factory=curl_factory)
266 curl = cl._CreateCurl()
267 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
268 self.assertFalse(curl.getopt(pycurl.CAINFO))
269 self.assertFalse(curl.getopt(pycurl.CAPATH))
271 def testCertVerifyCafile(self):
272 mycert = "/tmp/some/UNUSED/cert/file.pem"
273 cfgfn = client.GenericCurlConfig(cafile=mycert)
275 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
276 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
277 curl_factory=curl_factory)
279 curl = cl._CreateCurl()
280 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
281 self.assertEqual(curl.getopt(pycurl.CAINFO), mycert)
282 self.assertFalse(curl.getopt(pycurl.CAPATH))
284 def testCertVerifyCapath(self):
285 certdir = "/tmp/some/UNUSED/cert/directory"
286 pcverfn = _FakeOpenSslPycurlVersion
287 cfgfn = client.GenericCurlConfig(capath=certdir,
288 _pycurl_version_fn=pcverfn)
290 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
291 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
292 curl_factory=curl_factory)
294 curl = cl._CreateCurl()
295 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
296 self.assertEqual(curl.getopt(pycurl.CAPATH), certdir)
297 self.assertFalse(curl.getopt(pycurl.CAINFO))
299 def testCertVerifyCapathGnuTls(self):
300 certdir = "/tmp/some/UNUSED/cert/directory"
301 pcverfn = _FakeGnuTlsPycurlVersion
302 cfgfn = client.GenericCurlConfig(capath=certdir,
303 _pycurl_version_fn=pcverfn)
305 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
306 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
307 curl_factory=curl_factory)
309 self.assertRaises(client.Error, cl._CreateCurl)
311 def testCertVerifyNoSsl(self):
312 certdir = "/tmp/some/UNUSED/cert/directory"
313 pcverfn = _FakeNoSslPycurlVersion
314 cfgfn = client.GenericCurlConfig(capath=certdir,
315 _pycurl_version_fn=pcverfn)
317 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
318 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
319 curl_factory=curl_factory)
321 self.assertRaises(client.Error, cl._CreateCurl)
323 def testCertVerifyFancySsl(self):
324 certdir = "/tmp/some/UNUSED/cert/directory"
325 pcverfn = _FakeFancySslPycurlVersion
326 cfgfn = client.GenericCurlConfig(capath=certdir,
327 _pycurl_version_fn=pcverfn)
329 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
330 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
331 curl_factory=curl_factory)
333 self.assertRaises(NotImplementedError, cl._CreateCurl)
335 def testCertVerifyCapath(self):
336 for connect_timeout in [None, 1, 5, 10, 30, 60, 300]:
337 for timeout in [None, 1, 30, 60, 3600, 24 * 3600]:
338 cfgfn = client.GenericCurlConfig(connect_timeout=connect_timeout,
341 curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
342 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
343 curl_factory=curl_factory)
345 curl = cl._CreateCurl()
346 self.assertEqual(curl.getopt(pycurl.CONNECTTIMEOUT), connect_timeout)
347 self.assertEqual(curl.getopt(pycurl.TIMEOUT), timeout)
350 class GanetiRapiClientTests(testutils.GanetiTestCase):
352 testutils.GanetiTestCase.setUp(self)
354 self.rapi = RapiMock()
355 self.curl = rapi.testutils.FakeCurl(self.rapi)
356 self.client = client.GanetiRapiClient("master.example.com",
357 curl_factory=lambda: self.curl)
359 def assertHandler(self, handler_cls):
360 self.failUnless(isinstance(self.rapi.GetLastHandler(), handler_cls))
362 def assertQuery(self, key, value):
363 self.assertEqual(value, self.rapi.GetLastHandler().queryargs.get(key, None))
365 def assertItems(self, items):
366 self.assertEqual(items, self.rapi.GetLastHandler().items)
368 def assertBulk(self):
369 self.assertTrue(self.rapi.GetLastHandler().useBulk())
371 def assertDryRun(self):
372 self.assertTrue(self.rapi.GetLastHandler().dryRun())
374 def assertUseForce(self):
375 self.assertTrue(self.rapi.GetLastHandler().useForce())
377 def testEncodeQuery(self):
394 self.assertEqualValues(self.client._EncodeQuery(query),
398 for i in [[1, 2, 3], {"moo": "boo"}, (1, 2, 3)]:
399 self.assertRaises(ValueError, self.client._EncodeQuery, [("x", i)])
401 def testCurlSettings(self):
402 self.rapi.AddResponse("2")
403 self.assertEqual(2, self.client.GetVersion())
404 self.assertHandler(rlib2.R_version)
406 # Signals should be disabled by default
407 self.assert_(self.curl.getopt(pycurl.NOSIGNAL))
409 # No auth and no proxy
410 self.assertFalse(self.curl.getopt(pycurl.USERPWD))
411 self.assert_(self.curl.getopt(pycurl.PROXY) is None)
413 # Content-type is required for requests
414 headers = self.curl.getopt(pycurl.HTTPHEADER)
415 self.assert_("Content-type: application/json" in headers)
417 def testHttpError(self):
418 self.rapi.AddResponse(None, code=404)
420 self.client.GetJobStatus(15140)
421 except client.GanetiApiError, err:
422 self.assertEqual(err.code, 404)
424 self.fail("Didn't raise exception")
426 def testGetVersion(self):
427 self.rapi.AddResponse("2")
428 self.assertEqual(2, self.client.GetVersion())
429 self.assertHandler(rlib2.R_version)
431 def testGetFeatures(self):
432 for features in [[], ["foo", "bar", "baz"]]:
433 self.rapi.AddResponse(serializer.DumpJson(features))
434 self.assertEqual(features, self.client.GetFeatures())
435 self.assertHandler(rlib2.R_2_features)
437 def testGetFeaturesNotFound(self):
438 self.rapi.AddResponse(None, code=404)
439 self.assertEqual([], self.client.GetFeatures())
441 def testGetOperatingSystems(self):
442 self.rapi.AddResponse("[\"beos\"]")
443 self.assertEqual(["beos"], self.client.GetOperatingSystems())
444 self.assertHandler(rlib2.R_2_os)
446 def testGetClusterTags(self):
447 self.rapi.AddResponse("[\"tag\"]")
448 self.assertEqual(["tag"], self.client.GetClusterTags())
449 self.assertHandler(rlib2.R_2_tags)
451 def testAddClusterTags(self):
452 self.rapi.AddResponse("1234")
453 self.assertEqual(1234,
454 self.client.AddClusterTags(["awesome"], dry_run=True))
455 self.assertHandler(rlib2.R_2_tags)
457 self.assertQuery("tag", ["awesome"])
459 def testDeleteClusterTags(self):
460 self.rapi.AddResponse("5107")
461 self.assertEqual(5107, self.client.DeleteClusterTags(["awesome"],
463 self.assertHandler(rlib2.R_2_tags)
465 self.assertQuery("tag", ["awesome"])
467 def testGetInfo(self):
468 self.rapi.AddResponse("{}")
469 self.assertEqual({}, self.client.GetInfo())
470 self.assertHandler(rlib2.R_2_info)
472 def testGetInstances(self):
473 self.rapi.AddResponse("[]")
474 self.assertEqual([], self.client.GetInstances(bulk=True))
475 self.assertHandler(rlib2.R_2_instances)
478 def testGetInstance(self):
479 self.rapi.AddResponse("[]")
480 self.assertEqual([], self.client.GetInstance("instance"))
481 self.assertHandler(rlib2.R_2_instances_name)
482 self.assertItems(["instance"])
484 def testGetInstanceInfo(self):
485 self.rapi.AddResponse("21291")
486 self.assertEqual(21291, self.client.GetInstanceInfo("inst3"))
487 self.assertHandler(rlib2.R_2_instances_name_info)
488 self.assertItems(["inst3"])
489 self.assertQuery("static", None)
491 self.rapi.AddResponse("3428")
492 self.assertEqual(3428, self.client.GetInstanceInfo("inst31", static=False))
493 self.assertHandler(rlib2.R_2_instances_name_info)
494 self.assertItems(["inst31"])
495 self.assertQuery("static", ["0"])
497 self.rapi.AddResponse("15665")
498 self.assertEqual(15665, self.client.GetInstanceInfo("inst32", static=True))
499 self.assertHandler(rlib2.R_2_instances_name_info)
500 self.assertItems(["inst32"])
501 self.assertQuery("static", ["1"])
503 def testInstancesMultiAlloc(self):
505 constants.JOB_IDS_KEY: ["23423"],
506 opcodes.OpInstanceMultiAlloc.ALLOCATABLE_KEY: ["foobar"],
507 opcodes.OpInstanceMultiAlloc.FAILED_KEY: ["foobar2"],
509 self.rapi.AddResponse(serializer.DumpJson(response))
510 insts = [self.client.InstanceAllocation("create", "foobar",
512 self.client.InstanceAllocation("create", "foobar2",
513 "drbd8", [{"size": 100}], [])]
514 resp = self.client.InstancesMultiAlloc(insts)
515 self.assertEqual(resp, response)
516 self.assertHandler(rlib2.R_2_instances_multi_alloc)
518 def testCreateInstanceOldVersion(self):
519 # The old request format, version 0, is no longer supported
520 self.rapi.AddResponse(None, code=404)
521 self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
522 "create", "inst1.example.com", "plain", [], [])
523 self.assertEqual(self.rapi.CountPending(), 0)
525 def testCreateInstance(self):
526 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
527 self.rapi.AddResponse("23030")
528 job_id = self.client.CreateInstance("create", "inst1.example.com",
529 "plain", [], [], dry_run=True)
530 self.assertEqual(job_id, 23030)
531 self.assertHandler(rlib2.R_2_instances)
534 data = serializer.LoadJson(self.rapi.GetLastRequestData())
536 for field in ["dry_run", "beparams", "hvparams", "start"]:
537 self.assertFalse(field in data)
539 self.assertEqual(data["name"], "inst1.example.com")
540 self.assertEqual(data["disk_template"], "plain")
542 def testCreateInstance2(self):
543 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
544 self.rapi.AddResponse("24740")
545 job_id = self.client.CreateInstance("import", "inst2.example.com",
546 "drbd8", [{"size": 100,}],
547 [{}, {"bridge": "br1", }],
548 dry_run=False, start=True,
549 pnode="node1", snode="node9",
551 self.assertEqual(job_id, 24740)
552 self.assertHandler(rlib2.R_2_instances)
554 data = serializer.LoadJson(self.rapi.GetLastRequestData())
555 self.assertEqual(data[rlib2._REQ_DATA_VERSION], 1)
556 self.assertEqual(data["name"], "inst2.example.com")
557 self.assertEqual(data["disk_template"], "drbd8")
558 self.assertEqual(data["start"], True)
559 self.assertEqual(data["ip_check"], False)
560 self.assertEqualValues(data["disks"], [{"size": 100,}])
561 self.assertEqualValues(data["nics"], [{}, {"bridge": "br1", }])
563 def testDeleteInstance(self):
564 self.rapi.AddResponse("1234")
565 self.assertEqual(1234, self.client.DeleteInstance("instance", dry_run=True))
566 self.assertHandler(rlib2.R_2_instances_name)
567 self.assertItems(["instance"])
570 def testGetInstanceTags(self):
571 self.rapi.AddResponse("[]")
572 self.assertEqual([], self.client.GetInstanceTags("fooinstance"))
573 self.assertHandler(rlib2.R_2_instances_name_tags)
574 self.assertItems(["fooinstance"])
576 def testAddInstanceTags(self):
577 self.rapi.AddResponse("1234")
578 self.assertEqual(1234,
579 self.client.AddInstanceTags("fooinstance", ["awesome"], dry_run=True))
580 self.assertHandler(rlib2.R_2_instances_name_tags)
581 self.assertItems(["fooinstance"])
583 self.assertQuery("tag", ["awesome"])
585 def testDeleteInstanceTags(self):
586 self.rapi.AddResponse("25826")
587 self.assertEqual(25826, self.client.DeleteInstanceTags("foo", ["awesome"],
589 self.assertHandler(rlib2.R_2_instances_name_tags)
590 self.assertItems(["foo"])
592 self.assertQuery("tag", ["awesome"])
594 def testRebootInstance(self):
595 self.rapi.AddResponse("6146")
596 job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
597 ignore_secondaries=True, dry_run=True,
599 self.assertEqual(6146, job_id)
600 self.assertHandler(rlib2.R_2_instances_name_reboot)
601 self.assertItems(["i-bar"])
603 self.assertQuery("type", ["hard"])
604 self.assertQuery("ignore_secondaries", ["1"])
605 self.assertQuery("reason", ["Updates"])
607 def testRebootInstanceDefaultReason(self):
608 self.rapi.AddResponse("6146")
609 job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
610 ignore_secondaries=True, dry_run=True)
611 self.assertEqual(6146, job_id)
612 self.assertHandler(rlib2.R_2_instances_name_reboot)
613 self.assertItems(["i-bar"])
615 self.assertQuery("type", ["hard"])
616 self.assertQuery("ignore_secondaries", ["1"])
617 self.assertQuery("reason", None)
619 def testShutdownInstance(self):
620 self.rapi.AddResponse("1487")
621 self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
624 self.assertHandler(rlib2.R_2_instances_name_shutdown)
625 self.assertItems(["foo-instance"])
627 self.assertQuery("reason", ["NoMore"])
629 def testShutdownInstanceDefaultReason(self):
630 self.rapi.AddResponse("1487")
631 self.assertEqual(1487, self.client.ShutdownInstance("foo-instance",
633 self.assertHandler(rlib2.R_2_instances_name_shutdown)
634 self.assertItems(["foo-instance"])
636 self.assertQuery("reason", None)
638 def testStartupInstance(self):
639 self.rapi.AddResponse("27149")
640 self.assertEqual(27149, self.client.StartupInstance("bar-instance",
643 self.assertHandler(rlib2.R_2_instances_name_startup)
644 self.assertItems(["bar-instance"])
646 self.assertQuery("reason", ["New"])
648 def testStartupInstanceDefaultReason(self):
649 self.rapi.AddResponse("27149")
650 self.assertEqual(27149, self.client.StartupInstance("bar-instance",
652 self.assertHandler(rlib2.R_2_instances_name_startup)
653 self.assertItems(["bar-instance"])
655 self.assertQuery("reason", None)
657 def testReinstallInstance(self):
658 self.rapi.AddResponse(serializer.DumpJson([]))
659 self.rapi.AddResponse("19119")
660 self.assertEqual(19119, self.client.ReinstallInstance("baz-instance",
663 self.assertHandler(rlib2.R_2_instances_name_reinstall)
664 self.assertItems(["baz-instance"])
665 self.assertQuery("os", ["DOS"])
666 self.assertQuery("nostartup", ["1"])
667 self.assertEqual(self.rapi.CountPending(), 0)
669 def testReinstallInstanceNew(self):
670 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
671 self.rapi.AddResponse("25689")
672 self.assertEqual(25689, self.client.ReinstallInstance("moo-instance",
675 self.assertHandler(rlib2.R_2_instances_name_reinstall)
676 self.assertItems(["moo-instance"])
677 data = serializer.LoadJson(self.rapi.GetLastRequestData())
678 self.assertEqual(len(data), 2)
679 self.assertEqual(data["os"], "Debian")
680 self.assertEqual(data["start"], False)
681 self.assertEqual(self.rapi.CountPending(), 0)
683 def testReinstallInstanceWithOsparams1(self):
684 self.rapi.AddResponse(serializer.DumpJson([]))
685 self.assertRaises(client.GanetiApiError, self.client.ReinstallInstance,
686 "doo-instance", osparams={"x": "y"})
687 self.assertEqual(self.rapi.CountPending(), 0)
689 def testReinstallInstanceWithOsparams2(self):
694 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_REINSTALL_REQV1]))
695 self.rapi.AddResponse("1717")
696 self.assertEqual(1717, self.client.ReinstallInstance("zoo-instance",
698 self.assertHandler(rlib2.R_2_instances_name_reinstall)
699 self.assertItems(["zoo-instance"])
700 data = serializer.LoadJson(self.rapi.GetLastRequestData())
701 self.assertEqual(len(data), 2)
702 self.assertEqual(data["osparams"], osparams)
703 self.assertEqual(data["start"], True)
704 self.assertEqual(self.rapi.CountPending(), 0)
706 def testReplaceInstanceDisks(self):
707 self.rapi.AddResponse("999")
708 job_id = self.client.ReplaceInstanceDisks("instance-name",
709 disks=[0, 1], iallocator="hail")
710 self.assertEqual(999, job_id)
711 self.assertHandler(rlib2.R_2_instances_name_replace_disks)
712 self.assertItems(["instance-name"])
713 self.assertQuery("disks", ["0,1"])
714 self.assertQuery("mode", ["replace_auto"])
715 self.assertQuery("iallocator", ["hail"])
717 self.rapi.AddResponse("1000")
718 job_id = self.client.ReplaceInstanceDisks("instance-bar",
719 disks=[1], mode="replace_on_secondary", remote_node="foo-node")
720 self.assertEqual(1000, job_id)
721 self.assertItems(["instance-bar"])
722 self.assertQuery("disks", ["1"])
723 self.assertQuery("remote_node", ["foo-node"])
725 self.rapi.AddResponse("5175")
726 self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
727 self.assertItems(["instance-moo"])
728 self.assertQuery("disks", None)
730 def testPrepareExport(self):
731 self.rapi.AddResponse("8326")
732 self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
733 self.assertHandler(rlib2.R_2_instances_name_prepare_export)
734 self.assertItems(["inst1"])
735 self.assertQuery("mode", ["local"])
737 def testExportInstance(self):
738 self.rapi.AddResponse("19695")
739 job_id = self.client.ExportInstance("inst2", "local", "nodeX",
741 self.assertEqual(job_id, 19695)
742 self.assertHandler(rlib2.R_2_instances_name_export)
743 self.assertItems(["inst2"])
745 data = serializer.LoadJson(self.rapi.GetLastRequestData())
746 self.assertEqual(data["mode"], "local")
747 self.assertEqual(data["destination"], "nodeX")
748 self.assertEqual(data["shutdown"], True)
750 def testMigrateInstanceDefaults(self):
751 self.rapi.AddResponse("24873")
752 job_id = self.client.MigrateInstance("inst91")
753 self.assertEqual(job_id, 24873)
754 self.assertHandler(rlib2.R_2_instances_name_migrate)
755 self.assertItems(["inst91"])
757 data = serializer.LoadJson(self.rapi.GetLastRequestData())
758 self.assertFalse(data)
760 def testMigrateInstance(self):
761 for mode in constants.HT_MIGRATION_MODES:
762 for cleanup in [False, True]:
763 self.rapi.AddResponse("31910")
764 job_id = self.client.MigrateInstance("inst289", mode=mode,
766 self.assertEqual(job_id, 31910)
767 self.assertHandler(rlib2.R_2_instances_name_migrate)
768 self.assertItems(["inst289"])
770 data = serializer.LoadJson(self.rapi.GetLastRequestData())
771 self.assertEqual(len(data), 2)
772 self.assertEqual(data["mode"], mode)
773 self.assertEqual(data["cleanup"], cleanup)
775 def testFailoverInstanceDefaults(self):
776 self.rapi.AddResponse("7639")
777 job_id = self.client.FailoverInstance("inst13579")
778 self.assertEqual(job_id, 7639)
779 self.assertHandler(rlib2.R_2_instances_name_failover)
780 self.assertItems(["inst13579"])
782 data = serializer.LoadJson(self.rapi.GetLastRequestData())
783 self.assertFalse(data)
785 def testFailoverInstance(self):
786 for iallocator in ["dumb", "hail"]:
787 for ignore_consistency in [False, True]:
788 for target_node in ["node-a", "node2"]:
789 self.rapi.AddResponse("19161")
791 self.client.FailoverInstance("inst251", iallocator=iallocator,
792 ignore_consistency=ignore_consistency,
793 target_node=target_node)
794 self.assertEqual(job_id, 19161)
795 self.assertHandler(rlib2.R_2_instances_name_failover)
796 self.assertItems(["inst251"])
798 data = serializer.LoadJson(self.rapi.GetLastRequestData())
799 self.assertEqual(len(data), 3)
800 self.assertEqual(data["iallocator"], iallocator)
801 self.assertEqual(data["ignore_consistency"], ignore_consistency)
802 self.assertEqual(data["target_node"], target_node)
803 self.assertEqual(self.rapi.CountPending(), 0)
805 def testRenameInstanceDefaults(self):
806 new_name = "newnametha7euqu"
807 self.rapi.AddResponse("8791")
808 job_id = self.client.RenameInstance("inst18821", new_name)
809 self.assertEqual(job_id, 8791)
810 self.assertHandler(rlib2.R_2_instances_name_rename)
811 self.assertItems(["inst18821"])
813 data = serializer.LoadJson(self.rapi.GetLastRequestData())
814 self.assertEqualValues(data, {"new_name": new_name, })
816 def testRenameInstance(self):
817 new_name = "new-name-yiux1iin"
818 for ip_check in [False, True]:
819 for name_check in [False, True]:
820 self.rapi.AddResponse("24776")
821 job_id = self.client.RenameInstance("inst20967", new_name,
823 name_check=name_check)
824 self.assertEqual(job_id, 24776)
825 self.assertHandler(rlib2.R_2_instances_name_rename)
826 self.assertItems(["inst20967"])
828 data = serializer.LoadJson(self.rapi.GetLastRequestData())
829 self.assertEqual(len(data), 3)
830 self.assertEqual(data["new_name"], new_name)
831 self.assertEqual(data["ip_check"], ip_check)
832 self.assertEqual(data["name_check"], name_check)
834 def testGetJobs(self):
835 self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
836 ' { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
837 self.assertEqual([123, 124], self.client.GetJobs())
838 self.assertHandler(rlib2.R_2_jobs)
840 def testGetJobStatus(self):
841 self.rapi.AddResponse("{\"foo\": \"bar\"}")
842 self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
843 self.assertHandler(rlib2.R_2_jobs_id)
844 self.assertItems(["1234"])
846 def testWaitForJobChange(self):
847 fields = ["id", "summary"]
849 "job_info": [123, "something"],
853 self.rapi.AddResponse(serializer.DumpJson(expected))
854 result = self.client.WaitForJobChange(123, fields, [], -1)
855 self.assertEqualValues(expected, result)
856 self.assertHandler(rlib2.R_2_jobs_id_wait)
857 self.assertItems(["123"])
859 def testCancelJob(self):
860 self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
861 self.assertEqual([True, "Job 123 will be canceled"],
862 self.client.CancelJob(999, dry_run=True))
863 self.assertHandler(rlib2.R_2_jobs_id)
864 self.assertItems(["999"])
867 def testGetNodes(self):
868 self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
869 " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
870 self.assertEqual(["node1", "node2"], self.client.GetNodes())
871 self.assertHandler(rlib2.R_2_nodes)
873 self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
874 " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
875 self.assertEqual([{"id": "node1", "uri": "uri1"},
876 {"id": "node2", "uri": "uri2"}],
877 self.client.GetNodes(bulk=True))
878 self.assertHandler(rlib2.R_2_nodes)
881 def testGetNode(self):
882 self.rapi.AddResponse("{}")
883 self.assertEqual({}, self.client.GetNode("node-foo"))
884 self.assertHandler(rlib2.R_2_nodes_name)
885 self.assertItems(["node-foo"])
887 def testEvacuateNode(self):
888 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
889 self.rapi.AddResponse("9876")
890 job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
891 self.assertEqual(9876, job_id)
892 self.assertHandler(rlib2.R_2_nodes_name_evacuate)
893 self.assertItems(["node-1"])
894 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
895 { "remote_node": "node-2", })
896 self.assertEqual(self.rapi.CountPending(), 0)
898 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
899 self.rapi.AddResponse("8888")
900 job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True,
901 mode=constants.NODE_EVAC_ALL,
903 self.assertEqual(8888, job_id)
904 self.assertItems(["node-3"])
905 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()), {
906 "iallocator": "hail",
908 "early_release": True,
912 self.assertRaises(client.GanetiApiError,
913 self.client.EvacuateNode,
914 "node-4", iallocator="hail", remote_node="node-5")
915 self.assertEqual(self.rapi.CountPending(), 0)
917 def testEvacuateNodeOldResponse(self):
918 self.rapi.AddResponse(serializer.DumpJson([]))
919 self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
920 "node-4", accept_old=False)
921 self.assertEqual(self.rapi.CountPending(), 0)
923 for mode in [client.NODE_EVAC_PRI, client.NODE_EVAC_ALL]:
924 self.rapi.AddResponse(serializer.DumpJson([]))
925 self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
926 "node-4", accept_old=True, mode=mode)
927 self.assertEqual(self.rapi.CountPending(), 0)
929 self.rapi.AddResponse(serializer.DumpJson([]))
930 self.rapi.AddResponse(serializer.DumpJson("21533"))
931 result = self.client.EvacuateNode("node-3", iallocator="hail",
932 dry_run=True, accept_old=True,
933 mode=client.NODE_EVAC_SEC,
935 self.assertEqual(result, "21533")
936 self.assertItems(["node-3"])
937 self.assertQuery("iallocator", ["hail"])
938 self.assertQuery("early_release", ["1"])
939 self.assertFalse(self.rapi.GetLastRequestData())
941 self.assertEqual(self.rapi.CountPending(), 0)
943 def testMigrateNode(self):
944 self.rapi.AddResponse(serializer.DumpJson([]))
945 self.rapi.AddResponse("1111")
946 self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
947 self.assertHandler(rlib2.R_2_nodes_name_migrate)
948 self.assertItems(["node-a"])
949 self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
951 self.assertFalse(self.rapi.GetLastRequestData())
953 self.rapi.AddResponse(serializer.DumpJson([]))
954 self.rapi.AddResponse("1112")
955 self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
957 self.assertHandler(rlib2.R_2_nodes_name_migrate)
958 self.assertItems(["node-a"])
959 self.assertQuery("mode", ["live"])
961 self.assertFalse(self.rapi.GetLastRequestData())
963 self.rapi.AddResponse(serializer.DumpJson([]))
964 self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
965 "node-c", target_node="foonode")
966 self.assertEqual(self.rapi.CountPending(), 0)
968 def testMigrateNodeBodyData(self):
969 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
970 self.rapi.AddResponse("27539")
971 self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
973 self.assertHandler(rlib2.R_2_nodes_name_migrate)
974 self.assertItems(["node-a"])
975 self.assertFalse(self.rapi.GetLastHandler().queryargs)
976 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
979 self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
980 self.rapi.AddResponse("14219")
981 self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
984 self.assertHandler(rlib2.R_2_nodes_name_migrate)
985 self.assertItems(["node-x"])
987 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
988 { "target_node": "node9", "iallocator": "ial", })
990 self.assertEqual(self.rapi.CountPending(), 0)
992 def testGetNodeRole(self):
993 self.rapi.AddResponse("\"master\"")
994 self.assertEqual("master", self.client.GetNodeRole("node-a"))
995 self.assertHandler(rlib2.R_2_nodes_name_role)
996 self.assertItems(["node-a"])
998 def testSetNodeRole(self):
999 self.rapi.AddResponse("789")
1000 self.assertEqual(789,
1001 self.client.SetNodeRole("node-foo", "master-candidate", force=True))
1002 self.assertHandler(rlib2.R_2_nodes_name_role)
1003 self.assertItems(["node-foo"])
1004 self.assertQuery("force", ["1"])
1005 self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
1007 def testPowercycleNode(self):
1008 self.rapi.AddResponse("23051")
1009 self.assertEqual(23051,
1010 self.client.PowercycleNode("node5468", force=True))
1011 self.assertHandler(rlib2.R_2_nodes_name_powercycle)
1012 self.assertItems(["node5468"])
1013 self.assertQuery("force", ["1"])
1014 self.assertFalse(self.rapi.GetLastRequestData())
1015 self.assertEqual(self.rapi.CountPending(), 0)
1017 def testModifyNode(self):
1018 self.rapi.AddResponse("3783")
1019 job_id = self.client.ModifyNode("node16979.example.com", drained=True)
1020 self.assertEqual(job_id, 3783)
1021 self.assertHandler(rlib2.R_2_nodes_name_modify)
1022 self.assertItems(["node16979.example.com"])
1023 self.assertEqual(self.rapi.CountPending(), 0)
1025 def testGetNodeStorageUnits(self):
1026 self.rapi.AddResponse("42")
1027 self.assertEqual(42,
1028 self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
1029 self.assertHandler(rlib2.R_2_nodes_name_storage)
1030 self.assertItems(["node-x"])
1031 self.assertQuery("storage_type", ["lvm-pv"])
1032 self.assertQuery("output_fields", ["fields"])
1034 def testModifyNodeStorageUnits(self):
1035 self.rapi.AddResponse("14")
1036 self.assertEqual(14,
1037 self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
1038 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1039 self.assertItems(["node-z"])
1040 self.assertQuery("storage_type", ["lvm-pv"])
1041 self.assertQuery("name", ["hda"])
1042 self.assertQuery("allocatable", None)
1044 for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
1045 self.rapi.AddResponse("7205")
1046 job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
1047 allocatable=allocatable)
1048 self.assertEqual(7205, job_id)
1049 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
1050 self.assertItems(["node-z"])
1051 self.assertQuery("storage_type", ["lvm-pv"])
1052 self.assertQuery("name", ["hda"])
1053 self.assertQuery("allocatable", [query_allocatable])
1055 def testRepairNodeStorageUnits(self):
1056 self.rapi.AddResponse("99")
1057 self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
1059 self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
1060 self.assertItems(["node-z"])
1061 self.assertQuery("storage_type", ["lvm-pv"])
1062 self.assertQuery("name", ["hda"])
1064 def testGetNodeTags(self):
1065 self.rapi.AddResponse("[\"fry\", \"bender\"]")
1066 self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
1067 self.assertHandler(rlib2.R_2_nodes_name_tags)
1068 self.assertItems(["node-k"])
1070 def testAddNodeTags(self):
1071 self.rapi.AddResponse("1234")
1072 self.assertEqual(1234,
1073 self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
1074 self.assertHandler(rlib2.R_2_nodes_name_tags)
1075 self.assertItems(["node-v"])
1077 self.assertQuery("tag", ["awesome"])
1079 def testDeleteNodeTags(self):
1080 self.rapi.AddResponse("16861")
1081 self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
1083 self.assertHandler(rlib2.R_2_nodes_name_tags)
1084 self.assertItems(["node-w"])
1086 self.assertQuery("tag", ["awesome"])
1088 def testGetGroups(self):
1089 groups = [{"name": "group1",
1090 "uri": "/2/groups/group1",
1093 "uri": "/2/groups/group2",
1096 self.rapi.AddResponse(serializer.DumpJson(groups))
1097 self.assertEqual(["group1", "group2"], self.client.GetGroups())
1098 self.assertHandler(rlib2.R_2_groups)
1100 def testGetGroupsBulk(self):
1101 groups = [{"name": "group1",
1102 "uri": "/2/groups/group1",
1104 "node_list": ["gnt1.test",
1109 "uri": "/2/groups/group2",
1111 "node_list": ["gnt3.test",
1115 self.rapi.AddResponse(serializer.DumpJson(groups))
1117 self.assertEqual(groups, self.client.GetGroups(bulk=True))
1118 self.assertHandler(rlib2.R_2_groups)
1121 def testGetGroup(self):
1122 group = {"ctime": None,
1125 self.rapi.AddResponse(serializer.DumpJson(group))
1126 self.assertEqual({"ctime": None, "name": "default"},
1127 self.client.GetGroup("default"))
1128 self.assertHandler(rlib2.R_2_groups_name)
1129 self.assertItems(["default"])
1131 def testCreateGroup(self):
1132 self.rapi.AddResponse("12345")
1133 job_id = self.client.CreateGroup("newgroup", dry_run=True)
1134 self.assertEqual(job_id, 12345)
1135 self.assertHandler(rlib2.R_2_groups)
1138 def testDeleteGroup(self):
1139 self.rapi.AddResponse("12346")
1140 job_id = self.client.DeleteGroup("newgroup", dry_run=True)
1141 self.assertEqual(job_id, 12346)
1142 self.assertHandler(rlib2.R_2_groups_name)
1145 def testRenameGroup(self):
1146 self.rapi.AddResponse("12347")
1147 job_id = self.client.RenameGroup("oldname", "newname")
1148 self.assertEqual(job_id, 12347)
1149 self.assertHandler(rlib2.R_2_groups_name_rename)
1151 def testModifyGroup(self):
1152 self.rapi.AddResponse("12348")
1153 job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
1154 self.assertEqual(job_id, 12348)
1155 self.assertHandler(rlib2.R_2_groups_name_modify)
1157 def testAssignGroupNodes(self):
1158 self.rapi.AddResponse("12349")
1159 job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
1160 force=True, dry_run=True)
1161 self.assertEqual(job_id, 12349)
1162 self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
1164 self.assertUseForce()
1166 def testGetNetworksBulk(self):
1167 networks = [{"name": "network1",
1168 "uri": "/2/networks/network1",
1169 "network": "192.168.0.0/24",
1171 {"name": "network2",
1172 "uri": "/2/networks/network2",
1173 "network": "192.168.0.0/24",
1176 self.rapi.AddResponse(serializer.DumpJson(networks))
1178 self.assertEqual(networks, self.client.GetNetworks(bulk=True))
1179 self.assertHandler(rlib2.R_2_networks)
1182 def testGetNetwork(self):
1183 network = {"ctime": None,
1186 self.rapi.AddResponse(serializer.DumpJson(network))
1187 self.assertEqual({"ctime": None, "name": "network1"},
1188 self.client.GetNetwork("network1"))
1189 self.assertHandler(rlib2.R_2_networks_name)
1190 self.assertItems(["network1"])
1192 def testCreateNetwork(self):
1193 self.rapi.AddResponse("12345")
1194 job_id = self.client.CreateNetwork("newnetwork", network="192.168.0.0/24",
1196 self.assertEqual(job_id, 12345)
1197 self.assertHandler(rlib2.R_2_networks)
1200 def testModifyNetwork(self):
1201 self.rapi.AddResponse("12346")
1202 job_id = self.client.ModifyNetwork("mynetwork", gateway="192.168.0.10",
1204 self.assertEqual(job_id, 12346)
1205 self.assertHandler(rlib2.R_2_networks_name_modify)
1207 def testDeleteNetwork(self):
1208 self.rapi.AddResponse("12347")
1209 job_id = self.client.DeleteNetwork("newnetwork", dry_run=True)
1210 self.assertEqual(job_id, 12347)
1211 self.assertHandler(rlib2.R_2_networks_name)
1214 def testConnectNetwork(self):
1215 self.rapi.AddResponse("12348")
1216 job_id = self.client.ConnectNetwork("mynetwork", "default",
1217 "bridged", "br0", dry_run=True)
1218 self.assertEqual(job_id, 12348)
1219 self.assertHandler(rlib2.R_2_networks_name_connect)
1222 def testDisconnectNetwork(self):
1223 self.rapi.AddResponse("12349")
1224 job_id = self.client.DisconnectNetwork("mynetwork", "default", dry_run=True)
1225 self.assertEqual(job_id, 12349)
1226 self.assertHandler(rlib2.R_2_networks_name_disconnect)
1229 def testGetNetworkTags(self):
1230 self.rapi.AddResponse("[]")
1231 self.assertEqual([], self.client.GetNetworkTags("fooNetwork"))
1232 self.assertHandler(rlib2.R_2_networks_name_tags)
1233 self.assertItems(["fooNetwork"])
1235 def testAddNetworkTags(self):
1236 self.rapi.AddResponse("1234")
1237 self.assertEqual(1234,
1238 self.client.AddNetworkTags("fooNetwork", ["awesome"], dry_run=True))
1239 self.assertHandler(rlib2.R_2_networks_name_tags)
1240 self.assertItems(["fooNetwork"])
1242 self.assertQuery("tag", ["awesome"])
1244 def testDeleteNetworkTags(self):
1245 self.rapi.AddResponse("25826")
1246 self.assertEqual(25826, self.client.DeleteNetworkTags("foo", ["awesome"],
1248 self.assertHandler(rlib2.R_2_networks_name_tags)
1249 self.assertItems(["foo"])
1251 self.assertQuery("tag", ["awesome"])
1253 def testModifyInstance(self):
1254 self.rapi.AddResponse("23681")
1255 job_id = self.client.ModifyInstance("inst7210", os_name="linux")
1256 self.assertEqual(job_id, 23681)
1257 self.assertItems(["inst7210"])
1258 self.assertHandler(rlib2.R_2_instances_name_modify)
1259 self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
1260 { "os_name": "linux", })
1262 def testModifyCluster(self):
1263 for mnh in [None, False, True]:
1264 self.rapi.AddResponse("14470")
1265 self.assertEqual(14470,
1266 self.client.ModifyCluster(maintain_node_health=mnh))
1267 self.assertHandler(rlib2.R_2_cluster_modify)
1268 self.assertItems([])
1269 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1270 self.assertEqual(len(data), 1)
1271 self.assertEqual(data["maintain_node_health"], mnh)
1272 self.assertEqual(self.rapi.CountPending(), 0)
1274 def testRedistributeConfig(self):
1275 self.rapi.AddResponse("3364")
1276 job_id = self.client.RedistributeConfig()
1277 self.assertEqual(job_id, 3364)
1278 self.assertItems([])
1279 self.assertHandler(rlib2.R_2_redist_config)
1281 def testActivateInstanceDisks(self):
1282 self.rapi.AddResponse("23547")
1283 job_id = self.client.ActivateInstanceDisks("inst28204")
1284 self.assertEqual(job_id, 23547)
1285 self.assertItems(["inst28204"])
1286 self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1287 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1289 def testActivateInstanceDisksIgnoreSize(self):
1290 self.rapi.AddResponse("11044")
1291 job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
1292 self.assertEqual(job_id, 11044)
1293 self.assertItems(["inst28204"])
1294 self.assertHandler(rlib2.R_2_instances_name_activate_disks)
1295 self.assertQuery("ignore_size", ["1"])
1297 def testDeactivateInstanceDisks(self):
1298 self.rapi.AddResponse("14591")
1299 job_id = self.client.DeactivateInstanceDisks("inst28234")
1300 self.assertEqual(job_id, 14591)
1301 self.assertItems(["inst28234"])
1302 self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
1303 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1305 def testRecreateInstanceDisks(self):
1306 self.rapi.AddResponse("13553")
1307 job_id = self.client.RecreateInstanceDisks("inst23153")
1308 self.assertEqual(job_id, 13553)
1309 self.assertItems(["inst23153"])
1310 self.assertHandler(rlib2.R_2_instances_name_recreate_disks)
1311 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1313 def testGetInstanceConsole(self):
1314 self.rapi.AddResponse("26876")
1315 job_id = self.client.GetInstanceConsole("inst21491")
1316 self.assertEqual(job_id, 26876)
1317 self.assertItems(["inst21491"])
1318 self.assertHandler(rlib2.R_2_instances_name_console)
1319 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1320 self.assertFalse(self.rapi.GetLastRequestData())
1322 def testGrowInstanceDisk(self):
1323 for idx, wait_for_sync in enumerate([None, False, True]):
1324 amount = 128 + (512 * idx)
1325 self.assertEqual(self.rapi.CountPending(), 0)
1326 self.rapi.AddResponse("30783")
1327 self.assertEqual(30783,
1328 self.client.GrowInstanceDisk("eze8ch", idx, amount,
1329 wait_for_sync=wait_for_sync))
1330 self.assertHandler(rlib2.R_2_instances_name_disk_grow)
1331 self.assertItems(["eze8ch", str(idx)])
1332 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1333 if wait_for_sync is None:
1334 self.assertEqual(len(data), 1)
1335 self.assert_("wait_for_sync" not in data)
1337 self.assertEqual(len(data), 2)
1338 self.assertEqual(data["wait_for_sync"], wait_for_sync)
1339 self.assertEqual(data["amount"], amount)
1340 self.assertEqual(self.rapi.CountPending(), 0)
1342 def testGetGroupTags(self):
1343 self.rapi.AddResponse("[]")
1344 self.assertEqual([], self.client.GetGroupTags("fooGroup"))
1345 self.assertHandler(rlib2.R_2_groups_name_tags)
1346 self.assertItems(["fooGroup"])
1348 def testAddGroupTags(self):
1349 self.rapi.AddResponse("1234")
1350 self.assertEqual(1234,
1351 self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
1352 self.assertHandler(rlib2.R_2_groups_name_tags)
1353 self.assertItems(["fooGroup"])
1355 self.assertQuery("tag", ["awesome"])
1357 def testDeleteGroupTags(self):
1358 self.rapi.AddResponse("25826")
1359 self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
1361 self.assertHandler(rlib2.R_2_groups_name_tags)
1362 self.assertItems(["foo"])
1364 self.assertQuery("tag", ["awesome"])
1366 def testQuery(self):
1367 for idx, what in enumerate(constants.QR_VIA_RAPI):
1368 for idx2, qfilter in enumerate([None, ["?", "name"]]):
1369 job_id = 11010 + (idx << 4) + (idx2 << 16)
1370 fields = sorted(query.ALL_FIELDS[what].keys())[:10]
1372 self.rapi.AddResponse(str(job_id))
1373 self.assertEqual(self.client.Query(what, fields, qfilter=qfilter),
1375 self.assertItems([what])
1376 self.assertHandler(rlib2.R_2_query)
1377 self.assertFalse(self.rapi.GetLastHandler().queryargs)
1378 data = serializer.LoadJson(self.rapi.GetLastRequestData())
1379 self.assertEqual(data["fields"], fields)
1381 self.assertTrue("qfilter" not in data)
1383 self.assertEqual(data["qfilter"], qfilter)
1384 self.assertEqual(self.rapi.CountPending(), 0)
1386 def testQueryFields(self):
1387 exp_result = objects.QueryFieldsResponse(fields=[
1388 objects.QueryFieldDefinition(name="pnode", title="PNode",
1389 kind=constants.QFT_NUMBER),
1390 objects.QueryFieldDefinition(name="other", title="Other",
1391 kind=constants.QFT_BOOL),
1394 for what in constants.QR_VIA_RAPI:
1395 for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
1396 self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
1397 result = self.client.QueryFields(what, fields=fields)
1398 self.assertItems([what])
1399 self.assertHandler(rlib2.R_2_query_fields)
1400 self.assertFalse(self.rapi.GetLastRequestData())
1402 queryargs = self.rapi.GetLastHandler().queryargs
1404 self.assertFalse(queryargs)
1406 self.assertEqual(queryargs, {
1407 "fields": [",".join(fields)],
1410 self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
1411 exp_result.ToDict())
1413 self.assertEqual(self.rapi.CountPending(), 0)
1415 def testWaitForJobCompletionNoChange(self):
1416 resp = serializer.DumpJson({
1417 "status": constants.JOB_STATUS_WAITING,
1420 for retries in [1, 5, 25]:
1421 for _ in range(retries):
1422 self.rapi.AddResponse(resp)
1424 self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
1426 self.assertHandler(rlib2.R_2_jobs_id)
1427 self.assertItems(["22789"])
1429 self.assertEqual(self.rapi.CountPending(), 0)
1431 def testWaitForJobCompletionAlreadyFinished(self):
1432 self.rapi.AddResponse(serializer.DumpJson({
1433 "status": constants.JOB_STATUS_SUCCESS,
1436 self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
1438 self.assertHandler(rlib2.R_2_jobs_id)
1439 self.assertItems(["22793"])
1441 self.assertEqual(self.rapi.CountPending(), 0)
1443 def testWaitForJobCompletionEmptyResponse(self):
1444 self.rapi.AddResponse("{}")
1445 self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
1447 self.assertHandler(rlib2.R_2_jobs_id)
1448 self.assertItems(["22793"])
1450 self.assertEqual(self.rapi.CountPending(), 0)
1452 def testWaitForJobCompletionOutOfRetries(self):
1453 for retries in [3, 10, 21]:
1454 for _ in range(retries):
1455 self.rapi.AddResponse(serializer.DumpJson({
1456 "status": constants.JOB_STATUS_RUNNING,
1459 self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
1460 retries=retries - 1))
1461 self.assertHandler(rlib2.R_2_jobs_id)
1462 self.assertItems(["30948"])
1464 self.assertEqual(self.rapi.CountPending(), 1)
1465 self.rapi.ResetResponses()
1467 def testWaitForJobCompletionSuccessAndFailure(self):
1468 for retries in [1, 4, 13]:
1469 for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
1470 (True, constants.JOB_STATUS_SUCCESS)]:
1471 for _ in range(retries):
1472 self.rapi.AddResponse(serializer.DumpJson({
1473 "status": constants.JOB_STATUS_RUNNING,
1476 self.rapi.AddResponse(serializer.DumpJson({
1477 "status": end_status,
1480 result = self.client.WaitForJobCompletion(3187, period=None,
1481 retries=retries + 1)
1482 self.assertEqual(result, success)
1483 self.assertHandler(rlib2.R_2_jobs_id)
1484 self.assertItems(["3187"])
1486 self.assertEqual(self.rapi.CountPending(), 0)
1489 class RapiTestRunner(unittest.TextTestRunner):
1490 def run(self, *args):
1491 global _used_handlers
1492 assert _used_handlers is None
1494 _used_handlers = set()
1497 result = unittest.TextTestRunner.run(self, *args)
1499 diff = (set(connector.CONNECTOR.values()) - _used_handlers -
1502 raise AssertionError("The following RAPI resources were not used by the"
1503 " RAPI client: %r" % utils.CommaJoin(diff))
1505 # Reset global variable
1506 _used_handlers = None
1511 if __name__ == "__main__":
1512 client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)