On Wed, Jun 4, 2014 at 3:57 PM, Dimitris Bliablias <[email protected]>
wrote:
> 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 | 37 +++++++++++++++++++++++++++++++++++++
> lib/rpc_defs.py | 5 +++++
> lib/server/noded.py | 10 ++++++++++
> 3 files changed, 52 insertions(+)
>
> diff --git a/lib/backend.py b/lib/backend.py
> index 0e23c12..4fc89ce 100644
> --- a/lib/backend.py
> +++ b/lib/backend.py
> @@ -2373,6 +2373,43 @@ 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" % (src_cmd, dest_cmd)
>
As mentioned before, this is dangerous. Instead, src_cmd and dest_cmd
should be lists of strings, and we should do something like
command = "%s | %s" % (utils_text.ShellQuoteArgs(src_cmd),
utils_text.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 7eb53f0..c575c37 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 7c11b5a..b36e5d8 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
>
>
Rest LGTM