commit 55f389ae1e457224a3f7aaf7d99a087a9fa62889 Author: James Antill Date: Mon Aug 8 14:11:14 2022 -0400 Import rpm: e21fe6460a1fa0cc0e82243f49afd37162e34ded diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..21d0719 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +SOURCES/RHEV-Application-Provisioning-Tool.exe_4.43-5 +SOURCES/libguestfs.keyring +SOURCES/rhsrvany-fd659e77cdd9da484fdc9dcbe0605c62ec26fa30.tar.gz +SOURCES/rhsrvany.exe +SOURCES/virt-v2v-1.42.0.tar.gz diff --git a/0001-RHEL-v2v-Select-correct-qemu-binary-for-o-qemu-mode-.patch b/0001-RHEL-v2v-Select-correct-qemu-binary-for-o-qemu-mode-.patch new file mode 100644 index 0000000..89790ba --- /dev/null +++ b/0001-RHEL-v2v-Select-correct-qemu-binary-for-o-qemu-mode-.patch @@ -0,0 +1,30 @@ +From d7c0992dfb11982d96cac8e279c454d82787918a Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sun, 28 Sep 2014 19:14:43 +0100 +Subject: [PATCH] RHEL: v2v: Select correct qemu binary for -o qemu mode + (RHBZ#1147313). + +RHEL does not have qemu-system-x86_64 (etc), and in addition the +qemu binary is located in /usr/libexec. Encode the path to this +binary directly in the script. + +Note that we don't support people running qemu directly like this. +It's just for quick testing of converted VMs, and to help us with +support cases. +--- + output/output_qemu.ml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/output/output_qemu.ml b/output/output_qemu.ml +index 3269fba5..7f2e9284 100644 +--- a/output/output_qemu.ml ++++ b/output/output_qemu.ml +@@ -137,7 +137,7 @@ module QEMU = struct + * module deals with shell and qemu comma quoting. + *) + let cmd = Qemuopts.create () in +- Qemuopts.set_binary_by_arch cmd (Some guestcaps.gcaps_arch); ++ Qemuopts.set_binary cmd "/usr/libexec/qemu-kvm"; + + let flag = Qemuopts.flag cmd + and arg = Qemuopts.arg cmd diff --git a/0001-libvirt-make-use-of-libvirt-s-default-auth-handler-R.patch b/0001-libvirt-make-use-of-libvirt-s-default-auth-handler-R.patch new file mode 100644 index 0000000..00a9bbb --- /dev/null +++ b/0001-libvirt-make-use-of-libvirt-s-default-auth-handler-R.patch @@ -0,0 +1,41 @@ +From 2ab37349cf37d0ffdb9929ca24c2a024600a4848 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Thu, 21 May 2020 13:32:21 +0200 +Subject: [PATCH] libvirt: make use of libvirt's default auth handler + (RHBZ#1838425) + +Use the default libvirt authentication handler as base for ours, +overriding it with our callback only in case we have a password to +supply. + +(cherry picked from commit ce66cac50179baf2fb8b404f7eba49048c7819b0) +--- + v2v/libvirt_utils.ml | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/v2v/libvirt_utils.ml b/v2v/libvirt_utils.ml +index 7df17b29..4d0b8639 100644 +--- a/v2v/libvirt_utils.ml ++++ b/v2v/libvirt_utils.ml +@@ -33,10 +33,14 @@ let auth_for_password_file ?password_file () = + ) creds + in + +- { +- Libvirt.Connect.credtype = [ Libvirt.Connect.CredentialPassphrase ]; +- cb = auth_fn; +- } ++ let base_auth = Libvirt.Connect.get_auth_default () in ++ ++ if password_file = None then ++ base_auth ++ else ++ { base_auth with ++ cb = auth_fn; ++ } + + let get_domain conn name = + let dom = +-- +2.31.1 + diff --git a/0001-options-Use-new-cryptsetup-open-API-if-available.patch b/0001-options-Use-new-cryptsetup-open-API-if-available.patch new file mode 100644 index 0000000..1347302 --- /dev/null +++ b/0001-options-Use-new-cryptsetup-open-API-if-available.patch @@ -0,0 +1,34 @@ +From 96ea18db4a4f2e336145553c0fbbba59ede2221e Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 30 Mar 2020 14:34:43 +0100 +Subject: [PATCH 1/4] options: Use new cryptsetup-open API if available. + +Fall back to luks-open if we're using libguestfs <= 1.43.1. +--- + options/decrypt.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/options/decrypt.c b/options/decrypt.c +index 683cf5e..d868f70 100644 +--- a/common/options/decrypt.c ++++ b/common/options/decrypt.c +@@ -97,11 +97,15 @@ inspect_do_decrypt (guestfs_h *g, struct key_store *ks) + + /* Try each key in turn. */ + for (j = 0; keys[j] != NULL; ++j) { +- /* XXX Should we call guestfs_luks_open_ro if readonly flag ++ /* XXX Should we set GUESTFS_CRYPTSETUP_OPEN_READONLY if readonly + * is set? This might break 'mount_ro'. + */ + guestfs_push_error_handler (g, NULL, NULL); ++#ifdef GUESTFS_HAVE_CRYPTSETUP_OPEN ++ r = guestfs_cryptsetup_open (g, partitions[i], keys[j], mapname, -1); ++#else + r = guestfs_luks_open (g, partitions[i], keys[j], mapname); ++#endif + guestfs_pop_error_handler (g); + if (r == 0) + goto opened; +-- +2.18.4 + diff --git a/0002-RHEL-v2v-Disable-the-qemu-boot-oo-qemu-boot-option-R.patch b/0002-RHEL-v2v-Disable-the-qemu-boot-oo-qemu-boot-option-R.patch new file mode 100644 index 0000000..b5ef618 --- /dev/null +++ b/0002-RHEL-v2v-Disable-the-qemu-boot-oo-qemu-boot-option-R.patch @@ -0,0 +1,109 @@ +From 610f53a67a0804ee76e9213c503b7bb00dd722b8 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 30 Sep 2014 10:50:27 +0100 +Subject: [PATCH] RHEL: v2v: Disable the --qemu-boot / -oo qemu-boot option + (RHBZ#1147313). + +This cannot work because there is no Gtk or SDL output mode +in RHEL's qemu-kvm. + +In addition you will have to edit the -display option in the +qemu script. +--- + docs/virt-v2v-output-local.pod | 6 ++---- + docs/virt-v2v.pod | 12 ------------ + output/output_qemu.ml | 3 +++ + v2v/v2v.ml | 2 -- + 4 files changed, 5 insertions(+), 18 deletions(-) + +diff --git a/docs/virt-v2v-output-local.pod b/docs/virt-v2v-output-local.pod +index d2a1c270..0be37f5e 100644 +--- a/docs/virt-v2v-output-local.pod ++++ b/docs/virt-v2v-output-local.pod +@@ -9,7 +9,7 @@ or libvirt + + virt-v2v [-i* options] -o local -os DIRECTORY + +- virt-v2v [-i* options] -o qemu -os DIRECTORY [--qemu-boot] ++ virt-v2v [-i* options] -o qemu -os DIRECTORY + + virt-v2v [-i* options] -o null + +@@ -47,12 +47,10 @@ where C is the guest name. + + =item B<-o qemu -os> C + +-=item B<-o qemu -os> C B<--qemu-boot> +- + This converts the guest to files in C. Unlike I<-o local> + above, a shell script is created which contains the raw qemu command + you would need to boot the guest. However the shell script is not +-run, I you also add the I<--qemu-boot> option. ++run. + + =item B<-o null> + +diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod +index 4e912b6c..7d0bafff 100644 +--- a/docs/virt-v2v.pod ++++ b/docs/virt-v2v.pod +@@ -139,11 +139,6 @@ Since F contains the path(s) to the guest disk + image(s) you do not need to specify the name of the disk image on the + command line. + +-To convert a local disk image and immediately boot it in local +-qemu, do: +- +- virt-v2v -i disk disk.img -o qemu -os /var/tmp -oo qemu-boot +- + =head1 OPTIONS + + =over 4 +@@ -487,9 +482,6 @@ This is similar to I<-o local>, except that a shell script is written + which you can use to boot the guest in qemu. The converted disks and + shell script are written to the directory specified by I<-os>. + +-When using this output mode, you can also specify the I<-oo qemu-boot> +-option which boots the guest under qemu immediately. +- + =item B<-o> B + + This is the same as I<-o rhv>. +@@ -743,10 +735,6 @@ Print information about the source guest and stop. This option is + useful when you are setting up network and bridge maps. + See L. + +-=item B<--qemu-boot> +- +-This is the same as I<-oo qemu-boot>. +- + =item B<-q> + + =item B<--quiet> +diff --git a/output/output_qemu.ml b/output/output_qemu.ml +index 7f2e9284..527d3c5e 100644 +--- a/output/output_qemu.ml ++++ b/output/output_qemu.ml +@@ -63,6 +63,9 @@ module QEMU = struct + ) options.output_options; + let qemu_boot = !qemu_boot in + ++ if qemu_boot then ++ error (f_"-o qemu: the -oo qemu-boot option cannot be used in RHEL"); ++ + (* -os must be set to a directory. *) + let output_storage = + match options.output_storage with +diff --git a/v2v/v2v.ml b/v2v/v2v.ml +index 9790416e..97b4e4ec 100644 +--- a/v2v/v2v.ml ++++ b/v2v/v2v.ml +@@ -270,8 +270,6 @@ let rec main () = + s_"Same as ‘-ip filename’"; + [ L"print-source" ], Getopt.Set print_source, + s_"Print source and stop"; +- [ L"qemu-boot" ], Getopt.Unit (fun () -> set_output_option_compat "qemu-boot" ""), +- s_"Boot in qemu (-o qemu only)"; + [ L"root" ], Getopt.String ("ask|... ", set_root_choice), + s_"How to choose root filesystem"; + [ L"vddk-config" ], Getopt.String ("filename", set_input_option_compat "vddk-config"), diff --git a/0002-i-libvirt-print-URI-without-connecting-RHBZ-1839917.patch b/0002-i-libvirt-print-URI-without-connecting-RHBZ-1839917.patch new file mode 100644 index 0000000..7bf3082 --- /dev/null +++ b/0002-i-libvirt-print-URI-without-connecting-RHBZ-1839917.patch @@ -0,0 +1,214 @@ +From e04f4d6aa0e94a61b40fa6b10a5274ea89cd96a1 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Mon, 25 May 2020 16:52:07 +0200 +Subject: [PATCH] -i libvirt: print URI without connecting (RHBZ#1839917) + +Pass (again) around the libvirt URI string in the various input_libvirt +subclasses so that input_libvirt#as_options does not need to connect to +print the connection URI. + +As related change: pass input_conn as non-optional string parameter in +classes that require one (all but input_libvirt_other, basically). This +avoids the need for extra checks. + +(cherry picked from commit 86d87563ee03e86ca9abdcad4f674af66a883006) +--- + v2v/input_libvirt.ml | 10 +++++----- + v2v/input_libvirt_other.ml | 12 ++++++++---- + v2v/input_libvirt_other.mli | 4 ++-- + v2v/input_libvirt_vcenter_https.ml | 4 ++-- + v2v/input_libvirt_vcenter_https.mli | 2 +- + v2v/input_libvirt_vddk.ml | 9 ++------- + v2v/input_libvirt_vddk.mli | 4 ++-- + v2v/input_libvirt_xen_ssh.ml | 4 ++-- + v2v/input_libvirt_xen_ssh.mli | 2 +- + 9 files changed, 25 insertions(+), 26 deletions(-) + +diff --git a/v2v/input_libvirt.ml b/v2v/input_libvirt.ml +index cd5f351c..352fae94 100644 +--- a/v2v/input_libvirt.ml ++++ b/v2v/input_libvirt.ml +@@ -53,22 +53,22 @@ let input_libvirt input_conn input_password input_transport guest = + + | Some _, None, _ (* No scheme? *) + | Some _, Some "", _ -> +- Input_libvirt_other.input_libvirt_other libvirt_conn guest ++ Input_libvirt_other.input_libvirt_other libvirt_conn ?input_conn guest + + (* vCenter over https. *) + | Some server, Some ("esx"|"gsx"|"vpx"), None -> + Input_libvirt_vcenter_https.input_libvirt_vcenter_https +- libvirt_conn input_password parsed_uri server guest ++ libvirt_conn orig_uri input_password parsed_uri server guest + + (* vCenter or ESXi using nbdkit vddk plugin *) + | Some server, Some ("esx"|"gsx"|"vpx"), Some (`VDDK vddk_options) -> + Input_libvirt_vddk.input_libvirt_vddk +- libvirt_conn input_conn input_password vddk_options parsed_uri guest ++ libvirt_conn orig_uri input_password vddk_options parsed_uri guest + + (* Xen over SSH *) + | Some server, Some "xen+ssh", _ -> + Input_libvirt_xen_ssh.input_libvirt_xen_ssh +- libvirt_conn input_password parsed_uri server guest ++ libvirt_conn orig_uri input_password parsed_uri server guest + + (* Old virt-v2v also supported qemu+ssh://. However I am + * deliberately not supporting this in new virt-v2v. Don't +@@ -79,6 +79,6 @@ let input_libvirt input_conn input_password input_transport guest = + | Some _, Some _, _ -> + warning (f_"no support for remote libvirt connections to '-ic %s'. The conversion may fail when it tries to read the source disks.") + orig_uri; +- Input_libvirt_other.input_libvirt_other libvirt_conn guest ++ Input_libvirt_other.input_libvirt_other libvirt_conn ?input_conn guest + + let () = Modules_list.register_input_module "libvirt" +diff --git a/v2v/input_libvirt_other.ml b/v2v/input_libvirt_other.ml +index e00944db..6a19ae52 100644 +--- a/v2v/input_libvirt_other.ml ++++ b/v2v/input_libvirt_other.ml +@@ -40,12 +40,16 @@ let error_if_libvirt_does_not_support_json_backingfile () = + error (f_"because of libvirt bug https://bugzilla.redhat.com/1134878 you must EITHER upgrade to libvirt >= 2.1.0 OR set this environment variable:\n\nexport LIBGUESTFS_BACKEND=direct\n\nand then rerun the virt-v2v command.") + + (* Superclass. *) +-class virtual input_libvirt libvirt_conn guest = ++class virtual input_libvirt libvirt_conn ?input_conn guest = + object (self) + inherit input + + method as_options = +- sprintf "-i libvirt -ic %s %s" (Libvirt.Connect.get_uri self#conn) guest ++ sprintf "-i libvirt%s %s" ++ (match input_conn with ++ | None -> "" ++ | Some uri -> " -ic " ^ uri) ++ guest + + method private conn : Libvirt.rw Libvirt.Connect.t = + Lazy.force libvirt_conn +@@ -54,9 +58,9 @@ end + (* Subclass specialized for handling anything that's *not* VMware vCenter + * or Xen. + *) +-class input_libvirt_other libvirt_conn guest = ++class input_libvirt_other libvirt_conn ?input_conn guest = + object (self) +- inherit input_libvirt libvirt_conn guest ++ inherit input_libvirt libvirt_conn ?input_conn guest + + method source ?bandwidth () = + debug "input_libvirt_other: source ()"; +diff --git a/v2v/input_libvirt_other.mli b/v2v/input_libvirt_other.mli +index c528c3ee..ae2c0c6d 100644 +--- a/v2v/input_libvirt_other.mli ++++ b/v2v/input_libvirt_other.mli +@@ -20,11 +20,11 @@ + + val error_if_libvirt_does_not_support_json_backingfile : unit -> unit + +-class virtual input_libvirt : Libvirt.rw Libvirt.Connect.t Lazy.t -> string -> object ++class virtual input_libvirt : Libvirt.rw Libvirt.Connect.t Lazy.t -> ?input_conn:string -> string -> object + method precheck : unit -> unit + method as_options : string + method virtual source : ?bandwidth:Types.bandwidth -> unit -> Types.source * Types.source_disk list + method private conn : Libvirt.rw Libvirt.Connect.t + end + +-val input_libvirt_other : Libvirt.rw Libvirt.Connect.t Lazy.t -> string -> Types.input ++val input_libvirt_other : Libvirt.rw Libvirt.Connect.t Lazy.t -> ?input_conn:string -> string -> Types.input +diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml +index 77bc315d..ed2e5eed 100644 +--- a/v2v/input_libvirt_vcenter_https.ml ++++ b/v2v/input_libvirt_vcenter_https.ml +@@ -32,9 +32,9 @@ open Printf + + (* Subclass specialized for handling VMware vCenter over https. *) + class input_libvirt_vcenter_https +- libvirt_conn input_password parsed_uri server guest = ++ libvirt_conn input_conn input_password parsed_uri server guest = + object (self) +- inherit input_libvirt libvirt_conn guest ++ inherit input_libvirt libvirt_conn ~input_conn guest + + val mutable dcPath = "" + +diff --git a/v2v/input_libvirt_vcenter_https.mli b/v2v/input_libvirt_vcenter_https.mli +index c2e0f3fe..a12a9815 100644 +--- a/v2v/input_libvirt_vcenter_https.mli ++++ b/v2v/input_libvirt_vcenter_https.mli +@@ -18,4 +18,4 @@ + + (** [-i libvirt] when the source is VMware vCenter *) + +-val input_libvirt_vcenter_https : Libvirt.rw Libvirt.Connect.t Lazy.t -> string option -> Xml.uri -> string -> string -> Types.input ++val input_libvirt_vcenter_https : Libvirt.rw Libvirt.Connect.t Lazy.t -> string -> string option -> Xml.uri -> string -> string -> Types.input +diff --git a/v2v/input_libvirt_vddk.ml b/v2v/input_libvirt_vddk.ml +index fbd1e0c6..75fd146e 100644 +--- a/v2v/input_libvirt_vddk.ml ++++ b/v2v/input_libvirt_vddk.ml +@@ -99,7 +99,7 @@ class input_libvirt_vddk libvirt_conn input_conn input_password vddk_options + in + + object (self) +- inherit input_libvirt libvirt_conn guest as super ++ inherit input_libvirt libvirt_conn ~input_conn guest as super + + method precheck () = + error_unless_thumbprint () +@@ -138,12 +138,7 @@ object (self) + match parsed_uri.Xml.uri_server with + | Some server -> server + | None -> +- match input_conn with +- | Some input_conn -> +- error (f_"‘-ic %s’ URL does not contain a host name field") +- input_conn +- | None -> +- error (f_"you must use the ‘-ic’ parameter. See the virt-v2v-input-vmware(1) manual.") in ++ error (f_"‘-ic %s’ URL does not contain a host name field") input_conn in + + let user = parsed_uri.Xml.uri_user in + +diff --git a/v2v/input_libvirt_vddk.mli b/v2v/input_libvirt_vddk.mli +index 2fc6e9cf..f37d88e7 100644 +--- a/v2v/input_libvirt_vddk.mli ++++ b/v2v/input_libvirt_vddk.mli +@@ -25,7 +25,7 @@ val print_input_options : unit -> unit + val parse_input_options : (string * string) list -> vddk_options + (** Print and parse vddk -io options. *) + +-val input_libvirt_vddk : Libvirt.rw Libvirt.Connect.t Lazy.t -> string option -> string option -> vddk_options -> Xml.uri -> string -> Types.input +-(** [input_libvirt_vddk libvirt_conn vddk_options parsed_uri guest] ++val input_libvirt_vddk : Libvirt.rw Libvirt.Connect.t Lazy.t -> string -> string option -> vddk_options -> Xml.uri -> string -> Types.input ++(** [input_libvirt_vddk libvirt_conn input_conn vddk_options parsed_uri guest] + creates and returns a {!Types.input} object specialized for reading + the guest disks using the nbdkit vddk plugin. *) +diff --git a/v2v/input_libvirt_xen_ssh.ml b/v2v/input_libvirt_xen_ssh.ml +index bd1235a6..ec366b4a 100644 +--- a/v2v/input_libvirt_xen_ssh.ml ++++ b/v2v/input_libvirt_xen_ssh.ml +@@ -30,9 +30,9 @@ open Input_libvirt_other + open Printf + + (* Subclass specialized for handling Xen over SSH. *) +-class input_libvirt_xen_ssh libvirt_conn input_password parsed_uri server guest = ++class input_libvirt_xen_ssh libvirt_conn input_conn input_password parsed_uri server guest = + object (self) +- inherit input_libvirt libvirt_conn guest ++ inherit input_libvirt libvirt_conn ~input_conn guest + + method precheck () = + if backend_is_libvirt () then +diff --git a/v2v/input_libvirt_xen_ssh.mli b/v2v/input_libvirt_xen_ssh.mli +index 120a52f7..3cbca9d7 100644 +--- a/v2v/input_libvirt_xen_ssh.mli ++++ b/v2v/input_libvirt_xen_ssh.mli +@@ -18,4 +18,4 @@ + + (** [-i libvirt] when the source is Xen *) + +-val input_libvirt_xen_ssh : Libvirt.rw Libvirt.Connect.t Lazy.t -> string option -> Xml.uri -> string -> string -> Types.input ++val input_libvirt_xen_ssh : Libvirt.rw Libvirt.Connect.t Lazy.t -> string -> string option -> Xml.uri -> string -> string -> Types.input +-- +2.31.1 + diff --git a/0002-options-Use-cryptX-instead-of-luksX-as-the-temporary.patch b/0002-options-Use-cryptX-instead-of-luksX-as-the-temporary.patch new file mode 100644 index 0000000..d4bfce6 --- /dev/null +++ b/0002-options-Use-cryptX-instead-of-luksX-as-the-temporary.patch @@ -0,0 +1,41 @@ +From f9770058fa3bd8871b8b4ded0b10d4be418224ae Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 7 Sep 2020 10:15:40 +0100 +Subject: [PATCH 2/4] options: Use cryptX instead of luksX as the temporary + name. + +--- + options/decrypt.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/options/decrypt.c b/options/decrypt.c +index d868f70..45de5b2 100644 +--- a/common/options/decrypt.c ++++ b/common/options/decrypt.c +@@ -38,18 +38,18 @@ + + /** + * Make a LUKS map name from the partition name, +- * eg. C<"/dev/vda2" =E "luksvda2"> ++ * eg. C<"/dev/vda2" =E "cryptvda2"> + */ + static void + make_mapname (const char *device, char *mapname, size_t len) + { + size_t i = 0; + +- if (len < 5) ++ if (len < 6) + abort (); +- strcpy (mapname, "luks"); +- mapname += 4; +- len -= 4; ++ strcpy (mapname, "crypt"); ++ mapname += 5; ++ len -= 5; + + if (STRPREFIX (device, "/dev/")) + i = 5; +-- +2.18.4 + diff --git a/0003-RHEL-Fix-list-of-supported-sound-cards-to-match-RHEL.patch b/0003-RHEL-Fix-list-of-supported-sound-cards-to-match-RHEL.patch new file mode 100644 index 0000000..11b2476 --- /dev/null +++ b/0003-RHEL-Fix-list-of-supported-sound-cards-to-match-RHEL.patch @@ -0,0 +1,31 @@ +From b61fc893f429eb4bec34816d667cc930e50ccd0f Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 24 Apr 2015 09:45:41 -0400 +Subject: [PATCH] RHEL: Fix list of supported sound cards to match RHEL qemu + (RHBZ#1176493). + +--- + lib/utils.ml | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/lib/utils.ml b/lib/utils.ml +index 128bb697..7116a4f9 100644 +--- a/lib/utils.ml ++++ b/lib/utils.ml +@@ -60,13 +60,14 @@ let kvm_arch = function + (* Does qemu support the given sound card? *) + let qemu_supports_sound_card = function + | Types.AC97 +- | Types.ES1370 + | Types.ICH6 + | Types.ICH9 + | Types.PCSpeaker ++ -> true ++ | Types.ES1370 + | Types.SB16 + | Types.USBAudio +- -> true ++ -> false + + (* Find the UEFI firmware. *) + let find_uefi_firmware guest_arch = diff --git a/0003-options-Support-Windows-BitLocker-RHBZ-1808977.patch b/0003-options-Support-Windows-BitLocker-RHBZ-1808977.patch new file mode 100644 index 0000000..7871d02 --- /dev/null +++ b/0003-options-Support-Windows-BitLocker-RHBZ-1808977.patch @@ -0,0 +1,56 @@ +From 778c08fe7b7eb00b7f48189dd1a3edf3f3be2625 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 30 Mar 2020 14:40:45 +0100 +Subject: [PATCH 3/4] options: Support Windows BitLocker (RHBZ#1808977). + +--- + mltools/tools_utils.mli | 5 ++--- + options/decrypt.c | 9 ++++----- + 2 files changed, 6 insertions(+), 8 deletions(-) + +diff --git a/mltools/tools_utils.mli b/mltools/tools_utils.mli +index 102abff..1d1ac8a 100644 +--- a/common/mltools/tools_utils.mli ++++ b/common/mltools/tools_utils.mli +@@ -195,9 +195,8 @@ val is_btrfs_subvolume : Guestfs.guestfs -> string -> bool + (** Checks if a filesystem is a btrfs subvolume. *) + + val inspect_decrypt : Guestfs.guestfs -> key_store -> unit +-(** Simple implementation of decryption: look for any [crypto_LUKS] +- partitions and decrypt them, then rescan for VGs. This only works +- for Fedora whole-disk encryption. *) ++(** Simple implementation of decryption: look for any encrypted ++ partitions and decrypt them, then rescan for VGs. *) + + val with_timeout : string -> int -> ?sleep:int -> (unit -> 'a option) -> 'a + (** [with_timeout op timeout ?sleep fn] implements a timeout loop. +diff --git a/options/decrypt.c b/options/decrypt.c +index 45de5b2..8eb24bc 100644 +--- a/common/options/decrypt.c ++++ b/common/options/decrypt.c +@@ -65,10 +65,8 @@ make_mapname (const char *device, char *mapname, size_t len) + } + + /** +- * Simple implementation of decryption: look for any C +- * partitions and decrypt them, then rescan for VGs. This only works +- * for Fedora whole-disk encryption. WIP to make this work for other +- * encryption schemes. ++ * Simple implementation of decryption: look for any encrypted ++ * partitions and decrypt them, then rescan for VGs. + */ + void + inspect_do_decrypt (guestfs_h *g, struct key_store *ks) +@@ -82,7 +80,8 @@ inspect_do_decrypt (guestfs_h *g, struct key_store *ks) + + for (i = 0; partitions[i] != NULL; ++i) { + CLEANUP_FREE char *type = guestfs_vfs_type (g, partitions[i]); +- if (type && STREQ (type, "crypto_LUKS")) { ++ if (type && ++ (STREQ (type, "crypto_LUKS") || STREQ (type, "BitLocker"))) { + char mapname[32]; + make_mapname (partitions[i], mapname, sizeof mapname); + +-- +2.18.4 + diff --git a/0003-vCenter-fix-parsing-of-HTTP-status-string-RHBZ-18373.patch b/0003-vCenter-fix-parsing-of-HTTP-status-string-RHBZ-18373.patch new file mode 100644 index 0000000..85d3802 --- /dev/null +++ b/0003-vCenter-fix-parsing-of-HTTP-status-string-RHBZ-18373.patch @@ -0,0 +1,34 @@ +From bb94c68c521aa546d3f2e59aa25e388bfd9c5fc5 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Tue, 19 May 2020 12:14:18 +0200 +Subject: [PATCH] vCenter: fix parsing of HTTP status string (RHBZ#1837328) + +vCenter 7 answers with an HTTP/2 status string, so we cannot extract +the status code from it by using fixed positions in that string. +Hence, pick the status code by reading what's after the whitespace. + +Tested with vCenter 6.5 and 7. + +(cherry picked from commit d2aa82317964d62fcc8dc7b6737773003d04b998) +--- + v2v/vCenter.ml | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml +index c28a4ced..4c128b0c 100644 +--- a/v2v/vCenter.ml ++++ b/v2v/vCenter.ml +@@ -190,7 +190,9 @@ and fetch_headers_from_url password_file uri sslverify https_url = + | [] -> + dump_response stderr; + error (f_"vcenter: no status code in output of ‘curl’ command. Is ‘curl’ installed?") +- | ss -> String.sub (List.hd (List.rev ss)) 9 3 in ++ | ss -> ++ let s = List.hd (List.rev ss) in ++ String.sub s (String.index s ' ' + 1) 3 in + + let headers = + List.map ( +-- +2.31.1 + diff --git a/0004-RHEL-Fixes-for-libguestfs-winsupport.patch b/0004-RHEL-Fixes-for-libguestfs-winsupport.patch new file mode 100644 index 0000000..2540451 --- /dev/null +++ b/0004-RHEL-Fixes-for-libguestfs-winsupport.patch @@ -0,0 +1,101 @@ +From 5d70bf1302ea3f1006d87672676f86eb5d40eb85 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sun, 30 Aug 2015 03:21:57 -0400 +Subject: [PATCH] RHEL: Fixes for libguestfs-winsupport. + +In tests we cannot use guestfish for arbitrary Windows edits. +In virt-v2v helpers we must set the program name to virt-v2v. +--- + convert/convert.ml | 1 + + convert/windows_virtio.ml | 1 + + test-data/phony-guests/make-windows-img.sh | 1 + + tests/test-v2v-virtio-win-iso.sh | 8 +++++++- + tests/test-v2v-windows-conversion.sh | 8 +++++++- + 5 files changed, 17 insertions(+), 2 deletions(-) + +diff --git a/convert/convert.ml b/convert/convert.ml +index 87fca725..5e0e6c2b 100644 +--- a/convert/convert.ml ++++ b/convert/convert.ml +@@ -51,6 +51,7 @@ let rec convert dir options source = + + message (f_"Opening the source"); + let g = open_guestfs ~identifier:"v2v" () in ++ g#set_program "virt-v2v"; + g#set_memsize (g#get_memsize () * 2); + (* Setting the number of vCPUs allows parallel mkinitrd, but make + * sure this is not too large because each vCPU consumes guest RAM. +diff --git a/convert/windows_virtio.ml b/convert/windows_virtio.ml +index a27cd6a5..183166b7 100644 +--- a/convert/windows_virtio.ml ++++ b/convert/windows_virtio.ml +@@ -241,6 +241,7 @@ and copy_from_virtio_win g inspect srcdir destdir filter missing = + let g2 = + try + let g2 = open_guestfs ~identifier:"virtio_win" () in ++ g#set_program "virt-v2v"; + g2#add_drive_opts virtio_win ~readonly:true; + g2#launch (); + g2 +diff --git a/test-data/phony-guests/make-windows-img.sh b/test-data/phony-guests/make-windows-img.sh +index 30908a91..73cf5144 100755 +--- a/test-data/phony-guests/make-windows-img.sh ++++ b/test-data/phony-guests/make-windows-img.sh +@@ -37,6 +37,7 @@ fi + + # Create a disk image. + guestfish < "$script" + :> "$expected" + ++cat >> "$script" < "$response" ++guestfish --ro -a "$d/windows-sda" < "$script" > "$response" + diff -u "$expected" "$response" +diff --git a/tests/test-v2v-windows-conversion.sh b/tests/test-v2v-windows-conversion.sh +index a4cf191d..1ff41f6a 100755 +--- a/tests/test-v2v-windows-conversion.sh ++++ b/tests/test-v2v-windows-conversion.sh +@@ -76,6 +76,12 @@ mktest () + :> "$script" + :> "$expected" + ++cat >> "$script" < "$response" ++guestfish --ro -a "$d/windows-sda" < "$script" > "$response" + diff -u "$expected" "$response" + + # We also update the Registry several times, for firstboot, and (ONLY diff --git a/0004-options-Ignore-errors-from-guestfs_luks_uuid.patch b/0004-options-Ignore-errors-from-guestfs_luks_uuid.patch new file mode 100644 index 0000000..48ff652 --- /dev/null +++ b/0004-options-Ignore-errors-from-guestfs_luks_uuid.patch @@ -0,0 +1,50 @@ +From 132c355d3ba10b6ec303cbc059d6732056474695 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 6 Oct 2020 15:04:27 +0100 +Subject: [PATCH 4/4] options: Ignore errors from guestfs_luks_uuid. + +For BitLocker disks cryptsetup does not (yet? ever?) support reading +UUIDs and this function will fail. Skip reading the UUID in this +case. + +Updates commit bb4a2dc17a78b53437896d4215ae82df8e11b788. +--- + options/decrypt.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/options/decrypt.c b/options/decrypt.c +index 8eb24bc..434b7d5 100644 +--- a/common/options/decrypt.c ++++ b/common/options/decrypt.c +@@ -25,6 +25,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -82,11 +83,19 @@ inspect_do_decrypt (guestfs_h *g, struct key_store *ks) + CLEANUP_FREE char *type = guestfs_vfs_type (g, partitions[i]); + if (type && + (STREQ (type, "crypto_LUKS") || STREQ (type, "BitLocker"))) { ++ bool is_bitlocker = STREQ (type, "BitLocker"); + char mapname[32]; + make_mapname (partitions[i], mapname, sizeof mapname); + + #ifdef GUESTFS_HAVE_LUKS_UUID +- CLEANUP_FREE char *uuid = guestfs_luks_uuid (g, partitions[i]); ++ CLEANUP_FREE char *uuid = NULL; ++ ++ /* This fails for Windows BitLocker disks because cryptsetup ++ * luksUUID cannot read a UUID (unclear if this is a limitation ++ * of the format or cryptsetup). ++ */ ++ if (!is_bitlocker) ++ uuid = guestfs_luks_uuid (g, partitions[i]); + #else + const char *uuid = NULL; + #endif +-- +2.18.4 + diff --git a/0004-v2v-o-libvirt-Remove-cache-none-RHBZ-1837453.patch b/0004-v2v-o-libvirt-Remove-cache-none-RHBZ-1837453.patch new file mode 100644 index 0000000..9247c51 --- /dev/null +++ b/0004-v2v-o-libvirt-Remove-cache-none-RHBZ-1837453.patch @@ -0,0 +1,97 @@ +From 939d57ef4d5bcfa31e9b98104822962b89572481 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 19 May 2020 14:40:01 +0100 +Subject: [PATCH] v2v: -o libvirt: Remove cache=none (RHBZ#1837453). + +Traditionally if you did live migration (KVM to KVM), you had to +ensure that cache=none was set on all disks of the guest up front. +This was because of quirks in how NFS works (I think the close-to-open +consistency and the fact that during live migration both qemus have +the file open), and we had to assume the worst case that a guest might +be backed by NFS. + +Because of this when virt-v2v converts a guest to run on KVM using +libvirt it sets cache=none. + +This is not necessary with modern qemu. If qemu supports the +drop-cache property of the file block driver, which libvirt will +automatically detect for us, then libvirt live migration is able to +tell qemu to drop cached data at the right time even if the backing is +NFS. + +It also had a significant performance impact. In some synthetic +benchmarks it could show 2 or 3 times slower performance. + +Thanks: Ming Xie, Peter Krempa. +(cherry picked from commit 9720f45e0cd9283739fd2a67c19e66912489dfc7) +--- + docs/virt-v2v-output-local.pod | 2 +- + tests/test-v2v-cdrom.expected | 2 +- + tests/test-v2v-floppy.expected | 2 +- + tests/test-v2v-i-ova.xml | 2 +- + v2v/create_libvirt_xml.ml | 1 - + 5 files changed, 4 insertions(+), 5 deletions(-) + +diff --git a/docs/virt-v2v-output-local.pod b/docs/virt-v2v-output-local.pod +index 38df007d..a5f155cb 100644 +--- a/docs/virt-v2v-output-local.pod ++++ b/docs/virt-v2v-output-local.pod +@@ -127,7 +127,7 @@ Edit F to change F to the pool + name. In other words, locate the following bit of XML: + + +- ++ + + + +diff --git a/tests/test-v2v-cdrom.expected b/tests/test-v2v-cdrom.expected +index e18ea6f2..34d2bf59 100644 +--- a/tests/test-v2v-cdrom.expected ++++ b/tests/test-v2v-cdrom.expected +@@ -1,5 +1,5 @@ + +- ++ + + + +diff --git a/tests/test-v2v-floppy.expected b/tests/test-v2v-floppy.expected +index dd74ed94..a718c21f 100644 +--- a/tests/test-v2v-floppy.expected ++++ b/tests/test-v2v-floppy.expected +@@ -1,5 +1,5 @@ + +- ++ + + + +diff --git a/tests/test-v2v-i-ova.xml b/tests/test-v2v-i-ova.xml +index 7c198283..e26f4f83 100644 +--- a/tests/test-v2v-i-ova.xml ++++ b/tests/test-v2v-i-ova.xml +@@ -22,7 +22,7 @@ + restart + + +- ++ + + + +diff --git a/v2v/create_libvirt_xml.ml b/v2v/create_libvirt_xml.ml +index 05553c4f..5a1fba0f 100644 +--- a/v2v/create_libvirt_xml.ml ++++ b/v2v/create_libvirt_xml.ml +@@ -336,7 +336,6 @@ let create_libvirt_xml ?pool source targets target_buses guestcaps + e "driver" [ + "name", "qemu"; + "type", t.target_format; +- "cache", "none" + ] []; + (match pool with + | None -> +-- +2.31.1 + diff --git a/0005-RHEL-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch b/0005-RHEL-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch new file mode 100644 index 0000000..2be9f81 --- /dev/null +++ b/0005-RHEL-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch @@ -0,0 +1,23 @@ +From 37e241d6d4f22331b34c2ed0af233c73be2b0869 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 2 Mar 2017 14:21:37 +0100 +Subject: [PATCH] RHEL: v2v: -i disk: force VNC as display (RHBZ#1372671) + +The SDL output mode is not supported in RHEL's qemu-kvm. +--- + input/input_disk.ml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/input/input_disk.ml b/input/input_disk.ml +index 508adf9d..20f2e898 100644 +--- a/input/input_disk.ml ++++ b/input/input_disk.ml +@@ -76,7 +76,7 @@ module Disk = struct + s_features = [ "acpi"; "apic"; "pae" ]; + s_firmware = UnknownFirmware; (* causes virt-v2v to autodetect *) + s_display = +- Some { s_display_type = Window; s_keymap = None; s_password = None; ++ Some { s_display_type = VNC; s_keymap = None; s_password = None; + s_listen = LNoListen; s_port = None }; + s_sound = None; + s_disks = s_disks; diff --git a/0005-v2v-Remove-extraneous-when-setting-bandwidth-RHBZ-18.patch b/0005-v2v-Remove-extraneous-when-setting-bandwidth-RHBZ-18.patch new file mode 100644 index 0000000..f783eac --- /dev/null +++ b/0005-v2v-Remove-extraneous-when-setting-bandwidth-RHBZ-18.patch @@ -0,0 +1,51 @@ +From f3ea9ceb1c3c9741d4f62d0c1d23b7c94634353a Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 28 May 2020 11:40:45 +0100 +Subject: [PATCH] v2v: Remove extraneous '=' when setting bandwidth + (RHBZ#1841096). + +Commit c3a54d6aed6dfc65f9ffa59976bb8d20044c03a8 ("v2v: Add standalone +nbdkit module.") was supposed to be a simple refactoring but it broke +the --bandwidth and --bandwidth-file options (amongst other things). + +Because of an extra '=' character which was accidentally left over, it +would add an extra character in the nbdkit-rate-filter command line. +For example: + + virt-v2v .. --bandwidth 200M + +would invoke: + + nbdkit .. --filter rate rate==200M + +which causes a parse error. The --bandwidth-file option does not +invoke a parse error but does not work, for similar reasons. + +Thanks: Ming Xie +(cherry picked from commit a89a084b2d0f6d40716c1d34969f6c49ea28e9b3) +--- + v2v/nbdkit_sources.ml | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/v2v/nbdkit_sources.ml b/v2v/nbdkit_sources.ml +index 979c3773..402dfd0e 100644 +--- a/v2v/nbdkit_sources.ml ++++ b/v2v/nbdkit_sources.ml +@@ -118,11 +118,11 @@ let common_create ?bandwidth ?extra_debug ?extra_env plugin_name plugin_args = + let args = + match bandwidth with + | StaticBandwidth rate -> +- [ "rate=", rate ] ++ [ "rate", rate ] + | DynamicBandwidth (None, filename) -> +- [ "rate-file=", filename ] ++ [ "rate-file", filename ] + | DynamicBandwidth (Some rate, filename) -> +- [ "rate=", rate; "rate-file=", filename ] in ++ [ "rate", rate; "rate-file", filename ] in + cmd, args + ) + else cmd, [] in +-- +2.31.1 + diff --git a/0006-RHEL-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-1430203.patch b/0006-RHEL-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-1430203.patch new file mode 100644 index 0000000..95dfe7c --- /dev/null +++ b/0006-RHEL-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-1430203.patch @@ -0,0 +1,23 @@ +From 8ee8aec8739c6c0a4024ad187be56f525e8089c0 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Wed, 8 Mar 2017 11:03:40 +0100 +Subject: [PATCH] RHEL: v2v: do not mention SUSE Xen hosts (RHBZ#1430203) + +They are not supported in RHEL. +--- + docs/virt-v2v-input-xen.pod | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/docs/virt-v2v-input-xen.pod b/docs/virt-v2v-input-xen.pod +index 8080ebea..ad5772de 100644 +--- a/docs/virt-v2v-input-xen.pod ++++ b/docs/virt-v2v-input-xen.pod +@@ -11,7 +11,7 @@ virt-v2v-input-xen - Using virt-v2v to convert guests from Xen + =head1 DESCRIPTION + + This page documents how to use L to convert guests from +-RHEL 5 Xen, or SLES and OpenSUSE Xen hosts. ++RHEL 5 Xen hosts. + + =head1 INPUT FROM XEN + diff --git a/0006-v2v-it-vddk-Don-t-use-nbdkit-readahead-filter-with-V.patch b/0006-v2v-it-vddk-Don-t-use-nbdkit-readahead-filter-with-V.patch new file mode 100644 index 0000000..8f0baac --- /dev/null +++ b/0006-v2v-it-vddk-Don-t-use-nbdkit-readahead-filter-with-V.patch @@ -0,0 +1,49 @@ +From 4e0b3de57486613c8f28ef7726df728cccd7624b Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 28 May 2020 10:59:57 +0100 +Subject: [PATCH] v2v: -it vddk: Don't use nbdkit readahead filter with VDDK + (RHBZ#1832805). + +This filter deliberately tries to coalesce reads into larger requests. +Unfortunately VMware has low limits on the size of requests it can +serve to a VDDK client and the larger requests would break with errors +like this: + + nbdkit: vddk[3]: error: [NFC ERROR] NfcFssrvrProcessErrorMsg: received NFC error 5 from server: Failed to allocate the requested 33554456 bytes + +We already increase the maximum request size by changing the +configuration on the VMware server, but it's not sufficient for VDDK +with the readahead filter. + +As readahead is only an optimization, the simplest solution is to +disable this filter when we're using nbdkit-vddk-plugin. + +Thanks: Ming Xie +(cherry picked from commit 1438174488f111fa24420758ba3bf0218dc9ee2a) +--- + v2v/nbdkit_sources.ml | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/v2v/nbdkit_sources.ml b/v2v/nbdkit_sources.ml +index 402dfd0e..bfda91a7 100644 +--- a/v2v/nbdkit_sources.ml ++++ b/v2v/nbdkit_sources.ml +@@ -97,9 +97,13 @@ let common_create ?bandwidth ?extra_debug ?extra_env plugin_name plugin_args = + let cmd = Nbdkit.add_filter_if_available cmd "retry" in + + (* Adding the readahead filter is always a win for our access +- * patterns. However if it doesn't exist don't worry. ++ * patterns. If it doesn't exist don't worry. However it ++ * breaks VMware servers (RHBZ#1832805). + *) +- let cmd = Nbdkit.add_filter_if_available cmd "readahead" in ++ let cmd = ++ if plugin_name <> "vddk" then ++ Nbdkit.add_filter_if_available cmd "readahead" ++ else cmd in + + (* Caching extents speeds up qemu-img, especially its consecutive + * block_status requests with req_one=1. +-- +2.31.1 + diff --git a/0007-RHEL-point-to-KB-for-supported-v2v-hypervisors-guest.patch b/0007-RHEL-point-to-KB-for-supported-v2v-hypervisors-guest.patch new file mode 100644 index 0000000..922f52f --- /dev/null +++ b/0007-RHEL-point-to-KB-for-supported-v2v-hypervisors-guest.patch @@ -0,0 +1,124 @@ +From fd0c34d843bb5ba9e1b33e0dfd1250943c760a70 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Tue, 26 Mar 2019 09:42:25 +0100 +Subject: [PATCH] RHEL: point to KB for supported v2v hypervisors/guests + +--- + docs/virt-v2v-support.pod | 104 ++------------------------------------ + 1 file changed, 4 insertions(+), 100 deletions(-) + +diff --git a/docs/virt-v2v-support.pod b/docs/virt-v2v-support.pod +index 9815f51f..1ffc0f9d 100644 +--- a/docs/virt-v2v-support.pod ++++ b/docs/virt-v2v-support.pod +@@ -8,106 +8,10 @@ systems and guests in virt-v2v + This page documents which foreign hypervisors, virtualization + management systems and guest types that L can support. + +-Note this page applies to upstream virt-v2v from +-L and in downstream distributions of virt-v2v +-sometimes features are intentionally removed, or are present but not +-supported. +- +-=head2 Hypervisors (Input) +- +-=over 4 +- +-=item VMware ESXi +- +-Must be managed by VMware vCenter E 5.0 unless VDDK is available. +- +-=item OVA exported from VMware +- +-OVAs from other hypervisors will not work. +- +-=item VMX from VMware +- +-VMX files generated by other hypervisors will not work. +- +-=item RHEL 5 Xen +- +-=item SUSE Xen +- +-=item Citrix Xen +- +-Citrix Xen has not been recently tested. +- +-=item Hyper-V +- +-Not recently tested. Requires that you export the disk or use +-L on Hyper-V. +- +-=item Direct from disk images +- +-Only disk images exported from supported hypervisors, and using +-container formats supported by qemu. +- +-=item Physical machines +- +-Using the L tool. +- +-=back +- +-=head2 Hypervisors (Output) +- +-QEMU and KVM only. +- +-=head2 Virtualization management systems (Output) +- +-=over 4 +- +-=item OpenStack +- +-=item Red Hat Virtualization (RHV) 4.1 and up +- +-=item Local libvirt +- +-And hence L, L, and similar tools. +- +-=item Local disk +- +-=back +- +-=head2 Guests +- +-=over 4 +- +-=item Red Hat Enterprise Linux 3, 4, 5, 6, 7 +- +-=item CentOS 3, 4, 5, 6, 7 +- +-=item Scientific Linux 3, 4, 5, 6, 7 +- +-=item Oracle Linux +- +-=item Fedora +- +-=item SLES 10 and up +- +-=item OpenSUSE 10 and up +- +-=item ALT Linux 9 and up +- +-=item Debian 6 and up +- +-=item Ubuntu 10.04, 12.04, 14.04, 16.04, and up +- +-=item Windows XP to Windows 10 / Windows Server 2016 +- +-We use Windows internal version numbers, see +-L +- +-Currently NT 5.2 to NT 6.3 are supported. +- +-See L below for additional notes on converting Windows +-guests. +- +-=back ++For more information on supported hypervisors, and guest types in ++RHEL, please consult the following Knowledgebase article on these ++Red Hat Customer Portal: ++L. + + =head2 Guest firmware + diff --git a/0007-v2v-nbdkit-Handle-password-parameter-in-common_creat.patch b/0007-v2v-nbdkit-Handle-password-parameter-in-common_creat.patch new file mode 100644 index 0000000..6c98216 --- /dev/null +++ b/0007-v2v-nbdkit-Handle-password-parameter-in-common_creat.patch @@ -0,0 +1,116 @@ +From bcb9f50eee4050e72a532a0b805531dc72105a4f Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 1 Jun 2020 17:18:59 +0100 +Subject: [PATCH] v2v: nbdkit: Handle password= parameter in common_create. + +Just refactoring. + +(cherry picked from commit 36c008009a601634ec1c1fbc4f619b21988f075c) +--- + v2v/nbdkit_sources.ml | 42 +++++++++++++++++++----------------------- + 1 file changed, 19 insertions(+), 23 deletions(-) + +diff --git a/v2v/nbdkit_sources.ml b/v2v/nbdkit_sources.ml +index bfda91a7..47832011 100644 +--- a/v2v/nbdkit_sources.ml ++++ b/v2v/nbdkit_sources.ml +@@ -58,7 +58,8 @@ let error_unless_nbdkit_compiled_with_selinux config = + 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.") + ) + +-let common_create ?bandwidth ?extra_debug ?extra_env plugin_name plugin_args = ++let common_create ?bandwidth ?extra_debug ?extra_env password ++ plugin_name plugin_args = + error_unless_nbdkit_working (); + let config = Nbdkit.config () in + error_unless_nbdkit_min_version config; +@@ -136,6 +137,15 @@ let common_create ?bandwidth ?extra_debug ?extra_env plugin_name plugin_args = + List.fold_left (fun cmd (k, v) -> Nbdkit.add_arg cmd k v) + cmd (plugin_args @ rate_args) in + ++ (* Handle the password parameter specially. *) ++ let cmd = ++ match password with ++ | NoPassword -> cmd ++ | AskForPassword -> ++ Nbdkit.add_arg cmd "password" "-" ++ | PasswordFile password_file -> ++ Nbdkit.add_arg cmd "password" ("+" ^ password_file) in ++ + cmd + + (* VDDK libraries are located under lib32/ or lib64/ relative to the +@@ -223,20 +233,16 @@ See also the virt-v2v-input-vmware(1) manual.") libNN + let get_args () = List.rev !args in + add_arg, get_args in + +- let password_param = +- match password_file with +- | None -> +- (* nbdkit asks for the password interactively *) +- "password", "-" +- | Some password_file -> +- (* nbdkit reads the password from the file *) +- "password", "+" ^ password_file in + add_arg ("server", server); + add_arg ("user", user); +- add_arg password_param; + add_arg ("vm", sprintf "moref=%s" moref); + add_arg ("file", path); + ++ let password = ++ match password_file with ++ | None -> AskForPassword ++ | Some password_file -> PasswordFile password_file in ++ + (* The passthrough parameters. *) + Option.may (fun s -> add_arg ("config", s)) config; + Option.may (fun s -> add_arg ("cookie", s)) cookie; +@@ -251,7 +257,7 @@ See also the virt-v2v-input-vmware(1) manual.") libNN + let debug_flag = + if version >= (1, 17, 10) then Some ("vddk.datapath", "0") else None in + +- common_create ?bandwidth ?extra_debug:debug_flag ?extra_env:env ++ common_create ?bandwidth ?extra_debug:debug_flag ?extra_env:env password + "vddk" (get_args ()) + + (* Create an nbdkit module specialized for reading from SSH sources. *) +@@ -267,14 +273,9 @@ let create_ssh ?bandwidth ~password ?port ~server ?user path = + add_arg ("host", server); + Option.may (fun s -> add_arg ("port", s)) port; + Option.may (fun s -> add_arg ("user", s)) user; +- (match password with +- | NoPassword -> () +- | AskForPassword -> add_arg ("password", "-") +- | PasswordFile password_file -> add_arg ("password", "+" ^ password_file) +- ); + add_arg ("path", path); + +- common_create ?bandwidth "ssh" (get_args ()) ++ common_create ?bandwidth password "ssh" (get_args ()) + + (* Create an nbdkit module specialized for reading from Curl sources. *) + let create_curl ?bandwidth ?cookie ~password ?(sslverify=true) ?user url = +@@ -287,18 +288,13 @@ let create_curl ?bandwidth ?cookie ~password ?(sslverify=true) ?user url = + add_arg, get_args in + + Option.may (fun s -> add_arg ("user", s)) user; +- (match password with +- | NoPassword -> () +- | AskForPassword -> add_arg ("password", "-") +- | PasswordFile password_file -> add_arg ("password", "+" ^ password_file) +- ); + (* https://bugzilla.redhat.com/show_bug.cgi?id=1146007#c10 *) + add_arg ("timeout", "2000"); + Option.may (fun s -> add_arg ("cookie", s)) cookie; + if not sslverify then add_arg ("sslverify", "false"); + add_arg ("url", url); + +- common_create ?bandwidth "curl" (get_args ()) ++ common_create ?bandwidth password "curl" (get_args ()) + + let run cmd = + let sock, _ = Nbdkit.run_unix cmd in +-- +2.31.1 + diff --git a/0008-RHEL-Disable-o-glance.patch b/0008-RHEL-Disable-o-glance.patch new file mode 100644 index 0000000..cbb09e1 --- /dev/null +++ b/0008-RHEL-Disable-o-glance.patch @@ -0,0 +1,216 @@ +From 14507902a675fd2e0356c0faf67524eb04e974d2 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 30 Jun 2021 11:15:52 +0100 +Subject: [PATCH] RHEL: Disable -o glance + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1977539 +--- + docs/virt-v2v-output-openstack.pod | 56 ++---------------------------- + docs/virt-v2v.pod | 20 ----------- + output/output_glance.mli | 2 +- + tests/test-v2v-o-glance.sh | 3 ++ + v2v/v2v.ml | 7 +--- + 5 files changed, 7 insertions(+), 81 deletions(-) + +diff --git a/docs/virt-v2v-output-openstack.pod b/docs/virt-v2v-output-openstack.pod +index f5a3abad..1ab356e8 100644 +--- a/docs/virt-v2v-output-openstack.pod ++++ b/docs/virt-v2v-output-openstack.pod +@@ -10,13 +10,10 @@ virt-v2v-output-openstack - Using virt-v2v to convert guests to OpenStack + [-oo verify-server-certificate=false] + [-oo os-username=admin] [-oo os-*=*] + +- virt-v2v [-i* options] -o glance +- + =head1 DESCRIPTION + + This page documents how to use L to convert guests to run +-on OpenStack. There are two output modes you can select, but only +-I<-o openstack> should be used normally. ++on OpenStack. + + =over 4 + +@@ -27,15 +24,6 @@ Full description: L + This is the modern method for uploading to OpenStack via the REST API. + Guests can be directly converted into Cinder volumes. + +-=item B<-o glance> +- +-Full description: L +- +-This is the old method for uploading to Glance. Unfortunately Glance +-is not well suited to storing converted guests (since virt-v2v deals +-with "pets" not templated "cattle"), so this method is not recommended +-unless you really know what you are doing. +- + =back + + =head1 OUTPUT TO OPENSTACK +@@ -170,50 +158,10 @@ no Cinder volume type is used. + The following options are B supported with OpenStack: I<-oa>, + I<-of>. + +-=head1 OUTPUT TO GLANCE +- +-Note this is a legacy option. In most cases you should use +-L instead. +- +-To output to OpenStack Glance, use the I<-o glance> option. +- +-This runs the L CLI program which must be installed on the +-virt-v2v conversion host. For authentication to work, you will need +-to set C environment variables. +- +-Normally there is a file called C or C +-which you can simply C to set everything up. +- +-Virt-v2v adds metadata for the guest to Glance, describing such things +-as the guest operating system and what drivers it requires. The +-command C will display the metadata as "Property" +-fields such as C and C. +- +-=head2 Glance and sparseness +- +-Glance image upload doesn't appear to correctly handle sparseness. +-For this reason, using qcow2 will be faster and use less space on the +-Glance server. Use the virt-v2v S> option. +- +-=head2 Glance and multiple disks +- +-If the guest has a single disk, then the name of the disk in Glance +-will be the name of the guest. You can control this using the I<-on> +-option. +- +-Glance doesn't have a concept of associating multiple disks with a +-single guest, and Nova doesn't allow you to boot a guest from multiple +-Glance disks either. If the guest has multiple disks, then the first +-(assumed to be the system disk) will have the name of the guest, and +-the second and subsequent data disks will be called +-C-disk2>, C-disk3> etc. It may be best to +-leave the system disk in Glance, and import the data disks to Cinder. +- + =head1 SEE ALSO + + L, +-L, +-L. ++L. + + =head1 AUTHOR + +diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod +index 7d0bafff..84e049cc 100644 +--- a/docs/virt-v2v.pod ++++ b/docs/virt-v2v.pod +@@ -416,14 +416,6 @@ See L below. + + This is the same as I<-o local>. + +-=item B<-o> B +- +-This is a legacy option. You should probably use I<-o openstack> +-instead. +- +-Set the output method to OpenStack Glance. In this mode the converted +-guest is uploaded to Glance. See L. +- + =item B<-o> B + + This option is deprecated and will be removed in S. +@@ -1148,11 +1140,6 @@ and output methods may use disk space, as outlined in the table below. + This temporarily places a full copy of the uncompressed source disks + in C<$VIRT_V2V_TMPDIR> (or F). + +-=item I<-o glance> +- +-This temporarily places a full copy of the output disks in +-C<$VIRT_V2V_TMPDIR> (or F). +- + =item I<-o local> + + =item I<-o qemu> +@@ -1336,13 +1323,6 @@ instance. + Because of how Cinder volumes are presented as F block devices, + using I<-o openstack> normally requires that virt-v2v is run as root. + +-=item Writing to Glance +- +-This does I need root (in fact it probably won’t work), but may +-require either a special user and/or for you to source a script that +-sets authentication environment variables. Consult the Glance +-documentation. +- + =item Writing to block devices + + This normally requires root. See the next section. +diff --git a/output/output_glance.mli b/output/output_glance.mli +index 972320a2..9befc461 100644 +--- a/output/output_glance.mli ++++ b/output/output_glance.mli +@@ -18,4 +18,4 @@ + + (** [-o glance] output mode. *) + +-module Glance : Output.OUTPUT ++(*module Glance : Output.OUTPUT*) +diff --git a/tests/test-v2v-o-glance.sh b/tests/test-v2v-o-glance.sh +index c0db9115..074b5e16 100755 +--- a/tests/test-v2v-o-glance.sh ++++ b/tests/test-v2v-o-glance.sh +@@ -20,6 +20,9 @@ + + set -e + ++# Feature is disabled in RHEL 9. ++exit 77 ++ + source ./functions.sh + set -e + set -x +diff --git a/v2v/v2v.ml b/v2v/v2v.ml +index 97b4e4ec..41e020cb 100644 +--- a/v2v/v2v.ml ++++ b/v2v/v2v.ml +@@ -192,7 +192,6 @@ let rec main () = + if !output_mode <> `Not_set then + error (f_"%s option used more than once on the command line") "-o"; + match mode with +- | "glance" -> output_mode := `Glance + | "libvirt" -> output_mode := `Libvirt + | "disk" | "local" -> output_mode := `Disk + | "json" -> output_mode := `JSON +@@ -250,7 +249,7 @@ let rec main () = + s_"Map network ‘in’ to ‘out’"; + [ L"no-trim" ], Getopt.String ("-", no_trim_warning), + s_"Ignored for backwards compatibility"; +- [ S 'o' ], Getopt.String ("glance|json|libvirt|local|null|openstack|qemu|rhv|rhv-upload|vdsm", set_output_mode), ++ [ S 'o' ], Getopt.String ("json|libvirt|local|null|openstack|qemu|rhv|rhv-upload|vdsm", set_output_mode), + s_"Set output mode (default: libvirt)"; + [ M"oa" ], Getopt.String ("sparse|preallocated", set_output_alloc), + s_"Set output allocation mode"; +@@ -318,8 +317,6 @@ virt-v2v -i libvirtxml guest-domain.xml -o local -os /var/tmp + + virt-v2v -i disk disk.img -o local -os /var/tmp + +-virt-v2v -i disk disk.img -o glance +- + There is a companion front-end called \"virt-p2v\" which comes as an + ISO or CD image that can be booted on physical machines. + +@@ -387,7 +384,6 @@ read the man page virt-v2v(1). + pr "input:libvirtxml\n"; + pr "input:ova\n"; + pr "input:vmx\n"; +- pr "output:glance\n"; + pr "output:json\n"; + pr "output:libvirt\n"; + pr "output:local\n"; +@@ -481,7 +477,6 @@ read the man page virt-v2v(1). + | `Disk -> (module Output_disk.Disk) + | `Null -> (module Output_null.Null) + | `QEmu -> (module Output_qemu.QEMU) +- | `Glance -> (module Output_glance.Glance) + | `Openstack -> (module Output_openstack.Openstack) + | `RHV_Upload -> (module Output_rhv_upload.RHVUpload) + | `RHV -> (module Output_rhv.RHV) diff --git a/0008-v2v-nbdkit-Don-t-use-password-parameter-RHBZ-1842440.patch b/0008-v2v-nbdkit-Don-t-use-password-parameter-RHBZ-1842440.patch new file mode 100644 index 0000000..ffd539e --- /dev/null +++ b/0008-v2v-nbdkit-Don-t-use-password-parameter-RHBZ-1842440.patch @@ -0,0 +1,57 @@ +From 89ab50eb404664ac3522294f2f46a1c904a28abd Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 1 Jun 2020 17:35:58 +0100 +Subject: [PATCH] v2v: nbdkit: Don't use password=- parameter (RHBZ#1842440). + +This was broken with all nbdkit plugins, some in more ways than others. + +Because we start nbdkit in the background and wait 30 seconds for it +to start running, the user had only 30 seconds to type in a password +before we timed out the process. In addition with the VDDK plugin +password=- had been broken ever since we changed the plugin to use a +reexec +(https://www.redhat.com/archives/libguestfs/2020-June/msg00012.html). + +The solution is to read the password ourselves and pass it to nbdkit +as a private file. + +(cherry picked from commit 16b551c77c88219a2f68e2fc37daf2dc4d88e4ed) +--- + v2v/nbdkit_sources.ml | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/v2v/nbdkit_sources.ml b/v2v/nbdkit_sources.ml +index 47832011..f5e91911 100644 +--- a/v2v/nbdkit_sources.ml ++++ b/v2v/nbdkit_sources.ml +@@ -142,7 +142,26 @@ let common_create ?bandwidth ?extra_debug ?extra_env password + match password with + | NoPassword -> cmd + | AskForPassword -> +- Nbdkit.add_arg cmd "password" "-" ++ (* Because we will start nbdkit in the background and then wait ++ * for 30 seconds for it to start up, we cannot use the ++ * password=- feature of nbdkit to read the password ++ * interactively (since in the words of the movie the user has ++ * only "30 seconds to comply"). In any case this feature broke ++ * in the VDDK plugin in nbdkit 1.18 and 1.20. So in the ++ * AskForPassword case we read the password here. ++ *) ++ printf "password: "; ++ let open Unix in ++ let orig = tcgetattr stdin in ++ let tios = { orig with c_echo = false } in ++ tcsetattr stdin TCSAFLUSH tios; (* Disable echo. *) ++ let password = read_line () in ++ tcsetattr stdin TCSAFLUSH orig; (* Restore echo. *) ++ printf "\n"; ++ let password_file = Filename.temp_file "v2vnbdkit" ".txt" in ++ unlink_on_exit password_file; ++ with_open_out password_file (fun chan -> output_string chan password); ++ Nbdkit.add_arg cmd "password" ("+" ^ password_file) + | PasswordFile password_file -> + Nbdkit.add_arg cmd "password" ("+" ^ password_file) in + +-- +2.31.1 + diff --git a/0009-RHEL-Remove-the-in-place-option.patch b/0009-RHEL-Remove-the-in-place-option.patch new file mode 100644 index 0000000..b554409 --- /dev/null +++ b/0009-RHEL-Remove-the-in-place-option.patch @@ -0,0 +1,84 @@ +From 1176553cf7a9a7f7961887372757234ffdfae2bd Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 2 Dec 2021 11:56:05 +0000 +Subject: [PATCH] RHEL: Remove the --in-place option + +This disables the virt-v2v --in-place option which we do not +wish to support in RHEL. +--- + docs/virt-v2v.pod | 8 -------- + tests/Makefile.am | 1 - + v2v/v2v.ml | 8 -------- + 3 files changed, 17 deletions(-) + +diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod +index 84e049cc..7ad22f00 100644 +--- a/docs/virt-v2v.pod ++++ b/docs/virt-v2v.pod +@@ -21,9 +21,6 @@ There is also a companion front-end called L which comes + as an ISO, CD or PXE image that can be booted on physical machines to + virtualize those machines (physical to virtual, or p2v). + +-For in-place conversion, there is a separate tool called +-L. +- + =head2 Input and Output + + You normally run virt-v2v with several I<-i*> options controlling the +@@ -36,10 +33,6 @@ The input and output sides of virt-v2v are separate and unrelated. + Virt-v2v can read from any input and write to any output. Therefore + these sides of virt-v2v are documented separately in this manual. + +-Virt-v2v normally copies from the input to the output, called "copying +-mode". In this case the source guest is always left unchanged. +-In-place conversions may be done using L. +- + =head2 Other virt-v2v topics + + L — Supported hypervisors, virtualization +@@ -1587,7 +1580,6 @@ L, +-L, + L, + L, + L, +diff --git a/tests/Makefile.am b/tests/Makefile.am +index d36e230b..db32e42b 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -77,7 +77,6 @@ TESTS = \ + test-v2v-floppy.sh \ + test-v2v-i-disk.sh \ + test-v2v-i-ova.sh \ +- test-v2v-in-place.sh \ + test-v2v-mac.sh \ + test-v2v-machine-readable.sh \ + test-v2v-networks-and-bridges.sh \ +diff --git a/v2v/v2v.ml b/v2v/v2v.ml +index 41e020cb..e00f9814 100644 +--- a/v2v/v2v.ml ++++ b/v2v/v2v.ml +@@ -214,12 +214,6 @@ let rec main () = + warning (f_"the --vmtype option has been removed and now does nothing") + in + +- (* Options that are errors. *) +- let in_place_error _ = +- error (f_"The --in-place option has been replaced by the \ +- ‘virt-v2v-in-place’ program") +- in +- + let argspec = [ + [ L"bandwidth" ], Getopt.String ("bps", set_string_option_once "--bandwidth" bandwidth), + s_"Set bandwidth to bits per sec"; +@@ -241,8 +235,6 @@ let rec main () = + s_"Use password from file to connect to input hypervisor"; + [ M"it" ], Getopt.String ("transport", set_string_option_once "-it" input_transport), + s_"Input transport"; +- [ L"in-place" ], Getopt.Unit in_place_error, +- s_"Use virt-v2v-in-place instead"; + [ L"mac" ], Getopt.String ("mac:network|bridge|ip:out", add_mac), + s_"Map NIC to network or bridge or assign static IP"; + [ S 'n'; L"network" ], Getopt.String ("in:out", add_network), diff --git a/0009-libosinfo-declare-autocleanup-funcs-with-libosinfo-1.patch b/0009-libosinfo-declare-autocleanup-funcs-with-libosinfo-1.patch new file mode 100644 index 0000000..bda1f39 --- /dev/null +++ b/0009-libosinfo-declare-autocleanup-funcs-with-libosinfo-1.patch @@ -0,0 +1,44 @@ +From a8f3d2b2e87aead9f6a1db66dccebb6239ddf004 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Fri, 19 Jun 2020 17:57:36 +0200 +Subject: [PATCH] libosinfo: declare autocleanup funcs with libosinfo < 1.8.0 + +libosinfo 1.8.0 declares them automatically for all of its classes, so +there is no need to declare ours. This requires fixing the definition of +the IS_LIBOSINFO_VERSION macro to wrap its body in brackets. + +While in the process, simplify the workaround for a related bug by +removing a now-useless check. + +(cherry picked from commit c1caf7132000a4560c3e20c2753978e8dd10036a) +--- + v2v/libosinfo-c.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/v2v/libosinfo-c.c b/v2v/libosinfo-c.c +index 1ab6bb4d..497840c2 100644 +--- a/v2v/libosinfo-c.c ++++ b/v2v/libosinfo-c.c +@@ -40,12 +40,18 @@ + #define V2V_LIBOSINFO_VERSION_HEX \ + MAKE_VERSION_HEX(OSINFO_MAJOR_VERSION, OSINFO_MINOR_VERSION, OSINFO_MICRO_VERSION) + #define IS_LIBOSINFO_VERSION(maj, min, mic) \ +- V2V_LIBOSINFO_VERSION_HEX >= MAKE_VERSION_HEX(maj, min, mic) ++ (V2V_LIBOSINFO_VERSION_HEX >= MAKE_VERSION_HEX(maj, min, mic)) + ++/* ++ * libosinfo 1.8.0 provides auto-cleanup functions for all its classes, ++ * so avoid declaring our own. ++ */ ++#if !IS_LIBOSINFO_VERSION(1, 8, 0) + G_DEFINE_AUTOPTR_CLEANUP_FUNC(OsinfoFilter, g_object_unref) + G_DEFINE_AUTOPTR_CLEANUP_FUNC(OsinfoLoader, g_object_unref) + G_DEFINE_AUTOPTR_CLEANUP_FUNC(OsinfoList, g_object_unref) + G_DEFINE_AUTOPTR_CLEANUP_FUNC(OsinfoOsList, g_object_unref) ++#endif + + typedef OsinfoDb *OsinfoDb_t; + typedef OsinfoOs *OsinfoOs_t; +-- +2.31.1 + diff --git a/0010-output-Remove-o-json-mode.patch b/0010-output-Remove-o-json-mode.patch new file mode 100644 index 0000000..355af01 --- /dev/null +++ b/0010-output-Remove-o-json-mode.patch @@ -0,0 +1,1125 @@ +From a1f1129dc148639ed0b05b737157268d9b824a63 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 11 Apr 2022 11:01:46 +0100 +Subject: [PATCH] output: Remove -o json mode + +This removes the -o json mode completely. + +Reviewed-by: Laszlo Ersek +(cherry picked from commit 4e6b389b4e27c8d13e57fcaf777d96ad7e08650b) +--- + docs/virt-v2v.pod | 4 - + output/Makefile.am | 51 +----- + output/create_json.ml | 338 ----------------------------------- + output/create_json.mli | 27 --- + output/output_json.ml | 153 ---------------- + output/output_json.mli | 21 --- + output/var_expander.ml | 72 -------- + output/var_expander.mli | 82 --------- + output/var_expander_tests.ml | 113 ------------ + tests/Makefile.am | 2 - + tests/test-v2v-o-json.sh | 68 ------- + v2v/v2v.ml | 7 +- + 12 files changed, 5 insertions(+), 933 deletions(-) + delete mode 100644 output/create_json.ml + delete mode 100644 output/create_json.mli + delete mode 100644 output/output_json.ml + delete mode 100644 output/output_json.mli + delete mode 100644 output/var_expander.ml + delete mode 100644 output/var_expander.mli + delete mode 100644 output/var_expander_tests.ml + delete mode 100755 tests/test-v2v-o-json.sh + +diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod +index 7ad22f00..912f1bc3 100644 +--- a/docs/virt-v2v.pod ++++ b/docs/virt-v2v.pod +@@ -409,10 +409,6 @@ See L below. + + This is the same as I<-o local>. + +-=item B<-o> B +- +-This option is deprecated and will be removed in S. +- + =item B<-o> B + + Set the output method to I. This is the default. +diff --git a/output/Makefile.am b/output/Makefile.am +index 61caf68b..dd488549 100644 +--- a/output/Makefile.am ++++ b/output/Makefile.am +@@ -39,18 +39,15 @@ EXTRA_DIST = \ + rhv-upload-precheck.py \ + rhv-upload-transfer.py \ + rhv-upload-vmcheck.py \ +- test-v2v-python-syntax.sh \ +- var_expander_tests.ml ++ test-v2v-python-syntax.sh + + SOURCES_MLI = \ + changeuid.mli \ +- create_json.mli \ + create_libvirt_xml.mli \ + openstack_image_properties.mli \ + output.mli \ + output_disk.mli \ + output_glance.mli \ +- output_json.mli \ + output_libvirt.mli \ + output_null.mli \ + output_openstack.mli \ +@@ -66,14 +63,11 @@ SOURCES_MLI = \ + output_rhv_upload_transfer_source.mli \ + output_rhv_upload_vmcheck_source.mli \ + python_script.mli \ +- qemuopts.mli \ +- var_expander.mli ++ qemuopts.mli + + SOURCES_ML = \ + changeuid.ml \ + python_script.ml \ +- var_expander.ml \ +- create_json.ml \ + create_libvirt_xml.ml \ + qemuopts.ml \ + openstack_image_properties.ml \ +@@ -87,7 +81,6 @@ SOURCES_ML = \ + output.ml \ + output_disk.ml \ + output_glance.ml \ +- output_json.ml \ + output_libvirt.ml \ + output_null.ml \ + output_openstack.ml \ +@@ -203,47 +196,9 @@ $(MLOUTPUT_CMA): $(OBJECTS) libmloutput.a + $(OCAMLFIND) mklib $(OCAMLPACKAGES) \ + $(OBJECTS) $(libmloutput_a_OBJECTS) -o mloutput + +-# Unit tests. +-TESTS = +-if HAVE_OCAML_PKG_OUNIT +-TESTS += \ +- var_expander_tests +-check_PROGRAMS = \ +- var_expander_tests +-endif +- +-var_expander_tests_BOBJECTS = \ +- var_expander.cmo \ +- var_expander_tests.cmo +-var_expander_tests_XOBJECTS = $(var_expander_tests_BOBJECTS:.cmo=.cmx) +- +-var_expander_tests_SOURCES = dummy.c +-var_expander_tests_CPPFLAGS = $(virt_v2v_CPPFLAGS) +-var_expander_tests_CFLAGS = $(virt_v2v_CFLAGS) +- +-if !HAVE_OCAMLOPT +-# Can't call this var_expander_tests_OBJECTS because automake gets confused. +-var_expander_tests_THEOBJECTS = $(var_expander_tests_BOBJECTS) +-var_expander_tests.cmo: OCAMLPACKAGES += -package ounit2 +-else +-var_expander_tests_THEOBJECTS = $(var_expander_tests_XOBJECTS) +-var_expander_tests.cmx: OCAMLPACKAGES += -package ounit2 +-endif +- +-var_expander_tests_DEPENDENCIES = \ +- $(var_expander_tests_THEOBJECTS) \ +- $(top_builddir)/common/mlpcre/mlpcre.$(MLARCHIVE) \ +- $(top_srcdir)/ocaml-link.sh +-var_expander_tests_LINK = \ +- $(top_srcdir)/ocaml-link.sh -cclib '$(OCAMLCLIBS)' -- \ +- $(OCAMLFIND) $(BEST) $(OCAMLFLAGS) \ +- $(OCAMLPACKAGES) -package ounit2 \ +- $(OCAMLLINKFLAGS) \ +- $(var_expander_tests_THEOBJECTS) -o $@ +- + # Unit tests. + TESTS_ENVIRONMENT = $(top_builddir)/run --test +-TESTS += test-v2v-python-syntax.sh ++TESTS = test-v2v-python-syntax.sh + + # Dependencies. + .depend: \ +diff --git a/output/create_json.ml b/output/create_json.ml +deleted file mode 100644 +index cbc27fdc..00000000 +--- a/output/create_json.ml ++++ /dev/null +@@ -1,338 +0,0 @@ +-(* virt-v2v +- * Copyright (C) 2019 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 C_utils +-open Tools_utils +- +-open Types +-open Utils +- +-module G = Guestfs +- +-let json_list_of_string_list = +- List.map (fun x -> JSON.String x) +- +-let json_list_of_string_string_list = +- List.map (fun (x, y) -> x, JSON.String y) +- +-let push_optional_string lst name = function +- | None -> () +- | Some v -> List.push_back lst (name, JSON.String v) +- +-let push_optional_int lst name = function +- | None -> () +- | Some v -> List.push_back lst (name, JSON.Int (Int64.of_int v)) +- +-let json_unknown_string = function +- | "unknown" -> JSON.Null +- | v -> JSON.String v +- +-let create_json_metadata source inspect +- { guestcaps; target_buses; target_firmware; target_nics } +- outdisk_name output_format output_name = +- let doc = ref [ +- "version", JSON.Int 1L; +- "name", JSON.String output_name; +- "memory", JSON.Int source.s_memory; +- "vcpu", JSON.Int (Int64.of_int source.s_vcpu); +- ] in +- +- (match source.s_genid with +- | None -> () +- | Some genid -> List.push_back doc ("genid", JSON.String genid) +- ); +- +- if source.s_cpu_vendor <> None || source.s_cpu_model <> None || +- source.s_cpu_topology <> None then ( +- let cpu = ref [] in +- +- push_optional_string cpu "vendor" source.s_cpu_vendor; +- push_optional_string cpu "model" source.s_cpu_model; +- (match source.s_cpu_topology with +- | None -> () +- | Some { s_cpu_sockets; s_cpu_cores; s_cpu_threads } -> +- let attrs = [ +- "sockets", JSON.Int (Int64.of_int s_cpu_sockets); +- "cores", JSON.Int (Int64.of_int s_cpu_cores); +- "threads", JSON.Int (Int64.of_int s_cpu_threads); +- ] in +- List.push_back cpu ("topology", JSON.Dict attrs) +- ); +- +- List.push_back doc ("cpu", JSON.Dict !cpu); +- ); +- +- let firmware = +- let firmware_type = +- match target_firmware with +- | TargetBIOS -> "bios" +- | TargetUEFI -> "uefi" in +- +- let fw = ref [ +- "type", JSON.String firmware_type; +- ] in +- +- (match target_firmware with +- | TargetBIOS -> () +- | TargetUEFI -> +- let uefi_firmware = find_uefi_firmware guestcaps.gcaps_arch in +- let flags = +- List.map ( +- function +- | Uefi.UEFI_FLAG_SECURE_BOOT_REQUIRED -> "secure_boot_required" +- ) uefi_firmware.Uefi.flags in +- +- let uefi = ref [ +- "code", JSON.String uefi_firmware.Uefi.code; +- "vars", JSON.String uefi_firmware.Uefi.vars; +- "flags", JSON.List (json_list_of_string_list flags); +- ] in +- +- push_optional_string uefi "code-debug" uefi_firmware.Uefi.code_debug; +- +- List.push_back fw ("uefi", JSON.Dict !uefi) +- ); +- +- !fw in +- List.push_back doc ("firmware", JSON.Dict firmware); +- +- List.push_back doc ("features", +- JSON.List (json_list_of_string_list source.s_features)); +- +- let machine = +- match guestcaps.gcaps_machine with +- | I440FX -> "pc" +- | Q35 -> "q35" +- | Virt -> "virt" in +- List.push_back doc ("machine", JSON.String machine); +- +- let disks, removables = +- let disks = ref [] +- and removables = ref [] in +- +- let iter_bus bus_name drive_prefix i = function +- | BusSlotEmpty -> () +- | BusSlotDisk d -> +- (* Find the corresponding target disk. *) +- let outdisk = outdisk_name d.s_disk_id in +- +- let disk = [ +- "dev", JSON.String (drive_prefix ^ drive_name i); +- "bus", JSON.String bus_name; +- "format", JSON.String output_format; +- "file", JSON.String outdisk; +- ] in +- +- List.push_back disks (JSON.Dict disk) +- +- | BusSlotRemovable { s_removable_type = CDROM } -> +- let cdrom = [ +- "type", JSON.String "cdrom"; +- "dev", JSON.String (drive_prefix ^ drive_name i); +- "bus", JSON.String bus_name; +- ] in +- +- List.push_back removables (JSON.Dict cdrom) +- +- | BusSlotRemovable { s_removable_type = Floppy } -> +- let floppy = [ +- "type", JSON.String "floppy"; +- "dev", JSON.String (drive_prefix ^ drive_name i); +- ] in +- +- List.push_back removables (JSON.Dict floppy) +- in +- +- Array.iteri (iter_bus "virtio" "vd") target_buses.target_virtio_blk_bus; +- Array.iteri (iter_bus "ide" "hd") target_buses.target_ide_bus; +- Array.iteri (iter_bus "scsi" "sd") target_buses.target_scsi_bus; +- Array.iteri (iter_bus "floppy" "fd") target_buses.target_floppy_bus; +- +- !disks, !removables in +- List.push_back doc ("disks", JSON.List disks); +- List.push_back doc ("removables", JSON.List removables); +- +- let nics = +- List.map ( +- fun { s_mac = mac; s_vnet_type = vnet_type; s_nic_model = nic_model; +- s_vnet = vnet; } -> +- let vnet_type_str = +- match vnet_type with +- | Bridge -> "bridge" +- | Network -> "network" in +- +- let nic = ref [ +- "vnet", JSON.String vnet; +- "vnet-type", JSON.String vnet_type_str; +- ] in +- +- let nic_model_str = Option.map string_of_nic_model nic_model in +- push_optional_string nic "model" nic_model_str; +- +- push_optional_string nic "mac" mac; +- +- JSON.Dict !nic +- ) target_nics in +- List.push_back doc ("nics", JSON.List nics); +- +- let guestcaps_dict = +- let block_bus = +- match guestcaps.gcaps_block_bus with +- | Virtio_blk -> "virtio-blk" +- | IDE -> "ide" in +- let net_bus = +- match guestcaps.gcaps_net_bus with +- | Virtio_net -> "virtio-net" +- | E1000 -> "e1000" +- | RTL8139 -> "rtl8139" in +- let video = "vga" in +- let machine = +- match guestcaps.gcaps_machine with +- | I440FX -> "i440fx" +- | Q35 -> "q35" +- | Virt -> "virt" in +- +- [ +- "block-bus", JSON.String block_bus; +- "net-bus", JSON.String net_bus; +- "video", JSON.String video; +- "machine", JSON.String machine; +- "arch", JSON.String guestcaps.gcaps_arch; +- "virtio-rng", JSON.Bool guestcaps.gcaps_virtio_rng; +- "virtio-balloon", JSON.Bool guestcaps.gcaps_virtio_balloon; +- "isa-pvpanic", JSON.Bool guestcaps.gcaps_isa_pvpanic; +- "virtio-socket", JSON.Bool guestcaps.gcaps_virtio_socket; +- "acpi", JSON.Bool guestcaps.gcaps_acpi; +- "virtio-1-0", JSON.Bool guestcaps.gcaps_virtio_1_0; +- ] in +- List.push_back doc ("guestcaps", JSON.Dict guestcaps_dict); +- +- (match source.s_sound with +- | None -> () +- | Some { s_sound_model = model } -> +- let sound = [ +- "model", JSON.String (string_of_source_sound_model model); +- ] in +- List.push_back doc ("sound", JSON.Dict sound) +- ); +- +- (match source.s_display with +- | None -> () +- | Some d -> +- let display_type = +- match d.s_display_type with +- | Window -> "window" +- | VNC -> "vnc" +- | Spice -> "spice" in +- +- let display = ref [ +- "type", JSON.String display_type; +- ] in +- +- push_optional_string display "keymap" d.s_keymap; +- push_optional_string display "password" d.s_password; +- +- let listen = +- match d.s_listen with +- | LNoListen -> None +- | LAddress address -> +- Some [ +- "type", JSON.String "address"; +- "address", JSON.String address; +- ] +- | LNetwork network -> +- Some [ +- "type", JSON.String "network"; +- "network", JSON.String network; +- ] +- | LSocket None -> +- Some [ +- "type", JSON.String "socket"; +- "socket", JSON.Null; +- ] +- | LSocket (Some socket) -> +- Some [ +- "type", JSON.String "socket"; +- "socket", JSON.String socket; +- ] +- | LNone -> +- Some [ +- "type", JSON.String "none"; +- ] in +- (match listen with +- | None -> () +- | Some l -> List.push_back display ("listen", JSON.Dict l) +- ); +- +- push_optional_int display "port" d.s_port; +- +- List.push_back doc ("display", JSON.Dict !display) +- ); +- +- let inspect_dict = +- let apps = +- List.map ( +- fun { G.app2_name = name; app2_display_name = display_name; +- app2_epoch = epoch; app2_version = version; +- app2_release = release; app2_arch = arch; } -> +- JSON.Dict [ +- "name", JSON.String name; +- "display-name", JSON.String display_name; +- "epoch", JSON.Int (Int64.of_int32 epoch); +- "version", JSON.String version; +- "release", JSON.String release; +- "arch", JSON.String arch; +- ] +- ) inspect.i_apps in +- +- let firmware_dict = +- match inspect.i_firmware with +- | I_BIOS -> +- [ +- "type", JSON.String "bios"; +- ] +- | I_UEFI devices -> +- [ +- "type", JSON.String "uefi"; +- "devices", JSON.List (json_list_of_string_list devices); +- ] in +- +- [ +- "root", JSON.String inspect.i_root; +- "type", JSON.String inspect.i_type; +- "distro", json_unknown_string inspect.i_distro; +- "osinfo", json_unknown_string inspect.i_osinfo; +- "arch", JSON.String inspect.i_arch; +- "major-version", JSON.Int (Int64.of_int inspect.i_major_version); +- "minor-version", JSON.Int (Int64.of_int inspect.i_minor_version); +- "package-format", json_unknown_string inspect.i_package_format; +- "package-management", json_unknown_string inspect.i_package_management; +- "product-name", json_unknown_string inspect.i_product_name; +- "product-variant", json_unknown_string inspect.i_product_variant; +- "mountpoints", JSON.Dict (json_list_of_string_string_list inspect.i_mountpoints); +- "applications", JSON.List apps; +- "windows-systemroot", JSON.String inspect.i_windows_systemroot; +- "windows-software-hive", JSON.String inspect.i_windows_software_hive; +- "windows-system-hive", JSON.String inspect.i_windows_system_hive; +- "windows-current-control-set", JSON.String inspect.i_windows_current_control_set; +- "firmware", JSON.Dict firmware_dict; +- ] in +- List.push_back doc ("inspect", JSON.Dict inspect_dict); +- +- !doc +diff --git a/output/create_json.mli b/output/create_json.mli +deleted file mode 100644 +index 97086ff5..00000000 +--- a/output/create_json.mli ++++ /dev/null +@@ -1,27 +0,0 @@ +-(* virt-v2v +- * Copyright (C) 2019 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. +- *) +- +-(** Create JSON metadata for [-o json]. *) +- +-val create_json_metadata : Types.source -> Types.inspect -> +- Types.target_meta -> +- (int -> string) -> string -> string -> +- JSON.doc +-(** [create_json_metadata source targets outdisk_map output_format output_name] +- creates the JSON with the majority of the data that virt-v2v used for the +- conversion. *) +diff --git a/output/output_json.ml b/output/output_json.ml +deleted file mode 100644 +index 6e81b639..00000000 +--- a/output/output_json.ml ++++ /dev/null +@@ -1,153 +0,0 @@ +-(* virt-v2v +- * Copyright (C) 2009-2021 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 Printf +-open Unix +- +-open C_utils +-open Std_utils +-open Tools_utils +-open Common_gettext.Gettext +- +-open Types +-open Utils +- +-open Output +- +-module Json = struct +- type poptions = string * Types.output_allocation * string * string * string +- +- type t = unit +- +- let to_string options = +- "-o json" ^ +- match options.output_storage with +- | Some os -> " -os " ^ os +- | None -> "" +- +- let query_output_options () = +- printf (f_"Output options (-oo) which can be used with -o json: +- +- -oo json-disks-pattern=PATTERN Pattern for the disks. +-") +- +- let parse_options options source = +- if options.output_conn <> None then +- error_option_cannot_be_used_in_output_mode "json" "-oc"; +- if options.output_password <> None then +- error_option_cannot_be_used_in_output_mode "json" "-op"; +- +- let known_pattern_variables = ["DiskNo"; "DiskDeviceName"; "GuestName"] in +- let json_disks_pattern = ref None in +- List.iter ( +- fun (k, v) -> +- match k with +- | "json-disks-pattern" -> +- if !json_disks_pattern <> None then +- error (f_"-o json: -oo json-disks-pattern set more than once"); +- let vars = +- try Var_expander.scan_variables v +- with Var_expander.Invalid_variable var -> +- error (f_"-o json: -oo json-disks-pattern: invalid variable %%{%s}") +- var in +- List.iter ( +- fun var -> +- if not (List.mem var known_pattern_variables) then +- error (f_"-o json: -oo json-disks-pattern: unhandled variable %%{%s}") +- var +- ) vars; +- json_disks_pattern := Some v +- | k -> +- error (f_"-o json: unknown output option ‘-oo %s’") k +- ) options.output_options; +- +- let json_disks_pattern = +- Option.default "%{GuestName}-%{DiskDeviceName}" !json_disks_pattern in +- +- (* -os must be set to a directory. *) +- let output_storage = +- match options.output_storage with +- | None -> +- error (f_"-o json: output directory was not specified, use '-os /dir'") +- | Some d when not (is_directory d) -> +- error (f_"-os %s: output directory does not exist or is not a directory") d +- | Some d -> d in +- +- let output_name = Option.default source.s_name options.output_name in +- +- (json_disks_pattern, +- options.output_alloc, options.output_format, output_name, output_storage) +- +- let rec setup dir options source = +- let disks = get_disks dir in +- let json_disks_pattern, +- output_alloc, output_format, output_name, +- output_storage = options in +- +- List.iter ( +- fun (i, size) -> +- let socket = sprintf "%s/out%d" dir i in +- On_exit.unlink socket; +- +- (* Create the actual output disk. *) +- let outdisk = json_path output_storage output_name +- json_disks_pattern i in +- mkdir_p (Filename.dirname outdisk) 0o755; +- +- output_to_local_file output_alloc output_format outdisk size socket +- ) disks +- +- (* For -o json, return the output disk name of the i'th disk. *) +- and json_path os output_name json_disks_pattern i = +- let outname = +- let vars_fn = function +- | "DiskNo" -> Some (string_of_int (i+1)) +- | "DiskDeviceName" -> Some (sprintf "sd%s" (drive_name i)) +- | "GuestName" -> Some output_name +- | _ -> assert false +- in +- Var_expander.replace_fn json_disks_pattern vars_fn in +- let outdisk = os // outname in +- let outdisk = absolute_path outdisk in +- outdisk +- +- let finalize dir options () source inspect target_meta = +- let json_disks_pattern, +- output_alloc, output_format, output_name, output_storage = options in +- +- let doc = +- Create_json.create_json_metadata source inspect target_meta +- (json_path output_storage output_name json_disks_pattern) +- output_format output_name in +- let doc_string = JSON.string_of_doc ~fmt:JSON.Indented doc in +- +- if verbose () then ( +- eprintf "resulting JSON:\n"; +- output_string Stdlib.stderr doc_string; +- eprintf "\n\n%!"; +- ); +- +- let file = output_storage // output_name ^ ".json" in +- with_open_out file ( +- fun chan -> +- output_string chan doc_string; +- output_char chan '\n' +- ) +- +- let request_size = None +-end +diff --git a/output/output_json.mli b/output/output_json.mli +deleted file mode 100644 +index 00786ef7..00000000 +--- a/output/output_json.mli ++++ /dev/null +@@ -1,21 +0,0 @@ +-(* virt-v2v +- * Copyright (C) 2009-2021 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. +- *) +- +-(** [-o json] output mode. *) +- +-module Json : Output.OUTPUT +diff --git a/output/var_expander.ml b/output/var_expander.ml +deleted file mode 100644 +index 24b9bafe..00000000 +--- a/output/var_expander.ml ++++ /dev/null +@@ -1,72 +0,0 @@ +-(* virt-v2v +- * Copyright (C) 2019 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 +- +-exception Invalid_variable of string +- +-let var_re = PCRE.compile "(^|[^%])%{([^}]+)}" +- +-let check_variable var = +- String.iter ( +- function +- | '0'..'9' +- | 'a'..'z' +- | 'A'..'Z' +- | '_' +- | '-' -> () +- | _ -> raise (Invalid_variable var) +- ) var +- +-let scan_variables str = +- let res = ref [] in +- let offset = ref 0 in +- while PCRE.matches ~offset:!offset var_re str; do +- let var = PCRE.sub 2 in +- check_variable var; +- let _, end_ = PCRE.subi 0 in +- List.push_back res var; +- offset := end_ +- done; +- List.remove_duplicates !res +- +-let replace_fn str fn = +- let res = ref str in +- let offset = ref 0 in +- while PCRE.matches ~offset:!offset var_re !res; do +- let var = PCRE.sub 2 in +- check_variable var; +- let start_, end_ = PCRE.subi 0 in +- match fn var with +- | None -> +- offset := end_ +- | Some text -> +- let prefix_len = +- let prefix_start, prefix_end = PCRE.subi 1 in +- prefix_end - prefix_start in +- res := (String.sub !res 0 (start_ + prefix_len)) ^ text ^ (String.sub !res end_ (String.length !res - end_)); +- offset := start_ + prefix_len + String.length text +- done; +- !res +- +-let replace_list str lst = +- let fn var = +- try Some (List.assoc var lst) +- with Not_found -> None +- in +- replace_fn str fn +diff --git a/output/var_expander.mli b/output/var_expander.mli +deleted file mode 100644 +index 80aa33c2..00000000 +--- a/output/var_expander.mli ++++ /dev/null +@@ -1,82 +0,0 @@ +-(* virt-v2v +- * Copyright (C) 2019 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. +- *) +- +-(** Simple variable expander. +- +- This module provides the support to expand variables in strings, +- specified in the form of [%{name}]. +- +- For example: +- +-{v +-let str = "variable-%{INDEX} in %{INDEX} replaced %{INDEX} times" +-let index = ref 0 +-let fn = function +- | "INDEX" -> +- incr index; +- Some (string_of_int !index) +- | _ -> None +-in +-let str = Var_expander.replace_fn str fn +-(* now str is "variable-1 in 2 replaced 3 times" *) +-v} +- +- The names of variables can contain only ASCII letters (uppercase, +- and lowercase), digits, underscores, and dashes. +- +- The replacement is done in a single pass: this means that if a +- variable is replaced with the text of a variable, that new text +- is kept as is in the final output. In practice: +- +-{v +-let str = "%{VAR}" +-let str = Var_expander.replace_list str [("VAR", "%{VAR}")] +-(* now str is "%{VAR}" *) +-v} +-*) +- +-exception Invalid_variable of string +-(** Invalid variable name error. +- +- In case a variable contains characters not allowed, then this +- exception with the actual unacceptable variable. *) +- +-val scan_variables : string -> string list +-(** Scan the pattern string for all the variables available. +- +- This can raise {!Invalid_variable} in case there are invalid +- variable names. *) +- +-val replace_fn : string -> (string -> string option) -> string +-(** Replaces a string expanding all the variables. +- +- The replacement function specify how a variable is replaced; +- if [None] is returned, then that variable is not replaced. +- +- This can raise {!Invalid_variable} in case there are invalid +- variable names. *) +- +-val replace_list : string -> (string * string) list -> string +-(** Replaces a string expanding all the variables. +- +- The replacement list specify how a variable is replaced; +- if it is not specified in the list, then that variable is not +- replaced. +- +- This can raise {!Invalid_variable} in case there are invalid +- variable names. *) +diff --git a/output/var_expander_tests.ml b/output/var_expander_tests.ml +deleted file mode 100644 +index 35b62836..00000000 +--- a/output/var_expander_tests.ml ++++ /dev/null +@@ -1,113 +0,0 @@ +-(* virt-v2v +- * Copyright (C) 2019 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 Printf +-open OUnit +- +-open Std_utils +- +-let assert_equal_string = assert_equal ~printer:identity +-let assert_equal_stringlist = assert_equal ~printer:(fun x -> "(" ^ (String.escaped (String.concat "," x)) ^ ")") +- +-let replace_none_fn _ = None +-let replace_empty_fn _ = Some "" +- +-let test_no_replacement () = +- assert_equal_string "" (Var_expander.replace_fn "" replace_none_fn); +- assert_equal_string "x" (Var_expander.replace_fn "x" replace_none_fn); +- assert_equal_string "%{}" (Var_expander.replace_fn "%{}" replace_none_fn); +- assert_equal_string "%{EMPTY}" (Var_expander.replace_fn "%{EMPTY}" replace_none_fn); +- assert_equal_string "%{EMPTY} %{no}" (Var_expander.replace_fn "%{EMPTY} %{no}" replace_none_fn); +- assert_equal_string "a %{EMPTY} b" (Var_expander.replace_fn "a %{EMPTY} b" replace_none_fn); +- () +- +-let test_replacements () = +- assert_equal_string "" (Var_expander.replace_fn "%{EMPTY}" replace_empty_fn); +- assert_equal_string "x " (Var_expander.replace_fn "x %{EMPTY}" replace_empty_fn); +- assert_equal_string "xy" (Var_expander.replace_fn "x%{EMPTY}y" replace_empty_fn); +- assert_equal_string "x<->y" (Var_expander.replace_fn "x%{FOO}y" (function | "FOO" -> Some "<->" | _ -> None)); +- assert_equal_string "a x b" (Var_expander.replace_fn "a %{FOO} b" (function | "FOO" -> Some "x" | _ -> None)); +- assert_equal_string "%{FOO} x" (Var_expander.replace_fn "%{FOO} %{BAR}" (function | "BAR" -> Some "x" | _ -> None)); +- assert_equal_string "%{FOO}" (Var_expander.replace_fn "%{BAR}" (function | "BAR" -> Some "%{FOO}" | _ -> None)); +- assert_equal_string "%{FOO} x" (Var_expander.replace_fn "%{BAR} %{FOO}" (function | "BAR" -> Some "%{FOO}" | "FOO" -> Some "x" | _ -> None)); +- begin +- let str = "%{INDEX}, %{INDEX}, %{INDEX}" in +- let index = ref 0 in +- let fn = function +- | "INDEX" -> +- incr index; +- Some (string_of_int !index) +- | _ -> None +- in +- assert_equal_string "1, 2, 3" (Var_expander.replace_fn str fn) +- end; +- () +- +-let test_escape () = +- assert_equal_string "%%{FOO}" (Var_expander.replace_fn "%%{FOO}" replace_empty_fn); +- assert_equal_string "x %%{FOO} x" (Var_expander.replace_fn "%{FOO} %%{FOO} %{FOO}" (function | "FOO" -> Some "x" | _ -> None)); +- () +- +-let test_list () = +- assert_equal_string "x %{NONE}" (Var_expander.replace_list "%{FOO} %{NONE}" [("FOO", "x")]); +- () +- +-let test_scan_variables () = +- let assert_invalid_variable var = +- let str = "%{" ^ var ^ "}" in +- assert_raises (Var_expander.Invalid_variable var) +- (fun () -> Var_expander.scan_variables str) +- in +- assert_equal_stringlist [] (Var_expander.scan_variables ""); +- assert_equal_stringlist [] (Var_expander.scan_variables "foo"); +- assert_equal_stringlist ["FOO"] (Var_expander.scan_variables "%{FOO}"); +- assert_equal_stringlist ["FOO"; "BAR"] (Var_expander.scan_variables "%{FOO} %{BAR}"); +- assert_equal_stringlist ["FOO"; "BAR"] (Var_expander.scan_variables "%{FOO} %{BAR} %{FOO}"); +- assert_equal_stringlist ["FOO"; "BAR"] (Var_expander.scan_variables "%{FOO} %%{ESCAPED} %{BAR}"); +- assert_invalid_variable "FOO/BAR"; +- () +- +-let test_errors () = +- let assert_invalid_variable var = +- let str = "%{" ^ var ^ "}" in +- assert_raises (Var_expander.Invalid_variable var) +- (fun () -> Var_expander.replace_fn str replace_none_fn) +- in +- assert_invalid_variable "FOO/BAR"; +- assert_invalid_variable "FOO:BAR"; +- assert_invalid_variable "FOO(BAR"; +- assert_invalid_variable "FOO)BAR"; +- assert_invalid_variable "FOO@BAR"; +- () +- +-(* Suites declaration. *) +-let suite = +- TestList ([ +- "basic" >::: [ +- "no_replacement" >:: test_no_replacement; +- "replacements" >:: test_replacements; +- "escape" >:: test_escape; +- "list" >:: test_list; +- "scan_variables" >:: test_scan_variables; +- "errors" >:: test_errors; +- ]; +- ]) +- +-let () = +- ignore (run_test_tt_main suite); +- Printf.fprintf stderr "\n" +diff --git a/tests/Makefile.am b/tests/Makefile.am +index db32e42b..e787a86c 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -81,7 +81,6 @@ TESTS = \ + test-v2v-machine-readable.sh \ + test-v2v-networks-and-bridges.sh \ + test-v2v-o-glance.sh \ +- test-v2v-o-json.sh \ + test-v2v-o-libvirt.sh \ + test-v2v-o-null.sh \ + test-v2v-o-openstack.sh \ +@@ -241,7 +240,6 @@ EXTRA_DIST += \ + test-v2v-networks-and-bridges.sh \ + test-v2v-networks-and-bridges-expected.xml \ + test-v2v-o-glance.sh \ +- test-v2v-o-json.sh \ + test-v2v-o-libvirt.sh \ + test-v2v-o-null.sh \ + test-v2v-o-openstack.sh \ +diff --git a/tests/test-v2v-o-json.sh b/tests/test-v2v-o-json.sh +deleted file mode 100755 +index 15e7ad5a..00000000 +--- a/tests/test-v2v-o-json.sh ++++ /dev/null +@@ -1,68 +0,0 @@ +-#!/bin/bash - +-# libguestfs virt-v2v test script +-# Copyright (C) 2019 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. +- +-# Test -o json. +- +-set -e +-set -x +- +-source ./functions.sh +-set -e +-set -x +- +-skip_if_skipped +-requires test -f ../test-data/phony-guests/windows.img +-requires jq --version +- +-libvirt_uri="test://$abs_top_builddir/test-data/phony-guests/guests.xml" +- +-export VIRT_TOOLS_DATA_DIR="$srcdir/../test-data/fake-virt-tools" +- +-guestname=windows +- +-d=test-v2v-o-json.d +-rm -rf $d +-cleanup_fn rm -r $d +-mkdir $d +- +-json=$d/$guestname.json +-disk=$d/$guestname-sda +- +-$VG virt-v2v --debug-gc \ +- -i libvirt -ic "$libvirt_uri" windows \ +- -o json -os $d -on $guestname +- +-# Test the disk was created. +-test -f $disk +- +-# Test the JSON. +-test x$(jq -r '.name' $json) = xwindows +-test x$(jq -r '.inspect.type' $json) = xwindows +-test x$(jq -r '.inspect.distro' $json) = xwindows +-test $(jq -r '.disks | length' $json) -eq 1 +-test $(jq -r '.disks[0].file' $json) = $(realpath $disk) +-test $(jq -r '.nics | length' $json) -eq 1 +-test $(jq -r '.removables | length' $json) -eq 0 +- +-# libguestfs 1.40 didn't have osinfo inspection data, but we want this +-# test to work with 1.40, so ignore if jq returns this field as +-# "null". +-osinfo=$(jq -r '.inspect.osinfo' $json) +-if [ "x$osinfo" != "xnull" ]; then +- test x$osinfo = xwin7 +-fi +diff --git a/v2v/v2v.ml b/v2v/v2v.ml +index e00f9814..994982ac 100644 +--- a/v2v/v2v.ml ++++ b/v2v/v2v.ml +@@ -194,7 +194,6 @@ let rec main () = + match mode with + | "libvirt" -> output_mode := `Libvirt + | "disk" | "local" -> output_mode := `Disk +- | "json" -> output_mode := `JSON + | "null" -> output_mode := `Null + | "openstack" | "osp" | "rhosp" -> output_mode := `Openstack + | "ovirt" | "rhv" | "rhev" -> output_mode := `RHV +@@ -241,7 +240,7 @@ let rec main () = + s_"Map network ‘in’ to ‘out’"; + [ L"no-trim" ], Getopt.String ("-", no_trim_warning), + s_"Ignored for backwards compatibility"; +- [ S 'o' ], Getopt.String ("json|libvirt|local|null|openstack|qemu|rhv|rhv-upload|vdsm", set_output_mode), ++ [ S 'o' ], Getopt.String ("libvirt|local|null|openstack|qemu|rhv|rhv-upload|vdsm", set_output_mode), + s_"Set output mode (default: libvirt)"; + [ M"oa" ], Getopt.String ("sparse|preallocated", set_output_alloc), + s_"Set output allocation mode"; +@@ -376,7 +375,6 @@ read the man page virt-v2v(1). + pr "input:libvirtxml\n"; + pr "input:ova\n"; + pr "input:vmx\n"; +- pr "output:json\n"; + pr "output:libvirt\n"; + pr "output:local\n"; + pr "output:null\n"; +@@ -472,8 +470,7 @@ read the man page virt-v2v(1). + | `Openstack -> (module Output_openstack.Openstack) + | `RHV_Upload -> (module Output_rhv_upload.RHVUpload) + | `RHV -> (module Output_rhv.RHV) +- | `VDSM -> (module Output_vdsm.VDSM) +- | `JSON -> (module Output_json.Json) in ++ | `VDSM -> (module Output_vdsm.VDSM) in + + let output_options = { + Output.output_alloc = output_alloc; diff --git a/0010-v2v-Use-common-documentation-for-keys-from-stdin.patch b/0010-v2v-Use-common-documentation-for-keys-from-stdin.patch new file mode 100644 index 0000000..4171f8a --- /dev/null +++ b/0010-v2v-Use-common-documentation-for-keys-from-stdin.patch @@ -0,0 +1,60 @@ +From 6aec975c07d60a2518d3f16ee91db1d03a704882 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 30 Jul 2020 14:01:48 +0100 +Subject: [PATCH] v2v: Use common documentation for --keys-from-stdin. + +(cherry picked from commit 3f9b5f26398694a8a496eae85525e3be5c4b9cca) +--- + common | 2 +- + docs/virt-v2v.pod | 11 ++++------- + 2 files changed, 5 insertions(+), 8 deletions(-) + +Submodule common be42b0b8..5ea1baec: +diff --git a/common/options/Makefile.am b/common/options/Makefile.am +index b38fedc..f7ea749 100644 +--- a/common/options/Makefile.am ++++ b/common/options/Makefile.am +@@ -19,6 +19,7 @@ include $(top_srcdir)/subdir-rules.mk + + EXTRA_DIST = \ + key-option.pod \ ++ keys-from-stdin-option.pod \ + blocksize-option.pod + + # liboptions.la contains guestfish code which is used in other +diff --git a/common/options/keys-from-stdin-option.pod b/common/options/keys-from-stdin-option.pod +new file mode 100644 +index 0000000..03c5339 +--- /dev/null ++++ b/common/options/keys-from-stdin-option.pod +@@ -0,0 +1,4 @@ ++=item B<--keys-from-stdin> ++ ++Read key or passphrase parameters from stdin. The default is ++to try to read passphrases from the user by opening F. +diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod +index a00fa8af..74934eb4 100644 +--- a/docs/virt-v2v.pod ++++ b/docs/virt-v2v.pod +@@ -382,14 +382,11 @@ through VDDK. + + __INCLUDE:key-option.pod__ + +-=item B<--keys-from-stdin> ++__INCLUDE:keys-from-stdin-option.pod__ + +-Read key or passphrase parameters from stdin. The default is +-to try to read passphrases from the user by opening F. +- +-Note this options only applies to keys and passphrases for encrypted +-devices and partitions, not for passwords used to connect to remote +-servers. ++Note I<--keys-from-stdin> only applies to keys and passphrases for ++encrypted devices and partitions, not for passwords used to connect to ++remote servers. + + =item B<--mac> aa:bb:cc:dd:ee:ffB<:network:>out + +-- +2.31.1 + diff --git a/0011-docs-Multiple-keys-must-be-supplied-one-per-line-RHB.patch b/0011-docs-Multiple-keys-must-be-supplied-one-per-line-RHB.patch new file mode 100644 index 0000000..75ca17c --- /dev/null +++ b/0011-docs-Multiple-keys-must-be-supplied-one-per-line-RHB.patch @@ -0,0 +1,26 @@ +From 37ae5e04bd5f95c0c8a462dc6ef3fbdcfff4af75 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 30 Jul 2020 14:10:18 +0100 +Subject: [PATCH] docs: Multiple keys must be supplied one per line + (RHBZ#1858765). + +(cherry picked from commit 7ba65d14c0139dcf7fec45d33cee67c0f6737dd2) +--- + common | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Submodule common 5ea1baec..9338df5e: +diff --git a/common/options/keys-from-stdin-option.pod b/common/options/keys-from-stdin-option.pod +index 03c5339..8379039 100644 +--- a/common/options/keys-from-stdin-option.pod ++++ b/common/options/keys-from-stdin-option.pod +@@ -2,3 +2,6 @@ + + Read key or passphrase parameters from stdin. The default is + to try to read passphrases from the user by opening F. ++ ++If there are multiple encrypted devices then you may need to supply ++multiple keys on stdin, one per line. +-- +2.31.1 + diff --git a/0011-output-Remove-unused-dummy.c.patch b/0011-output-Remove-unused-dummy.c.patch new file mode 100644 index 0000000..7c00d1a --- /dev/null +++ b/0011-output-Remove-unused-dummy.c.patch @@ -0,0 +1,27 @@ +From 42da4736c2078801c0a5ebbe3825086f9b8d25ea Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 12 Apr 2022 11:53:45 +0100 +Subject: [PATCH] output: Remove unused dummy.c +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This was removed when I removed -o json support, but I did not delete +the file from git. “make maintainer-check-extra-dist” complained +about this. + +Fixes: commit 4e6b389b4e27c8d13e57fcaf777d96ad7e08650b +(cherry picked from commit 0a1286df1725560e2789134d12022fc52572f9b0) +--- + output/dummy.c | 2 -- + 1 file changed, 2 deletions(-) + delete mode 100644 output/dummy.c + +diff --git a/output/dummy.c b/output/dummy.c +deleted file mode 100644 +index ebab6198..00000000 +--- a/output/dummy.c ++++ /dev/null +@@ -1,2 +0,0 @@ +-/* Dummy source, to be used for OCaml-based tools with no C sources. */ +-enum { foo = 1 }; diff --git a/0012-adopt-inversion-of-SELinux-relabeling-in-virt-custom.patch b/0012-adopt-inversion-of-SELinux-relabeling-in-virt-custom.patch new file mode 100644 index 0000000..dd89566 --- /dev/null +++ b/0012-adopt-inversion-of-SELinux-relabeling-in-virt-custom.patch @@ -0,0 +1,79 @@ +From 7b22bc65e5df2bbe9f5ccf8ab05e67afb5a4cb8f Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Tue, 10 May 2022 12:53:07 +0200 +Subject: [PATCH] adopt inversion of SELinux relabeling in virt-customize + +Remove "--selinux-relabel" options. + +Do not add any "--no-selinux-relabel" options; rely on the internal check +for SELinux support instead ("is_selinux_guest" in +"common/mlcustomize/SELinux_relabel.ml"). + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1554735 +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2075718 +Signed-off-by: Laszlo Ersek +Message-Id: <20220510105307.15402-1-lersek@redhat.com> +Acked-by: Richard W.M. Jones +[lersek@redhat.com: incorporate common submodule update] +(cherry picked from commit 0c24fc6015ce7719acff3bcead7eb227b6de3f21) +--- + common | 2 +- + tests/test-v2v-conversion-of.sh | 7 ------- + 2 files changed, 1 insertion(+), 8 deletions(-) + +Submodule common 201632e4..af6cb55b (rewind): +diff --git a/common/mlcustomize/guest_packages.ml b/common/mlcustomize/guest_packages.ml +index 7c29a2ab..4c3c34ed 100644 +--- a/common/mlcustomize/guest_packages.ml ++++ b/common/mlcustomize/guest_packages.ml +@@ -73,9 +73,9 @@ let install_command packages package_management = + | "zypper" -> sprintf "zypper -n in -l %s" quoted_args + + | "unknown" -> +- error_unknown_package_manager "--install" ++ error_unknown_package_manager (s_"--install") + | pm -> +- error_unimplemented_package_manager "--install" pm ++ error_unimplemented_package_manager (s_"--install") pm + + let update_command package_management = + match package_management with +@@ -103,9 +103,9 @@ let update_command package_management = + | "zypper" -> "zypper -n update -l" + + | "unknown" -> +- error_unknown_package_manager "--update" ++ error_unknown_package_manager (s_"--update") + | pm -> +- error_unimplemented_package_manager "--update" pm ++ error_unimplemented_package_manager (s_"--update") pm + + let uninstall_command packages package_management = + let quoted_args = String.concat " " (List.map quote packages) in +@@ -127,6 +127,6 @@ let uninstall_command packages package_management = + | "zypper" -> sprintf "zypper -n rm %s" quoted_args + + | "unknown" -> +- error_unknown_package_manager "--uninstall" ++ error_unknown_package_manager (s_"--uninstall") + | pm -> +- error_unimplemented_package_manager "--uninstall" pm ++ error_unimplemented_package_manager (s_"--uninstall") pm +diff --git a/tests/test-v2v-conversion-of.sh b/tests/test-v2v-conversion-of.sh +index 5a974d1b..5c5cae7c 100755 +--- a/tests/test-v2v-conversion-of.sh ++++ b/tests/test-v2v-conversion-of.sh +@@ -53,13 +53,6 @@ fi + # Some guests need special virt-builder parameters. + # See virt-builder --notes "$guestname" + declare -a extra +-case "$guestname" in +- fedora*|rhel*|centos*) +- extra[${#extra[*]}]='--selinux-relabel' +- ;; +- *) +- ;; +-esac + + # Don't try to update Windows versions. + case "$guestname" in diff --git a/0012-v2v-Check-that-mac-ip-parameters-are-sensible-RHBZ-1.patch b/0012-v2v-Check-that-mac-ip-parameters-are-sensible-RHBZ-1.patch new file mode 100644 index 0000000..428ce02 --- /dev/null +++ b/0012-v2v-Check-that-mac-ip-parameters-are-sensible-RHBZ-1.patch @@ -0,0 +1,126 @@ +From fd1cbaa0907b30f639497c38953fe605bfc68ad0 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 28 Jul 2020 13:20:10 +0100 +Subject: [PATCH] v2v: Check that --mac :ip: parameters are sensible + (RHBZ#1858775). +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is not a complete check since IP addresses come in many forms, +but this at least stops nonsense being written through to the Windows +firstboot script. + +$ virt-v2v --mac 11:22:33:44:55:66:ip:hello,world,999,invalid -i disk test1.img -o null +virt-v2v: error: cannot parse --mac ip ipaddr: doesn’t look like +“hello” is an IP address + +$ virt-v2v --mac 11:22:33:44:55:66:ip:192.168.0.10,192.168.0.1,999,192.168.2.1,192.168.2.2 -i disk test1.img -o null +virt-v2v: error: --mac ip prefix length field is out of range + +Thanks: Zi Liu +(cherry picked from commit e8bcf9615490447e1b53a8b0d3e9d202ab178cf0) +--- + v2v/cmdline.ml | 55 ++++++++++++++++++++++++++++++++------------------ + 1 file changed, 35 insertions(+), 20 deletions(-) + +diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml +index 249137ab..3b74f307 100644 +--- a/v2v/cmdline.ml ++++ b/v2v/cmdline.ml +@@ -47,6 +47,7 @@ type cmdline = { + + (* Matches --mac command line parameters. *) + let mac_re = PCRE.compile ~anchored:true "([[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}:[[:xdigit:]]{2}):(network|bridge|ip):(.*)" ++let mac_ip_re = PCRE.compile ~anchored:true "([[:xdigit:]]|:|\\.)+" + + let parse_cmdline () = + let bandwidth = ref None in +@@ -102,7 +103,7 @@ let parse_cmdline () = + + let network_map = Networks.create () in + let static_ips = ref [] in +- let add_network str = ++ let rec add_network str = + match String.split ":" str with + | "", "" -> + error (f_"invalid -n/--network parameter") +@@ -110,8 +111,7 @@ let parse_cmdline () = + Networks.add_default_network network_map out + | in_, out -> + Networks.add_network network_map in_ out +- in +- let add_bridge str = ++ and add_bridge str = + match String.split ":" str with + | "", "" -> + error (f_"invalid -b/--bridge parameter") +@@ -119,8 +119,7 @@ let parse_cmdline () = + Networks.add_default_bridge network_map out + | in_, out -> + Networks.add_bridge network_map in_ out +- in +- let add_mac str = ++ and add_mac str = + if not (PCRE.matches mac_re str) then + error (f_"cannot parse --mac \"%s\" parameter") str; + let mac = PCRE.sub 1 and out = PCRE.sub 3 in +@@ -130,24 +129,40 @@ let parse_cmdline () = + | "bridge" -> + Networks.add_mac network_map mac Bridge out + | "ip" -> +- let add if_mac_addr if_ip_address if_default_gateway +- if_prefix_length if_nameservers = +- List.push_back static_ips +- { if_mac_addr; if_ip_address; if_default_gateway; +- if_prefix_length; if_nameservers } +- in + (match String.nsplit "," out with +- | [] -> +- error (f_"invalid --mac ip option") +- | [ip] -> add mac ip None None [] +- | [ip; gw] -> add mac ip (Some gw) None [] ++ | [] -> error (f_"invalid --mac ip option") ++ | [ip] -> add_static_ip mac ip None None [] ++ | [ip; gw] -> add_static_ip mac ip (Some gw) None [] + | ip :: gw :: len :: nameservers -> +- let len = +- try int_of_string len with +- | Failure _ -> error (f_"cannot parse --mac ip prefix length field as an integer: %s") len in +- add mac ip (Some gw) (Some len) nameservers +- ); ++ add_static_ip mac ip (Some gw) (Some len) nameservers ++ ) + | _ -> assert false ++ and add_static_ip if_mac_addr if_ip_address if_default_gateway ++ if_prefix_length_str if_nameservers = ++ (* Check the IP addresses and prefix length are sensible. This ++ * is only a very simple test that they are sane, since IP addresses ++ * come in too many valid forms to check thoroughly. ++ *) ++ let rec error_unless_ip_addr what addr = ++ if not (PCRE.matches mac_ip_re addr) then ++ error (f_"cannot parse --mac ip %s: doesn’t look like “%s” is an IP address") what addr ++ in ++ error_unless_ip_addr "ipaddr" if_ip_address; ++ Option.may (error_unless_ip_addr "gw") if_default_gateway; ++ List.iter (error_unless_ip_addr "nameserver") if_nameservers; ++ let if_prefix_length = ++ match if_prefix_length_str with ++ | None -> None ++ | Some len -> ++ let len = ++ try int_of_string len with ++ | Failure _ -> error (f_"cannot parse --mac ip prefix length field as an integer: %s") len in ++ if len < 0 || len > 128 then ++ error (f_"--mac ip prefix length field is out of range"); ++ Some len in ++ List.push_back static_ips ++ { if_mac_addr; if_ip_address; if_default_gateway; ++ if_prefix_length; if_nameservers } + in + + let no_trim_warning _ = +-- +2.31.1 + diff --git a/0013-libvirt-read-password-file-outside-libvirt-auth-call.patch b/0013-libvirt-read-password-file-outside-libvirt-auth-call.patch new file mode 100644 index 0000000..0c992b1 --- /dev/null +++ b/0013-libvirt-read-password-file-outside-libvirt-auth-call.patch @@ -0,0 +1,33 @@ +From 207552533f0b4ed2e2d570a827a85a44d4248b78 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Mon, 17 Aug 2020 09:17:51 +0200 +Subject: [PATCH] libvirt: read password file outside libvirt auth callback + +This way errors that occur while reading the password file are properly +propagated, instead of being reported as errors of the libvirt +authentication callback. + +Reported by: Ming Xie. + +(cherry picked from commit 76f9f3a0603f33c85d681fe13e24516331c6aea7) +--- + v2v/libvirt_utils.ml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/v2v/libvirt_utils.ml b/v2v/libvirt_utils.ml +index 4d0b8639..1a24b049 100644 +--- a/v2v/libvirt_utils.ml ++++ b/v2v/libvirt_utils.ml +@@ -24,8 +24,8 @@ open Common_gettext.Gettext + module. *) + + let auth_for_password_file ?password_file () = ++ let password = Option.map read_first_line_from_file password_file in + let auth_fn creds = +- let password = Option.map read_first_line_from_file password_file in + List.map ( + function + | { Libvirt.Connect.typ = Libvirt.Connect.CredentialPassphrase } -> password +-- +2.31.1 + diff --git a/0013-output-create_libvirt_xml-wire-up-the-QEMU-guest-age.patch b/0013-output-create_libvirt_xml-wire-up-the-QEMU-guest-age.patch new file mode 100644 index 0000000..9fa3822 --- /dev/null +++ b/0013-output-create_libvirt_xml-wire-up-the-QEMU-guest-age.patch @@ -0,0 +1,105 @@ +From 0699afed37343d73c6803cabec466e1c3ca229b0 Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Mon, 13 Jun 2022 19:01:32 +0200 +Subject: [PATCH] output/create_libvirt_xml: wire up the QEMU guest agent + +The intent (even before RHBZ#2028764) has been to install the QEMU guest +agent in the converted domain unconditionally. Therefore, in order for the +GA to be actually accessible from the host side, augment the libvirt +output module with a "guest agent connection" also unconditionally. + +For starters, the domain needs a virtio-serial device. Then there must be +a port on the device that (in the guest) the GA identifies by name, and +that (on the host) is exposed as a listening socket (usually in the unix +address family). The adress of that port (usually a pathname, i.e., for a +unix domain socket) is then passed to whatever host-side application wants +to talk to the GA. + +The minimal domain XML fragment for that ("minimal" for our purposes) is + + + + + + +The "controller" element is needed because "controller/@model" is where we +regulate "virtio" vs. "virtio-transitional". + +Everything else is filled in by libvirt. Notably, libvirt (a) creates and +binds the unix domain socket itself (usually +"/var/lib/libvirt/qemu/channel/target/DOMAIN/org.qemu.guest_agent.0"), (b) +passes the file descriptor to QEMU, and (c) figures out the socket +pathname for commands such as + + virsh domfsinfo DOMAIN + virsh domhostname DOMAIN --source agent + virsh domifaddr DOMAIN --source agent + virsh guestinfo DOMAIN + +For QEMU, the corresponding options would be + + -chardev socket,id=agent,server=on,wait=off,path=/tmp/DOMAIN-agent \ + -device virtio-serial-pci,id=vioserial \ + -device virtserialport,bus=vioserial.0,nr=1,chardev=agent,name=org.qemu.guest_agent.0 \ + +Note the "path=/tmp/DOMAIN-agent" property of "-chardev"; virt-v2v would +have to generate that (in place of the "fd=nnnn" property that libvirt +passes to QEMU). + +Omit extending the QEMU output module for now, as the QGA protocol is +based on JSON, and one needs "virsh" or "virt-manager" (or another +management application interface) anyway, for efficiently exchanging +messages with QGA. I don't know of end-user tools that directly connect to +"/tmp/DOMAIN-agent". + +Don't modify the RHV and OpenStack outputs either; both of these +management products likely configure the virtio-serial device +automatically, for the agent access. + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2028764 +Signed-off-by: Laszlo Ersek +Message-Id: <20220613170135.12557-2-lersek@redhat.com> +Reviewed-by: Richard W.M. Jones +Tested-by: Richard W.M. Jones +(cherry picked from commit 48c6ea27c5a7053e418622f7450e3f9ef05c923f) +--- + output/create_libvirt_xml.ml | 11 +++++++++++ + tests/test-v2v-i-ova.xml | 4 ++++ + 2 files changed, 15 insertions(+) + +diff --git a/output/create_libvirt_xml.ml b/output/create_libvirt_xml.ml +index 68d0a909..531a4f75 100644 +--- a/output/create_libvirt_xml.ml ++++ b/output/create_libvirt_xml.ml +@@ -524,6 +524,17 @@ let create_libvirt_xml ?pool source inspect + e "console" ["type", "pty"] []; + ]; + ++ (* Given that we install the QEMU Guest Agent for both Linux and Windows ++ * guests unconditionally, create the virtio-serial device that's needed for ++ * communication between the host and the agent. ++ *) ++ List.push_back_list devices [ ++ e "controller" ["type", "virtio-serial"; "model", virtio_model] []; ++ e "channel" ["type", "unix"] [ ++ e "target" ["type", "virtio"; "name", "org.qemu.guest_agent.0"] [] ++ ] ++ ]; ++ + List.push_back_list body [ + e "devices" [] !devices; + ]; +diff --git a/tests/test-v2v-i-ova.xml b/tests/test-v2v-i-ova.xml +index 6b8cda62..da1db473 100644 +--- a/tests/test-v2v-i-ova.xml ++++ b/tests/test-v2v-i-ova.xml +@@ -49,5 +49,9 @@ + + + ++ ++ ++ ++ + + diff --git a/0014-RHEL-8-v2v-Select-correct-qemu-binary-for-o-qemu-mod.patch b/0014-RHEL-8-v2v-Select-correct-qemu-binary-for-o-qemu-mod.patch new file mode 100644 index 0000000..8871b92 --- /dev/null +++ b/0014-RHEL-8-v2v-Select-correct-qemu-binary-for-o-qemu-mod.patch @@ -0,0 +1,33 @@ +From 9331544f2456f1aef7299920d0c84dff4e47d132 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sun, 28 Sep 2014 19:14:43 +0100 +Subject: [PATCH] RHEL 8: v2v: Select correct qemu binary for -o qemu mode + (RHBZ#1147313). + +RHEL 8 does not have qemu-system-x86_64 (etc), and in addition the +qemu binary is located in /usr/libexec. Encode the path to this +binary directly in the script. + +Note that we don't support people running qemu directly like this. +It's just for quick testing of converted VMs, and to help us with +support cases. +--- + v2v/output_qemu.ml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/v2v/output_qemu.ml b/v2v/output_qemu.ml +index be3a3c5e..85d08265 100644 +--- a/v2v/output_qemu.ml ++++ b/v2v/output_qemu.ml +@@ -81,7 +81,7 @@ object + * module deals with shell and qemu comma quoting. + *) + let cmd = Qemuopts.create () in +- Qemuopts.set_binary_by_arch cmd (Some guestcaps.gcaps_arch); ++ Qemuopts.set_binary cmd "/usr/libexec/qemu-kvm"; + + let flag = Qemuopts.flag cmd + and arg = Qemuopts.arg cmd +-- +2.31.1 + diff --git a/0014-convert_linux-extract-qemu-guest-agent-package-name.patch b/0014-convert_linux-extract-qemu-guest-agent-package-name.patch new file mode 100644 index 0000000..a5d7e2f --- /dev/null +++ b/0014-convert_linux-extract-qemu-guest-agent-package-name.patch @@ -0,0 +1,82 @@ +From 82c7526e052d2aa64a6754ff0e1082937e3ee4bc Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Mon, 13 Jun 2022 19:01:34 +0200 +Subject: [PATCH] convert_linux: extract qemu-guest-agent package name + +In commit a30383e35d34 ("v2v: linux: do not install qemu-guest-agent if +already installed", 2019-09-20), the name of the package providing the +QEMU guest agent was hard-coded as "qemu-guest-agent", regardless of +distro family. Turns out this is actually correct (and may have been +intentional, only it was not specifically documented): in all OS families +currently recognized by our "family" function (`RHEL_family, `ALT_family, +`SUSE_family, `Debian_family), the *binary* package is indeed called +"qemu-guest-agent": + +- https://brewweb.engineering.redhat.com/brew/packageinfo?packageID=47646 +- http://rpmfind.net/linux/rpm2html/search.php?query=qemu-guest-agent&submit=Search+...&system=&arch= +- https://packages.altlinux.org/en/sisyphus/srpms/qemu/ +- https://packages.debian.org/search?keywords=qemu-guest-agent&searchon=names&suite=all§ion=all + +As a way of documenting this, extract the mapping to a new helper function +named "qga_pkg_of_family". + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2028764 +Signed-off-by: Laszlo Ersek +Reviewed-by: Richard W.M. Jones +Message-Id: <20220613170135.12557-4-lersek@redhat.com> +(cherry picked from commit f65e8e68fb4eb9b8d40ac0fe7bfc3122a13e5251) +--- + convert/convert_linux.ml | 33 +++++++++++++++++++++++++-------- + 1 file changed, 25 insertions(+), 8 deletions(-) + +diff --git a/convert/convert_linux.ml b/convert/convert_linux.ml +index 79462aa1..2ddbc07a 100644 +--- a/convert/convert_linux.ml ++++ b/convert/convert_linux.ml +@@ -56,6 +56,16 @@ let convert (g : G.guestfs) source inspect keep_serial_console _ = + | "debian" | "ubuntu" | "linuxmint" | "kalilinux" -> `Debian_family + | _ -> assert false in + ++ (* map the OS family name to the qemu-guest-agent package name *) ++ let qga_pkg_of_family = ++ function ++ | `RHEL_family ++ | `ALT_family ++ | `SUSE_family ++ | `Debian_family -> Some "qemu-guest-agent" ++ | _ -> None ++ in ++ + assert (inspect.i_package_format = "rpm" || inspect.i_package_format = "deb"); + + (* Fail early if i_apps is empty. Certain steps such as kernel +@@ -539,14 +549,21 @@ let convert (g : G.guestfs) source inspect keep_serial_console _ = + + and install_linux_tools () = + (* It is not fatal if we fail to install the QEMU guest agent. *) +- let has_qemu_guest_agent = +- List.exists ( +- fun { G.app2_name = name } -> +- name = "qemu-guest-agent" +- ) inspect.i_apps in +- if not has_qemu_guest_agent then +- (* FIXME -- install qemu-guest-agent here *) +- () ++ match qga_pkg_of_family family with ++ | None -> warning (f_"The name of the package that provides the QEMU Guest \ ++ Agent for this guest OS is unknown. The guest agent \ ++ will not be installed. Please consider reporting a \ ++ bug according to the BUGS section of the virt-v2v(1) \ ++ manual.") ++ | Some qga_pkg -> ++ let has_qemu_guest_agent = ++ List.exists ( ++ fun { G.app2_name = name } -> ++ name = qga_pkg ++ ) inspect.i_apps in ++ if not has_qemu_guest_agent then ++ (* FIXME -- install qemu-guest-agent here *) ++ () + + and configure_kernel () = + (* Previously this function would try to install kernels, but we diff --git a/0015-RHEL-8-v2v-Disable-the-qemu-boot-option-RHBZ-1147313.patch b/0015-RHEL-8-v2v-Disable-the-qemu-boot-option-RHBZ-1147313.patch new file mode 100644 index 0000000..c1ceb9b --- /dev/null +++ b/0015-RHEL-8-v2v-Disable-the-qemu-boot-option-RHBZ-1147313.patch @@ -0,0 +1,105 @@ +From 7df465dede750140bbc5a2579a5256061af63e03 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 30 Sep 2014 10:50:27 +0100 +Subject: [PATCH] RHEL 8: v2v: Disable the --qemu-boot option (RHBZ#1147313). + +This cannot work because there is no Gtk or SDL output mode +in RHEL 8's qemu-kvm. + +In addition you will have to edit the -display option in the +qemu script. +--- + docs/virt-v2v-output-local.pod | 6 ++---- + docs/virt-v2v.pod | 13 ------------- + v2v/cmdline.ml | 3 ++- + 3 files changed, 4 insertions(+), 18 deletions(-) + +diff --git a/docs/virt-v2v-output-local.pod b/docs/virt-v2v-output-local.pod +index a5f155cb..3a2e6238 100644 +--- a/docs/virt-v2v-output-local.pod ++++ b/docs/virt-v2v-output-local.pod +@@ -9,7 +9,7 @@ or libvirt + + virt-v2v [-i* options] -o local -os DIRECTORY + +- virt-v2v [-i* options] -o qemu -os DIRECTORY [--qemu-boot] ++ virt-v2v [-i* options] -o qemu -os DIRECTORY + + virt-v2v [-i* options] -o json -os DIRECTORY + [-oo json-disks-pattern=PATTERN] +@@ -50,12 +50,10 @@ where C is the guest name. + + =item B<-o qemu -os> C + +-=item B<-o qemu -os> C B<--qemu-boot> +- + This converts the guest to files in C. Unlike I<-o local> + above, a shell script is created which contains the raw qemu command + you would need to boot the guest. However the shell script is not +-run, I you also add the I<--qemu-boot> option. ++run. + + =item B<-o json -os> C + +diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod +index 74934eb4..a19f0a73 100644 +--- a/docs/virt-v2v.pod ++++ b/docs/virt-v2v.pod +@@ -144,11 +144,6 @@ Since F contains the path(s) to the guest disk + image(s) you do not need to specify the name of the disk image on the + command line. + +-To convert a local disk image and immediately boot it in local +-qemu, do: +- +- virt-v2v -i disk disk.img -o qemu -os /var/tmp --qemu-boot +- + =head1 OPTIONS + + =over 4 +@@ -537,9 +532,6 @@ This is similar to I<-o local>, except that a shell script is written + which you can use to boot the guest in qemu. The converted disks and + shell script are written to the directory specified by I<-os>. + +-When using this output mode, you can also specify the I<--qemu-boot> +-option which boots the guest under qemu immediately. +- + =item B<-o> B + + This is the same as I<-o rhv>. +@@ -815,11 +807,6 @@ Print information about the source guest and stop. This option is + useful when you are setting up network and bridge maps. + See L. + +-=item B<--qemu-boot> +- +-When using I<-o qemu> only, this boots the guest immediately after +-virt-v2v finishes. +- + =item B<-q> + + =item B<--quiet> +diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml +index 3b74f307..df69e2e0 100644 +--- a/v2v/cmdline.ml ++++ b/v2v/cmdline.ml +@@ -284,7 +284,6 @@ let parse_cmdline () = + s_"Estimate size of source and stop"; + [ L"print-source" ], Getopt.Set print_source, + s_"Print source and stop"; +- [ L"qemu-boot" ], Getopt.Set qemu_boot, s_"Boot in qemu (-o qemu only)"; + [ L"root" ], Getopt.String ("ask|... ", set_root_choice), + s_"How to choose root filesystem"; + [ L"vddk-config" ], Getopt.String ("filename", set_input_option_compat "vddk-config"), +@@ -668,6 +667,8 @@ read the man page virt-v2v(1). + | Some d when not (is_directory d) -> + error (f_"-os %s: output directory does not exist or is not a directory") d + | Some d -> d in ++ if qemu_boot then ++ error (f_"-o qemu: the --qemu-boot option cannot be used in RHEL"); + Output_qemu.output_qemu os qemu_boot, + output_format, output_alloc + +-- +2.31.1 + diff --git a/0015-convert_linux-install-the-QEMU-guest-agent-with-a-fi.patch b/0015-convert_linux-install-the-QEMU-guest-agent-with-a-fi.patch new file mode 100644 index 0000000..5a5c7cb --- /dev/null +++ b/0015-convert_linux-install-the-QEMU-guest-agent-with-a-fi.patch @@ -0,0 +1,119 @@ +From e32a5ee7deb9a381ab285aba92c4de23e3c6ee2e Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Mon, 13 Jun 2022 19:01:35 +0200 +Subject: [PATCH] convert_linux: install the QEMU guest agent with a firstboot + script + +Register a firstboot script, for installing the guest agent with the +guest's own package manager -- that is, "Guest_packages.install_command". + +For installing the package, network connectivity is required. Check it +first with "nmcli" (also checking whether NetworkManager is running), then +with "systemd-networkd-wait-online" (dependent on systemd-networkd). Note +that NetworkManager and systemd-networkd are never supposed to be enabled +at the same time. + +The source domain's SELinux policy may not allow our firstboot service to +execute the package's installation scripts (if any). For that reason, +temporarily disable SELinux around package installation. + +After installation, register another script for launching the agent. + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2028764 +Signed-off-by: Laszlo Ersek +Message-Id: <20220613170135.12557-5-lersek@redhat.com> +Reviewed-by: Richard W.M. Jones +(cherry picked from commit e64356896377af1ac75a03d6a4c6a4208910bbf4) +--- + convert/convert_linux.ml | 78 ++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 76 insertions(+), 2 deletions(-) + +diff --git a/convert/convert_linux.ml b/convert/convert_linux.ml +index 2ddbc07a..59d143bd 100644 +--- a/convert/convert_linux.ml ++++ b/convert/convert_linux.ml +@@ -562,8 +562,82 @@ let convert (g : G.guestfs) source inspect keep_serial_console _ = + name = qga_pkg + ) inspect.i_apps in + if not has_qemu_guest_agent then +- (* FIXME -- install qemu-guest-agent here *) +- () ++ try ++ let inst_cmd = Guest_packages.install_command [qga_pkg] ++ inspect.i_package_management in ++ ++ (* Use only the portable filename character set in this. *) ++ let selinux_enforcing = "/root/virt-v2v-fb-selinux-enforcing" ++ and timeout = 30 in ++ let fbs = ++ Firstboot.add_firstboot_script g inspect.i_root ++ in ++ info (f_"The QEMU Guest Agent will be installed for this guest at \ ++ first boot."); ++ ++ (* Wait for the network to come online in the guest (best effort). ++ *) ++ fbs "wait online" ++ (sprintf "#!/bin/sh\n\ ++ if conn=$(nmcli networking connectivity); then\n\ ++ \ \ tries=0\n\ ++ \ \ while\n\ ++ \ \ \ \ test $tries -lt %d &&\n\ ++ \ \ \ \ test full != \"$conn\"\n\ ++ \ \ do\n\ ++ \ \ \ \ sleep 1\n\ ++ \ \ \ \ tries=$((tries + 1))\n\ ++ \ \ \ \ conn=$(nmcli networking connectivity)\n\ ++ \ \ done\n\ ++ elif systemctl -q is-active systemd-networkd; then\n\ ++ \ \ /usr/lib/systemd/systemd-networkd-wait-online \\\n\ ++ \ \ \ \ -q --timeout=%d\n\ ++ fi\n" timeout timeout); ++ ++ (* Disable SELinux temporarily around package installation. Refer to ++ * and ++ * . ++ *) ++ fbs "setenforce 0" ++ (sprintf "#!/bin/sh\n\ ++ rm -f %s\n\ ++ if command -v getenforce >/dev/null &&\n\ ++ \ \ test Enforcing = \"$(getenforce)\"\n\ ++ then\n\ ++ \ \ touch %s\n\ ++ \ \ setenforce 0\n\ ++ fi\n" selinux_enforcing selinux_enforcing); ++ fbs "install qga" inst_cmd; ++ fbs "setenforce restore" ++ (sprintf "#!/bin/sh\n\ ++ if test -f %s; then\n\ ++ \ \ setenforce 1\n\ ++ \ \ rm -f %s\n\ ++ fi\n" selinux_enforcing selinux_enforcing); ++ ++ (* Start the agent now and at subsequent boots. The following ++ * commands should work on both sysvinit distros / distro versions ++ * (regardless of "/etc/rc.d/" vs. "/etc/init.d/" being the scheme ++ * in use) and systemd distros (via redirection to systemctl). ++ * ++ * On distros where the chkconfig command is redirected to ++ * systemctl, the chkconfig command is likely superfluous. That's ++ * because on systemd distros, the QGA package comes with such ++ * runtime dependencies / triggers that the presence of the ++ * virtio-serial port named "org.qemu.guest_agent.0" automatically ++ * starts the agent during (second and later) boots. However, even ++ * on such distros, the chkconfig command should do no harm. ++ *) ++ fbs "start qga" ++ (sprintf "#!/bin/sh\n\ ++ service %s start\n\ ++ chkconfig %s on\n" qga_pkg qga_pkg) ++ with ++ | Guest_packages.Unknown_package_manager msg ++ | Guest_packages.Unimplemented_package_manager msg -> ++ warning (f_"The QEMU Guest Agent will not be installed. The \ ++ install command for package ‘%s’ could not be created: \ ++ %s.") qga_pkg msg + + and configure_kernel () = + (* Previously this function would try to install kernels, but we diff --git a/0016-RHEL-8-Fix-list-of-supported-sound-cards-to-match-RH.patch b/0016-RHEL-8-Fix-list-of-supported-sound-cards-to-match-RH.patch new file mode 100644 index 0000000..412223f --- /dev/null +++ b/0016-RHEL-8-Fix-list-of-supported-sound-cards-to-match-RH.patch @@ -0,0 +1,34 @@ +From ff5ae6613f5b344371cd8523a022af08fa6f191b Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 24 Apr 2015 09:45:41 -0400 +Subject: [PATCH] RHEL 8: Fix list of supported sound cards to match RHEL qemu + (RHBZ#1176493). + +--- + v2v/utils.ml | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/v2v/utils.ml b/v2v/utils.ml +index ccbb9d68..c2940582 100644 +--- a/v2v/utils.ml ++++ b/v2v/utils.ml +@@ -55,13 +55,14 @@ let kvm_arch = function + (* Does qemu support the given sound card? *) + let qemu_supports_sound_card = function + | Types.AC97 +- | Types.ES1370 + | Types.ICH6 + | Types.ICH9 + | Types.PCSpeaker ++ -> true ++ | Types.ES1370 + | Types.SB16 + | Types.USBAudio +- -> true ++ -> false + + (* Find the UEFI firmware. *) + let find_uefi_firmware guest_arch = +-- +2.31.1 + diff --git a/0016-RHV-outputs-limit-copied-disk-count-to-23.patch b/0016-RHV-outputs-limit-copied-disk-count-to-23.patch new file mode 100644 index 0000000..411ecd7 --- /dev/null +++ b/0016-RHV-outputs-limit-copied-disk-count-to-23.patch @@ -0,0 +1,122 @@ +From 50a74177b3577952159d87335cf40c0ad3e51b4d Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Fri, 17 Jun 2022 11:53:37 +0200 +Subject: [PATCH] RHV outputs: limit copied disk count to 23 + +We currently support virtio-blk (commonly) or IDE (unusually) for exposing +disks to the converted guest; refer to "guestcaps.gcaps_block_bus" in +"lib/create_ovf.ml". When using virtio-blk (i.e., in the common case), RHV +can deal with at most 23 disks, as it plugs each virtio-blk device in a +separate slot on the PCI(e) root bus; and the other slots are reserved for +various purposes. When a domain has too many disks, the problem only +becomes apparent once the copying finishes and an import is attempted. +Modify the RHV outputs to fail relatively early when a domain has more +than 23 disks that need to be copied. + +Notes: + +- With IDE, the theoretical limit may even be as low as 4. However, in the + "Output_module.setup" function, we don't have access to + "guestcaps.gcaps_block_bus", and in practice the IDE limitation has not + caused surprises. So for now stick with 23, assuming virtio-blk. + Modifying the "Output_module.setup" parameter list just for this seems + overkill. + +- We could move the new check to an even earlier step, namely + "Output_module.parse_options", due to the v2v directory deliberately + existing (and having been populated with input sockets) at that time. + However, even discounting the fact that "parse_options" is not a good + name for including this kind of step, "parse_options" does not have + access to the v2v directory name, and modifying the signature just for + this is (again) overkill. + +- By adding the check to "Output_module.setup", we waste *some* effort + (namely, the conversion occurs between "parse_options" and "setup"), + but: (a) the "rhv-disk-uuid" count check (against the disk count) is + already being done in the rhv-upload module's "setup" function, (b) in + practice the slowest step ought to be the copying, and placing the new + check in "setup" is early enough to prevent that. + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2051564 +Signed-off-by: Laszlo Ersek +Message-Id: <20220617095337.9122-1-lersek@redhat.com> +Reviewed-by: Richard W.M. Jones +(cherry picked from commit e186cc2bea99a077990f192953e1bf6c9ba70e79) +--- + output/output.ml | 5 +++++ + output/output.mli | 7 +++++++ + output/output_rhv.ml | 1 + + output/output_rhv_upload.ml | 1 + + output/output_vdsm.ml | 1 + + 5 files changed, 15 insertions(+) + +diff --git a/output/output.ml b/output/output.ml +index 10e685c4..5c6670b9 100644 +--- a/output/output.ml ++++ b/output/output.ml +@@ -64,6 +64,11 @@ let get_disks dir = + in + loop [] 0 + ++let error_if_disk_count_gt dir n = ++ let socket = sprintf "%s/in%d" dir n in ++ if Sys.file_exists socket then ++ error (f_"this output module doesn't support copying more than %d disks") n ++ + let output_to_local_file ?(changeuid = fun f -> f ()) + output_alloc output_format filename size socket = + (* Check nbdkit is installed and has the required plugin. *) +diff --git a/output/output.mli b/output/output.mli +index 533a0c51..8d3d6865 100644 +--- a/output/output.mli ++++ b/output/output.mli +@@ -76,6 +76,13 @@ val get_disks : string -> (int * int64) list + (** Examines the v2v directory and opens each input socket (in0 etc), + returning a list of input disk index and size. *) + ++val error_if_disk_count_gt : string -> int -> unit ++(** This function lets an output module enforce a maximum disk count. ++ [error_if_disk_count_gt dir n] checks whether the domain has more than [n] ++ disks that need to be copied, by examining the existence of input NBD socket ++ "in[n]" in the v2v directory [dir]. If the socket exists, [error] is ++ called. *) ++ + val output_to_local_file : ?changeuid:((unit -> unit) -> unit) -> + Types.output_allocation -> + string -> string -> int64 -> string -> +diff --git a/output/output_rhv.ml b/output/output_rhv.ml +index 119207fd..8571e07b 100644 +--- a/output/output_rhv.ml ++++ b/output/output_rhv.ml +@@ -56,6 +56,7 @@ module RHV = struct + (options.output_alloc, options.output_format, output_name, output_storage) + + let rec setup dir options source = ++ error_if_disk_count_gt dir 23; + let disks = get_disks dir in + let output_alloc, output_format, output_name, output_storage = options in + +diff --git a/output/output_rhv_upload.ml b/output/output_rhv_upload.ml +index 828996b3..f2ced4f4 100644 +--- a/output/output_rhv_upload.ml ++++ b/output/output_rhv_upload.ml +@@ -133,6 +133,7 @@ after their uploads (if you do, you must supply one for each disk): + else PCRE.matches (Lazy.force rex_uuid) uuid + + let rec setup dir options source = ++ error_if_disk_count_gt dir 23; + let disks = get_disks dir in + let output_conn, output_format, + output_password, output_name, output_storage, +diff --git a/output/output_vdsm.ml b/output/output_vdsm.ml +index a1e8c246..23d1b9cd 100644 +--- a/output/output_vdsm.ml ++++ b/output/output_vdsm.ml +@@ -119,6 +119,7 @@ For each disk you must supply one of each of these options: + compat, ovf_flavour) + + let setup dir options source = ++ error_if_disk_count_gt dir 23; + let disks = get_disks dir in + let output_alloc, output_format, + output_name, output_storage, diff --git a/0017-RHEL-8-Fix-tests-for-libguestfs-winsupport.patch b/0017-RHEL-8-Fix-tests-for-libguestfs-winsupport.patch new file mode 100644 index 0000000..327e2fa --- /dev/null +++ b/0017-RHEL-8-Fix-tests-for-libguestfs-winsupport.patch @@ -0,0 +1,79 @@ +From d6b625021e4bc1662b796e8c2f2a646d118f9fa1 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sun, 30 Aug 2015 03:21:57 -0400 +Subject: [PATCH] RHEL 8: Fix tests for libguestfs-winsupport. + +It doesn't let us use guestfish for arbitrary Windows edits. +--- + test-data/phony-guests/make-windows-img.sh | 1 + + tests/test-v2v-virtio-win-iso.sh | 8 +++++++- + tests/test-v2v-windows-conversion.sh | 8 +++++++- + 3 files changed, 15 insertions(+), 2 deletions(-) + +diff --git a/test-data/phony-guests/make-windows-img.sh b/test-data/phony-guests/make-windows-img.sh +index 30908a91..73cf5144 100755 +--- a/test-data/phony-guests/make-windows-img.sh ++++ b/test-data/phony-guests/make-windows-img.sh +@@ -37,6 +37,7 @@ fi + + # Create a disk image. + guestfish < "$script" + :> "$expected" + ++cat >> "$script" < "$response" ++guestfish --ro -a "$d/windows-sda" < "$script" > "$response" + diff -u "$expected" "$response" + + rm -r $d +diff --git a/tests/test-v2v-windows-conversion.sh b/tests/test-v2v-windows-conversion.sh +index f1da222a..ff94fe39 100755 +--- a/tests/test-v2v-windows-conversion.sh ++++ b/tests/test-v2v-windows-conversion.sh +@@ -73,6 +73,12 @@ mktest () + :> "$script" + :> "$expected" + ++cat >> "$script" < "$response" ++guestfish --ro -a "$d/windows-sda" < "$script" > "$response" + diff -u "$expected" "$response" + + # We also update the Registry several times, for firstboot, and (ONLY +-- +2.31.1 + diff --git a/0017-convert-document-networking-dependency-of-key-ID-cle.patch b/0017-convert-document-networking-dependency-of-key-ID-cle.patch new file mode 100644 index 0000000..c244498 --- /dev/null +++ b/0017-convert-document-networking-dependency-of-key-ID-cle.patch @@ -0,0 +1,49 @@ +From 81a201269e5451cd76348e0da6d0ef4c0fb4c0dd Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Fri, 1 Jul 2022 15:30:42 +0200 +Subject: [PATCH] convert: document networking dependency of "--key ID:clevis" + +Virt-v2v enables appliance networking already, for the sake of +"unconfigure_vmware". We now have a second use case for networking: "--key +ID:clevis". Update the comment in the code. + +(Short log for libguestfs-common commit range 35467027f657..af6cb55bc58a: + +Laszlo Ersek (12): + options: fix UUID comparison logic bug in get_keys() + mltools/tools_utils: remove unused function "key_store_to_cli" + mltools/tools_utils: allow multiple "--key" options for OCaml tools too + options: replace NULL-termination with number-of-elements in get_keys() + options: wrap each passphrase from get_keys() into a struct + options: add back-end for LUKS decryption with Clevis+Tang + options: introduce selector type "key_clevis" + options: generalize "--key" selector parsing for C-language utilities + mltools/tools_utils-c: handle internal type error with abort() + mltools/tools_utils: generalize "--key" selector parsing for OCaml utils + options, mltools/tools_utils: parse "--key ID:clevis" options + options, mltools/tools_utils: add helper for network dependency +). + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1809453 +Signed-off-by: Laszlo Ersek +Message-Id: <20220628115856.5820-1-lersek@redhat.com> +Reviewed-by: Richard W.M. Jones +(cherry picked from commit 98fa5ab2685371c681282ce5de704877af27be74) +--- + convert/convert.ml | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/convert/convert.ml b/convert/convert.ml +index 5e0e6c2b..b678dc92 100644 +--- a/convert/convert.ml ++++ b/convert/convert.ml +@@ -57,7 +57,8 @@ let rec convert dir options source = + * sure this is not too large because each vCPU consumes guest RAM. + *) + g#set_smp (min 8 (Sysconf.nr_processors_online ())); +- (* The network is only used by the unconfigure_vmware () function. *) ++ (* The network is used by the unconfigure_vmware () function, and the "--key ++ * ID:clevis" command line options (if any). *) + g#set_network true; + List.iter ( + fun { s_disk_id = i } -> diff --git a/0018-RHEL-8-v2v-Disable-the-virt-v2v-in-place-option.patch b/0018-RHEL-8-v2v-Disable-the-virt-v2v-in-place-option.patch new file mode 100644 index 0000000..2fdb600 --- /dev/null +++ b/0018-RHEL-8-v2v-Disable-the-virt-v2v-in-place-option.patch @@ -0,0 +1,286 @@ +From d55dcb095a383ff924acbfbe1c81a3a1eb4f4495 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 14 Jan 2016 11:53:42 -0500 +Subject: [PATCH] RHEL 8: v2v: Disable the virt-v2v --in-place option. + +This disables the virt-v2v --in-place option which we do not +wish to support in RHEL. +(See commit d0069559a939e47e5f29973ed9a69a13f0b58301). +--- + docs/test-v2v-docs.sh | 1 + + docs/virt-v2v.pod | 48 +---------------- + tests/Makefile.am | 2 - + tests/test-v2v-in-place.sh | 108 ------------------------------------- + v2v/cmdline.ml | 8 +-- + 5 files changed, 7 insertions(+), 160 deletions(-) + delete mode 100755 tests/test-v2v-in-place.sh + +diff --git a/docs/test-v2v-docs.sh b/docs/test-v2v-docs.sh +index dd2b1233..8fef46cc 100755 +--- a/docs/test-v2v-docs.sh ++++ b/docs/test-v2v-docs.sh +@@ -27,6 +27,7 @@ $top_srcdir/podcheck.pl virt-v2v.pod virt-v2v \ + --debug-overlay,\ + --ic,\ + --if,\ ++--in-place,\ + --io,\ + --ip,\ + --it,\ +diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod +index a19f0a73..6f9f323e 100644 +--- a/docs/virt-v2v.pod ++++ b/docs/virt-v2v.pod +@@ -8,10 +8,6 @@ virt-v2v - Convert a guest to use KVM + [-o mode] [other -o* options] + [guest|filename] + +- virt-v2v --in-place +- [-i mode] [other -i* options] +- [guest|filename] +- + =head1 DESCRIPTION + + Virt-v2v converts a single guest from a foreign hypervisor to run on +@@ -39,9 +35,6 @@ these sides of virt-v2v are documented separately in this manual. + + Virt-v2v normally copies from the input to the output, called "copying + mode". In this case the source guest is always left unchanged. +-In-place conversion (I<--in-place>) only uses the I<-i*> options and +-modifies the source guest in-place. (See L +-below.) + + =head2 Other virt-v2v topics + +@@ -301,20 +294,6 @@ For I<-i disk> only, this specifies the format of the input disk + image. For other input methods you should specify the input + format in the metadata. + +-=item B<--in-place> +- +-Do not create an output virtual machine in the target hypervisor. +-Instead, adjust the guest OS in the source VM to run in the input +-hypervisor. +- +-This mode is meant for integration with other toolsets, which take the +-responsibility of converting the VM configuration, providing for +-rollback in case of errors, transforming the storage, etc. +- +-See L below. +- +-Conflicts with all I<-o *> options. +- + =item B<-io> OPTION=VALUE + + Set input option(s) related to the current input mode or transport. +@@ -1332,7 +1311,7 @@ have at least 100 available inodes. + =head3 Minimum free space check in the host + + You must have sufficient free space in the host directory used to +-store temporary overlays (except in I<--in-place> mode). To find out ++store temporary overlays. To find out + which directory this is, use: + + $ df -h "`guestfish get-cachedir`" +@@ -1435,31 +1414,6 @@ that instead. + + + +-=head2 In-place conversion +- +-It is also possible to use virt-v2v in scenarios where a foreign VM +-has already been imported into a KVM-based hypervisor, but still needs +-adjustments in the guest to make it run in the new virtual hardware. +- +-In that case it is assumed that a third-party tool has created the +-target VM in the supported KVM-based hypervisor based on the source VM +-configuration and contents, but using virtual devices more appropriate +-for KVM (e.g. virtio storage and network, etc.). +- +-Then, to make the guest OS boot and run in the changed environment, +-one can use: +- +- virt-v2v -ic qemu:///system converted_vm --in-place +- +-Virt-v2v will analyze the configuration of C in the +-C libvirt instance, and apply various fixups to the +-guest OS configuration to make it match the VM configuration. This +-may include installing virtio drivers, configuring the bootloader, the +-mountpoints, the network interfaces, and so on. +- +-Should an error occur during the operation, virt-v2v exits with an +-error code leaving the VM in an undefined state. +- + =head2 Machine readable output + + The I<--machine-readable> option can be used to make the output more +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 871dc3c9..eee4e1af 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -76,7 +76,6 @@ TESTS = \ + test-v2v-floppy.sh \ + test-v2v-i-disk.sh \ + test-v2v-i-ova.sh \ +- test-v2v-in-place.sh \ + test-v2v-mac.sh \ + test-v2v-machine-readable.sh \ + test-v2v-networks-and-bridges.sh \ +@@ -225,7 +224,6 @@ EXTRA_DIST += \ + test-v2v-i-vmx-3.vmx \ + test-v2v-i-vmx-4.vmx \ + test-v2v-i-vmx-5.vmx \ +- test-v2v-in-place.sh \ + test-v2v-it-vddk-io-query.sh \ + test-v2v-machine-readable.sh \ + test-v2v-mac-expected.xml \ +diff --git a/tests/test-v2v-in-place.sh b/tests/test-v2v-in-place.sh +deleted file mode 100755 +index 6f7d78f3..00000000 +--- a/tests/test-v2v-in-place.sh ++++ /dev/null +@@ -1,108 +0,0 @@ +-#!/bin/bash - +-# libguestfs virt-v2v test script +-# Copyright (C) 2014 Red Hat Inc. +-# Copyright (C) 2015 Parallels IP Holdings GmbH. +-# +-# 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. +- +-# Test --in-place. +- +-unset CDPATH +-export LANG=C +-set -e +- +-$TEST_FUNCTIONS +-skip_if_skipped +-skip_if_backend uml +-skip_unless_phony_guest windows.img +- +-img_base="$abs_top_builddir/test-data/phony-guests/windows.img" +- +-export VIRT_TOOLS_DATA_DIR="$top_srcdir/test-data/fake-virt-tools" +-export VIRTIO_WIN="$top_srcdir/test-data/fake-virtio-win" +- +-d=$PWD/test-v2v-in-place.d +-rm -rf $d +-mkdir $d +- +-img="$d/test.qcow2" +-rm -f $img +-qemu-img create -f qcow2 -b $img_base -o compat=1.1,backing_fmt=raw $img +-md5="$(do_md5 $img_base)" +- +-libvirt_xml="$d/test.xml" +-rm -f $libvirt_xml +-n=windows-overlay +-cat > $libvirt_xml < +- +- $n +- 1048576 +- +- hvm +- +- +- +- +- +- +- +- +- +- +- +-EOF +- +-$VG virt-v2v --debug-gc -i libvirt -ic "test://$libvirt_xml" $n --in-place +- +-# Test that the drivers have been copied over into the guest +-script="$d/test.fish" +-expected="$d/expected" +-response="$d/response" +- +-mktest () +-{ +- local cmd="$1" exp="$2" +- +- echo "echo '$cmd'" >> "$script" +- echo "$cmd" >> "$expected" +- +- echo "$cmd" >> "$script" +- echo "$exp" >> "$expected" +-} +- +-:> "$script" +-:> "$expected" +- +-firstboot_dir="/Program Files/Guestfs/Firstboot" +-mktest "is-dir \"$firstboot_dir\"" true +-mktest "is-file \"$firstboot_dir/firstboot.bat\"" true +-mktest "is-dir \"$firstboot_dir/scripts\"" true +-virtio_dir="/Windows/Drivers/VirtIO" +-mktest "is-dir \"$virtio_dir\"" true +-for drv in netkvm qxl vioscsi viostor; do +- for sfx in cat inf sys; do +- mktest "is-file \"$virtio_dir/$drv.$sfx\"" true +- done +-done +- +-guestfish --ro -a "$img" -i < "$script" > "$response" +-diff -u "$expected" "$response" +- +-# Test the base image remained untouched +-test "$md5" = "$(do_md5 $img_base)" +- +-# Clean up. +-rm -r $d +diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml +index df69e2e0..7b79d462 100644 +--- a/v2v/cmdline.ml ++++ b/v2v/cmdline.ml +@@ -252,8 +252,7 @@ let parse_cmdline () = + s_"Use password from file to connect to input hypervisor"; + [ M"it" ], Getopt.String ("transport", set_string_option_once "-it" input_transport), + s_"Input transport"; +- [ L"in-place" ], Getopt.Set in_place, +- s_"Only tune the guest in the input VM"; ++ [ L"in-place" ], Getopt.Set in_place, Getopt.hidden_option_description; + [ L"mac" ], Getopt.String ("mac:network|bridge|ip:out", add_mac), + s_"Map NIC to network or bridge or assign static IP"; + [ S 'n'; L"network" ], Getopt.String ("in:out", add_network), +@@ -396,7 +395,6 @@ read the man page virt-v2v(1). + pr "vddk\n"; + pr "colours-option\n"; + pr "vdsm-compat-option\n"; +- pr "in-place\n"; + pr "io/oo\n"; + pr "mac-option\n"; + pr "bandwidth-option\n"; +@@ -572,6 +570,10 @@ read the man page virt-v2v(1). + error (f_"only ‘-it ssh’ can be used here") in + Input_vmx.input_vmx input_password input_transport arg in + ++ (* Prevent use of --in-place option in RHEL. *) ++ if in_place then ++ error (f_"--in-place cannot be used in RHEL"); ++ + (* Common error message. *) + let error_option_cannot_be_used_in_output_mode mode opt = + error (f_"-o %s: %s option cannot be used in this output mode") mode opt +-- +2.31.1 + diff --git a/0018-qemu-nbd-Implement-output-compression-for-qcow2-file.patch b/0018-qemu-nbd-Implement-output-compression-for-qcow2-file.patch new file mode 100644 index 0000000..6f57e5c --- /dev/null +++ b/0018-qemu-nbd-Implement-output-compression-for-qcow2-file.patch @@ -0,0 +1,142 @@ +From 80831868395d161af8c47edf2f54234c63581d8d Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 28 Jan 2022 09:30:29 +0000 +Subject: [PATCH] qemu-nbd: Implement output compression for qcow2 files + +Reviewed-by: Laszlo Ersek +(cherry picked from commit 71c4301909cb307def02ebcd0e89beee4138e7f2) +--- + lib/qemuNBD.ml | 11 +++++++++-- + lib/qemuNBD.mli | 5 +++++ + output/output.ml | 39 ++++++++++++++++++++++++++++++++++++--- + output/output.mli | 1 + + 4 files changed, 51 insertions(+), 5 deletions(-) + +diff --git a/lib/qemuNBD.ml b/lib/qemuNBD.ml +index ae21b17c..bbb65f41 100644 +--- a/lib/qemuNBD.ml ++++ b/lib/qemuNBD.ml +@@ -55,14 +55,16 @@ type cmd = { + disk : string; + mutable snapshot : bool; + mutable format : string option; ++ mutable imgopts : bool; + } + +-let create disk = { disk; snapshot = false; format = None } ++let create disk = { disk; snapshot = false; format = None; imgopts = false } + + let set_snapshot cmd snap = cmd.snapshot <- snap + let set_format cmd format = cmd.format <- format ++let set_image_opts cmd imgopts = cmd.imgopts <- imgopts + +-let run_unix socket { disk; snapshot; format } = ++let run_unix socket { disk; snapshot; format; imgopts } = + assert (disk <> ""); + + (* Create a temporary directory where we place the PID file. *) +@@ -85,6 +87,11 @@ let run_unix socket { disk; snapshot; format } = + (* -s adds a protective overlay. *) + if snapshot then List.push_back args "-s"; + ++ (* --image-opts reinterprets the filename parameter as a set of ++ * image options. ++ *) ++ if imgopts then List.push_back args "--image-opts"; ++ + if have_selinux && qemu_nbd_has_selinux_label_option () then ( + List.push_back args "--selinux-label"; + List.push_back args "system_u:object_r:svirt_socket_t:s0" +diff --git a/lib/qemuNBD.mli b/lib/qemuNBD.mli +index e10d3106..afe9d944 100644 +--- a/lib/qemuNBD.mli ++++ b/lib/qemuNBD.mli +@@ -43,6 +43,11 @@ val set_snapshot : cmd -> bool -> unit + val set_format : cmd -> string option -> unit + (** Set the format [--format] parameter. *) + ++val set_image_opts : cmd -> bool -> unit ++(** Set whether the [--image-opts] parameter is used. This changes ++ the meaning of the [filename] parameter to a set of image options. ++ Consult the qemu-nbd man page for more details. *) ++ + val run_unix : string -> cmd -> string * int + (** Start qemu-nbd command listening on a Unix domain socket, + waiting for the process to start up. +diff --git a/output/output.ml b/output/output.ml +index 5c6670b9..23c3932d 100644 +--- a/output/output.ml ++++ b/output/output.ml +@@ -69,7 +69,7 @@ let error_if_disk_count_gt dir n = + if Sys.file_exists socket then + error (f_"this output module doesn't support copying more than %d disks") n + +-let output_to_local_file ?(changeuid = fun f -> f ()) ++let output_to_local_file ?(changeuid = fun f -> f ()) ?(compressed = false) + output_alloc output_format filename size socket = + (* Check nbdkit is installed and has the required plugin. *) + if not (Nbdkit.is_installed ()) then +@@ -78,6 +78,24 @@ let output_to_local_file ?(changeuid = fun f -> f ()) + error (f_"nbdkit-file-plugin is not installed or not working"); + let nbdkit_config = Nbdkit.config () in + ++ if compressed then ( ++ (* Only allow compressed with -of qcow2. *) ++ if output_format <> "qcow2" then ++ error (f_"‘-oo compressed’ is only allowed when the output format \ ++ is a local qcow2-format file, i.e. ‘-of qcow2’"); ++ ++ (* Check nbdcopy is new enough. This assumes that the version of ++ * libnbd is the same as the version of nbdcopy, but parsing this ++ * is easier. We can remove this check when we build-depend on ++ * libnbd >= 1.14. ++ *) ++ let version = ++ NBD.create () |> NBD.get_version |> ++ String.nsplit "." |> List.map int_of_string in ++ if version < [1; 13; 5] then ++ error (f_"-oo compressed option requires nbdcopy >= 1.13.5") ++ ); ++ + let g = open_guestfs () in + let preallocation = + match output_alloc with +@@ -103,9 +121,24 @@ let output_to_local_file ?(changeuid = fun f -> f ()) + On_exit.kill pid + + | "qcow2" -> +- let cmd = QemuNBD.create filename in ++ let cmd = ++ if compressed then ( ++ let qemu_quote str = String.replace str "," ",," in ++ let image_opts = [ "driver=compress"; ++ "file.driver=qcow2"; ++ "file.file.driver=file"; ++ "file.file.filename=" ^ qemu_quote filename ] in ++ let image_opts = String.concat "," image_opts in ++ let cmd = QemuNBD.create image_opts in ++ QemuNBD.set_image_opts cmd true; ++ cmd ++ ) ++ else (* not compressed *) ( ++ let cmd = QemuNBD.create filename in ++ QemuNBD.set_format cmd (Some "qcow2"); ++ cmd ++ ) in + QemuNBD.set_snapshot cmd false; +- QemuNBD.set_format cmd (Some "qcow2"); + let _, pid = QemuNBD.run_unix socket cmd in + On_exit.kill pid + +diff --git a/output/output.mli b/output/output.mli +index 8d3d6865..c1f0f53d 100644 +--- a/output/output.mli ++++ b/output/output.mli +@@ -84,6 +84,7 @@ val error_if_disk_count_gt : string -> int -> unit + called. *) + + val output_to_local_file : ?changeuid:((unit -> unit) -> unit) -> ++ ?compressed:bool -> + Types.output_allocation -> + string -> string -> int64 -> string -> + unit diff --git a/0019-RHEL-8-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch b/0019-RHEL-8-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch new file mode 100644 index 0000000..8485297 --- /dev/null +++ b/0019-RHEL-8-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch @@ -0,0 +1,26 @@ +From ca9e31a9ae2e9cf5df5c65955ad746ee9f8d560b Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 2 Mar 2017 14:21:37 +0100 +Subject: [PATCH] RHEL 8: v2v: -i disk: force VNC as display (RHBZ#1372671) + +The SDL output mode is not supported in RHEL 8's qemu-kvm. +--- + v2v/input_disk.ml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/v2v/input_disk.ml b/v2v/input_disk.ml +index d146e84c..4e403003 100644 +--- a/v2v/input_disk.ml ++++ b/v2v/input_disk.ml +@@ -89,7 +89,7 @@ class input_disk input_format disk = object + s_features = [ "acpi"; "apic"; "pae" ]; + s_firmware = UnknownFirmware; (* causes virt-v2v to autodetect *) + s_display = +- Some { s_display_type = Window; s_keymap = None; s_password = None; ++ Some { s_display_type = VNC; s_keymap = None; s_password = None; + s_listen = LNoListen; s_port = None }; + s_video = None; + s_sound = None; +-- +2.31.1 + diff --git a/0019-o-disk-o-libvirt-o-qemu-Implement-of-qcow2-oo-compre.patch b/0019-o-disk-o-libvirt-o-qemu-Implement-of-qcow2-oo-compre.patch new file mode 100644 index 0000000..6da1880 --- /dev/null +++ b/0019-o-disk-o-libvirt-o-qemu-Implement-of-qcow2-oo-compre.patch @@ -0,0 +1,272 @@ +From ca3643d06eed2de22cb81ad2eb13ba7f75c0487e Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 28 Jan 2022 09:30:58 +0000 +Subject: [PATCH] -o disk, -o libvirt, -o qemu: Implement -of qcow2 -oo + compressed + +For various output modes, implement -oo compressed which can be used +to generate compressed qcow2 files. This option was dropped when +modularizing virt-v2v, and required changes to nbdcopy which are +finally upstream in libnbd >= 1.13.5. + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2047660 +Fixes: commit 255722cbf39afc0b012e2ac00d16fa6ba2f8c21f +Reported-by: Xiaodai Wang +Reviewed-by: Laszlo Ersek +(cherry picked from commit 53690a0c602a4286fdb9408fdf6a01cc352697ec) +--- + TODO | 14 -------------- + output/output_disk.ml | 29 +++++++++++++++++++++-------- + output/output_libvirt.ml | 31 ++++++++++++++++++++++--------- + output/output_qemu.ml | 38 +++++++++++++++++++++----------------- + 4 files changed, 64 insertions(+), 48 deletions(-) + +diff --git a/TODO b/TODO +index f578d506..04b1dd20 100644 +--- a/TODO ++++ b/TODO +@@ -1,17 +1,3 @@ +-virt-v2v -o disk|qemu -oo compressed +------------------------------------- +- +-This was temporarily dropped when I modularized virt-v2v. It would +-not be too difficult to add it back. The following is the qemu-nbd +-command required (to be run as the output helper) which creates a +-compressed qcow2 disk image: +- +-$ qemu-nbd --image-opts driver=compress,file.driver=qcow2,file.file.driver=file,file.file.filename=new.qcow2 +- +-Note this requires fixes in nbdcopy so it obeys the advertised block +-alignment: +-https://lists.gnu.org/archive/html/qemu-block/2022-01/threads.html#00729 +- + virt-v2v -o rhv-upload + ---------------------- + +diff --git a/output/output_disk.ml b/output/output_disk.ml +index bc5b4e1c..abcfcdc0 100644 +--- a/output/output_disk.ml ++++ b/output/output_disk.ml +@@ -30,7 +30,7 @@ open Create_libvirt_xml + open Output + + module Disk = struct +- type poptions = Types.output_allocation * string * string * string ++ type poptions = bool * Types.output_allocation * string * string * string + + type t = unit + +@@ -41,11 +41,21 @@ module Disk = struct + | None -> "" + + let query_output_options () = +- printf (f_"No output options can be used in this mode.\n") ++ printf (f_"Output options that can be used with -o disk: ++ ++ -oo compressed Compress the output file (used only with -of qcow2) ++") + + let parse_options options source = +- if options.output_options <> [] then +- error (f_"no -oo (output options) are allowed here"); ++ let compressed = ref false in ++ List.iter ( ++ function ++ | "compressed", "" -> compressed := true ++ | "compressed", v -> compressed := bool_of_string v ++ | k, _ -> ++ error (f_"-o disk: unknown output option ‘-oo %s’") k ++ ) options.output_options; ++ + if options.output_password <> None then + error_option_cannot_be_used_in_output_mode "local" "-op"; + +@@ -60,11 +70,13 @@ module Disk = struct + + let output_name = Option.default source.s_name options.output_name in + +- options.output_alloc, options.output_format, output_name, output_storage ++ !compressed, options.output_alloc, options.output_format, ++ output_name, output_storage + + let setup dir options source = + let disks = get_disks dir in +- let output_alloc, output_format, output_name, output_storage = options in ++ let compressed, output_alloc, output_format, output_name, output_storage = ++ options in + + List.iter ( + fun (i, size) -> +@@ -73,11 +85,12 @@ module Disk = struct + + (* Create the actual output disk. *) + let outdisk = disk_path output_storage output_name i in +- output_to_local_file output_alloc output_format outdisk size socket ++ output_to_local_file ~compressed output_alloc output_format ++ outdisk size socket + ) disks + + let finalize dir options () source inspect target_meta = +- let output_alloc, output_format, output_name, output_storage = options in ++ let _, output_alloc, output_format, output_name, output_storage = options in + + (* Convert metadata to libvirt XML. *) + (match target_meta.target_firmware with +diff --git a/output/output_libvirt.ml b/output/output_libvirt.ml +index e0d3432d..04b4c5f8 100644 +--- a/output/output_libvirt.ml ++++ b/output/output_libvirt.ml +@@ -32,7 +32,7 @@ open Create_libvirt_xml + open Output + + module Libvirt_ = struct +- type poptions = Libvirt.rw Libvirt.Connect.t Lazy.t * ++ type poptions = Libvirt.rw Libvirt.Connect.t Lazy.t * bool * + Types.output_allocation * string * string * string + + type t = string * string +@@ -44,11 +44,21 @@ module Libvirt_ = struct + | None -> "" + + let query_output_options () = +- printf (f_"No output options can be used in this mode.\n") ++ printf (f_"Output options that can be used with -o libvirt: ++ ++ -oo compressed Compress the output file (used only with -of qcow2) ++") + + let parse_options options source = +- if options.output_options <> [] then +- error (f_"no -oo (output options) are allowed here"); ++ let compressed = ref false in ++ List.iter ( ++ function ++ | "compressed", "" -> compressed := true ++ | "compressed", v -> compressed := bool_of_string v ++ | k, _ -> ++ error (f_"-o disk: unknown output option ‘-oo %s’") k ++ ) options.output_options; ++ + if options.output_password <> None then + error_option_cannot_be_used_in_output_mode "libvirt" "-op"; + +@@ -59,12 +69,13 @@ module Libvirt_ = struct + + let output_name = Option.default source.s_name options.output_name in + +- (conn, options.output_alloc, options.output_format, output_name, +- output_pool) ++ (conn, !compressed, options.output_alloc, options.output_format, ++ output_name, output_pool) + + let setup dir options source = + let disks = get_disks dir in +- let conn, output_alloc, output_format, output_name, output_pool = options in ++ let conn, compressed, output_alloc, output_format, ++ output_name, output_pool = options in + let conn = Lazy.force conn in + + (* Get the capabilities from libvirt. *) +@@ -119,13 +130,15 @@ module Libvirt_ = struct + + (* Create the actual output disk. *) + let outdisk = target_path // output_name ^ "-sd" ^ (drive_name i) in +- output_to_local_file output_alloc output_format outdisk size socket ++ output_to_local_file ~compressed output_alloc output_format ++ outdisk size socket + ) disks; + + (capabilities_xml, pool_name) + + let rec finalize dir options t source inspect target_meta = +- let conn, output_alloc, output_format, output_name, output_pool = options in ++ let conn, _, output_alloc, output_format, output_name, output_pool = ++ options in + let capabilities_xml, pool_name = t in + + (match target_meta.target_firmware with +diff --git a/output/output_qemu.ml b/output/output_qemu.ml +index 527d3c5e..e7efbb73 100644 +--- a/output/output_qemu.ml ++++ b/output/output_qemu.ml +@@ -29,7 +29,8 @@ open Utils + open Output + + module QEMU = struct +- type poptions = bool * Types.output_allocation * string * string * string ++ type poptions = bool * bool * ++ Types.output_allocation * string * string * string + + type t = unit + +@@ -42,6 +43,7 @@ module QEMU = struct + let query_output_options () = + printf (f_"Output options (-oo) which can be used with -o qemu: + ++ -oo compressed Compress the output file (used only with -of qcow2) + -oo qemu-boot Boot the guest in qemu after conversion + ") + +@@ -49,19 +51,19 @@ module QEMU = struct + if options.output_password <> None then + error_option_cannot_be_used_in_output_mode "qemu" "-op"; + +- let qemu_boot = ref false in ++ let compressed = ref false ++ and qemu_boot = ref false in + List.iter ( +- fun (k, v) -> +- match k with +- | "qemu-boot" -> +- if v = "" || v = "true" then qemu_boot := true +- else if v = "false" then qemu_boot := false +- else +- error (f_"-o qemu: use -oo qemu-boot[=true|false]") +- | k -> +- error (f_"-o qemu: unknown output option ‘-oo %s’") k +- ) options.output_options; +- let qemu_boot = !qemu_boot in ++ function ++ | "compressed", "" -> compressed := true ++ | "compressed", v -> compressed := bool_of_string v ++ | "qemu-boot", "" -> qemu_boot := true ++ | "qemu-boot", v -> qemu_boot := bool_of_string v ++ | k, _ -> ++ error (f_"-o qemu: unknown output option ‘-oo %s’") k ++ ) options.output_options; ++ let compressed = !compressed ++ and qemu_boot = !qemu_boot in + + if qemu_boot then + error (f_"-o qemu: the -oo qemu-boot option cannot be used in RHEL"); +@@ -77,12 +79,13 @@ module QEMU = struct + + let output_name = Option.default source.s_name options.output_name in + +- (qemu_boot, options.output_alloc, options.output_format, ++ (compressed, qemu_boot, options.output_alloc, options.output_format, + output_name, output_storage) + + let setup dir options source = + let disks = get_disks dir in +- let _, output_alloc, output_format, output_name, output_storage = options in ++ let compressed, _, output_alloc, output_format, ++ output_name, output_storage = options in + + List.iter ( + fun (i, size) -> +@@ -91,11 +94,12 @@ module QEMU = struct + + (* Create the actual output disk. *) + let outdisk = disk_path output_storage output_name i in +- output_to_local_file output_alloc output_format outdisk size socket ++ output_to_local_file ~compressed output_alloc output_format ++ outdisk size socket + ) disks + + let finalize dir options () source inspect target_meta = +- let qemu_boot, output_alloc, output_format, ++ let _, qemu_boot, output_alloc, output_format, + output_name, output_storage = options in + + let { guestcaps; target_buses; target_firmware } = target_meta in diff --git a/0020-RHEL-8-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch b/0020-RHEL-8-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch new file mode 100644 index 0000000..0b215db --- /dev/null +++ b/0020-RHEL-8-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch @@ -0,0 +1,26 @@ +From 959c084383b259ff54a247b4fdda3254e3f335db Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Wed, 8 Mar 2017 11:03:40 +0100 +Subject: [PATCH] RHEL 8: v2v: do not mention SUSE Xen hosts (RHBZ#1430203) + +They are not supported in RHEL 8. +--- + docs/virt-v2v-input-xen.pod | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/docs/virt-v2v-input-xen.pod b/docs/virt-v2v-input-xen.pod +index 3b3cf0f0..32da2848 100644 +--- a/docs/virt-v2v-input-xen.pod ++++ b/docs/virt-v2v-input-xen.pod +@@ -12,7 +12,7 @@ virt-v2v-input-xen - Using virt-v2v to convert guests from Xen + =head1 DESCRIPTION + + This page documents how to use L to convert guests from +-RHEL 5 Xen, or SLES and OpenSUSE Xen hosts. ++RHEL 5 Xen hosts. + + =head1 INPUT FROM XEN + +-- +2.31.1 + diff --git a/0020-tests-Add-a-simple-test-of-o-local-of-qcow2-oo-compr.patch b/0020-tests-Add-a-simple-test-of-o-local-of-qcow2-oo-compr.patch new file mode 100644 index 0000000..7559e6c --- /dev/null +++ b/0020-tests-Add-a-simple-test-of-o-local-of-qcow2-oo-compr.patch @@ -0,0 +1,114 @@ +From 672b9795e85b48f337b3da2d6fa393e7788d79a1 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 1 Jul 2022 11:18:53 +0100 +Subject: [PATCH] tests: Add a simple test of -o local -of qcow2 -oo compressed + +This only tests that it doesn't completely fail, which it did before +we fixed nbdcopy. I checked the file sizes manually and with +compression the resulting file is about half the size. + +This test is a clone of tests/test-v2v-of-option.sh. In order to +compare the sizes across the two tests, and to keep the tests fairly +similar I added an ls -l command to the original test. + +Reviewed-by: Laszlo Ersek +(cherry picked from commit 7505750972b49e1a448c519a27998bd5f20be60a) +--- + tests/Makefile.am | 2 + + tests/test-v2v-o-local-qcow2-compressed.sh | 53 ++++++++++++++++++++++ + tests/test-v2v-of-option.sh | 2 + + 3 files changed, 57 insertions(+) + create mode 100755 tests/test-v2v-o-local-qcow2-compressed.sh + +diff --git a/tests/Makefile.am b/tests/Makefile.am +index e787a86c..a26ecf7a 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -82,6 +82,7 @@ TESTS = \ + test-v2v-networks-and-bridges.sh \ + test-v2v-o-glance.sh \ + test-v2v-o-libvirt.sh \ ++ test-v2v-o-local-qcow2-compressed.sh \ + test-v2v-o-null.sh \ + test-v2v-o-openstack.sh \ + test-v2v-o-qemu.sh \ +@@ -241,6 +242,7 @@ EXTRA_DIST += \ + test-v2v-networks-and-bridges-expected.xml \ + test-v2v-o-glance.sh \ + test-v2v-o-libvirt.sh \ ++ test-v2v-o-local-qcow2-compressed.sh \ + test-v2v-o-null.sh \ + test-v2v-o-openstack.sh \ + test-v2v-o-qemu.sh \ +diff --git a/tests/test-v2v-o-local-qcow2-compressed.sh b/tests/test-v2v-o-local-qcow2-compressed.sh +new file mode 100755 +index 00000000..32c9ebbe +--- /dev/null ++++ b/tests/test-v2v-o-local-qcow2-compressed.sh +@@ -0,0 +1,53 @@ ++#!/bin/bash - ++# libguestfs virt-v2v test script ++# Copyright (C) 2014-2022 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. ++ ++# Test -o local -of qcow2 -oo compressed. ++ ++set -e ++ ++source ./functions.sh ++set -e ++set -x ++ ++skip_if_skipped ++requires test -f ../test-data/phony-guests/windows.img ++ ++# This requires fixed nbdcopy >= 1.13.5. ++requires nbdcopy --version ++nbdcopy --version | { ++ IFS=' .' read name major minor release ++ requires test \( "$major" -gt 1 \) -o \ ++ \( "$major" -eq 1 -a "$minor" -gt 13 \) -o \ ++ \( "$major" -eq 1 -a "$minor" -eq 13 -a "$release" -ge 5 \) ++} ++ ++export VIRT_TOOLS_DATA_DIR="$srcdir/../test-data/fake-virt-tools" ++ ++d=test-v2v-o-local-qcow2-compressed.d ++rm -rf $d ++cleanup_fn rm -rf $d ++mkdir $d ++ ++$VG virt-v2v --debug-gc \ ++ -i disk ../test-data/phony-guests/windows.img \ ++ -o local -of qcow2 -oo compressed -os $d ++ ++# Test the libvirt XML metadata and a disk was created. ++ls -l $d ++test -f $d/windows.xml ++test -f $d/windows-sda +diff --git a/tests/test-v2v-of-option.sh b/tests/test-v2v-of-option.sh +index bdfd3418..6c5f5938 100755 +--- a/tests/test-v2v-of-option.sh ++++ b/tests/test-v2v-of-option.sh +@@ -42,6 +42,8 @@ $VG virt-v2v --debug-gc \ + -i libvirt -ic "$libvirt_uri" windows \ + -o local -os $d -of qcow2 + ++ls -l $d ++ + # Test the disk is qcow2 format. + if [ "$(guestfish disk-format $d/windows-sda)" != qcow2 ]; then + echo "$0: test failed: output is not qcow2" diff --git a/0021-RHEL-8-v2v-rhv-upload-Remove-restriction-on-oa-spars.patch b/0021-RHEL-8-v2v-rhv-upload-Remove-restriction-on-oa-spars.patch new file mode 100644 index 0000000..4484602 --- /dev/null +++ b/0021-RHEL-8-v2v-rhv-upload-Remove-restriction-on-oa-spars.patch @@ -0,0 +1,89 @@ +From 4bd92b1fc4f830529b439c4a4e09281fcd9eab78 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 14 May 2018 10:16:58 +0100 +Subject: [PATCH] RHEL 8: v2v: rhv-upload: Remove restriction on -oa sparse. + +See: https://bugzilla.redhat.com/show_bug.cgi?id=1565681 +and the v2v-devel private thread "Do we already support migration using FC?" +--- + docs/virt-v2v-output-rhv.pod | 8 +------- + v2v/output_rhv_upload.ml | 10 +--------- + v2v/rhv-upload-plugin.py | 4 +--- + 3 files changed, 3 insertions(+), 19 deletions(-) + +diff --git a/docs/virt-v2v-output-rhv.pod b/docs/virt-v2v-output-rhv.pod +index 7c9b478a..36c3676f 100644 +--- a/docs/virt-v2v-output-rhv.pod ++++ b/docs/virt-v2v-output-rhv.pod +@@ -5,7 +5,7 @@ virt-v2v-output-rhv - Using virt-v2v to convert guests to oVirt or RHV + =head1 SYNOPSIS + + virt-v2v [-i* options] -o rhv-upload [-oc ENGINE_URL] -os STORAGE +- [-op PASSWORD] [-of raw] ++ [-op PASSWORD] + [-oo rhv-cafile=FILE] + [-oo rhv-cluster=CLUSTER] + [-oo rhv-direct] +@@ -79,12 +79,6 @@ username is not specified then virt-v2v defaults to using + C which is the typical superuser account for oVirt + instances. + +-=item I<-of raw> +- +-Currently you must use I<-of raw> and you cannot use I<-oa preallocated>. +- +-These restrictions will be loosened in a future version. +- + =item I<-op> F + + A file containing a password to be used when connecting to the oVirt +diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml +index 5c6c2611..81896e53 100644 +--- a/v2v/output_rhv_upload.ml ++++ b/v2v/output_rhv_upload.ml +@@ -135,17 +135,10 @@ let error_unless_nbdkit_compiled_with_selinux config = + 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.") + ) + +-(* Output sparse must be sparse. We may be able to +- * lift this limitation in future, but it requires changes on the +- * RHV side. See TODO file for details. XXX +- *) ++(* Output format must be raw. *) + let error_current_limitation required_param = + error (f_"rhv-upload: currently you must use ‘%s’. This restriction will be loosened in a future version.") required_param + +-let error_unless_output_alloc_sparse output_alloc = +- if output_alloc <> Sparse then +- error_current_limitation "-oa sparse" +- + let json_optstring = function + | Some s -> JSON.String s + | None -> JSON.Null +@@ -247,7 +240,6 @@ object + error_unless_nbdkit_min_version config; + error_unless_nbdkit_python_plugin_working plugin_script; + error_unless_nbdkit_compiled_with_selinux config; +- error_unless_output_alloc_sparse output_alloc; + + (* Python code prechecks. *) + let precheck_fn = tmpdir // "v2vprecheck.json" in +diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py +index d3e6260e..471102da 100644 +--- a/v2v/rhv-upload-plugin.py ++++ b/v2v/rhv-upload-plugin.py +@@ -477,10 +477,8 @@ def create_disk(connection): + # size, based on qemu-img measure of the overlay. + initial_size=params['disk_size'], + provisioned_size=params['disk_size'], +- # XXX Ignores params['output_sparse']. +- # Handling this properly will be complex, see: + # https://www.redhat.com/archives/libguestfs/2018-March/msg00177.html +- sparse=True, ++ sparse=params['output_sparse'], + storage_domains=[ + types.StorageDomain( + name=params['output_storage'], +-- +2.31.1 + diff --git a/0021-RHEL-9-oo-compressed-Remove-nbdcopy-version-check-an.patch b/0021-RHEL-9-oo-compressed-Remove-nbdcopy-version-check-an.patch new file mode 100644 index 0000000..afc8660 --- /dev/null +++ b/0021-RHEL-9-oo-compressed-Remove-nbdcopy-version-check-an.patch @@ -0,0 +1,47 @@ +From b61a03ad272bb08ff5ca757ade6a23bfef34fdc9 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 5 Jul 2022 11:56:54 +0100 +Subject: [PATCH] RHEL 9: -oo compressed: Remove nbdcopy version check and test + +In RHEL 9 nbdcopy 1.12.4-2 will be sufficient (vs nbdcopy 1.13.5 +upstream). We will enforce this through RPM dependencies and test it +separately. Thus remove the version check and test. +--- + output/output.ml | 11 ----------- + tests/Makefile.am | 1 - + 2 files changed, 12 deletions(-) + +diff --git a/output/output.ml b/output/output.ml +index 23c3932d..496c32b6 100644 +--- a/output/output.ml ++++ b/output/output.ml +@@ -83,17 +83,6 @@ let output_to_local_file ?(changeuid = fun f -> f ()) ?(compressed = false) + if output_format <> "qcow2" then + error (f_"‘-oo compressed’ is only allowed when the output format \ + is a local qcow2-format file, i.e. ‘-of qcow2’"); +- +- (* Check nbdcopy is new enough. This assumes that the version of +- * libnbd is the same as the version of nbdcopy, but parsing this +- * is easier. We can remove this check when we build-depend on +- * libnbd >= 1.14. +- *) +- let version = +- NBD.create () |> NBD.get_version |> +- String.nsplit "." |> List.map int_of_string in +- if version < [1; 13; 5] then +- error (f_"-oo compressed option requires nbdcopy >= 1.13.5") + ); + + let g = open_guestfs () in +diff --git a/tests/Makefile.am b/tests/Makefile.am +index a26ecf7a..47e5f10d 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -82,7 +82,6 @@ TESTS = \ + test-v2v-networks-and-bridges.sh \ + test-v2v-o-glance.sh \ + test-v2v-o-libvirt.sh \ +- test-v2v-o-local-qcow2-compressed.sh \ + test-v2v-o-null.sh \ + test-v2v-o-openstack.sh \ + test-v2v-o-qemu.sh \ diff --git a/0022-RHEL-8-use-platform-python.patch b/0022-RHEL-8-use-platform-python.patch new file mode 100644 index 0000000..bf6e733 --- /dev/null +++ b/0022-RHEL-8-use-platform-python.patch @@ -0,0 +1,27 @@ +From ca86a08fe00a56a21d239cb6d1ca6dc9f8ff28fa Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Sun, 16 Dec 2018 16:42:46 +0100 +Subject: [PATCH] RHEL 8: use platform-python + +Use the stable platform-python provided in BaseOS, instead of relying on +some arbitrary version installed by the user. +--- + v2v/python_script.ml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/v2v/python_script.ml b/v2v/python_script.ml +index 33c5e9a2..b1ea8f9d 100644 +--- a/v2v/python_script.ml ++++ b/v2v/python_script.ml +@@ -24,7 +24,7 @@ open Unix_utils + + open Common_gettext.Gettext + +-let python = "python3" (* Defined by PEP 394 *) ++let python = "/usr/libexec/platform-python" + + type script = { + tmpdir : string; (* Temporary directory. *) +-- +2.31.1 + diff --git a/0022-RHEL-9-tests-Remove-btrfs-test.patch b/0022-RHEL-9-tests-Remove-btrfs-test.patch new file mode 100644 index 0000000..cf4fbc8 --- /dev/null +++ b/0022-RHEL-9-tests-Remove-btrfs-test.patch @@ -0,0 +1,22 @@ +From 8a8ff53b7d438e82085d52199d21c980a54c733d Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 5 Jul 2022 11:58:09 +0100 +Subject: [PATCH] RHEL 9: tests: Remove btrfs test + +RHEL does not have btrfs so this test always fails. +--- + tests/Makefile.am | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 47e5f10d..9560cc77 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -96,7 +96,6 @@ TESTS = \ + test-v2v-sound.sh \ + test-v2v-virtio-win-iso.sh \ + test-v2v-fedora-conversion.sh \ +- test-v2v-fedora-btrfs-conversion.sh \ + test-v2v-fedora-luks-on-lvm-conversion.sh \ + test-v2v-fedora-lvm-on-luks-conversion.sh \ + test-v2v-fedora-md-conversion.sh \ diff --git a/0023-RHEL-8-point-to-KB-for-supported-v2v-hypervisors-gue.patch b/0023-RHEL-8-point-to-KB-for-supported-v2v-hypervisors-gue.patch new file mode 100644 index 0000000..bc2de07 --- /dev/null +++ b/0023-RHEL-8-point-to-KB-for-supported-v2v-hypervisors-gue.patch @@ -0,0 +1,125 @@ +From 1de8532631a765c03196774e0b4a41966284bae3 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Tue, 26 Mar 2019 09:42:25 +0100 +Subject: [PATCH] RHEL 8: point to KB for supported v2v hypervisors/guests + +--- + docs/virt-v2v-support.pod | 102 ++------------------------------------ + 1 file changed, 4 insertions(+), 98 deletions(-) + +diff --git a/docs/virt-v2v-support.pod b/docs/virt-v2v-support.pod +index 8333366b..a5150907 100644 +--- a/docs/virt-v2v-support.pod ++++ b/docs/virt-v2v-support.pod +@@ -8,104 +8,10 @@ systems and guests in virt-v2v + This page documents which foreign hypervisors, virtualization + management systems and guest types that L can support. + +-Note this page applies to upstream virt-v2v from +-L and in downstream distributions of virt-v2v +-sometimes features are intentionally removed, or are present but not +-supported. +- +-=head2 Hypervisors (Input) +- +-=over 4 +- +-=item VMware ESXi +- +-Must be managed by VMware vCenter E 5.0 unless VDDK is available. +- +-=item OVA exported from VMware +- +-OVAs from other hypervisors will not work. +- +-=item VMX from VMware +- +-VMX files generated by other hypervisors will not work. +- +-=item RHEL 5 Xen +- +-=item SUSE Xen +- +-=item Citrix Xen +- +-Citrix Xen has not been recently tested. +- +-=item Hyper-V +- +-Not recently tested. Requires that you export the disk or use +-L on Hyper-V. +- +-=item Direct from disk images +- +-Only disk images exported from supported hypervisors, and using +-container formats supported by qemu. +- +-=item Physical machines +- +-Using the L tool. +- +-=back +- +-=head2 Hypervisors (Output) +- +-QEMU and KVM only. +- +-=head2 Virtualization management systems (Output) +- +-=over 4 +- +-=item OpenStack +- +-=item Red Hat Virtualization (RHV) 4.1 and up +- +-=item Local libvirt +- +-And hence L, L, and similar tools. +- +-=item Local disk +- +-=back +- +-=head2 Guests +- +-=over 4 +- +-=item Red Hat Enterprise Linux 3, 4, 5, 6, 7 +- +-=item CentOS 3, 4, 5, 6, 7 +- +-=item Scientific Linux 3, 4, 5, 6, 7 +- +-=item Oracle Linux +- +-=item Fedora +- +-=item SLES 10 and up +- +-=item OpenSUSE 10 and up +- +-=item Debian 6 and up +- +-=item Ubuntu 10.04, 12.04, 14.04, 16.04, and up +- +-=item Windows XP to Windows 10 / Windows Server 2016 +- +-We use Windows internal version numbers, see +-L +- +-Currently NT 5.2 to NT 6.3 are supported. +- +-See L below for additional notes on converting Windows +-guests. +- +-=back ++For more information on supported hypervisors, and guest types in ++RHEL, please consult the following Knowledgebase article on these ++Red Hat Customer Portal: ++L. + + =head2 Guest firmware + +-- +2.31.1 + diff --git a/0023-convert-convert_linux-complete-the-remapping-of-NVMe.patch b/0023-convert-convert_linux-complete-the-remapping-of-NVMe.patch new file mode 100644 index 0000000..08a653f --- /dev/null +++ b/0023-convert-convert_linux-complete-the-remapping-of-NVMe.patch @@ -0,0 +1,80 @@ +From ba2963bc57c8c8a3d6f7cc2fd274c9ebd4ddb7d8 Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Wed, 6 Jul 2022 12:32:15 +0200 +Subject: [PATCH] convert/convert_linux: complete the remapping of NVMe devices + +In commit 75872bf282d7 ("input: -i vmx: Add support for NVMe devices", +2022-04-08), we missed that pathnames such as + + /dev/nvme0n1[p1] + +would not match our "rex_device_cciss" and "rex_device" regular +expressions. + +As a consequence, we don't remap such pathnames now in the boot config +files with Augeas. + +Add a new regex and associated mapping logic for this kind of pathname. + +Notes: + +(1) "rex_device_cciss" could be extended internally with an alternative +pattern: + + ^/dev/(cciss/c\\d+d\\d+|nvme\\d+n1)(?:p(\\d+))?$ + ^^^^^^^^^^^ + +but Rich suggested we should add a separate, complete regexp for +maintainability. + +(2) Even with a separate regexp, we could reuse the existent CCISS pattern +handler: + + if PCRE.matches rex_device_cciss value || + PCRE.matches rex_device_nvme value then ( + let device = PCRE.sub 1 + and part = try PCRE.sub 2 with Not_found -> "" in + "/dev/" ^ replace device ^ part + ) + +Namely, although "PCRE.matches" creates/updates global state, and +"PCRE.sub" reads that state, the "||" operator in OCaml has short-circuit +behavior, and both regexps have the same structure. + +But, using the same maintainability argument, let's keep the handler logic +for NVMe detached. + +Fixes: 75872bf282d7f2322110caca70963717b43806b1 +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2101665 +Signed-off-by: Laszlo Ersek +Message-Id: <20220706103215.5607-1-lersek@redhat.com> +Reviewed-by: Richard W.M. Jones +(cherry picked from commit 4368b94ee1724c16aa35c0ee42ce4c51ce037b5a) +--- + convert/convert_linux.ml | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/convert/convert_linux.ml b/convert/convert_linux.ml +index 59d143bd..a66ff1e4 100644 +--- a/convert/convert_linux.ml ++++ b/convert/convert_linux.ml +@@ -1199,6 +1199,7 @@ let convert (g : G.guestfs) source inspect keep_serial_console _ = + (* Map device names for each entry. *) + let rex_resume = PCRE.compile "^resume=(/dev/[-a-z\\d/_]+)(.*)$" + and rex_device_cciss = PCRE.compile "^/dev/(cciss/c\\d+d\\d+)(?:p(\\d+))?$" ++ and rex_device_nvme = PCRE.compile "^/dev/(nvme\\d+n1)(?:p(\\d+))?$" + and rex_device = PCRE.compile "^/dev/([a-z]+)(\\d*)?$" in + + let rec replace_if_device path value = +@@ -1221,6 +1222,11 @@ let convert (g : G.guestfs) source inspect keep_serial_console _ = + and part = try PCRE.sub 2 with Not_found -> "" in + "/dev/" ^ replace device ^ part + ) ++ else if PCRE.matches rex_device_nvme value then ( ++ let device = PCRE.sub 1 ++ and part = try PCRE.sub 2 with Not_found -> "" in ++ "/dev/" ^ replace device ^ part ++ ) + else if PCRE.matches rex_device value then ( + let device = PCRE.sub 1 + and part = try PCRE.sub 2 with Not_found -> "" in diff --git a/0024-input-xen-sync-ip-limitations-language-from-input-vm.patch b/0024-input-xen-sync-ip-limitations-language-from-input-vm.patch new file mode 100644 index 0000000..9637e0b --- /dev/null +++ b/0024-input-xen-sync-ip-limitations-language-from-input-vm.patch @@ -0,0 +1,49 @@ +From c34fe9a52abdde05cb31c5bd2c99237652e1b0dc Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Mon, 11 Jul 2022 09:01:56 +0200 +Subject: [PATCH] input-xen: sync "-ip" limitations language from input-vmware + manual + +My analysis in +was partially wrong; I had missed that for the xen+ssh transport, the +client-side libvirt library launches a naked "ssh" utility, underneath +"Libvirt.Connect.connect_auth": + + setup [input/input_xen_ssh.ml] + Libvirt.Connect.connect_auth + no effect of "-ip" + Nbdkit_ssh.create_ssh [input/nbdkit_ssh.ml] + starts nbdkit with the ssh + plugin honoring "-ip" + +Which requires a password just the same, and ignores "-ip" just the same. + +Recommend the ssh agent in the docs. + +Fixes: 46298c6514710013c59828b4933f0b3b1a354566 +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1854275 +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2062360 +Signed-off-by: Laszlo Ersek +Message-Id: <20220711070157.5399-2-lersek@redhat.com> +Reviewed-by: Richard W.M. Jones +(cherry picked from commit ae067a9ce0eb5631940a8cc5dcc5ee056903276b) +--- + docs/virt-v2v-input-xen.pod | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/docs/virt-v2v-input-xen.pod b/docs/virt-v2v-input-xen.pod +index ad5772de..80ad94f7 100644 +--- a/docs/virt-v2v-input-xen.pod ++++ b/docs/virt-v2v-input-xen.pod +@@ -32,6 +32,11 @@ server to the Xen host. For example: + $ ssh root@xen.example.com + [ logs straight into the shell, no password is requested ] + ++Note that support for non-interactive authentication via the I<-ip> ++option is incomplete. Some operations remain that still require the ++user to enter the password manually. Therefore ssh-agent is recommended ++over the I<-ip> option. See L. ++ + With some modern ssh implementations, legacy crypto policies required + to interoperate with RHEL 5 sshd are disabled. To enable them you may + need to run this command on the conversion server (ie. ssh client), diff --git a/0024-v2v-Allow-large-temporary-directory-to-be-set-on-a-g.patch b/0024-v2v-Allow-large-temporary-directory-to-be-set-on-a-g.patch new file mode 100644 index 0000000..6d8c541 --- /dev/null +++ b/0024-v2v-Allow-large-temporary-directory-to-be-set-on-a-g.patch @@ -0,0 +1,388 @@ +From 186c237ac1cb6f6830cfe2d08dfdcfdbdffab264 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 6 Apr 2020 10:19:12 +0100 +Subject: [PATCH] v2v: Allow large temporary directory to be set on a global + basis. + +Previously we placed large files in g#get_cachedir () (usually +/var/tmp). However the problem is this ties the libguestfs appliance +and the virt-v2v overlay files to the same location. + +When virt-v2v is run in a container, or any other situation where +local storage is limited, it's helpful to be able to put the overlay +files on an externally mounted PVC, which might be using NFS and +shared between containers. But putting the libguestfs appliance on +NFS in a shared location is certainly not recommended. + +This allows the two locations to be set separately: + + VIRT_V2V_TMPDIR - location of large temporary files, can use NFS + and may be shared + + LIBGUESTFS_CACHEDIR - location of libguestfs appliance + +Another motivation for this patch is to allow more reliable cleanup of +large temporary files by an external process, as described in the +updated documentation. + +Small temporary files are placed in $TMPDIR (usually /tmp). I cleaned +up some existing code which used /var/tmp for small temporaries. + +(cherry picked from commit 717b808bc5cb632778973eb000600e87eaf5c31a) +--- + docs/virt-v2v.pod | 27 +++++++++++++++++++-------- + v2v/input_ova.ml | 4 ++-- + v2v/input_vmx.ml | 3 +-- + v2v/output_glance.ml | 3 +-- + v2v/output_null.ml | 3 +-- + v2v/output_rhv_upload.ml | 29 ++++++++++++++++------------- + v2v/parse_ova.ml | 6 ++---- + v2v/python_script.ml | 12 +++--------- + v2v/python_script.mli | 5 +---- + v2v/utils.ml | 6 +++++- + v2v/utils.mli | 5 +++++ + v2v/v2v.ml | 14 ++++++-------- + 12 files changed, 62 insertions(+), 55 deletions(-) + +diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod +index 6f9f323e..af69d633 100644 +--- a/docs/virt-v2v.pod ++++ b/docs/virt-v2v.pod +@@ -1172,8 +1172,8 @@ possible. + =head3 Disk space + + Virt-v2v places potentially large temporary files in +-C<$LIBGUESTFS_CACHEDIR> (which is F if you don't set it). +-Using tmpfs is a bad idea. ++C<$VIRT_V2V_TMPDIR> (usually F, see also ++L below). Using tmpfs is a bad idea. + + For each guest disk, an overlay is stored temporarily. This stores + the changes made during conversion, and is used as a cache. The +@@ -1186,12 +1186,12 @@ and output methods may use disk space, as outlined in the table below. + =item I<-i ova> + + This temporarily places a full copy of the uncompressed source disks +-in C<$LIBGUESTFS_CACHEDIR> (or F). ++in C<$VIRT_V2V_TMPDIR> (or F). + + =item I<-o glance> + + This temporarily places a full copy of the output disks in +-C<$LIBGUESTFS_CACHEDIR> (or F). ++C<$VIRT_V2V_TMPDIR> (or F). + + =item I<-o local> + +@@ -1311,7 +1311,7 @@ have at least 100 available inodes. + =head3 Minimum free space check in the host + + You must have sufficient free space in the host directory used to +-store temporary overlays. To find out ++store large temporary overlays. To find out + which directory this is, use: + + $ df -h "`guestfish get-cachedir`" +@@ -1319,9 +1319,12 @@ which directory this is, use: + /dev/mapper/root 50G 40G 6.8G 86% / + + and look under the C column. Virt-v2v will refuse to do the +-conversion at all unless at least 1GB is available there. ++conversion at all unless at least 1GB is available there. You can ++change the directory that virt-v2v uses by setting ++C<$VIRT_V2V_TMPDIR>. + +-See also L above. ++See also L above and L ++below. + + =head2 Running virt-v2v as root or non-root + +@@ -1496,10 +1499,18 @@ conversion. + + =over 4 + ++=item C ++ + =item C + + Location of the temporary directory used for the potentially large +-temporary overlay file. If not set, F is used. ++temporary overlay file. If neither environment variable is set then ++F is used. ++ ++To reliably ensure large temporary files are cleaned up (for example ++in case virt-v2v crashes) you should create a randomly named directory ++under F, set C to point to this directory, ++then when virt-v2v exits remove the directory. + + See the L section above. + +diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml +index 5d3bece1..d78a5ce8 100644 +--- a/v2v/input_ova.ml ++++ b/v2v/input_ova.ml +@@ -132,8 +132,8 @@ class input_ova ova = object + (* The spec allows the file to be gzip-compressed, in + * which case we must uncompress it into a temporary. + *) +- let temp_dir = (open_guestfs ())#get_cachedir () in +- let new_filename = Filename.temp_file ~temp_dir "ova" ".vmdk" in ++ let new_filename = ++ Filename.temp_file ~temp_dir:Utils.large_tmpdir "ova" ".vmdk" in + unlink_on_exit new_filename; + let cmd = + sprintf "zcat %s > %s" (quote filename) (quote new_filename) in +diff --git a/v2v/input_vmx.ml b/v2v/input_vmx.ml +index f1d143e9..7a7647e5 100644 +--- a/v2v/input_vmx.ml ++++ b/v2v/input_vmx.ml +@@ -389,8 +389,7 @@ and find_nics vmx = + + class input_vmx input_password input_transport arg = + let tmpdir = +- let base_dir = (open_guestfs ())#get_cachedir () in +- let t = Mkdtemp.temp_dir ~base_dir "vmx." in ++ let t = Mkdtemp.temp_dir "vmx." in + rmdir_on_exit t; + t in + object +diff --git a/v2v/output_glance.ml b/v2v/output_glance.ml +index 0a9e9181..e8facd0a 100644 +--- a/v2v/output_glance.ml ++++ b/v2v/output_glance.ml +@@ -33,8 +33,7 @@ class output_glance () = + * to write to a temporary file. XXX + *) + let tmpdir = +- let base_dir = (open_guestfs ())#get_cachedir () in +- let t = Mkdtemp.temp_dir ~base_dir "glance." in ++ let t = Mkdtemp.temp_dir ~base_dir:large_tmpdir "glance." in + rmdir_on_exit t; + t in + object +diff --git a/v2v/output_null.ml b/v2v/output_null.ml +index 3528da50..edb749ea 100644 +--- a/v2v/output_null.ml ++++ b/v2v/output_null.ml +@@ -75,8 +75,7 @@ class output_null = + * the null-co device w/ a JSON URL. + *) + let tmpdir = +- let base_dir = (open_guestfs ())#get_cachedir () in +- let t = Mkdtemp.temp_dir ~base_dir "null." in ++ let t = Mkdtemp.temp_dir ~base_dir:large_tmpdir "null." in + rmdir_on_exit t; + t in + object +diff --git a/v2v/output_rhv_upload.ml b/v2v/output_rhv_upload.ml +index 81896e53..913992d9 100644 +--- a/v2v/output_rhv_upload.ml ++++ b/v2v/output_rhv_upload.ml +@@ -148,25 +148,28 @@ class output_rhv_upload output_alloc output_conn + rhv_options = + (* Create a temporary directory which will be deleted on exit. *) + let tmpdir = +- let base_dir = (open_guestfs ())#get_cachedir () in +- let t = Mkdtemp.temp_dir ~base_dir "rhvupload." in ++ let t = Mkdtemp.temp_dir "rhvupload." in + rmdir_on_exit t; + t in + + let diskid_file_of_id id = tmpdir // sprintf "diskid.%d" id in + + (* Create Python scripts for precheck, vmcheck, plugin and create VM. *) +- let py_create = Python_script.create ~tmpdir in +- let precheck_script = py_create ~name:"rhv-upload-precheck.py" +- Output_rhv_upload_precheck_source.code in +- let vmcheck_script = py_create ~name:"rhv-upload-vmcheck.py" +- Output_rhv_upload_vmcheck_source.code in +- let plugin_script = py_create ~name:"rhv-upload-plugin.py" +- Output_rhv_upload_plugin_source.code in +- let createvm_script = py_create ~name:"rhv-upload-createvm.py" +- Output_rhv_upload_createvm_source.code in +- let deletedisks_script = py_create ~name:"rhv-upload-deletedisks.py" +- Output_rhv_upload_deletedisks_source.code in ++ let precheck_script = ++ Python_script.create ~name:"rhv-upload-precheck.py" ++ Output_rhv_upload_precheck_source.code in ++ let vmcheck_script = ++ Python_script.create ~name:"rhv-upload-vmcheck.py" ++ Output_rhv_upload_vmcheck_source.code in ++ let plugin_script = ++ Python_script.create ~name:"rhv-upload-plugin.py" ++ Output_rhv_upload_plugin_source.code in ++ let createvm_script = ++ Python_script.create ~name:"rhv-upload-createvm.py" ++ Output_rhv_upload_createvm_source.code in ++ let deletedisks_script = ++ Python_script.create ~name:"rhv-upload-deletedisks.py" ++ Output_rhv_upload_deletedisks_source.code in + + (* JSON parameters which are invariant between disks. *) + let json_params = [ +diff --git a/v2v/parse_ova.ml b/v2v/parse_ova.ml +index 0b939ac4..568ac5fa 100644 +--- a/v2v/parse_ova.ml ++++ b/v2v/parse_ova.ml +@@ -71,8 +71,7 @@ let rec parse_ova ova = + if is_directory ova then ova, Directory + else ( + let tmpdir = +- let base_dir = (open_guestfs ())#get_cachedir () in +- let t = Mkdtemp.temp_dir ~base_dir "ova." in ++ let t = Mkdtemp.temp_dir ~base_dir:large_tmpdir "ova." in + rmdir_on_exit t; + t in + +@@ -221,8 +220,7 @@ and uncompress_head format file = + *) + and uncompressed_type format file = + let head, headlen = uncompress_head format file in +- let tmpfile, chan = +- Filename.open_temp_file "ova.file." "" in ++ let tmpfile, chan = Filename.open_temp_file "ova.file." "" in + output chan head 0 headlen; + close_out chan; + let ret = detect_file_type tmpfile in +diff --git a/v2v/python_script.ml b/v2v/python_script.ml +index b1ea8f9d..212c8e1b 100644 +--- a/v2v/python_script.ml ++++ b/v2v/python_script.ml +@@ -31,15 +31,9 @@ type script = { + path : string; (* Path to script. *) + } + +-let create ?(name = "script.py") ?tmpdir code = +- let tmpdir = +- match tmpdir with +- | None -> +- let base_dir = (open_guestfs ())#get_cachedir () in +- let t = Mkdtemp.temp_dir ~base_dir "v2v." in +- rmdir_on_exit t; +- t +- | Some dir -> dir in ++let create ?(name = "script.py") code = ++ let tmpdir = Mkdtemp.temp_dir "v2v." in ++ rmdir_on_exit tmpdir; + let path = tmpdir // name in + with_open_out path (fun chan -> output_string chan code); + { tmpdir; path } +diff --git a/v2v/python_script.mli b/v2v/python_script.mli +index 6bf77e34..fdf73514 100644 +--- a/v2v/python_script.mli ++++ b/v2v/python_script.mli +@@ -20,14 +20,11 @@ + + type script + +-val create : ?name:string -> ?tmpdir:string -> string -> script ++val create : ?name:string -> string -> script + (** Create a Python script object. + + The optional parameter [?name] is a hint for the name of the script. + +- The optional parameter [?tmpdir] is the temporary directory to use +- (instead of creating a new one). +- + The parameter is the Python code. Usually this is + [Some_source.code] where [some_source.ml] is generated from + the Python file by [v2v/embed.sh] (see also [v2v/Makefile.am]). *) +diff --git a/v2v/utils.ml b/v2v/utils.ml +index c2940582..a6c359f0 100644 +--- a/v2v/utils.ml ++++ b/v2v/utils.ml +@@ -24,6 +24,10 @@ open Std_utils + open Tools_utils + open Common_gettext.Gettext + ++let large_tmpdir = ++ try Sys.getenv "VIRT_V2V_TMPDIR" ++ with Not_found -> (open_guestfs ())#get_cachedir () ++ + (* Is SELinux enabled and enforcing on the host? *) + let have_selinux = + 0 = Sys.command "getenforce 2>/dev/null | grep -isq Enforcing" +@@ -114,6 +118,7 @@ let qemu_img_supports_offset_and_size () = + * file that has an offset and size. + *) + let tmp = Filename.temp_file "v2vqemuimgtst" ".img" in ++ unlink_on_exit tmp; + Unix.truncate tmp 1024; + + let json = [ +@@ -133,7 +138,6 @@ let qemu_img_supports_offset_and_size () = + (if verbose () then "" else " 2>&1") in + debug "%s" cmd; + let r = 0 = Sys.command cmd in +- Unix.unlink tmp; + debug "qemu-img supports \"offset\" and \"size\" in json URLs: %b" r; + r + +diff --git a/v2v/utils.mli b/v2v/utils.mli +index 937e2b9b..d86ca507 100644 +--- a/v2v/utils.mli ++++ b/v2v/utils.mli +@@ -18,6 +18,11 @@ + + (** Utilities used in virt-v2v only. *) + ++val large_tmpdir : string ++(** [VIRT_V2V_TMPDIR] or [/var/tmp]. Create all large temporary files ++ such as overlays in this directory. Small temporary files can ++ use the default behaviour eg. of {!Filename.temp_file} *) ++ + val have_selinux : bool + (** True if SELinux is enabled and enforcing on the host. *) + +diff --git a/v2v/v2v.ml b/v2v/v2v.ml +index 73edff2c..a58ff433 100644 +--- a/v2v/v2v.ml ++++ b/v2v/v2v.ml +@@ -264,8 +264,6 @@ and set_source_networks_and_bridges cmdline source = + let nics = List.map (Networks.map cmdline.network_map) source.s_nics in + { source with s_nics = nics } + +-and overlay_dir = (open_guestfs ())#get_cachedir () +- + (* Conversion can fail or hang if there is insufficient free space in + * the temporary directory used to store overlays on the host + * (RHBZ#1316479). Although only a few hundred MB is actually +@@ -273,12 +271,12 @@ and overlay_dir = (open_guestfs ())#get_cachedir () + * guestfs appliance which is also stored here. + *) + and check_host_free_space () = +- let free_space = StatVFS.free_space (StatVFS.statvfs overlay_dir) in +- debug "check_host_free_space: overlay_dir=%s free_space=%Ld" +- overlay_dir free_space; ++ let free_space = StatVFS.free_space (StatVFS.statvfs large_tmpdir) in ++ debug "check_host_free_space: large_tmpdir=%s free_space=%Ld" ++ large_tmpdir free_space; + if free_space < 1_073_741_824L then + error (f_"insufficient free space in the conversion server temporary directory %s (%s).\n\nEither free up space in that directory, or set the LIBGUESTFS_CACHEDIR environment variable to point to another directory with more than 1GB of free space.\n\nSee also the virt-v2v(1) manual, section \"Minimum free space check in the host\".") +- overlay_dir (human_size free_space) ++ large_tmpdir (human_size free_space) + + (* Create a qcow2 v3 overlay to protect the source image(s). *) + and create_overlays source_disks = +@@ -286,7 +284,7 @@ and create_overlays source_disks = + List.mapi ( + fun i ({ s_qemu_uri = qemu_uri; s_format = format } as source) -> + let overlay_file = +- Filename.temp_file ~temp_dir:overlay_dir "v2vovl" ".qcow2" in ++ Filename.temp_file ~temp_dir:large_tmpdir "v2vovl" ".qcow2" in + unlink_on_exit overlay_file; + + (* There is a specific reason to use the newer qcow2 variant: +@@ -823,7 +821,7 @@ and preserve_overlays overlays src_name = + List.iter ( + fun ov -> + let saved_filename = +- sprintf "%s/%s-%s.qcow2" overlay_dir src_name ov.ov_sd in ++ sprintf "%s/%s-%s.qcow2" large_tmpdir src_name ov.ov_sd in + rename ov.ov_overlay_file saved_filename; + info (f_"Overlay saved as %s [--debug-overlays]") saved_filename + ) overlays +-- +2.31.1 + diff --git a/0025-input-xen-replace-enable-LEGACY-crypto-advice-with-t.patch b/0025-input-xen-replace-enable-LEGACY-crypto-advice-with-t.patch new file mode 100644 index 0000000..351b1f1 --- /dev/null +++ b/0025-input-xen-replace-enable-LEGACY-crypto-advice-with-t.patch @@ -0,0 +1,82 @@ +From 3f7f730ac9cbf38267839ffcebd6b6fd721123c5 Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Mon, 11 Jul 2022 09:01:57 +0200 +Subject: [PATCH] input-xen: replace "enable LEGACY crypto" advice with + targeted ssh options + +- "KexAlgorithms": the Fedora 35 ssh binary, using the DEFAULT + crypto-policy, cannot log in to RHEL5 sshd without relaxing + "KexAlgorithms". The server offers three algorithms: + "diffie-hellman-group-exchange-sha1", "diffie-hellman-group14-sha1", + "diffie-hellman-group1-sha1"; and according to RFC 9142, + "diffie-hellman-group14-sha1" is the least deprecated from those. (The + RFC marks it as MAY be implemented, and marks the other two as SHOULD + NOT be implemented.) Recommend "diffie-hellman-group14-sha1". + +- "MACs": the Fedora 35 ssh binary, using the FUTURE crypto-policy, cannot + log in to RHEL5 sshd without relaxing "MACs". The server offers + "hmac-md5", "hmac-sha1", "hmac-ripemd160", "hmac-ripemd160@openssh.com", + "hmac-sha1-96", "hmac-md5-96". After eliminating the MD5-based algos + (MD5 is considered completely broken), and the one based on truncated + SHA1, we're left with "hmac-sha1", "hmac-ripemd160", and + "hmac-ripemd160@openssh.com". RIPEMD-160 is generally trusted, but it is + compiled out of the Fedora 35 "ssh" client binary. Therefore only + "hmac-sha1" remains. + +- "HostKeyAlgorithms", "PubkeyAcceptedAlgorithms": these options control + the usage of public key algorithms, for authenticating the server to the + client, and vice versa, respectively. RHEL5 sshd only supports "ssh-rsa" + and "ssh-dss", and from those, "ssh-rsa" is more commonly used (for + example, "ssh-keygen" defaults to creating "ssh-rsa" keys). Recommend + "ssh-rsa". + +- "PubkeyAcceptedKeyTypes": this is the old ("legacy") name for + "PubkeyAcceptedAlgorithms". As of this writing, the latest upstream + release of libssh (also packaged in Fedora 35 -- libssh-0.9.6-1.fc35) + does not recognize the new "PubkeyAcceptedAlgorithms" option name, only + the original "PubkeyAcceptedKeyTypes". openssh-8.7p1-3.fc35 recognizes + both option variants. Include "PubkeyAcceptedKeyTypes" in the + recommendation along with "PubkeyAcceptedAlgorithms", for backward and + forward compatbility. + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2062360 +Signed-off-by: Laszlo Ersek +Message-Id: <20220711070157.5399-3-lersek@redhat.com> +Reviewed-by: Richard W.M. Jones +(cherry picked from commit af4a0454cdd21bb5e86f2dbfaa153e83afca3988) +--- + docs/virt-v2v-input-xen.pod | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +diff --git a/docs/virt-v2v-input-xen.pod b/docs/virt-v2v-input-xen.pod +index 80ad94f7..1775fc31 100644 +--- a/docs/virt-v2v-input-xen.pod ++++ b/docs/virt-v2v-input-xen.pod +@@ -37,12 +37,22 @@ option is incomplete. Some operations remain that still require the + user to enter the password manually. Therefore ssh-agent is recommended + over the I<-ip> option. See L. + +-With some modern ssh implementations, legacy crypto policies required +-to interoperate with RHEL 5 sshd are disabled. To enable them you may +-need to run this command on the conversion server (ie. ssh client), +-but read L first: ++With some modern ssh implementations, legacy crypto algorithms required ++to interoperate with RHEL 5 sshd are disabled. To enable them, you may ++need to add the following C stanza to your F<~/.ssh/config>: + +- # update-crypto-policies --set LEGACY ++ Host xen.example.com ++ KexAlgorithms +diffie-hellman-group14-sha1 ++ MACs +hmac-sha1 ++ HostKeyAlgorithms +ssh-rsa ++ PubkeyAcceptedKeyTypes +ssh-rsa ++ PubkeyAcceptedAlgorithms +ssh-rsa ++ ++(C and C have ++identical meaning; the former is the old option name, the latter is the ++new one. Virt-v2v uses both C and C when converting a guest ++from Xen, and on some operating systems, C and C may not ++both accept the same option variant.) + + =head2 Test libvirt connection to remote Xen host + diff --git a/0025-v2v-o-openstack-Allow-guests-to-be-converted-to-UEFI.patch b/0025-v2v-o-openstack-Allow-guests-to-be-converted-to-UEFI.patch new file mode 100644 index 0000000..70c0b6c --- /dev/null +++ b/0025-v2v-o-openstack-Allow-guests-to-be-converted-to-UEFI.patch @@ -0,0 +1,34 @@ +From 82d56820db4f05711b125daf46a4777e99dbdf87 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 25 Aug 2020 08:23:52 +0100 +Subject: [PATCH] v2v: -o openstack: Allow guests to be converted to UEFI + (RHBZ#1872094). + +Since this output method was written the code has always been capable +of adding the hw_firmware_type = uefi image property, and this +property has been supported since at least OpenStack 12 which is years +old. + +Interestingly now all of the output modes support both BIOS and UEFI. + +(cherry picked from commit 5fa65a13fbbaab03cb558d0c776c17227433f1b3) +--- + v2v/output_openstack.ml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/v2v/output_openstack.ml b/v2v/output_openstack.ml +index 179b0edf..fdc04b02 100644 +--- a/v2v/output_openstack.ml ++++ b/v2v/output_openstack.ml +@@ -390,7 +390,7 @@ object + | None -> "" + | Some op -> " -op " ^ op) + +- method supported_firmware = [ TargetBIOS ] ++ method supported_firmware = [ TargetBIOS; TargetUEFI ] + + (* List of Cinder volume IDs. *) + val mutable volume_ids = [] +-- +2.31.1 + diff --git a/0026-common-Adapt-to-renamed-function-On_exit.rmdir-On_ex.patch b/0026-common-Adapt-to-renamed-function-On_exit.rmdir-On_ex.patch new file mode 100644 index 0000000..806e3da --- /dev/null +++ b/0026-common-Adapt-to-renamed-function-On_exit.rmdir-On_ex.patch @@ -0,0 +1,172 @@ +From ea881513e9c15b0a816d3ba4afe471ff2f591a03 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 14 Jul 2022 12:44:27 +0100 +Subject: [PATCH] common: Adapt to renamed function On_exit.rmdir -> + On_exit.rm_rf + +This function was renamed to make it clearer what it does (and that +it's potentially dangerous). The functionality is unchanged. + +Reviewed-by: Laszlo Ersek +(cherry picked from commit 2eb6441264deb0411d36dabaf8fb2da9f07c8439) +--- + common | 2 +- + input/OVA.ml | 2 +- + input/parse_domain_from_vmx.ml | 2 +- + lib/nbdkit.ml | 2 +- + lib/qemuNBD.ml | 2 +- + lib/utils.ml | 2 +- + output/python_script.ml | 2 +- + 7 files changed, 7 insertions(+), 7 deletions(-) + +Submodule common af6cb55b..fd964c1b: +diff --git a/common/mlcustomize/guest_packages.ml b/common/mlcustomize/guest_packages.ml +index 4c3c34ed..7c29a2ab 100644 +--- a/common/mlcustomize/guest_packages.ml ++++ b/common/mlcustomize/guest_packages.ml +@@ -73,9 +73,9 @@ let install_command packages package_management = + | "zypper" -> sprintf "zypper -n in -l %s" quoted_args + + | "unknown" -> +- error_unknown_package_manager (s_"--install") ++ error_unknown_package_manager "--install" + | pm -> +- error_unimplemented_package_manager (s_"--install") pm ++ error_unimplemented_package_manager "--install" pm + + let update_command package_management = + match package_management with +@@ -103,9 +103,9 @@ let update_command package_management = + | "zypper" -> "zypper -n update -l" + + | "unknown" -> +- error_unknown_package_manager (s_"--update") ++ error_unknown_package_manager "--update" + | pm -> +- error_unimplemented_package_manager (s_"--update") pm ++ error_unimplemented_package_manager "--update" pm + + let uninstall_command packages package_management = + let quoted_args = String.concat " " (List.map quote packages) in +@@ -127,6 +127,6 @@ let uninstall_command packages package_management = + | "zypper" -> sprintf "zypper -n rm %s" quoted_args + + | "unknown" -> +- error_unknown_package_manager (s_"--uninstall") ++ error_unknown_package_manager "--uninstall" + | pm -> +- error_unimplemented_package_manager (s_"--uninstall") pm ++ error_unimplemented_package_manager "--uninstall" pm +diff --git a/common/mltools/on_exit.ml b/common/mltools/on_exit.ml +index 53ccb68a..cae12e73 100644 +--- a/common/mltools/on_exit.ml ++++ b/common/mltools/on_exit.ml +@@ -52,7 +52,7 @@ let do_actions () = + List.iter (do_action (fun file -> Unix.unlink file)) !files; + List.iter (do_action ( + fun dir -> +- let cmd = sprintf "rm -rf %s" (Filename.quote dir) in ++ let cmd = sprintf "rm -rf -- %s" (Filename.quote dir) in + ignore (Tools_utils.shell_command cmd) + ) + ) !rmdirs; +@@ -102,7 +102,7 @@ let unlink filename = + register (); + List.push_front filename files + +-let rmdir dir = ++let rm_rf dir = + register (); + List.push_front dir rmdirs + +diff --git a/common/mltools/on_exit.mli b/common/mltools/on_exit.mli +index a02e3db3..9bcf104f 100644 +--- a/common/mltools/on_exit.mli ++++ b/common/mltools/on_exit.mli +@@ -47,7 +47,7 @@ val f : (unit -> unit) -> unit + val unlink : string -> unit + (** Unlink a single temporary file on exit. *) + +-val rmdir : string -> unit ++val rm_rf : string -> unit + (** Recursively remove a temporary directory on exit (using [rm -rf]). *) + + val kill : ?signal:int -> int -> unit +diff --git a/input/OVA.ml b/input/OVA.ml +index 9e9c3712..09ceee98 100644 +--- a/input/OVA.ml ++++ b/input/OVA.ml +@@ -78,7 +78,7 @@ let rec parse_ova ova = + else ( + let tmpdir = + let t = Mkdtemp.temp_dir ~base_dir:large_tmpdir "ova." in +- On_exit.rmdir t; ++ On_exit.rm_rf t; + t in + + match detect_file_type ova with +diff --git a/input/parse_domain_from_vmx.ml b/input/parse_domain_from_vmx.ml +index 947ca414..7aca2c24 100644 +--- a/input/parse_domain_from_vmx.ml ++++ b/input/parse_domain_from_vmx.ml +@@ -375,7 +375,7 @@ and find_nics vmx = + let parse_domain_from_vmx vmx_source = + let tmpdir = + let t = Mkdtemp.temp_dir "vmx." in +- On_exit.rmdir t; ++ On_exit.rm_rf t; + t in + + (* If the transport is SSH, fetch the file from remote, else +diff --git a/lib/nbdkit.ml b/lib/nbdkit.ml +index 07896684..1137b6bb 100644 +--- a/lib/nbdkit.ml ++++ b/lib/nbdkit.ml +@@ -105,7 +105,7 @@ let add_filter_if_available cmd filter = + let run_unix socket cmd = + (* Create a temporary directory where we place the PID file. *) + let piddir = Mkdtemp.temp_dir "v2vnbdkit." in +- On_exit.rmdir piddir; ++ On_exit.rm_rf piddir; + + let id = unique () in + let pidfile = piddir // sprintf "nbdkit%d.pid" id in +diff --git a/lib/qemuNBD.ml b/lib/qemuNBD.ml +index bbb65f41..c3dd1666 100644 +--- a/lib/qemuNBD.ml ++++ b/lib/qemuNBD.ml +@@ -69,7 +69,7 @@ let run_unix socket { disk; snapshot; format; imgopts } = + + (* Create a temporary directory where we place the PID file. *) + let piddir = Mkdtemp.temp_dir "v2vqemunbd." in +- On_exit.rmdir piddir; ++ On_exit.rm_rf piddir; + + let id = unique () in + let pidfile = piddir // sprintf "qemunbd%d.pid" id in +diff --git a/lib/utils.ml b/lib/utils.ml +index 7116a4f9..84b9a93f 100644 +--- a/lib/utils.ml ++++ b/lib/utils.ml +@@ -204,7 +204,7 @@ let error_if_no_ssh_agent () = + let create_v2v_directory () = + let d = Mkdtemp.temp_dir "v2v." in + chown_for_libvirt_rhbz_1045069 d; +- On_exit.rmdir d; ++ On_exit.rm_rf d; + d + + (* Wait for a file to appear until a timeout. *) +diff --git a/output/python_script.ml b/output/python_script.ml +index 54ccd1b5..ecf46c2d 100644 +--- a/output/python_script.ml ++++ b/output/python_script.ml +@@ -33,7 +33,7 @@ type script = { + + let create ?(name = "script.py") code = + let tmpdir = Mkdtemp.temp_dir "v2v." in +- On_exit.rmdir tmpdir; ++ On_exit.rm_rf tmpdir; + let path = tmpdir // name in + with_open_out path (fun chan -> output_string chan code); + { tmpdir; path } diff --git a/0026-v2v-Fix-spelling-mistake-in-uninstall-function-name.patch b/0026-v2v-Fix-spelling-mistake-in-uninstall-function-name.patch new file mode 100644 index 0000000..6005d5a --- /dev/null +++ b/0026-v2v-Fix-spelling-mistake-in-uninstall-function-name.patch @@ -0,0 +1,44 @@ +From 358122c089d1e4df014a6821365341d3220ab6e6 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 19 Jan 2021 11:26:23 +0000 +Subject: [PATCH] v2v: Fix spelling mistake in uninstall function name. + +Fixes: commit 53847717fa1d0ffc2a174275badf486eb1ed6fae +(cherry picked from commit 3515c9f617271bec89962ba8a2b8c690e6df4c99) +--- + v2v/convert_windows.ml | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml +index ba26949f..f2f7b95c 100644 +--- a/v2v/convert_windows.ml ++++ b/v2v/convert_windows.ml +@@ -135,7 +135,7 @@ let convert (g : G.guestfs) inspect _ output rcaps static_ips = + (* Locate and retrieve all the uninstallation commands for installed + * applications. + *) +- let unistallation_commands pretty_name matchfn extra_uninstall_string = ++ let uninstallation_commands pretty_name matchfn extra_uninstall_string = + let uninsts = ref [] in + + Registry.with_hive_readonly g inspect.i_windows_software_hive +@@ -198,14 +198,14 @@ let convert (g : G.guestfs) inspect _ output rcaps static_ips = + *) + let extra_uninstall_string = + Some "PREVENT_REBOOT=Yes LAUNCHED_BY_SETUP_EXE=Yes" in +- unistallation_commands "Parallels Tools" matchfn extra_uninstall_string in ++ uninstallation_commands "Parallels Tools" matchfn extra_uninstall_string in + + (* Locate and retrieve all uninstallation commands for VMware Tools. *) + let vmwaretools_uninst = + let matchfn s = + String.find s "VMware Tools" != -1 + in +- unistallation_commands "VMware Tools" matchfn None in ++ uninstallation_commands "VMware Tools" matchfn None in + + (*----------------------------------------------------------------------*) + (* Perform the conversion of the Windows guest. *) +-- +2.31.1 + diff --git a/0027-o-rhv-Unmount-the-temporary-NFS-mountpoint-as-late-a.patch b/0027-o-rhv-Unmount-the-temporary-NFS-mountpoint-as-late-a.patch new file mode 100644 index 0000000..050e4d9 --- /dev/null +++ b/0027-o-rhv-Unmount-the-temporary-NFS-mountpoint-as-late-a.patch @@ -0,0 +1,171 @@ +From 0d92a42aab3fb0e7569294675666976724156128 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 14 Jul 2022 13:15:49 +0100 +Subject: [PATCH] -o rhv: Unmount the temporary NFS mountpoint as late as + possible + +To partially avoid a potential race against nbdkit or qemu-nbd +releasing files on the mountpoint before they exit, unmount as late as +we can. + +See also https://bugzilla.redhat.com/show_bug.cgi?id=1953286#c26 + +Reviewed-by: Laszlo Ersek +(cherry picked from commit e96357fc3b26aaf96eaa21afa36c894a27af6261) +--- + common | 2 +- + output/output_rhv.ml | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +Submodule common fd964c1b..1000604f: +diff --git a/common/mltools/on_exit.ml b/common/mltools/on_exit.ml +index cae12e73..f8ef74e1 100644 +--- a/common/mltools/on_exit.ml ++++ b/common/mltools/on_exit.ml +@@ -23,39 +23,39 @@ open Common_gettext.Gettext + open Unix + open Printf + +-(* List of files to unlink. *) +-let files = ref [] ++type action = ++ | Unlink of string (* filename *) ++ | Rm_rf of string (* directory *) ++ | Kill of int * int (* signal, pid *) ++ | Fn of (unit -> unit) (* generic function *) + +-(* List of directories to remove. *) +-let rmdirs = ref [] +- +-(* List of PIDs to kill. *) +-let kills = ref [] +- +-(* List of functions to call. *) +-let fns = ref [] ++(* List of (priority, action). *) ++let actions = ref [] + + (* Perform a single exit action, printing any exception but + * otherwise ignoring failures. + *) +-let do_action f arg = +- try f arg with exn -> debug "%s" (Printexc.to_string exn) ++let do_action action = ++ try ++ match action with ++ | Unlink file -> Unix.unlink file ++ | Rm_rf dir -> ++ let cmd = sprintf "rm -rf -- %s" (Filename.quote dir) in ++ ignore (Tools_utils.shell_command cmd) ++ | Kill (signal, pid) -> ++ kill pid signal ++ | Fn f -> f () ++ with exn -> debug "%s" (Printexc.to_string exn) + + (* Make sure the actions are performed only once. *) + let done_actions = ref false + +-(* Perform the exit actions. *) ++(* Perform the exit actions in priority order (lowest prio first). *) + let do_actions () = + if not !done_actions then ( +- List.iter (do_action (fun f -> f ())) !fns; +- List.iter (do_action (fun (signal, pid) -> kill pid signal)) !kills; +- List.iter (do_action (fun file -> Unix.unlink file)) !files; +- List.iter (do_action ( +- fun dir -> +- let cmd = sprintf "rm -rf -- %s" (Filename.quote dir) in +- ignore (Tools_utils.shell_command cmd) +- ) +- ) !rmdirs; ++ let actions = List.sort (fun (a, _) (b, _) -> compare a b) !actions in ++ let actions = List.map snd actions in ++ List.iter do_action actions + ); + done_actions := true + +@@ -94,18 +94,18 @@ let register () = + ); + registered := true + +-let f fn = ++let f ?(prio = 5000) fn = + register (); +- List.push_front fn fns ++ List.push_front (prio, Fn fn) actions + +-let unlink filename = ++let unlink ?(prio = 5000) filename = + register (); +- List.push_front filename files ++ List.push_front (prio, Unlink filename) actions + +-let rm_rf dir = ++let rm_rf ?(prio = 5000) dir = + register (); +- List.push_front dir rmdirs ++ List.push_front (prio, Rm_rf dir) actions + +-let kill ?(signal = Sys.sigterm) pid = ++let kill ?(prio = 5000) ?(signal = Sys.sigterm) pid = + register (); +- List.push_front (signal, pid) kills ++ List.push_front (prio, Kill (signal, pid)) actions +diff --git a/common/mltools/on_exit.mli b/common/mltools/on_exit.mli +index 9bcf104f..66a85542 100644 +--- a/common/mltools/on_exit.mli ++++ b/common/mltools/on_exit.mli +@@ -28,6 +28,12 @@ + killing another process, so we provide simple + wrappers for those common actions here. + ++ Actions can be ordered by setting the optional [?prio] ++ parameter in the range 0..9999. By default actions ++ have priority 5000. Lower numbered actions run first. ++ Higher numbered actions run last. So to have an action ++ run at the very end before exit you might use [~prio:9999] ++ + Note this module registers signal handlers for + SIGINT, SIGQUIT, SIGTERM and SIGHUP. This means + that any program that links with mltools.cmxa +@@ -39,18 +45,20 @@ + Your cleanup action might no longer run unless the + program calls {!Stdlib.exit}. *) + +-val f : (unit -> unit) -> unit ++val f : ?prio:int -> (unit -> unit) -> unit + (** Register a function [f] which runs when the program exits. + Similar to [Stdlib.at_exit] but also runs if the program is +- killed with a signal that we can catch. *) ++ killed with a signal that we can catch. ++ ++ [?prio] is the priority, default 5000. See the description above. *) + +-val unlink : string -> unit ++val unlink : ?prio:int -> string -> unit + (** Unlink a single temporary file on exit. *) + +-val rm_rf : string -> unit ++val rm_rf : ?prio:int -> string -> unit + (** Recursively remove a temporary directory on exit (using [rm -rf]). *) + +-val kill : ?signal:int -> int -> unit ++val kill : ?prio:int -> ?signal:int -> int -> unit + (** Kill [PID] on exit. The signal sent defaults to [Sys.sigterm]. + + Use this with care since you can end up unintentionally killing +diff --git a/output/output_rhv.ml b/output/output_rhv.ml +index 8571e07b..15a2c14a 100644 +--- a/output/output_rhv.ml ++++ b/output/output_rhv.ml +@@ -204,8 +204,8 @@ module RHV = struct + if run_command cmd <> 0 then + error (f_"mount command failed, see earlier errors.\n\nThis probably means you didn't specify the right %s path [-os %s], or else you need to rerun virt-v2v as root.") domain_class os; + +- (* Make sure it is unmounted at exit. *) +- On_exit.f ( ++ (* Make sure it is unmounted at exit, as late as possible (prio=9999) *) ++ On_exit.f ~prio:9999 ( + fun () -> + let cmd = [ "umount"; mp ] in + ignore (run_command cmd); diff --git a/0027-v2v-windows-Refactor-uninstallation_commands-functio.patch b/0027-v2v-windows-Refactor-uninstallation_commands-functio.patch new file mode 100644 index 0000000..43b9fb7 --- /dev/null +++ b/0027-v2v-windows-Refactor-uninstallation_commands-functio.patch @@ -0,0 +1,137 @@ +From 9c81b523857e057b8361cbbcc4647ed02b572ca0 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 19 Jan 2021 11:38:46 +0000 +Subject: [PATCH] v2v: windows: Refactor uninstallation_commands function. + +Simplify and shorten this function: + + - Remove unnecessary use of Not_found exception and generally + simplify flow control. + + - Use sprintf. + +This shouldn't change what the function does. + +(cherry picked from commit d48530209a79725f26d6e25101bed6f228f45e8d) +--- + v2v/convert_windows.ml | 89 ++++++++++++++++++------------------------ + 1 file changed, 37 insertions(+), 52 deletions(-) + +diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml +index f2f7b95c..84db742f 100644 +--- a/v2v/convert_windows.ml ++++ b/v2v/convert_windows.ml +@@ -135,56 +135,41 @@ let convert (g : G.guestfs) inspect _ output rcaps static_ips = + (* Locate and retrieve all the uninstallation commands for installed + * applications. + *) +- let uninstallation_commands pretty_name matchfn extra_uninstall_string = +- let uninsts = ref [] in ++ let uninstallation_commands pretty_name matchfn extra_uninstall_params = ++ let path = ["Microsoft"; "Windows"; "CurrentVersion"; "Uninstall"] in ++ let uninstval = "UninstallString" in ++ let ret = ref [] in + +- Registry.with_hive_readonly g inspect.i_windows_software_hive +- (fun reg -> +- try +- let path = ["Microsoft"; "Windows"; "CurrentVersion"; "Uninstall"] in +- let node = +- match Registry.get_node reg path with +- | None -> raise Not_found +- | Some node -> node in +- let uninstnodes = g#hivex_node_children node in +- +- Array.iter ( +- fun { G.hivex_node_h = uninstnode } -> +- try ++ Registry.with_hive_readonly g inspect.i_windows_software_hive ( ++ fun reg -> ++ match Registry.get_node reg path with ++ | None -> () ++ | Some node -> ++ let uninstnodes = g#hivex_node_children node in ++ Array.iter ( ++ fun { G.hivex_node_h = uninstnode } -> + let valueh = g#hivex_node_get_value uninstnode "DisplayName" in +- if valueh = 0L then +- raise Not_found; +- +- let dispname = g#hivex_value_string valueh in +- if not (matchfn dispname) then +- raise Not_found; +- +- let uninstval = "UninstallString" in +- let valueh = g#hivex_node_get_value uninstnode uninstval in +- if valueh = 0L then ( +- let name = g#hivex_node_name uninstnode in +- warning (f_"cannot uninstall %s: registry key ‘HKLM\\SOFTWARE\\%s\\%s’ with DisplayName ‘%s’ doesn't contain value ‘%s’") +- pretty_name (String.concat "\\" path) name dispname uninstval; +- raise Not_found +- ); +- +- let uninst = (g#hivex_value_string valueh) ^ +- " /quiet /norestart /l*v+ \"%~dpn0.log\"" ^ +- " REBOOT=ReallySuppress REMOVE=ALL" in +- let uninst = +- match extra_uninstall_string with +- | None -> uninst +- | Some s -> uninst ^ " " ^ s in +- +- List.push_front uninst uninsts +- with +- Not_found -> () +- ) uninstnodes +- with +- Not_found -> () +- ); +- +- !uninsts ++ if valueh <> 0L then ( ++ let dispname = g#hivex_value_string valueh in ++ if matchfn dispname then ( ++ let valueh = g#hivex_node_get_value uninstnode uninstval in ++ if valueh <> 0L then ( ++ let reg_cmd = g#hivex_value_string valueh in ++ let cmd = ++ sprintf "%s /quiet /norestart /l*v+ \"%%~dpn0.log\" REBOOT=ReallySuppress REMOVE=ALL %s" ++ reg_cmd extra_uninstall_params in ++ List.push_front cmd ret ++ ) ++ else ++ let name = g#hivex_node_name uninstnode in ++ warning (f_"cannot uninstall %s: registry key ‘HKLM\\SOFTWARE\\%s\\%s’ with DisplayName ‘%s’ doesn't contain value ‘%s’") ++ pretty_name (String.concat "\\" path) name ++ dispname uninstval ++ ) ++ ) ++ ) uninstnodes ++ ) (* with_hive_readonly *); ++ !ret + in + + (* Locate and retrieve all uninstallation commands for Parallels Tools. *) +@@ -196,16 +181,16 @@ let convert (g : G.guestfs) inspect _ output rcaps static_ips = + (* Without these custom Parallels-specific MSI properties the + * uninstaller still shows a no-way-out reboot dialog. + *) +- let extra_uninstall_string = +- Some "PREVENT_REBOOT=Yes LAUNCHED_BY_SETUP_EXE=Yes" in +- uninstallation_commands "Parallels Tools" matchfn extra_uninstall_string in ++ let extra_uninstall_params = ++ "PREVENT_REBOOT=Yes LAUNCHED_BY_SETUP_EXE=Yes" in ++ uninstallation_commands "Parallels Tools" matchfn extra_uninstall_params in + + (* Locate and retrieve all uninstallation commands for VMware Tools. *) + let vmwaretools_uninst = + let matchfn s = + String.find s "VMware Tools" != -1 + in +- uninstallation_commands "VMware Tools" matchfn None in ++ uninstallation_commands "VMware Tools" matchfn "" in + + (*----------------------------------------------------------------------*) + (* Perform the conversion of the Windows guest. *) +-- +2.31.1 + diff --git a/0028-output-Permit-output-modes-to-wait-on-the-local-NBD-.patch b/0028-output-Permit-output-modes-to-wait-on-the-local-NBD-.patch new file mode 100644 index 0000000..4a02e5e --- /dev/null +++ b/0028-output-Permit-output-modes-to-wait-on-the-local-NBD-.patch @@ -0,0 +1,179 @@ +From 96efdcf54c887ae88d54332df12a5f5dd962fd0a Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 15 Jul 2022 11:25:45 +0100 +Subject: [PATCH] output: Permit output modes to wait on the local NBD server + +Output.output_to_local_file is used by several output modes that write +to local files or devices. It launches an instance of qemu-nbd or +nbdkit connected to the local file. + +Previously we unconditionally added an On_exit handler to kill the NBD +server. This is usually safe because nbdcopy --flush has guaranteed +that the data was written through to permanent storage, and so killing +the NBD server is just there to prevent orphaned processes. + +However for output to RHV (-o rhv) we actually need the NBD server to +be cleaned up before we exit. See the analysis here: + +https://bugzilla.redhat.com/show_bug.cgi?id=1953286#c26 + +Allow an alternate strategy of waiting for the NBD server to exit +during virt-v2v shutdown. + +We only need this in virt-v2v so implement it here instead of pushing +it all the way into the On_exit module. + +Reviewed-by: Laszlo Ersek +(cherry picked from commit e2a1a7b4dfb6a9e44260da10a7e7029c09753b5c) +--- + output/output.ml | 91 ++++++++++++++++++++++++++++------------------- + output/output.mli | 17 +++++++-- + 2 files changed, 69 insertions(+), 39 deletions(-) + +diff --git a/output/output.ml b/output/output.ml +index 496c32b6..8f83a324 100644 +--- a/output/output.ml ++++ b/output/output.ml +@@ -69,7 +69,10 @@ let error_if_disk_count_gt dir n = + if Sys.file_exists socket then + error (f_"this output module doesn't support copying more than %d disks") n + ++type on_exit_kill = Kill | KillAndWait ++ + let output_to_local_file ?(changeuid = fun f -> f ()) ?(compressed = false) ++ ?(on_exit_kill = Kill) + output_alloc output_format filename size socket = + (* Check nbdkit is installed and has the required plugin. *) + if not (Nbdkit.is_installed ()) then +@@ -94,46 +97,60 @@ let output_to_local_file ?(changeuid = fun f -> f ()) ?(compressed = false) + fun () -> g#disk_create ?preallocation filename output_format size + ); + +- match output_format with +- | "raw" -> +- let cmd = Nbdkit.create "file" in +- Nbdkit.add_arg cmd "file" filename; +- if Nbdkit.version nbdkit_config >= (1, 22, 0) then ( +- let cmd = Nbdkit.add_arg cmd "cache" "none" in +- cmd +- ); +- let _, pid = Nbdkit.run_unix socket cmd in ++ let pid = ++ match output_format with ++ | "raw" -> ++ let cmd = Nbdkit.create "file" in ++ Nbdkit.add_arg cmd "file" filename; ++ if Nbdkit.version nbdkit_config >= (1, 22, 0) then ( ++ let cmd = Nbdkit.add_arg cmd "cache" "none" in ++ cmd ++ ); ++ let _, pid = Nbdkit.run_unix socket cmd in ++ pid + +- (* --exit-with-parent should ensure nbdkit is cleaned +- * up when we exit, but it's not supported everywhere. +- *) +- On_exit.kill pid ++ | "qcow2" -> ++ let cmd = ++ if compressed then ( ++ let qemu_quote str = String.replace str "," ",," in ++ let image_opts = [ "driver=compress"; ++ "file.driver=qcow2"; ++ "file.file.driver=file"; ++ "file.file.filename=" ^ qemu_quote filename ] in ++ let image_opts = String.concat "," image_opts in ++ let cmd = QemuNBD.create image_opts in ++ QemuNBD.set_image_opts cmd true; ++ cmd ++ ) ++ else (* not compressed *) ( ++ let cmd = QemuNBD.create filename in ++ QemuNBD.set_format cmd (Some "qcow2"); ++ cmd ++ ) in ++ QemuNBD.set_snapshot cmd false; ++ let _, pid = QemuNBD.run_unix socket cmd in ++ pid + +- | "qcow2" -> +- let cmd = +- if compressed then ( +- let qemu_quote str = String.replace str "," ",," in +- let image_opts = [ "driver=compress"; +- "file.driver=qcow2"; +- "file.file.driver=file"; +- "file.file.filename=" ^ qemu_quote filename ] in +- let image_opts = String.concat "," image_opts in +- let cmd = QemuNBD.create image_opts in +- QemuNBD.set_image_opts cmd true; +- cmd +- ) +- else (* not compressed *) ( +- let cmd = QemuNBD.create filename in +- QemuNBD.set_format cmd (Some "qcow2"); +- cmd +- ) in +- QemuNBD.set_snapshot cmd false; +- let _, pid = QemuNBD.run_unix socket cmd in +- On_exit.kill pid ++ | _ -> ++ error (f_"output mode only supports raw or qcow2 format (format: %s)") ++ output_format in ++ ++ match on_exit_kill with ++ | Kill -> ++ (* Kill the NBD server on exit. (For nbdkit we use --exit-with-parent ++ * but it's not supported everywhere). ++ *) ++ On_exit.kill pid + +- | _ -> +- error (f_"output mode only supports raw or qcow2 format (format: %s)") +- output_format ++ | KillAndWait -> ++ On_exit.f ( ++ fun () -> ++ kill pid Sys.sigterm; ++ (* Errors from the NBD server don't matter. On successful ++ * completion we've already committed the data to disk. ++ *) ++ ignore (waitpid [] pid) ++ ) + + let disk_path os name i = + let outdisk = sprintf "%s/%s-sd%s" os name (drive_name i) in +diff --git a/output/output.mli b/output/output.mli +index c1f0f53d..c4486311 100644 +--- a/output/output.mli ++++ b/output/output.mli +@@ -83,14 +83,27 @@ val error_if_disk_count_gt : string -> int -> unit + "in[n]" in the v2v directory [dir]. If the socket exists, [error] is + called. *) + ++type on_exit_kill = Kill | KillAndWait ++ + val output_to_local_file : ?changeuid:((unit -> unit) -> unit) -> +- ?compressed:bool -> ++ ?compressed:bool -> ?on_exit_kill:on_exit_kill -> + Types.output_allocation -> + string -> string -> int64 -> string -> + unit + (** When an output mode wants to create a local file with a + particular format (only "raw" or "qcow2" allowed) then +- this common function can be used. *) ++ this common function can be used. ++ ++ Optional parameter [?on_exit_kill] controls how the NBD server ++ is cleaned up. The default is {!Kill} which registers an ++ {!On_exit.kill} handler that kills (but does not wait for) ++ the server when virt-v2v exits. Most callers should use this. ++ ++ Setting [~on_exit_kill:KillAndWait] should be used if the NBD ++ server must fully exit before we continue with the rest of ++ virt-v2v shut down. This is only necessary if some other action ++ (such as unmounting a host filesystem or removing a host device) ++ depends on the NBD server releasing resources. *) + + val disk_path : string -> string -> int -> string + (** For [-o disk|qemu], return the output disk name of the i'th disk, diff --git a/0028-v2v-Replace-broken-VMware-Tools-uninstall-command-ms.patch b/0028-v2v-Replace-broken-VMware-Tools-uninstall-command-ms.patch new file mode 100644 index 0000000..79faab6 --- /dev/null +++ b/0028-v2v-Replace-broken-VMware-Tools-uninstall-command-ms.patch @@ -0,0 +1,62 @@ +From 2bf5fc815d53e581398e787ae96444c438945ab3 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 19 Jan 2021 12:17:49 +0000 +Subject: [PATCH] v2v: Replace broken VMware Tools uninstall command msiexec /i + with /x. + +Fixes: https://bugzilla.redhat.com/1917760 +Thanks: Chetan Nagarkar +(cherry picked from commit f7496b0a7e76a06bda8d7ec1aba36741f8cb295c) +--- + v2v/convert_windows.ml | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml +index 84db742f..44cef5ed 100644 +--- a/v2v/convert_windows.ml ++++ b/v2v/convert_windows.ml +@@ -135,7 +135,7 @@ let convert (g : G.guestfs) inspect _ output rcaps static_ips = + (* Locate and retrieve all the uninstallation commands for installed + * applications. + *) +- let uninstallation_commands pretty_name matchfn extra_uninstall_params = ++ let uninstallation_commands pretty_name matchfn modfn extra_uninstall_params = + let path = ["Microsoft"; "Windows"; "CurrentVersion"; "Uninstall"] in + let uninstval = "UninstallString" in + let ret = ref [] in +@@ -155,6 +155,7 @@ let convert (g : G.guestfs) inspect _ output rcaps static_ips = + let valueh = g#hivex_node_get_value uninstnode uninstval in + if valueh <> 0L then ( + let reg_cmd = g#hivex_value_string valueh in ++ let reg_cmd = modfn reg_cmd in + let cmd = + sprintf "%s /quiet /norestart /l*v+ \"%%~dpn0.log\" REBOOT=ReallySuppress REMOVE=ALL %s" + reg_cmd extra_uninstall_params in +@@ -183,14 +184,22 @@ let convert (g : G.guestfs) inspect _ output rcaps static_ips = + *) + let extra_uninstall_params = + "PREVENT_REBOOT=Yes LAUNCHED_BY_SETUP_EXE=Yes" in +- uninstallation_commands "Parallels Tools" matchfn extra_uninstall_params in ++ uninstallation_commands "Parallels Tools" matchfn identity ++ extra_uninstall_params in + + (* Locate and retrieve all uninstallation commands for VMware Tools. *) + let vmwaretools_uninst = + let matchfn s = + String.find s "VMware Tools" != -1 + in +- uninstallation_commands "VMware Tools" matchfn "" in ++ (* VMware Tools writes the install command (MsiExec /I) into the ++ * UninstallString key in the registry, rather than the uninstall ++ * command. Try to spot this and rewrite. (RHBZ#1917760). ++ *) ++ let re1 = PCRE.compile ~caseless:true "msiexec" in ++ let re2 = PCRE.compile ~caseless:true "/i" in ++ let msifn s = if PCRE.matches re1 s then PCRE.replace re2 "/x" s else s in ++ uninstallation_commands "VMware Tools" matchfn msifn "" in + + (*----------------------------------------------------------------------*) + (* Perform the conversion of the Windows guest. *) +-- +2.31.1 + diff --git a/0029-o-rhv-Wait-for-the-NBD-server-to-exit-to-avoid-a-rac.patch b/0029-o-rhv-Wait-for-the-NBD-server-to-exit-to-avoid-a-rac.patch new file mode 100644 index 0000000..9799170 --- /dev/null +++ b/0029-o-rhv-Wait-for-the-NBD-server-to-exit-to-avoid-a-rac.patch @@ -0,0 +1,33 @@ +From f820585c37beb648ab856818179091349a604523 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 15 Jul 2022 11:37:46 +0100 +Subject: [PATCH] -o rhv: Wait for the NBD server to exit to avoid a race with + unmounting + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1953286#c26 +Reviewed-by: Laszlo Ersek +(cherry picked from commit 2fbd578b4e6884a23063ad67ee36f02c4eb6c668) +--- + output/output_rhv.ml | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/output/output_rhv.ml b/output/output_rhv.ml +index 15a2c14a..45f831e3 100644 +--- a/output/output_rhv.ml ++++ b/output/output_rhv.ml +@@ -175,7 +175,14 @@ module RHV = struct + chmod filename 0o666 + ) + in +- output_to_local_file ~changeuid ++ ++ (* We have to wait for the NBD server to exit rather than just ++ * killing it, otherwise it races with unmounting. See: ++ * https://bugzilla.redhat.com/show_bug.cgi?id=1953286#c26 ++ *) ++ let on_exit_kill = Output.KillAndWait in ++ ++ output_to_local_file ~changeuid ~on_exit_kill + output_alloc output_format filename size socket + ) (List.combine disks filenames); + diff --git a/0030-output-create_libvirt_xml-relax-VCPU-feature-checkin.patch b/0030-output-create_libvirt_xml-relax-VCPU-feature-checkin.patch new file mode 100644 index 0000000..8d856c9 --- /dev/null +++ b/0030-output-create_libvirt_xml-relax-VCPU-feature-checkin.patch @@ -0,0 +1,66 @@ +From 29c6ee9322da082e3be9faa94cf4a6840b49cd97 Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Fri, 22 Jul 2022 09:36:27 +0200 +Subject: [PATCH] output/create_libvirt_xml: relax VCPU feature checking for + "qemu64" + +When the source domain doesn't specify a VCPU model ("s_cpu_model" is +None), and the guest OS is assumed to work with the default VCPU model +("gcaps_default_cpu" is true), we don't output any element. In that +case, libvirtd augments the domain config with: + + [1] + qemu64 + + +where the @check='none' attribute ensures that the converted domain will +be launched, for example, on an Intel host, despite the "qemu64" VCPU +model containing AMD-only feature flags such as "svm". + +However, if the source domain explicitly specifies the "qemu64" model +(mostly seen with "-i libvirt -ic qemu://..."), we presently output + + [2] + qemu64 + + +which libvirtd completes as + + [3] + qemu64 + + +In [3], cpu/@match='minimum' and cpu/model/@fallback='allow' are both +laxer than @match='exact' and @fallback='forbid', respectively, in [1]. + +However, cpu/@check='partial' in [3] is stricter than @check='none' in +[1]; it causes libvirtd to catch the "svm" feature flag on an Intel host, +and prevents the converted domain from starting. + +The "qemu64" VCPU model is supposed to run on every possible host +, +therefore make an exception for the explicitly specified "qemu64" VCPU +model, and generate the @check='none' attribute. + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2107503 +Signed-off-by: Laszlo Ersek +Message-Id: <20220722073627.6511-1-lersek@redhat.com> +Acked-by: Richard W.M. Jones +(cherry picked from commit e5297c3180fd3ebea41a40f4c5a66969a24b9ff3) +--- + output/create_libvirt_xml.ml | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/output/create_libvirt_xml.ml b/output/create_libvirt_xml.ml +index 531a4f75..bd01304d 100644 +--- a/output/create_libvirt_xml.ml ++++ b/output/create_libvirt_xml.ml +@@ -192,6 +192,8 @@ let create_libvirt_xml ?pool source inspect + List.push_back cpu_attrs ("mode", "host-passthrough"); + | Some model -> + List.push_back cpu_attrs ("match", "minimum"); ++ if model = "qemu64" then ++ List.push_back cpu_attrs ("check", "none"); + (match source.s_cpu_vendor with + | None -> () + | Some vendor -> diff --git a/0030-v2v-rhv-upload-plugin-Defer-imageio-connection.patch b/0030-v2v-rhv-upload-plugin-Defer-imageio-connection.patch new file mode 100644 index 0000000..070b77a --- /dev/null +++ b/0030-v2v-rhv-upload-plugin-Defer-imageio-connection.patch @@ -0,0 +1,83 @@ +From 987ddcd2ad7546212d3afed52b56f27a664624d6 Mon Sep 17 00:00:00 2001 +From: Nir Soffer +Date: Thu, 21 Jan 2021 03:40:00 +0200 +Subject: [PATCH] v2v: rhv-upload-plugin: Defer imageio connection + +When using vddk input with certain vmware version, qemu-img may spend +lot of time getting source image extents. If getting image extents takes +more than 60 seconds, imageio server closes the idle connection, and the +transfer will fail on the first write with: + +nbdkit: python[1]: error: /var/tmp/rhvupload.0OKqWA/rhv-upload-plugin.py: pwrite: error: +Traceback (most recent call last): + File "/var/tmp/rhvupload.0OKqWA/rhv-upload-plugin.py", line 94, in wrapper + return func(h, *args) + File "/var/tmp/rhvupload.0OKqWA/rhv-upload-plugin.py", line 230, in pwrite + r = http.getresponse() + File "/usr/lib64/python3.6/http/client.py", line 1361, in getresponse + response.begin() + File "/usr/lib64/python3.6/http/client.py", line 311, in begin + version, status, reason = self._read_status() + File "/usr/lib64/python3.6/http/client.py", line 280, in _read_status + raise RemoteDisconnected("Remote end closed connection without" + http.client.RemoteDisconnected: Remote end closed connection without response + +This happens only when not using unix socket, for example when running +on non-ovirt host, or ovirt host from another data center, or when using +-oo rhv_direct=false + +When using unix socket, we close the initial HTTPSConnection, and +created a new UnixHTTPConnection. This connection is not connected to +the server yet. When qemu-img tries to access the server, the connection +is connected automatically. + +Fix the issue by closing the initial connection used to get server +options and initialize the handle, and storing a closed connection in +the handle. + +Here is the flow with this change: + +1. Create HTTPSConnection for getting server options +2. Close the connection[1] +3. If using unix socket, create UnixHTTPConnection. +4. Store the connection in the handle. +5. When qemu-img try to write/zero, the connection is reconnects + automatically to imageio server[2] + +Tested by adding a 300 milliseconds delay in nbdkit file plugin. Due to +the way qemu-img works, this cause more than 2 minutes delay after +open() but before the first pwrite(). Without this change, the import +fails consistently when using rhv_direct=false. + +[1] https://github.com/python/cpython/blob/34df10a9a16b38d54421eeeaf73ec89828563be7/Lib/http/client.py#L958 +[2] https://github.com/python/cpython/blob/34df10a9a16b38d54421eeeaf73ec89828563be7/Lib/http/client.py#L972 + +Signed-off-by: Nir Soffer +(cherry picked from commit 1d5fc257765c444644e5bfc6525e86ff201755f0) +--- + v2v/rhv-upload-plugin.py | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py +index 471102da..7cd6dea6 100644 +--- a/v2v/rhv-upload-plugin.py ++++ b/v2v/rhv-upload-plugin.py +@@ -117,6 +117,15 @@ def open(readonly): + destination_url = parse_transfer_url(transfer) + http = create_http(destination_url) + options = get_options(http, destination_url) ++ ++ # Close the initial connection to imageio server. When qemu-img will ++ # try to access the server, HTTPConnection will reconnect ++ # automatically. If we keep this connection idle and qemu-img is too ++ # slow getting image extents, imageio server may close the connection, ++ # and the import will fail on the first write. ++ # See https://bugzilla.redhat.com/1916176. ++ http.close() ++ + http = optimize_http(http, host, options) + except: + cancel_transfer(connection, transfer) +-- +2.31.1 + diff --git a/0031-input-xen-cover-RHEL9-OpenSSL-crypto-settings.patch b/0031-input-xen-cover-RHEL9-OpenSSL-crypto-settings.patch new file mode 100644 index 0000000..ae3fa10 --- /dev/null +++ b/0031-input-xen-cover-RHEL9-OpenSSL-crypto-settings.patch @@ -0,0 +1,59 @@ +From 9e1c78a4dda8e8f504fd8f01d7ff5a02e6d3b8ff Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Fri, 29 Jul 2022 12:57:03 +0200 +Subject: [PATCH] input-xen: cover RHEL9 OpenSSL crypto settings + +In [master] commit af4a0454cdd2 ("input-xen: replace "enable LEGACY +crypto" advice with targeted ssh options", 2022-07-11), we documented how +the libssh / openssh crypto settings needed to be relaxed, for connecting +to RHEL5 sshd. [rhel-9.1 commit: 3f7f730ac9cb.] + +It turns out that in RHEL9, the non-LEGACY crypto policies disable SHA1 in +signature algorithms even at the OpenSSL level. Explain how the user can +re-enable that separately, for individual virt-v2v invocations. + +The method depends on Rich's libvirt commit 45912ac399ab ("rpc: Pass +OPENSSL_CONF through to ssh invocations", 2022-07-25), which is is going +to be released in upstream libvirt v8.6.0. + +Thanks: Dmitry Belyavskiy & Rich Jones +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2062360 +Signed-off-by: Laszlo Ersek +Message-Id: <20220729105703.10150-1-lersek@redhat.com> +Reviewed-by: Richard W.M. Jones +(cherry picked from commit ddab06d5eb99696f5fd1073b8ec91efbc8c3e4ab) +--- + docs/virt-v2v-input-xen.pod | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/docs/virt-v2v-input-xen.pod b/docs/virt-v2v-input-xen.pod +index 1775fc31..9c3981e1 100644 +--- a/docs/virt-v2v-input-xen.pod ++++ b/docs/virt-v2v-input-xen.pod +@@ -54,6 +54,26 @@ new one. Virt-v2v uses both C and C when converting a guest + from Xen, and on some operating systems, C and C may not + both accept the same option variant.) + ++When connecting to RHEL 5 sshd from RHEL 9, the SHA1 algorithm's use in ++signatures has to be re-enabled at the OpenSSL level, in addition to the ++above SSH configuration. Create a file called F<$HOME/openssl-sha1.cnf> ++with the following contents: ++ ++ .include /etc/ssl/openssl.cnf ++ [openssl_init] ++ alg_section = evp_properties ++ [evp_properties] ++ rh-allow-sha1-signatures = yes ++ ++and export the following variable into the environment of the ++C process: ++ ++ OPENSSL_CONF=$HOME/openssl-sha1.cnf ++ ++Note that the C environment variable will only take effect ++if the libvirt client library used by virt-v2v is at least version ++8.6.0. ++ + =head2 Test libvirt connection to remote Xen host + + Use the L command to list the guests on the remote Xen host: diff --git a/0031-v2v-windows-Fix-schtasks-SD-parameter.patch b/0031-v2v-windows-Fix-schtasks-SD-parameter.patch new file mode 100644 index 0000000..657c680 --- /dev/null +++ b/0031-v2v-windows-Fix-schtasks-SD-parameter.patch @@ -0,0 +1,37 @@ +From 88429f56491ed0e5b3f5f91e6e352fa1251484bc Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 30 Nov 2020 08:55:34 +0000 +Subject: [PATCH] v2v: windows: Fix schtasks /SD parameter. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Thanks: Dinesh Herath, Tomáš Golembiovský, Bryan Kinney, Mark Zealey + +Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1895323 +(cherry picked from commit b65711c9293415f671d35d0e2f9b55a74343da45) +--- + v2v/convert_windows.ml | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml +index 44cef5ed..4d844e2d 100644 +--- a/v2v/convert_windows.ml ++++ b/v2v/convert_windows.ml +@@ -422,11 +422,12 @@ popd + and configure_qemu_ga files = + List.iter ( + fun msi_path -> ++ (* Windows is a trashfire. https://stackoverflow.com/a/18730884 *) + let fb_script = sprintf "\ + echo Removing any previously scheduled qemu-ga installation + schtasks.exe /Delete /TN Firstboot-qemu-ga /F + echo Scheduling delayed installation of qemu-ga from %s +-powershell.exe -command \"$d = (get-date).AddSeconds(120); schtasks.exe /Create /SC ONCE /ST $d.ToString('HH:mm') /SD $d.ToString('MM/dd/yyyy') /RU SYSTEM /TN Firstboot-qemu-ga /TR \\\"C:\\%s /forcerestart /qn /l+*vx C:\\%s.log\\\"\" ++powershell.exe -command \"$d = (get-date).AddSeconds(120); $FormatHack = ($([System.Globalization.DateTimeFormatInfo]::CurrentInfo.ShortDatePattern) -replace 'M+/', 'MM/') -replace 'd+/', 'dd/'; schtasks.exe /Create /SC ONCE /ST $d.ToString('HH:mm') /SD $d.ToString($FormatHack) /RU SYSTEM /TN Firstboot-qemu-ga /TR \\\"C:\\%s /forcerestart /qn /l+*vx C:\\%s.log\\\"\" + " + msi_path msi_path msi_path in + Firstboot.add_firstboot_script g inspect.i_root +-- +2.31.1 + diff --git a/0032-v2v-Turn-pnp_wait.exe-warning-into-a-debug-message.patch b/0032-v2v-Turn-pnp_wait.exe-warning-into-a-debug-message.patch new file mode 100644 index 0000000..c68e53f --- /dev/null +++ b/0032-v2v-Turn-pnp_wait.exe-warning-into-a-debug-message.patch @@ -0,0 +1,32 @@ +From b04361528b04dc39368c1d90760e50fad63baa9f Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 3 Dec 2020 10:14:08 +0000 +Subject: [PATCH] v2v: Turn pnp_wait.exe warning into a debug message. + +We've used virt-v2v for years in RHEL without pnp_wait and it's never +been an issue. We don't need a warning here. + +Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1903960 +(cherry picked from commit 834bea6931b49dc4b14ebe04fd0e0884290bfb78) +--- + v2v/convert_windows.ml | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml +index 4d844e2d..33fbd410 100644 +--- a/v2v/convert_windows.ml ++++ b/v2v/convert_windows.ml +@@ -267,8 +267,8 @@ let convert (g : G.guestfs) inspect _ output rcaps static_ips = + if Sys.file_exists tool_path then + configure_wait_pnp tool_path + else +- warning (f_"%s is missing. Firstboot scripts may conflict with PnP.") +- tool_path; ++ debug (f_"%s is missing. Firstboot scripts may conflict with PnP.") ++ tool_path; + + (* Install RHEV-APT only if appropriate for the output hypervisor. *) + if output#install_rhev_apt then ( +-- +2.31.1 + diff --git a/0033-docs-UEFI-guest-conversion-to-o-openstack-is-support.patch b/0033-docs-UEFI-guest-conversion-to-o-openstack-is-support.patch new file mode 100644 index 0000000..918de9c --- /dev/null +++ b/0033-docs-UEFI-guest-conversion-to-o-openstack-is-support.patch @@ -0,0 +1,27 @@ +From 6fb69c6239902cd4462b6c28bc82118cbf9643f2 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 25 Aug 2020 08:27:42 +0100 +Subject: [PATCH] docs: UEFI guest conversion to -o openstack is supported + (RHBZ#1872100). + +(cherry picked from commit db4e673df51d1235a040dc4a4782268743523e5a) +--- + docs/virt-v2v-support.pod | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/docs/virt-v2v-support.pod b/docs/virt-v2v-support.pod +index a5150907..1ffc0f9d 100644 +--- a/docs/virt-v2v-support.pod ++++ b/docs/virt-v2v-support.pod +@@ -38,7 +38,7 @@ hypervisor, else you will have to adjust paths in the metadata. + + =item UEFI on OpenStack + +-Not supported. ++Supported since virt-v2v E 1.43.2. + + =item UEFI on oVirt or RHV + +-- +2.31.1 + diff --git a/0034-docs-o-openstack-Clarify-name-of-file-containing-Ope.patch b/0034-docs-o-openstack-Clarify-name-of-file-containing-Ope.patch new file mode 100644 index 0000000..4dc1e6a --- /dev/null +++ b/0034-docs-o-openstack-Clarify-name-of-file-containing-Ope.patch @@ -0,0 +1,47 @@ +From 8a57af71779e274d31fe7f87a75bc937a59575db Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 27 Apr 2021 16:12:12 +0100 +Subject: [PATCH] docs: -o openstack: Clarify name of file containing OpenStack + auth + +In particular, don't use "stackrc" since you will likely be connecting +to the undercloud. + +Thanks: Ming Xie +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1871754 +(cherry picked from commit 61b4b5cc2f64e7a642ea03681f36829dbe665825) +--- + docs/virt-v2v-output-openstack.pod | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/docs/virt-v2v-output-openstack.pod b/docs/virt-v2v-output-openstack.pod +index 78623d97..f5a3abad 100644 +--- a/docs/virt-v2v-output-openstack.pod ++++ b/docs/virt-v2v-output-openstack.pod +@@ -89,8 +89,8 @@ endpoints. You will need to either set up your C<$OS_*> environment + variables or use output options on the virt-v2v command line to + authenticate with OpenStack. + +-Normally there is a file called something like C, +-C etc which you can simply C to set everything up. ++Normally there is a file called C or C ++which you can simply C to set everything up. + + For example: + +@@ -179,8 +179,10 @@ To output to OpenStack Glance, use the I<-o glance> option. + + This runs the L CLI program which must be installed on the + virt-v2v conversion host. For authentication to work, you will need +-to set C environment variables. In most cases you can do this +-by sourcing a file called something like F. ++to set C environment variables. ++ ++Normally there is a file called C or C ++which you can simply C to set everything up. + + Virt-v2v adds metadata for the guest to Glance, describing such things + as the guest operating system and what drivers it requires. The +-- +2.31.1 + diff --git a/0035-v2v-Allow-output-to-block-devices-RHBZ-1868690.patch b/0035-v2v-Allow-output-to-block-devices-RHBZ-1868690.patch new file mode 100644 index 0000000..92d98f7 --- /dev/null +++ b/0035-v2v-Allow-output-to-block-devices-RHBZ-1868690.patch @@ -0,0 +1,152 @@ +From 704e86cb3bd4ddc3b7c207967f0413b4637be1f3 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 1 Sep 2020 14:44:17 +0100 +Subject: [PATCH] v2v: Allow output to block devices (RHBZ#1868690). + +We previously implicitly supported writing to block devices instead of +local files, but there were several problems: + +* Block devices could be deleted, especially if virt-v2v failed during + a conversion. + +* Block devices could be overwritten by a file with the same name, + although I believe this is just an observed consequence of the + previous point, or at least I was not able to reproduce this until + virt-v2v failed for another reason and then I noticed that because + the block device was deleted, the next run overwrote it with a file. + +* It was not documented anywhere how to do it. + +This commit makes the small code change needed to allow virt-v2v to +write to a block device, only for existing outputs which write to +local files (ie. using TargetFile). Also it avoids deleting block +devices accidentally on failure. + +Note this commit intentionally does not prevent you from writing qcow2 +to a block device. RHV uses this so it is a thing that people do. + +(cherry picked from commit 9a5974fa3bc038e5e5dbb9605a6db77d06e7bf77) +--- + docs/virt-v2v.pod | 33 ++++++++++++++++++++++++++++++ + v2v/v2v.ml | 51 ++++++++++++++++++++++++++++------------------- + 2 files changed, 63 insertions(+), 21 deletions(-) + +diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod +index af69d633..50b0bc8e 100644 +--- a/docs/virt-v2v.pod ++++ b/docs/virt-v2v.pod +@@ -1378,8 +1378,41 @@ require either a special user and/or for you to source a script that + sets authentication environment variables. Consult the Glance + documentation. + ++=item Writing to block devices ++ ++This normally requires root. See the next section. ++ + =back + ++=head2 Writing to block devices ++ ++Some output modes write to local files. In general these modes also ++let you write to block devices, but before you run virt-v2v you may ++have to arrange for symbolic links to the desired block devices in the ++output directory. ++ ++For example if using I<-o local -os /dir> then virt-v2v would normally ++create files called: ++ ++ /dir/name-sda # first disk ++ /dir/name-sdb # second disk ++ ... ++ /dir/name.xml # metadata ++ ++If you wish the disks to be written to block devices then you would ++need to create F-sda> (etc) as symlinks to the block ++devices: ++ ++ # lvcreate -L 10G -n VolumeForDiskA VG ++ # lvcreate -L 6G -n VolumeForDiskB VG ++ # ln -sf /dev/VG/VolumeForDiskA /dir/name-sda ++ # ln -sf /dev/VG/VolumeForDiskB /dir/name-sdb ++ ++Note that you must precreate the correct number of block devices of ++the correct size. Typically I<-of raw> has to be used too, but other ++formats such as qcow2 can be useful occasionally so virt-v2v does not ++force you to use raw on block devices. ++ + =head2 Minimal XML for -i libvirtxml option + + When using the I<-i libvirtxml> option, you have to supply some +diff --git a/v2v/v2v.ml b/v2v/v2v.ml +index a58ff433..1f8d0138 100644 +--- a/v2v/v2v.ml ++++ b/v2v/v2v.ml +@@ -681,7 +681,10 @@ and copy_targets cmdline targets input output = + fun t -> + match t.target_file with + | TargetURI _ -> () +- | TargetFile s -> try unlink s with _ -> () ++ | TargetFile filename -> ++ if not (is_block_device filename) then ( ++ try unlink filename with _ -> () ++ ) + ) targets + ) + ); +@@ -711,27 +714,33 @@ and copy_targets cmdline targets input output = + + (match t.target_file with + | TargetFile filename -> +- (* It turns out that libguestfs's disk creation code is +- * considerably more flexible and easier to use than +- * qemu-img, so create the disk explicitly using libguestfs +- * then pass the 'qemu-img convert -n' option so qemu reuses +- * the disk. +- * +- * Also we allow the output mode to actually create the disk +- * image. This lets the output mode set ownership and +- * permissions correctly if required. ++ (* As a special case, allow output to a block device or ++ * symlink to a block device. In this case we don't ++ * create/overwrite the block device. (RHBZ#1868690). + *) +- (* What output preallocation mode should we use? *) +- let preallocation = +- match t.target_format, cmdline.output_alloc with +- | ("raw"|"qcow2"), Sparse -> Some "sparse" +- | ("raw"|"qcow2"), Preallocated -> Some "full" +- | _ -> None (* ignore -oa flag for other formats *) in +- let compat = +- match t.target_format with "qcow2" -> Some "1.1" | _ -> None in +- output#disk_create filename t.target_format +- t.target_overlay.ov_virtual_size +- ?preallocation ?compat ++ if not (is_block_device filename) then ( ++ (* It turns out that libguestfs's disk creation code is ++ * considerably more flexible and easier to use than ++ * qemu-img, so create the disk explicitly using libguestfs ++ * then pass the 'qemu-img convert -n' option so qemu reuses ++ * the disk. ++ * ++ * Also we allow the output mode to actually create the disk ++ * image. This lets the output mode set ownership and ++ * permissions correctly if required. ++ *) ++ (* What output preallocation mode should we use? *) ++ let preallocation = ++ match t.target_format, cmdline.output_alloc with ++ | ("raw"|"qcow2"), Sparse -> Some "sparse" ++ | ("raw"|"qcow2"), Preallocated -> Some "full" ++ | _ -> None (* ignore -oa flag for other formats *) in ++ let compat = ++ match t.target_format with "qcow2" -> Some "1.1" | _ -> None in ++ output#disk_create filename t.target_format ++ t.target_overlay.ov_virtual_size ++ ?preallocation ?compat ++ ) + + | TargetURI _ -> + (* XXX For the moment we assume that qemu URI outputs +-- +2.31.1 + diff --git a/0036-v2v-Disable-readahead-for-VMware-curl-sources-too-RH.patch b/0036-v2v-Disable-readahead-for-VMware-curl-sources-too-RH.patch new file mode 100644 index 0000000..9d4be88 --- /dev/null +++ b/0036-v2v-Disable-readahead-for-VMware-curl-sources-too-RH.patch @@ -0,0 +1,42 @@ +From e12604349587b67b3b4c3d0b7b1779999460a93d Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 19 Jun 2020 13:43:47 +0100 +Subject: [PATCH] v2v: Disable readahead for VMware curl sources too + (RHBZ#1848862). + +This appears to be the cause of timeouts during the conversion step +where VMware VCenter server's Tomcat HTTPS server stops responding to +requests (or rather, responds only with 503 errors). The server later +recovers and in fact because of the retry filter the conversion +usually succeeds, but I found that we can avoid the problem by +disabling readahead. + +(cherry picked from commit 9f4940068022d4e7abdfea6617b73a2b206f19aa) +--- + v2v/nbdkit_sources.ml | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/v2v/nbdkit_sources.ml b/v2v/nbdkit_sources.ml +index f5e91911..7c177e35 100644 +--- a/v2v/nbdkit_sources.ml ++++ b/v2v/nbdkit_sources.ml +@@ -99,12 +99,12 @@ let common_create ?bandwidth ?extra_debug ?extra_env password + + (* Adding the readahead filter is always a win for our access + * patterns. If it doesn't exist don't worry. However it +- * breaks VMware servers (RHBZ#1832805). ++ * breaks VMware servers (RHBZ#1832805, RHBZ#1848862). + *) + let cmd = +- if plugin_name <> "vddk" then +- Nbdkit.add_filter_if_available cmd "readahead" +- else cmd in ++ match plugin_name with ++ | "vddk" | "curl" -> cmd ++ | _ -> Nbdkit.add_filter_if_available cmd "readahead" in + + (* Caching extents speeds up qemu-img, especially its consecutive + * block_status requests with req_one=1. +-- +2.31.1 + diff --git a/0037-docs-Document-how-to-remove-Out-of-HTTP-sessions-lim.patch b/0037-docs-Document-how-to-remove-Out-of-HTTP-sessions-lim.patch new file mode 100644 index 0000000..82231bc --- /dev/null +++ b/0037-docs-Document-how-to-remove-Out-of-HTTP-sessions-lim.patch @@ -0,0 +1,37 @@ +From c0c4fa145da8a1d7b423c6f54bdf94d270c633de Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 3 Dec 2020 10:06:29 +0000 +Subject: [PATCH] docs: Document how to remove "Out of HTTP sessions" limit. + +Thanks: Tamir +(cherry picked from commit 00649e98be43b4b05a28c5c8c858a54ec4fe3e7a) +--- + docs/virt-v2v-input-vmware.pod | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/docs/virt-v2v-input-vmware.pod b/docs/virt-v2v-input-vmware.pod +index e4df920e..ae8964dd 100644 +--- a/docs/virt-v2v-input-vmware.pod ++++ b/docs/virt-v2v-input-vmware.pod +@@ -579,6 +579,18 @@ a stable IP address. After that log in to the vCenter server’s admin + console at C. Under the C tab, select + C and then reboot it. + ++=head2 vCenter: "Out of HTTP sessions: Limited to ..." ++ ++VMware vCenter appears to limit HTTP sessions and in some ++circumstances virt-v2v may exceed this number. You can adjust or ++remove the limit by editing F on the vCenter ++server. Increase the CmaxSessionCountE> field, or set it to ++C<0> which makes it unlimited: ++ ++ ++ 0 ++ ++ + =head1 SEE ALSO + + L. +-- +2.31.1 + diff --git a/0038-v2v-Increase-required-free-space-in-Windows-to-100-M.patch b/0038-v2v-Increase-required-free-space-in-Windows-to-100-M.patch new file mode 100644 index 0000000..68a020c --- /dev/null +++ b/0038-v2v-Increase-required-free-space-in-Windows-to-100-M.patch @@ -0,0 +1,131 @@ +From 90e0e0cfe7d90bb9b8cc4a8eb9225266b1622453 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 15 Apr 2021 16:52:36 +0100 +Subject: [PATCH] v2v: Increase required free space in Windows to 100 MB + +With an increasing number of drivers being installed in Windows the +existing limit (20 MB) was far too low. In fact we found that a guest +with 63 MB of free space would sometimes run out of space. + +This commit increases the required space to 100 MB for Windows. + +There are also a couple of smaller fixes: + + - We now properly distinguish between / as a Linux boot drive, + and Windows. + + - The error message has been improved to display MBs instead of bytes. + +Reported-by: Ming Xie +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1949147 +(cherry picked from commit dfcf60c916a986a352938b432231a36558a3bc05) +--- + docs/virt-v2v.pod | 8 +++++++- + v2v/v2v.ml | 46 +++++++++++++++++++++++++--------------------- + 2 files changed, 32 insertions(+), 22 deletions(-) + +diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod +index 50b0bc8e..4016c724 100644 +--- a/docs/virt-v2v.pod ++++ b/docs/virt-v2v.pod +@@ -1288,7 +1288,7 @@ to perform the conversion. Currently it checks: + + =over 4 + +-=item Linux root filesystem or Windows C drive ++=item Linux root filesystem + + Minimum free space: 20 MB + +@@ -1299,6 +1299,12 @@ Minimum free space: 50 MB + This is because we need to build a new initramfs for some Enterprise + Linux conversions. + ++=item Windows C drive ++ ++Minimum free space: 100 MB ++ ++We may have to copy in many virtio drivers and guest agents. ++ + =item Any other mountable filesystem + + Minimum free space: 10 MB +diff --git a/v2v/v2v.ml b/v2v/v2v.ml +index 1f8d0138..bde51885 100644 +--- a/v2v/v2v.ml ++++ b/v2v/v2v.ml +@@ -108,7 +108,7 @@ let rec main () = + let inspect = Inspect_source.inspect_source cmdline.root_choice g in + + let mpstats = get_mpstats g in +- check_guest_free_space mpstats; ++ check_guest_free_space inspect mpstats; + + (* Estimate space required on target for each disk. Note this is a max. *) + (match conversion_mode with +@@ -377,27 +377,28 @@ and print_mpstat chan { mp_dev = dev; mp_path = path; + * + * Also make sure filesystems have available inodes. (RHBZ#1764569) + *) +-and check_guest_free_space mpstats = ++and check_guest_free_space inspect mpstats = + message (f_"Checking for sufficient free disk space in the guest"); + + (* Check whether /boot has its own mount point. *) + let has_boot = List.exists (fun { mp_path } -> mp_path = "/boot") mpstats in ++ let is_windows = inspect.i_distro = "windows" in + +- let needed_bytes_for_mp = function +- | "/boot" +- | "/" when not has_boot -> +- (* We usually regenerate the initramfs, which has a +- * typical size of 20-30MB. Hence: +- *) +- 50_000_000L +- | "/" -> +- (* We may install some packages, and they would usually go +- * on the root filesystem. +- *) +- 20_000_000L +- | _ -> +- (* For everything else, just make sure there is some free space. *) +- 10_000_000L ++ let needed_megabytes_for_mp = function ++ (* We usually regenerate the initramfs, which has a ++ * typical size of 20-30MB. Hence: ++ *) ++ | "/boot" | "/" when not has_boot && not is_windows -> 50 ++ (* We may install some packages, and they would usually go ++ * on the root filesystem. ++ *) ++ | "/" when not is_windows -> 20 ++ (* Windows requires copying in many device drivers and possibly ++ * guest agents, so we need more space. (RHBZ#1949147). ++ *) ++ | "/" (* when is_windows *) -> 100 ++ (* For everything else, just make sure there is some free space. *) ++ | _ -> 10 + in + + (* Reasonable headroom for conversion operations. *) +@@ -407,10 +408,13 @@ and check_guest_free_space mpstats = + fun { mp_path; mp_statvfs = { G.bfree; bsize; files; ffree } } -> + (* bfree = free blocks for root user *) + let free_bytes = bfree *^ bsize in +- let needed_bytes = needed_bytes_for_mp mp_path in +- if free_bytes < needed_bytes then +- error (f_"not enough free space for conversion on filesystem ‘%s’. %Ld bytes free < %Ld bytes needed") +- mp_path free_bytes needed_bytes; ++ let needed_megabytes = needed_megabytes_for_mp mp_path in ++ let needed_bytes = Int64.of_int needed_megabytes *^ 1024L *^ 1024L in ++ if free_bytes < needed_bytes then ( ++ let mb i = Int64.to_float i /. 1024. /. 1024. in ++ error (f_"not enough free space for conversion on filesystem ‘%s’. %.1f MB free < %d MB needed") ++ mp_path (mb free_bytes) needed_megabytes ++ ); + (* Not all the filesystems have inode counts. *) + if files > 0L && ffree < needed_inodes then + error (f_"not enough available inodes for conversion on filesystem ‘%s’. %Ld inodes available < %Ld inodes needed") +-- +2.31.1 + diff --git a/0039-v2v-windows-Allow-qxldod.inf-as-synonym-for-qxl.inf.patch b/0039-v2v-windows-Allow-qxldod.inf-as-synonym-for-qxl.inf.patch new file mode 100644 index 0000000..309de2b --- /dev/null +++ b/0039-v2v-windows-Allow-qxldod.inf-as-synonym-for-qxl.inf.patch @@ -0,0 +1,30 @@ +From 575cb719ceb56d5f1812b6580f3a181bd95f5030 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 27 Apr 2021 17:29:42 +0100 +Subject: [PATCH] v2v: windows: Allow qxldod.inf as synonym for qxl.inf + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1926102 +Thanks: Xiaodai Wang, Ming Xie +(cherry picked from commit 11d1f3cd6878ae7713e589194f97526f744dc090) +--- + v2v/windows_virtio.ml | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/v2v/windows_virtio.ml b/v2v/windows_virtio.ml +index 4e00cd61..b8256bad 100644 +--- a/v2v/windows_virtio.ml ++++ b/v2v/windows_virtio.ml +@@ -155,7 +155,9 @@ let rec install_drivers ((g, _) as reg) inspect rcaps = + + (* Can we install the QXL driver? *) + let video : guestcaps_video_type = +- let has_qxl = g#exists (driverdir // "qxl.inf") in ++ let has_qxl = ++ g#exists (driverdir // "qxl.inf") || ++ g#exists (driverdir // "qxldod.inf") in + match rcaps.rcaps_video, has_qxl with + | Some QXL, false -> + error (f_"there is no QXL driver for this version of Windows (%d.%d %s). virt-v2v looks for this driver in %s") +-- +2.31.1 + diff --git a/0040-RHEL-8-docs-Fix-version-of-virt-v2v-which-added-UEFI.patch b/0040-RHEL-8-docs-Fix-version-of-virt-v2v-which-added-UEFI.patch new file mode 100644 index 0000000..f63b905 --- /dev/null +++ b/0040-RHEL-8-docs-Fix-version-of-virt-v2v-which-added-UEFI.patch @@ -0,0 +1,28 @@ +From e8d3beabfba4b309296569e84b275724e3cd9709 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 30 Jun 2021 16:18:20 +0100 +Subject: [PATCH] RHEL 8: docs: Fix version of virt-v2v which added UEFI for + OpenStack + +Reported-by: Tingting Zheng +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1872100#c7 +--- + docs/virt-v2v-support.pod | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/docs/virt-v2v-support.pod b/docs/virt-v2v-support.pod +index 1ffc0f9d..a9bfffab 100644 +--- a/docs/virt-v2v-support.pod ++++ b/docs/virt-v2v-support.pod +@@ -38,7 +38,7 @@ hypervisor, else you will have to adjust paths in the metadata. + + =item UEFI on OpenStack + +-Supported since virt-v2v E 1.43.2. ++Supported since virt-v2v E 1.42.0-7. + + =item UEFI on oVirt or RHV + +-- +2.31.1 + diff --git a/0041-v2v-Increase-Linux-minimum-root-filesystem-to-100-MB.patch b/0041-v2v-Increase-Linux-minimum-root-filesystem-to-100-MB.patch new file mode 100644 index 0000000..1275268 --- /dev/null +++ b/0041-v2v-Increase-Linux-minimum-root-filesystem-to-100-MB.patch @@ -0,0 +1,60 @@ +From 906e087d6c57d4c1f24ecb60f98a6c98f75881a7 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 20 May 2021 09:10:20 +0100 +Subject: [PATCH] v2v: Increase Linux minimum root filesystem to 100 MB + +Ming Xie created a RHEL 8.3 guest which required around 70 MB free in +order to recreate the initramfs (temporary space used by the pigz +step). Increase the minimum space required to 100 MB, the same as for +Windows. + +Seealso commit dfcf60c916a986a352938b432231a36558a3bc05. + +Reported-by: Ming Xie +Fixes: https://bugzilla.redhat.com/1764569#c16 +(cherry picked from commit e82ff27c3bea5ce2cc3b7d1ce8d775989fc7e5a5) +--- + docs/virt-v2v.pod | 2 +- + v2v/v2v.ml | 12 +++++------- + 2 files changed, 6 insertions(+), 8 deletions(-) + +diff --git a/docs/virt-v2v.pod b/docs/virt-v2v.pod +index 4016c724..4ecce369 100644 +--- a/docs/virt-v2v.pod ++++ b/docs/virt-v2v.pod +@@ -1290,7 +1290,7 @@ to perform the conversion. Currently it checks: + + =item Linux root filesystem + +-Minimum free space: 20 MB ++Minimum free space: 100 MB + + =item Linux F + +diff --git a/v2v/v2v.ml b/v2v/v2v.ml +index bde51885..8af86687 100644 +--- a/v2v/v2v.ml ++++ b/v2v/v2v.ml +@@ -389,14 +389,12 @@ and check_guest_free_space inspect mpstats = + * typical size of 20-30MB. Hence: + *) + | "/boot" | "/" when not has_boot && not is_windows -> 50 +- (* We may install some packages, and they would usually go +- * on the root filesystem. ++ (* Both Linux and Windows require installation of files, ++ * device drivers and guest agents. ++ * https://bugzilla.redhat.com/1949147 ++ * https://bugzilla.redhat.com/1764569#c16 + *) +- | "/" when not is_windows -> 20 +- (* Windows requires copying in many device drivers and possibly +- * guest agents, so we need more space. (RHBZ#1949147). +- *) +- | "/" (* when is_windows *) -> 100 ++ | "/" -> 100 + (* For everything else, just make sure there is some free space. *) + | _ -> 10 + in +-- +2.31.1 + diff --git a/0042-v2v-rhv-upload-plugin-Fix-waiting-for-finalize.patch b/0042-v2v-rhv-upload-plugin-Fix-waiting-for-finalize.patch new file mode 100644 index 0000000..ea1d459 --- /dev/null +++ b/0042-v2v-rhv-upload-plugin-Fix-waiting-for-finalize.patch @@ -0,0 +1,179 @@ +From 419aa23f0c6338b01b644094c3af2c024470e9b2 Mon Sep 17 00:00:00 2001 +From: Nir Soffer +Date: Sat, 10 Jul 2021 02:35:27 +0300 +Subject: [PATCH] v2v: rhv-upload-plugin: Fix waiting for finalize + +Waiting for image transfer finalize is complex. In the past we tried to +simplify the process by waiting on the disk status, but turns out that +due to the way oVirt lock the disk, this is not reliable. + +These is finalize success flow: + +1. User asks to finalize the transfer +2. oVirt sets transfer phase to FINALIZING_SUCCESS +3. oVirt finalizes the transfer +4. oVirt sets disk status to OK +5. oVirt unlocks the disk and changes transfer phase to FINISHED_SUCCESS +6. oVirt removes the transfer + +In oVirt logs we can see that disk status changes to OK about 3 seconds +before the disk is actually unlocked. This is a very old problem that is +unlikely to be fixed. + +The only way to wait for transfer completion is to poll the transfer +phase, but oVirt makes this hard by removing the transfer shortly after +it completes, so we may not be able to get the FINISHED_SUCCESS phase. +If the transfer was removed before we got one of the final phases, we +need to check the disk status to understand the result of transfer. + +oVirt 4.4.7 made polling transfer phase easier by keeping the transfer +after completion, but we need to support older versions so we must have +generic code that work with any version. + +To make debugging easier, we log the transfer phase during polling. Here +is a typical transfer log when finalizing transfer: + + finalizing transfer 59e545f3-db1f-4a6b-90b1-80ac66572faa + transfer 59e545f3-db1f-4a6b-90b1-80ac66572faa is finalizing_success + transfer 59e545f3-db1f-4a6b-90b1-80ac66572faa is finalizing_success + transfer 59e545f3-db1f-4a6b-90b1-80ac66572faa is finalizing_success + transfer 59e545f3-db1f-4a6b-90b1-80ac66572faa is finalizing_success + transfer 59e545f3-db1f-4a6b-90b1-80ac66572faa is finished_success + transfer 59e545f3-db1f-4a6b-90b1-80ac66572faa finalized in 5.153 seconds + +Signed-off-by: Nir Soffer +Fixes: https://bugzilla.redhat.com/1976024 +(cherry picked from commit 79702b28329d15a7485801ed7e915d486fcc0cf4) +--- + v2v/rhv-upload-plugin.py | 98 ++++++++++++++++++++++++++++------------ + 1 file changed, 69 insertions(+), 29 deletions(-) + +diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py +index 7cd6dea6..61ade1a8 100644 +--- a/v2v/rhv-upload-plugin.py ++++ b/v2v/rhv-upload-plugin.py +@@ -601,17 +601,29 @@ def finalize_transfer(connection, transfer, disk_id): + """ + Finalize a transfer, making the transfer disk available. + +- If finalizing succeeds, transfer's phase will change to FINISHED_SUCCESS +- and the transer's disk status will change to OK. On errors, the transfer's +- phase will change to FINISHED_FAILURE and the disk status will change to +- ILLEGAL and it will be removed. In both cases the transfer entity will be +- removed shortly after. ++ If finalizing succeeds, the transfer's disk status will change to OK ++ and transfer's phase will change to FINISHED_SUCCESS. Unfortunately, ++ the disk status is modified before the transfer finishes, and oVirt ++ may still hold a lock on the disk at this point. + +- If oVirt fails to finalize the transfer, transfer's phase will change to +- PAUSED_SYSTEM. In this case the disk's status will change to ILLEGAL and it +- will not be removed. ++ The only way to make sure that the disk is unlocked, is to wait ++ until the transfer phase switches FINISHED_SUCCESS. Unfortunately ++ oVirt makes this hard to use because the transfer is removed shortly ++ after switching the phase to the final phase. However if the ++ transfer was removed, we can be sure that the disk is not locked, ++ since oVirt releases the locks before removing the transfer. + +- For simplicity, we track only disk's status changes. ++ On errors, the transfer's phase will change to FINISHED_FAILURE and ++ the disk status will change to ILLEGAL and it will be removed. Again ++ the transfer will be removed shortly after that. ++ ++ If oVirt fails to finalize the transfer, transfer's phase will ++ change to PAUSED_SYSTEM. In this case the disk's status will change ++ to ILLEGAL and it will not be removed. ++ ++ oVirt 4.4.7 made waiting for transfer easier by keeping transfers ++ after they complete, but we must support older versions so we have ++ generic code that work with any version. + + For more info see: + - http://ovirt.github.io/ovirt-engine-api-model/4.4/#services/image_transfer +@@ -626,34 +638,62 @@ def finalize_transfer(connection, transfer, disk_id): + + transfer_service.finalize() + +- disk_service = (connection.system_service() +- .disks_service() +- .disk_service(disk_id)) +- + while True: + time.sleep(1) + try: +- disk = disk_service.get() ++ transfer = transfer_service.get() + except sdk.NotFoundError: +- # Disk verification failed and the system removed the disk. +- raise RuntimeError( +- "transfer %s failed: disk %s was removed" +- % (transfer.id, disk_id)) ++ # Transfer was removed (ovirt < 4.4.7). We need to check the ++ # disk status to understand if the transfer was successful. ++ # Due to the way oVirt does locking, we know that the disk ++ # is unlocked at this point so we can check only once. + +- if disk.status == types.DiskStatus.ILLEGAL: +- # Disk verification failed or transfer was paused by the system. +- raise RuntimeError( +- "transfer %s failed: disk is ILLEGAL" % transfer.id) ++ debug("transfer %s was removed, checking disk %s status" ++ % (transfer.id, disk_id)) ++ ++ disk_service = (connection.system_service() ++ .disks_service() ++ .disk_service(disk_id)) + +- if disk.status == types.DiskStatus.OK: +- debug("transfer %s finalized in %.3f seconds" +- % (transfer.id, time.time() - start)) +- break ++ try: ++ disk = disk_service.get() ++ except sdk.NotFoundError: ++ raise RuntimeError( ++ "transfer %s failed: disk %s was removed" ++ % (transfer.id, disk_id)) ++ ++ debug("disk %s is %s" % (disk_id, disk.status)) ++ ++ if disk.status == types.DiskStatus.OK: ++ break + +- if time.time() > start + timeout: + raise RuntimeError( +- "timed out waiting for transfer %s to finalize" +- % transfer.id) ++ "transfer %s failed: disk is %s" % (transfer.id, disk.status)) ++ else: ++ # Transfer exists, check if it reached one of the final ++ # phases, or we timed out. ++ ++ debug("transfer %s is %s" % (transfer.id, transfer.phase)) ++ ++ if transfer.phase == types.ImageTransferPhase.FINISHED_SUCCESS: ++ break ++ ++ if transfer.phase == types.ImageTransferPhase.FINISHED_FAILURE: ++ raise RuntimeError( ++ "transfer %s has failed" % (transfer.id,)) ++ ++ if transfer.phase == types.ImageTransferPhase.PAUSED_SYSTEM: ++ raise RuntimeError( ++ "transfer %s was paused by system" % (transfer.id,)) ++ ++ if time.time() > start + timeout: ++ raise RuntimeError( ++ "timed out waiting for transfer %s to finalize, " ++ "transfer is %s" ++ % (transfer.id, transfer.phase)) ++ ++ debug("transfer %s finalized in %.3f seconds" ++ % (transfer.id, time.time() - start)) + + + def transfer_supports_format(): +-- +2.31.1 + diff --git a/0043-v2v-windows-Do-not-fix-NTFS-heads-in-Windows-Vista-a.patch b/0043-v2v-windows-Do-not-fix-NTFS-heads-in-Windows-Vista-a.patch new file mode 100644 index 0000000..cc45c67 --- /dev/null +++ b/0043-v2v-windows-Do-not-fix-NTFS-heads-in-Windows-Vista-a.patch @@ -0,0 +1,80 @@ +From 72f50e52515369ef8decda9493422d6235f5b365 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 18 Aug 2021 11:00:12 +0100 +Subject: [PATCH] v2v: windows: Do not fix NTFS heads in Windows Vista and + later + +Setting/adjusting the number of drive heads in the NTFS header is only +necessary for ancient versions of Windows. Modern versions ignore +this. In addition this operation broke when we added BitLocker +support. Only do this for ancient Windows 2000/XP and skip it for +everything else. + +Reported-by: Ming Xie +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1994984 +(cherry picked from commit 0a394c5c2f802098c9e481b4bacee7821e5dd0ae) +--- + v2v/convert_windows.ml | 44 ++++++++++++++++++++++-------------------- + 1 file changed, 23 insertions(+), 21 deletions(-) + +diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml +index 33fbd410..13de10cb 100644 +--- a/v2v/convert_windows.ml ++++ b/v2v/convert_windows.ml +@@ -730,30 +730,32 @@ if errorlevel 3010 exit /b 0 + however, as this is specific to Windows 2003 it lists location + 0x1A as unused. + *) +- let rootpart = inspect.i_root in ++ if inspect.i_major_version < 6 (* is Windows 2000/XP *) then ( ++ let rootpart = inspect.i_root in + +- (* Ignore if the rootpart is something like /dev/sda. RHBZ#1276540. *) +- if not (g#is_whole_device rootpart) then ( +- (* Check that the root device contains NTFS magic. *) +- let magic = g#pread_device rootpart 8 3L in +- if magic = "NTFS " then ( +- (* Get the size of the whole disk containing the root partition. *) +- let rootdev = g#part_to_dev rootpart in (* eg. /dev/sda *) +- let size = g#blockdev_getsize64 rootdev in ++ (* Ignore if the rootpart is something like /dev/sda. RHBZ#1276540. *) ++ if not (g#is_whole_device rootpart) then ( ++ (* Check that the root device contains NTFS magic. *) ++ let magic = g#pread_device rootpart 8 3L in ++ if magic = "NTFS " then ( ++ (* Get the size of the whole disk containing the root partition. *) ++ let rootdev = g#part_to_dev rootpart in (* eg. /dev/sda *) ++ let size = g#blockdev_getsize64 rootdev in + +- let heads = (* refer to the table above *) +- if size < 2114445312L then 0x40 +- else if size < 4228374780L then 0x80 +- else 0xff in ++ let heads = (* refer to the table above *) ++ if size < 2114445312L then 0x40 ++ else if size < 4228374780L then 0x80 ++ else 0xff in + +- (* Update NTFS's idea of the number of heads. This is an +- * unsigned 16 bit little-endian integer, offset 0x1a from the +- * beginning of the partition. +- *) +- let b = Bytes.create 2 in +- Bytes.unsafe_set b 0 (Char.chr heads); +- Bytes.unsafe_set b 1 '\000'; +- ignore (g#pwrite_device rootpart (Bytes.to_string b) 0x1a_L) ++ (* Update NTFS's idea of the number of heads. This is an ++ * unsigned 16 bit little-endian integer, offset 0x1a from the ++ * beginning of the partition. ++ *) ++ let b = Bytes.create 2 in ++ Bytes.unsafe_set b 0 (Char.chr heads); ++ Bytes.unsafe_set b 1 '\000'; ++ ignore (g#pwrite_device rootpart (Bytes.to_string b) 0x1a_L) ++ ) + ) + ) + +-- +2.31.1 + diff --git a/0044-v2v-vcenter-Implement-cookie-scripts.patch b/0044-v2v-vcenter-Implement-cookie-scripts.patch new file mode 100644 index 0000000..d0553fb --- /dev/null +++ b/0044-v2v-vcenter-Implement-cookie-scripts.patch @@ -0,0 +1,275 @@ +From cc9a507e2372b5b6408964f9c31a3bd526aabf7c Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 23 Sep 2020 09:56:27 +0100 +Subject: [PATCH] v2v: vcenter: Implement cookie scripts. + +For conversions[*] which take longer than 30 minutes it can happen +that the HTTPS authorization cookie that we fetched from VMware when +we first connect expires. This can especially happen when there are +multiple disks, because we may not "touch" (therefore autorenew) the +second disk while we are doing the long conversion. This can lead to +failures, some of which are silent: again if there are multiple disks, +fstrim of the non-system disks can fail silently resulting in the copy +step taking a very long time. + +The solution to this is to use the new nbdkit-curl-plugin +cookie-script feature which allows nbdkit to automatically renew the +cookie as required. + +During the conversion or copying steps you may see the cookie being +autorenewed: + + nbdkit: curl[3]: debug: curl: running cookie-script + nbdkit: curl[3]: debug: cookie-script returned cookies + +This removes the ?user and ?password parameters from Nbdkit_sources.- +create_curl because they are no longer needed after this change. +Note for future: if we need to add them back, we must prevent both +user and cookie_script parameters from being used at the same time, +because simply having the user parameter will try basic +authentication, overriding the cookie, which will either fail (no +password) or run very slowly. + +This change requires nbdkit >= 1.22 which is checked at runtime only +if this feature is used. + +[*] Note here I mean conversions not the total runtime of virt-v2v. +When doing the copy the cookie does not expire because it is +continuously auto-renewed by VMware as we continuously access the disk +(this works differently from systems like Docker where the cookie is +only valid from the absolute time when it is first created). This +change also implements the cookie-script logic for copying. + +(cherry picked from commit 2b9a11743b74ef3716b66a7e395108a26382e331) + +Notes for cherry pick to RHEL 8.6: + +We no longer need the session_cookie field inside virt-v2v since it is +replaced by the cookie script. However it is still needed by +virt-v2v-copy-to-local. (This utility is removed upstream and in RHEL +9, but we need to keep it around at least for appearances in RHEL 8.) + +So when cherry picking I had to retain the get_session_cookie function +which required also keeping fetch_headers_and_url as it was (not +dropping headers). +--- + v2v/nbdkit_sources.ml | 34 ++++++++++++----- + v2v/nbdkit_sources.mli | 5 +-- + v2v/parse_libvirt_xml.ml | 3 +- + v2v/vCenter.ml | 80 +++++++++++++++++++++++++++++++--------- + 4 files changed, 90 insertions(+), 32 deletions(-) + +diff --git a/v2v/nbdkit_sources.ml b/v2v/nbdkit_sources.ml +index 7c177e35..16af5f5c 100644 +--- a/v2v/nbdkit_sources.ml ++++ b/v2v/nbdkit_sources.ml +@@ -26,7 +26,6 @@ open Types + open Utils + + let nbdkit_min_version = (1, 12, 0) +-let nbdkit_min_version_string = "1.12.0" + + type password = + | NoPassword (* no password option at all *) +@@ -38,11 +37,16 @@ let error_unless_nbdkit_working () = + if not (Nbdkit.is_installed ()) then + error (f_"nbdkit is not installed or not working") + +-let error_unless_nbdkit_min_version config = ++let error_unless_nbdkit_version_ge config min_version = + let version = Nbdkit.version config in +- if version < nbdkit_min_version then +- error (f_"nbdkit is too old. nbdkit >= %s is required.") +- nbdkit_min_version_string ++ if version < min_version then ( ++ let min_major, min_minor, min_release = min_version in ++ error (f_"nbdkit is too old. nbdkit >= %d.%d.%d is required.") ++ min_major min_minor min_release ++ ) ++ ++let error_unless_nbdkit_min_version config = ++ error_unless_nbdkit_version_ge config nbdkit_min_version + + let error_unless_nbdkit_plugin_exists plugin = + if not (Nbdkit.probe_plugin plugin) then +@@ -297,23 +301,35 @@ let create_ssh ?bandwidth ~password ?port ~server ?user path = + common_create ?bandwidth password "ssh" (get_args ()) + + (* Create an nbdkit module specialized for reading from Curl sources. *) +-let create_curl ?bandwidth ?cookie ~password ?(sslverify=true) ?user url = ++let create_curl ?bandwidth ?cookie_script ?cookie_script_renew ++ ?(sslverify=true) url = + error_unless_nbdkit_plugin_exists "curl"; + ++ (* The cookie* parameters require nbdkit 1.22, so check that early. *) ++ if cookie_script <> None || cookie_script_renew <> None then ( ++ let config = Nbdkit.config () in ++ error_unless_nbdkit_version_ge config (1, 22, 0) ++ ); ++ + let add_arg, get_args = + let args = ref [] in + let add_arg (k, v) = List.push_front (k, v) args in + let get_args () = List.rev !args in + add_arg, get_args in + +- Option.may (fun s -> add_arg ("user", s)) user; + (* https://bugzilla.redhat.com/show_bug.cgi?id=1146007#c10 *) + add_arg ("timeout", "2000"); +- Option.may (fun s -> add_arg ("cookie", s)) cookie; ++ Option.may (fun s -> add_arg ("cookie-script", s)) cookie_script; ++ Option.may (fun i -> add_arg ("cookie-script-renew", string_of_int i)) ++ cookie_script_renew; + if not sslverify then add_arg ("sslverify", "false"); + add_arg ("url", url); + +- common_create ?bandwidth password "curl" (get_args ()) ++ (* For lots of extra debugging, uncomment one or both lines. *) ++ (*add_arg ("--debug", "curl.verbose=1");*) ++ (*add_arg ("--debug", "curl.scripts=1");*) ++ ++ common_create ?bandwidth NoPassword "curl" (get_args ()) + + let run cmd = + let sock, _ = Nbdkit.run_unix cmd in +diff --git a/v2v/nbdkit_sources.mli b/v2v/nbdkit_sources.mli +index 94810ea6..922642df 100644 +--- a/v2v/nbdkit_sources.mli ++++ b/v2v/nbdkit_sources.mli +@@ -60,10 +60,9 @@ val create_ssh : ?bandwidth:Types.bandwidth -> + Note this doesn't run nbdkit yet, it just creates the object. *) + + val create_curl : ?bandwidth:Types.bandwidth -> +- ?cookie:string -> +- password:password -> ++ ?cookie_script:string -> ++ ?cookie_script_renew:int -> + ?sslverify:bool -> +- ?user:string -> + string -> Nbdkit.cmd + (** Create a nbdkit object using the Curl plugin. The required + string parameter is the URL. +diff --git a/v2v/parse_libvirt_xml.ml b/v2v/parse_libvirt_xml.ml +index 0b136839..fffc5a24 100644 +--- a/v2v/parse_libvirt_xml.ml ++++ b/v2v/parse_libvirt_xml.ml +@@ -319,8 +319,7 @@ let parse_libvirt_xml ?bandwidth ?conn xml = + | _, Some port -> + invalid_arg "invalid port number in libvirt XML" in + sprintf "%s://%s%s%s" driver host port (uri_quote path) in +- let nbdkit = Nbdkit_sources.create_curl ?bandwidth ~password:NoPassword +- url in ++ let nbdkit = Nbdkit_sources.create_curl ?bandwidth url in + let qemu_uri = Nbdkit_sources.run nbdkit in + add_disk qemu_uri format controller P_dont_rewrite + | Some protocol, _, _ -> +diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml +index 4c128b0c..ead03364 100644 +--- a/v2v/vCenter.ml ++++ b/v2v/vCenter.ml +@@ -46,11 +46,12 @@ let rec map_source ?bandwidth ?password_file dcPath uri server path = + (* XXX only works if the query string is not URI-quoted *) + String.find query "no_verify=1" = -1 in + ++ (* Check the URL exists and authentication info is correct. *) + let https_url = + let https_url = get_https_url dcPath uri server path in +- (* Check the URL exists. *) +- let status, _, _ = ++ let status, _, dump_response = + fetch_headers_from_url password_file uri sslverify https_url in ++ + (* If a disk is actually a snapshot image it will have '-00000n' + * appended to its name, e.g.: + * [yellow:storage1] RHEL4-X/RHEL4-X-000003.vmdk +@@ -58,28 +59,71 @@ let rec map_source ?bandwidth ?password_file dcPath uri server path = + * a 404 and the vmdk name looks like it might be a snapshot, try + * again without the snapshot suffix. + *) +- if status = "404" && PCRE.matches snapshot_re path then ( +- let path = PCRE.sub 1 ^ PCRE.sub 2 in +- get_https_url dcPath uri server path +- ) +- else +- (* Note that other non-200 status errors will be handled +- * in get_session_cookie below, so we don't have to worry +- * about them here. +- *) +- https_url in ++ let https_url, status, dump_response = ++ if status = "404" && PCRE.matches snapshot_re path then ( ++ let path = PCRE.sub 1 ^ PCRE.sub 2 in ++ let https_url = get_https_url dcPath uri server path in ++ let status, _, dump_response = ++ fetch_headers_from_url password_file uri sslverify https_url in ++ https_url, status, dump_response ++ ) ++ else (https_url, status, dump_response) in ++ ++ if status = "401" then ( ++ dump_response stderr; ++ if uri.uri_user <> None then ++ error (f_"vcenter: incorrect username or password") ++ else ++ error (f_"vcenter: incorrect username or password. You might need to specify the username in the URI like this: [vpx|esx|..]://USERNAME@[etc]") ++ ); ++ ++ if status = "404" then ( ++ dump_response stderr; ++ error (f_"vcenter: URL not found: %s") https_url ++ ); ++ ++ if status <> "200" then ( ++ dump_response stderr; ++ error (f_"vcenter: invalid response from server: %s") status ++ ); ++ ++ https_url in + + let session_cookie = + get_session_cookie password_file uri sslverify https_url in + +- let password = +- match password_file with +- | None -> Nbdkit_sources.NoPassword +- | Some password_file -> Nbdkit_sources.PasswordFile password_file in ++ (* Write a cookie script to retrieve the session cookie. ++ * See nbdkit-curl-plugin(1) "Example: VMware ESXi cookies" ++ *) ++ let cookie_script, chan = ++ Filename.open_temp_file ~perms:0o700 "v2vcs" ".sh" in ++ unlink_on_exit cookie_script; ++ let fpf fs = fprintf chan fs in ++ fpf "#!/bin/sh -\n"; ++ fpf "\n"; ++ fpf "curl --head -s"; ++ if not sslverify then fpf " --insecure"; ++ (match uri.uri_user, password_file with ++ | None, None -> () ++ | Some user, None -> fpf " -u %s" (quote user) ++ | None, Some password_file -> ++ fpf " -u \"$LOGNAME\":\"$(cat %s)\"" (quote password_file) ++ | Some user, Some password_file -> ++ fpf " -u %s:\"$(cat %s)\"" (quote user) (quote password_file) ++ ); ++ fpf " %s" (quote https_url); ++ fpf " |\n"; ++ fpf "\tsed -ne %s\n" (quote "{ s/^Set-Cookie: \\([^;]*\\);.*/\\1/ip }"); ++ close_out chan; ++ ++ (* VMware authentication expires after 30 minutes so we must renew ++ * after < 30 minutes. ++ *) ++ let cookie_script_renew = 25*60 in + + let nbdkit = +- Nbdkit_sources.create_curl ?bandwidth ?cookie:session_cookie ~password ~sslverify +- ?user:uri.uri_user https_url in ++ Nbdkit_sources.create_curl ?bandwidth ~cookie_script ~cookie_script_renew ++ ~sslverify https_url in + let qemu_uri = Nbdkit_sources.run nbdkit in + + (* Return the struct. *) +-- +2.31.1 + diff --git a/0045-convert-convert_windows.ml-Handle-date-formats-with-.patch b/0045-convert-convert_windows.ml-Handle-date-formats-with-.patch new file mode 100644 index 0000000..f2100e7 --- /dev/null +++ b/0045-convert-convert_windows.ml-Handle-date-formats-with-.patch @@ -0,0 +1,44 @@ +From 84cb43440a2ad143eb7474a028b1b1549cb8c0f1 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 12 Nov 2021 08:47:55 +0000 +Subject: [PATCH] convert/convert_windows.ml: Handle date formats with dots + instead of / + +If the ShortDatePattern is yy.M.d (as can happen for US locale) we may +not always reformat the date for schtasks.exe correctly. For +explanation and testing see: + +https://bugzilla.redhat.com/show_bug.cgi?id=1895323#c46 (- #c50) + +Thanks: Xiaodai Wang for suggesting the fix and testing it +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1895323 +(cherry picked from commit d9dc6c42ae64ba92993dbd9477f003ba73fcfa2f) +--- + v2v/convert_windows.ml | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml +index 13de10cb..6c7440aa 100644 +--- a/v2v/convert_windows.ml ++++ b/v2v/convert_windows.ml +@@ -422,12 +422,15 @@ popd + and configure_qemu_ga files = + List.iter ( + fun msi_path -> +- (* Windows is a trashfire. https://stackoverflow.com/a/18730884 *) ++ (* Windows is a trashfire. ++ * https://stackoverflow.com/a/18730884 ++ * https://bugzilla.redhat.com/show_bug.cgi?id=1895323 ++ *) + let fb_script = sprintf "\ + echo Removing any previously scheduled qemu-ga installation + schtasks.exe /Delete /TN Firstboot-qemu-ga /F + echo Scheduling delayed installation of qemu-ga from %s +-powershell.exe -command \"$d = (get-date).AddSeconds(120); $FormatHack = ($([System.Globalization.DateTimeFormatInfo]::CurrentInfo.ShortDatePattern) -replace 'M+/', 'MM/') -replace 'd+/', 'dd/'; schtasks.exe /Create /SC ONCE /ST $d.ToString('HH:mm') /SD $d.ToString($FormatHack) /RU SYSTEM /TN Firstboot-qemu-ga /TR \\\"C:\\%s /forcerestart /qn /l+*vx C:\\%s.log\\\"\" ++powershell.exe -command \"$d = (get-date).AddSeconds(120); $FormatHack = (($([System.Globalization.DateTimeFormatInfo]::CurrentInfo.ShortDatePattern) -replace 'y+', 'yyyy') -replace 'M+', 'MM') -replace 'd+', 'dd'; schtasks.exe /Create /SC ONCE /ST $d.ToString('HH:mm') /SD $d.ToString($FormatHack) /RU SYSTEM /TN Firstboot-qemu-ga /TR \\\"C:\\%s /forcerestart /qn /l+*vx C:\\%s.log\\\"\" + " + msi_path msi_path msi_path in + Firstboot.add_firstboot_script g inspect.i_root +-- +2.31.1 + diff --git a/0046-v2v-Force-format-of-input-to-be-specified.patch b/0046-v2v-Force-format-of-input-to-be-specified.patch new file mode 100644 index 0000000..f8a42f9 --- /dev/null +++ b/0046-v2v-Force-format-of-input-to-be-specified.patch @@ -0,0 +1,211 @@ +From 350baba10cbef38f7e2829927c2768c7f913e82f Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 23 Nov 2021 09:58:50 +0000 +Subject: [PATCH] v2v: Force format of input to be specified + +qemu 6.1 unnecessarily insists on the backing format of files being +set. Change the type of the input disk so the format is no longer an +option, but must be set by the input mode. + +This change is only required on the 1.44 branch, since modular +virt-v2v uses the qemu-nbd -s (snapshot) option to do the equivalent +which seems to handle the backing format automatically. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2025769 +Reported-by: Vera Wu +(cherry picked from commit 40cfe6da0861ca6360f670e254c71ed923a0402f) +--- + v2v/input_disk.ml | 2 +- + v2v/input_libvirt_vcenter_https.ml | 2 +- + v2v/input_libvirt_vddk.ml | 2 +- + v2v/input_vmx.ml | 2 +- + v2v/parse_libvirt_xml.ml | 13 +++++++++---- + v2v/parse_ovf_from_ova.ml | 2 +- + v2v/types.ml | 9 +++------ + v2v/types.mli | 2 +- + v2v/v2v.ml | 19 +++++++------------ + 9 files changed, 25 insertions(+), 28 deletions(-) + +diff --git a/v2v/input_disk.ml b/v2v/input_disk.ml +index 4e403003..beaa9a4d 100644 +--- a/v2v/input_disk.ml ++++ b/v2v/input_disk.ml +@@ -64,7 +64,7 @@ class input_disk input_format disk = object + let disk = { + s_disk_id = 0; + s_qemu_uri = disk_absolute; +- s_format = Some format; ++ s_format = format; + s_controller = None; + } in + +diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml +index ed2e5eed..f3c55b79 100644 +--- a/v2v/input_libvirt_vcenter_https.ml ++++ b/v2v/input_libvirt_vcenter_https.ml +@@ -84,7 +84,7 @@ object (self) + (* The libvirt ESX driver doesn't normally specify a format, but + * the format of the -flat file is *always* raw, so force it here. + *) +- { disk with s_qemu_uri = qemu_uri; s_format = Some "raw" } ++ { disk with s_qemu_uri = qemu_uri; s_format = "raw" } + ) disks in + + source, disks +diff --git a/v2v/input_libvirt_vddk.ml b/v2v/input_libvirt_vddk.ml +index 75fd146e..9463f6ba 100644 +--- a/v2v/input_libvirt_vddk.ml ++++ b/v2v/input_libvirt_vddk.ml +@@ -187,7 +187,7 @@ object (self) + (* nbdkit always presents us with the raw disk blocks from + * the guest, so force the format to raw here. + *) +- { disk with s_qemu_uri = qemu_uri; s_format = Some "raw" } ++ { disk with s_qemu_uri = qemu_uri; s_format = "raw" } + ) disks in + + source, disks +diff --git a/v2v/input_vmx.ml b/v2v/input_vmx.ml +index 7a7647e5..a4ed999a 100644 +--- a/v2v/input_vmx.ml ++++ b/v2v/input_vmx.ml +@@ -190,7 +190,7 @@ and find_hdds ?bandwidth input_password vmx vmx_source + let uri, format = qemu_uri_of_filename ?bandwidth input_password + vmx_source filename in + let s = { s_disk_id = (-1); +- s_qemu_uri = uri; s_format = Some format; ++ s_qemu_uri = uri; s_format = format; + s_controller = Some controller } in + Some (c, t, s) + | _ -> None +diff --git a/v2v/parse_libvirt_xml.ml b/v2v/parse_libvirt_xml.ml +index fffc5a24..27e08135 100644 +--- a/v2v/parse_libvirt_xml.ml ++++ b/v2v/parse_libvirt_xml.ml +@@ -270,9 +270,10 @@ let parse_libvirt_xml ?bandwidth ?conn xml = + + let format = + match xpath_string "driver/@type" with +- | Some "aio" -> Some "raw" (* Xen wierdness *) +- | None -> None +- | Some format -> Some format in ++ | Some "aio" -> "raw" (* Xen wierdness *) ++ | Some format -> format ++ | None -> ++ error (f_" attribute is missing from the libvirt XML") in + + (* The attribute may be 'block', 'file', + * 'network' or 'volume'. We ignore any other types. +@@ -339,7 +340,11 @@ let parse_libvirt_xml ?bandwidth ?conn xml = + let xpath_string = Xpath_helpers.xpath_string xpathctx in + + (* Use the format specified in the volume itself. *) +- let format = xpath_string "/volume/target/format/@type" in ++ let format = ++ match xpath_string "/volume/target/format/@type" with ++ | Some format -> format ++ | None -> ++ error (f_". attribute is missing from the libvirt XML of volume %s") vol in + + (match xpath_string "/volume/@type" with + | None | Some "file" -> +diff --git a/v2v/parse_ovf_from_ova.ml b/v2v/parse_ovf_from_ova.ml +index 758718a2..bc795166 100644 +--- a/v2v/parse_ovf_from_ova.ml ++++ b/v2v/parse_ovf_from_ova.ml +@@ -157,7 +157,7 @@ and parse_disks xpathctx = + source_disk = { + s_disk_id = i; + s_qemu_uri = ""; +- s_format = Some "vmdk"; ++ s_format = "vmdk"; + s_controller = controller; + }; + href = href; +diff --git a/v2v/types.ml b/v2v/types.ml +index 53daefed..e04bfacf 100644 +--- a/v2v/types.ml ++++ b/v2v/types.ml +@@ -56,7 +56,7 @@ and source_firmware = + and source_disk = { + s_disk_id : int; + s_qemu_uri : string; +- s_format : string option; ++ s_format : string; + s_controller : s_controller option; + } + and s_controller = Source_IDE | Source_SATA | Source_SCSI | +@@ -197,11 +197,8 @@ and string_of_source_firmware = function + + and string_of_source_disk { s_qemu_uri = qemu_uri; s_format = format; + s_controller = controller } = +- sprintf "\t%s%s%s" +- qemu_uri +- (match format with +- | None -> "" +- | Some format -> " (" ^ format ^ ")") ++ sprintf "\t%s (%s)%s" ++ qemu_uri format + (match controller with + | None -> "" + | Some controller -> " [" ^ string_of_controller controller ^ "]") +diff --git a/v2v/types.mli b/v2v/types.mli +index a9b0a70e..61a19eea 100644 +--- a/v2v/types.mli ++++ b/v2v/types.mli +@@ -103,7 +103,7 @@ and source_firmware = + and source_disk = { + s_disk_id : int; (** A unique ID for each source disk. *) + s_qemu_uri : string; (** QEMU URI of source disk. *) +- s_format : string option; (** Format. *) ++ s_format : string; (** Format of source disk. *) + s_controller : s_controller option; (** Controller, eg. IDE, SCSI. *) + } + (** A source disk. *) +diff --git a/v2v/v2v.ml b/v2v/v2v.ml +index 8af86687..203b93f1 100644 +--- a/v2v/v2v.ml ++++ b/v2v/v2v.ml +@@ -293,12 +293,11 @@ and create_overlays source_disks = + * should allow us to fstrim/blkdiscard and avoid copying + * significant parts of the data over the wire. + *) +- let options = +- "compat=1.1" ^ +- (match format with None -> "" +- | Some fmt -> ",backing_fmt=" ^ fmt) in +- let cmd = [ "qemu-img"; "create"; "-q"; "-f"; "qcow2"; "-b"; qemu_uri; +- "-o"; options; overlay_file ] in ++ let cmd = [ "qemu-img"; "create"; "-q"; ++ "-o"; "compat=1.1"; ++ "-b"; qemu_uri; "-F"; format; ++ "-f"; "qcow2"; ++ overlay_file ] in + if run_command cmd <> 0 then + error (f_"qemu-img command failed, see earlier errors"); + +@@ -344,7 +343,7 @@ and populate_overlays g overlays = + and populate_disks g source_disks = + List.iter ( + fun ({s_qemu_uri = qemu_uri; s_format = format}) -> +- g#add_drive_opts qemu_uri ?format ~cachemode:"unsafe" ++ g#add_drive_opts qemu_uri ~format ~cachemode:"unsafe" + ~discard:"besteffort" + ) source_disks + +@@ -604,11 +603,7 @@ and get_target_formats cmdline output overlays = + | None -> + match cmdline.output_format with + | Some format -> format +- | None -> +- match ov.ov_source.s_format with +- | Some format -> format +- | None -> +- error (f_"disk %s (%s) has no defined format.\n\nThe input metadata did not define the disk format (eg. raw/qcow2/etc) of this disk, and so virt-v2v will try to autodetect the format when reading it.\n\nHowever because the input format was not defined, we do not know what output format you want to use. You have two choices: either define the original format in the source metadata, or use the ‘-of’ option to force the output format.") ov.ov_sd ov.ov_source.s_qemu_uri in ++ | None -> ov.ov_source.s_format in + + (* What really happens here is that the call to #disk_create + * below fails if the format is not raw or qcow2. We would +-- +2.31.1 + diff --git a/0047-v2v-Cope-with-libvirt-vpx-esx-driver-which-does-not-.patch b/0047-v2v-Cope-with-libvirt-vpx-esx-driver-which-does-not-.patch new file mode 100644 index 0000000..5d26d0c --- /dev/null +++ b/0047-v2v-Cope-with-libvirt-vpx-esx-driver-which-does-not-.patch @@ -0,0 +1,44 @@ +From 992af0707ad54d39ec707da6daa6c4ca7c3fc69a Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Wed, 24 Nov 2021 11:23:38 +0000 +Subject: [PATCH] v2v: Cope with libvirt vpx/esx driver which does not set + format + +See discussion in this bug: +https://bugzilla.redhat.com/show_bug.cgi?id=2026199 + +Fixes: commit 40cfe6da0861ca6360f670e254c71ed923a0402f +(cherry picked from commit 59dc3293a9b4fdf11da8571c50e3e5badbb511c2) +--- + v2v/parse_libvirt_xml.ml | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/v2v/parse_libvirt_xml.ml b/v2v/parse_libvirt_xml.ml +index 27e08135..e65fbf4a 100644 +--- a/v2v/parse_libvirt_xml.ml ++++ b/v2v/parse_libvirt_xml.ml +@@ -273,7 +273,11 @@ let parse_libvirt_xml ?bandwidth ?conn xml = + | Some "aio" -> "raw" (* Xen wierdness *) + | Some format -> format + | None -> +- error (f_" attribute is missing from the libvirt XML") in ++ (* Some libvirt drivers don't set the format. Typically ++ * this is the vpx/esx driver (see RHBZ#2026199). We ++ * can assume "raw", as it will be overwritten later. ++ *) ++ "raw" in + + (* The attribute may be 'block', 'file', + * 'network' or 'volume'. We ignore any other types. +@@ -344,7 +348,7 @@ let parse_libvirt_xml ?bandwidth ?conn xml = + match xpath_string "/volume/target/format/@type" with + | Some format -> format + | None -> +- error (f_". attribute is missing from the libvirt XML of volume %s") vol in ++ error (f_" attribute is missing from the libvirt XML of volume %s") vol in + + (match xpath_string "/volume/@type" with + | None | Some "file" -> +-- +2.31.1 + diff --git a/0048-o-rhv-upload-wait-for-VM-creation-task.patch b/0048-o-rhv-upload-wait-for-VM-creation-task.patch new file mode 100644 index 0000000..138966c --- /dev/null +++ b/0048-o-rhv-upload-wait-for-VM-creation-task.patch @@ -0,0 +1,182 @@ +From 8036ab4bc8f37030fcaceda14678cb14dbbed547 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Golembiovsk=C3=BD?= +Date: Wed, 20 Apr 2022 17:14:26 +0200 +Subject: [PATCH] -o rhv-upload: wait for VM creation task +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +oVirt API call for VM creation finishes before the VM is actually +created. Entities may be still locked after virt-v2v terminates and if +user tries to perform (scripted) actions after virt-v2v those operations +may fail. To prevent this it is useful to monitor the task and wait for +the completion. This will also help to prevent some corner case +scenarios (that would be difficult to debug) when the VM creation job +fails after virt-v2v already termintates with success. + +Thanks: Nir Soffer +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1985827 +Signed-off-by: Tomáš Golembiovský +Reviewed-by: Arik Hadas +Reviewed-by: Nir Soffer +(cherry picked from commit 291edb363e841e1c555954a070def671a651cfab) +--- + .../ovirtsdk4/__init__.py | 10 +++- + .../ovirtsdk4/types.py | 19 +++++++ + v2v/rhv-upload-createvm.py | 57 ++++++++++++++++++- + 3 files changed, 84 insertions(+), 2 deletions(-) + +diff --git a/tests/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py b/tests/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py +index abb7050c..ba0649cb 100644 +--- a/tests/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py ++++ b/tests/test-v2v-o-rhv-upload-module/ovirtsdk4/__init__.py +@@ -63,6 +63,9 @@ class SystemService(object): + def disks_service(self): + return DisksService() + ++ def jobs_service(self): ++ return JobsService() ++ + def image_transfers_service(self): + return ImageTransfersService() + +@@ -108,6 +111,11 @@ class DisksService(object): + return DiskService(disk_id) + + ++class JobsService(object): ++ def list(self, search=None): ++ return [types.Job()] ++ ++ + class ImageTransferService(object): + def __init__(self): + self._finalized = False +@@ -139,7 +147,7 @@ class StorageDomainsService(object): + + + class VmsService(object): +- def add(self, vm): ++ def add(self, vm, query=None): + return vm + + def list(self, search=None): +diff --git a/tests/test-v2v-o-rhv-upload-module/ovirtsdk4/types.py b/tests/test-v2v-o-rhv-upload-module/ovirtsdk4/types.py +index 732887aa..8e734756 100644 +--- a/tests/test-v2v-o-rhv-upload-module/ovirtsdk4/types.py ++++ b/tests/test-v2v-o-rhv-upload-module/ovirtsdk4/types.py +@@ -138,6 +138,25 @@ class Initialization(object): + pass + + ++class JobStatus(Enum): ++ ABORTED = "aborted" ++ FAILED = "failed" ++ FINISHED = "finished" ++ STARTED = "started" ++ UNKNOWN = "unknown" ++ ++ def __init__(self, image): ++ self._image = image ++ ++ def __str__(self): ++ return self._image ++ ++ ++class Job(object): ++ description = "Fake job" ++ status = JobStatus.FINISHED ++ ++ + class StorageDomain(object): + def __init__(self, name=None): + pass +diff --git a/v2v/rhv-upload-createvm.py b/v2v/rhv-upload-createvm.py +index 50bb7e34..8887c52b 100644 +--- a/v2v/rhv-upload-createvm.py ++++ b/v2v/rhv-upload-createvm.py +@@ -19,12 +19,54 @@ + import json + import logging + import sys ++import time ++import uuid + + from urllib.parse import urlparse + + import ovirtsdk4 as sdk + import ovirtsdk4.types as types + ++ ++def debug(s): ++ if params['verbose']: ++ print(s, file=sys.stderr) ++ sys.stderr.flush() ++ ++ ++def jobs_completed(system_service, correlation_id): ++ jobs_service = system_service.jobs_service() ++ ++ try: ++ jobs = jobs_service.list( ++ search="correlation_id=%s" % correlation_id) ++ except sdk.Error as e: ++ debug( ++ "Error searching for jobs with correlation id %s: %s" % ++ (correlation_id, e)) ++ # We don't know, assume that jobs did not complete yet. ++ return False ++ ++ # STARTED is the only "in progress" status, anything else means the job ++ # has already terminated. ++ if all(job.status != types.JobStatus.STARTED for job in jobs): ++ failed_jobs = [(job.description, str(job.status)) ++ for job in jobs ++ if job.status != types.JobStatus.FINISHED] ++ if failed_jobs: ++ raise RuntimeError( ++ "Failed to create a VM! Failed jobs: %r" % failed_jobs) ++ return True ++ else: ++ running_jobs = [(job.description, str(job.status)) for job in jobs] ++ debug("Some jobs with correlation id %s are running: %s" % ++ (correlation_id, running_jobs)) ++ return False ++ ++ ++# Seconds to wait for the VM import job to complete in oVirt. ++timeout = 3 * 60 ++ + # Parameters are passed in via a JSON doc from the OCaml code. + # Because this Python code ships embedded inside virt-v2v there + # is no formal API here. +@@ -67,6 +109,7 @@ system_service = connection.system_service() + cluster = system_service.clusters_service().cluster_service(params['rhv_cluster_uuid']) + cluster = cluster.get() + ++correlation_id = str(uuid.uuid4()) + vms_service = system_service.vms_service() + vm = vms_service.add( + types.Vm( +@@ -77,5 +120,17 @@ vm = vms_service.add( + data=ovf, + ) + ) +- ) ++ ), ++ query={'correlation_id': correlation_id}, + ) ++ ++# Wait for the import job to finish. ++endt = time.monotonic() + timeout ++while True: ++ time.sleep(10) ++ if jobs_completed(system_service, correlation_id): ++ break ++ if time.monotonic() > endt: ++ raise RuntimeError( ++ "Timed out waiting for VM creation!" ++ " Jobs still running for correlation id %s" % correlation_id) +-- +2.31.1 + diff --git a/0049-tests-Add-test-of-i-ova-from-a-directory.patch b/0049-tests-Add-test-of-i-ova-from-a-directory.patch new file mode 100644 index 0000000..b158e7d --- /dev/null +++ b/0049-tests-Add-test-of-i-ova-from-a-directory.patch @@ -0,0 +1,96 @@ +From 7748be2af952898c9c38d02e9a539c71cbfbb56b Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 25 May 2021 10:13:00 +0100 +Subject: [PATCH] tests: Add test of -i ova from a directory. + +This was not tested previously. + +(cherry picked from commit a00ce662cb33c33706a013ff98ff89244cd14667) +--- + tests/Makefile.am | 2 ++ + tests/test-v2v-i-ova-directory.sh | 53 +++++++++++++++++++++++++++++++ + 2 files changed, 55 insertions(+) + create mode 100755 tests/test-v2v-i-ova-directory.sh + +diff --git a/tests/Makefile.am b/tests/Makefile.am +index eee4e1af..e4b907fe 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -58,6 +58,7 @@ TESTS = \ + test-v2v-copy-to-local.sh \ + test-v2v-i-ova-bad-sha1.sh \ + test-v2v-i-ova-bad-sha256.sh \ ++ test-v2v-i-ova-directory.sh \ + test-v2v-i-ova-formats.sh \ + test-v2v-i-ova-good-checksums.sh \ + test-v2v-i-ova-gz.sh \ +@@ -185,6 +186,7 @@ EXTRA_DIST += \ + test-v2v-i-ova-bad-sha1.sh \ + test-v2v-i-ova-bad-sha256.sh \ + test-v2v-i-ova-checksums.ovf \ ++ test-v2v-i-ova-directory.sh \ + test-v2v-i-ova-formats.expected \ + test-v2v-i-ova-formats.ovf \ + test-v2v-i-ova-formats.sh \ +diff --git a/tests/test-v2v-i-ova-directory.sh b/tests/test-v2v-i-ova-directory.sh +new file mode 100755 +index 00000000..7c593139 +--- /dev/null ++++ b/tests/test-v2v-i-ova-directory.sh +@@ -0,0 +1,53 @@ ++#!/bin/bash - ++# libguestfs virt-v2v test script ++# Copyright (C) 2014-2021 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. ++ ++# Test -i ova option with a directory. ++ ++set -e ++ ++$TEST_FUNCTIONS ++skip_if_skipped ++skip_if_backend uml ++skip_unless_phony_guest windows.img ++ ++skip_unless_libvirt_minimum_version 3 1 0 ++ ++export VIRT_TOOLS_DATA_DIR="$top_srcdir/test-data/fake-virt-tools" ++export VIRTIO_WIN="$top_srcdir/test-data/fake-virtio-win" ++ ++d=test-v2v-i-ova-directory.d ++rm -rf $d ++mkdir $d ++ ++vmdk=test-ova.vmdk ++ovf=test-v2v-i-ova.ovf ++mf=test-ova.mf ++ ++qemu-img convert $top_builddir/test-data/phony-guests/windows.img \ ++ -O vmdk $d/$vmdk ++cp "$srcdir/$ovf" $d/$ovf ++sha1=`do_sha1 $d/$ovf` ++echo "SHA1($ovf)= $sha1" > $d/$mf ++sha256=`do_sha256 $d/$vmdk` ++echo "SHA256($vmdk)= $sha256" >> $d/$mf ++ ++$VG virt-v2v --debug-gc \ ++ -i ova $d \ ++ -o null ++ ++rm -rf $d +-- +2.31.1 + diff --git a/0050-v2v-i-ova-Fix-parsing-if-OVA-directory-name-has-a-tr.patch b/0050-v2v-i-ova-Fix-parsing-if-OVA-directory-name-has-a-tr.patch new file mode 100644 index 0000000..438a929 --- /dev/null +++ b/0050-v2v-i-ova-Fix-parsing-if-OVA-directory-name-has-a-tr.patch @@ -0,0 +1,66 @@ +From 9e52e90cf8d570516d4098584c263c9d8b76c447 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 25 May 2021 10:27:53 +0100 +Subject: [PATCH] v2v: -i ova: Fix parsing if OVA directory name has a trailing + "/" + +If you use an OVA directory with a trailing "/" in the name, virt-v2v +would fail with: + +virt-v2v: error: internal error: assertion failed at parse_ova.ml, line 273, char 15 + +The fix for this is to knock off the trailing "/" if present. + +Reported-by: Xiaodai Wang +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1964324 +(cherry picked from commit f8428f5eaaff6dedc54a40138f760298a7a3a965) +--- + v2v/parse_ova.ml | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/v2v/parse_ova.ml b/v2v/parse_ova.ml +index 568ac5fa..fc413d2a 100644 +--- a/v2v/parse_ova.ml ++++ b/v2v/parse_ova.ml +@@ -57,6 +57,13 @@ and ova_type = + *) + | TarOptimized of string (* tarball *) + ++let string_of_t { orig_ova; top_dir; ova_type } = ++ sprintf "orig_ova = %s, top_dir = %s, ova_type = %s" ++ orig_ova top_dir ++ (match ova_type with ++ | Directory -> "Directory" ++ | TarOptimized tarball -> "TarOptimized " ^ tarball) ++ + type file_ref = + | LocalFile of string + | TarFile of string * string +@@ -122,6 +129,13 @@ let rec parse_ova ova = + (* Exploded path must be absolute (RHBZ#1155121). *) + let top_dir = absolute_path top_dir in + ++ (* top_dir must not end with / except if it == "/" (which is ++ * likely not what you want). (RHBZ#1964324) ++ *) ++ let top_dir = ++ if top_dir = "/" || not (String.is_suffix top_dir "/") then top_dir ++ else String.sub top_dir 0 (String.length top_dir - 1) in ++ + (* If virt-v2v is running as root, and the backend is libvirt, then + * we have to chmod the directory to 0755 and files to 0644 + * so it is readable by qemu.qemu. This is libvirt bug RHBZ#890291. +@@ -136,7 +150,9 @@ let rec parse_ova ova = + ignore (run_command cmd) + ); + +- { orig_ova = ova; top_dir; ova_type } ++ let ova = { orig_ova = ova; top_dir; ova_type } in ++ debug "ova: %s" (string_of_t ova); ++ ova + + (* Return true if [libvirt] supports ["json:"] pseudo-URLs and accepts the + * ["raw"] driver. Function also returns true if [libvirt] backend is not +-- +2.31.1 + diff --git a/SOURCES b/SOURCES new file mode 100644 index 0000000..e5f23a5 --- /dev/null +++ b/SOURCES @@ -0,0 +1,18 @@ +Source Offer + +A complete machine-readable copy of the source code corresponding to +portions of the accompanying package is available upon request. This +offer is valid to anyone in receipt of this information and shall +expire three years following the date of the final distribution of +this package by Red Hat, Inc. + +To obtain such source code, send a check or money order in the amount +of US$10.00 to: + +General Counsel +Red Hat, Inc. +100 East Davie Street +Raleigh, NC 27601 USA + +Please specify the name, version and release of the package for which +you are requesting corresponding source code. diff --git a/copy-patches.sh b/copy-patches.sh new file mode 100755 index 0000000..38f8f37 --- /dev/null +++ b/copy-patches.sh @@ -0,0 +1,55 @@ +#!/bin/bash - + +set -e + +# Maintainer script to copy patches from the git repo to the current +# directory. Use it like this: +# ./copy-patches.sh + +rhel_version=8.7.0 + +# Check we're in the right directory. +if [ ! -f virt-v2v.spec ]; then + echo "$0: run this from the directory containing 'virt-v2v.spec'" + exit 1 +fi + +git_checkout=$HOME/d/virt-v2v-rhel-$rhel_version +if [ ! -d $git_checkout ]; then + echo "$0: $git_checkout does not exist" + echo "This script is only for use by the maintainer when preparing a" + echo "virt-v2v release on RHEL." + exit 1 +fi + +# Get the base version of virt-v2v. +version=`grep '^Version:' virt-v2v.spec | awk '{print $2}'` +tag="v$version" + +# Remove any existing patches. +git rm -f [0-9]*.patch ||: +rm -f [0-9]*.patch + +# Get the patches. +(cd $git_checkout; rm -f [0-9]*.patch; git format-patch -N --submodule=diff $tag) +mv $git_checkout/[0-9]*.patch . + +# Remove any not to be applied. +rm -f *NOT-FOR-RPM*.patch + +# Add the patches. +git add [0-9]*.patch + +# Print out the patch lines. +echo +echo "--- Copy the following text into virt-v2v.spec file" +echo + +echo "# Patches." +for f in [0-9]*.patch; do + n=`echo $f | awk -F- '{print $1}'` + echo "Patch$n: $f" +done + +echo +echo "--- End of text" diff --git a/gating.yaml b/gating.yaml new file mode 100755 index 0000000..c2335de --- /dev/null +++ b/gating.yaml @@ -0,0 +1,8 @@ +# recipients: libvirt-qe +--- !Policy +product_versions: + - rhel-9 +decision_context: osci_compose_gate +rules: + - !PassingTestCaseRule {test_case_name: osci.brew-build.tier0.functional} + - !PassingTestCaseRule {test_case_name: libvirt-ci.v2v.brew-build.gating.x86_64.tier1.functional} diff --git a/libguestfs.keyring b/libguestfs.keyring new file mode 100644 index 0000000..bb3eb55 Binary files /dev/null and b/libguestfs.keyring differ diff --git a/sources b/sources new file mode 100644 index 0000000..8f19c5f --- /dev/null +++ b/sources @@ -0,0 +1,5 @@ +SHA1 (RHEV-Application-Provisioning-Tool.exe_4.43-5) = 130adbc011dc0af736465b813c2b22a600c128c1 +SHA1 (libguestfs.keyring) = 1bbc40f501a7fef9eef2a39b701a71aee2fea7c4 +SHA1 (rhsrvany-fd659e77cdd9da484fdc9dcbe0605c62ec26fa30.tar.gz) = 136ff75deb496e48eb448bc4ae156f3911464a90 +SHA1 (rhsrvany.exe) = 2bd96e478fc004cd323b5bd754c856641877dac6 +SHA1 (virt-v2v-1.42.0.tar.gz) = bdbdc7cca87735af64f7e99c050ead24fa92aa7d diff --git a/tests/basic-test.sh b/tests/basic-test.sh new file mode 100755 index 0000000..17fc7c3 --- /dev/null +++ b/tests/basic-test.sh @@ -0,0 +1,13 @@ +#!/bin/bash - +set -e +set -x + +# This only makes sure that virt-v2v isn't totally broken. +# virt-v2v is extensively tested on real guests by the QE +# team using a mix of automated and manual testing. + +# Fix libvirt. +systemctl restart libvirtd + +virt-builder fedora-30 +virt-v2v -i disk fedora-30.img -o null diff --git a/tests/tests.yml b/tests/tests.yml new file mode 100644 index 0000000..9dae6bd --- /dev/null +++ b/tests/tests.yml @@ -0,0 +1,13 @@ +- hosts: localhost + roles: + - role: standard-test-basic + tags: + - classic + required_packages: + - virt-v2v + - guestfs-tools + - libvirt-daemon-kvm + tests: + - simple: + dir: . + run: ./basic-test.sh diff --git a/virt-v2v-1.42.0.tar.gz.sig b/virt-v2v-1.42.0.tar.gz.sig new file mode 100644 index 0000000..6b56583 --- /dev/null +++ b/virt-v2v-1.42.0.tar.gz.sig @@ -0,0 +1,17 @@ +-----BEGIN PGP SIGNATURE----- + +iQJFBAABCAAvFiEE93dPsa0HSn6Mh2fqkXOPc+G3aKAFAl6YQ9QRHHJpY2hAYW5u +ZXhpYS5vcmcACgkQkXOPc+G3aKAgTBAAiT/ojN14i0NRzpuGSb7I9oupzclVqic8 +c5NIXH8TGYLY9tVMYSsr+uyWu8Qk2lsqV6knXeqbBKot/682v2AlYn6ZpG+cl8tm +ZKjVSwMwLVdAvV5zTaggEO/Xs8WbtSkmTk184s62804qlc+mv0ngFTGZomKjH4o1 +tHgJnegeR/lppeBnIuhAC/hWo6SyhPul8UnDg3rnByWOX7Qs3p4lY9y5hHv2pQfK +ezXLDYBBAtQ3oe3p8jh3SCe7GLxxX8oxDCn6l8K7AK4czRMLJ/iykS/iE+E1bazM +V7rUItPfK3MhrWThlekn4u5tOclCDKbK75Hgkb2qjeK9Ctad80boXnNEnIv0UWFr +SaqCKmJrOtohn2oR/aUmTXm2u09jy+nQTRhvqy/2TNTdExCa1A6n7r0EcEJQMQPX +DK34+cbn3J+/+BA9kyH2a2/pTwJBaCk4PCXyrxWAkHyLUt9HZwmtPXUeBhq/iMIf +QZSo/LgXTTNEpsFx5K3xuvy6Ps/IaImeI8xdU2wl252/HN4wY3roZOBNflbTCF2m +aXFXf6bReZmO9HJg5674zCYkB0N8nSPMaHmv7EWyK7sEMKCUuYnWMiEBHtIZA+dW +Qp3IdoODkjciwVzJL2E7RhA2GNvwnkay4WYqb0mjAPVktVTnhla7S1hSD8SM6Fs7 +sVAPrKAFidk= +=l3OH +-----END PGP SIGNATURE----- diff --git a/virt-v2v.spec b/virt-v2v.spec new file mode 100644 index 0000000..c018566 --- /dev/null +++ b/virt-v2v.spec @@ -0,0 +1,480 @@ +# If we should verify tarball signature with GPGv2. +%global verify_tarball_signature 1 + +# If there are patches which touch autotools files, set this to 1. +%global patches_touch_autotools 1 + +# The source directory. +%global source_directory 1.42-stable + +Name: virt-v2v +Epoch: 1 +Version: 1.42.0 +Release: 19%{?dist} +Summary: Convert a virtual machine to run on KVM + +License: GPLv2+ +URL: https://github.com/libguestfs/virt-v2v + +Source0: http://download.libguestfs.org/virt-v2v/%{source_directory}/%{name}-%{version}.tar.gz +%if 0%{verify_tarball_signature} +Source1: http://download.libguestfs.org/virt-v2v/%{source_directory}/%{name}-%{version}.tar.gz.sig +# Keyring used to verify tarball signature. +Source2: libguestfs.keyring +%endif + +# Architectures where virt-v2v is shipped. +# +# not on aarch64 because it is not useful there +# not on %%{power64} because of RHBZ#1287826 +# not on s390x because it is not useful there +ExclusiveArch: x86_64 + +# RHEL 8 git repository is: +# https://github.com/libguestfs/virt-v2v/tree/rhel-8.6.0 +# Use 'copy-patches.sh' to copy the patches from the git repo +# to the current directory. + +# Patches. +Patch0001: 0001-libvirt-make-use-of-libvirt-s-default-auth-handler-R.patch +Patch0002: 0002-i-libvirt-print-URI-without-connecting-RHBZ-1839917.patch +Patch0003: 0003-vCenter-fix-parsing-of-HTTP-status-string-RHBZ-18373.patch +Patch0004: 0004-v2v-o-libvirt-Remove-cache-none-RHBZ-1837453.patch +Patch0005: 0005-v2v-Remove-extraneous-when-setting-bandwidth-RHBZ-18.patch +Patch0006: 0006-v2v-it-vddk-Don-t-use-nbdkit-readahead-filter-with-V.patch +Patch0007: 0007-v2v-nbdkit-Handle-password-parameter-in-common_creat.patch +Patch0008: 0008-v2v-nbdkit-Don-t-use-password-parameter-RHBZ-1842440.patch +Patch0009: 0009-libosinfo-declare-autocleanup-funcs-with-libosinfo-1.patch +Patch0010: 0010-v2v-Use-common-documentation-for-keys-from-stdin.patch +Patch0011: 0011-docs-Multiple-keys-must-be-supplied-one-per-line-RHB.patch +Patch0012: 0012-v2v-Check-that-mac-ip-parameters-are-sensible-RHBZ-1.patch +Patch0013: 0013-libvirt-read-password-file-outside-libvirt-auth-call.patch +Patch0014: 0014-RHEL-8-v2v-Select-correct-qemu-binary-for-o-qemu-mod.patch +Patch0015: 0015-RHEL-8-v2v-Disable-the-qemu-boot-option-RHBZ-1147313.patch +Patch0016: 0016-RHEL-8-Fix-list-of-supported-sound-cards-to-match-RH.patch +Patch0017: 0017-RHEL-8-Fix-tests-for-libguestfs-winsupport.patch +Patch0018: 0018-RHEL-8-v2v-Disable-the-virt-v2v-in-place-option.patch +Patch0019: 0019-RHEL-8-v2v-i-disk-force-VNC-as-display-RHBZ-1372671.patch +Patch0020: 0020-RHEL-8-v2v-do-not-mention-SUSE-Xen-hosts-RHBZ-143020.patch +Patch0021: 0021-RHEL-8-v2v-rhv-upload-Remove-restriction-on-oa-spars.patch +Patch0022: 0022-RHEL-8-use-platform-python.patch +Patch0023: 0023-RHEL-8-point-to-KB-for-supported-v2v-hypervisors-gue.patch +Patch0024: 0024-v2v-Allow-large-temporary-directory-to-be-set-on-a-g.patch +Patch0025: 0025-v2v-o-openstack-Allow-guests-to-be-converted-to-UEFI.patch +Patch0026: 0026-v2v-Fix-spelling-mistake-in-uninstall-function-name.patch +Patch0027: 0027-v2v-windows-Refactor-uninstallation_commands-functio.patch +Patch0028: 0028-v2v-Replace-broken-VMware-Tools-uninstall-command-ms.patch +#Patch0029: 0029-Update-common-submodule-to-latest-upstream.patch +Patch0030: 0030-v2v-rhv-upload-plugin-Defer-imageio-connection.patch +Patch0031: 0031-v2v-windows-Fix-schtasks-SD-parameter.patch +Patch0032: 0032-v2v-Turn-pnp_wait.exe-warning-into-a-debug-message.patch +Patch0033: 0033-docs-UEFI-guest-conversion-to-o-openstack-is-support.patch +Patch0034: 0034-docs-o-openstack-Clarify-name-of-file-containing-Ope.patch +Patch0035: 0035-v2v-Allow-output-to-block-devices-RHBZ-1868690.patch +Patch0036: 0036-v2v-Disable-readahead-for-VMware-curl-sources-too-RH.patch +Patch0037: 0037-docs-Document-how-to-remove-Out-of-HTTP-sessions-lim.patch +Patch0038: 0038-v2v-Increase-required-free-space-in-Windows-to-100-M.patch +Patch0039: 0039-v2v-windows-Allow-qxldod.inf-as-synonym-for-qxl.inf.patch +Patch0040: 0040-RHEL-8-docs-Fix-version-of-virt-v2v-which-added-UEFI.patch +Patch0041: 0041-v2v-Increase-Linux-minimum-root-filesystem-to-100-MB.patch +Patch0042: 0042-v2v-rhv-upload-plugin-Fix-waiting-for-finalize.patch +Patch0043: 0043-v2v-windows-Do-not-fix-NTFS-heads-in-Windows-Vista-a.patch +Patch0044: 0044-v2v-vcenter-Implement-cookie-scripts.patch +Patch0045: 0045-convert-convert_windows.ml-Handle-date-formats-with-.patch +Patch0046: 0046-v2v-Force-format-of-input-to-be-specified.patch +Patch0047: 0047-v2v-Cope-with-libvirt-vpx-esx-driver-which-does-not-.patch +Patch0048: 0048-o-rhv-upload-wait-for-VM-creation-task.patch +Patch0049: 0049-tests-Add-test-of-i-ova-from-a-directory.patch +Patch0050: 0050-v2v-i-ova-Fix-parsing-if-OVA-directory-name-has-a-tr.patch + +# Patches which apply to the common/ submodule. +# These have to be hand-modified. +Patch1001: 0001-options-Use-new-cryptsetup-open-API-if-available.patch +Patch1002: 0002-options-Use-cryptX-instead-of-luksX-as-the-temporary.patch +Patch1003: 0003-options-Support-Windows-BitLocker-RHBZ-1808977.patch +Patch1004: 0004-options-Ignore-errors-from-guestfs_luks_uuid.patch + +# Use git for patch management. +BuildRequires: git + +%if 0%{patches_touch_autotools} +BuildRequires: autoconf, automake, libtool +%endif + +# RHSRVANY and RHEV-APT, used for Windows virt-v2v conversions. +# RHSRVANY is built from source under Fedora from +# mingw32-srvany-1.0-15.20150115gitfd659e77.fc23.noarch +# RHEV-APT is taken from the RHEV Tools CD +# See https://bugzilla.redhat.com/show_bug.cgi?id=1186850 +Source94: rhsrvany-fd659e77cdd9da484fdc9dcbe0605c62ec26fa30.tar.gz +Source95: SOURCES +Source96: rhsrvany.exe +Source97: RHEV-Application-Provisioning-Tool.exe_4.43-5 + +Source99: copy-patches.sh + +BuildRequires: /usr/bin/pod2man +BuildRequires: gcc +BuildRequires: ocaml >= 4.01 +BuildRequires: libguestfs-devel >= 1:1.42 + +BuildRequires: augeas-devel +BuildRequires: bash-completion +BuildRequires: file-devel +BuildRequires: gettext-devel +BuildRequires: jansson-devel +BuildRequires: libosinfo-devel +BuildRequires: libvirt-devel +BuildRequires: libvirt-daemon-kvm +BuildRequires: libxml2-devel +BuildRequires: pcre-devel +BuildRequires: perl(Sys::Guestfs) +BuildRequires: po4a +BuildRequires: /usr/bin/virsh + +BuildRequires: ocaml-findlib-devel +BuildRequires: ocaml-libguestfs-devel +BuildRequires: ocaml-fileutils-devel +BuildRequires: ocaml-gettext-devel + +BuildRequires: nbdkit-python-plugin + +%if 0%{verify_tarball_signature} +BuildRequires: gnupg2 +%endif + +Requires: libguestfs%{?_isa} >= 1:1.42 +Requires: libguestfs-tools-c >= 1:1.42 + +# For Windows conversions. +Requires: libguestfs-winsupport >= 7.2 + +Requires: gawk +Requires: gzip +Requires: unzip +Requires: curl + +# Ensure the UEFI firmware is available, to properly convert +# EFI guests (RHBZ#1429643). +%ifarch x86_64 +Requires: edk2-ovmf +%endif +%ifarch aarch64 +Requires: edk2-aarch64 +%endif + +# Needed for -it vddk, and -o rhv-upload. +Requires: nbdkit +Requires: nbdkit-curl-plugin +Requires: nbdkit-python-plugin +Requires: nbdkit-ssh-plugin +Requires: nbdkit-vddk-plugin +Requires: platform-python + + +%description +Virt-v2v converts a single guest from a foreign hypervisor to run on +KVM. It can read Linux and Windows guests running on VMware, Xen, +Hyper-V and some other hypervisors, and convert them to KVM managed by +libvirt, OpenStack, oVirt, Red Hat Virtualisation (RHV) or several +other targets. It can modify the guest to make it bootable on KVM and +install virtio drivers so it will run quickly. + + +%package bash-completion +Summary: Bash tab-completion for %{name} +BuildArch: noarch +Requires: bash-completion >= 2.0 +Requires: %{name} = %{epoch}:%{version}-%{release} + +# The bash completion for virt-v2v were shipped with the others of libguestfs: +Obsoletes: libguestfs-bash-completion < 1:1.42.0 + + +%description bash-completion +Install this package if you want intelligent bash tab-completion +for %{name}. + + +%package man-pages-ja +Summary: Japanese (ja) man pages for %{name} +BuildArch: noarch +Requires: %{name} = %{epoch}:%{version}-%{release} + +# The man pages for virt-v2v were shipped with the others of libguestfs: +Obsoletes: libguestfs-man-pages-ja < 1:1.42.0 + +%description man-pages-ja +%{name}-man-pages-ja contains Japanese (ja) man pages +for %{name}. + + +%package man-pages-uk +Summary: Ukrainian (uk) man pages for %{name} +BuildArch: noarch +Requires: %{name} = %{epoch}:%{version}-%{release} + +# The man pages for virt-v2v were shipped with the others of libguestfs: +Obsoletes: libguestfs-man-pages-uk < 1:1.42.0 + +%description man-pages-uk +%{name}-man-pages-uk contains Ukrainian (uk) man pages +for %{name}. + + +%prep +%if 0%{verify_tarball_signature} +tmphome="$(mktemp -d)" +gpgv2 --homedir "$tmphome" --keyring %{SOURCE2} %{SOURCE1} %{SOURCE0} +%endif +%setup -q + +# Use git to manage patches. +# http://rwmj.wordpress.com/2011/08/09/nice-rpm-git-patch-management-trick/ +git init +git config user.email "libguestfs@redhat.com" +git config user.name "libguestfs" +git add . +git commit -a -q -m "%{version} baseline" +git am %{patches} + +%if 0%{patches_touch_autotools} +autoreconf -fi +%endif + + +%build +%configure \ + --with-extra="rhel=%{rhel},release=%{release}" + +make V=1 %{?_smp_mflags} + + +%install +%make_install + +# Virt-tools data directory. +mkdir -p $RPM_BUILD_ROOT%{_datadir}/virt-tools +cp %{SOURCE96} $RPM_BUILD_ROOT%{_datadir}/virt-tools/rhsrvany.exe +cp %{SOURCE97} $RPM_BUILD_ROOT%{_datadir}/virt-tools/rhev-apt.exe + +# Delete the v2v test harness. +rm -r $RPM_BUILD_ROOT%{_libdir}/ocaml/v2v_test_harness +rm -r $RPM_BUILD_ROOT%{_libdir}/ocaml/stublibs/dllv2v_test_harness* +rm $RPM_BUILD_ROOT%{_mandir}/man1/virt-v2v-test-harness.1* + +# Find locale files. +%find_lang %{name} + + +%check +# All tests fail at the moment because of bugs in libvirt blockdev. +# # Tests fail on both armv7 and ppc64le in Fedora 31 because the kernel +# # cannot boot on qemu. +# %ifnarch %{arm} ppc64le + +# # On x86_64 this single test fails with: "virt-v2v: warning: the +# # target hypervisor does not support a x86_64 KVM guest". Missing +# # BuildRequires? +# %ifarch x86_64 +# truncate -s 0 tests/test-v2v-o-libvirt.sh +# %endif + +# # This test fails in mock. +# truncate -s 0 tests/test-v2v-oa-option.sh + +# # Make sure we can see the debug messages (RHBZ#1230160). +# export LIBGUESTFS_DEBUG=1 +# export LIBGUESTFS_TRACE=1 + +# make %{?_smp_mflags} check || { +# cat tests/test-suite.log +# exit 1 +# } + +# %endif + + +%files -f %{name}.lang +%doc COPYING README +%{_bindir}/virt-v2v +%{_bindir}/virt-v2v-copy-to-local +%{_mandir}/man1/virt-v2v.1* +%{_mandir}/man1/virt-v2v-copy-to-local.1* +%{_mandir}/man1/virt-v2v-hacking.1* +%{_mandir}/man1/virt-v2v-input-vmware.1* +%{_mandir}/man1/virt-v2v-input-xen.1* +%{_mandir}/man1/virt-v2v-output-local.1* +%{_mandir}/man1/virt-v2v-output-openstack.1* +%{_mandir}/man1/virt-v2v-output-rhv.1* +%{_mandir}/man1/virt-v2v-release-notes-1.42.1* +%{_mandir}/man1/virt-v2v-support.1* +%{_datadir}/virt-tools + + +%files bash-completion +%doc COPYING +%{_datadir}/bash-completion/completions/virt-v2v +%{_datadir}/bash-completion/completions/virt-v2v-copy-to-local + + +%files man-pages-ja +%doc COPYING +%lang(ja) %{_mandir}/ja/man1/*.1* + + +%files man-pages-uk +%doc COPYING +%lang(uk) %{_mandir}/uk/man1/*.1* + + +%changelog +* Tue Apr 26 2022 Richard W.M. Jones - 1:1.42.0-19 +- Fix assertion failure when parsing OVA dir with trailing slash + resolves: rhbz#2028823 +- For -o rhv-upload wait for VM creation task + resolves: rhbz#1985827 + +* Wed Nov 24 2021 Richard W.M. Jones - 1:1.42.0-18 +- Additional fix for backing file specified without backing format + related: rhbz#2025769 + +* Tue Nov 23 2021 Richard W.M. Jones - 1:1.42.0-17 +- Correct regexps used to fix schtasks command +- Fix backing file specified without backing format + resolves: rhbz#2023279, rhbz#2025769 + +* Fri Oct 29 2021 Richard W.M. Jones - 1:1.42.0-16 +- Implement cookie scripts for more reliable vCenter/HTTPS transfers + resolves: rhbz#2018173 + +* Wed Aug 18 2021 Richard W.M. Jones - 1:1.42.0-15 +- v2v: windows: Do not fix NTFS heads in Windows Vista and later + resolves: rhbz#1995000 + +* Fri Jul 16 2021 Richard W.M. Jones - 1:1.42.0-14 +- v2v: rhv-upload-plugin: Fix waiting for finalize + resolves: rhbz#1976024 + +* Wed Jun 30 2021 Richard W.M. Jones - 1:1.42.0-13 +- docs: Fix version of virt-v2v which added UEFI for OpenStack + related: rhbz#1872100 +- v2v: Increase Linux minimum root filesystem to 100 MB + resolves: rhbz#1764569 + +* Tue May 11 2021 Richard W.M. Jones - 1:1.42.0-12 +- v2v: Fix conversion of BitLocker guests + resolves: rhbz#1959051 + +* Tue Apr 27 2021 Richard W.M. Jones - 1:1.42.0-11 +- v2v: windows: Allow qxldod.inf as synonym for qxl.inf + resolves: rhbz#1926102 +- v2v: Increase required free space in Windows to 100 MB + resolves: rhbz#1949147 +- docs: Document how to remove "Out of HTTP sessions" limit +- v2v: Disable readahead for VMware curl sources too + resolves: rhbz#1848862 +- v2v: Allow output to block devices + resolves: rhbz#1868690 +- docs: -o openstack: Clarify name of file containing OpenStack auth + resolves: rhbz#1871754 +- docs: UEFI guest conversion to -o openstack is supported + resolves: rhbz#1872100 +- v2v: Turn pnp_wait.exe warning into a debug message + resolves: rhbz#1903960 +- v2v: windows: Fix schtasks /SD parameter + resolves: rhbz#1895323 + +* Thu Jan 21 2021 Richard W.M. Jones - 1:1.42.0-9 +- v2v: rhv-upload-plugin: Defer imageio connection + resolves: rhbz#1911568 + +* Tue Jan 19 2021 Richard W.M. Jones - 1:1.42.0-8 +- Replace broken VMware Tools uninstall command msiexec /i with /x. + resolves: rhbz#1917760 + +* Tue Jan 12 2021 Richard W.M. Jones - 1:1.42.0-7 +- Tell virt-v2v where overlay files must be placed +- Allow conversion to UEFI openstack + resolves: rhbz#1820282 rhbz#1872094 + +* Tue Sep 01 2020 Pino Toscano - 1:1.42.0-6 +- Improve the documentation of --keys-from-stdin + resolves: rhbz#1858765 +- Check that --mac :ip: parameters are sensible + resolves: rhbz#1858775 +- -i libvirt: read password file outside libvirt auth callback + resolves: rhbz#1869454 + +* Wed Jun 24 2020 Pino Toscano - 1:1.42.0-5 +- Ship a newer version of rhev-apt.exe + resolves: rhbz#1850000 +- Ship the rhsrvany sources with a note for them, as requested by + Red Hat Legal. +- -i libvirt: ask for the password ourselves instead of letting nbdkit + ask for it (and potentially time out) + related: rhbz#1838425 +- Fix build with libosinfo >= 1.8.0 + resolves: rhbz#1850423 + +* Thu May 28 2020 Pino Toscano - 1:1.42.0-4 +- -i libvirt: ask again for the password when -ip is not specified + resolves: rhbz#1838425 +- -i libvirt: print URI without connecting + resolves: rhbz#1839917 +- Handle HTTP/2 replies from vCenter + resolves: rhbz#1840126 +- -o libvirt: remove cache=none from disks + resolves: rhbz#1837453 +- Fix parameters for the nbdkit rate filter + resolves: rhbz#1841096 +- -it vddk: do not use the nbdkit readahead filter with VDDK + resolves: rhbz#1832805 + +* Wed May 06 2020 Pino Toscano - 1:1.42.0-3 +- Actually fix epoch dependencies. +- Fix virt-v2v-man-pages-uk migration from libguestfs-man-pages-uk. + +* Wed May 06 2020 Pino Toscano - 1:1.42.0-2 +- Bump the libguestfs requirement to 1.42.0. +- Bump the epoch to 1 to match the version virt-v2v had when built from + the libguestfs source. + +* Thu Apr 16 2020 Richard W.M. Jones - 1.42.0-1 +- New upstream stable version 1.42.0. + +* Sat Apr 04 2020 Richard W.M. Jones - 1.41.8-11 +- Update all OCaml dependencies for RPM 4.16. + +* Thu Feb 27 2020 Richard W.M. Jones - 1.41.8-10 +- OCaml 4.10.0 final. + +* Fri Jan 31 2020 Fedora Release Engineering - 1.41.8-9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Sun Jan 19 2020 Richard W.M. Jones - 1.41.8-8 +- Bump release and rebuild. + +* Sun Jan 19 2020 Richard W.M. Jones - 1.41.8-7 +- Bump release and rebuild. + +* Sun Jan 19 2020 Richard W.M. Jones - 1.41.8-6 +- Bump release and rebuild. + +* Sun Jan 19 2020 Richard W.M. Jones - 1.41.8-5 +- OCaml 4.10.0+beta1 rebuild. +- Use nbdkit-python-plugin (now all Python 3 in Rawhide). + +* Wed Nov 27 2019 Richard W.M. Jones - 1.41.8-4 +- Use license instead of doc for COPYING file. +- Include license in all subpackages. +- Use gpgverify macro. +- Don't own bash-completion directory because we Require the + bash-completion package which owns it already. + +* Tue Nov 26 2019 Richard W.M. Jones - 1.41.8-2 +- Fix permissions on .sig file. +- Disable -oa preallocated test since it fails in reviewers mock environment. + +* Fri Nov 15 2019 Richard W.M. Jones - 1.41.8-1 +- Initial release of separate virt-v2v program, was part of libguestfs.