[Libguestfs] [PATCH v2 3/4] v2v: take requested caps into account when converting

Roman Kagan rkagan at virtuozzo.com
Sat Feb 20 08:26:09 UTC 2016


Give the caller certain control over what kind of interface to use for
virtual disks, network and video cards upon conversion.

For that, make convert functions accept additional rcaps parameter
containing an object with optional capabilities similar to the ones
produced on output, with None indicating that the decision is left to
the convert function itself.

To facilicate review, this patch unconditionally passes rcaps with no
preferences; populating it with more sensible values is done in a
followup patch.

Signed-off-by: Roman Kagan <rkagan at virtuozzo.com>
---

Notes:
    v2:
     - use match instead of mixing match and if

 v2v/convert_linux.ml   | 49 +++++++++++++++++++--------
 v2v/convert_windows.ml |  4 +--
 v2v/modules_list.ml    |  3 +-
 v2v/modules_list.mli   |  3 +-
 v2v/v2v.ml             | 13 ++++++--
 v2v/windows_virtio.ml  | 89 +++++++++++++++++++++++++++++++++++++-------------
 v2v/windows_virtio.mli |  6 ++++
 7 files changed, 125 insertions(+), 42 deletions(-)

diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml
index 5d3e16b..bf396d7 100644
--- a/v2v/convert_linux.ml
+++ b/v2v/convert_linux.ml
@@ -59,7 +59,7 @@ let string_of_kernel_info ki =
     ki.ki_supports_virtio ki.ki_is_xen_kernel ki.ki_is_debug
 
 (* The conversion function. *)
