From a52978c71b8f86c6854dd946ec66325e772e804f Mon Sep 17 00:00:00 2001
From: Michael Hanselmann <hansmi@google.com>
Date: Thu, 15 Sep 2011 17:41:59 +0200
Subject: [PATCH] RAPI: Add resource to recreate instance's disks

This was still missing from RAPI.

Signed-off-by: Michael Hanselmann <hansmi@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>
---
 doc/rapi.rst                        | 17 +++++++++++++++++
 lib/opcodes.py                      |  2 +-
 lib/rapi/client.py                  | 25 +++++++++++++++++++++++++
 lib/rapi/connector.py               |  2 ++
 lib/rapi/rlib2.py                   | 15 +++++++++++++++
 test/docs_unittest.py               |  1 -
 test/ganeti.rapi.client_unittest.py |  8 ++++++++
 test/ganeti.rapi.rlib2_unittest.py  | 20 ++++++++++++++++++++
 8 files changed, 88 insertions(+), 2 deletions(-)

diff --git a/doc/rapi.rst b/doc/rapi.rst
index efb4a4b5e..20602b052 100644
--- a/doc/rapi.rst
+++ b/doc/rapi.rst
@@ -811,6 +811,23 @@ It supports the following commands: ``PUT``.
 Takes no parameters.
 
 
+``/2/instances/[instance_name]/recreate-disks``
++++++++++++++++++++++++++++++++++++++++++++++++++
+
+Recreate disks of an instance. Supports the following commands:
+``POST``.
+
+``POST``
+~~~~~~~~
+
+Returns a job ID.
+
+Body parameters:
+
+.. opcode_params:: OP_INSTANCE_RECREATE_DISKS
+   :exclude: instance_name
+
+
 ``/2/instances/[instance_name]/disk/[disk_index]/grow``
 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
diff --git a/lib/opcodes.py b/lib/opcodes.py
index 36104f7c7..6b2f1870b 100644
--- a/lib/opcodes.py
+++ b/lib/opcodes.py
@@ -1268,7 +1268,7 @@ class OpInstanceDeactivateDisks(OpCode):
 
 
 class OpInstanceRecreateDisks(OpCode):
-  """Deactivate an instance's disks."""
+  """Recreate an instance's disks."""
   OP_DSC_FIELD = "instance_name"
   OP_PARAMS = [
     _PInstanceName,
diff --git a/lib/rapi/client.py b/lib/rapi/client.py
index dac670b1b..8ad0d95a1 100644
--- a/lib/rapi/client.py
+++ b/lib/rapi/client.py
@@ -753,6 +753,31 @@ class GanetiRapiClient(object): # pylint: disable=R0904
                              ("/%s/instances/%s/deactivate-disks" %
                               (GANETI_RAPI_VERSION, instance)), None, None)
 
