mrc0mmand / rpms / libguestfs

Forked from rpms/libguestfs 3 years ago
Clone

Blame SOURCES/0009-v2v-Add-general-mechanism-for-input-and-output-optio.patch

d0ea73
From 5198d704e964fa896773d250624858e865c30082 Mon Sep 17 00:00:00 2001
d0ea73
From: "Richard W.M. Jones" <rjones@redhat.com>
d0ea73
Date: Thu, 22 Mar 2018 10:29:23 +0000
d0ea73
Subject: [PATCH] v2v: Add general mechanism for input and output options
d0ea73
 (-io/-oo).
d0ea73
d0ea73
Currently we have a bunch of ad hoc options like --vddk* and --vdsm*
d0ea73
(and proposed to add --rhv*) to handle extra parameters for input and
d0ea73
output modes/transports.  This complicates the command line parsing
d0ea73
and also the clarity of the command line (becauseit's not very obvious
d0ea73
which options apply to which side of the conversion).
d0ea73
d0ea73
Replace these with a general mechanism for handling input and output
d0ea73
options.
d0ea73
d0ea73
Thus (for example):
d0ea73
d0ea73
  --vddk-thumbprint=...   becomes   -io vddk-thumbprint=...
d0ea73
  --vdsm-compat=0.10                -oo vdsm-compat=0.10
d0ea73
d0ea73
The responsibility for parsing input and output options moves into the
d0ea73
input and output drivers.
d0ea73
d0ea73
This improves error checking so it's harder now for wrong flags to be
d0ea73
included on the command line when they don't apply to the current mode.
d0ea73
d0ea73
The old option names are preserved for compatibility.
d0ea73
d0ea73
(cherry picked from commit 6327e716cdd2f161bc639733f216a3a29d26ad3c)
d0ea73
---
d0ea73
 v2v/Makefile.am                  |   4 +
d0ea73
 v2v/cmdline.ml                   | 229 ++++++++++++++-------------
d0ea73
 v2v/input_libvirt.ml             |   4 +-
d0ea73
 v2v/input_libvirt.mli            |   4 +-
d0ea73
 v2v/input_libvirt_vddk.ml        | 112 +++++++++-----
d0ea73
 v2v/input_libvirt_vddk.mli       |  16 +-
d0ea73
 v2v/output_vdsm.ml               |  79 +++++++++-
d0ea73
 v2v/output_vdsm.mli              |  13 +-
d0ea73
 v2v/test-v2v-docs.sh             |  31 +++-
d0ea73
 v2v/test-v2v-it-vddk-io-query.sh |  38 +++++
d0ea73
 v2v/test-v2v-o-vdsm-oo-query.sh  |  38 +++++
d0ea73
 v2v/test-v2v-o-vdsm-options.sh   |  16 +-
d0ea73
 v2v/virt-v2v.pod                 | 258 ++++++++++++++++---------------
d0ea73
 13 files changed, 530 insertions(+), 312 deletions(-)
d0ea73
 create mode 100755 v2v/test-v2v-it-vddk-io-query.sh
d0ea73
 create mode 100755 v2v/test-v2v-o-vdsm-oo-query.sh
d0ea73
d0ea73
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
d0ea73
index 0c3224b24..482ba58e5 100644
d0ea73
--- a/v2v/Makefile.am
d0ea73
+++ b/v2v/Makefile.am
d0ea73
@@ -307,6 +307,8 @@ TESTS = \
d0ea73
 	test-v2v-i-ova-tar.sh \
d0ea73
 	test-v2v-i-ova-two-disks.sh \
d0ea73
 	test-v2v-i-vmx.sh \
d0ea73
+	test-v2v-it-vddk-io-query.sh \
d0ea73
+	test-v2v-o-vdsm-oo-query.sh \
d0ea73
 	test-v2v-bad-networks-and-bridges.sh
d0ea73
 
d0ea73
 if HAVE_LIBVIRT
d0ea73
@@ -470,6 +472,7 @@ EXTRA_DIST += \
d0ea73
 	test-v2v-i-vmx-4.vmx \
d0ea73
 	test-v2v-i-vmx-5.vmx \
d0ea73
 	test-v2v-in-place.sh \
d0ea73
+	test-v2v-it-vddk-io-query.sh \
d0ea73
 	test-v2v-machine-readable.sh \
d0ea73
 	test-v2v-networks-and-bridges-expected.xml \
d0ea73
 	test-v2v-networks-and-bridges.sh \
d0ea73
@@ -480,6 +483,7 @@ EXTRA_DIST += \
d0ea73
 	test-v2v-o-null.sh \
d0ea73
 	test-v2v-o-qemu.sh \
d0ea73
 	test-v2v-o-rhv.sh \
d0ea73
+	test-v2v-o-vdsm-oo-query.sh \
d0ea73
 	test-v2v-o-vdsm-options.sh \
d0ea73
 	test-v2v-oa-option.sh \
d0ea73
 	test-v2v-of-option.sh \
d0ea73
diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
d0ea73
index a83fcbae0..5b8f686a8 100644
d0ea73
--- a/v2v/cmdline.ml
d0ea73
+++ b/v2v/cmdline.ml
d0ea73
@@ -65,24 +65,6 @@ let parse_cmdline () =
d0ea73
   let output_password = ref None in
d0ea73
   let output_storage = ref None in
d0ea73
   let password_file = ref None in
d0ea73
-  let vddk_config = ref None in
d0ea73
-  let vddk_cookie = ref None in
d0ea73
-  let vddk_libdir = ref None in
d0ea73
-  let vddk_nfchostport = ref None in
d0ea73
-  let vddk_port = ref None in
d0ea73
-  let vddk_snapshot = ref None in
d0ea73
-  let vddk_thumbprint = ref None in
d0ea73
-  let vddk_transports = ref None in
d0ea73
-  let vddk_vimapiver = ref None in
d0ea73
-  let vdsm_vm_uuid = ref None in
d0ea73
-  let vdsm_ovf_output = ref None in (* default "." *)
d0ea73
-
d0ea73
-  let vdsm_compat = ref "0.10" in
d0ea73
-  let set_vdsm_compat s = vdsm_compat := s in
d0ea73
-
d0ea73
-  let vdsm_ovf_flavour = ref Create_ovf.RHVExportStorageDomain in
d0ea73
-  let set_vdsm_ovf_flavour arg =
d0ea73
-    vdsm_ovf_flavour := Create_ovf.ovf_flavour_of_string arg in
d0ea73
 
d0ea73
   let set_string_option_once optname optref arg =
d0ea73
     match !optref with
d0ea73
@@ -106,6 +88,15 @@ let parse_cmdline () =
d0ea73
       error (f_"unknown -i option: %s") s
d0ea73
   in
d0ea73
 
d0ea73
+  let input_options = ref [] in
d0ea73
+  let set_input_option_compat k v =
d0ea73
+    input_options := (k, v) :: !input_options
d0ea73
+  in
d0ea73
+  let set_input_option option =
d0ea73
+    let k, v = String.split "=" option in
d0ea73
+    set_input_option_compat k v
d0ea73
+  in
d0ea73
+
d0ea73
   let network_map = ref NetworkMap.empty in
d0ea73
   let add_network, add_bridge =
d0ea73
     let add flag name t str =
d0ea73
@@ -159,6 +150,15 @@ let parse_cmdline () =
d0ea73
       error (f_"unknown -oa option: %s") s
d0ea73
   in
d0ea73
 
d0ea73
+  let output_options = ref [] in
d0ea73
+  let set_output_option_compat k v =
d0ea73
+    output_options := (k, v) :: !output_options
d0ea73
+  in
d0ea73
+  let set_output_option option =
d0ea73
+    let k, v = String.split "=" option in
d0ea73
+    set_output_option_compat k v
d0ea73
+  in
d0ea73
+
d0ea73
   let root_choice = ref AskRoot in
d0ea73
   let set_root_choice = function
d0ea73
     | "ask" -> root_choice := AskRoot
d0ea73
@@ -169,12 +169,6 @@ let parse_cmdline () =
d0ea73
       error (f_"unknown --root option: %s") s
d0ea73
   in
d0ea73
 
d0ea73
-  let vdsm_image_uuids = ref [] in
d0ea73
-  let add_vdsm_image_uuid s = List.push_front s vdsm_image_uuids in
d0ea73
-
d0ea73
-  let vdsm_vol_uuids = ref [] in
d0ea73
-  let add_vdsm_vol_uuid s = List.push_front s vdsm_vol_uuids in
d0ea73
-
d0ea73
   let vmtype_warning _ =
d0ea73
     warning (f_"the --vmtype option has been removed and now does nothing")
d0ea73
   in
d0ea73
@@ -198,6 +192,8 @@ let parse_cmdline () =
d0ea73
                                     s_"Libvirt URI";
d0ea73
     [ M"if" ],       Getopt.String ("format", set_string_option_once "-if" input_format),
d0ea73
                                     s_"Input format (for -i disk)";
d0ea73
+    [ M"io" ],       Getopt.String ("option[=value]", set_input_option),
d0ea73
+                                    s_"Set option for input mode";
d0ea73
     [ M"it" ],       Getopt.String ("transport", set_string_option_once "-it" input_transport),
d0ea73
                                     s_"Input transport";
