Roman Kagan
2016-Feb-09 14:53 UTC
[Libguestfs] [PATCH 0/4] v2v: more control over device types
The decision on which device type to use for disks, network and video cards on output used to be taken deep inside the converting functions. This is not always desirable. In particular, there are scenarios when this decision is made before the convertion takes place. E.g. in in-place mode, the decisions are taken and the output VM configuration is created outside of v2v tool. This patchset adds support for such scenarios. Specifically, - the input configuration parsers are taught to extract network and video device models in addition to storage controllers - the converting functions are taught to take the requested device types into consideration - the main routine in in-place mode takes the relevant data from the input VM and passes it to the converter The copying mode may eventually also profit from this patchset by taking command-line options for controlling device types, but this isn't included here. Roman Kagan (4): v2v: collect source network and video adapter types v2v: introduce requested guestcaps type v2v: take requested caps into account when converting v2v: in-place: request caps based on source config test-data/phony-guests/guests.xml.in | 8 +++ v2v/convert_linux.ml | 49 +++++++++++---- v2v/convert_windows.ml | 4 +- v2v/input_disk.ml | 2 + v2v/input_libvirtxml.ml | 32 ++++++++++ v2v/input_ova.ml | 2 + v2v/modules_list.ml | 3 +- v2v/modules_list.mli | 3 +- v2v/test-v2v-i-ova-formats.expected | 1 + v2v/test-v2v-i-ova-gz.expected | 1 + v2v/test-v2v-i-ova-two-disks.expected | 1 + v2v/test-v2v-print-source.sh | 4 +- v2v/types.ml | 73 +++++++++++++++++++---- v2v/types.mli | 17 +++++- v2v/v2v.ml | 58 +++++++++++++++++- v2v/windows_virtio.ml | 108 ++++++++++++++++++++++++---------- v2v/windows_virtio.mli | 8 ++- 17 files changed, 309 insertions(+), 65 deletions(-) -- 2.5.0
Roman Kagan
2016-Feb-09 14:53 UTC
[Libguestfs] [PATCH 1/4] v2v: collect source network and video adapter types
Those will be useful when making decisions about what configuration to set on output. The data is also included in --print-source so the tests are adjusted accordingly. Signed-off-by: Roman Kagan <rkagan@virtuozzo.com> --- test-data/phony-guests/guests.xml.in | 8 ++++++++ v2v/input_disk.ml | 2 ++ v2v/input_libvirtxml.ml | 32 ++++++++++++++++++++++++++++++++ v2v/input_ova.ml | 2 ++ v2v/test-v2v-i-ova-formats.expected | 1 + v2v/test-v2v-i-ova-gz.expected | 1 + v2v/test-v2v-i-ova-two-disks.expected | 1 + v2v/test-v2v-print-source.sh | 4 +++- v2v/types.ml | 26 ++++++++++++++++++++++++-- v2v/types.mli | 7 +++++++ 10 files changed, 81 insertions(+), 3 deletions(-) diff --git a/test-data/phony-guests/guests.xml.in b/test-data/phony-guests/guests.xml.in index 8f7ac81..9c7c989 100644 --- a/test-data/phony-guests/guests.xml.in +++ b/test-data/phony-guests/guests.xml.in @@ -276,6 +276,14 @@ <source file='@abs_builddir@/windows.img'/> <target dev='vda' bus='virtio'/> </disk> + <interface type='network'> + <mac address='00:11:22:33:44:55'/> + <source network='default'/> + <model type='virtio'/> + </interface> + <video> + <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1'/> + </video> </devices> </domain> diff --git a/v2v/input_disk.ml b/v2v/input_disk.ml index 1cb6713..17ad61d 100644 --- a/v2v/input_disk.ml +++ b/v2v/input_disk.ml @@ -75,6 +75,7 @@ class input_disk input_format disk = object (* Give the guest a simple generic network interface. *) let network = { s_mac = None; + s_nic_model = None; s_vnet = "default"; s_vnet_orig = "default"; s_vnet_type = Network } in @@ -89,6 +90,7 @@ class input_disk input_format disk = object s_display Some { s_display_type = Window; s_keymap = None; s_password = None; s_listen = LNone; s_port = None }; + s_video = None; s_sound = None; s_disks = [disk]; s_removables = []; diff --git a/v2v/input_libvirtxml.ml b/v2v/input_libvirtxml.ml index 3537011..c6f7a1f 100644 --- a/v2v/input_libvirtxml.ml +++ b/v2v/input_libvirtxml.ml @@ -140,6 +140,25 @@ let parse_libvirt_xml ?conn xml None ) in + (* Video adapter. *) + let video + let obj = Xml.xpath_eval_expression xpathctx "/domain/devices/video" in + let nr_nodes = Xml.xpathobj_nr_nodes obj in + if nr_nodes < 1 then None + else ( + (* Ignore everything except the first <video> device. *) + let node = Xml.xpathobj_node obj 0 in + + Xml.xpathctx_set_current_context xpathctx node; + match xpath_string "model/@type" with + | None -> None + | Some "qxl" | Some "virtio" -> Some Source_QXL + | Some "cirrus" | Some "vga" -> Some Source_Cirrus + | Some model -> + warning (f_"unknown video adapter model %s ignored") model; + None + ) in + (* Sound card. *) let sound let obj = Xml.xpath_eval_expression xpathctx "/domain/devices/sound" in @@ -329,6 +348,17 @@ let parse_libvirt_xml ?conn xml | Some "00:00:00:00:00:00" (* thanks, VMware *) -> None | Some mac -> Some mac in + let model + match xpath_string "model/@type" with + | None -> None + | Some "virtio" -> Some Source_virtio_net + | Some "e1000" -> Some Source_e1000 + | Some "rtl8139" -> Some Source_rtl8139 + | Some model -> + warning (f_"unknown network adapter model %s ignored") model; + None + in + let vnet_type match xpath_string "@type" with | Some "network" -> Some Network @@ -340,6 +370,7 @@ let parse_libvirt_xml ?conn xml let add_nic vnet let nic = { s_mac = mac; + s_nic_model = model; s_vnet = vnet; s_vnet_orig = vnet; s_vnet_type = vnet_type @@ -366,6 +397,7 @@ let parse_libvirt_xml ?conn xml s_features = features; s_firmware = UnknownFirmware; (* XXX until RHBZ#1217444 is fixed *) s_display = display; + s_video = video; s_sound = sound; s_disks = []; s_removables = removables; diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml index c8c6b94..db0588d 100644 --- a/v2v/input_ova.ml +++ b/v2v/input_ova.ml @@ -350,6 +350,7 @@ object xpath_string_default "rasd:ElementName/text()" (sprintf"eth%d" i) in let nic = { s_mac = None; + s_nic_model = None; s_vnet = vnet; s_vnet_orig = vnet; s_vnet_type = Network; @@ -366,6 +367,7 @@ object s_features = []; (* XXX *) s_firmware = firmware; s_display = None; (* XXX *) + s_video = None; s_sound = None; s_disks = disks; s_removables = removables; diff --git a/v2v/test-v2v-i-ova-formats.expected b/v2v/test-v2v-i-ova-formats.expected index c83e5dd..7049aee 100644 --- a/v2v/test-v2v-i-ova-formats.expected +++ b/v2v/test-v2v-i-ova-formats.expected @@ -7,6 +7,7 @@ hypervisor type: vmware CPU features: firmware: uefi display: + video: sound: disks: disk1.vmdk (vmdk) [scsi] diff --git a/v2v/test-v2v-i-ova-gz.expected b/v2v/test-v2v-i-ova-gz.expected index be6cde3..50ba746 100644 --- a/v2v/test-v2v-i-ova-gz.expected +++ b/v2v/test-v2v-i-ova-gz.expected @@ -7,6 +7,7 @@ hypervisor type: vmware CPU features: firmware: bios display: + video: sound: disks: .vmdk (vmdk) [scsi] diff --git a/v2v/test-v2v-i-ova-two-disks.expected b/v2v/test-v2v-i-ova-two-disks.expected index dcbd43e..cc850a7 100644 --- a/v2v/test-v2v-i-ova-two-disks.expected +++ b/v2v/test-v2v-i-ova-two-disks.expected @@ -7,6 +7,7 @@ hypervisor type: vmware CPU features: firmware: bios display: + video: sound: disks: disk1.vmdk (vmdk) [scsi] diff --git a/v2v/test-v2v-print-source.sh b/v2v/test-v2v-print-source.sh index 8dd0145..8af6104 100755 --- a/v2v/test-v2v-print-source.sh +++ b/v2v/test-v2v-print-source.sh @@ -60,11 +60,13 @@ hypervisor type: test CPU features: firmware: unknown display: + video: qxl sound: disks: /windows.img (raw) [virtio] removable media: -NICs:" ]; then +NICs: + Network \"default\" mac: 00:11:22:33:44:55 [virtio]" ]; then echo "$0: unexpected output from test:" cat $d/output.orig exit 1 diff --git a/v2v/types.ml b/v2v/types.ml index a9d28e0..2cb67fb 100644 --- a/v2v/types.ml +++ b/v2v/types.ml @@ -32,6 +32,7 @@ type source = { s_features : string list; s_firmware : source_firmware; s_display : source_display option; + s_video : source_video option; s_sound : source_sound option; s_disks : source_disk list; s_removables : source_removable list; @@ -63,10 +64,12 @@ and source_removable = { and s_removable_type = CDROM | Floppy and source_nic = { s_mac : string option; + s_nic_model : s_nic_model option; s_vnet : string; s_vnet_orig : string; s_vnet_type : vnet_type; } +and s_nic_model = Source_rtl8139 | Source_e1000 | Source_virtio_net and vnet_type = Bridge | Network and source_display = { s_display_type : s_display_type; @@ -81,6 +84,8 @@ and s_display_listen | LAddress of string | LNetwork of string +and source_video = Source_Cirrus | Source_QXL + and source_sound = { s_sound_model : source_sound_model; } @@ -95,6 +100,7 @@ hypervisor type: %s CPU features: %s firmware: %s display: %s + video: %s sound: %s disks: %s @@ -112,6 +118,9 @@ NICs: (match s.s_display with | None -> "" | Some display -> string_of_source_display display) + (match s.s_video with + | None -> "" + | Some video -> string_of_source_video video) (match s.s_sound with | None -> "" | Some sound -> string_of_source_sound sound) @@ -188,13 +197,22 @@ and string_of_source_removable { s_removable_type = typ; | Some controller -> " [" ^ string_of_controller controller ^ "]") (match i with None -> "" | Some i -> sprintf " in slot %d" i) -and string_of_source_nic { s_mac = mac; s_vnet = vnet; s_vnet_type = typ } - sprintf "\t%s \"%s\"%s" +and string_of_source_nic { s_mac = mac; s_nic_model = model; s_vnet = vnet; + s_vnet_type = typ } + sprintf "\t%s \"%s\"%s%s" (match typ with Bridge -> "Bridge" | Network -> "Network") vnet (match mac with | None -> "" | Some mac -> " mac: " ^ mac) + (match model with + | None -> "" + | Some model -> " [" ^ string_of_nic_model model ^ "]") + +and string_of_nic_model = function + | Source_virtio_net -> "virtio" + | Source_e1000 -> "e1000" + | Source_rtl8139 -> "rtl8139" and string_of_source_display { s_display_type = typ; s_keymap = keymap; s_password = password; @@ -209,6 +227,10 @@ and string_of_source_display { s_display_type = typ; | LNetwork n -> sprintf " listening on network %s" n ) +and string_of_source_video = function + | Source_QXL -> "qxl" + | Source_Cirrus -> "cirrus" + and string_of_source_sound { s_sound_model = model } string_of_source_sound_model model diff --git a/v2v/types.mli b/v2v/types.mli index f482a92..656ae03 100644 --- a/v2v/types.mli +++ b/v2v/types.mli @@ -29,6 +29,7 @@ type source = { s_features : string list; (** Machine features. *) s_firmware : source_firmware; (** Firmware (BIOS or EFI). *) s_display : source_display option; (** Guest display. *) + s_video : source_video option; (** Video adapter. *) s_sound : source_sound option; (** Sound card. *) s_disks : source_disk list; (** Disk images. *) s_removables : source_removable list; (** CDROMs etc. *) @@ -82,10 +83,13 @@ and s_removable_type = CDROM | Floppy and source_nic = { s_mac : string option; (** MAC address. *) + s_nic_model : s_nic_model option; (** Network adapter model. *) s_vnet : string; (** Source network name. *) s_vnet_orig : string; (** Original network (if we map it). *) s_vnet_type : vnet_type; (** Source network type. *) } +(** Network adapter models. *) +and s_nic_model = Source_rtl8139 | Source_e1000 | Source_virtio_net (** Network interfaces. *) and vnet_type = Bridge | Network @@ -103,6 +107,9 @@ and s_display_listen | LAddress of string (** Listen address. *) | LNetwork of string (** Listen network. *) +(** Video adapter model. *) +and source_video = Source_Cirrus | Source_QXL + and source_sound = { s_sound_model : source_sound_model; (** Sound model. *) } -- 2.5.0
Roman Kagan
2016-Feb-09 14:53 UTC
[Libguestfs] [PATCH 2/4] v2v: introduce requested guestcaps type
Introduce a type to contain the guestcaps that are to be put in effect in the converted VM: options of the block type, net type, and video. It'll be populated by the caller and passed into convert function to affect its choice of of devices and drivers. Signed-off-by: Roman Kagan <rkagan@virtuozzo.com> --- v2v/types.ml | 47 +++++++++++++++++++++++++++++++++++++---------- v2v/types.mli | 8 ++++++++ 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/v2v/types.ml b/v2v/types.ml index 2cb67fb..ab27510 100644 --- a/v2v/types.ml +++ b/v2v/types.ml @@ -357,10 +357,29 @@ type guestcaps = { gcaps_arch : string; gcaps_acpi : bool; } +and requested_guestcaps = { + rcaps_block_bus : guestcaps_block_type option; + rcaps_net_bus : guestcaps_net_type option; + rcaps_video : guestcaps_video_type option; +} and guestcaps_block_type = Virtio_blk | IDE and guestcaps_net_type = Virtio_net | E1000 | RTL8139 and guestcaps_video_type = QXL | Cirrus +let string_of_block_type block_type + (match block_type with + | Virtio_blk -> "virtio-blk" + | IDE -> "ide") +let string_of_net_type net_type + (match net_type with + | Virtio_net -> "virtio-net" + | E1000 -> "e1000" + | RTL8139 -> "rtl8139") +let string_of_video video + (match video with + | QXL -> "qxl" + | Cirrus -> "cirrus") + let string_of_guestcaps gcaps sprintf "\ gcaps_block_bus = %s @@ -368,19 +387,27 @@ gcaps_net_bus = %s gcaps_video = %s gcaps_arch = %s gcaps_acpi = %b -" (match gcaps.gcaps_block_bus with - | Virtio_blk -> "virtio" - | IDE -> "ide") - (match gcaps.gcaps_net_bus with - | Virtio_net -> "virtio-net" - | E1000 -> "e1000" - | RTL8139 -> "rtl8139") - (match gcaps.gcaps_video with - | QXL -> "qxl" - | Cirrus -> "cirrus") +" (string_of_block_type gcaps.gcaps_block_bus) + (string_of_net_type gcaps.gcaps_net_bus) + (string_of_video gcaps.gcaps_video) gcaps.gcaps_arch gcaps.gcaps_acpi +let string_of_requested_guestcaps rcaps + sprintf "\ +rcaps_block_bus = %s +rcaps_net_bus = %s +rcaps_video = %s +" (match rcaps.rcaps_block_bus with + | None -> "unspecified" + | Some block_type -> (string_of_block_type block_type)) + (match rcaps.rcaps_net_bus with + | None -> "unspecified" + | Some net_type -> (string_of_net_type net_type)) + (match rcaps.rcaps_video with + | None -> "unspecified" + | Some video -> (string_of_video video)) + type target_buses = { target_virtio_blk_bus : target_bus_slot array; target_ide_bus : target_bus_slot array; diff --git a/v2v/types.mli b/v2v/types.mli index 656ae03..2949fd0 100644 --- a/v2v/types.mli +++ b/v2v/types.mli @@ -205,6 +205,13 @@ type guestcaps = { gcaps_arch : string; (** Architecture that KVM must emulate. *) gcaps_acpi : bool; (** True if guest supports acpi. *) } +and requested_guestcaps = { + rcaps_block_bus : guestcaps_block_type option; + rcaps_net_bus : guestcaps_net_type option; + rcaps_video : guestcaps_video_type option; + (** Requested guest capabilities, to allow the caller to affect converter + choices *) +} (** Guest capabilities after conversion. eg. Was virtio found or installed? *) and guestcaps_block_type = Virtio_blk | IDE @@ -212,6 +219,7 @@ and guestcaps_net_type = Virtio_net | E1000 | RTL8139 and guestcaps_video_type = QXL | Cirrus val string_of_guestcaps : guestcaps -> string +val string_of_requested_guestcaps : requested_guestcaps -> string type target_buses = { target_virtio_blk_bus : target_bus_slot array; -- 2.5.0
Roman Kagan
2016-Feb-09 14:53 UTC
[Libguestfs] [PATCH 3/4] v2v: take requested caps into account when converting
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@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
Roman Kagan
2016-Feb-09 14:53 UTC
[Libguestfs] [PATCH 4/4] v2v: in-place: request caps based on source config
In in-place mode, the decisions on which interfaces to use are made and the source configuration is created by the outside entity. So in that case v2v needs to look it up in the source configuraion, and try to follow. For that, the source configuration is used to populate requested caps object which is then passed to the convert routine. Signed-off-by: Roman Kagan <rkagan@virtuozzo.com> --- v2v/types.mli | 6 +++--- v2v/v2v.ml | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/v2v/types.mli b/v2v/types.mli index 2949fd0..7ee78bd 100644 --- a/v2v/types.mli +++ b/v2v/types.mli @@ -66,7 +66,7 @@ and source_disk = { (** A source disk. *) and s_controller = Source_IDE | Source_SCSI | Source_virtio_blk -(** Source disk controller. +(** Source disk controller (in ascending order of preference). For the purposes of this field, we can treat virtio-scsi as [SCSI]. However we don't support conversions from virtio in any @@ -88,7 +88,7 @@ and source_nic = { s_vnet_orig : string; (** Original network (if we map it). *) s_vnet_type : vnet_type; (** Source network type. *) } -(** Network adapter models. *) +(** Network adapter models (in ascending order of preference). *) and s_nic_model = Source_rtl8139 | Source_e1000 | Source_virtio_net (** Network interfaces. *) and vnet_type = Bridge | Network @@ -107,7 +107,7 @@ and s_display_listen | LAddress of string (** Listen address. *) | LNetwork of string (** Listen network. *) -(** Video adapter model. *) +(** Video adapter model (in ascending order of preference). *) and source_video = Source_Cirrus | Source_QXL and source_sound = { diff --git a/v2v/v2v.ml b/v2v/v2v.ml index c828e48..7f5decf 100644 --- a/v2v/v2v.ml +++ b/v2v/v2v.ml @@ -82,11 +82,17 @@ let rec main () ); let keep_serial_console = output#keep_serial_console in - let rcaps = { - rcaps_block_bus = None; - rcaps_net_bus = None; - rcaps_video = None; - } in + let rcaps + match conversion_mode with + | Copying (_, _) -> + { + rcaps_block_bus = None; + rcaps_net_bus = None; + rcaps_video = None; + } + | In_place -> + rcaps_from_source source + in let guestcaps = do_convert g inspect source keep_serial_console rcaps in g#umount_all (); @@ -974,4 +980,43 @@ and preserve_overlays overlays src_name printf (f_"Overlay saved as %s [--debug-overlays]\n") saved_filename ) overlays +and rcaps_from_source source + (* Request guest caps based on source configuration. *) + + (* rely on s_controller enum being in ascending preference order, and None + * being smaller than Some anything *) + let best_block_type + List.fold_left max None + (List.map (fun sd -> sd.s_controller) source.s_disks) in + let block_type + match best_block_type with + | Some Source_virtio_blk -> Some Virtio_blk + | Some Source_SCSI -> None + | Some Source_IDE -> Some IDE + | None -> None in + + (* rely on s_nic_model enum being in ascending preference order, and None + * being smaller than Some anything *) + let best_net_type + List.fold_left max None + (List.map (fun nic -> nic.s_nic_model) source.s_nics) in + let net_type + match best_net_type with + | Some Source_virtio_net -> Some Virtio_net + | Some Source_e1000 -> Some E1000 + | Some Source_rtl8139 -> Some RTL8139 + | None -> None in + + let video + match source.s_video with + | Some Source_QXL -> Some QXL + | Some Source_Cirrus -> Some Cirrus + | None -> None in + + { + rcaps_block_bus = block_type; + rcaps_net_bus = net_type; + rcaps_video = video; + } + let () = run_main_and_handle_errors main -- 2.5.0
Richard W.M. Jones
2016-Feb-09 18:15 UTC
Re: [Libguestfs] [PATCH 1/4] v2v: collect source network and video adapter types
On Tue, Feb 09, 2016 at 05:53:55PM +0300, Roman Kagan wrote:> +and s_nic_model = Source_rtl8139 | Source_e1000 | Source_virtio_net[...]> +and source_video = Source_Cirrus | Source_QXLAs you know there could be a lot of other input devices. At the moment the code basically ignores these (but it prints a warning "unknown [video|network] adapter model %s ignored"). I think we should only print warnings when that information is useful and/or actionable for the user, which it isn't in this case. (I know we don't always obey that rule right now, but I think it's still a good rule ...) So I think a better way to do it would be: and s_nic_model | Source_rtl8139 | Source_e1000 | Source_virtio_net | Source_other_nic of string and source_video | Source_Cirrus | Source_QXL | Source_other_video of string and then change the match code to be something like: let model match xpath_string "model/@type" with | None -> None | Some "virtio" -> Some Source_virtio_net | Some "e1000" -> Some Source_e1000 | Some "rtl8139" -> Some Source_rtl8139 | Some model -> Some (Source_other_nic model) in (similarly for video model). We don't throw away the NIC model if it's something we can't handle, but we still have special cases for virtio-net/e1000/rtl8139, so we can handle them in a type safe way. BTW if you're wondering why I sometimes put the 'in' of 'let .. in' on the right hand side of the last line of code, and sometimes on a line by itself, it's because the rule is: Attach 'in' to the last line if what you're defining is a non-function. Put 'in' on a line on its own if what you're defining is a function. Above is an example of a non-function. An example of a function definition would be: let f () ... in Apart from that, the patch looks fine to me. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-p2v converts physical machines to virtual machines. Boot with a live CD or over the network (PXE) and turn machines into KVM guests. http://libguestfs.org/virt-v2v
Richard W.M. Jones
2016-Feb-09 18:18 UTC
Re: [Libguestfs] [PATCH 2/4] v2v: introduce requested guestcaps type
This patch is fine. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-df lists disk usage of guests without needing to install any software inside the virtual machine. Supports Linux and Windows. http://people.redhat.com/~rjones/virt-df/
Richard W.M. Jones
2016-Feb-09 19:02 UTC
Re: [Libguestfs] [PATCH 3/4] v2v: take requested caps into account when converting
On Tue, Feb 09, 2016 at 05:53:57PM +0300, Roman Kagan wrote:> 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;This is a bit obscure, and type unsafe. I think it's better to cover all the cases by a big match statement. The code would look something like this: if not (copy_drivers g inspect driverdir) then ( match rcaps with | { rcaps_block_bus = Some Virtio_blk } | { rcaps_net_bus = Some Virtio_net } | { rcaps_video = Some QXL } -> (* User requested virtio, but we have no virtio-win drivers. *) error [...] | { rcaps_block_bus = (Some IDE | None); rcaps_net_bus = ((Some E1000 | Some RTL8139 | None) as net_type); rcaps_video = (Some Cirrus | None) } -> warning [...]; let net_type match net_type with | Some model -> model | None -> RTL8139 in (IDE, model, Cirrus) ) else ( ...> 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 > + );Again, I found this code (and the following code for net/video) to be very confusing. Any time you've got multiple levels of match + if, you're probably doing it wrong, and it's better to do the whole lot with pattern matching (especially since the compiler helps you to find missing cases this way). For example: match rcaps.rcaps_block_bus, has_viostor with | { None, false } (* Warn the user things could be better with virtio-win, but continue * with IDE. *) warning [...]; IDE | { Some IDE, false } -> (* User requested IDE, so no warning is required. *) IDE | { Some Virtio_blk, false } -> (* Error: request cannot be satisfied *) error [...]; | { None, true } -> (* Good news, we can configure virtio-win. *) etc etc. I'm going to have to think about this some more. Rich.> (* 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 > > _______________________________________________ > Libguestfs mailing list > Libguestfs@redhat.com > https://www.redhat.com/mailman/listinfo/libguestfs-- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-df lists disk usage of guests without needing to install any software inside the virtual machine. Supports Linux and Windows. http://people.redhat.com/~rjones/virt-df/
Possibly Parallel Threads
- [PATCH v4 1/5] v2v: collect source network and video adapter types
- [PATCH v2 1/4] v2v: collect source network and video adapter types
- [PATCH 4/4] v2v: in-place: request caps based on source config
- [PATCH] v2v: Fix parsing of OVA files and documentation for --network and --bridge (RHBZ#1559027).
- [PATCH 2/2] v2v: -i ova: Factor out the OVF parsing into a separate module.