-let rec convert ~keep_serial_console (g : G.guestfs) inspect source =
+let rec convert ~keep_serial_console (g : G.guestfs) inspect source rcaps =
   (*----------------------------------------------------------------------*)
   (* Inspect the guest first.  We already did some basic inspection in
    * the common v2v.ml code, but that has to deal with generic guests
@@ -1115,19 +1115,26 @@ let rec convert ~keep_serial_console (g : G.guestfs) inspect source =
       warning (f_"The display driver was updated to '%s', but X11 does not seem to be installed in the guest.  X may not function correctly.")
         video_driver
 
-  and configure_kernel_modules virtio =
+  and configure_kernel_modules block_type net_type =
     (* This function modifies modules.conf (and its various aliases). *)
 
     (* Update 'alias eth0 ...'. *)
     let paths = augeas_modprobe ". =~ regexp('eth[0-9]+')" in
-    let net_device = if virtio then "virtio_net" else "e1000" in
+    let net_device =
+      match net_type with
+      | Virtio_net -> "virtio_net"
+      | E1000 -> "e1000"
+      | RTL8139 -> "rtl8139cp"
+    in
+
     List.iter (
       fun path -> g#aug_set (path ^ "/modulename") net_device
     ) paths;
 
     (* Update 'alias scsi_hostadapter ...' *)
     let paths = augeas_modprobe ". =~ regexp('scsi_hostadapter.*')" in
-    if virtio then (
+    match block_type with
+    | Virtio_blk ->
       if paths <> [] then (
         (* There's only 1 scsi controller in the converted guest.
          * Convert only the first scsi_hostadapter entry to virtio
@@ -1150,10 +1157,10 @@ let rec convert ~keep_serial_console (g : G.guestfs) inspect source =
         g#aug_set (sprintf "/files%s/alias[last()]/modulename" modpath)
           "virtio_blk"
       )
-    ) else (* not virtio *) (
+    | IDE ->
       (* There is no scsi controller in an IDE guest. *)
       List.iter (fun path -> ignore (g#aug_rm path)) (List.rev paths)
-    );
+    ;
 
     (* Display a warning about any leftover Xen modules which we
      * haven't converted.  These are likely to cause an error when
@@ -1215,7 +1222,7 @@ let rec convert ~keep_serial_console (g : G.guestfs) inspect source =
 
     !modpath
 
-  and remap_block_devices virtio =
+  and remap_block_devices block_type =
     (* This function's job is to iterate over boot configuration
      * files, replacing "hda" with "vda" or whatever is appropriate.
      * This is mostly applicable to old guests, since newer OSes use
@@ -1238,7 +1245,9 @@ let rec convert ~keep_serial_console (g : G.guestfs) inspect source =
         (* All modern distros use libata: *) "sd" in
 
     let block_prefix_after_conversion =
-      if virtio then "vd" else ide_block_prefix in
+      match block_type with
+      | Virtio_blk -> "vd"
+      | IDE -> ide_block_prefix in
 
     let map =
       mapi (
@@ -1411,15 +1420,29 @@ let rec convert ~keep_serial_console (g : G.guestfs) inspect source =
 
   let acpi = supports_acpi () in
 
-  let video = get_display_driver () in
+  let video =
+    match rcaps.rcaps_video with
+    | None -> get_display_driver ()
+    | Some video -> video in
+
+  let block_type =
+    match rcaps.rcaps_block_bus with
+    | None -> if virtio then Virtio_blk else IDE
+    | Some block_type -> block_type in
+
+  let net_type =
+    match rcaps.rcaps_net_bus with
+    | None -> if virtio then Virtio_net else E1000
+    | Some net_type -> net_type in
+
   configure_display_driver video;
-  remap_block_devices virtio;
-  configure_kernel_modules virtio;
+  remap_block_devices block_type;
+  configure_kernel_modules block_type net_type;
   rebuild_initrd kernel;
 
   let guestcaps = {
-    gcaps_block_bus = if virtio then Virtio_blk else IDE;
-    gcaps_net_bus = if virtio then Virtio_net else E1000;
+    gcaps_block_bus = block_type;
+    gcaps_net_bus = net_type;
     gcaps_video = video;
     gcaps_arch = Utils.kvm_arch inspect.i_arch;
     gcaps_acpi = acpi;
diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml
index f6f0911..5daae6c 100644
--- a/v2v/convert_windows.ml
+++ b/v2v/convert_windows.ml
@@ -37,7 +37,7 @@ module G = Guestfs
  * time the Windows VM is booted on KVM.
  *)
 
-let convert ~keep_serial_console (g : G.guestfs) inspect source =
+let convert ~keep_serial_console (g : G.guestfs) inspect source rcaps =
   (* Get the data directory. *)
   let virt_tools_data_dir =
     try Sys.getenv "VIRT_TOOLS_DATA_DIR"
@@ -283,7 +283,7 @@ if errorlevel 3010 exit /b 0
     disable_services root current_cs;
     disable_autoreboot root current_cs;
     Windows_virtio.install_drivers g inspect systemroot
-                                   root current_cs
+                                   root current_cs rcaps
 
   and disable_services root current_cs =
     (* Disable miscellaneous services. *)
diff --git a/v2v/modules_list.ml b/v2v/modules_list.ml
index ec964c1..fd7b2ff 100644
--- a/v2v/modules_list.ml
+++ b/v2v/modules_list.ml
@@ -29,7 +29,8 @@ and output_modules () = List.sort compare !output_modules
 
 type conversion_fn =
   keep_serial_console:bool ->
-  Guestfs.guestfs -> Types.inspect -> Types.source -> Types.guestcaps
+  Guestfs.guestfs -> Types.inspect -> Types.source ->
+  Types.requested_guestcaps -> Types.guestcaps
 
 let convert_modules = ref []
 
diff --git a/v2v/modules_list.mli b/v2v/modules_list.mli
index 967a319..0560832 100644
--- a/v2v/modules_list.mli
+++ b/v2v/modules_list.mli
@@ -32,7 +32,8 @@ val output_modules : unit -> string list
 
 type conversion_fn =
   keep_serial_console:bool ->
-  Guestfs.guestfs -> Types.inspect -> Types.source -> Types.guestcaps
+  Guestfs.guestfs -> Types.inspect -> Types.source ->
+  Types.requested_guestcaps -> Types.guestcaps
 
 val register_convert_module : (Types.inspect -> bool) -> string -> conversion_fn -> unit
 (** [register_convert_module inspect_fn name fn] registers a
diff --git a/v2v/v2v.ml b/v2v/v2v.ml
index 5082e9a..c828e48 100644
--- a/v2v/v2v.ml
+++ b/v2v/v2v.ml
@@ -82,7 +82,12 @@ let rec main () =
   );
 
   let keep_serial_console = output#keep_serial_console in
-  let guestcaps = do_convert g inspect source keep_serial_console in
+  let rcaps = {
+                rcaps_block_bus = None;
+                rcaps_net_bus = None;
+                rcaps_video = None;
+              } in
+  let guestcaps = do_convert g inspect source keep_serial_console rcaps in
 
   g#umount_all ();
 
@@ -699,7 +704,7 @@ and check_target_free_space mpstats source targets output =
 
   output#check_target_free_space source targets
 
-and do_convert g inspect source keep_serial_console =
+and do_convert g inspect source keep_serial_console rcaps =
   (* Conversion. *)
   (match inspect.i_product_name with
   | "unknown" ->
@@ -714,7 +719,9 @@ and do_convert g inspect source keep_serial_console =
       error (f_"virt-v2v is unable to convert this guest type (%s/%s)")
         inspect.i_type inspect.i_distro in
   if verbose () then printf "picked conversion module %s\n%!" conversion_name;
-  let guestcaps = convert ~keep_serial_console g inspect source in
+  if verbose () then printf "requested caps: %s%!"
+    (string_of_requested_guestcaps rcaps);
+  let guestcaps = convert ~keep_serial_console g inspect source rcaps in
   if verbose () then printf "%s%!" (string_of_guestcaps guestcaps);
 
   (* Did we manage to install virtio drivers? *)
diff --git a/v2v/windows_virtio.ml b/v2v/windows_virtio.ml
index d78bb0c..a505072 100644
--- a/v2v/windows_virtio.ml
+++ b/v2v/windows_virtio.ml
@@ -33,57 +33,102 @@ let virtio_win =
     with Not_found ->
       Guestfs_config.datadir // "virtio-win"
 
-let rec install_drivers g inspect systemroot root current_cs =
+let rec install_drivers g inspect systemroot root current_cs rcaps =
   (* Copy the virtio drivers to the guest. *)
   let driverdir = sprintf "%s/Drivers/VirtIO" systemroot in
   g#mkdir_p driverdir;
 
   if not (copy_drivers g inspect driverdir) then (
-    warning (f_"there are no virtio drivers available for this version of Windows (%d.%d %s %s).  virt-v2v looks for drivers in %s\n\nThe guest will be configured to use slower emulated devices.")
+    match rcaps with
+    | { rcaps_block_bus = Some Virtio_blk }
+    | { rcaps_net_bus = Some Virtio_net }
+    | { rcaps_video = Some QXL } ->
+      error (f_"there are no virtio drivers available for this version of Windows (%d.%d %s %s).  virt-v2v looks for drivers in %s")
             inspect.i_major_version inspect.i_minor_version inspect.i_arch
-            inspect.i_product_variant virtio_win;
-    ( IDE, RTL8139, Cirrus )
+            inspect.i_product_variant virtio_win
+
+    | { rcaps_block_bus = (Some IDE | None);
+        rcaps_net_bus = ((Some E1000 | Some RTL8139 | None) as net_type);
+        rcaps_video = (Some Cirrus | None) } ->
+      warning (f_"there are no virtio drivers available for this version of Windows (%d.%d %s %s).  virt-v2v looks for drivers in %s\n\nThe guest will be configured to use slower emulated devices.")
+              inspect.i_major_version inspect.i_minor_version inspect.i_arch
+              inspect.i_product_variant virtio_win;
+      let net_type =
+        match net_type with
+        | Some model -> model
+        | None -> RTL8139 in
+      (IDE, net_type, Cirrus)
   )
   else (
     (* Can we install the block driver? *)
     let block : guestcaps_block_type =
-      let source = driverdir // "viostor.sys" in
-      if g#exists source then (
+      let has_viostor = g#exists (driverdir // "viostor.inf") in
+      match rcaps.rcaps_block_bus, has_viostor with
+      | Some Virtio_blk, false ->
+        error (f_"there is no viostor (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.")
+              inspect.i_major_version inspect.i_minor_version
+              inspect.i_arch virtio_win
+
+      | None, false ->
+        warning (f_"there is no viostor (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.")
+                inspect.i_major_version inspect.i_minor_version
+                inspect.i_arch virtio_win;
+        IDE
+
+      | (Some Virtio_blk | None), true ->
+        (* Block driver needs tweaks to allow booting; the rest is set up by PnP
+         * manager *)
+        let source = driverdir // "viostor.sys" in
         let target = sprintf "%s/system32/drivers/viostor.sys" systemroot in
         let target = g#case_sensitive_path target in
         g#cp source target;
         add_viostor_to_registry g inspect root current_cs;
         Virtio_blk
-      ) else (
-        warning (f_"there is no viostor (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.")
-                inspect.i_major_version inspect.i_minor_version
-                inspect.i_arch virtio_win;
-        IDE
-      ) in
+
+      | Some IDE, _ ->
+        IDE in
 
     (* Can we install the virtio-net driver? *)
     let net : guestcaps_net_type =
-      if not (g#exists (driverdir // "netkvm.inf")) then (
+      let has_netkvm = g#exists (driverdir // "netkvm.inf") in
+      match rcaps.rcaps_net_bus, has_netkvm with
+      | Some Virtio_net, false ->
+        error (f_"there is no virtio network driver for this version of Windows (%d.%d %s).  virt-v2v looks for this driver in %s")
+              inspect.i_major_version inspect.i_minor_version
+              inspect.i_arch virtio_win
+
+      | None, false ->
         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.")
                 inspect.i_major_version inspect.i_minor_version
                 inspect.i_arch virtio_win;
         RTL8139
-      )
-      else
-        (* It will be installed at firstboot. *)
-        Virtio_net in
+
+      | (Some Virtio_net | None), true ->
+        Virtio_net
+
+      | Some net_type, _ ->
+        net_type in
 
     (* Can we install the QXL driver? *)
     let video : guestcaps_video_type =
-      if not (g#exists (driverdir // "qxl.inf")) then (
+      let has_qxl = g#exists (driverdir // "qxl.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")
+              inspect.i_major_version inspect.i_minor_version
+              inspect.i_arch virtio_win
+
+      | None, false ->
         warning (f_"there is no QXL 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 basic VGA display driver.")
                 inspect.i_major_version inspect.i_minor_version
                 inspect.i_arch virtio_win;
         Cirrus
-      )
-      else
-        (* It will be installed at firstboot. *)
-        QXL in
+
+      | (Some QXL | None), true ->
+        QXL
+
+      | Some Cirrus, _ ->
+        Cirrus in
 
     (block, net, video)
   )
diff --git a/v2v/windows_virtio.mli b/v2v/windows_virtio.mli
index 2046fae..86dbaf6 100644
--- a/v2v/windows_virtio.mli
+++ b/v2v/windows_virtio.mli
@@ -20,6 +20,7 @@
 
 val install_drivers
     : Guestfs.guestfs -> Types.inspect -> string -> int64 -> string ->
+      Types.requested_guestcaps ->
       Types.guestcaps_block_type * Types.guestcaps_net_type * Types.guestcaps_video_type
 (** [install_drivers g inspect systemroot root current_cs]
     installs virtio drivers from the driver directory or driver
@@ -30,6 +31,11 @@ val install_drivers
     when this function is called).  [current_cs] is the name of the
     [CurrentControlSet] (eg. ["ControlSet001"]).
 
+    [rcaps] is the set of guest "capabilities" requested by the caller.  This
+    may include the type of the block driver, network driver, and video driver.
+    install_drivers will adjust its choices based on that information, and
+    abort if the requested driver wasn't found.
+
     This returns the tuple [(block_driver, net_driver, video_driver)]
     reflecting what devices are now required by the guest, either
     virtio devices if we managed to install those, or legacy devices
-- 
2.5.0




More information about the Libguestfs mailing list