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
34 from ganeti.rapi import connector
35 from ganeti.rapi import rlib2
36 from ganeti.rapi import client
41 _URI_RE = re.compile(r"https://(?P<host>.*):(?P<port>\d+)(?P<path>/.*)")
44 def _GetPathFromUri(uri):
45 """Gets the path and query from a URI.
48 match = _URI_RE.match(uri)
50 return match.groupdict()["path"]
56 def __init__(self, rapi):
61 def setopt(self, opt, value):
62 self._opts[opt] = value
64 def getopt(self, opt):
65 return self._opts.get(opt)
67 def unsetopt(self, opt):
68 self._opts.pop(opt, None)
70 def getinfo(self, info):
71 return self._info[info]
74 method = self._opts[pycurl.CUSTOMREQUEST]
75 url = self._opts[pycurl.URL]
76 request_body = self._opts[pycurl.POSTFIELDS]
77 writefn = self._opts[pycurl.WRITEFUNCTION]
79 path = _GetPathFromUri(url)
80 (code, resp_body) = self._rapi.FetchResponse(path, method, request_body)
82 self._info[pycurl.RESPONSE_CODE] = code
83 if resp_body is not None:
87 class RapiMock(object):
89 self._mapper = connector.Mapper()
91 self._last_handler = None
92 self._last_req_data = None
94 def AddResponse(self, response, code=200):
95 self._responses.insert(0, (code, response))
97 def CountPending(self):
98 return len(self._responses)
100 def GetLastHandler(self):
101 return self._last_handler
103 def GetLastRequestData(self):
104 return self._last_req_data
106 def FetchResponse(self, path, method, request_body):
107 self._last_req_data = request_body
110 HandlerClass, items, args = self._mapper.getController(path)
111 self._last_handler = HandlerClass(items, args, None)
112 if not hasattr(self._last_handler, method.upper()):
113 raise http.HttpNotImplemented(message="Method not implemented")
115 except http.HttpException, ex:
117 response = ex.message
119 if not self._responses:
120 raise Exception("No responses")
122 (code, response) = self._responses.pop()
124 return code, response
127 class TestConstants(unittest.TestCase):
129 self.assertEqual(client.GANETI_RAPI_PORT, constants.DEFAULT_RAPI_PORT)
130 self.assertEqual(client.GANETI_RAPI_VERSION, constants.RAPI_VERSION)
131 self.assertEqual(client.HTTP_APP_JSON, http.HTTP_APP_JSON)
132 self.assertEqual(client._REQ_DATA_VERSION_FIELD, rlib2._REQ_DATA_VERSION)
133 self.assertEqual(client._INST_CREATE_REQV1, rlib2._INST_CREATE_REQV1)
134 self.assertEqual(client._INST_NIC_PARAMS, constants.INIC_PARAMS)
137 class RapiMockTest(unittest.TestCase):
141 self.assertEqual((404, None), rapi.FetchResponse("/foo", "GET", None))
142 self.assertEqual((501, "Method not implemented"),
143 rapi.FetchResponse("/version", "POST", None))
144 rapi.AddResponse("2")
145 code, response = rapi.FetchResponse("/version", "GET", None)
146 self.assertEqual(200, code)
147 self.assertEqual("2", response)
148 self.failUnless(isinstance(rapi.GetLastHandler(), rlib2.R_version))
151 def _FakeNoSslPycurlVersion():
152 # Note: incomplete version tuple
153 return (3, "7.16.0", 462848, "mysystem", 1581, None, 0)
156 def _FakeFancySslPycurlVersion():
157 # Note: incomplete version tuple
158 return (3, "7.16.0", 462848, "mysystem", 1581, "FancySSL/1.2.3", 0)
161 def _FakeOpenSslPycurlVersion():
162 # Note: incomplete version tuple
163 return (2, "7.15.5", 462597, "othersystem", 668, "OpenSSL/0.9.8c", 0)
166 def _FakeGnuTlsPycurlVersion():
167 # Note: incomplete version tuple
168 return (3, "7.18.0", 463360, "somesystem", 1581, "GnuTLS/2.0.4", 0)
171 class TestExtendedConfig(unittest.TestCase):
173 curl = FakeCurl(RapiMock())
174 cl = client.GanetiRapiClient("master.example.com",
175 username="user", password="pw",
178 self.assertEqual(curl.getopt(pycurl.HTTPAUTH), pycurl.HTTPAUTH_BASIC)
179 self.assertEqual(curl.getopt(pycurl.USERPWD), "user:pw")
181 def testInvalidAuth(self):
183 self.assertRaises(client.Error, client.GanetiRapiClient,
184 "master-a.example.com", password="pw")
186 self.assertRaises(client.Error, client.GanetiRapiClient,
187 "master-b.example.com", username="user")
189 def testCertVerifyInvalidCombinations(self):
190 self.assertRaises(client.Error, client.GenericCurlConfig,
191 use_curl_cabundle=True, cafile="cert1.pem")
192 self.assertRaises(client.Error, client.GenericCurlConfig,
193 use_curl_cabundle=True, capath="certs/")
194 self.assertRaises(client.Error, client.GenericCurlConfig,
195 use_curl_cabundle=True,
196 cafile="cert1.pem", capath="certs/")
198 def testProxySignalVerifyHostname(self):
199 for use_gnutls in [False, True]:
201 pcverfn = _FakeGnuTlsPycurlVersion
203 pcverfn = _FakeOpenSslPycurlVersion
205 for proxy in ["", "http://127.0.0.1:1234"]:
206 for use_signal in [False, True]:
207 for verify_hostname in [False, True]:
208 cfgfn = client.GenericCurlConfig(proxy=proxy, use_signal=use_signal,
209 verify_hostname=verify_hostname,
210 _pycurl_version_fn=pcverfn)
212 curl = FakeCurl(RapiMock())
213 cl = client.GanetiRapiClient("master.example.com",
214 curl_config_fn=cfgfn, curl=curl)
216 self.assertEqual(curl.getopt(pycurl.PROXY), proxy)
217 self.assertEqual(curl.getopt(pycurl.NOSIGNAL), not use_signal)
220 self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 2)
222 self.assertEqual(curl.getopt(pycurl.SSL_VERIFYHOST), 0)
224 def testNoCertVerify(self):
225 cfgfn = client.GenericCurlConfig()
227 curl = FakeCurl(RapiMock())
228 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
231 self.assertFalse(curl.getopt(pycurl.SSL_VERIFYPEER))
232 self.assertFalse(curl.getopt(pycurl.CAINFO))
233 self.assertFalse(curl.getopt(pycurl.CAPATH))
235 def testCertVerifyCurlBundle(self):
236 cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
238 curl = FakeCurl(RapiMock())
239 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
242 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
243 self.assertFalse(curl.getopt(pycurl.CAINFO))
244 self.assertFalse(curl.getopt(pycurl.CAPATH))
246 def testCertVerifyCafile(self):
247 mycert = "/tmp/some/UNUSED/cert/file.pem"
248 cfgfn = client.GenericCurlConfig(cafile=mycert)
250 curl = FakeCurl(RapiMock())
251 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
254 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
255 self.assertEqual(curl.getopt(pycurl.CAINFO), mycert)
256 self.assertFalse(curl.getopt(pycurl.CAPATH))
258 def testCertVerifyCapath(self):
259 certdir = "/tmp/some/UNUSED/cert/directory"
260 pcverfn = _FakeOpenSslPycurlVersion
261 cfgfn = client.GenericCurlConfig(capath=certdir,
262 _pycurl_version_fn=pcverfn)
264 curl = FakeCurl(RapiMock())
265 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
268 self.assert_(curl.getopt(pycurl.SSL_VERIFYPEER))
269 self.assertEqual(curl.getopt(pycurl.CAPATH), certdir)
270 self.assertFalse(curl.getopt(pycurl.CAINFO))
272 def testCertVerifyCapathGnuTls(self):
273 certdir = "/tmp/some/UNUSED/cert/directory"
274 pcverfn = _FakeGnuTlsPycurlVersion
275 cfgfn = client.GenericCurlConfig(capath=certdir,
276 _pycurl_version_fn=pcverfn)
278 curl = FakeCurl(RapiMock())
279 self.assertRaises(client.Error, client.GanetiRapiClient,
280 "master.example.com", curl_config_fn=cfgfn, curl=curl)
282 def testCertVerifyNoSsl(self):
283 certdir = "/tmp/some/UNUSED/cert/directory"
284 pcverfn = _FakeNoSslPycurlVersion
285 cfgfn = client.GenericCurlConfig(capath=certdir,
286 _pycurl_version_fn=pcverfn)
288 curl = FakeCurl(RapiMock())
289 self.assertRaises(client.Error, client.GanetiRapiClient,
290 "master.example.com", curl_config_fn=cfgfn, curl=curl)
292 def testCertVerifyFancySsl(self):
293 certdir = "/tmp/some/UNUSED/cert/directory"
294 pcverfn = _FakeFancySslPycurlVersion
295 cfgfn = client.GenericCurlConfig(capath=certdir,
296 _pycurl_version_fn=pcverfn)
298 curl = FakeCurl(RapiMock())
299 self.assertRaises(NotImplementedError, client.GanetiRapiClient,
300 "master.example.com", curl_config_fn=cfgfn, curl=curl)
302 def testCertVerifyCapath(self):
303 for connect_timeout in [None, 1, 5, 10, 30, 60, 300]:
304 for timeout in [None, 1, 30, 60, 3600, 24 * 3600]:
305 cfgfn = client.GenericCurlConfig(connect_timeout=connect_timeout,
308 curl = FakeCurl(RapiMock())
309 cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
312 self.assertEqual(curl.getopt(pycurl.CONNECTTIMEOUT), connect_timeout)
313 self.assertEqual(curl.getopt(pycurl.TIMEOUT), timeout)
316 class GanetiRapiClientTests(testutils.GanetiTestCase):
318 testutils.GanetiTestCase.setUp(self)
320 self.rapi = RapiMock()
321 self.curl = FakeCurl(self.rapi)
322 self.client = client.GanetiRapiClient("master.example.com",
325 # Signals should be disabled by default
326 self.assert_(self.curl.getopt(pycurl.NOSIGNAL))
328 # No auth and no proxy
329 self.assertFalse(self.curl.getopt(pycurl.USERPWD))
330 self.assert_(self.curl.getopt(pycurl.PROXY) is None)
332 # Content-type is required for requests
333 headers = self.curl.getopt(pycurl.HTTPHEADER)
334 self.assert_("Content-type: application/json" in headers)
336 def assertHandler(self, handler_cls):
337 self.failUnless(isinstance(self.rapi.GetLastHandler(), handler_cls))
339 def assertQuery(self, key, value):
340 self.assertEqual(value, self.rapi.GetLastHandler().queryargs.get(key, None))
342 def assertItems(self, items):
343 self.assertEqual(items, self.rapi.GetLastHandler().items)
345 def assertBulk(self):
346 self.assertTrue(self.rapi.GetLastHandler().useBulk())
348 def assertDryRun(self):
349 self.assertTrue(self.rapi.GetLastHandler().dryRun())
351 def testEncodeQuery(self):
368 self.assertEqualValues(self.client._EncodeQuery(query),
372 for i in [[1, 2, 3], {"moo": "boo"}, (1, 2, 3)]:
373 self.assertRaises(ValueError, self.client._EncodeQuery, [("x", i)])
375 def testHttpError(self):
376 self.rapi.AddResponse(None, code=404)
378 self.client.GetJobStatus(15140)
379 except client.GanetiApiError, err:
380 self.assertEqual(err.code, 404)
382 self.fail("Didn't raise exception")
384 def testGetVersion(self):
385 self.client._version = None
386 self.rapi.AddResponse("2")
387 self.assertEqual(2, self.client.GetVersion())
388 self.assertHandler(rlib2.R_version)
390 def testGetFeatures(self):
391 for features in [[], ["foo", "bar", "baz"]]:
392 self.rapi.AddResponse(serializer.DumpJson(features))
393 self.assertEqual(features, self.client.GetFeatures())
394 self.assertHandler(rlib2.R_2_features)
396 def testGetFeaturesNotFound(self):
397 self.rapi.AddResponse(None, code=404)
398 self.assertEqual([], self.client.GetFeatures())
400 def testGetOperatingSystems(self):
401 self.rapi.AddResponse("[\"beos\"]")
402 self.assertEqual(["beos"], self.client.GetOperatingSystems())
403 self.assertHandler(rlib2.R_2_os)
405 def testGetClusterTags(self):
406 self.rapi.AddResponse("[\"tag\"]")
407 self.assertEqual(["tag"], self.client.GetClusterTags())
408 self.assertHandler(rlib2.R_2_tags)
410 def testAddClusterTags(self):
411 self.rapi.AddResponse("1234")
412 self.assertEqual(1234,
413 self.client.AddClusterTags(["awesome"], dry_run=True))
414 self.assertHandler(rlib2.R_2_tags)
416 self.assertQuery("tag", ["awesome"])
418 def testDeleteClusterTags(self):
419 self.rapi.AddResponse("5107")
420 self.assertEqual(5107, self.client.DeleteClusterTags(["awesome"],
422 self.assertHandler(rlib2.R_2_tags)
424 self.assertQuery("tag", ["awesome"])
426 def testGetInfo(self):
427 self.rapi.AddResponse("{}")
428 self.assertEqual({}, self.client.GetInfo())
429 self.assertHandler(rlib2.R_2_info)
431 def testGetInstances(self):
432 self.rapi.AddResponse("[]")
433 self.assertEqual([], self.client.GetInstances(bulk=True))
434 self.assertHandler(rlib2.R_2_instances)
437 def testGetInstance(self):
438 self.rapi.AddResponse("[]")
439 self.assertEqual([], self.client.GetInstance("instance"))
440 self.assertHandler(rlib2.R_2_instances_name)
441 self.assertItems(["instance"])
443 def testGetInstanceInfo(self):
444 self.rapi.AddResponse("21291")
445 self.assertEqual(21291, self.client.GetInstanceInfo("inst3"))
446 self.assertHandler(rlib2.R_2_instances_name_info)
447 self.assertItems(["inst3"])
448 self.assertQuery("static", None)
450 self.rapi.AddResponse("3428")
451 self.assertEqual(3428, self.client.GetInstanceInfo("inst31", static=False))
452 self.assertHandler(rlib2.R_2_instances_name_info)
453 self.assertItems(["inst31"])
454 self.assertQuery("static", ["0"])
456 self.rapi.AddResponse("15665")
457 self.assertEqual(15665, self.client.GetInstanceInfo("inst32", static=True))
458 self.assertHandler(rlib2.R_2_instances_name_info)
459 self.assertItems(["inst32"])
460 self.assertQuery("static", ["1"])
462 def testCreateInstanceOldVersion(self):
464 self.rapi.AddResponse(None, code=404)
465 self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
466 "create", "inst1.example.com", "plain", [], [])
467 self.assertEqual(self.rapi.CountPending(), 0)
470 self.rapi.AddResponse(None, code=404)
471 self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
472 "create", "inst1.example.com", "plain", [],
474 self.assertEqual(self.rapi.CountPending(), 0)
476 # Unsupported NIC fields
477 self.rapi.AddResponse(None, code=404)
478 self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
479 "create", "inst1.example.com", "plain", [],
480 [{"x": True, "y": False}])
481 self.assertEqual(self.rapi.CountPending(), 0)
483 # Unsupported disk fields
484 self.rapi.AddResponse(None, code=404)
485 self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
486 "create", "inst1.example.com", "plain",
487 [{}, {"moo": "foo",}], [{}])
488 self.assertEqual(self.rapi.CountPending(), 0)
491 self.rapi.AddResponse(None, code=404)
492 self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
493 "create", "inst1.example.com", "plain", [], [{}],
495 self.assertEqual(self.rapi.CountPending(), 0)
497 self.rapi.AddResponse(None, code=404)
498 self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
499 "create", "inst1.example.com", "plain", [], [{}],
501 self.assertEqual(self.rapi.CountPending(), 0)
506 [{ "mac": constants.VALUE_AUTO, }],
507 [{ "ip": "192.0.2.99", "mode": constants.NIC_MODE_ROUTED, }],
513 [{ "size": 321, }, { "size": 4096, }],
516 for idx, nics in enumerate(testnics):
517 for disks in testdisks:
519 constants.BE_MEMORY: 512,
520 constants.BE_AUTO_BALANCE: False,
523 constants.HV_MIGRATION_PORT: 9876,
524 constants.HV_VNC_TLS: True,
527 self.rapi.AddResponse(None, code=404)
528 self.rapi.AddResponse(serializer.DumpJson(3122617 + idx))
529 job_id = self.client.CreateInstance("create", "inst1.example.com",
530 "plain", disks, nics,
531 pnode="node99", dry_run=True,
534 self.assertEqual(job_id, 3122617 + idx)
535 self.assertHandler(rlib2.R_2_instances)
537 self.assertEqual(self.rapi.CountPending(), 0)
539 data = serializer.LoadJson(self.rapi.GetLastRequestData())
540 self.assertEqual(data["name"], "inst1.example.com")
541 self.assertEqual(data["disk_template"], "plain")
542 self.assertEqual(data["pnode"], "node99")
543 self.assertEqual(data[constants.BE_MEMORY], 512)
544 self.assertEqual(data[constants.BE_AUTO_BALANCE], False)
545 self.assertEqual(data[constants.HV_MIGRATION_PORT], 9876)
546 self.assertEqual(data[constants.HV_VNC_TLS], True)
547 self.assertEqual(data["disks"], [disk["size"] for disk in disks])
549 def testCreateInstance(self):
550 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
551 self.rapi.AddResponse("23030")
552 job_id = self.client.CreateInstance("create", "inst1.example.com",
553 "plain", [], [], dry_run=True)
554 self.assertEqual(job_id, 23030)
555 self.assertHandler(rlib2.R_2_instances)
558 data = serializer.LoadJson(self.rapi.GetLastRequestData())
560 for field in ["dry_run", "beparams", "hvparams", "start"]:
561 self.assertFalse(field in data)
563 self.assertEqual(data["name"], "inst1.example.com")
564 self.assertEqual(data["disk_template"], "plain")
566 def testCreateInstance2(self):
567 self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
568 self.rapi.AddResponse("24740")
569 job_id = self.client.CreateInstance("import", "inst2.example.com",
570 "drbd8", [{"size": 100,}],
571 [{}, {"bridge": "br1", }],
572 dry_run=False, start=True,
573 pnode="node1", snode="node9",
575 self.assertEqual(job_id, 24740)
576 self.assertHandler(rlib2.R_2_instances)
578 data = serializer.LoadJson(self.rapi.GetLastRequestData())
579 self.assertEqual(data[rlib2._REQ_DATA_VERSION], 1)
580 self.assertEqual(data["name"], "inst2.example.com")
581 self.assertEqual(data["disk_template"], "drbd8")
582 self.assertEqual(data["start"], True)
583 self.assertEqual(data["ip_check"], False)
584 self.assertEqualValues(data["disks"], [{"size": 100,}])
585 self.assertEqualValues(data["nics"], [{}, {"bridge": "br1", }])
587 def testDeleteInstance(self):
588 self.rapi.AddResponse("1234")
589 self.assertEqual(1234, self.client.DeleteInstance("instance", dry_run=True))
590 self.assertHandler(rlib2.R_2_instances_name)
591 self.assertItems(["instance"])
594 def testGetInstanceTags(self):
595 self.rapi.AddResponse("[]")
596 self.assertEqual([], self.client.GetInstanceTags("fooinstance"))
597 self.assertHandler(rlib2.R_2_instances_name_tags)
598 self.assertItems(["fooinstance"])
600 def testAddInstanceTags(self):
601 self.rapi.AddResponse("1234")
602 self.assertEqual(1234,
603 self.client.AddInstanceTags("fooinstance", ["awesome"], dry_run=True))
604 self.assertHandler(rlib2.R_2_instances_name_tags)
605 self.assertItems(["fooinstance"])
607 self.assertQuery("tag", ["awesome"])
609 def testDeleteInstanceTags(self):
610 self.rapi.AddResponse("25826")
611 self.assertEqual(25826, self.client.DeleteInstanceTags("foo", ["awesome"],
613 self.assertHandler(rlib2.R_2_instances_name_tags)
614 self.assertItems(["foo"])
616 self.assertQuery("tag", ["awesome"])
618 def testRebootInstance(self):
619 self.rapi.AddResponse("6146")
620 job_id = self.client.RebootInstance("i-bar", reboot_type="hard",
621 ignore_secondaries=True, dry_run=True)
622 self.assertEqual(6146, job_id)
623 self.assertHandler(rlib2.R_2_instances_name_reboot)
624 self.assertItems(["i-bar"])
626 self.assertQuery("type", ["hard"])
627 self.assertQuery("ignore_secondaries", ["1"])
629 def testShutdownInstance(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"])
637 def testStartupInstance(self):
638 self.rapi.AddResponse("27149")
639 self.assertEqual(27149, self.client.StartupInstance("bar-instance",
641 self.assertHandler(rlib2.R_2_instances_name_startup)
642 self.assertItems(["bar-instance"])
645 def testReinstallInstance(self):
646 self.rapi.AddResponse("19119")
647 self.assertEqual(19119, self.client.ReinstallInstance("baz-instance", "DOS",
649 self.assertHandler(rlib2.R_2_instances_name_reinstall)
650 self.assertItems(["baz-instance"])
651 self.assertQuery("os", ["DOS"])
652 self.assertQuery("nostartup", ["1"])
654 def testReplaceInstanceDisks(self):
655 self.rapi.AddResponse("999")
656 job_id = self.client.ReplaceInstanceDisks("instance-name",
657 disks=[0, 1], dry_run=True, iallocator="hail")
658 self.assertEqual(999, job_id)
659 self.assertHandler(rlib2.R_2_instances_name_replace_disks)
660 self.assertItems(["instance-name"])
661 self.assertQuery("disks", ["0,1"])
662 self.assertQuery("mode", ["replace_auto"])
663 self.assertQuery("iallocator", ["hail"])
666 self.rapi.AddResponse("1000")
667 job_id = self.client.ReplaceInstanceDisks("instance-bar",
668 disks=[1], mode="replace_on_secondary", remote_node="foo-node",
670 self.assertEqual(1000, job_id)
671 self.assertItems(["instance-bar"])
672 self.assertQuery("disks", ["1"])
673 self.assertQuery("remote_node", ["foo-node"])
676 self.rapi.AddResponse("5175")
677 self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
678 self.assertItems(["instance-moo"])
679 self.assertQuery("disks", None)
681 def testPrepareExport(self):
682 self.rapi.AddResponse("8326")
683 self.assertEqual(8326, self.client.PrepareExport("inst1", "local"))
684 self.assertHandler(rlib2.R_2_instances_name_prepare_export)
685 self.assertItems(["inst1"])
686 self.assertQuery("mode", ["local"])
688 def testExportInstance(self):
689 self.rapi.AddResponse("19695")
690 job_id = self.client.ExportInstance("inst2", "local", "nodeX",
692 self.assertEqual(job_id, 19695)
693 self.assertHandler(rlib2.R_2_instances_name_export)
694 self.assertItems(["inst2"])
696 data = serializer.LoadJson(self.rapi.GetLastRequestData())
697 self.assertEqual(data["mode"], "local")
698 self.assertEqual(data["destination"], "nodeX")
699 self.assertEqual(data["shutdown"], True)
701 def testGetJobs(self):
702 self.rapi.AddResponse('[ { "id": "123", "uri": "\\/2\\/jobs\\/123" },'
703 ' { "id": "124", "uri": "\\/2\\/jobs\\/124" } ]')
704 self.assertEqual([123, 124], self.client.GetJobs())
705 self.assertHandler(rlib2.R_2_jobs)
707 def testGetJobStatus(self):
708 self.rapi.AddResponse("{\"foo\": \"bar\"}")
709 self.assertEqual({"foo": "bar"}, self.client.GetJobStatus(1234))
710 self.assertHandler(rlib2.R_2_jobs_id)
711 self.assertItems(["1234"])
713 def testWaitForJobChange(self):
714 fields = ["id", "summary"]
716 "job_info": [123, "something"],
720 self.rapi.AddResponse(serializer.DumpJson(expected))
721 result = self.client.WaitForJobChange(123, fields, [], -1)
722 self.assertEqualValues(expected, result)
723 self.assertHandler(rlib2.R_2_jobs_id_wait)
724 self.assertItems(["123"])
726 def testCancelJob(self):
727 self.rapi.AddResponse("[true, \"Job 123 will be canceled\"]")
728 self.assertEqual([True, "Job 123 will be canceled"],
729 self.client.CancelJob(999, dry_run=True))
730 self.assertHandler(rlib2.R_2_jobs_id)
731 self.assertItems(["999"])
734 def testGetNodes(self):
735 self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
736 " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
737 self.assertEqual(["node1", "node2"], self.client.GetNodes())
738 self.assertHandler(rlib2.R_2_nodes)
740 self.rapi.AddResponse("[ { \"id\": \"node1\", \"uri\": \"uri1\" },"
741 " { \"id\": \"node2\", \"uri\": \"uri2\" } ]")
742 self.assertEqual([{"id": "node1", "uri": "uri1"},
743 {"id": "node2", "uri": "uri2"}],
744 self.client.GetNodes(bulk=True))
745 self.assertHandler(rlib2.R_2_nodes)
748 def testGetNode(self):
749 self.rapi.AddResponse("{}")
750 self.assertEqual({}, self.client.GetNode("node-foo"))
751 self.assertHandler(rlib2.R_2_nodes_name)
752 self.assertItems(["node-foo"])
754 def testEvacuateNode(self):
755 self.rapi.AddResponse("9876")
756 job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
757 self.assertEqual(9876, job_id)
758 self.assertHandler(rlib2.R_2_nodes_name_evacuate)
759 self.assertItems(["node-1"])
760 self.assertQuery("remote_node", ["node-2"])
762 self.rapi.AddResponse("8888")
763 job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True)
764 self.assertEqual(8888, job_id)
765 self.assertItems(["node-3"])
766 self.assertQuery("iallocator", ["hail"])
769 self.assertRaises(client.GanetiApiError,
770 self.client.EvacuateNode,
771 "node-4", iallocator="hail", remote_node="node-5")
773 def testMigrateNode(self):
774 self.rapi.AddResponse("1111")
775 self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
776 self.assertHandler(rlib2.R_2_nodes_name_migrate)
777 self.assertItems(["node-a"])
778 self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
781 self.rapi.AddResponse("1112")
782 self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
784 self.assertHandler(rlib2.R_2_nodes_name_migrate)
785 self.assertItems(["node-a"])
786 self.assertQuery("mode", ["live"])
789 def testGetNodeRole(self):
790 self.rapi.AddResponse("\"master\"")
791 self.assertEqual("master", self.client.GetNodeRole("node-a"))
792 self.assertHandler(rlib2.R_2_nodes_name_role)
793 self.assertItems(["node-a"])
795 def testSetNodeRole(self):
796 self.rapi.AddResponse("789")
797 self.assertEqual(789,
798 self.client.SetNodeRole("node-foo", "master-candidate", force=True))
799 self.assertHandler(rlib2.R_2_nodes_name_role)
800 self.assertItems(["node-foo"])
801 self.assertQuery("force", ["1"])
802 self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
804 def testGetNodeStorageUnits(self):
805 self.rapi.AddResponse("42")
807 self.client.GetNodeStorageUnits("node-x", "lvm-pv", "fields"))
808 self.assertHandler(rlib2.R_2_nodes_name_storage)
809 self.assertItems(["node-x"])
810 self.assertQuery("storage_type", ["lvm-pv"])
811 self.assertQuery("output_fields", ["fields"])
813 def testModifyNodeStorageUnits(self):
814 self.rapi.AddResponse("14")
816 self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda"))
817 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
818 self.assertItems(["node-z"])
819 self.assertQuery("storage_type", ["lvm-pv"])
820 self.assertQuery("name", ["hda"])
821 self.assertQuery("allocatable", None)
823 for allocatable, query_allocatable in [(True, "1"), (False, "0")]:
824 self.rapi.AddResponse("7205")
825 job_id = self.client.ModifyNodeStorageUnits("node-z", "lvm-pv", "hda",
826 allocatable=allocatable)
827 self.assertEqual(7205, job_id)
828 self.assertHandler(rlib2.R_2_nodes_name_storage_modify)
829 self.assertItems(["node-z"])
830 self.assertQuery("storage_type", ["lvm-pv"])
831 self.assertQuery("name", ["hda"])
832 self.assertQuery("allocatable", [query_allocatable])
834 def testRepairNodeStorageUnits(self):
835 self.rapi.AddResponse("99")
836 self.assertEqual(99, self.client.RepairNodeStorageUnits("node-z", "lvm-pv",
838 self.assertHandler(rlib2.R_2_nodes_name_storage_repair)
839 self.assertItems(["node-z"])
840 self.assertQuery("storage_type", ["lvm-pv"])
841 self.assertQuery("name", ["hda"])
843 def testGetNodeTags(self):
844 self.rapi.AddResponse("[\"fry\", \"bender\"]")
845 self.assertEqual(["fry", "bender"], self.client.GetNodeTags("node-k"))
846 self.assertHandler(rlib2.R_2_nodes_name_tags)
847 self.assertItems(["node-k"])
849 def testAddNodeTags(self):
850 self.rapi.AddResponse("1234")
851 self.assertEqual(1234,
852 self.client.AddNodeTags("node-v", ["awesome"], dry_run=True))
853 self.assertHandler(rlib2.R_2_nodes_name_tags)
854 self.assertItems(["node-v"])
856 self.assertQuery("tag", ["awesome"])
858 def testDeleteNodeTags(self):
859 self.rapi.AddResponse("16861")
860 self.assertEqual(16861, self.client.DeleteNodeTags("node-w", ["awesome"],
862 self.assertHandler(rlib2.R_2_nodes_name_tags)
863 self.assertItems(["node-w"])
865 self.assertQuery("tag", ["awesome"])
868 if __name__ == '__main__':
869 client.UsesRapiClient(testutils.GanetiTestProgram)()