From cddd07669d18a5a848f82dbde27b84ef405ef9fa Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" 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 --- 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