Skip to content
Snippets Groups Projects
Commit e23881ed authored by Michael Hanselmann's avatar Michael Hanselmann
Browse files

RAPI: Add resource to grow instance disk


Signed-off-by: default avatarMichael Hanselmann <hansmi@google.com>
Reviewed-by: default avatarIustin Pop <iustin@google.com>
parent b714765a
No related branches found
No related tags found
No related merge requests found
...@@ -824,6 +824,26 @@ It supports the following commands: ``PUT``. ...@@ -824,6 +824,26 @@ It supports the following commands: ``PUT``.
Takes no parameters. Takes no parameters.
``/2/instances/[instance_name]/disk/[disk_index]/grow``
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Grows one disk of an instance.
Supports the following commands: ``POST``.
``POST``
~~~~~~~~
Returns a job ID.
Body parameters:
``amount`` (int, required)
Amount of disk space to add.
``wait_for_sync`` (bool)
Whether to wait for the disk to synchronize.
``/2/instances/[instance_name]/prepare-export`` ``/2/instances/[instance_name]/prepare-export``
+++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++
......
...@@ -757,6 +757,35 @@ class GanetiRapiClient(object): ...@@ -757,6 +757,35 @@ class GanetiRapiClient(object):
("/%s/instances/%s/modify" % ("/%s/instances/%s/modify" %
(GANETI_RAPI_VERSION, instance)), None, body) (GANETI_RAPI_VERSION, instance)), None, body)
def GrowInstanceDisk(self, instance, disk, amount, wait_for_sync=None):
"""Grows a disk of an instance.
More details for parameters can be found in the RAPI documentation.
@type instance: string
@param instance: Instance name
@type disk: integer
@param disk: Disk index
@type amount: integer
@param amount: Grow disk by this amount (MiB)
@type wait_for_sync: bool
@param wait_for_sync: Wait for disk to synchronize
@rtype: int
@return: job id
"""
body = {
"amount": amount,
}
if wait_for_sync is not None:
body["wait_for_sync"] = wait_for_sync
return self._SendRequest(HTTP_POST,
("/%s/instances/%s/disk/%s/grow" %
(GANETI_RAPI_VERSION, instance, disk)),
None, body)
def GetInstanceTags(self, instance): def GetInstanceTags(self, instance):
"""Gets tags for an instance. """Gets tags for an instance.
......
...@@ -38,6 +38,7 @@ from ganeti.rapi import rlib2 ...@@ -38,6 +38,7 @@ from ganeti.rapi import rlib2
_NAME_PATTERN = r"[\w\._-]+" _NAME_PATTERN = r"[\w\._-]+"
_DISK_PATTERN = r"\d+"
# the connection map is created at the end of this file # the connection map is created at the end of this file
CONNECTOR = {} CONNECTOR = {}
...@@ -147,7 +148,7 @@ class R_2(baserlib.R_Generic): ...@@ -147,7 +148,7 @@ class R_2(baserlib.R_Generic):
def GetHandlers(node_name_pattern, instance_name_pattern, def GetHandlers(node_name_pattern, instance_name_pattern,
group_name_pattern, job_id_pattern): group_name_pattern, job_id_pattern, disk_pattern):
"""Returns all supported resources and their handlers. """Returns all supported resources and their handlers.
""" """
...@@ -211,6 +212,9 @@ def GetHandlers(node_name_pattern, instance_name_pattern, ...@@ -211,6 +212,9 @@ def GetHandlers(node_name_pattern, instance_name_pattern,
rlib2.R_2_instances_name_rename, rlib2.R_2_instances_name_rename,
re.compile(r'^/2/instances/(%s)/modify$' % instance_name_pattern): re.compile(r'^/2/instances/(%s)/modify$' % instance_name_pattern):
rlib2.R_2_instances_name_modify, rlib2.R_2_instances_name_modify,
re.compile(r"^/2/instances/(%s)/disk/(%s)/grow$" %
(instance_name_pattern, disk_pattern)):
rlib2.R_2_instances_name_disk_grow,
"/2/groups": rlib2.R_2_groups, "/2/groups": rlib2.R_2_groups,
re.compile(r'^/2/groups/(%s)$' % group_name_pattern): re.compile(r'^/2/groups/(%s)$' % group_name_pattern):
...@@ -236,4 +240,4 @@ def GetHandlers(node_name_pattern, instance_name_pattern, ...@@ -236,4 +240,4 @@ def GetHandlers(node_name_pattern, instance_name_pattern,
CONNECTOR.update(GetHandlers(_NAME_PATTERN, _NAME_PATTERN, _NAME_PATTERN, CONNECTOR.update(GetHandlers(_NAME_PATTERN, _NAME_PATTERN, _NAME_PATTERN,
constants.JOB_ID_TEMPLATE)) constants.JOB_ID_TEMPLATE, _DISK_PATTERN))
...@@ -1299,6 +1299,24 @@ class R_2_instances_name_modify(baserlib.R_Generic): ...@@ -1299,6 +1299,24 @@ class R_2_instances_name_modify(baserlib.R_Generic):
return baserlib.SubmitJob([op]) return baserlib.SubmitJob([op])
class R_2_instances_name_disk_grow(baserlib.R_Generic):
"""/2/instances/[instance_name]/disk/[index]/grow resource.
"""
def POST(self):
"""Increases the size of an instance disk.
@return: a job id
"""
op = baserlib.FillOpcode(opcodes.OpGrowDisk, self.request_body, {
"instance_name": self.items[0],
"disk": int(self.items[1]),
})
return baserlib.SubmitJob([op])
class _R_Tags(baserlib.R_Generic): class _R_Tags(baserlib.R_Generic):
""" Quasiclass for tagging resources """ Quasiclass for tagging resources
......
...@@ -79,11 +79,13 @@ class TestDocs(unittest.TestCase): ...@@ -79,11 +79,13 @@ class TestDocs(unittest.TestCase):
instance_name = "[instance_name]" instance_name = "[instance_name]"
group_name = "[group_name]" group_name = "[group_name]"
job_id = "[job_id]" job_id = "[job_id]"
disk_index = "[disk_index]"
resources = connector.GetHandlers(re.escape(node_name), resources = connector.GetHandlers(re.escape(node_name),
re.escape(instance_name), re.escape(instance_name),
re.escape(group_name), re.escape(group_name),
re.escape(job_id)) re.escape(job_id),
re.escape(disk_index))
titles = [] titles = []
......
...@@ -1051,6 +1051,26 @@ class GanetiRapiClientTests(testutils.GanetiTestCase): ...@@ -1051,6 +1051,26 @@ class GanetiRapiClientTests(testutils.GanetiTestCase):
self.assertEqual(data["maintain_node_health"], mnh) self.assertEqual(data["maintain_node_health"], mnh)
self.assertEqual(self.rapi.CountPending(), 0) self.assertEqual(self.rapi.CountPending(), 0)
def testGrowInstanceDisk(self):
for idx, wait_for_sync in enumerate([None, False, True]):
amount = 128 + (512 * idx)
self.assertEqual(self.rapi.CountPending(), 0)
self.rapi.AddResponse("30783")
self.assertEqual(30783,
self.client.GrowInstanceDisk("eze8ch", idx, amount,
wait_for_sync=wait_for_sync))
self.assertHandler(rlib2.R_2_instances_name_disk_grow)
self.assertItems(["eze8ch", str(idx)])
data = serializer.LoadJson(self.rapi.GetLastRequestData())
if wait_for_sync is None:
self.assertEqual(len(data), 1)
self.assert_("wait_for_sync" not in data)
else:
self.assertEqual(len(data), 2)
self.assertEqual(data["wait_for_sync"], wait_for_sync)
self.assertEqual(data["amount"], amount)
self.assertEqual(self.rapi.CountPending(), 0)
if __name__ == '__main__': if __name__ == '__main__':
client.UsesRapiClient(testutils.GanetiTestProgram)() client.UsesRapiClient(testutils.GanetiTestProgram)()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment