On 1/15/24 19:24, Richard W.M. Jones wrote:
> Xml.uri is a convenient way to pass the multiple ssh fields to
> virt-v2v and is still used internally by the -i vmx code.  However
> don't leak this awkward implementation into the new ssh.ml module.
>
> Like Nbdkit_ssh, we'll only deal with the explicit (port, server,
> user, path) fields separately.
>
> Note after this refactoring:
>
>  - The new Ssh module interface looks broadly similar to the
>    Nbdkit_ssh interface.
>
>  - vmx_source_of_arg assertions are no longer required inside the new
>    Ssh module, which was a mild layering violation before.
> ---
>  input/ssh.mli                  | 21 ++++++++++-----------
>  input/input_vmx.ml             | 21 ++++++++++++++++-----
>  input/parse_domain_from_vmx.ml | 20 ++++++++++++++++++--
>  input/ssh.ml                   | 32 +++++++++++---------------------
>  4 files changed, 55 insertions(+), 39 deletions(-)

Complicated patch; I'll quote it out of (formatting) order:

>
> diff --git a/input/ssh.mli b/input/ssh.mli
> index 62e78bd3e8..1f39cd1bea 100644
> --- a/input/ssh.mli
> +++ b/input/ssh.mli
> @@ -18,16 +18,15 @@
>
>  (** 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 password ?port server ?user path]
> +    checks that [path] exists on the remote server. *)
> +val remote_file_exists : password:Nbdkit_ssh.password ->
> +                         ?port:string -> server:string -> ?user:string ->
> +                         string -> bool
>
> -(** [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
> -
> -(** [download_file ssh_uri output]
> -    uses scp to copy the single remote file at [ssh_uri] to
> +(** [download_file password ?port server ?user path output]
> +    uses scp to copy the single remote file at [path] to
>      the local file called [output]. *)
> -val download_file : Xml.uri -> string -> unit
> +val download_file : password:Nbdkit_ssh.password ->
> +                    ?port:string -> server:string -> ?user:string -> string 
> ->
> +                    string -> unit

OK

> diff --git a/input/ssh.ml b/input/ssh.ml
> index fbc0e54f5d..4e0e420e20 100644
> --- a/input/ssh.ml
> +++ b/input/ssh.ml
> @@ -22,29 +22,19 @@ 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 local file. *)

OK

> -let download_file uri output =
> +let download_file ~password ?port ~server ?user path output =

(1) so here's where I suggest that (if syntactically possible) we don't
bind "password", just use "_".

>    let cmd =
>      sprintf "scp%s%s %s%s:%s %s"
>              (if verbose () then "" else " -q")
> -            (match port_of_uri uri with
> +            (match port with
>               | None -> ""
> -             | Some port -> sprintf " -P %d" port)
> -            (match uri.Xml.uri_user with
> +             | Some port -> sprintf " -P %s" port)
> +            (match user with
>               | None -> ""
>               | Some user -> quote user ^ "@")
> -            (quote (server_of_uri uri))
> -            (quote (path_of_uri uri))
> +            (quote server)
> +            (quote path)
>              (quote output) in
>    if verbose () then
>      eprintf "%s\n%!" cmd;

OK (sneaky change: port changes from integer to string; but OK)

> @@ -53,16 +43,16 @@ let download_file uri output =
>                see earlier error messages")
>
>  (* Test if [path] exists on the remote server. *)
> -let remote_file_exists uri path =
> +let remote_file_exists ~password ?port ~server ?user path =
>    let cmd =
>      sprintf "ssh%s %s%s test -f %s"
> -            (match port_of_uri uri with
> +            (match port with
>               | None -> ""
> -             | Some port -> sprintf " -p %d" port)
> -            (match uri.Xml.uri_user with
> +             | Some port -> sprintf " -p %s" port)
> +            (match user with
>               | None -> ""
>               | Some user -> quote user ^ "@")
> -            (quote (server_of_uri uri))
> +            (quote server)
>              (* 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

Same two comments:

(2) suggest binding the password with just "_" for now,

and same "sneaky" (but otherwise harmless / intended) remark about the
port type change.

> diff --git a/input/input_vmx.ml b/input/input_vmx.ml
> index b9cce10fed..b3426fa242 100644
> --- a/input/input_vmx.ml
> +++ b/input/input_vmx.ml
> @@ -83,22 +83,33 @@ module VMX = struct
>              let socket = sprintf "%s/in%d" dir i in
>              On_exit.unlink socket;
>
> -            let vmx_path = Ssh.path_of_uri uri in
> +            let vmx_path =
> +              match uri.uri_path with
> +              | None -> assert false (* checked by vmx_source_of_arg *)
> +              | Some path -> path 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
>
> +            let server =
> +              match uri.uri_server with
> +              | None -> assert false (* checked by vmx_source_of_arg *)
> +              | Some server -> server in
> +            let port =
> +              match uri.uri_port with
> +              | i when i <= 0 -> None
> +              | i -> Some (string_of_int i) in
> +            let user = uri.Xml.uri_user in
> +
>              (* RHBZ#1774386 *)
> -            if not (Ssh.remote_file_exists uri flat_vmdk) then
> +            if not (Ssh.remote_file_exists ~password ?port ~server ?user
> +                      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 = 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 cor = dir // "convert" in
>              let bandwidth = options.bandwidth in
>              let nbdkit = Nbdkit_ssh.create_ssh ?bandwidth ~cor ~password

OK (complicated, with *_of_uri being flattened in one go, but seems OK)

> diff --git a/input/parse_domain_from_vmx.ml b/input/parse_domain_from_vmx.ml
> index 94ae9957e3..99c86b1ae0 100644
> --- a/input/parse_domain_from_vmx.ml
> +++ b/input/parse_domain_from_vmx.ml
> @@ -335,8 +335,21 @@ let parse_domain_from_vmx vmx_source =
>      match vmx_source with
>      | File filename -> Parse_vmx.parse_file filename
>      | SSH (password, uri) ->

(3) So this is the pattern where -- corresponding to my other suggestion
-- we'd have to bind "password" for real, because now we are passing it
to "download_file".

> +       let server =
> +         match uri.uri_server with
> +         | None -> assert false (* checked by vmx_source_of_arg *)
> +         | Some server -> server in
> +       let port =
> +         match uri.uri_port with
> +         | i when i <= 0 -> None
> +         | i -> Some (string_of_int i) in
> +       let user = uri.Xml.uri_user in
> +       let path =
> +         match uri.uri_path with
> +         | None -> assert false (* checked by vmx_source_of_arg *)
> +         | Some path -> path in
>         let filename = tmpdir // "source.vmx" in
> -       Ssh.download_file uri filename;
> +       Ssh.download_file ~password ?port ~server ?user path filename;
>         Parse_vmx.parse_file filename in
>
>    let name =

OK (although not a fan of the code duplication)

> @@ -346,7 +359,10 @@ 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 (Ssh.path_of_uri uri) in
> +       | SSH (_, uri) ->
> +          match uri.uri_path with
> +          | None -> assert false (* checked by vmx_source_of_arg *)
> +          | Some path -> name_from_disk path in
>
>    let genid =
>      (* See: 
> https://lists.nongnu.org/archive/html/qemu-devel/2018-07/msg02019.html *)

Hm. I consider this a bit of unwelcome fallout, especially with the same
match on "uri.uri_path" as above (I do realize we evaluate different
expressions on both "Some path" branches -- "path" versus
"name_from_disk path").

(4) Can we introduce a helper function that takes a URI and returns a
tuple (server, port, user, path)? Then it could be called from both
"input_vmx.ml" and "parse_domain_from_vmx.ml", plus in the latter, we
could use the path component of the returned tuple for both the
"Ssh.download_file" call and for the "name_from_disk" call.

... In effect I'm suggesting to *replace* the *_of_uri helpers in the
Ssh module with a new (unified) helper function in -- say -- Utils. If
you agree with that idea, then it might be best to first perform that
conversion / extraction in a separate patch, prepended to this one.

Laszlo
_______________________________________________
Libguestfs mailing list -- guestfs@lists.libguestfs.org
To unsubscribe send an email to guestfs-le...@lists.libguestfs.org

Reply via email to