#!/usr/bin/python
#
-# Copyright (C) 2010 Google Inc.
+# Copyright (C) 2010, 2011 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
"""Script for unittesting the RAPI client module"""
-import re
import unittest
import warnings
import pycurl
from ganeti import constants
from ganeti import http
from ganeti import serializer
+from ganeti import utils
+from ganeti import query
+from ganeti import objects
+from ganeti import rapi
+import ganeti.rapi.testutils
from ganeti.rapi import connector
from ganeti.rapi import rlib2
from ganeti.rapi import client
import testutils
-_URI_RE = re.compile(r"https://(?P<host>.*):(?P<port>\d+)(?P<path>/.*)")
+# List of resource handlers which aren't used by the RAPI client
+_KNOWN_UNUSED = set([
+ rlib2.R_root,
+ rlib2.R_2,
+ ])
-
-def _GetPathFromUri(uri):
- """Gets the path and query from a URI.
-
- """
- match = _URI_RE.match(uri)
- if match:
- return match.groupdict()["path"]
- else:
- return None
-
-
-class FakeCurl:
- def __init__(self, rapi):
- self._rapi = rapi
- self._opts = {}
- self._info = {}
-
- def setopt(self, opt, value):
- self._opts[opt] = value
-
- def getopt(self, opt):
- return self._opts.get(opt)
-
- def unsetopt(self, opt):
- self._opts.pop(opt, None)
-
- def getinfo(self, info):
- return self._info[info]
-
- def perform(self):
- method = self._opts[pycurl.CUSTOMREQUEST]
- url = self._opts[pycurl.URL]
- request_body = self._opts[pycurl.POSTFIELDS]
- writefn = self._opts[pycurl.WRITEFUNCTION]
-
- path = _GetPathFromUri(url)
- (code, resp_body) = self._rapi.FetchResponse(path, method, request_body)
-
- self._info[pycurl.RESPONSE_CODE] = code
- if resp_body is not None:
- writefn(resp_body)
+# Global variable for collecting used handlers
+_used_handlers = None
class RapiMock(object):
self._last_handler = None
self._last_req_data = None
+ def ResetResponses(self):
+ del self._responses[:]
+
def AddResponse(self, response, code=200):
self._responses.insert(0, (code, response))
def GetLastRequestData(self):
return self._last_req_data
- def FetchResponse(self, path, method, request_body):
+ def FetchResponse(self, path, method, headers, request_body):
self._last_req_data = request_body
try:
- HandlerClass, items, args = self._mapper.getController(path)
- self._last_handler = HandlerClass(items, args, None)
+ (handler_cls, items, args) = self._mapper.getController(path)
+
+ # Record handler as used
+ _used_handlers.add(handler_cls)
+
+ self._last_handler = handler_cls(items, args, None)
if not hasattr(self._last_handler, method.upper()):
raise http.HttpNotImplemented(message="Method not implemented")
self.assertEqual(client.GANETI_RAPI_VERSION, constants.RAPI_VERSION)
self.assertEqual(client.HTTP_APP_JSON, http.HTTP_APP_JSON)
self.assertEqual(client._REQ_DATA_VERSION_FIELD, rlib2._REQ_DATA_VERSION)
+ self.assertEqual(client.JOB_STATUS_QUEUED, constants.JOB_STATUS_QUEUED)
+ self.assertEqual(client.JOB_STATUS_WAITING, constants.JOB_STATUS_WAITING)
+ self.assertEqual(client.JOB_STATUS_CANCELING,
+ constants.JOB_STATUS_CANCELING)
+ self.assertEqual(client.JOB_STATUS_RUNNING, constants.JOB_STATUS_RUNNING)
+ self.assertEqual(client.JOB_STATUS_CANCELED, constants.JOB_STATUS_CANCELED)
+ self.assertEqual(client.JOB_STATUS_SUCCESS, constants.JOB_STATUS_SUCCESS)
+ self.assertEqual(client.JOB_STATUS_ERROR, constants.JOB_STATUS_ERROR)
+ self.assertEqual(client.JOB_STATUS_FINALIZED, constants.JOBS_FINALIZED)
+ self.assertEqual(client.JOB_STATUS_ALL, constants.JOB_STATUS_ALL)
+
+ # Node evacuation
+ self.assertEqual(client.NODE_EVAC_PRI, constants.NODE_EVAC_PRI)
+ self.assertEqual(client.NODE_EVAC_SEC, constants.NODE_EVAC_SEC)
+ self.assertEqual(client.NODE_EVAC_ALL, constants.NODE_EVAC_ALL)
+
+ # Legacy name
+ self.assertEqual(client.JOB_STATUS_WAITLOCK, constants.JOB_STATUS_WAITING)
+
+ # RAPI feature strings
self.assertEqual(client._INST_CREATE_REQV1, rlib2._INST_CREATE_REQV1)
+ self.assertEqual(client.INST_CREATE_REQV1, rlib2._INST_CREATE_REQV1)
self.assertEqual(client._INST_REINSTALL_REQV1, rlib2._INST_REINSTALL_REQV1)
- self.assertEqual(client._INST_NIC_PARAMS, constants.INIC_PARAMS)
+ self.assertEqual(client.INST_REINSTALL_REQV1, rlib2._INST_REINSTALL_REQV1)
+ self.assertEqual(client._NODE_MIGRATE_REQV1, rlib2._NODE_MIGRATE_REQV1)
+ self.assertEqual(client.NODE_MIGRATE_REQV1, rlib2._NODE_MIGRATE_REQV1)
+ self.assertEqual(client._NODE_EVAC_RES1, rlib2._NODE_EVAC_RES1)
+ self.assertEqual(client.NODE_EVAC_RES1, rlib2._NODE_EVAC_RES1)
class RapiMockTest(unittest.TestCase):
def test(self):
rapi = RapiMock()
path = "/version"
- self.assertEqual((404, None), rapi.FetchResponse("/foo", "GET", None))
+ self.assertEqual((404, None), rapi.FetchResponse("/foo", "GET", None, None))
self.assertEqual((501, "Method not implemented"),
- rapi.FetchResponse("/version", "POST", None))
+ rapi.FetchResponse("/version", "POST", None, None))
rapi.AddResponse("2")
- code, response = rapi.FetchResponse("/version", "GET", None)
+ code, response = rapi.FetchResponse("/version", "GET", None, None)
self.assertEqual(200, code)
self.assertEqual("2", response)
self.failUnless(isinstance(rapi.GetLastHandler(), rlib2.R_version))
class TestExtendedConfig(unittest.TestCase):
def testAuth(self):
cl = client.GanetiRapiClient("master.example.com",
- username="user", password="pw",
- curl_factory=lambda: FakeCurl(RapiMock()))
+ username="user", password="pw",
+ curl_factory=lambda: rapi.testutils.FakeCurl(RapiMock()))
curl = cl._CreateCurl()
self.assertEqual(curl.getopt(pycurl.HTTPAUTH), pycurl.HTTPAUTH_BASIC)
verify_hostname=verify_hostname,
_pycurl_version_fn=pcverfn)
- curl_factory = lambda: FakeCurl(RapiMock())
+ curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
cl = client.GanetiRapiClient("master.example.com",
curl_config_fn=cfgfn,
curl_factory=curl_factory)
def testNoCertVerify(self):
cfgfn = client.GenericCurlConfig()
- curl_factory = lambda: FakeCurl(RapiMock())
+ curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
curl_factory=curl_factory)
def testCertVerifyCurlBundle(self):
cfgfn = client.GenericCurlConfig(use_curl_cabundle=True)
- curl_factory = lambda: FakeCurl(RapiMock())
+ curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
curl_factory=curl_factory)
mycert = "/tmp/some/UNUSED/cert/file.pem"
cfgfn = client.GenericCurlConfig(cafile=mycert)
- curl_factory = lambda: FakeCurl(RapiMock())
+ curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
curl_factory=curl_factory)
cfgfn = client.GenericCurlConfig(capath=certdir,
_pycurl_version_fn=pcverfn)
- curl_factory = lambda: FakeCurl(RapiMock())
+ curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
curl_factory=curl_factory)
cfgfn = client.GenericCurlConfig(capath=certdir,
_pycurl_version_fn=pcverfn)
- curl_factory = lambda: FakeCurl(RapiMock())
+ curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
curl_factory=curl_factory)
cfgfn = client.GenericCurlConfig(capath=certdir,
_pycurl_version_fn=pcverfn)
- curl_factory = lambda: FakeCurl(RapiMock())
+ curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
curl_factory=curl_factory)
cfgfn = client.GenericCurlConfig(capath=certdir,
_pycurl_version_fn=pcverfn)
- curl_factory = lambda: FakeCurl(RapiMock())
+ curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
curl_factory=curl_factory)
cfgfn = client.GenericCurlConfig(connect_timeout=connect_timeout,
timeout=timeout)
- curl_factory = lambda: FakeCurl(RapiMock())
+ curl_factory = lambda: rapi.testutils.FakeCurl(RapiMock())
cl = client.GanetiRapiClient("master.example.com", curl_config_fn=cfgfn,
curl_factory=curl_factory)
testutils.GanetiTestCase.setUp(self)
self.rapi = RapiMock()
- self.curl = FakeCurl(self.rapi)
+ self.curl = rapi.testutils.FakeCurl(self.rapi)
self.client = client.GanetiRapiClient("master.example.com",
curl_factory=lambda: self.curl)
def assertDryRun(self):
self.assertTrue(self.rapi.GetLastHandler().dryRun())
+ def assertUseForce(self):
+ self.assertTrue(self.rapi.GetLastHandler().useForce())
+
def testEncodeQuery(self):
query = [
("a", None),
self.assertQuery("static", ["1"])
def testCreateInstanceOldVersion(self):
- # No NICs
+ # The old request format, version 0, is no longer supported
self.rapi.AddResponse(None, code=404)
self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
"create", "inst1.example.com", "plain", [], [])
self.assertEqual(self.rapi.CountPending(), 0)
- # More than one NIC
- self.rapi.AddResponse(None, code=404)
- self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
- "create", "inst1.example.com", "plain", [],
- [{}, {}, {}])
- self.assertEqual(self.rapi.CountPending(), 0)
-
- # Unsupported NIC fields
- self.rapi.AddResponse(None, code=404)
- self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
- "create", "inst1.example.com", "plain", [],
- [{"x": True, "y": False}])
- self.assertEqual(self.rapi.CountPending(), 0)
-
- # Unsupported disk fields
- self.rapi.AddResponse(None, code=404)
- self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
- "create", "inst1.example.com", "plain",
- [{}, {"moo": "foo",}], [{}])
- self.assertEqual(self.rapi.CountPending(), 0)
-
- # Unsupported fields
- self.rapi.AddResponse(None, code=404)
- self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
- "create", "inst1.example.com", "plain", [], [{}],
- hello_world=123)
- self.assertEqual(self.rapi.CountPending(), 0)
-
- self.rapi.AddResponse(None, code=404)
- self.assertRaises(client.GanetiApiError, self.client.CreateInstance,
- "create", "inst1.example.com", "plain", [], [{}],
- memory=128)
- self.assertEqual(self.rapi.CountPending(), 0)
-
- # Normal creation
- testnics = [
- [{}],
- [{ "mac": constants.VALUE_AUTO, }],
- [{ "ip": "192.0.2.99", "mode": constants.NIC_MODE_ROUTED, }],
- ]
-
- testdisks = [
- [],
- [{ "size": 128, }],
- [{ "size": 321, }, { "size": 4096, }],
- ]
-
- for idx, nics in enumerate(testnics):
- for disks in testdisks:
- beparams = {
- constants.BE_MEMORY: 512,
- constants.BE_AUTO_BALANCE: False,
- }
- hvparams = {
- constants.HV_MIGRATION_PORT: 9876,
- constants.HV_VNC_TLS: True,
- }
-
- self.rapi.AddResponse(None, code=404)
- self.rapi.AddResponse(serializer.DumpJson(3122617 + idx))
- job_id = self.client.CreateInstance("create", "inst1.example.com",
- "plain", disks, nics,
- pnode="node99", dry_run=True,
- hvparams=hvparams,
- beparams=beparams)
- self.assertEqual(job_id, 3122617 + idx)
- self.assertHandler(rlib2.R_2_instances)
- self.assertDryRun()
- self.assertEqual(self.rapi.CountPending(), 0)
-
- data = serializer.LoadJson(self.rapi.GetLastRequestData())
- self.assertEqual(data["name"], "inst1.example.com")
- self.assertEqual(data["disk_template"], "plain")
- self.assertEqual(data["pnode"], "node99")
- self.assertEqual(data[constants.BE_MEMORY], 512)
- self.assertEqual(data[constants.BE_AUTO_BALANCE], False)
- self.assertEqual(data[constants.HV_MIGRATION_PORT], 9876)
- self.assertEqual(data[constants.HV_VNC_TLS], True)
- self.assertEqual(data["disks"], [disk["size"] for disk in disks])
-
def testCreateInstance(self):
self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
self.rapi.AddResponse("23030")
def testReplaceInstanceDisks(self):
self.rapi.AddResponse("999")
job_id = self.client.ReplaceInstanceDisks("instance-name",
- disks=[0, 1], dry_run=True, iallocator="hail")
+ disks=[0, 1], iallocator="hail")
self.assertEqual(999, job_id)
self.assertHandler(rlib2.R_2_instances_name_replace_disks)
self.assertItems(["instance-name"])
self.assertQuery("disks", ["0,1"])
self.assertQuery("mode", ["replace_auto"])
self.assertQuery("iallocator", ["hail"])
- self.assertDryRun()
self.rapi.AddResponse("1000")
job_id = self.client.ReplaceInstanceDisks("instance-bar",
- disks=[1], mode="replace_on_secondary", remote_node="foo-node",
- dry_run=True)
+ disks=[1], mode="replace_on_secondary", remote_node="foo-node")
self.assertEqual(1000, job_id)
self.assertItems(["instance-bar"])
self.assertQuery("disks", ["1"])
self.assertQuery("remote_node", ["foo-node"])
- self.assertDryRun()
self.rapi.AddResponse("5175")
self.assertEqual(5175, self.client.ReplaceInstanceDisks("instance-moo"))
self.assertEqual(data["mode"], mode)
self.assertEqual(data["cleanup"], cleanup)
+ def testFailoverInstanceDefaults(self):
+ self.rapi.AddResponse("7639")
+ job_id = self.client.FailoverInstance("inst13579")
+ self.assertEqual(job_id, 7639)
+ self.assertHandler(rlib2.R_2_instances_name_failover)
+ self.assertItems(["inst13579"])
+
+ data = serializer.LoadJson(self.rapi.GetLastRequestData())
+ self.assertFalse(data)
+
+ def testFailoverInstance(self):
+ for iallocator in ["dumb", "hail"]:
+ for ignore_consistency in [False, True]:
+ for target_node in ["node-a", "node2"]:
+ self.rapi.AddResponse("19161")
+ job_id = \
+ self.client.FailoverInstance("inst251", iallocator=iallocator,
+ ignore_consistency=ignore_consistency,
+ target_node=target_node)
+ self.assertEqual(job_id, 19161)
+ self.assertHandler(rlib2.R_2_instances_name_failover)
+ self.assertItems(["inst251"])
+
+ data = serializer.LoadJson(self.rapi.GetLastRequestData())
+ self.assertEqual(len(data), 3)
+ self.assertEqual(data["iallocator"], iallocator)
+ self.assertEqual(data["ignore_consistency"], ignore_consistency)
+ self.assertEqual(data["target_node"], target_node)
+ self.assertEqual(self.rapi.CountPending(), 0)
+
def testRenameInstanceDefaults(self):
new_name = "newnametha7euqu"
self.rapi.AddResponse("8791")
self.assertItems(["node-foo"])
def testEvacuateNode(self):
+ self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
self.rapi.AddResponse("9876")
job_id = self.client.EvacuateNode("node-1", remote_node="node-2")
self.assertEqual(9876, job_id)
self.assertHandler(rlib2.R_2_nodes_name_evacuate)
self.assertItems(["node-1"])
- self.assertQuery("remote_node", ["node-2"])
+ self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
+ { "remote_node": "node-2", })
+ self.assertEqual(self.rapi.CountPending(), 0)
+ self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_EVAC_RES1]))
self.rapi.AddResponse("8888")
- job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True)
+ job_id = self.client.EvacuateNode("node-3", iallocator="hail", dry_run=True,
+ mode=constants.NODE_EVAC_ALL,
+ early_release=True)
self.assertEqual(8888, job_id)
self.assertItems(["node-3"])
- self.assertQuery("iallocator", ["hail"])
+ self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()), {
+ "iallocator": "hail",
+ "mode": "all",
+ "early_release": True,
+ })
self.assertDryRun()
self.assertRaises(client.GanetiApiError,
self.client.EvacuateNode,
"node-4", iallocator="hail", remote_node="node-5")
+ self.assertEqual(self.rapi.CountPending(), 0)
+
+ def testEvacuateNodeOldResponse(self):
+ self.rapi.AddResponse(serializer.DumpJson([]))
+ self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
+ "node-4", accept_old=False)
+ self.assertEqual(self.rapi.CountPending(), 0)
+
+ for mode in [client.NODE_EVAC_PRI, client.NODE_EVAC_ALL]:
+ self.rapi.AddResponse(serializer.DumpJson([]))
+ self.assertRaises(client.GanetiApiError, self.client.EvacuateNode,
+ "node-4", accept_old=True, mode=mode)
+ self.assertEqual(self.rapi.CountPending(), 0)
+
+ self.rapi.AddResponse(serializer.DumpJson([]))
+ self.rapi.AddResponse(serializer.DumpJson("21533"))
+ result = self.client.EvacuateNode("node-3", iallocator="hail",
+ dry_run=True, accept_old=True,
+ mode=client.NODE_EVAC_SEC,
+ early_release=True)
+ self.assertEqual(result, "21533")
+ self.assertItems(["node-3"])
+ self.assertQuery("iallocator", ["hail"])
+ self.assertQuery("early_release", ["1"])
+ self.assertFalse(self.rapi.GetLastRequestData())
+ self.assertDryRun()
+ self.assertEqual(self.rapi.CountPending(), 0)
def testMigrateNode(self):
+ self.rapi.AddResponse(serializer.DumpJson([]))
self.rapi.AddResponse("1111")
self.assertEqual(1111, self.client.MigrateNode("node-a", dry_run=True))
self.assertHandler(rlib2.R_2_nodes_name_migrate)
self.assertItems(["node-a"])
self.assert_("mode" not in self.rapi.GetLastHandler().queryargs)
self.assertDryRun()
+ self.assertFalse(self.rapi.GetLastRequestData())
+ self.rapi.AddResponse(serializer.DumpJson([]))
self.rapi.AddResponse("1112")
self.assertEqual(1112, self.client.MigrateNode("node-a", dry_run=True,
mode="live"))
self.assertItems(["node-a"])
self.assertQuery("mode", ["live"])
self.assertDryRun()
+ self.assertFalse(self.rapi.GetLastRequestData())
+
+ self.rapi.AddResponse(serializer.DumpJson([]))
+ self.assertRaises(client.GanetiApiError, self.client.MigrateNode,
+ "node-c", target_node="foonode")
+ self.assertEqual(self.rapi.CountPending(), 0)
+
+ def testMigrateNodeBodyData(self):
+ self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
+ self.rapi.AddResponse("27539")
+ self.assertEqual(27539, self.client.MigrateNode("node-a", dry_run=False,
+ mode="live"))
+ self.assertHandler(rlib2.R_2_nodes_name_migrate)
+ self.assertItems(["node-a"])
+ self.assertFalse(self.rapi.GetLastHandler().queryargs)
+ self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
+ { "mode": "live", })
+
+ self.rapi.AddResponse(serializer.DumpJson([rlib2._NODE_MIGRATE_REQV1]))
+ self.rapi.AddResponse("14219")
+ self.assertEqual(14219, self.client.MigrateNode("node-x", dry_run=True,
+ target_node="node9",
+ iallocator="ial"))
+ self.assertHandler(rlib2.R_2_nodes_name_migrate)
+ self.assertItems(["node-x"])
+ self.assertDryRun()
+ self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
+ { "target_node": "node9", "iallocator": "ial", })
+
+ self.assertEqual(self.rapi.CountPending(), 0)
def testGetNodeRole(self):
self.rapi.AddResponse("\"master\"")
self.assertQuery("force", ["1"])
self.assertEqual("\"master-candidate\"", self.rapi.GetLastRequestData())
+ def testPowercycleNode(self):
+ self.rapi.AddResponse("23051")
+ self.assertEqual(23051,
+ self.client.PowercycleNode("node5468", force=True))
+ self.assertHandler(rlib2.R_2_nodes_name_powercycle)
+ self.assertItems(["node5468"])
+ self.assertQuery("force", ["1"])
+ self.assertFalse(self.rapi.GetLastRequestData())
+ self.assertEqual(self.rapi.CountPending(), 0)
+
+ def testModifyNode(self):
+ self.rapi.AddResponse("3783")
+ job_id = self.client.ModifyNode("node16979.example.com", drained=True)
+ self.assertEqual(job_id, 3783)
+ self.assertHandler(rlib2.R_2_nodes_name_modify)
+ self.assertItems(["node16979.example.com"])
+ self.assertEqual(self.rapi.CountPending(), 0)
+
def testGetNodeStorageUnits(self):
self.rapi.AddResponse("42")
self.assertEqual(42,
self.assertEqual(job_id, 12347)
self.assertHandler(rlib2.R_2_groups_name_rename)
+ def testModifyGroup(self):
+ self.rapi.AddResponse("12348")
+ job_id = self.client.ModifyGroup("mygroup", alloc_policy="foo")
+ self.assertEqual(job_id, 12348)
+ self.assertHandler(rlib2.R_2_groups_name_modify)
+
+ def testAssignGroupNodes(self):
+ self.rapi.AddResponse("12349")
+ job_id = self.client.AssignGroupNodes("mygroup", ["node1", "node2"],
+ force=True, dry_run=True)
+ self.assertEqual(job_id, 12349)
+ self.assertHandler(rlib2.R_2_groups_name_assign_nodes)
+ self.assertDryRun()
+ self.assertUseForce()
+
+ def testModifyInstance(self):
+ self.rapi.AddResponse("23681")
+ job_id = self.client.ModifyInstance("inst7210", os_name="linux")
+ self.assertEqual(job_id, 23681)
+ self.assertItems(["inst7210"])
+ self.assertHandler(rlib2.R_2_instances_name_modify)
+ self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
+ { "os_name": "linux", })
+
def testModifyCluster(self):
for mnh in [None, False, True]:
self.rapi.AddResponse("14470")
self.assertEqual(data["maintain_node_health"], mnh)
self.assertEqual(self.rapi.CountPending(), 0)
+ def testRedistributeConfig(self):
+ self.rapi.AddResponse("3364")
+ job_id = self.client.RedistributeConfig()
+ self.assertEqual(job_id, 3364)
+ self.assertItems([])
+ self.assertHandler(rlib2.R_2_redist_config)
+
+ def testActivateInstanceDisks(self):
+ self.rapi.AddResponse("23547")
+ job_id = self.client.ActivateInstanceDisks("inst28204")
+ self.assertEqual(job_id, 23547)
+ self.assertItems(["inst28204"])
+ self.assertHandler(rlib2.R_2_instances_name_activate_disks)
+ self.assertFalse(self.rapi.GetLastHandler().queryargs)
+
+ def testActivateInstanceDisksIgnoreSize(self):
+ self.rapi.AddResponse("11044")
+ job_id = self.client.ActivateInstanceDisks("inst28204", ignore_size=True)
+ self.assertEqual(job_id, 11044)
+ self.assertItems(["inst28204"])
+ self.assertHandler(rlib2.R_2_instances_name_activate_disks)
+ self.assertQuery("ignore_size", ["1"])
+
+ def testDeactivateInstanceDisks(self):
+ self.rapi.AddResponse("14591")
+ job_id = self.client.DeactivateInstanceDisks("inst28234")
+ self.assertEqual(job_id, 14591)
+ self.assertItems(["inst28234"])
+ self.assertHandler(rlib2.R_2_instances_name_deactivate_disks)
+ self.assertFalse(self.rapi.GetLastHandler().queryargs)
+
+ def testRecreateInstanceDisks(self):
+ self.rapi.AddResponse("13553")
+ job_id = self.client.RecreateInstanceDisks("inst23153")
+ self.assertEqual(job_id, 13553)
+ self.assertItems(["inst23153"])
+ self.assertHandler(rlib2.R_2_instances_name_recreate_disks)
+ self.assertFalse(self.rapi.GetLastHandler().queryargs)
+
+ def testGetInstanceConsole(self):
+ self.rapi.AddResponse("26876")
+ job_id = self.client.GetInstanceConsole("inst21491")
+ self.assertEqual(job_id, 26876)
+ self.assertItems(["inst21491"])
+ self.assertHandler(rlib2.R_2_instances_name_console)
+ self.assertFalse(self.rapi.GetLastHandler().queryargs)
+ self.assertFalse(self.rapi.GetLastRequestData())
+
def testGrowInstanceDisk(self):
for idx, wait_for_sync in enumerate([None, False, True]):
amount = 128 + (512 * idx)
self.assertEqual(data["amount"], amount)
self.assertEqual(self.rapi.CountPending(), 0)
+ def testGetGroupTags(self):
+ self.rapi.AddResponse("[]")
+ self.assertEqual([], self.client.GetGroupTags("fooGroup"))
+ self.assertHandler(rlib2.R_2_groups_name_tags)
+ self.assertItems(["fooGroup"])
+
+ def testAddGroupTags(self):
+ self.rapi.AddResponse("1234")
+ self.assertEqual(1234,
+ self.client.AddGroupTags("fooGroup", ["awesome"], dry_run=True))
+ self.assertHandler(rlib2.R_2_groups_name_tags)
+ self.assertItems(["fooGroup"])
+ self.assertDryRun()
+ self.assertQuery("tag", ["awesome"])
+
+ def testDeleteGroupTags(self):
+ self.rapi.AddResponse("25826")
+ self.assertEqual(25826, self.client.DeleteGroupTags("foo", ["awesome"],
+ dry_run=True))
+ self.assertHandler(rlib2.R_2_groups_name_tags)
+ self.assertItems(["foo"])
+ self.assertDryRun()
+ self.assertQuery("tag", ["awesome"])
+
+ def testQuery(self):
+ for idx, what in enumerate(constants.QR_VIA_RAPI):
+ for idx2, qfilter in enumerate([None, ["?", "name"]]):
+ job_id = 11010 + (idx << 4) + (idx2 << 16)
+ fields = sorted(query.ALL_FIELDS[what].keys())[:10]
+
+ self.rapi.AddResponse(str(job_id))
+ self.assertEqual(self.client.Query(what, fields, qfilter=qfilter),
+ job_id)
+ self.assertItems([what])
+ self.assertHandler(rlib2.R_2_query)
+ self.assertFalse(self.rapi.GetLastHandler().queryargs)
+ data = serializer.LoadJson(self.rapi.GetLastRequestData())
+ self.assertEqual(data["fields"], fields)
+ if qfilter is None:
+ self.assertTrue("qfilter" not in data)
+ else:
+ self.assertEqual(data["qfilter"], qfilter)
+ self.assertEqual(self.rapi.CountPending(), 0)
+
+ def testQueryFields(self):
+ exp_result = objects.QueryFieldsResponse(fields=[
+ objects.QueryFieldDefinition(name="pnode", title="PNode",
+ kind=constants.QFT_NUMBER),
+ objects.QueryFieldDefinition(name="other", title="Other",
+ kind=constants.QFT_BOOL),
+ ])
+
+ for what in constants.QR_VIA_RAPI:
+ for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
+ self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
+ result = self.client.QueryFields(what, fields=fields)
+ self.assertItems([what])
+ self.assertHandler(rlib2.R_2_query_fields)
+ self.assertFalse(self.rapi.GetLastRequestData())
+
+ queryargs = self.rapi.GetLastHandler().queryargs
+ if fields is None:
+ self.assertFalse(queryargs)
+ else:
+ self.assertEqual(queryargs, {
+ "fields": [",".join(fields)],
+ })
+
+ self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
+ exp_result.ToDict())
+
+ self.assertEqual(self.rapi.CountPending(), 0)
+
+ def testWaitForJobCompletionNoChange(self):
+ resp = serializer.DumpJson({
+ "status": constants.JOB_STATUS_WAITING,
+ })
+
+ for retries in [1, 5, 25]:
+ for _ in range(retries):
+ self.rapi.AddResponse(resp)
+
+ self.assertFalse(self.client.WaitForJobCompletion(22789, period=None,
+ retries=retries))
+ self.assertHandler(rlib2.R_2_jobs_id)
+ self.assertItems(["22789"])
+
+ self.assertEqual(self.rapi.CountPending(), 0)
+
+ def testWaitForJobCompletionAlreadyFinished(self):
+ self.rapi.AddResponse(serializer.DumpJson({
+ "status": constants.JOB_STATUS_SUCCESS,
+ }))
+
+ self.assertTrue(self.client.WaitForJobCompletion(22793, period=None,
+ retries=1))
+ self.assertHandler(rlib2.R_2_jobs_id)
+ self.assertItems(["22793"])
+
+ self.assertEqual(self.rapi.CountPending(), 0)
+
+ def testWaitForJobCompletionEmptyResponse(self):
+ self.rapi.AddResponse("{}")
+ self.assertFalse(self.client.WaitForJobCompletion(22793, period=None,
+ retries=10))
+ self.assertHandler(rlib2.R_2_jobs_id)
+ self.assertItems(["22793"])
+
+ self.assertEqual(self.rapi.CountPending(), 0)
+
+ def testWaitForJobCompletionOutOfRetries(self):
+ for retries in [3, 10, 21]:
+ for _ in range(retries):
+ self.rapi.AddResponse(serializer.DumpJson({
+ "status": constants.JOB_STATUS_RUNNING,
+ }))
+
+ self.assertFalse(self.client.WaitForJobCompletion(30948, period=None,
+ retries=retries - 1))
+ self.assertHandler(rlib2.R_2_jobs_id)
+ self.assertItems(["30948"])
+
+ self.assertEqual(self.rapi.CountPending(), 1)
+ self.rapi.ResetResponses()
+
+ def testWaitForJobCompletionSuccessAndFailure(self):
+ for retries in [1, 4, 13]:
+ for (success, end_status) in [(False, constants.JOB_STATUS_ERROR),
+ (True, constants.JOB_STATUS_SUCCESS)]:
+ for _ in range(retries):
+ self.rapi.AddResponse(serializer.DumpJson({
+ "status": constants.JOB_STATUS_RUNNING,
+ }))
+
+ self.rapi.AddResponse(serializer.DumpJson({
+ "status": end_status,
+ }))
+
+ result = self.client.WaitForJobCompletion(3187, period=None,
+ retries=retries + 1)
+ self.assertEqual(result, success)
+ self.assertHandler(rlib2.R_2_jobs_id)
+ self.assertItems(["3187"])
+
+ self.assertEqual(self.rapi.CountPending(), 0)
+
+
+class RapiTestRunner(unittest.TextTestRunner):
+ def run(self, *args):
+ global _used_handlers
+ assert _used_handlers is None
+
+ _used_handlers = set()
+ try:
+ # Run actual tests
+ result = unittest.TextTestRunner.run(self, *args)
+
+ diff = (set(connector.CONNECTOR.values()) - _used_handlers -
+ _KNOWN_UNUSED)
+ if diff:
+ raise AssertionError("The following RAPI resources were not used by the"
+ " RAPI client: %r" % utils.CommaJoin(diff))
+ finally:
+ # Reset global variable
+ _used_handlers = None
+
+ return result
+
if __name__ == '__main__':
- client.UsesRapiClient(testutils.GanetiTestProgram)()
+ client.UsesRapiClient(testutils.GanetiTestProgram)(testRunner=RapiTestRunner)