d0ea73
     [ L"in-place" ], Getopt.Set in_place,
d0ea73
@@ -220,6 +216,8 @@ let parse_cmdline () =
d0ea73
                                     s_"Set output format";
d0ea73
     [ M"on" ],       Getopt.String ("name", set_string_option_once "-on" output_name),
d0ea73
                                     s_"Rename guest when converting";
d0ea73
+    [ M"oo" ],       Getopt.String ("option[=value]", set_output_option),
d0ea73
+                                    s_"Set option for output mode";
d0ea73
     [ M"op" ],       Getopt.String ("filename", set_string_option_once "-op" output_password),
d0ea73
                                     s_"Use password from file to connect to output hypervisor";
d0ea73
     [ M"os" ],       Getopt.String ("storage", set_string_option_once "-os" output_storage),
d0ea73
@@ -231,36 +229,36 @@ let parse_cmdline () =
d0ea73
     [ L"qemu-boot" ], Getopt.Set qemu_boot, s_"Boot in qemu (-o qemu only)";
d0ea73
     [ L"root" ],     Getopt.String ("ask|... ", set_root_choice),
d0ea73
                                     s_"How to choose root filesystem";
d0ea73
-    [ L"vddk-config" ], Getopt.String ("filename", set_string_option_once "--vddk-config" vddk_config),
d0ea73
-                                    s_"Set VDDK config file";
d0ea73
-    [ L"vddk-cookie" ], Getopt.String ("cookie", set_string_option_once "--vddk-cookie" vddk_cookie),
d0ea73
-                                    s_"Set VDDK cookie";
d0ea73
-    [ L"vddk-libdir" ], Getopt.String ("libdir", set_string_option_once "--vddk-libdir" vddk_libdir),
d0ea73
-                                    s_"Set VDDK library parent directory";
d0ea73
-    [ L"vddk-nfchostport" ], Getopt.String ("nfchostport", set_string_option_once "--vddk-nfchostport" vddk_nfchostport),
d0ea73
-                                    s_"Set VDDK nfchostport";
d0ea73
-    [ L"vddk-port" ], Getopt.String ("port", set_string_option_once "--vddk-port" vddk_port),
d0ea73
-                                    s_"Set VDDK port";
d0ea73
-    [ L"vddk-snapshot" ], Getopt.String ("snapshot-moref", set_string_option_once "--vddk-snapshot" vddk_snapshot),
d0ea73
-                                    s_"Set VDDK snapshot";
d0ea73
-    [ L"vddk-thumbprint" ], Getopt.String ("thumbprint", set_string_option_once "--vddk-thumbprint" vddk_thumbprint),
d0ea73
-                                    s_"Set VDDK thumbprint";
d0ea73
-    [ L"vddk-transports" ], Getopt.String ("transports", set_string_option_once "--vddk-transports" vddk_transports),
d0ea73
-                                    s_"Set VDDK transports";
d0ea73
-    [ L"vddk-vimapiver" ], Getopt.String ("apiver", set_string_option_once "--vddk-vimapiver" vddk_vimapiver),
d0ea73
-                                    s_"Set VDDK vimapiver";
d0ea73
-    [ L"vdsm-compat" ], Getopt.Symbol ("0.10|1.1", ["0.10"; "1.1"], set_vdsm_compat),
d0ea73
-                                    s_"Write qcow2 with compat=0.10|1.1";
d0ea73
-    [ L"vdsm-image-uuid" ], Getopt.String ("uuid", add_vdsm_image_uuid),
d0ea73
-                                    s_"Output image UUID(s)";
d0ea73
-    [ L"vdsm-vol-uuid" ], Getopt.String ("uuid", add_vdsm_vol_uuid),
d0ea73
-                                    s_"Output vol UUID(s)";
d0ea73
-    [ L"vdsm-vm-uuid" ], Getopt.String ("uuid", set_string_option_once "--vdsm-vm-uuid" vdsm_vm_uuid),
d0ea73
-                                    s_"Output VM UUID";
d0ea73
-    [ L"vdsm-ovf-output" ], Getopt.String ("-", set_string_option_once "--vdsm-ovf-output" vdsm_ovf_output),
d0ea73
-                                    s_"Output OVF file";
d0ea73
-    [ L"vdsm-ovf-flavour" ], Getopt.Symbol (ovf_flavours_str, Create_ovf.ovf_flavours, set_vdsm_ovf_flavour),
d0ea73
-                                    s_"Set the type of generated OVF (default rhvexp)";
d0ea73
+    [ L"vddk-config" ], Getopt.String ("filename", set_input_option_compat "vddk-config"),
d0ea73
+                                    s_"Same as ‘-io vddk-config=filename’";
d0ea73
+    [ L"vddk-cookie" ], Getopt.String ("cookie", set_input_option_compat "vddk-cookie"),
d0ea73
+                                    s_"Same as ‘-io vddk-cookie=filename’";
d0ea73
+    [ L"vddk-libdir" ], Getopt.String ("libdir", set_input_option_compat "vddk-libdir"),
d0ea73
+                                    s_"Same as ‘-io vddk-libdir=libdir’";
d0ea73
+    [ L"vddk-nfchostport" ], Getopt.String ("nfchostport", set_input_option_compat "vddk-nfchostport"),
d0ea73
+                                    s_"Same as ‘-io vddk-nfchostport=nfchostport’";
d0ea73
+    [ L"vddk-port" ], Getopt.String ("port", set_input_option_compat "vddk-port"),
d0ea73
+                                    s_"Same as ‘-io vddk-port=port’";
d0ea73
+    [ L"vddk-snapshot" ], Getopt.String ("snapshot-moref", set_input_option_compat "vddk-snapshot"),
d0ea73
+                                    s_"Same as ‘-io vddk-snapshot=snapshot-moref’";
d0ea73
+    [ L"vddk-thumbprint" ], Getopt.String ("thumbprint", set_input_option_compat "vddk-thumbprint"),
d0ea73
+                                    s_"Same as ‘-io vddk-thumbprint=thumbprint’";
d0ea73
+    [ L"vddk-transports" ], Getopt.String ("transports", set_input_option_compat "vddk-transports"),
d0ea73
+                                    s_"Same as ‘-io vddk-transports=transports’";
d0ea73
+    [ L"vddk-vimapiver" ], Getopt.String ("apiver", set_input_option_compat "vddk-vimapiver"),
d0ea73
+                                    s_"Same as ‘-io vddk-vimapiver=apiver’";
d0ea73
+    [ L"vdsm-compat" ], Getopt.String ("0.10|1.1", set_output_option_compat "vdsm-compat"),
d0ea73
+                                    s_"Same as ‘-oo vdsm-compat=0.10|1.1’";
d0ea73
+    [ L"vdsm-image-uuid" ], Getopt.String ("uuid", set_output_option_compat "vdsm-image-uuid"),
d0ea73
+                                    s_"Same as ‘-oo vdsm-image-uuid=uuid’";
d0ea73
+    [ L"vdsm-vol-uuid" ], Getopt.String ("uuid", set_output_option_compat "vdsm-vol-uuid"),
d0ea73
+                                    s_"Same as ‘-oo vdsm-vol-uuid=uuid’";
d0ea73
+    [ L"vdsm-vm-uuid" ], Getopt.String ("uuid", set_output_option_compat "vdsm-vm-uuid"),
d0ea73
+                                    s_"Same as ‘-oo vdsm-vm-uuid=uuid’";
d0ea73
+    [ L"vdsm-ovf-output" ], Getopt.String ("dir", set_output_option_compat "vdsm-ovf-output"),
d0ea73
+                                    s_"Same as ‘-oo vdsm-ovf-output=dir’";
d0ea73
+    [ L"vdsm-ovf-flavour" ], Getopt.String (ovf_flavours_str, set_output_option_compat "vdsm-ovf-flavour"),
d0ea73
+                                    s_"Same as ‘-oo vdsm-ovf-flavour=flavour’";
d0ea73
     [ L"vmtype" ],   Getopt.String ("-", vmtype_warning),
d0ea73
                                     s_"Ignored for backwards compatibility";
d0ea73
   ] in
d0ea73
@@ -299,6 +297,7 @@ read the man page virt-v2v(1).
d0ea73
   let input_conn = !input_conn in
d0ea73
   let input_format = !input_format in
d0ea73
   let input_mode = !input_mode in
d0ea73
+  let input_options = List.rev !input_options in
d0ea73
   let input_transport =
d0ea73
     match !input_transport with
d0ea73
     | None -> None
d0ea73
@@ -317,28 +316,13 @@ read the man page virt-v2v(1).
d0ea73
   let output_format = !output_format in
d0ea73
   let output_mode = !output_mode in
d0ea73
   let output_name = !output_name in
d0ea73
+  let output_options = List.rev !output_options in
d0ea73
   let output_password = !output_password in
d0ea73
   let output_storage = !output_storage in
d0ea73
   let password_file = !password_file in
d0ea73
   let print_source = !print_source in
d0ea73
   let qemu_boot = !qemu_boot in
d0ea73
   let root_choice = !root_choice in
