mrc0mmand / rpms / libguestfs

Forked from rpms/libguestfs 3 years ago
Clone
Blob Blame History Raw
From 6ea4891f843196d822af07b91155f86cee87736a Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Mon, 6 Jul 2015 12:37:23 +0100
Subject: [PATCH] v2v: Add a check before copying that UEFI is supported
 (RHBZ#1184690).

If UEFI is required by the guest, but not supported by the host, then
you wouldn't see an error message until after copying.

Add an additional method to the output object so we can check this
before copying, to avoid a long wait.

Thanks: Junqin Zhou
https://bugzilla.redhat.com/show_bug.cgi?id=1184690#c22
(cherry picked from commit b04f39bf10e4f760d880d1077e6ffb68d028c0ae)
---
 v2v/output_libvirt.ml | 12 ++++++++++++
 v2v/output_qemu.ml    |  9 +++++++++
 v2v/types.ml          |  1 +
 v2v/types.mli         |  4 ++++
 v2v/v2v.ml            | 40 ++++++++++++++++++++++------------------
 5 files changed, 48 insertions(+), 18 deletions(-)

diff --git a/v2v/output_libvirt.ml b/v2v/output_libvirt.ml
index 40280dd..de4aeb4 100644
--- a/v2v/output_libvirt.ml
+++ b/v2v/output_libvirt.ml
@@ -376,6 +376,18 @@ class output_libvirt verbose oc output_pool = object
         { t with target_file = target_file }
     ) targets
 
+  method check_target_firmware guestcaps target_firmware =
+    match target_firmware with
+    | TargetBIOS -> ()
+    | TargetUEFI ->
+       (* This will fail with an error if the target firmware is
+        * not installed on the host.
+        * XXX Can remove this method when libvirt supports
+        * <loader type="efi"/> since then it will be up to
+        * libvirt to check this.
+        *)
+       ignore (find_uefi_firmware guestcaps.gcaps_arch)
+
   method create_metadata source targets guestcaps _ target_firmware =
     (* We copied directly into the final pool directory.  However we
      * have to tell libvirt.
diff --git a/v2v/output_qemu.ml b/v2v/output_qemu.ml
index c593030..c5e38f2 100644
--- a/v2v/output_qemu.ml
+++ b/v2v/output_qemu.ml
@@ -40,6 +40,15 @@ object
         { t with target_file = target_file }
     ) targets
 
+  method check_target_firmware guestcaps target_firmware =
+    match target_firmware with
+    | TargetBIOS -> ()
+    | TargetUEFI ->
+       (* This will fail with an error if the target firmware is
+        * not installed on the host.
+        *)
+       ignore (find_uefi_firmware guestcaps.gcaps_arch)
+
   method create_metadata source targets guestcaps inspect target_firmware =
     let name = source.s_name in
     let file = dir // name ^ ".sh" in
diff --git a/v2v/types.ml b/v2v/types.ml
index 41d2686..7b33965 100644
--- a/v2v/types.ml
+++ b/v2v/types.ml
@@ -312,6 +312,7 @@ class virtual output verbose = object
   method virtual as_options : string
   method virtual prepare_targets : source -> target list -> target list
   method virtual supported_firmware : target_firmware list
+  method check_target_firmware (_ : guestcaps) (_ : target_firmware) = ()
   method check_target_free_space (_ : source) (_ : target list) = ()
   method disk_create = (new Guestfs.guestfs ())#disk_create
   method virtual create_metadata : source -> target list -> guestcaps -> inspect -> target_firmware -> unit
diff --git a/v2v/types.mli b/v2v/types.mli
index da398d3..e7e99eb 100644
--- a/v2v/types.mli
+++ b/v2v/types.mli
@@ -202,6 +202,10 @@ class virtual output : bool -> object
   method virtual supported_firmware : target_firmware list
   (** Does this output method support UEFI?  Allows us to abort early if
       conversion is impossible. *)
+  method check_target_firmware : guestcaps -> target_firmware -> unit
+  (** Called before conversion once the guest's target firmware is known.
+      Can be used as an additional check that the target firmware is
+      supported on the host. *)
   method check_target_free_space : source -> target list -> unit
   (** Called before conversion.  Can be used to check there is enough space
       on the target, using the [target.target_estimated_size] field. *)
diff --git a/v2v/v2v.ml b/v2v/v2v.ml
index d509a4c..c18039f 100644
--- a/v2v/v2v.ml
+++ b/v2v/v2v.ml
@@ -217,24 +217,6 @@ let rec main () =
   msg (f_"Inspecting the overlay");
   let inspect = inspect_source ~verbose g root_choice in
 
-  (* Does the guest require UEFI on the target? *)
-  let target_firmware =
-    match source.s_firmware with
-    | BIOS -> TargetBIOS
-    | UEFI -> TargetUEFI
-    | UnknownFirmware ->
-       if inspect.i_uefi then TargetUEFI else TargetBIOS in
-  let supported_firmware = output#supported_firmware in
-  if not (List.mem target_firmware supported_firmware) then
-    error (f_"this guest cannot run on the target, because the target does not support %s firmware (supported firmware on target: %s)")
-          (string_of_target_firmware target_firmware)
-          (String.concat " "
-            (List.map string_of_target_firmware supported_firmware));
-  (match target_firmware with
-   | TargetBIOS -> ()
-   | TargetUEFI ->
-       info ~prog (f_"This guest requires UEFI on the target to boot."));
-
   (* The guest free disk space check and the target free space
    * estimation both require statvfs information from mountpoints, so
    * get that information first.
@@ -308,6 +290,28 @@ let rec main () =
   g#shutdown ();
   g#close ();
 
+  (* Does the guest require UEFI on the target? *)
+  msg (f_"Checking if the guest needs BIOS or UEFI to boot");
+  let target_firmware =
+    match source.s_firmware with
+    | BIOS -> TargetBIOS
+    | UEFI -> TargetUEFI
+    | UnknownFirmware ->
+       if inspect.i_uefi then TargetUEFI else TargetBIOS in
+  let supported_firmware = output#supported_firmware in
+  if not (List.mem target_firmware supported_firmware) then
+    error (f_"this guest cannot run on the target, because the target does not support %s firmware (supported firmware on target: %s)")
+          (string_of_target_firmware target_firmware)
+          (String.concat " "
+            (List.map string_of_target_firmware supported_firmware));
+
+  output#check_target_firmware guestcaps target_firmware;
+
+  (match target_firmware with
+   | TargetBIOS -> ()
+   | TargetUEFI ->
+       info ~prog (f_"This guest requires UEFI on the target to boot."));
+
   (* Force a GC here, to ensure that we're using the minimum resources
    * as we go into the copy stage.  The particular reason is that
    * Windows conversion may have opened a second libguestfs handle
-- 
1.8.3.1