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(a)virtuozzo.com>
---
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 | 108 +++++++++++++++++++++++++++++++++++--------------
v2v/windows_virtio.mli | 8 +++-
7 files changed, 137 insertions(+), 51 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 bdce038..8e0430c 100644
--- a/v2v/windows_virtio.ml
+++ b/v2v/windows_virtio.ml
@@ -33,57 +33,105 @@ 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 (
+ let block_type = match rcaps.rcaps_block_bus with
+ | None -> IDE
+ | Some block_type -> block_type in
+ let net_type = match rcaps.rcaps_net_bus with
+ | None -> RTL8139
+ | Some net_type -> net_type in
+ let video = match rcaps.rcaps_video with
+ | None -> Cirrus
+ | Some video -> video in
+
+ if block_type = Virtio_blk || net_type = Virtio_net || video = QXL then
+ 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;
+
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;
- ( IDE, RTL8139, Cirrus )
+ ( block_type, net_type, video )
)
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 with
+ | None ->
+ if not has_viostor then (
+ 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
+ )
+ else
+ Virtio_blk
+ | Some blk_type ->
+ if blk_type = Virtio_blk && not has_viostor then
+ 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;
+ blk_type
+ in
+
+ (* Block driver needs tweaks to allow booting; the rest is set up by PnP
+ * manager *)
+ if block = Virtio_blk then (
+ 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
+ add_viostor_to_registry g inspect root current_cs
+ );
(* Can we install the virtio-net driver? *)
let net : guestcaps_net_type =
- if not (g#exists (driverdir // "netkvm.inf")) 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.")
- inspect.i_major_version inspect.i_minor_version
- inspect.i_arch virtio_win;
- RTL8139
- )
- else
- (* It will be installed at firstboot. *)
- Virtio_net in
+ let has_netkvm = g#exists (driverdir // "netkvm.inf") in
+ match rcaps.rcaps_net_bus with
+ | None ->
+ 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.")
+ inspect.i_major_version inspect.i_minor_version
+ inspect.i_arch virtio_win;
+ RTL8139
+ )
+ else
+ Virtio_net
+ | Some net_type ->
+ if net_type = Virtio_net && not has_netkvm then
+ 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;
+ net_type
+ in
(* Can we install the QXL driver? *)
let video : guestcaps_video_type =
- if not (g#exists (driverdir // "qxl.inf")) then (
- 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 standard
VGA.")
- inspect.i_major_version inspect.i_minor_version
- inspect.i_arch virtio_win;
- Cirrus
- )
- else
- (* It will be installed at firstboot. *)
- QXL in
+ let has_qxl = g#exists (driverdir // "qxl.inf") in
+ match rcaps.rcaps_video with
+ | None ->
+ if not has_qxl then (
+ 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 standard
VGA.")
+ inspect.i_major_version inspect.i_minor_version
+ inspect.i_arch virtio_win;
+ Cirrus
+ )
+ else
+ QXL
+ | Some video ->
+ if video = QXL && not has_qxl then
+ 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;
+ video
+ in
(block, net, video)
)
diff --git a/v2v/windows_virtio.mli b/v2v/windows_virtio.mli
index eb7a57a..1b3f14a 100644
--- a/v2v/windows_virtio.mli
+++ b/v2v/windows_virtio.mli
@@ -20,8 +20,9 @@
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 virtio_win root current_cs]
+(** [install_drivers g inspect systemroot virtio_win root current_cs rcaps]
installs virtio drivers from the driver directory or driver
ISO ([virtio_win]) into the guest driver directory and updates
the registry so that the [viostor.sys] driver gets loaded by
@@ -31,6 +32,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