d0ea73
-  let vddk_options =
d0ea73
-      { Input_libvirt_vddk.vddk_config = !vddk_config;
d0ea73
-        vddk_cookie = !vddk_cookie;
d0ea73
-        vddk_libdir = !vddk_libdir;
d0ea73
-        vddk_nfchostport = !vddk_nfchostport;
d0ea73
-        vddk_port = !vddk_port;
d0ea73
-        vddk_snapshot = !vddk_snapshot;
d0ea73
-        vddk_thumbprint = !vddk_thumbprint;
d0ea73
-        vddk_transports = !vddk_transports;
d0ea73
-        vddk_vimapiver = !vddk_vimapiver } in
d0ea73
-  let vdsm_compat = !vdsm_compat in
d0ea73
-  let vdsm_image_uuids = List.rev !vdsm_image_uuids in
d0ea73
-  let vdsm_vol_uuids = List.rev !vdsm_vol_uuids in
d0ea73
-  let vdsm_vm_uuid = !vdsm_vm_uuid in
d0ea73
-  let vdsm_ovf_output = Option.default "." !vdsm_ovf_output in
d0ea73
-  let vdsm_ovf_flavour = !vdsm_ovf_flavour in
d0ea73
 
d0ea73
   (* No arguments and machine-readable mode?  Print out some facts
d0ea73
    * about what this binary supports.
d0ea73
@@ -352,6 +336,7 @@ read the man page virt-v2v(1).
d0ea73
     printf "colours-option\n";
d0ea73
     printf "vdsm-compat-option\n";
d0ea73
     printf "in-place\n";
d0ea73
+    printf "io/oo\n";
d0ea73
     List.iter (printf "input:%s\n") (Modules_list.input_modules ());
d0ea73
     List.iter (printf "output:%s\n") (Modules_list.output_modules ());
d0ea73
     List.iter (printf "convert:%s\n") (Modules_list.convert_modules ());
d0ea73
@@ -359,6 +344,65 @@ read the man page virt-v2v(1).
d0ea73
     exit 0
d0ea73
   );
d0ea73
 
d0ea73
+  (* Input transport affects whether some input options should or
d0ea73
+   * should not be used.
d0ea73
+   *)
d0ea73
+  let input_transport =
d0ea73
+    let is_query = input_options = ["?", ""] in
d0ea73
+    let no_options () =
d0ea73
+      if is_query then (
d0ea73
+        printf (f_"No -io (input options) are supported with this input transport.\n");
d0ea73
+        exit 0
d0ea73
+      )
d0ea73
+      else if input_options <> [] then
d0ea73
+        error (f_"no -io (input options) are allowed here");
d0ea73
+    in
d0ea73
+    match input_transport with
d0ea73
+    | None -> no_options (); None
d0ea73
+    | Some `SSH -> no_options (); Some `SSH
d0ea73
+    | Some `VDDK ->
d0ea73
+       if is_query then (
d0ea73
+         Input_libvirt_vddk.print_input_options ();
d0ea73
+         exit 0
d0ea73
+       )
d0ea73
+       else (
d0ea73
+         let vddk_options =
d0ea73
+           Input_libvirt_vddk.parse_input_options input_options in
d0ea73
+         Some (`VDDK vddk_options)
d0ea73
+       ) in
d0ea73
+
d0ea73
+  (* Output mode affects whether some output options should or
d0ea73
+   * should not be used.
d0ea73
+   *)
d0ea73
+  let output_mode =
d0ea73
+    let is_query = output_options = ["?", ""] in
d0ea73
+    let no_options () =
d0ea73
+      if is_query then (
d0ea73
+        printf (f_"No -oo (output options) are supported in this output mode.\n");
d0ea73
+        exit 0
d0ea73
+      )
d0ea73
+      else if output_options <> [] then
d0ea73
+        error (f_"no -oo (output options) are allowed here");
d0ea73
+    in
d0ea73
+    match output_mode with
d0ea73
+    | `Not_set -> no_options (); `Not_set
d0ea73
+    | `Glance -> no_options (); `Glance
d0ea73
+    | `Libvirt -> no_options (); `Libvirt
d0ea73
+    | `Local -> no_options (); `Local
d0ea73
+    | `Null -> no_options (); `Null
d0ea73
+    | `RHV -> no_options (); `RHV
d0ea73
+    | `QEmu -> no_options (); `QEmu
d0ea73
+    | `VDSM ->
d0ea73
+       if is_query then (
d0ea73
+         Output_vdsm.print_output_options ();
d0ea73
+         exit 0
d0ea73
+       )
d0ea73
+       else (
d0ea73
+         let vdsm_options =
d0ea73
+           Output_vdsm.parse_output_options output_options in
d0ea73
+         `VDSM vdsm_options
d0ea73
+       ) in
d0ea73
+
d0ea73
   (* Parse out the password from the password file. *)
d0ea73
   let password =
d0ea73
     match password_file with
d0ea73
@@ -367,27 +411,6 @@ read the man page virt-v2v(1).
d0ea73
       let password = read_first_line_from_file filename in
d0ea73
       Some password in
d0ea73
 
d0ea73
-  (* Input transport affects whether some parameters should or
d0ea73
-   * should not be used.
d0ea73
-   *)
d0ea73
-  (match input_transport with
d0ea73
-   | None
d0ea73
-   | Some `SSH ->
d0ea73
-      if !vddk_config <> None ||
d0ea73
-         !vddk_cookie <> None ||
d0ea73
-         !vddk_libdir <> None ||
d0ea73
-         !vddk_nfchostport <> None ||
d0ea73
-         !vddk_port <> None ||
d0ea73
-         !vddk_snapshot <> None ||
d0ea73
-         !vddk_thumbprint <> None ||
d0ea73
-         !vddk_transports <> None ||
d0ea73
-         !vddk_vimapiver <> None then
d0ea73
-        error (f_"‘--vddk-*’ options should only be used when conversion via the nbdkit VDDK plugin has been enabled, ie. using ‘-it vddk’.")
d0ea73
-   | Some `VDDK ->
d0ea73
-      if !vddk_thumbprint = None then
d0ea73
-        error (f_"‘--vddk-thumbprint’ is required when using ‘-it vddk’.")
d0ea73
-  );
d0ea73
-
d0ea73
   (* Parsing of the argument(s) depends on the input mode. *)
d0ea73
   let input =
d0ea73
     match input_mode with
d0ea73
@@ -413,11 +436,10 @@ read the man page virt-v2v(1).
d0ea73
       let input_transport =
d0ea73
         match input_transport with
d0ea73
         | None -> None
d0ea73
-        | Some `VDDK -> Some `VDDK
d0ea73
+        | (Some (`VDDK _) as vddk) -> vddk
d0ea73
         | Some `SSH ->
d0ea73
            error (f_"only ‘-it vddk’ can be used here") in
d0ea73
-      Input_libvirt.input_libvirt vddk_options password
d0ea73
-                                  input_conn input_transport guest
d0ea73
+      Input_libvirt.input_libvirt password input_conn input_transport guest
d0ea73
 
d0ea73
     | `LibvirtXML ->
d0ea73
       (* -i libvirtxml: Expecting a filename (XML file). *)
d0ea73
@@ -448,7 +470,7 @@ read the man page virt-v2v(1).
d0ea73
         match input_transport with
d0ea73
         | None -> None
d0ea73
         | Some `SSH -> Some `SSH
d0ea73
-        | Some `VDDK ->
d0ea73
+        | Some (`VDDK _) ->
d0ea73
            error (f_"only ‘-it ssh’ can be used here") in
d0ea73
       Input_vmx.input_vmx input_transport arg in
d0ea73
 
d0ea73
@@ -546,7 +568,7 @@ read the man page virt-v2v(1).
d0ea73
       Output_rhv.output_rhv os output_alloc,
d0ea73
       output_format, output_alloc
d0ea73
 
d0ea73
-    | `VDSM ->
d0ea73
+    | `VDSM vdsm_options ->
d0ea73
       if output_password <> None then
d0ea73
         error_option_cannot_be_used_in_output_mode "vdsm" "-op";
d0ea73
       let os =
d0ea73
@@ -556,21 +578,6 @@ read the man page virt-v2v(1).
d0ea73
         | Some d -> d in
d0ea73
       if qemu_boot then
d0ea73
         error_option_cannot_be_used_in_output_mode "vdsm" "--qemu-boot";
d0ea73
-      let vdsm_vm_uuid =
d0ea73
-        match vdsm_vm_uuid with
d0ea73
-        | None ->
d0ea73
-           error (f_"-o vdsm: --vdsm-image-uuid was not specified")
d0ea73
-        | Some s -> s in
d0ea73
-      if vdsm_image_uuids = [] || vdsm_vol_uuids = [] then
d0ea73
-        error (f_"-o vdsm: either --vdsm-vol-uuid or --vdsm-vm-uuid was not specified");
d0ea73
-      let vdsm_options = {
d0ea73
-        Output_vdsm.image_uuids = vdsm_image_uuids;
d0ea73
-        vol_uuids = vdsm_vol_uuids;
d0ea73
-        vm_uuid = vdsm_vm_uuid;
d0ea73
-        ovf_output = vdsm_ovf_output;
d0ea73
-        compat = vdsm_compat;
d0ea73
-        ovf_flavour = vdsm_ovf_flavour;
d0ea73
-      } in
d0ea73
       Output_vdsm.output_vdsm os vdsm_options output_alloc,
d0ea73
       output_format, output_alloc in
d0ea73
 
d0ea73
diff --git a/v2v/input_libvirt.ml b/v2v/input_libvirt.ml
d0ea73
index 25c81b924..377257dc2 100644
d0ea73
--- a/v2v/input_libvirt.ml
d0ea73
+++ b/v2v/input_libvirt.ml
d0ea73
@@ -27,7 +27,7 @@ open Types
d0ea73
 open Utils
d0ea73
 
d0ea73
 (* Choose the right subclass based on the URI. *)
d0ea73
-let input_libvirt vddk_options password libvirt_uri input_transport guest =
d0ea73
+let input_libvirt password libvirt_uri input_transport guest =
d0ea73
   match libvirt_uri with
d0ea73
   | None ->
d0ea73
     Input_libvirt_other.input_libvirt_other password libvirt_uri guest
d0ea73
@@ -53,7 +53,7 @@ let input_libvirt vddk_options password libvirt_uri input_transport guest =
d0ea73
          password libvirt_uri parsed_uri server guest
d0ea73
 
d0ea73
     (* vCenter or ESXi using nbdkit vddk plugin *)
d0ea73
-    | Some server, Some ("esx"|"gsx"|"vpx"), Some `VDDK ->
d0ea73
+    | Some server, Some ("esx"|"gsx"|"vpx"), Some (`VDDK vddk_options) ->
d0ea73
        Input_libvirt_vddk.input_libvirt_vddk vddk_options password
d0ea73
                                              libvirt_uri parsed_uri guest
d0ea73
 
d0ea73
diff --git a/v2v/input_libvirt.mli b/v2v/input_libvirt.mli
d0ea73
index 6f9162482..08824bb67 100644
d0ea73
--- a/v2v/input_libvirt.mli
d0ea73
+++ b/v2v/input_libvirt.mli
d0ea73
@@ -18,7 +18,7 @@
d0ea73
 
d0ea73
 (** [-i libvirt] source. *)
d0ea73
 
d0ea73
-val input_libvirt : Input_libvirt_vddk.vddk_options -> string option -> string option -> [`VDDK] option -> string -> Types.input
d0ea73
-(** [input_libvirt vddk_options password libvirt_uri input_transport guest]
d0ea73
+val input_libvirt : string option -> string option -> [`VDDK of Input_libvirt_vddk.vddk_options] option -> string -> Types.input
d0ea73
+(** [input_libvirt password libvirt_uri input_transport guest]
d0ea73
     creates and returns a new {!Types.input} object specialized for reading
d0ea73
     input from libvirt sources. *)
d0ea73
diff --git a/v2v/input_libvirt_vddk.ml b/v2v/input_libvirt_vddk.ml
d0ea73
index a53f3e71d..0b3ed7af9 100644
d0ea73
--- a/v2v/input_libvirt_vddk.ml
d0ea73
+++ b/v2v/input_libvirt_vddk.ml
d0ea73
@@ -33,22 +33,73 @@ open Xpath_helpers
d0ea73
 
d0ea73
 open Printf
d0ea73
 
d0ea73
-type vddk_options = {
d0ea73
-    vddk_config : string option;
d0ea73
-    vddk_cookie : string option;
d0ea73
-    vddk_libdir : string option;
d0ea73
-    vddk_nfchostport : string option;
d0ea73
-    vddk_port : string option;
d0ea73
-    vddk_snapshot : string option;
d0ea73
-    vddk_thumbprint : string option;
d0ea73
-    vddk_transports : string option;
d0ea73
-    vddk_vimapiver : string option;
d0ea73
-}
d0ea73
+type vddk_options = (string * string) list
d0ea73
+
d0ea73
+(* List of vddk-* input options. *)
d0ea73
+let vddk_option_keys =
d0ea73
+  [ "config";
d0ea73
+    "cookie";
d0ea73
+    "libdir";
d0ea73
+    "nfchostport";
d0ea73
+    "port";
d0ea73
+    "snapshot";
d0ea73
+    "thumbprint";
d0ea73
+    "transports";
d0ea73
+    "vimapiver" ]
d0ea73
+
d0ea73
+let print_input_options () =
d0ea73
+  printf (f_"Input options (-io) which can be used with -it vddk:
d0ea73
+
d0ea73
+  -io vddk-thumbprint=xx:xx:xx:...
d0ea73
+                               VDDK server thumbprint (required)
d0ea73
+
d0ea73
+All other settings are optional:
d0ea73
+
d0ea73
+  -io vddk-config=FILE         VDDK configuration file
d0ea73
+  -io vddk-cookie=COOKIE       VDDK cookie
d0ea73
+  -io vddk-libdir=LIBDIR       VDDK library parent directory
d0ea73
+  -io vddk-nfchostport=PORT    VDDK nfchostport
d0ea73
+  -io vddk-port=PORT           VDDK port
d0ea73
+  -io vddk-snapshot=SNAPSHOT-MOREF
d0ea73
+                               VDDK snapshot moref
d0ea73
+  -io vddk-transports=MODE:MODE:..
d0ea73
+                               VDDK transports
d0ea73
+  -io vddk-vimapiver=APIVER    VDDK vimapiver
d0ea73
+
d0ea73
+Refer to nbdkit-vddk-plugin(1) and the VDDK documentation for further
d0ea73
+information on these settings.
d0ea73
+")
d0ea73
+
d0ea73
+let parse_input_options options =
d0ea73
+  (* Check there are no options we don't understand.  Also removes
d0ea73
+   * the "vddk-" prefix from the internal list.
d0ea73
+   *)
d0ea73
+  let options =
d0ea73
+    List.map (
d0ea73
+      fun (key, value) ->
d0ea73
+        let error_invalid_key () =
d0ea73
+          error (f_"-it vddk: ‘-io %s’ is not a valid input option") key
d0ea73
+        in
d0ea73
+        if not (String.is_prefix key "vddk-") then error_invalid_key ();
d0ea73
+        let key = String.sub key 5 (String.length key-5) in
d0ea73
+        if not (List.mem key vddk_option_keys) then error_invalid_key ();
d0ea73
+
d0ea73
+        (key, value)
d0ea73
+    ) options in
d0ea73
+
d0ea73
+  (* Check no option appears twice. *)
d0ea73
+  let keys = List.map fst options in
d0ea73
+  if List.length keys <> List.length (List.sort_uniq keys) then
d0ea73
+    error (f_"-it vddk: duplicate -io options on the command line");
d0ea73
+
d0ea73
+  options
d0ea73
 
d0ea73
 (* Subclass specialized for handling VMware via nbdkit vddk plugin. *)
d0ea73
 class input_libvirt_vddk vddk_options password libvirt_uri parsed_uri guest =
d0ea73
   (* The VDDK path. *)
d0ea73
-  let libdir = vddk_options.vddk_libdir in
d0ea73
+  let libdir =
d0ea73
+    try Some (List.assoc "libdir" vddk_options)
d0ea73
+    with Not_found -> None in
d0ea73
 
d0ea73
   (* VDDK libraries are located under lib32/ or lib64/ relative to the
d0ea73
    * libdir.  Note this is unrelated to Linux multilib or multiarch.
d0ea73
@@ -68,7 +119,7 @@ class input_libvirt_vddk vddk_options password libvirt_uri parsed_uri guest =
d0ea73
      | None -> ()
d0ea73
      | Some libdir ->
d0ea73
         if not (is_directory libdir) then
d0ea73
-          error (f_"‘--vddk-libdir %s’ does not point to a directory.  See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") libdir
d0ea73
+          error (f_"‘-io vddk-libdir=%s’ does not point to a directory.  See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") libdir
d0ea73
     );
d0ea73
 
d0ea73
     (match library_path with
d0ea73
@@ -122,15 +173,15 @@ See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.")
d0ea73
       else
d0ea73
         error (f_"nbdkit VDDK plugin is not installed or not working.  It is required if you want to use VDDK.
d0ea73
 
d0ea73
-It looks like you did not set the right path in the ‘--vddk-libdir’ option, or your copy of the VDDK directory is incomplete.  There should be a library called ’<libdir>/%s/libvixDiskLib.so.?’.
d0ea73
+It looks like you did not set the right path in the ‘-io vddk-libdir’ option, or your copy of the VDDK directory is incomplete.  There should be a library called ’<libdir>/%s/libvixDiskLib.so.?’.
d0ea73
 
d0ea73
 See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") libNN
d0ea73
     )
d0ea73
   in
d0ea73
 
d0ea73
   let error_unless_thumbprint () =
d0ea73
-    if vddk_options.vddk_thumbprint = None then
d0ea73
-      error (f_"You must pass the ‘--vddk-thumbprint’ option with the SSL thumbprint of the VMware server.  To find the thumbprint, see the nbdkit-vddk-plugin(1) manual.  See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.")
d0ea73
+    if not (List.mem_assoc "thumbprint" vddk_options) then
d0ea73
+      error (f_"You must pass the ‘-io vddk-thumbprint’ option with the SSL thumbprint of the VMware server.  To find the thumbprint, see the nbdkit-vddk-plugin(1) manual.  See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.")
d0ea73
   in
d0ea73
 
d0ea73
   (* Check that nbdkit was compiled with SELinux support (for the
d0ea73
@@ -147,18 +198,6 @@ See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") libNN
d0ea73
       error (f_"nbdkit was compiled without SELinux support.  You will have to recompile nbdkit with libselinux-devel installed, or else set SELinux to Permissive mode while doing the conversion.")
d0ea73
   in
d0ea73
 
d0ea73
-  (* List of passthrough parameters. *)
d0ea73
-  let vddk_passthrus =
d0ea73
-    [ "config",      (fun { vddk_config }      -> vddk_config);
d0ea73
-      "cookie",      (fun { vddk_cookie }      -> vddk_cookie);
d0ea73
-      "libdir",      (fun { vddk_libdir }      -> vddk_libdir);
d0ea73
-      "nfchostport", (fun { vddk_nfchostport } -> vddk_nfchostport);
d0ea73
-      "port",        (fun { vddk_port }        -> vddk_port);
d0ea73
-      "snapshot",    (fun { vddk_snapshot }    -> vddk_snapshot);
d0ea73
-      "thumbprint",  (fun { vddk_thumbprint }  -> vddk_thumbprint);
d0ea73
-      "transports",  (fun { vddk_transports }  -> vddk_transports);
d0ea73
-      "vimapiver",   (fun { vddk_vimapiver }   -> vddk_vimapiver) ] in
d0ea73
-
d0ea73
 object
d0ea73
   inherit input_libvirt password libvirt_uri guest as super
d0ea73
 
d0ea73
@@ -172,14 +211,9 @@ object
d0ea73
 
d0ea73
   method as_options =
d0ea73
     let pt_options =
d0ea73
-      String.concat "" (
d0ea73
-        List.map (
d0ea73
-          fun (name, get_field) ->
d0ea73
-            match get_field vddk_options with
d0ea73
-            | None -> ""
d0ea73
-            | Some field -> sprintf " --vddk-%s %s" name field
d0ea73
-        ) vddk_passthrus
d0ea73
-      ) in
d0ea73
+      String.concat ""
d0ea73
+                    (List.map (fun (k, v) ->
d0ea73
+                         sprintf " -io vddk-%s=%s" k v) vddk_options) in
d0ea73
     sprintf "%s -it vddk %s"
d0ea73
             super#as_options (* superclass prints "-i libvirt etc" *)
d0ea73
             pt_options
d0ea73
@@ -284,11 +318,7 @@ object
d0ea73
       add_arg (sprintf "vm=moref=%s" moref);
d0ea73
 
d0ea73
       (* The passthrough parameters. *)
d0ea73
-      List.iter (
d0ea73
-        fun (name, get_field) ->
d0ea73
-          Option.may (fun field -> add_arg (sprintf "%s=%s" name field))
d0ea73
-                     (get_field vddk_options)
d0ea73
-      ) vddk_passthrus;
d0ea73
+      List.iter (fun (k, v) -> add_arg (sprintf "%s=%s" k v)) vddk_options;
d0ea73
 
d0ea73
       get_args () in
d0ea73
 
d0ea73
diff --git a/v2v/input_libvirt_vddk.mli b/v2v/input_libvirt_vddk.mli
d0ea73
index c8606c72a..1cebba506 100644
d0ea73
--- a/v2v/input_libvirt_vddk.mli
d0ea73
+++ b/v2v/input_libvirt_vddk.mli
d0ea73
@@ -18,19 +18,13 @@
d0ea73
 
d0ea73
 (** [-i libvirt] when the source is VMware via nbdkit vddk plugin *)
d0ea73
 
d0ea73
-type vddk_options = {
d0ea73
-    vddk_config : string option;
d0ea73
-    vddk_cookie : string option;
d0ea73
-    vddk_libdir : string option;
d0ea73
-    vddk_nfchostport : string option;
d0ea73
-    vddk_port : string option;
d0ea73
-    vddk_snapshot : string option;
d0ea73
-    vddk_thumbprint : string option;
d0ea73
-    vddk_transports : string option;
d0ea73
-    vddk_vimapiver : string option;
d0ea73
-}
d0ea73
+type vddk_options
d0ea73
 (** Various options passed through to the nbdkit vddk plugin unmodified. *)
d0ea73
 
d0ea73
+val print_input_options : unit -> unit
d0ea73
+val parse_input_options : (string * string) list -> vddk_options
d0ea73
+(** Print and parse vddk -io options. *)
d0ea73
+
d0ea73
 val input_libvirt_vddk : vddk_options -> string option -> string option -> Xml.uri -> string -> Types.input
d0ea73
 (** [input_libvirt_vddk vddk_options password libvirt_uri parsed_uri guest]
d0ea73
     creates and returns a {!Types.input} object specialized for reading
d0ea73
diff --git a/v2v/output_vdsm.ml b/v2v/output_vdsm.ml
d0ea73
index b76a2e930..92b3fd122 100644
d0ea73
--- a/v2v/output_vdsm.ml
d0ea73
+++ b/v2v/output_vdsm.ml
d0ea73
@@ -35,23 +35,90 @@ type vdsm_options = {
d0ea73
   ovf_flavour : Create_ovf.ovf_flavour;
d0ea73
 }
d0ea73
 
d0ea73
+let ovf_flavours_str = String.concat "|" Create_ovf.ovf_flavours
d0ea73
+
d0ea73
+let print_output_options () =
d0ea73
+  printf (f_"Output options (-oo) which can be used with -o vdsm:
d0ea73
+
d0ea73
+  -oo vdsm-compat=0.10|1.1     Write qcow2 with compat=0.10|1.1
d0ea73
+                                   (default: 0.10)
d0ea73
+  -oo vdsm-vm-uuid=UUID        VM UUID (required)
d0ea73
+  -oo vdsm-ovf-output=DIR      OVF metadata directory (required)
d0ea73
+  -oo vdsm-ovf-flavour=%s
d0ea73
+                               Set the type of generated OVF (default: rhvexp)
d0ea73
+
d0ea73
+For each disk you must supply one of each of these options:
d0ea73
+
d0ea73
+  -oo vdsm-image-uuid=UUID     Image directory UUID
d0ea73
+  -oo vdsm-vol-uuid=UUID       Disk volume UUID
d0ea73
+") ovf_flavours_str
d0ea73
+
d0ea73
+let parse_output_options options =
d0ea73
+  let vm_uuid = ref None in
d0ea73
+  let ovf_output = ref None in (* default "." *)
d0ea73
+  let compat = ref "0.10" in
d0ea73
+  let ovf_flavour = ref Create_ovf.RHVExportStorageDomain in
d0ea73
+  let image_uuids = ref [] in
d0ea73
+  let vol_uuids = ref [] in
d0ea73
+
d0ea73
+  List.iter (
d0ea73
+    function
d0ea73
+    | "vdsm-compat", "0.10" -> compat := "0.10"
d0ea73
+    | "vdsm-compat", "1.1" -> compat := "1.1"
d0ea73
+    | "vdsm-compat", v ->
d0ea73
+       error (f_"-o vdsm: unknown vdsm-compat level ‘%s’") v
d0ea73
+    | "vdsm-vm-uuid", v ->
d0ea73
+       if !vm_uuid <> None then
d0ea73
+         error (f_"-o vdsm: -oo vdsm-vm-uuid set twice");
d0ea73
+       vm_uuid := Some v;
d0ea73
+    | "vdsm-ovf-output", v ->
d0ea73
+       if !ovf_output <> None then
d0ea73
+         error (f_"-o vdsm: -oo vdsm-ovf-output set twice");
d0ea73
+       ovf_output := Some v;
d0ea73
+    | "vdsm-ovf-flavour", v ->
d0ea73
+       ovf_flavour := Create_ovf.ovf_flavour_of_string v
d0ea73
+    | "vdsm-image-uuid", v ->
d0ea73
+       List.push_front v image_uuids
d0ea73
+    | "vdsm-vol-uuid", v ->
d0ea73
+       List.push_front v vol_uuids
d0ea73
+    | k, _ ->
d0ea73
+       error (f_"-o vdsm: unknown output option ‘-oo %s’") k
d0ea73
+  ) options;
d0ea73
+
d0ea73
+  let compat = !compat in
d0ea73
+  let image_uuids = List.rev !image_uuids in
d0ea73
+  let vol_uuids = List.rev !vol_uuids in
d0ea73
+  if image_uuids = [] || vol_uuids = [] then
d0ea73
+    error (f_"-o vdsm: either -oo vdsm-vol-uuid or -oo vdsm-vm-uuid was not specified");
d0ea73
+  let vm_uuid =
d0ea73
+    match !vm_uuid with
d0ea73
+    | None ->
d0ea73
+       error (f_"-o vdsm: -oo vdsm-image-uuid was not specified")
d0ea73
+    | Some uuid -> uuid in
d0ea73
+  let ovf_output = Option.default "." !ovf_output in
d0ea73
+  let ovf_flavour = !ovf_flavour in
d0ea73
+
d0ea73
+  { image_uuids; vol_uuids; vm_uuid; ovf_output; compat; ovf_flavour }
d0ea73
+
d0ea73
 class output_vdsm os vdsm_options output_alloc =
d0ea73
 object
d0ea73
   inherit output
d0ea73
 
d0ea73
   method as_options =
d0ea73
-    sprintf "-o vdsm -os %s%s%s --vdsm-vm-uuid %s --vdsm-ovf-output %s%s%s" os
d0ea73
+    sprintf "-o vdsm -os %s%s%s -oo vdsm-vm-uuid=%s -oo vdsm-ovf-output=%s%s%s" os
d0ea73
       (String.concat ""
d0ea73
-         (List.map (sprintf " --vdsm-image-uuid %s") vdsm_options.image_uuids))
d0ea73
+         (List.map (sprintf " -oo vdsm-image-uuid=%s")
d0ea73
+                   vdsm_options.image_uuids))
d0ea73
       (String.concat ""
d0ea73
-         (List.map (sprintf " --vdsm-vol-uuid %s") vdsm_options.vol_uuids))
d0ea73
+         (List.map (sprintf " -oo vdsm-vol-uuid=%s")
d0ea73
+                   vdsm_options.vol_uuids))
d0ea73
       vdsm_options.vm_uuid
d0ea73
       vdsm_options.ovf_output
d0ea73
       (match vdsm_options.compat with
d0ea73
        | "0.10" -> "" (* currently this is the default, so don't print it *)
d0ea73
-       | s -> sprintf " --vdsm-compat=%s" s)
d0ea73
+       | s -> sprintf " -oo vdsm-compat=%s" s)
d0ea73
       (match vdsm_options.ovf_flavour with
d0ea73
-       | Create_ovf.OVirt -> "--vdsm-ovf-flavour=ovf"
d0ea73
+       | Create_ovf.OVirt -> "-oo vdsm-ovf-flavour=ovf"
d0ea73
        (* currently this is the default, so don't print it *)
d0ea73
        | Create_ovf.RHVExportStorageDomain -> "")
d0ea73
 
d0ea73
@@ -84,7 +151,7 @@ object
d0ea73
   method prepare_targets _ targets =
d0ea73
     if List.length vdsm_options.image_uuids <> List.length targets ||
d0ea73
       List.length vdsm_options.vol_uuids <> List.length targets then
d0ea73
-      error (f_"the number of ‘--vdsm-image-uuid’ and ‘--vdsm-vol-uuid’ parameters passed on the command line has to match the number of guest disk images (for this guest: %d)")
d0ea73
+      error (f_"the number of ‘-oo vdsm-image-uuid’ and ‘-oo vdsm-vol-uuid’ parameters passed on the command line has to match the number of guest disk images (for this guest: %d)")
d0ea73
         (List.length targets);
d0ea73
 
d0ea73
     let mp, uuid =
d0ea73
diff --git a/v2v/output_vdsm.mli b/v2v/output_vdsm.mli
d0ea73
index 6ed684638..36f327900 100644
d0ea73
--- a/v2v/output_vdsm.mli
d0ea73
+++ b/v2v/output_vdsm.mli
d0ea73
@@ -18,16 +18,13 @@
d0ea73
 
d0ea73
 (** [-o vdsm] target. *)
d0ea73
 
d0ea73
-type vdsm_options = {
d0ea73
-  image_uuids : string list;          (* --vdsm-image-uuid (multiple) *)
d0ea73
-  vol_uuids : string list;            (* --vdsm-vol-uuid (multiple) *)
d0ea73
-  vm_uuid : string;                   (* --vdsm-vm-uuid *)
d0ea73
-  ovf_output : string;                (* --vdsm-ovf-output *)
d0ea73
-  compat : string;                    (* --vdsm-compat=0.10|1.1 *)
d0ea73
-  ovf_flavour : Create_ovf.ovf_flavour;
d0ea73
-}
d0ea73
+type vdsm_options
d0ea73
 (** Miscellaneous extra command line parameters used by VDSM. *)
d0ea73
 
d0ea73
+val print_output_options : unit -> unit
d0ea73
+val parse_output_options : (string * string) list -> vdsm_options
d0ea73
+(** Print and parse vdsm -oo options. *)
d0ea73
+
d0ea73
 val output_vdsm : string -> vdsm_options -> Types.output_allocation -> Types.output
d0ea73
 (** [output_vdsm os vdsm_options output_alloc] creates and
d0ea73
     returns a new {!Types.output} object specialized for writing
d0ea73
diff --git a/v2v/test-v2v-docs.sh b/v2v/test-v2v-docs.sh
d0ea73
index 0e3bd916a..e1e22b599 100755
d0ea73
--- a/v2v/test-v2v-docs.sh
d0ea73
+++ b/v2v/test-v2v-docs.sh
d0ea73
@@ -22,4 +22,33 @@ $TEST_FUNCTIONS
d0ea73
 skip_if_skipped
d0ea73
 
d0ea73
 $top_srcdir/podcheck.pl virt-v2v.pod virt-v2v \
d0ea73
-  --ignore=--debug-overlay,--ic,--if,--it,--no-trim,--oa,--oc,--of,--on,--op,--os,--vmtype
d0ea73
+  --ignore=\
d0ea73
+--debug-overlay,\
d0ea73
+--ic,\
d0ea73
+--if,\
d0ea73
+--io,\
d0ea73
+--it,\
d0ea73
+--no-trim,\
d0ea73
+--oa,\
d0ea73
+--oc,\
d0ea73
+--of,\
d0ea73
+--on,\
d0ea73
+--oo,\
d0ea73
+--op,\
d0ea73
+--os,\
d0ea73
+--vddk-config,\
d0ea73
+--vddk-cookie,\
d0ea73
+--vddk-libdir,\
d0ea73
+--vddk-nfchostport,\
d0ea73
+--vddk-port,\
d0ea73
+--vddk-snapshot,\
d0ea73
+--vddk-thumbprint,\
d0ea73
+--vddk-transports,\
d0ea73
+--vddk-vimapiver,\
d0ea73
+--vdsm-compat,\
d0ea73
+--vdsm-image-uuid,\
d0ea73
+--vdsm-ovf-flavour,\
d0ea73
+--vdsm-ovf-output,\
d0ea73
+--vdsm-vm-uuid,\
d0ea73
+--vdsm-vol-uuid,\
d0ea73
+--vmtype
d0ea73
diff --git a/v2v/test-v2v-it-vddk-io-query.sh b/v2v/test-v2v-it-vddk-io-query.sh
d0ea73
new file mode 100755
d0ea73
index 000000000..014e30207
d0ea73
--- /dev/null
d0ea73
+++ b/v2v/test-v2v-it-vddk-io-query.sh
d0ea73
@@ -0,0 +1,38 @@
d0ea73
+#!/bin/bash -
d0ea73
+# libguestfs virt-v2v test script
d0ea73
+# Copyright (C) 2018 Red Hat Inc.
d0ea73
+#
d0ea73
+# This program is free software; you can redistribute it and/or modify
d0ea73
+# it under the terms of the GNU General Public License as published by
d0ea73
+# the Free Software Foundation; either version 2 of the License, or
d0ea73
+# (at your option) any later version.
d0ea73
+#
d0ea73
+# This program is distributed in the hope that it will be useful,
d0ea73
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
d0ea73
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
d0ea73
+# GNU General Public License for more details.
d0ea73
+#
d0ea73
+# You should have received a copy of the GNU General Public License
d0ea73
+# along with this program; if not, write to the Free Software
d0ea73
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
d0ea73
+
d0ea73
+# Test -io "?" option.
d0ea73
+
d0ea73
+set -e
d0ea73
+
d0ea73
+$TEST_FUNCTIONS
d0ea73
+skip_if_skipped
d0ea73
+
d0ea73
+export VIRT_TOOLS_DATA_DIR="$top_srcdir/test-data/fake-virt-tools"
d0ea73
+export VIRTIO_WIN="$top_srcdir/test-data/fake-virtio-win"
d0ea73
+
d0ea73
+f=test-v2v-it-vddk-io-query.actual
d0ea73
+rm -f $f
d0ea73
+
d0ea73
+$VG virt-v2v --debug-gc \
d0ea73
+    -it vddk -io "?" > $f
d0ea73
+
d0ea73
+grep -- "-io vddk-config" $f
d0ea73
+grep -- "-io vddk-thumbprint" $f
d0ea73
+
d0ea73
+rm $f
d0ea73
diff --git a/v2v/test-v2v-o-vdsm-oo-query.sh b/v2v/test-v2v-o-vdsm-oo-query.sh
d0ea73
new file mode 100755
d0ea73
index 000000000..5691446ea
d0ea73
--- /dev/null
d0ea73
+++ b/v2v/test-v2v-o-vdsm-oo-query.sh
d0ea73
@@ -0,0 +1,38 @@
d0ea73
+#!/bin/bash -
d0ea73
+# libguestfs virt-v2v test script
d0ea73
+# Copyright (C) 2018 Red Hat Inc.
d0ea73
+#
d0ea73
+# This program is free software; you can redistribute it and/or modify
d0ea73
+# it under the terms of the GNU General Public License as published by
d0ea73
+# the Free Software Foundation; either version 2 of the License, or
d0ea73
+# (at your option) any later version.
d0ea73
+#
d0ea73
+# This program is distributed in the hope that it will be useful,
d0ea73
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
d0ea73
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
d0ea73
+# GNU General Public License for more details.
d0ea73
+#
d0ea73
+# You should have received a copy of the GNU General Public License
d0ea73
+# along with this program; if not, write to the Free Software
d0ea73
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
d0ea73
+
d0ea73
+# Test -oo "?" option.
d0ea73
+
d0ea73
+set -e
d0ea73
+
d0ea73
+$TEST_FUNCTIONS
d0ea73
+skip_if_skipped
d0ea73
+
d0ea73
+export VIRT_TOOLS_DATA_DIR="$top_srcdir/test-data/fake-virt-tools"
d0ea73
+export VIRTIO_WIN="$top_srcdir/test-data/fake-virtio-win"
d0ea73
+
d0ea73
+f=test-v2v-o-vdsm-oo-query.actual
d0ea73
+rm -f $f
d0ea73
+
d0ea73
+$VG virt-v2v --debug-gc \
d0ea73
+    -o vdsm -oo "?" > $f
d0ea73
+
d0ea73
+grep -- "-oo vdsm-compat" $f
d0ea73
+grep -- "-oo vdsm-image-uuid" $f
d0ea73
+
d0ea73
+rm $f
d0ea73
diff --git a/v2v/test-v2v-o-vdsm-options.sh b/v2v/test-v2v-o-vdsm-options.sh
d0ea73
index 4ad5d4aad..65ce1234e 100755
d0ea73
--- a/v2v/test-v2v-o-vdsm-options.sh
d0ea73
+++ b/v2v/test-v2v-o-vdsm-options.sh
d0ea73
@@ -16,7 +16,7 @@
d0ea73
 # along with this program; if not, write to the Free Software
d0ea73
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
d0ea73
 
d0ea73
-# Test -o vdsm options --vdsm-*-uuid
d0ea73
+# Test -o vdsm options -oo vdsm-*-uuid
d0ea73
 
d0ea73
 set -e
d0ea73
 set -x
d0ea73
@@ -44,19 +44,19 @@ mkdir $d/12345678-1234-1234-1234-123456789abc/master
d0ea73
 mkdir $d/12345678-1234-1234-1234-123456789abc/master/vms
d0ea73
 mkdir $d/12345678-1234-1234-1234-123456789abc/master/vms/VM
d0ea73
 
d0ea73
-# The --vdsm-*-uuid options don't actually check that the
d0ea73
+# The -oo vdsm-*-uuid options don't actually check that the
d0ea73
 # parameter is a UUID, which is useful here.
d0ea73
 
d0ea73
 $VG virt-v2v --debug-gc \
d0ea73
     -i libvirt -ic "$libvirt_uri" windows \
d0ea73
     -o vdsm -os $d/12345678-1234-1234-1234-123456789abc \
d0ea73
     -of qcow2 \
d0ea73
-    --vdsm-image-uuid IMAGE \
d0ea73
-    --vdsm-vol-uuid VOL \
d0ea73
-    --vdsm-vm-uuid VM \
d0ea73
-    --vdsm-ovf-output $d/12345678-1234-1234-1234-123456789abc/master/vms/VM \
d0ea73
-    --vdsm-compat=1.1 \
d0ea73
-    --vdsm-ovf-flavour=ovirt
d0ea73
+    -oo vdsm-image-uuid=IMAGE \
d0ea73
+    -oo vdsm-vol-uuid=VOL \
d0ea73
+    -oo vdsm-vm-uuid=VM \
d0ea73
+    -oo vdsm-ovf-output=$d/12345678-1234-1234-1234-123456789abc/master/vms/VM \
d0ea73
+    -oo vdsm-compat=1.1 \
d0ea73
+    -oo vdsm-ovf-flavour=ovirt
d0ea73
 
d0ea73
 # Test the OVF metadata was created.
d0ea73
 test -f $d/12345678-1234-1234-1234-123456789abc/master/vms/VM/VM.ovf
d0ea73
diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
d0ea73
index 00ba45555..69ca23dfd 100644
d0ea73
--- a/v2v/virt-v2v.pod
d0ea73
+++ b/v2v/virt-v2v.pod
d0ea73
@@ -397,6 +397,47 @@ See L</IN PLACE CONVERSION> below.
d0ea73
 
d0ea73
 Conflicts with all I<-o *> options.
d0ea73
 
d0ea73
+=item B<-io> OPTION=VALUE
d0ea73
+
d0ea73
+Set input option(s) related to the current input mode or transport.
d0ea73
+To display short help on what options are available you can use:
d0ea73
+
d0ea73
+ virt-v2v -it vddk -io "?"
d0ea73
+
d0ea73
+=item B<-io vddk-libdir=>LIBDIR
d0ea73
+
d0ea73
+Set the VDDK library directory.  This directory should I<contain>
d0ea73
+subdirectories called F<include>, F<lib64> etc., but do not include
d0ea73
+F<lib64> actually in the parameter.
d0ea73
+
d0ea73
+In most cases this parameter is required when using the I<-it vddk>
d0ea73
+(VDDK) transport.  See L</INPUT FROM VDDK> below for details.
d0ea73
+
d0ea73
+=item B<-io vddk-thumbprint=>xx:xx:xx:...
d0ea73
+
d0ea73
+Set the thumbprint of the remote VMware server.
d0ea73
+
d0ea73
+This parameter is required when using the I<-it vddk> (VDDK) transport.
d0ea73
+See L</INPUT FROM VDDK> below for details.
d0ea73
+
d0ea73
+=item B<-io vddk-config=>FILENAME
d0ea73
+
d0ea73
+=item B<-io vddk-cookie=>COOKIE
d0ea73
+
d0ea73
+=item B<-io vddk-nfchostport=>PORT
d0ea73
+
d0ea73
+=item B<-io vddk-port=>PORT
d0ea73
+
d0ea73
+=item B<-io vddk-snapshot=>SNAPSHOT-MOREF
d0ea73
+
d0ea73
+=item B<-io vddk-transports=>MODE:MODE:...
d0ea73
+
d0ea73
+=item B<-io vddk-vimapiver=>APIVER
d0ea73
+
d0ea73
+When using VDDK mode, these options are passed unmodified to the
d0ea73
+L<nbdkit(1)> VDDK plugin.  Please refer to L<nbdkit-vddk-plugin(1)>.
d0ea73
+These are all optional.
d0ea73
+
d0ea73
 =item B<-it> B<ssh>
d0ea73
 
d0ea73
 When using I<-i vmx>, this enables the ssh transport.
d0ea73
@@ -406,7 +447,7 @@ See L</INPUT FROM VMWARE VMX> below.
d0ea73
 
d0ea73
 Use VMware VDDK as a transport to copy the input disks.  See
d0ea73
 L</INPUT FROM VDDK> below.  If you use this parameter then you may
d0ea73
-need to use other I<--vddk*> options to specify how to connect through
d0ea73
+need to use other I<-io vddk*> options to specify how to connect through
d0ea73
 VDDK.
d0ea73
 
d0ea73
 =item B<--keys-from-stdin>
d0ea73
@@ -569,6 +610,95 @@ If not specified, then the input format is used.
d0ea73
 Rename the guest when converting it.  If this option is not used then
d0ea73
 the output name is the same as the input name.
d0ea73
 
d0ea73
+=item B<-oo> OPTION=VALUE
d0ea73
+
d0ea73
+Set output option(s) related to the current output mode.
d0ea73
+To display short help on what options are available you can use:
d0ea73
+
d0ea73
+ virt-v2v -o vdsm -oo "?"
d0ea73
+
d0ea73
+=item B<-oo vdsm-compat=0.10>
d0ea73
+
d0ea73
+=item B<-oo vdsm-compat=1.1>
d0ea73
+
d0ea73
+If I<-o vdsm> and the output format is qcow2, then we add the qcow2
d0ea73
+I<compat=0.10> option to the output file for compatibility with RHEL 6
d0ea73
+(see L<https://bugzilla.redhat.com/1145582>).
d0ea73
+
d0ea73
+If I<-oo vdsm-compat=1.1> is used then modern qcow2 (I<compat=1.1>)
d0ea73
+files are generated instead.
d0ea73
+
d0ea73
+Currently I<-oo vdsm-compat=0.10> is the default, but this will change
d0ea73
+to I<-oo vdsm-compat=1.1> in a future version of virt-v2v (when we can
d0ea73
+assume that everyone is using a modern version of qemu).
d0ea73
+
d0ea73
+B<Note this option only affects I<-o vdsm> output>.  All other output
d0ea73
+modes (including I<-o rhv>) generate modern qcow2 I<compat=1.1>
d0ea73
+files, always.
d0ea73
+
d0ea73
+If this option is available, then C<vdsm-compat-option> will appear in
d0ea73
+the I<--machine-readable> output.
d0ea73
+
d0ea73
+=item B<-oo vdsm-image-uuid=>UUID
d0ea73
+
d0ea73
+=item B<-oo vdsm-vol-uuid=>UUID
d0ea73
+
d0ea73
+=item B<-oo vdsm-vm-uuid=>UUID
d0ea73
+
d0ea73
+=item B<-oo vdsm-ovf-output=>DIR
d0ea73
+
d0ea73
+Normally the RHV output mode chooses random UUIDs for the target
d0ea73
+guest.  However VDSM needs to control the UUIDs and passes these
d0ea73
+parameters when virt-v2v runs under VDSM control.  The parameters
d0ea73
+control:
d0ea73
+
d0ea73
+=over 4
d0ea73
+
d0ea73
+=item *
d0ea73
+
d0ea73
+the image directory of each guest disk (I<-oo vdsm-image-uuid>) (this
d0ea73
+option is passed once for each guest disk)
d0ea73
+
d0ea73
+=item *
d0ea73
+
d0ea73
+UUIDs for each guest disk (I<-oo vdsm-vol-uuid>) (this option
d0ea73
+is passed once for each guest disk)
d0ea73
+
d0ea73
+=item *
d0ea73
+
d0ea73
+the OVF file name (I<-oo vdsm-vm-uuid>).
d0ea73
+
d0ea73
+=item *
d0ea73
+
d0ea73
+the OVF output directory (default current directory) (I<-oo vdsm-ovf-output>).
d0ea73
+
d0ea73
+=back
d0ea73
+
d0ea73
+The format of UUIDs is: C<12345678-1234-1234-1234-123456789abc> (each
d0ea73
+hex digit can be C<0-9> or C<a-f>), conforming to S<OSF DCE 1.1>.
d0ea73
+
d0ea73
+These options can only be used with I<-o vdsm>.
d0ea73
+
d0ea73
+=item B<-oo vdsm-ovf-flavour=>flavour
d0ea73
+
d0ea73
+This option controls the format of the OVF generated at the end of conversion.
d0ea73
+Currently there are two possible flavours:
d0ea73
+
d0ea73
+=over 4
d0ea73
+
d0ea73
+=item rhevexp
d0ea73
+
d0ea73
+The OVF format used in RHV export storage domain.
d0ea73
+
d0ea73
+=item ovirt
d0ea73
+
d0ea73
+The OVF format understood by oVirt REST API.
d0ea73
+
d0ea73
+=back
d0ea73
+
d0ea73
+For backward compatibility the default is I<rhevexp>, but this may change in
d0ea73
+the future.
d0ea73
+
d0ea73
 =item B<-op> file
d0ea73
 
d0ea73
 Supply a file containing a password to be used when connecting to the
d0ea73
@@ -670,122 +800,6 @@ boot an operating system from the first virtio disk.  Specifically,
d0ea73
 F</boot> must be on the first virtio disk, and it cannot chainload an
d0ea73
 OS which is not in the first virtio disk.
d0ea73
 
d0ea73
-=item B<--vddk-libdir> LIBDIR
d0ea73
-
d0ea73
-Set the VDDK library directory.  This directory should I<contain>
d0ea73
-subdirectories called F<include>, F<lib64> etc., but do not include
d0ea73
-F<lib64> actually in the parameter.
d0ea73
-
d0ea73
-In most cases this parameter is required when using the I<-it vddk>
d0ea73
-(VDDK) transport.  See L</INPUT FROM VDDK> below for details.
d0ea73
-
d0ea73
-=item B<--vddk-thumbprint> xx:xx:xx:...
d0ea73
-
d0ea73
-Set the thumbprint of the remote VMware server.
d0ea73
-
d0ea73
-This parameter is required when using the I<-it vddk> (VDDK) transport.
d0ea73
-See L</INPUT FROM VDDK> below for details.
d0ea73
-
d0ea73
-=item B<--vddk-config> FILENAME
d0ea73
-
d0ea73
-=item B<--vddk-cookie> COOKIE
d0ea73
-
d0ea73
-=item B<--vddk-nfchostport> PORT
d0ea73
-
d0ea73
-=item B<--vddk-port> PORT
d0ea73
-
d0ea73
-=item B<--vddk-snapshot> SNAPSHOT-MOREF
d0ea73
-
d0ea73
-=item B<--vddk-transports> MODE:MODE:...
d0ea73
-
d0ea73
-=item B<--vddk-vimapiver> APIVER
d0ea73
-
d0ea73
-When using VDDK mode, these options are passed unmodified to the
d0ea73
-L<nbdkit(1)> VDDK plugin.  Please refer to L<nbdkit-vddk-plugin(1)>.
d0ea73
-These are all optional.
d0ea73
-
d0ea73
-=item B<--vdsm-compat=0.10>
d0ea73
-
d0ea73
-=item B<--vdsm-compat=1.1>
d0ea73
-
d0ea73
-If I<-o vdsm> and the output format is qcow2, then we add the qcow2
d0ea73
-I<compat=0.10> option to the output file for compatibility with RHEL 6
d0ea73
-(see L<https://bugzilla.redhat.com/1145582>).
d0ea73
-
d0ea73
-If I<--vdsm-compat=1.1> is used then modern qcow2 (I<compat=1.1>)
d0ea73
-files are generated instead.
d0ea73
-
d0ea73
-Currently I<--vdsm-compat=0.10> is the default, but this will change
d0ea73
-to I<--vdsm-compat=1.1> in a future version of virt-v2v (when we can
d0ea73
-assume that everyone is using a modern version of qemu).
d0ea73
-
d0ea73
-B<Note this option only affects I<-o vdsm> output>.  All other output
d0ea73
-modes (including I<-o rhv>) generate modern qcow2 I<compat=1.1>
d0ea73
-files, always.
d0ea73
-
d0ea73
-If this option is available, then C<vdsm-compat-option> will appear in
d0ea73
-the I<--machine-readable> output.
d0ea73
-
d0ea73
-=item B<--vdsm-image-uuid> UUID
d0ea73
-
d0ea73
-=item B<--vdsm-vol-uuid> UUID
d0ea73
-
d0ea73
-=item B<--vdsm-vm-uuid> UUID
d0ea73
-
d0ea73
-=item B<--vdsm-ovf-output>
d0ea73
-
d0ea73
-Normally the RHV output mode chooses random UUIDs for the target
d0ea73
-guest.  However VDSM needs to control the UUIDs and passes these
d0ea73
-parameters when virt-v2v runs under VDSM control.  The parameters
d0ea73
-control:
d0ea73
-
d0ea73
-=over 4
d0ea73
-
d0ea73
-=item *
d0ea73
-
d0ea73
-the image directory of each guest disk (I<--vdsm-image-uuid>) (this
d0ea73
-option is passed once for each guest disk)
d0ea73
-
d0ea73
-=item *
d0ea73
-
d0ea73
-UUIDs for each guest disk (I<--vdsm-vol-uuid>) (this option
d0ea73
-is passed once for each guest disk)
d0ea73
-
d0ea73
-=item *
d0ea73
-
d0ea73
-the OVF file name (I<--vdsm-vm-uuid>).
d0ea73
-
d0ea73
-=item *
d0ea73
-
d0ea73
-the OVF output directory (default current directory) (I<--vdsm-ovf-output>).
d0ea73
-
d0ea73
-=back
d0ea73
-
d0ea73
-The format of UUIDs is: C<12345678-1234-1234-1234-123456789abc> (each
d0ea73
-hex digit can be C<0-9> or C<a-f>), conforming to S<OSF DCE 1.1>.
d0ea73
-
d0ea73
-These options can only be used with I<-o vdsm>.
d0ea73
-
d0ea73
-=item B<--vdsm-ovf-flavour> flavour
d0ea73
-
d0ea73
-This option controls the format of the OVF generated at the end of conversion.
d0ea73
-Currently there are two possible flavours:
d0ea73
-
d0ea73
-=over 4
d0ea73
-
d0ea73
-=item rhevexp
d0ea73
-
d0ea73
-The OVF format used in RHV export storage domain.
d0ea73
-
d0ea73
-=item ovirt
d0ea73
-
d0ea73
-The OVF format understood by oVirt REST API.
d0ea73
-
d0ea73
-=back
d0ea73
-
d0ea73
-For backward compatibility the default is I<rhevexp>, but this may change in
d0ea73
-the future.
d0ea73
-
d0ea73
 =item B<-v>
d0ea73
 
d0ea73
 =item B<--verbose>
d0ea73
@@ -1679,15 +1693,15 @@ SSL thumbprint:
d0ea73
  $ virt-v2v \
d0ea73
      -ic 'vpx://root@vcenter.example.com/Datacenter/esxi?no_verify=1' \
d0ea73
      -it vddk \
d0ea73
-     --vddk-libdir /path/to/vmware-vix-disklib-distrib \
d0ea73
-     --vddk-thumbprint xx:xx:xx:... \
d0ea73
+     -io vddk-libdir=/path/to/vmware-vix-disklib-distrib \
d0ea73
+     -io vddk-thumbprint=xx:xx:xx:... \
d0ea73
      "Windows 2003" \
d0ea73
      -o local -os /var/tmp
d0ea73
 
d0ea73
 Other options that you might need to add in rare circumstances include
d0ea73
-I<--vddk-config>, I<--vddk-cookie>, I<--vddk-nfchostport>,
d0ea73
-I<--vddk-port>, I<--vddk-snapshot>, I<--vddk-transports> and
d0ea73
-I<--vddk-vimapiver>, which are all explained in the
d0ea73
+I<-io vddk-config>, I<-io vddk-cookie>, I<-io vddk-nfchostport>,
d0ea73
+I<-io vddk-port>, I<-io vddk-snapshot>, I<-io vddk-transports> and
d0ea73
+I<-io vddk-vimapiver>, which are all explained in the
d0ea73
 L<nbdkit-vddk-plugin(1)> documentation.
d0ea73
 
d0ea73
 =head2 VDDK: DEBUGGING VDDK FAILURES
d0ea73
-- 
6b9fda
2.21.0
d0ea73