You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
302 lines
11 KiB
302 lines
11 KiB
8 months ago
|
From cddd07669d18a5a848f82dbde27b84ef405ef9fa Mon Sep 17 00:00:00 2001
|
||
|
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||
|
Date: Mon, 15 Jan 2024 14:24:35 +0000
|
||
|
Subject: [PATCH] virt-v2v: -i vmx: Refactor ssh/scp code into a new module
|
||
|
|
||
|
This is a straight refactor of the existing code that handles ssh/scp
|
||
|
into a new module. In this commit I just copy the code around without
|
||
|
doing any cleanup; cleanup will follow in subsequent commits.
|
||
|
|
||
|
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
|
||
|
---
|
||
|
input/Makefile.am | 6 ++-
|
||
|
input/input_vmx.ml | 8 ++--
|
||
|
input/parse_domain_from_vmx.ml | 60 ++-----------------------
|
||
|
input/parse_domain_from_vmx.mli | 6 ---
|
||
|
input/ssh.ml | 78 +++++++++++++++++++++++++++++++++
|
||
|
input/ssh.mli | 34 ++++++++++++++
|
||
|
6 files changed, 123 insertions(+), 69 deletions(-)
|
||
|
create mode 100644 input/ssh.ml
|
||
|
create mode 100644 input/ssh.mli
|
||
|
|
||
|
diff --git a/input/Makefile.am b/input/Makefile.am
|
||
|
index de016d60..4153f878 100644
|
||
|
--- a/input/Makefile.am
|
||
|
+++ b/input/Makefile.am
|
||
|
@@ -39,6 +39,7 @@ SOURCES_MLI = \
|
||
|
parse_domain_from_vmx.mli \
|
||
|
parse_libvirt_xml.mli \
|
||
|
parse_vmx.mli \
|
||
|
+ ssh.mli \
|
||
|
vCenter.mli
|
||
|
|
||
|
SOURCES_ML = \
|
||
|
@@ -46,11 +47,12 @@ SOURCES_ML = \
|
||
|
parse_libvirt_xml.ml \
|
||
|
OVF.ml \
|
||
|
OVA.ml \
|
||
|
- parse_vmx.ml \
|
||
|
- parse_domain_from_vmx.ml \
|
||
|
nbdkit_curl.ml \
|
||
|
nbdkit_ssh.ml \
|
||
|
nbdkit_vddk.ml \
|
||
|
+ ssh.ml \
|
||
|
+ parse_vmx.ml \
|
||
|
+ parse_domain_from_vmx.ml \
|
||
|
vCenter.ml \
|
||
|
input.ml \
|
||
|
input_disk.ml \
|
||
|
diff --git a/input/input_vmx.ml b/input/input_vmx.ml
|
||
|
index eed8a433..bd20420c 100644
|
||
|
--- a/input/input_vmx.ml
|
||
|
+++ b/input/input_vmx.ml
|
||
|
@@ -79,21 +79,21 @@ module VMX = struct
|
||
|
let socket = sprintf "%s/in%d" dir i in
|
||
|
On_exit.unlink socket;
|
||
|
|
||
|
- let vmx_path = path_of_uri uri in
|
||
|
+ let vmx_path = Ssh.path_of_uri uri in
|
||
|
let abs_path = absolute_path_from_other_file vmx_path filename in
|
||
|
let flat_vmdk = PCRE.replace (PCRE.compile "\\.vmdk$")
|
||
|
"-flat.vmdk" abs_path in
|
||
|
|
||
|
(* RHBZ#1774386 *)
|
||
|
- if not (remote_file_exists uri flat_vmdk) then
|
||
|
+ if not (Ssh.remote_file_exists uri flat_vmdk) then
|
||
|
error (f_"This transport does not support guests with snapshots. \
|
||
|
Either collapse the snapshots for this guest and try \
|
||
|
the conversion again, or use one of the alternate \
|
||
|
conversion methods described in \
|
||
|
virt-v2v-input-vmware(1) section \"NOTES\".");
|
||
|
|
||
|
- let server = server_of_uri uri in
|
||
|
- let port = Option.map string_of_int (port_of_uri uri) in
|
||
|
+ let server = Ssh.server_of_uri uri in
|
||
|
+ let port = Option.map string_of_int (Ssh.port_of_uri uri) in
|
||
|
let user = uri.Xml.uri_user in
|
||
|
let password =
|
||
|
match options.input_password with
|
||
|
diff --git a/input/parse_domain_from_vmx.ml b/input/parse_domain_from_vmx.ml
|
||
|
index f24990f8..8cf5893c 100644
|
||
|
--- a/input/parse_domain_from_vmx.ml
|
||
|
+++ b/input/parse_domain_from_vmx.ml
|
||
|
@@ -51,61 +51,6 @@ let vmx_source_of_arg input_transport arg =
|
||
|
error (f_"vmx URI path component looks incorrect");
|
||
|
SSH uri
|
||
|
|
||
|
-(* Return various fields from the URI. The checks in vmx_source_of_arg
|
||
|
- * should ensure that none of these assertions fail.
|
||
|
- *)
|
||
|
-let port_of_uri { Xml.uri_port } =
|
||
|
- match uri_port with i when i <= 0 -> None | i -> Some i
|
||
|
-let server_of_uri { Xml.uri_server } =
|
||
|
- match uri_server with None -> assert false | Some s -> s
|
||
|
-let path_of_uri { Xml.uri_path } =
|
||
|
- match uri_path with None -> assert false | Some p -> p
|
||
|
-
|
||
|
-(* 'scp' a remote file into a temporary local file, returning the path
|
||
|
- * of the temporary local file.
|
||
|
- *)
|
||
|
-let scp_from_remote_to_temporary uri tmpdir filename =
|
||
|
- let localfile = tmpdir // filename in
|
||
|
-
|
||
|
- let cmd =
|
||
|
- sprintf "scp%s%s %s%s:%s %s"
|
||
|
- (if verbose () then "" else " -q")
|
||
|
- (match port_of_uri uri with
|
||
|
- | None -> ""
|
||
|
- | Some port -> sprintf " -P %d" port)
|
||
|
- (match uri.Xml.uri_user with
|
||
|
- | None -> ""
|
||
|
- | Some user -> quote user ^ "@")
|
||
|
- (quote (server_of_uri uri))
|
||
|
- (quote (path_of_uri uri))
|
||
|
- (quote localfile) in
|
||
|
- if verbose () then
|
||
|
- eprintf "%s\n%!" cmd;
|
||
|
- if Sys.command cmd <> 0 then
|
||
|
- error (f_"could not copy the VMX file from the remote server, \
|
||
|
- see earlier error messages");
|
||
|
- localfile
|
||
|
-
|
||
|
-(* Test if [path] exists on the remote server. *)
|
||
|
-let remote_file_exists uri path =
|
||
|
- let cmd =
|
||
|
- sprintf "ssh%s %s%s test -f %s"
|
||
|
- (match port_of_uri uri with
|
||
|
- | None -> ""
|
||
|
- | Some port -> sprintf " -p %d" port)
|
||
|
- (match uri.Xml.uri_user with
|
||
|
- | None -> ""
|
||
|
- | Some user -> quote user ^ "@")
|
||
|
- (quote (server_of_uri uri))
|
||
|
- (* Double quoting is necessary for 'ssh', first to protect
|
||
|
- * from the local shell, second to protect from the remote
|
||
|
- * shell. https://github.com/libguestfs/virt-v2v/issues/35#issuecomment-1741730963
|
||
|
- *)
|
||
|
- (quote (quote path)) in
|
||
|
- if verbose () then
|
||
|
- eprintf "%s\n%!" cmd;
|
||
|
- Sys.command cmd = 0
|
||
|
-
|
||
|
let rec find_disks vmx vmx_source =
|
||
|
(* Set the s_disk_id field to an incrementing number. *)
|
||
|
List.mapi
|
||
|
@@ -390,7 +335,8 @@ let parse_domain_from_vmx vmx_source =
|
||
|
match vmx_source with
|
||
|
| File filename -> Parse_vmx.parse_file filename
|
||
|
| SSH uri ->
|
||
|
- let filename = scp_from_remote_to_temporary uri tmpdir "source.vmx" in
|
||
|
+ let filename = Ssh.scp_from_remote_to_temporary uri tmpdir
|
||
|
+ "source.vmx" in
|
||
|
Parse_vmx.parse_file filename in
|
||
|
|
||
|
let name =
|
||
|
@@ -400,7 +346,7 @@ let parse_domain_from_vmx vmx_source =
|
||
|
warning (f_"no displayName key found in VMX file");
|
||
|
match vmx_source with
|
||
|
| File filename -> name_from_disk filename
|
||
|
- | SSH uri -> name_from_disk (path_of_uri uri) in
|
||
|
+ | SSH uri -> name_from_disk (Ssh.path_of_uri uri) in
|
||
|
|
||
|
let genid =
|
||
|
(* See: https://lists.nongnu.org/archive/html/qemu-devel/2018-07/msg02019.html *)
|
||
|
diff --git a/input/parse_domain_from_vmx.mli b/input/parse_domain_from_vmx.mli
|
||
|
index e354b32e..42f8100e 100644
|
||
|
--- a/input/parse_domain_from_vmx.mli
|
||
|
+++ b/input/parse_domain_from_vmx.mli
|
||
|
@@ -22,9 +22,3 @@ type vmx_source =
|
||
|
|
||
|
val vmx_source_of_arg : [`SSH] option -> string -> vmx_source
|
||
|
val parse_domain_from_vmx : vmx_source -> Types.source * string list
|
||
|
-
|
||
|
-(* XXX Exporting these is a hack. *)
|
||
|
-val path_of_uri : Xml.uri -> string
|
||
|
-val server_of_uri : Xml.uri -> string
|
||
|
-val port_of_uri : Xml.uri -> int option
|
||
|
-val remote_file_exists : Xml.uri -> string -> bool
|
||
|
diff --git a/input/ssh.ml b/input/ssh.ml
|
||
|
new file mode 100644
|
||
|
index 00000000..5e689d29
|
||
|
--- /dev/null
|
||
|
+++ b/input/ssh.ml
|
||
|
@@ -0,0 +1,78 @@
|
||
|
+(* virt-v2v
|
||
|
+ * Copyright (C) 2009-2024 Red Hat Inc.
|
||
|
+ *
|
||
|
+ * This program is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of the GNU General Public License as published by
|
||
|
+ * the Free Software Foundation; either version 2 of the License, or
|
||
|
+ * (at your option) any later version.
|
||
|
+ *
|
||
|
+ * This program is distributed in the hope that it will be useful,
|
||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ * GNU General Public License for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU General Public License along
|
||
|
+ * with this program; if not, write to the Free Software Foundation, Inc.,
|
||
|
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
+ *)
|
||
|
+
|
||
|
+open Std_utils
|
||
|
+open Tools_utils
|
||
|
+open Common_gettext.Gettext
|
||
|
+
|
||
|
+open Printf
|
||
|
+
|
||
|
+(* Return various fields from the URI. The checks in vmx_source_of_arg
|
||
|
+ * should ensure that none of these assertions fail.
|
||
|
+ *)
|
||
|
+let port_of_uri { Xml.uri_port } =
|
||
|
+ match uri_port with i when i <= 0 -> None | i -> Some i
|
||
|
+let server_of_uri { Xml.uri_server } =
|
||
|
+ match uri_server with None -> assert false | Some s -> s
|
||
|
+let path_of_uri { Xml.uri_path } =
|
||
|
+ match uri_path with None -> assert false | Some p -> p
|
||
|
+
|
||
|
+(* 'scp' a remote file into a temporary local file, returning the path
|
||
|
+ * of the temporary local file.
|
||
|
+ *)
|
||
|
+let scp_from_remote_to_temporary uri tmpdir filename =
|
||
|
+ let localfile = tmpdir // filename in
|
||
|
+
|
||
|
+ let cmd =
|
||
|
+ sprintf "scp%s%s %s%s:%s %s"
|
||
|
+ (if verbose () then "" else " -q")
|
||
|
+ (match port_of_uri uri with
|
||
|
+ | None -> ""
|
||
|
+ | Some port -> sprintf " -P %d" port)
|
||
|
+ (match uri.Xml.uri_user with
|
||
|
+ | None -> ""
|
||
|
+ | Some user -> quote user ^ "@")
|
||
|
+ (quote (server_of_uri uri))
|
||
|
+ (quote (path_of_uri uri))
|
||
|
+ (quote localfile) in
|
||
|
+ if verbose () then
|
||
|
+ eprintf "%s\n%!" cmd;
|
||
|
+ if Sys.command cmd <> 0 then
|
||
|
+ error (f_"could not copy the VMX file from the remote server, \
|
||
|
+ see earlier error messages");
|
||
|
+ localfile
|
||
|
+
|
||
|
+(* Test if [path] exists on the remote server. *)
|
||
|
+let remote_file_exists uri path =
|
||
|
+ let cmd =
|
||
|
+ sprintf "ssh%s %s%s test -f %s"
|
||
|
+ (match port_of_uri uri with
|
||
|
+ | None -> ""
|
||
|
+ | Some port -> sprintf " -p %d" port)
|
||
|
+ (match uri.Xml.uri_user with
|
||
|
+ | None -> ""
|
||
|
+ | Some user -> quote user ^ "@")
|
||
|
+ (quote (server_of_uri uri))
|
||
|
+ (* Double quoting is necessary for 'ssh', first to protect
|
||
|
+ * from the local shell, second to protect from the remote
|
||
|
+ * shell. https://github.com/libguestfs/virt-v2v/issues/35#issuecomment-1741730963
|
||
|
+ *)
|
||
|
+ (quote (quote path)) in
|
||
|
+ if verbose () then
|
||
|
+ eprintf "%s\n%!" cmd;
|
||
|
+ Sys.command cmd = 0
|
||
|
diff --git a/input/ssh.mli b/input/ssh.mli
|
||
|
new file mode 100644
|
||
|
index 00000000..e9a1a6a8
|
||
|
--- /dev/null
|
||
|
+++ b/input/ssh.mli
|
||
|
@@ -0,0 +1,34 @@
|
||
|
+(* virt-v2v
|
||
|
+ * Copyright (C) 2009-2024 Red Hat Inc.
|
||
|
+ *
|
||
|
+ * This program is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of the GNU General Public License as published by
|
||
|
+ * the Free Software Foundation; either version 2 of the License, or
|
||
|
+ * (at your option) any later version.
|
||
|
+ *
|
||
|
+ * This program is distributed in the hope that it will be useful,
|
||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ * GNU General Public License for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU General Public License along
|
||
|
+ * with this program; if not, write to the Free Software Foundation, Inc.,
|
||
|
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
+ *)
|
||
|
+
|
||
|
+(** Wrappers for finding and downloading remote files over ssh. *)
|
||
|
+
|
||
|
+val path_of_uri : Xml.uri -> string
|
||
|
+val server_of_uri : Xml.uri -> string
|
||
|
+val port_of_uri : Xml.uri -> int option
|
||
|
+
|
||
|
+(** [remote_file_exists ssh_uri path] checks that [path] exists
|
||
|
+ on the remote server [ssh_uri] (note any path inside [ssh_uri]
|
||
|
+ is ignored). *)
|
||
|
+val remote_file_exists : Xml.uri -> string -> bool
|
||
|
+
|
||
|
+(** [scp_from_remote_to_temporary ssh_uri tmpdir filename]
|
||
|
+ uses scp to copy the single remote file at [ssh_uri] to
|
||
|
+ the local file called [tmpdir/filename]. It returns the
|
||
|
+ final path [tmpdir/filename]. *)
|
||
|
+val scp_from_remote_to_temporary : Xml.uri -> string -> string -> string
|