Commit 8a47b447 authored by Michael Hanselmann's avatar Michael Hanselmann

RAPI client: Implement instance creation

Currently this only supports the new instance creation request data
format version 1, but support for the old version can be easily
implemented.

Most arguments are optional and documented in the RAPI documentation.
Signed-off-by: default avatarMichael Hanselmann <hansmi@google.com>
Reviewed-by: default avatarGuido Trotter <ultrotter@google.com>
parent 6395cebb
......@@ -56,6 +56,10 @@ NODE_ROLE_MASTER = "master"
NODE_ROLE_OFFLINE = "offline"
NODE_ROLE_REGULAR = "regular"
# Internal constants
_REQ_DATA_VERSION_FIELD = "__version__"
_INST_CREATE_REQV1 = "instance-create-reqv1"
class Error(Exception):
"""Base error class for this module.
......@@ -555,23 +559,64 @@ class GanetiRapiClient(object):
("/%s/instances/%s" %
(GANETI_RAPI_VERSION, instance)), None, None)
def CreateInstance(self, dry_run=False):
def CreateInstance(self, mode, name, disk_template, disks, nics,
**kwargs):
"""Creates a new instance.
More details for parameters can be found in the RAPI documentation.
@type mode: string
@param mode: Instance creation mode
@type name: string
@param name: Hostname of the instance to create
@type disk_template: string
@param disk_template: Disk template for instance (e.g. plain, diskless,
file, or drbd)
@type disks: list of dicts
@param disks: List of disk definitions
@type nics: list of dicts
@param nics: List of NIC definitions
@type dry_run: bool
@param dry_run: whether to perform a dry run
@keyword dry_run: whether to perform a dry run
@rtype: int
@return: job id
"""
# TODO: Pass arguments needed to actually create an instance.
query = []
if dry_run:
if kwargs.get("dry_run"):
query.append(("dry-run", 1))
if _INST_CREATE_REQV1 in self.GetFeatures():
# All required fields for request data version 1
body = {
_REQ_DATA_VERSION_FIELD: 1,
"mode": mode,
"name": name,
"disk_template": disk_template,
"disks": disks,
"nics": nics,
}
conflicts = set(kwargs.iterkeys()) & set(body.iterkeys())
if conflicts:
raise GanetiApiError("Required fields can not be specified as"
" keywords: %s" % ", ".join(conflicts))
body.update((key, value) for key, value in kwargs.iteritems()
if key != "dry_run")
else:
# TODO: Implement instance creation request data version 0
# When implementing version 0, care should be taken to refuse unknown
# parameters and invalid values. The interface of this function must stay
# exactly the same for version 0 and 1 (e.g. they aren't allowed to
# require different data types).
raise NotImplementedError("Support for instance creation request data"
" version 0 is not yet implemented")
return self._SendRequest(HTTP_POST, "/%s/instances" % GANETI_RAPI_VERSION,
query, None)
query, body)
def DeleteInstance(self, instance, dry_run=False):
"""Deletes an instance.
......
......@@ -239,12 +239,50 @@ class GanetiRapiClientTests(testutils.GanetiTestCase):
self.assertHandler(rlib2.R_2_instances_name)
self.assertItems(["instance"])
def testCreateInstanceOldVersion(self):
self.rapi.AddResponse(serializer.DumpJson([]))
self.assertRaises(NotImplementedError, self.client.CreateInstance,
"create", "inst1.example.com", "plain", [], [],
dry_run=True)
def testCreateInstance(self):
self.rapi.AddResponse("1234")
self.assertEqual(1234, self.client.CreateInstance(dry_run=True))
self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
self.rapi.AddResponse("23030")
job_id = self.client.CreateInstance("create", "inst1.example.com",
"plain", [], [], dry_run=True)
self.assertEqual(job_id, 23030)
self.assertHandler(rlib2.R_2_instances)
self.assertDryRun()
data = serializer.LoadJson(self.http.last_request.data)
for field in ["dry_run", "beparams", "hvparams", "start"]:
self.assertFalse(field in data)
self.assertEqual(data["name"], "inst1.example.com")
self.assertEqual(data["disk_template"], "plain")
def testCreateInstance2(self):
self.rapi.AddResponse(serializer.DumpJson([rlib2._INST_CREATE_REQV1]))
self.rapi.AddResponse("24740")
job_id = self.client.CreateInstance("import", "inst2.example.com",
"drbd8", [{"size": 100,}],
[{}, {"bridge": "br1", }],
dry_run=False, start=True,
pnode="node1", snode="node9",
ip_check=False)
self.assertEqual(job_id, 24740)
self.assertHandler(rlib2.R_2_instances)
data = serializer.LoadJson(self.http.last_request.data)
self.assertEqual(data[rlib2._REQ_DATA_VERSION], 1)
self.assertEqual(data["name"], "inst2.example.com")
self.assertEqual(data["disk_template"], "drbd8")
self.assertEqual(data["start"], True)
self.assertEqual(data["ip_check"], False)
self.assertEqualValues(data["disks"], [{"size": 100,}])
self.assertEqualValues(data["nics"], [{}, {"bridge": "br1", }])
def testDeleteInstance(self):
self.rapi.AddResponse("1234")
self.assertEqual(1234, self.client.DeleteInstance("instance", dry_run=True))
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment