From 7aef365762b549500ff59105adbe4ce4a28a6147 Mon Sep 17 00:00:00 2001 From: Srihari Parimi Date: Tue, 18 Aug 2026 07:08:20 -0400 Subject: [PATCH] Fix missing libxslt library after VMware to OpenShift VM migration resolves: RHEL-233944 Fix online-disks firstboot script under PowerShell Constrained Language Mode resolves: RHEL-210639 Fix delay during open-vm-tools removal when RHSM is unreachable resolves: RHEL-214049 Allow qemu-guest-agent install to skip unreachable guest repos resolves: RHEL-217581 Fix conversion pod crash during SELinux relabeling of large XFS filesystems resolves: RHEL-222316 Prevent multiple appliance launches for virtio-win.iso content resolves: RHEL-124850 --- ...linux.ml-Use-yum-dnf-clean_requireme.patch | 38 ++ 0012-common-update-submodule.patch | 455 ++++++++++++++++++ ...dd-new-selinux-relabel-excludes-flag.patch | 38 ++ 0014-common-update-submodule.patch | 275 +++++++++++ copy-patches.sh | 1 + virt-v2v.spec | 20 +- 6 files changed, 826 insertions(+), 1 deletion(-) create mode 100644 0011-convert-convert_linux.ml-Use-yum-dnf-clean_requireme.patch create mode 100644 0012-common-update-submodule.patch create mode 100644 0013-mlcustomize-Add-new-selinux-relabel-excludes-flag.patch create mode 100644 0014-common-update-submodule.patch diff --git a/0011-convert-convert_linux.ml-Use-yum-dnf-clean_requireme.patch b/0011-convert-convert_linux.ml-Use-yum-dnf-clean_requireme.patch new file mode 100644 index 0000000..62f0adc --- /dev/null +++ b/0011-convert-convert_linux.ml-Use-yum-dnf-clean_requireme.patch @@ -0,0 +1,38 @@ +From 785e1f1782025a7fdb79a5cb663a806294a73350 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 7 Aug 2026 15:48:48 +0100 +Subject: [PATCH] convert/convert_linux.ml: Use yum/dnf + clean_requirements_on_remove=False + +When removing packages, use the yum or dnf option +--setopt=clean_requirements_on_remove=False (in dnf this is also known +as --no-autoremove). This removes only the named package, not +dependencies. This is in the interests of making the most minimal +change possible to the guest during conversion. + +Update the common submodule: + + Richard W.M. Jones (1): + mlcustomize/guest_packages.ml: Add clean_requirements_on_remove option + +Fixes: https://redhat.atlassian.net/browse/RHEL-233944 +(cherry picked from commit af8fbd3ea0e24cc8cfb4297724916db87a36ad04) +--- + convert/convert_linux.ml | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/convert/convert_linux.ml b/convert/convert_linux.ml +index 979b3581..72220830 100644 +--- a/convert/convert_linux.ml ++++ b/convert/convert_linux.ml +@@ -1453,7 +1453,9 @@ fi + and uninstall_packages_nonfatal pkgs = + if pkgs <> [] then ( + let cmd = +- try Guest_packages.uninstall_command pkgs inspect.i_package_management ++ try ++ Guest_packages.uninstall_command ~clean_requirements_on_remove:false ++ pkgs inspect.i_package_management + with + | Guest_packages.Unknown_package_manager msg + | Guest_packages.Unimplemented_package_manager msg -> diff --git a/0012-common-update-submodule.patch b/0012-common-update-submodule.patch new file mode 100644 index 0000000..d670d48 --- /dev/null +++ b/0012-common-update-submodule.patch @@ -0,0 +1,455 @@ +From ff3a5eace1a749e31d224ae5640f1c267c519ac5 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Sat, 8 Aug 2026 08:08:18 +0100 +Subject: [PATCH] common: update submodule + + Richard W.M. Jones (2): + mlcustomize/firstboot.ml: Print the version of Windows + mlcustomize/firstboot.ml: Use rem for comments (instead of '::') + +(cherry picked from commit da0c19d25df40e31d6bf7c8f349478ddf616e02b) +--- + common | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Submodule common f865077d..b3841fbc: +diff --git a/common/mlcustomize/SELinux_relabel.ml b/common/mlcustomize/SELinux_relabel.ml +index 62450e41..3fd97221 100644 +--- a/common/mlcustomize/SELinux_relabel.ml ++++ b/common/mlcustomize/SELinux_relabel.ml +@@ -28,11 +28,11 @@ module G = Guestfs + * [libguestfs.git/daemon/selinux.ml]. + *) + +-let rec relabel (g : G.guestfs) = ++let rec relabel (g : G.guestfs) excludes = + (* Is the guest using SELinux? (Otherwise this is a no-op). *) + if is_selinux_guest g then ( + try +- use_setfiles g; ++ use_setfiles g excludes; + (* That worked, so we don't need to autorelabel. *) + g#rm_f "/.autorelabel" + with Failure _ -> +@@ -47,7 +47,7 @@ and is_selinux_guest g = + g#is_file ~followsymlinks:true "/usr/sbin/load_policy" && + g#is_file ~followsymlinks:true "/etc/selinux/config" + +-and use_setfiles g = ++and use_setfiles g excludes = + (* Is setfiles / SELinux relabelling functionality available? *) + if not (g#feature_available [| "selinuxrelabel" |]) then + failwith "no selinux relabel feature"; +@@ -121,5 +121,8 @@ and use_setfiles g = + List.sort compare |> (* sort them for consistency *) + Array.of_list in + ++ (* Excludes is actually a string array, not string list. *) ++ let excludes = Array.of_list excludes in ++ + (* Relabel everything. *) +- g#setfiles specfile mps ++ g#setfiles ~excludes specfile mps +diff --git a/common/mlcustomize/SELinux_relabel.mli b/common/mlcustomize/SELinux_relabel.mli +index 7b4f7ff2..5f1ae7ff 100644 +--- a/common/mlcustomize/SELinux_relabel.mli ++++ b/common/mlcustomize/SELinux_relabel.mli +@@ -18,12 +18,19 @@ + + (** SELinux-relabel the filesystem. *) + +-val relabel : Guestfs.guestfs -> unit ++val relabel : Guestfs.guestfs -> string list -> unit + (** Relabel the mounted guestfs filesystem using the current SELinux + policy that applies to the guest. + + If the guest does not look like it uses SELinux, this does nothing. + ++ The parameters are the guestfs handle and a list of directories ++ that may be excluded (by passing I<--selinux-relabel-exclude> ++ one or more times). ++ + In case relabelling is not possible (since it is an optional + feature which requires the setfiles(8) program), instead we +- fall back to touching [/.autorelabel]. *) ++ fall back to touching [/.autorelabel]. ++ ++ The excludes list only affects setfiles relabelling, ++ not [/.autorelabel] since we do not control how that works. *) +diff --git a/common/mlcustomize/customize-options.pod b/common/mlcustomize/customize-options.pod +index 95767cc7..f6e68f1e 100644 +--- a/common/mlcustomize/customize-options.pod ++++ b/common/mlcustomize/customize-options.pod +@@ -386,6 +386,22 @@ It cannot delete directories, only regular files. + + This is a compatibility option that does nothing. + ++=item B<--selinux-relabel-exclude> DIR ++ ++Exclude directories from being relabelled. ++ ++This advanced option lets you list directories in the guest which ++should not be relabelled, even when SELinux relabelling is ++enabled. Use this carefully, as any changes that are made ++inside these directories during customization will have incorrect ++SELinux labels, leading to potential failures later, so you must ++be sure that the directories do not need relabelling. ++ ++If in doubt, do not use this option. ++ ++You can pass the option multiple times, eg. ++I<--selinux-relabel-exclude=/foo> I<--selinux-relabel-exclude=/bar> ++ + =item B<--ssh-inject> USER[:SELECTOR] + + Inject an ssh key so the given C will be able to log in over +diff --git a/common/mlcustomize/customize-synopsis.pod b/common/mlcustomize/customize-synopsis.pod +index f5eeb69d..d6c4a280 100644 +--- a/common/mlcustomize/customize-synopsis.pod ++++ b/common/mlcustomize/customize-synopsis.pod +@@ -14,4 +14,4 @@ + [--truncate-recursive PATH] [--uninstall PKG,PKG..] [--update] + [--upload FILE:DEST] [--write FILE:CONTENT] [--no-logfile] + [--password-crypto md5|sha256|sha512] [--no-selinux-relabel] +- [--selinux-relabel] ++ [--selinux-relabel] [--selinux-relabel-exclude DIR] +diff --git a/common/mlcustomize/customize_cmdline.ml b/common/mlcustomize/customize_cmdline.ml +index b8eda519..24e05dc9 100644 +--- a/common/mlcustomize/customize_cmdline.ml ++++ b/common/mlcustomize/customize_cmdline.ml +@@ -115,6 +115,8 @@ and flags = { + (* --no-selinux-relabel *) + selinux_relabel_ignored : bool; + (* --selinux-relabel *) ++ selinux_relabel_excludes : string list; ++ (* --selinux-relabel-exclude *) + } + + type argspec = Getopt.keys * Getopt.spec * Getopt.doc +@@ -125,6 +127,7 @@ let rec argspec ?(v2v = false) () = + let password_crypto = ref None in + let no_selinux_relabel = ref false in + let selinux_relabel_ignored = ref false in ++ let selinux_relabel_excludes = ref [] in + + let rec get_ops () = { + ops = List.rev !ops; +@@ -135,6 +138,7 @@ let rec argspec ?(v2v = false) () = + password_crypto = !password_crypto; + no_selinux_relabel = !no_selinux_relabel; + selinux_relabel_ignored = !selinux_relabel_ignored; ++ selinux_relabel_excludes = !selinux_relabel_excludes; + } + in + +@@ -488,6 +492,15 @@ let rec argspec ?(v2v = false) () = + s_"Compatibility option doing nothing" + ), + None, "This is a compatibility option that does nothing.", false; ++ ( ++ [ L"selinux-relabel-exclude" ], ++ Getopt.String ( ++ s_"DIR", ++ List.push_back selinux_relabel_excludes ++ ), ++ s_"Exclude directories from SELinux relabelling" ++ ), ++ Some "DIR", "Exclude directories from being relabelled.\n\nThis advanced option lets you list directories in the guest which\nshould not be relabelled, even when SELinux relabelling is\nenabled. Use this carefully, as any changes that are made\ninside these directories during customization will have incorrect\nSELinux labels, leading to potential failures later, so you must\nbe sure that the directories do not need relabelling.\n\nIf in doubt, do not use this option.\n\nYou can pass the option multiple times, eg.\nI<--selinux-relabel-exclude=/foo> I<--selinux-relabel-exclude=/bar>", false; + ] + and customize_read_from_file filename = + let forbidden_commands = [ +diff --git a/common/mlcustomize/customize_cmdline.mli b/common/mlcustomize/customize_cmdline.mli +index baacda9d..abe10953 100644 +--- a/common/mlcustomize/customize_cmdline.mli ++++ b/common/mlcustomize/customize_cmdline.mli +@@ -107,17 +107,24 @@ and flags = { + (* --no-selinux-relabel *) + selinux_relabel_ignored : bool; + (* --selinux-relabel *) ++ selinux_relabel_excludes : string list; ++ (* --selinux-relabel-exclude *) + } + + type argspec = Getopt.keys * Getopt.spec * Getopt.doc + val argspec : ?v2v:bool -> unit -> (argspec * string option * string) list * (unit -> ops) +-(** This returns a pair [(list, get_ops)]. ++(** Return the argspec (a list of arguments, see {!Getopt} module) ++ with the full list of virt-customize options. ++ ++ If the parameter [~v2v] is true then this excludes parameters ++ that should be excluded from virt-v2v. For example ++ [--inject-qemu-ga] is excluded from the list because virt-v2v ++ decides itself whether and how to inject the QEMU guest agent. ++ ++ This returns a pair [(list, get_ops)]. + + [list] is a list of the command line arguments, plus some extra data. + + [get_ops] is a function you can call {i after} command line parsing + which will return the actual operations specified by the user on the +- command line. +- +- If the parameter [~v2v] is true then this excludes parameters +- that should be excluded from virt-v2v. *) +\ No newline at end of file ++ command line. This can be passed to {!Customize_run.run} *) +\ No newline at end of file +diff --git a/common/mlcustomize/customize_run.ml b/common/mlcustomize/customize_run.ml +index 1baf0f3c..4878c00f 100644 +--- a/common/mlcustomize/customize_run.ml ++++ b/common/mlcustomize/customize_run.ml +@@ -361,7 +361,7 @@ let run (g : G.guestfs) root (ops : ops) = + + if not ops.flags.no_selinux_relabel then ( + message (f_"SELinux relabelling"); +- SELinux_relabel.relabel g ++ SELinux_relabel.relabel g ops.flags.selinux_relabel_excludes + ); + + (* Clean up the log file: +diff --git a/common/mlcustomize/firstboot.ml b/common/mlcustomize/firstboot.ml +index 366beca9..74342be8 100644 +--- a/common/mlcustomize/firstboot.ml ++++ b/common/mlcustomize/firstboot.ml +@@ -299,12 +299,13 @@ exit /b + :main + echo starting firstboot service + echo effective user: %%USERNAME%% domain: %%USERDOMAIN%% ++ver + + if not exist "%%scripts_done%%" ( + mkdir "%%scripts_done%%" + ) + +-:: Pick the next script to run. ++rem Pick the next script to run. + for %%%%f in ("%%scripts%%"\*.bat) do ( + echo running "%%%%f" + pushd "%%scripts%%" +@@ -320,23 +321,23 @@ for %%%%f in ("%%scripts%%"\*.bat) do ( + echo Script failed, will retry on next boot + ) + +- :: Reboot the computer only if exit code indicates. +- :: Exit code 250 means do not reboot, otherwise reboot +- :: Reboot is necessary to free any locked files which +- :: may prevent later scripts from running. ++ rem Reboot the computer only if exit code indicates. ++ rem Exit code 250 means do not reboot, otherwise reboot. ++ rem Reboot is necessary to free any locked files which ++ rem may prevent later scripts from running. + if !elvl! NEQ 250 ( + shutdown /r /t 0 /y + +- :: Exit the script (in case shutdown returns before rebooting). +- :: On next boot, the whole firstboot service will be called again. +- ++ rem Exit the script (in case shutdown returns before ++ rem rebooting). On next boot, the whole firstboot ++ rem service will be called again. + exit /b + ) + ) + +-:: Fallthrough here if there are no scripts. ++rem Fallthrough here if there are no scripts. + +-:: Touch a sentinel file to say we have finished. ++rem Touch a sentinel file to say we have finished. + type nul > "%%firstboot%%\complete" + + echo uninstalling firstboot service +diff --git a/common/mlcustomize/guest_packages.ml b/common/mlcustomize/guest_packages.ml +index 5431811f..933b8c20 100644 +--- a/common/mlcustomize/guest_packages.ml ++++ b/common/mlcustomize/guest_packages.ml +@@ -44,7 +44,13 @@ let error_unimplemented_package_manager flag pm = + flag pm in + raise (Unimplemented_package_manager msg) + +-(* http://distrowatch.com/dwres.php?resource=package-management *) ++(* http://distrowatch.com/dwres.php?resource=package-management ++ * ++ * yum/dnf --setopt=skip_if_unavailable=True makes package installation ++ * a bit more reliable if an unrelated repo, or the network, are not ++ * available. The command will still fail if the package itself cannot ++ * be downloaded. ++ *) + let install_command packages package_management = + let quoted_args = String.concat " " (List.map quote packages) in + match package_management with +@@ -61,13 +67,20 @@ let install_command packages package_management = + apt-get $apt_opts update + apt-get $apt_opts install %s + " quoted_args +- | "dnf" -> sprintf "dnf -y install %s" quoted_args +- | "pisi" -> sprintf "pisi it %s" quoted_args +- | "pacman" -> sprintf "pacman -S --noconfirm %s" quoted_args +- | "urpmi" -> sprintf "urpmi %s" quoted_args +- | "xbps" -> sprintf "xbps-install -Sy %s" quoted_args +- | "yum" -> sprintf "yum -y install %s" quoted_args +- | "zypper" -> sprintf "zypper -n in -l %s" quoted_args ++ | "dnf" -> ++ sprintf "dnf --setopt=skip_if_unavailable=True -y install %s" quoted_args ++ | "pisi" -> ++ sprintf "pisi it %s" quoted_args ++ | "pacman" -> ++ sprintf "pacman -S --noconfirm %s" quoted_args ++ | "urpmi" -> ++ sprintf "urpmi %s" quoted_args ++ | "xbps" -> ++ sprintf "xbps-install -Sy %s" quoted_args ++ | "yum" -> ++ sprintf "yum --setopt=skip_if_unavailable=True -y install %s" quoted_args ++ | "zypper" -> ++ sprintf "zypper -n in -l %s" quoted_args + + | "unknown" -> + error_unknown_package_manager "--install" +@@ -90,13 +103,18 @@ let update_command package_management = + apt-get $apt_opts upgrade + " + | "dnf" -> +- sprintf "dnf%s -y --best upgrade" ++ sprintf "dnf%s --setopt=skip_if_unavailable=True -y --best upgrade" + (if verbose () then " --verbose" else "") +- | "pisi" -> "pisi upgrade" +- | "pacman" -> "pacman -Su" +- | "urpmi" -> "urpmi --auto-select" +- | "xbps" -> "xbps-install -Suy" +- | "yum" -> "yum -y update" ++ | "pisi" -> ++ "pisi upgrade" ++ | "pacman" -> ++ "pacman -Su" ++ | "urpmi" -> ++ "urpmi --auto-select" ++ | "xbps" -> ++ "xbps-install -Suy" ++ | "yum" -> ++ "yum -y --setopt=skip_if_unavailable=True update" + | "zypper" -> "zypper -n dup -l" + + | "unknown" -> +@@ -115,13 +133,21 @@ let uninstall_command packages package_management = + apt_opts='-q -y -o Dpkg::Options::=--force-confnew' + apt-get $apt_opts remove %s + " quoted_args +- | "dnf" -> sprintf "dnf -y remove %s" quoted_args +- | "pisi" -> sprintf "pisi rm %s" quoted_args +- | "pacman" -> sprintf "pacman -R %s" quoted_args +- | "urpmi" -> sprintf "urpme %s" quoted_args +- | "xbps" -> sprintf "xbps-remove -Sy %s" quoted_args +- | "yum" -> sprintf "yum -y remove %s" quoted_args +- | "zypper" -> sprintf "zypper -n rm %s" quoted_args ++ | "dnf" -> ++ sprintf "dnf -y --setopt=skip_if_unavailable=True --disableplugin=subscription-manager remove %s" ++ quoted_args ++ | "pisi" -> ++ sprintf "pisi rm %s" quoted_args ++ | "pacman" -> ++ sprintf "pacman -R %s" quoted_args ++ | "urpmi" -> ++ sprintf "urpme %s" quoted_args ++ | "xbps" -> ++ sprintf "xbps-remove -Sy %s" quoted_args ++ | "yum" -> ++ sprintf "yum -y --setopt=skip_if_unavailable=True remove %s" quoted_args ++ | "zypper" -> ++ sprintf "zypper -n rm %s" quoted_args + + | "unknown" -> + error_unknown_package_manager "--uninstall" +diff --git a/common/mlcustomize/inject_virtio_win.ml b/common/mlcustomize/inject_virtio_win.ml +index 0e5dcf05..6d7cf1a1 100644 +--- a/common/mlcustomize/inject_virtio_win.ml ++++ b/common/mlcustomize/inject_virtio_win.ml +@@ -43,15 +43,6 @@ type t = { + virtio_win : string; + (** Path to the virtio-win ISO or directory. *) + +- was_set : bool; +- (** If the virtio_win path was explicitly set, for example by +- the user setting an environment variable. +- +- This is used to "show intention" to use virtio-win instead +- of libosinfo. Although this behaviour is documented, IMHO it has +- always been a bad idea. We should change this in future to allow +- the user to select where they want to get drivers from. XXX *) +- + mutable block_driver_priority : string list + (** List of block drivers *) + } +@@ -74,20 +65,20 @@ type virtio_win_installed = { + let rec from_environment g root datadir = + let t = get_inspection g root in + +- let virtio_win, was_set = +- try Sys.getenv "VIRTIO_WIN", true ++ let virtio_win = ++ try Sys.getenv "VIRTIO_WIN" + with Not_found -> +- try Sys.getenv "VIRTIO_WIN_DIR" (* old name for VIRTIO_WIN *), true ++ try Sys.getenv "VIRTIO_WIN_DIR" (* old name for VIRTIO_WIN *) + with Not_found -> + let iso = datadir // "virtio-win" // "virtio-win.iso" in + (if Sys.file_exists iso then iso +- else datadir // "virtio-win"), false in ++ else datadir // "virtio-win") in + +- { t with virtio_win; was_set } ++ { t with virtio_win } + + and from_path g root path = + let t = get_inspection g root in +- { t with virtio_win = path; was_set = true } ++ { t with virtio_win = path } + + and get_inspection g root = + (* Fail hard if inspection hasn't been done or it's not a Windows +@@ -108,7 +99,7 @@ and get_inspection g root = + { g; root; + i_arch; i_major_version; i_minor_version; i_osinfo; + i_product_variant; i_windows_current_control_set; i_windows_systemroot; +- virtio_win = ""; was_set = false; ++ virtio_win = ""; + block_driver_priority = ["virtio_blk"; "vrtioblk"; "viostor"] } + + let get_block_driver_priority t = t.block_driver_priority +diff --git a/common/mlcustomize/v2v-customize-options.pod b/common/mlcustomize/v2v-customize-options.pod +index 6252ffe9..fee5f984 100644 +--- a/common/mlcustomize/v2v-customize-options.pod ++++ b/common/mlcustomize/v2v-customize-options.pod +@@ -332,6 +332,22 @@ It cannot delete directories, only regular files. + + This is a compatibility option that does nothing. + ++=item B<--selinux-relabel-exclude> DIR ++ ++Exclude directories from being relabelled. ++ ++This advanced option lets you list directories in the guest which ++should not be relabelled, even when SELinux relabelling is ++enabled. Use this carefully, as any changes that are made ++inside these directories during customization will have incorrect ++SELinux labels, leading to potential failures later, so you must ++be sure that the directories do not need relabelling. ++ ++If in doubt, do not use this option. ++ ++You can pass the option multiple times, eg. ++I<--selinux-relabel-exclude=/foo> I<--selinux-relabel-exclude=/bar> ++ + =item B<--ssh-inject> USER[:SELECTOR] + + Inject an ssh key so the given C will be able to log in over +diff --git a/common/mlcustomize/v2v-customize-synopsis.pod b/common/mlcustomize/v2v-customize-synopsis.pod +index 4c1a1547..5a1bc009 100644 +--- a/common/mlcustomize/v2v-customize-synopsis.pod ++++ b/common/mlcustomize/v2v-customize-synopsis.pod +@@ -12,4 +12,4 @@ + [--truncate-recursive PATH] [--uninstall PKG,PKG..] [--update] + [--upload FILE:DEST] [--write FILE:CONTENT] [--no-logfile] + [--password-crypto md5|sha256|sha512] [--no-selinux-relabel] +- [--selinux-relabel] ++ [--selinux-relabel] [--selinux-relabel-exclude DIR] diff --git a/0013-mlcustomize-Add-new-selinux-relabel-excludes-flag.patch b/0013-mlcustomize-Add-new-selinux-relabel-excludes-flag.patch new file mode 100644 index 0000000..90e6dab --- /dev/null +++ b/0013-mlcustomize-Add-new-selinux-relabel-excludes-flag.patch @@ -0,0 +1,38 @@ +From 5f8b6a6a12809d8a72aec96b2cf7691385099aa9 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 3 Aug 2026 13:35:08 +0100 +Subject: [PATCH] mlcustomize: Add new --selinux-relabel-excludes flag + +https://github.com/libguestfs/libguestfs/commit/f5ad08415182cd7ecac376aad19ffaa81bec7503 + +Update m4/guestfs-libraries.m4 to make libguestfs 1.61.1 required. +This is for the new guestfs_setfiles 'excludes' parameter, added in: + +https://github.com/libguestfs/libguestfs/commit/5364e6abbcd1ee42f23b26306225269329e7c663 + +Update the common submodule, bringing in: + + Richard W.M. Jones (3): + mlcustomize/customize_cmdline.mli: Fix differences in generated code + mlcustomize: Update generated files + mlcustomize: Pass --selinux-relabel-excludes through to setfiles + +(cherry picked from commit 4dcf8ea13ca2516005cdb64edbbb2534fe612d49) +--- + m4/guestfs-libraries.m4 | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/m4/guestfs-libraries.m4 b/m4/guestfs-libraries.m4 +index 81f4ce98..14154724 100644 +--- a/m4/guestfs-libraries.m4 ++++ b/m4/guestfs-libraries.m4 +@@ -21,7 +21,8 @@ dnl Of course we need libguestfs. + dnl + dnl We need libguestfs 1.59.2 for guestfs_xfs_info2. + dnl We need libguestfs 1.59.7 for text: and base64: prefix in LUKS funcs. +-PKG_CHECK_MODULES([LIBGUESTFS], [libguestfs >= 1.59.7]) ++dnl We need libguestfs 1.61.1 for guestfs_setfiles excludes parameter. ++PKG_CHECK_MODULES([LIBGUESTFS], [libguestfs >= 1.61.1]) + printf "libguestfs version is "; $PKG_CONFIG --modversion libguestfs + + dnl And libnbd. diff --git a/0014-common-update-submodule.patch b/0014-common-update-submodule.patch new file mode 100644 index 0000000..0b35ae4 --- /dev/null +++ b/0014-common-update-submodule.patch @@ -0,0 +1,275 @@ +From 684c30d5e634e8914a82031f1979a1d73e709da9 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 11 Aug 2026 17:59:35 +0100 +Subject: [PATCH] common: update submodule + + Surya Gupta (1): + inject_virtio_win: use lazy handle to avoid 3 appliance launches + +(cherry picked from commit c6ebad6a0d026b34483f295140edd9d98d71962a) +--- + common | 2 +- + m4/guestfs-libraries.m4 | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +Submodule common b3841fbc..8d3f79ee: +diff --git a/common/mlcustomize/guest_packages.ml b/common/mlcustomize/guest_packages.ml +index 933b8c20..fba59a64 100644 +--- a/common/mlcustomize/guest_packages.ml ++++ b/common/mlcustomize/guest_packages.ml +@@ -122,8 +122,14 @@ let update_command package_management = + | pm -> + error_unimplemented_package_manager "--update" pm + +-let uninstall_command packages package_management = ++let uninstall_command ?clean_requirements_on_remove ++ packages package_management = + let quoted_args = String.concat " " (List.map quote packages) in ++ let dnf_yum_clean_requirements_on_remove = ++ match clean_requirements_on_remove with ++ | None -> "" ++ | Some true -> "--setopt=clean_requirements_on_remove=True" ++ | Some false -> "--setopt=clean_requirements_on_remove=False" in + match package_management with + | "apk" -> sprintf "apk del %s" quoted_args + | "apt" -> +@@ -134,8 +140,10 @@ let uninstall_command packages package_management = + apt-get $apt_opts remove %s + " quoted_args + | "dnf" -> +- sprintf "dnf -y --setopt=skip_if_unavailable=True --disableplugin=subscription-manager remove %s" +- quoted_args ++ sprintf "dnf -y --setopt=skip_if_unavailable=True %s \ ++ --disableplugin=subscription-manager \ ++ remove %s" ++ dnf_yum_clean_requirements_on_remove quoted_args + | "pisi" -> + sprintf "pisi rm %s" quoted_args + | "pacman" -> +@@ -145,7 +153,9 @@ let uninstall_command packages package_management = + | "xbps" -> + sprintf "xbps-remove -Sy %s" quoted_args + | "yum" -> +- sprintf "yum -y --setopt=skip_if_unavailable=True remove %s" quoted_args ++ sprintf "yum -y --setopt=skip_if_unavailable=True %s \ ++ remove %s" ++ dnf_yum_clean_requirements_on_remove quoted_args + | "zypper" -> + sprintf "zypper -n rm %s" quoted_args + +diff --git a/common/mlcustomize/guest_packages.mli b/common/mlcustomize/guest_packages.mli +index 5f0925a0..ee03ca88 100644 +--- a/common/mlcustomize/guest_packages.mli ++++ b/common/mlcustomize/guest_packages.mli +@@ -38,7 +38,14 @@ val update_command : string -> string + script) for updating the OS packages that are currently installed in the + guest. *) + +-val uninstall_command : string list -> string -> string ++val uninstall_command : ?clean_requirements_on_remove:bool -> ++ string list -> string -> string + (** [uninstall_command packages package_management] produces a properly quoted + shell command string suitable for execution in the guest (directly or via a +- Firstboot script) for uninstalling the OS packages listed in [packages]. *) ++ Firstboot script) for uninstalling the OS packages listed in [packages]. ++ ++ If used, [?clean_requirements_on_remove] will add ++ [--setopt=clean_requirements_on_remove=(True|False)] to the ++ command. This is used by virt-v2v to avoid removing ++ dependencies (ie behaving like "noautoremove"). It currently ++ only works for yum/dmf. *) +diff --git a/common/mlcustomize/inject_virtio_win.ml b/common/mlcustomize/inject_virtio_win.ml +index 6d7cf1a1..3b52d4f0 100644 +--- a/common/mlcustomize/inject_virtio_win.ml ++++ b/common/mlcustomize/inject_virtio_win.ml +@@ -40,12 +40,20 @@ type t = { + i_windows_systemroot : string; + (** Inspection data needed by this module. *) + +- virtio_win : string; +- (** Path to the virtio-win ISO or directory. *) ++ virtio_win : virtio_win_t; ++ (** Source of virtio-win drivers: an ISO file or a directory. *) + + mutable block_driver_priority : string list + (** List of block drivers *) + } ++and virtio_win_t = Virtio_win_iso of iso_t | Virtio_win_dir of dir_t ++and iso_t = { ++ iso_path : string; ++ g2_lazy : Guestfs.guestfs Lazy.t; ++} ++and dir_t = { ++ dir_path : string; ++} + + type block_type = Virtio_blk | Virtio_SCSI | IDE + and net_type = Virtio_net | E1000 | RTL8139 +@@ -62,10 +70,30 @@ type virtio_win_installed = { + virtio_1_0 : bool; + } + ++let virtio_win_path = function ++ | Virtio_win_iso iso -> iso.iso_path ++ | Virtio_win_dir dir -> dir.dir_path ++ ++let make_virtio_win path = ++ if is_directory path then ++ Virtio_win_dir { dir_path = path } ++ else ++ let g2_lazy = lazy ( ++ try ++ let g2 = open_guestfs ~identifier:"virtio_win" () in ++ g2#add_drive_opts path ~readonly:true; ++ g2#launch (); ++ g2#mount_ro "/dev/sda" "/"; ++ g2 ++ with Guestfs.Error msg -> ++ error (f_"%s: cannot open virtio-win ISO file: %s") path msg ++ ) in ++ Virtio_win_iso { iso_path = path; g2_lazy } ++ + let rec from_environment g root datadir = + let t = get_inspection g root in + +- let virtio_win = ++ let path = + try Sys.getenv "VIRTIO_WIN" + with Not_found -> + try Sys.getenv "VIRTIO_WIN_DIR" (* old name for VIRTIO_WIN *) +@@ -74,11 +102,11 @@ let rec from_environment g root datadir = + (if Sys.file_exists iso then iso + else datadir // "virtio-win") in + +- { t with virtio_win } ++ { t with virtio_win = make_virtio_win path } + + and from_path g root path = + let t = get_inspection g root in +- { t with virtio_win = path } ++ { t with virtio_win = make_virtio_win path } + + and get_inspection g root = + (* Fail hard if inspection hasn't been done or it's not a Windows +@@ -99,7 +127,7 @@ and get_inspection g root = + { g; root; + i_arch; i_major_version; i_minor_version; i_osinfo; + i_product_variant; i_windows_current_control_set; i_windows_systemroot; +- virtio_win = ""; ++ virtio_win = Virtio_win_dir { dir_path = "" }; + block_driver_priority = ["virtio_blk"; "vrtioblk"; "viostor"] } + + let get_block_driver_priority t = t.block_driver_priority +@@ -143,7 +171,7 @@ let rec inject_virtio_win_drivers ({ g } as t) reg = + if not (copy_drivers t driverdir) then ( + warning (f_"there are no virtio drivers available for this version of Windows (%d.%d %s %s %s). virt-v2v looks for drivers in %s\n\nThe guest will be configured to use slower emulated devices.") + t.i_major_version t.i_minor_version t.i_arch +- t.i_product_variant t.i_osinfo t.virtio_win; ++ t.i_product_variant t.i_osinfo (virtio_win_path t.virtio_win); + { block_driver = IDE; net_driver = RTL8139; + virtio_rng = false; virtio_balloon = false; + isa_pvpanic = false; virtio_socket = false; +@@ -165,7 +193,7 @@ let rec inject_virtio_win_drivers ({ g } as t) reg = + | None -> + warning (f_"there is no virtio block device driver for this version of Windows (%d.%d %s). virt-v2v looks for this driver in %s\n\nThe guest will be configured to use a slower emulated device.") + t.i_major_version t.i_minor_version +- t.i_arch t.virtio_win; ++ t.i_arch (virtio_win_path t.virtio_win); + IDE + + | Some driver_name -> +@@ -196,7 +224,7 @@ let rec inject_virtio_win_drivers ({ g } as t) reg = + if not has_netkvm then ( + warning (f_"there is no virtio network driver for this version of Windows (%d.%d %s). virt-v2v looks for this driver in %s\n\nThe guest will be configured to use a slower emulated device.") + t.i_major_version t.i_minor_version +- t.i_arch t.virtio_win; ++ t.i_arch (virtio_win_path t.virtio_win); + RTL8139 + ) + else +@@ -364,19 +392,20 @@ and copy_blnsvr t tempdir = + *) + and copy_from_virtio_win ({ g } as t) srcdir destdir filter missing = + let ret = ref [] in +- if is_directory t.virtio_win then ( ++ (match t.virtio_win with ++ | Virtio_win_dir { dir_path } -> + debug "windows: copy_from_virtio_win: guest tools source directory %s" +- t.virtio_win; ++ dir_path; + +- let dir = t.virtio_win // srcdir in +- if not (is_directory dir) then missing () ++ let srcpath = dir_path // srcdir in ++ if not (is_directory srcpath) then missing () + else ( +- let cmd = sprintf "cd %s && find -L -type f" (quote dir) in ++ let cmd = sprintf "cd %s && find -L -type f" (quote srcpath) in + let paths = external_command cmd in + List.iter ( + fun path -> + if filter path then ( +- let source = dir // path in ++ let source = srcpath // path in + let target_name = String.lowercase_ascii (Filename.basename path) in + let target = destdir // target_name in + debug "windows: copying guest tools bits: 'host:%s' -> '%s'" +@@ -387,23 +416,12 @@ and copy_from_virtio_win ({ g } as t) srcdir destdir filter missing = + ) + ) paths + ) +- ) +- else if is_regular_file t.virtio_win || is_block_device t.virtio_win then ( ++ ++ | Virtio_win_iso { iso_path; g2_lazy } -> + debug "windows: copy_from_virtio_win: guest tools source ISO %s" +- t.virtio_win; ++ iso_path; + +- let g2 = +- try +- let g2 = open_guestfs ~identifier:"virtio_win" () in +- g2#add_drive_opts t.virtio_win ~readonly:true; +- g2#launch (); +- g2 +- with Guestfs.Error msg -> +- error (f_"%s: cannot open virtio-win ISO file: %s") t.virtio_win msg in +- (* Note we are mounting this as root on the *second* +- * handle, not the main handle containing the guest. +- *) +- g2#mount_ro "/dev/sda" "/"; ++ let g2 = Lazy.force g2_lazy in + let srcdir = "/" ^ srcdir in + if not (g2#is_dir srcdir) then missing () + else ( +@@ -415,14 +433,13 @@ and copy_from_virtio_win ({ g } as t) srcdir destdir filter missing = + let target_name = String.lowercase_ascii (Filename.basename path) in + let target = destdir ^ "/" ^ target_name in + debug "windows: copying guest tools bits: '%s:%s' -> '%s'" +- t.virtio_win path target; ++ iso_path path target; + + g#write target (g2#read_file source); + List.push_front target_name ret + ) + ) paths; + ); +- g2#close() + ); + !ret + +diff --git a/m4/guestfs-libraries.m4 b/m4/guestfs-libraries.m4 +index 14154724..250970e4 100644 +--- a/m4/guestfs-libraries.m4 ++++ b/m4/guestfs-libraries.m4 +@@ -21,8 +21,8 @@ dnl Of course we need libguestfs. + dnl + dnl We need libguestfs 1.59.2 for guestfs_xfs_info2. + dnl We need libguestfs 1.59.7 for text: and base64: prefix in LUKS funcs. +-dnl We need libguestfs 1.61.1 for guestfs_setfiles excludes parameter. +-PKG_CHECK_MODULES([LIBGUESTFS], [libguestfs >= 1.61.1]) ++dnl We need libguestfs 1.60.1 for guestfs_setfiles excludes parameter. ++PKG_CHECK_MODULES([LIBGUESTFS], [libguestfs >= 1.60.1]) + printf "libguestfs version is "; $PKG_CONFIG --modversion libguestfs + + dnl And libnbd. diff --git a/copy-patches.sh b/copy-patches.sh index 212a3f9..5b01a4c 100755 --- a/copy-patches.sh +++ b/copy-patches.sh @@ -18,6 +18,7 @@ fi case `id -un` in rjones) git_checkout=$HOME/d/$project-rhel-$rhel_version ;; lacos) git_checkout=$HOME/src/v2v/$project ;; + sparimi) git_checkout=$HOME/rhel10.3/upstream/$project ;; *) git_checkout=$HOME/d/$project-rhel-$rhel_version ;; esac if [ ! -d $git_checkout ]; then diff --git a/virt-v2v.spec b/virt-v2v.spec index 567f11b..f37e3fb 100644 --- a/virt-v2v.spec +++ b/virt-v2v.spec @@ -45,7 +45,7 @@ ExclusiveArch: x86_64 Name: virt-v2v Epoch: 1 Version: 2.12.0 -Release: 1%{?dist} +Release: 2%{?dist} Summary: Convert a virtual machine to run on KVM License: GPL-2.0-or-later AND LGPL-2.0-or-later @@ -75,6 +75,10 @@ Patch0007: 0007-RHEL-tests-Remove-btrfs-test.patch Patch0008: 0008-RHEL-Add-warning-about-virt-v2v-in-place-not-being-s.patch Patch0009: 0009-RHEL-output-output.ml-Remove-reduce-memory-pressure-.patch Patch0010: 0010-convert-windows-Fix-online-disks-script-for-PowerShe.patch +Patch0011: 0011-convert-convert_linux.ml-Use-yum-dnf-clean_requireme.patch +Patch0012: 0012-common-update-submodule.patch +Patch0013: 0013-mlcustomize-Add-new-selinux-relabel-excludes-flag.patch +Patch0014: 0014-common-update-submodule.patch BuildRequires: autoconf, automake, libtool BuildRequires: make @@ -380,6 +384,20 @@ done %changelog +* Mon Aug 17 2026 Srihari Parimi - 1:2.12.0-2 +- Fix missing libxslt library after VMware to OpenShift VM migration + resolves: RHEL-233944 +- Fix online-disks firstboot script under PowerShell Constrained Language Mode + resolves: RHEL-210639 +- Fix delay during open-vm-tools removal when RHSM is unreachable + resolves: RHEL-214049 +- Allow qemu-guest-agent install to skip unreachable guest repos + resolves: RHEL-217581 +- Fix conversion pod crash during SELinux relabeling of large XFS filesystems + resolves: RHEL-222316 +- Prevent multiple appliance launches for virtio-win.iso content + resolves: RHEL-124850 + * Tue Jul 14 2026 Richard W.M. Jones - 1:2.12.0-1 - Rebase to virt-v2v 2.12.0 Synchronize spec file with Fedora