From d326f1080aafe32d47b49064099f2e9d7759b2a0 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 16 May 2024 12:49:24 +0100 Subject: [PATCH] customize: Implement --inject-blnsvr operation Also updates the common submodule with the generated changes from libguestfs, and the implementation of Inject_virtio_win.inject_blnsvr. (cherry picked from commit 80d258baa49214c8e59b91d6085595c9b989fc0d) --- common | 2 +- customize/customize_run.ml | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) Submodule common 93a7f3af5..830cbdcf4: diff --git a/common/mlcustomize/customize-options.pod b/common/mlcustomize/customize-options.pod index ff93630d8..b2ac57526 100644 --- a/common/mlcustomize/customize-options.pod +++ b/common/mlcustomize/customize-options.pod @@ -193,6 +193,18 @@ L. Set the hostname of the guest to C. You can use a dotted hostname.domainname (FQDN) if you want. +=item B<--inject-blnsvr> METHOD + +Inject the Balloon Server (F) into a Windows guest. +This operation also injects a firstboot script so that the Balloon +Server is installed when the guest boots. + +The parameter is the same as used by the I<--inject-virtio-win> operation. + +Note that to do a full conversion of a Windows guest from a +foreign hypervisor like VMware (which involves many other operations) +you should use the L tool instead of this. + =item B<--inject-qemu-ga> METHOD Inject the QEMU Guest Agent into a Windows guest. The guest diff --git a/common/mlcustomize/customize-synopsis.pod b/common/mlcustomize/customize-synopsis.pod index bb0ce1255..957de8cf2 100644 --- a/common/mlcustomize/customize-synopsis.pod +++ b/common/mlcustomize/customize-synopsis.pod @@ -3,16 +3,16 @@ [--copy SOURCE:DEST] [--copy-in LOCALPATH:REMOTEDIR] [--delete PATH] [--edit FILE:EXPR] [--firstboot SCRIPT] [--firstboot-command 'CMD+ARGS'] [--firstboot-install PKG,PKG..] - [--hostname HOSTNAME] [--inject-qemu-ga METHOD] - [--inject-virtio-win METHOD] [--install PKG,PKG..] - [--link TARGET:LINK[:LINK..]] [--mkdir DIR] [--move SOURCE:DEST] - [--password USER:SELECTOR] [--root-password SELECTOR] - [--run SCRIPT] [--run-command 'CMD+ARGS'] [--scrub FILE] - [--sm-attach SELECTOR] [--sm-register] [--sm-remove] - [--sm-unregister] [--ssh-inject USER[:SELECTOR]] - [--tar-in TARFILE:REMOTEDIR] [--timezone TIMEZONE] [--touch FILE] - [--truncate FILE] [--truncate-recursive PATH] - [--uninstall PKG,PKG..] [--update] [--upload FILE:DEST] - [--write FILE:CONTENT] [--no-logfile] + [--hostname HOSTNAME] [--inject-blnsvr METHOD] + [--inject-qemu-ga METHOD] [--inject-virtio-win METHOD] + [--install PKG,PKG..] [--link TARGET:LINK[:LINK..]] [--mkdir DIR] + [--move SOURCE:DEST] [--password USER:SELECTOR] + [--root-password SELECTOR] [--run SCRIPT] + [--run-command 'CMD+ARGS'] [--scrub FILE] [--sm-attach SELECTOR] + [--sm-register] [--sm-remove] [--sm-unregister] + [--ssh-inject USER[:SELECTOR]] [--tar-in TARFILE:REMOTEDIR] + [--timezone TIMEZONE] [--touch FILE] [--truncate FILE] + [--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] [--sm-credentials SELECTOR] diff --git a/common/mlcustomize/customize_cmdline.ml b/common/mlcustomize/customize_cmdline.ml index 48ee33445..c4d6a77d5 100644 --- a/common/mlcustomize/customize_cmdline.ml +++ b/common/mlcustomize/customize_cmdline.ml @@ -61,6 +61,8 @@ and op = [ (* --firstboot-install PKG,PKG.. *) | `Hostname of string (* --hostname HOSTNAME *) + | `InjectBalloonServer of string + (* --inject-blnsvr METHOD *) | `InjectQemuGA of string (* --inject-qemu-ga METHOD *) | `InjectVirtioWin of string @@ -286,6 +288,12 @@ let rec argspec () = s_"Set the hostname" ), Some "HOSTNAME", "Set the hostname of the guest to C. You can use a\ndotted hostname.domainname (FQDN) if you want."; + ( + [ L"inject-blnsvr" ], + Getopt.String (s_"METHOD", fun s -> List.push_front (`InjectBalloonServer s) ops), + s_"Inject the Balloon Server into a Windows guest" + ), + Some "METHOD", "Inject the Balloon Server (F) into a Windows guest.\nThis operation also injects a firstboot script so that the Balloon\nServer is installed when the guest boots.\n\nThe parameter is the same as used by the I<--inject-virtio-win> operation.\n\nNote that to do a full conversion of a Windows guest from a\nforeign hypervisor like VMware (which involves many other operations)\nyou should use the L tool instead of this."; ( [ L"inject-qemu-ga" ], Getopt.String (s_"METHOD", fun s -> List.push_front (`InjectQemuGA s) ops), diff --git a/common/mlcustomize/customize_cmdline.mli b/common/mlcustomize/customize_cmdline.mli index 51a156eae..ee62961a1 100644 --- a/common/mlcustomize/customize_cmdline.mli +++ b/common/mlcustomize/customize_cmdline.mli @@ -53,6 +53,8 @@ and op = [ (* --firstboot-install PKG,PKG.. *) | `Hostname of string (* --hostname HOSTNAME *) + | `InjectBalloonServer of string + (* --inject-blnsvr METHOD *) | `InjectQemuGA of string (* --inject-qemu-ga METHOD *) | `InjectVirtioWin of string diff --git a/common/mlcustomize/inject_virtio_win.ml b/common/mlcustomize/inject_virtio_win.ml index 2a30b2008..4e0ed0e0e 100644 --- a/common/mlcustomize/inject_virtio_win.ml +++ b/common/mlcustomize/inject_virtio_win.ml @@ -24,6 +24,8 @@ open Common_gettext.Gettext open Regedit +let re_blnsvr = PCRE.compile ~caseless:true "\\bblnsvr\\.exe$" + type t = { g : Guestfs.guestfs; (** guestfs handle *) @@ -267,6 +269,18 @@ and inject_qemu_ga t = configure_qemu_ga t msi_files; msi_files <> [] (* return true if we found some qemu-ga MSI files *) +and inject_blnsvr t = + let files = copy_blnsvr t in + match files with + | [] -> false (* Didn't find or install anything. *) + + (* We usually find blnsvr.exe in two locations (drivers/by-os and + * drivers/by-driver). Pick the first. + *) + | blnsvr :: _ -> + configure_blnsvr t blnsvr; + true + and add_guestor_to_registry t ((g, root) as reg) drv_name drv_pciid = let ddb_node = g#hivex_node_get_child root "DriverDatabase" in @@ -351,6 +365,11 @@ and copy_qemu_ga t = (fun () -> error (f_"root directory ‘/’ is missing from the virtio-win directory or ISO.\n\nThis should not happen and may indicate that virtio-win or virt-v2v is broken in some way. Please report this as a bug with a full debug log.")) +and copy_blnsvr t = + copy_from_virtio_win t "/" "/" (virtio_iso_path_matches_blnsvr t) + (fun () -> + error (f_"root directory ‘/’ is missing from the virtio-win directory or ISO.\n\nThis should not happen and may indicate that virtio-win or virt-v2v is broken in some way. Please report this as a bug with a full debug log.")) + (* Copy all files from virtio_win directory/ISO located in [srcdir] * subdirectory and all its subdirectories to the [destdir]. The directory * hierarchy is not preserved, meaning all files will be directly in [destdir]. @@ -513,6 +532,10 @@ and virtio_iso_path_matches_qemu_ga t path = | ("x86_64", "rhev-qga64.msi") -> true | _ -> false +(* Find blnsvr for the current Windows version. *) +and virtio_iso_path_matches_blnsvr t path = + virtio_iso_path_matches_guest_os t path && PCRE.matches re_blnsvr path + (* Look up in libosinfo for the OS, and copy all the locally * available files specified as drivers for that OS to the [destdir]. * @@ -586,3 +609,10 @@ and configure_qemu_ga t files = Firstboot.add_firstboot_powershell t.g t.root (sprintf "install-%s.ps1" msi_path) !psh_script; ) files + +and configure_blnsvr t blnsvr = + let cmd = sprintf "\ + @echo off\n\ + echo Installing %s\n\ + c:\\%s -i\n" blnsvr blnsvr in + Firstboot.add_firstboot_script t.g t.root (sprintf "install-%s" blnsvr) cmd diff --git a/common/mlcustomize/inject_virtio_win.mli b/common/mlcustomize/inject_virtio_win.mli index d14f04973..d273c4dd3 100644 --- a/common/mlcustomize/inject_virtio_win.mli +++ b/common/mlcustomize/inject_virtio_win.mli @@ -93,3 +93,11 @@ val inject_qemu_ga : t -> bool the MSI(s). Returns [true] iff we were able to inject qemu-ga. *) + +val inject_blnsvr : t -> bool +(** Inject the Balloon Server ([blnsvr.exe]) into a Windows guest. + + A firstboot script is also injected which should install + the server by running [blnsvr -i]. + + Returns [true] iff we were able to inject the Balloon Server. *) diff --git a/customize/customize_run.ml b/customize/customize_run.ml index 1314d6e30..1d7c13eaf 100644 --- a/customize/customize_run.ml +++ b/customize/customize_run.ml @@ -113,8 +113,8 @@ let run (g : G.guestfs) root (ops : ops) = Hashtbl.replace passwords user pw in - (* Helper function to convert --inject-qemu-ga/--inject-virtio-win - * method parameter into a virtio-win handle. + (* Helper function to convert --inject-blnsvr/--inject-qemu-ga/ + * --inject-virtio-win method parameter into a virtio-win handle. *) let get_virtio_win_handle op meth = if g#inspect_get_type root <> "windows" then ( @@ -216,6 +216,15 @@ let run (g : G.guestfs) root (ops : ops) = if not (Hostname.set_hostname g root hostname) then warning (f_"hostname could not be set for this type of guest") + | `InjectBalloonServer meth -> + (match get_virtio_win_handle "--inject-blnsvr" meth with + | None -> () + | Some t -> + if not (Inject_virtio_win.inject_blnsvr t) then + warning (f_"--inject-blnsvr: blnsvr.exe not found in \ + virtio-win source that you specified") + ) + | `InjectQemuGA meth -> (match get_virtio_win_handle "--inject-qemu-ga" meth with | None -> ()