Introduce a new RPC call named 'blockdev_convert'. This method uses the
'backend.BlockdevConvert' function which takes as arguments the source
and target disks between which we will perform the actual data copy of
their contents.

This method first gets the export and import commands from the source
and target devices respectively, and then concatenates them to a unified
command using a pipe ("|"), following a similar approach with the impexp
daemon. Finally, the unified command is executed by this method.

Signed-off-by: Dimitris Bliablias <[email protected]>
---
 lib/backend.py      |   38 ++++++++++++++++++++++++++++++++++++++
 lib/rpc_defs.py     |    5 +++++
 lib/server/noded.py |   10 ++++++++++
 3 files changed, 53 insertions(+)

diff --git a/lib/backend.py b/lib/backend.py
index 26b6a2e..f74cac9 100644
--- a/lib/backend.py
+++ b/lib/backend.py
@@ -2379,6 +2379,44 @@ def _DownloadAndDumpDevice(source_url, target_path, 
size):
   target_file.close()
 
 
+def BlockdevConvert(src_disk, target_disk):
+  """Copies data from source block device to target.
+
+  This function gets the export and import commands from the source and
+  target devices respectively, and then concatenates them to a single
+  command using a pipe ("|"). Finally, executes the unified command that
+  will transfer the data between the devices during the disk template
+  conversion operation.
+
+  @type src_disk: L{objects.Disk}
+  @param src_disk: the disk object we want to copy from
+  @type target_disk: L{objects.Disk}
+  @param target_disk: the disk object we want to copy to
+
+  @rtype: NoneType
+  @return: None
+  @raise RPCFail: in case of failure
+
+  """
+  src_dev = _RecursiveFindBD(src_disk)
+  if src_dev is None:
+    _Fail("Cannot copy from device '%s': device not found", src_disk.uuid)
+
+  dest_dev = _RecursiveFindBD(target_disk)
+  if dest_dev is None:
+    _Fail("Cannot copy to device '%s': device not found", target_disk.uuid)
+
+  src_cmd = src_dev.Export()
+  dest_cmd = dest_dev.Import()
+  command = "%s | %s" % (utils.ShellQuoteArgs(src_cmd),
+                         utils.ShellQuoteArgs(dest_cmd))
+
+  result = utils.RunCmd(command)
+  if result.failed:
+    _Fail("Disk conversion command '%s' exited with error: %s; output: %s",
+          result.cmd, result.fail_reason, result.output)
+
+
 def BlockdevWipe(disk, offset, size):
   """Wipes a block device.
 
diff --git a/lib/rpc_defs.py b/lib/rpc_defs.py
index e709a37..9e00156 100644
--- a/lib/rpc_defs.py
+++ b/lib/rpc_defs.py
@@ -361,6 +361,11 @@ _BLOCKDEV_CALLS = [
     ("info", None, None),
     ("exclusive_storage", None, None),
     ], None, None, "Request creation of a given block device"),
+  ("blockdev_convert", SINGLE, None, constants.RPC_TMO_SLOW, [
+    ("bdev_src", ED_SINGLE_DISK_DICT_DP, None),
+    ("bdev_dest", ED_SINGLE_DISK_DICT_DP, None),
+    ], None, None,
+    "Request the copy of the source block device to the destination one"),
   ("blockdev_image", SINGLE, None, constants.RPC_TMO_SLOW, [
     ("bdev", ED_SINGLE_DISK_DICT_DP, None),
     ("image", None, None),
diff --git a/lib/server/noded.py b/lib/server/noded.py
index ee6103d..18257f6 100644
--- a/lib/server/noded.py
+++ b/lib/server/noded.py
@@ -215,6 +215,16 @@ class NodeRequestHandler(http.server.HttpServerHandler):
                                   excl_stor)
 
   @staticmethod
+  def perspective_blockdev_convert(params):
+    """Copy data from source block device to target.
+
+    """
+    disk_src, disk_dest = params
+    bdev_src = objects.Disk.FromDict(disk_src)
+    bdev_dest = objects.Disk.FromDict(disk_dest)
+    return backend.BlockdevConvert(bdev_src, bdev_dest)
+
+  @staticmethod
   def perspective_blockdev_pause_resume_sync(params):
     """Pause/resume sync of a block device.
 
-- 
1.7.10.4

Reply via email to