+  def RecreateInstanceDisks(self, instance, disks=None, nodes=None):
+    """Recreate an instance's disks.
+
+    @type instance: string
+    @param instance: Instance name
+    @type disks: list of int
+    @param disks: List of disk indexes
+    @type nodes: list of string
+    @param nodes: New instance nodes, if relocation is desired
+    @rtype: string
+    @return: job id
+
+    """
+    body = {}
+
+    if disks is not None:
+      body["disks"] = disks
+
+    if nodes is not None:
+      body["nodes"] = nodes
+
+    return self._SendRequest(HTTP_POST,
+                             ("/%s/instances/%s/recreate-disks" %
+                              (GANETI_RAPI_VERSION, instance)), None, body)
+
   def GrowInstanceDisk(self, instance, disk, amount, wait_for_sync=None):
     """Grows a disk of an instance.
 
diff --git a/lib/rapi/connector.py b/lib/rapi/connector.py
index d8524efad..8d0d3951a 100644
--- a/lib/rapi/connector.py
+++ b/lib/rapi/connector.py
@@ -143,6 +143,8 @@ def GetHandlers(node_name_pattern, instance_name_pattern,
       rlib2.R_2_instances_name_activate_disks,
     re.compile(r"^/2/instances/(%s)/deactivate-disks$" % instance_name_pattern):
       rlib2.R_2_instances_name_deactivate_disks,
+    re.compile(r"^/2/instances/(%s)/recreate-disks$" % instance_name_pattern):
+      rlib2.R_2_instances_name_recreate_disks,
     re.compile(r"^/2/instances/(%s)/prepare-export$" % instance_name_pattern):
       rlib2.R_2_instances_name_prepare_export,
     re.compile(r"^/2/instances/(%s)/export$" % instance_name_pattern):
diff --git a/lib/rapi/rlib2.py b/lib/rapi/rlib2.py
index 76d640b12..0d4f29ab3 100644
--- a/lib/rapi/rlib2.py
+++ b/lib/rapi/rlib2.py
@@ -995,6 +995,21 @@ class R_2_instances_name_deactivate_disks(baserlib.OpcodeResource):
       })
 
 
+class R_2_instances_name_recreate_disks(baserlib.OpcodeResource):
+  """/2/instances/[instance_name]/recreate-disks resource.
+
+  """
+  POST_OPCODE = opcodes.OpInstanceRecreateDisks
+
+  def GetPostOpInput(self):
+    """Recreate disks for an instance.
+
+    """
+    return ({}, {
+      "instance_name": self.items[0],
+      })
+
+
 class R_2_instances_name_prepare_export(baserlib.OpcodeResource):
   """/2/instances/[instance_name]/prepare-export resource.
 
diff --git a/test/docs_unittest.py b/test/docs_unittest.py
index 1815805d2..a695280a7 100755
--- a/test/docs_unittest.py
+++ b/test/docs_unittest.py
@@ -53,7 +53,6 @@ RAPI_OPCODE_EXCLUDE = frozenset([
   opcodes.OpClusterVerifyDisks,
   opcodes.OpInstanceChangeGroup,
   opcodes.OpInstanceMove,
-  opcodes.OpInstanceRecreateDisks,
   opcodes.OpNodePowercycle,
   opcodes.OpNodeQueryvols,
   opcodes.OpOobCommand,
diff --git a/test/ganeti.rapi.client_unittest.py b/test/ganeti.rapi.client_unittest.py
index 2d17df877..81d6ea6da 100755
--- a/test/ganeti.rapi.client_unittest.py
+++ b/test/ganeti.rapi.client_unittest.py
@@ -1166,6 +1166,14 @@ class GanetiRapiClientTests(testutils.GanetiTestCase):
     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")
diff --git a/test/ganeti.rapi.rlib2_unittest.py b/test/ganeti.rapi.rlib2_unittest.py
index 58127e4f8..74176adc1 100755
--- a/test/ganeti.rapi.rlib2_unittest.py
+++ b/test/ganeti.rapi.rlib2_unittest.py
@@ -446,6 +446,26 @@ class TestInstanceDeactivateDisks(unittest.TestCase):
     self.assertRaises(IndexError, cl.GetNextSubmittedJob)
 
 
+class TestInstanceRecreateDisks(unittest.TestCase):
+  def test(self):
+    clfactory = _FakeClientFactory(_FakeClient)
+    handler = _CreateHandler(rlib2.R_2_instances_name_recreate_disks,
+                             ["inst22357"], {}, {}, clfactory)
+    job_id = handler.POST()
+
+    cl = clfactory.GetNextClient()
+    self.assertRaises(IndexError, clfactory.GetNextClient)
+
+    (exp_job_id, (op, )) = cl.GetNextSubmittedJob()
+    self.assertEqual(job_id, exp_job_id)
+    self.assertTrue(isinstance(op, opcodes.OpInstanceRecreateDisks))
+    self.assertEqual(op.instance_name, "inst22357")
+    self.assertFalse(hasattr(op, "dry_run"))
+    self.assertFalse(hasattr(op, "force"))
+
+    self.assertRaises(IndexError, cl.GetNextSubmittedJob)
+
+
 class TestInstanceFailover(unittest.TestCase):
   def test(self):
     clfactory = _FakeClientFactory(_FakeClient)
-- 
GitLab