Roman Kagan
2016-Feb-20 08:26 UTC
[Libguestfs] [PATCH v2 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. --- v2: - add catch-all string-valued variants for source network and video adapter models - use match instead of mixing match and if 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 | 27 +++++++++++ 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 | 77 +++++++++++++++++++++++++----- v2v/types.mli | 19 +++++++- v2v/v2v.ml | 58 +++++++++++++++++++++-- v2v/windows_virtio.ml | 89 ++++++++++++++++++++++++++--------- v2v/windows_virtio.mli | 6 +++ 17 files changed, 298 insertions(+), 56 deletions(-) -- 2.5.0
Roman Kagan
2016-Feb-20 08:26 UTC
[Libguestfs] [PATCH v2 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> --- Notes: v2: - add catch-all string-valued variants for source network and video adapter models test-data/phony-guests/guests.xml.in | 8 ++++++++ v2v/input_disk.ml | 2 ++ v2v/input_libvirtxml.ml | 27 +++++++++++++++++++++++++++ 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 | 30 ++++++++++++++++++++++++++++-- v2v/types.mli | 9 +++++++++ 10 files changed, 82 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..9d8963d 100644 --- a/v2v/input_libvirtxml.ml +++ b/v2v/input_libvirtxml.ml @@ -140,6 +140,23 @@ 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 -> Some (Source_other_video model) + ) in + (* Sound card. *) let sound let obj = Xml.xpath_eval_expression xpathctx "/domain/devices/sound" in @@ -329,6 +346,14 @@ 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 -> Some (Source_other_nic model) in + let vnet_type match xpath_string "@type" with | Some "network" -> Some Network @@ -340,6 +365,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 +392,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..a082c37 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,13 @@ 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_other_nic of string | + Source_rtl8139 | Source_e1000 | Source_virtio_net and vnet_type = Bridge | Network and source_display = { s_display_type : s_display_type; @@ -81,6 +85,9 @@ and s_display_listen | LAddress of string | LNetwork of string +and source_video = Source_other_video of string | + Source_Cirrus | Source_QXL + and source_sound = { s_sound_model : source_sound_model; } @@ -95,6 +102,7 @@ hypervisor type: %s CPU features: %s firmware: %s display: %s + video: %s sound: %s disks: %s @@ -112,6 +120,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 +199,23 @@ 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" + | Source_other_nic model -> model and string_of_source_display { s_display_type = typ; s_keymap = keymap; s_password = password; @@ -209,6 +230,11 @@ 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" + | Source_other_video video -> video + 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..f58028f 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,14 @@ 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_other_nic of string | + Source_rtl8139 | Source_e1000 | Source_virtio_net (** Network interfaces. *) and vnet_type = Bridge | Network @@ -103,6 +108,10 @@ and s_display_listen | LAddress of string (** Listen address. *) | LNetwork of string (** Listen network. *) +(** Video adapter model. *) +and source_video = Source_other_video of string | + Source_Cirrus | Source_QXL + and source_sound = { s_sound_model : source_sound_model; (** Sound model. *) } -- 2.5.0
Roman Kagan
2016-Feb-20 08:26 UTC
[Libguestfs] [PATCH v2 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 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 a082c37..821b7ec 100644 --- a/v2v/types.ml +++ b/v2v/types.ml @@ -361,10 +361,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 @@ -372,19 +391,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 f58028f..0e40668 100644 --- a/v2v/types.mli +++ b/v2v/types.mli @@ -207,6 +207,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 @@ -214,6 +221,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-20 08:26 UTC
[Libguestfs] [PATCH v2 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> --- 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
Roman Kagan
2016-Feb-20 08:26 UTC
[Libguestfs] [PATCH v2 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> --- Notes: v2: - accept catch-all variants of source net and video as no preference 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 0e40668..fbd45cf 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_other_nic of string | Source_rtl8139 | Source_e1000 | Source_virtio_net (** Network interfaces. *) @@ -108,7 +108,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_other_video of string | Source_Cirrus | Source_QXL diff --git a/v2v/v2v.ml b/v2v/v2v.ml index c828e48..608150f 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 + | Some Source_other_nic _ | None -> None in + + let video + match source.s_video with + | Some Source_QXL -> Some QXL + | Some Source_Cirrus -> Some Cirrus + | Some Source_other_video _ | 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-22 14:12 UTC
Re: [Libguestfs] [PATCH v2 1/4] v2v: collect source network and video adapter types
On Sat, Feb 20, 2016 at 11:26:07AM +0300, Roman Kagan wrote:> 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> > --- > > Notes: > v2: > - add catch-all string-valued variants for source network and video adapter > modelsYup this one is all good now. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com libguestfs lets you edit virtual machines. Supports shell scripting, bindings from many languages. http://libguestfs.org
Richard W.M. Jones
2016-Feb-22 14:12 UTC
Re: [Libguestfs] [PATCH v2 2/4] v2v: introduce requested guestcaps type
On Sat, Feb 20, 2016 at 11:26:08AM +0300, Roman Kagan wrote:> 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 devices and drivers. > > Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>All good, as before. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com libguestfs lets you edit virtual machines. Supports shell scripting, bindings from many languages. http://libguestfs.org
Richard W.M. Jones
2016-Feb-22 14:20 UTC
Re: [Libguestfs] [PATCH v2 3/4] v2v: take requested caps into account when converting
On Sat, Feb 20, 2016 at 11:26:09AM +0300, Roman Kagan wrote:> 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> > --- > > Notes: > v2: > - use match instead of mixing match and ifI find the Windows_virtio.install_drivers function considerably easier to follow now, thanks. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com libguestfs lets you edit virtual machines. Supports shell scripting, bindings from many languages. http://libguestfs.org
Richard W.M. Jones
2016-Feb-22 15:04 UTC
Re: [Libguestfs] [PATCH v2 4/4] v2v: in-place: request caps based on source config
On Sat, Feb 20, 2016 at 11:26:10AM +0300, Roman Kagan wrote:> 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> > --- > > Notes: > v2: > - accept catch-all variants of source net and video as no preference > > 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 0e40668..fbd45cf 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_other_nic of string | > Source_rtl8139 | Source_e1000 | Source_virtio_net > (** Network interfaces. *) > @@ -108,7 +108,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_other_video of string | > Source_Cirrus | Source_QXL > > diff --git a/v2v/v2v.ml b/v2v/v2v.ml > index c828e48..608150f 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 (_, _) ->You can just write this: | 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 > + | Some Source_other_nic _ | None -> None in > + > + let video > + match source.s_video with > + | Some Source_QXL -> Some QXL > + | Some Source_Cirrus -> Some Cirrus > + | Some Source_other_video _ | None -> None in > + > + { > + rcaps_block_bus = block_type; > + rcaps_net_bus = net_type; > + rcaps_video = video; > + } > + > let () = run_main_and_handle_errors mainIt's a bit surprising, because I thought that you'd want to pass in the requested preferences on the command line? About the specific issue of ordering, although what you've written works, you could find a few surprises. eg: $ rlwrap ocaml OCaml version 4.02.3 # type t = A | B | C ;; type t = A | B | C # A < C ;; - : bool = true # A < B ;; - : bool = true # B < C ;; - : bool = true but ... # type t = A | B of int | C ;; type t = A | B of int | C # A < C ;; - : bool = true # A < B 3 ;; - : bool = true # B 3 < C ;; - : bool = false This happens because adding a parameter to an enum changes the internal representation. So the code as written could stop working with innocuous changes to the declared types, or even in a future version of OCaml, because it depends on internals of the OCaml representation. IMHO it's safer to make the ordering you want explicit. So: let precedence_of_s_controller_option = function | None -> 0 (* worst *) | Some Source_IDE -> 1 | Some Source_SCSI -> 2 | Some Source_virtio_blk -> 3 (* best *) and then you can have a function that finds the best "something" in a list of "somethings", using a polymorphic precedence function to compare the best: let rec find_best precedence = function | [] -> None, 0 | x :: xs -> let precedence_of_x = precedence x and best_in_xs, precedence_of_xs = find_best precedence xs in if precedence_of_x > precedence_of_xs then x, precedence_of_x else best_in_xs, precedence_of_xs This function has type: val find_best : ('a option -> int) -> 'a option list -> 'a option * int (Note it returns a pair: the best choice and also the precedence integer of that choice). The code to find the best block_type or net_type falls out fairly easily: let block_type let sctrls = List.map (fun sd -> sd.s_controller) source.s_disks in let best, _ = find_best precedence_of_s_controller_option sctrls in match best with | Some Source_virtio_blk -> Some Virtio_blk | Some Source_SCSI -> None | Some Source_IDE -> Some IDE | None -> None in 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/
Seemingly Similar Threads
- [PATCH 0/4] v2v: more control over device types
- [PATCH v3 0/5] v2v: more control over device types
- [PATCH v4 0/5] v2v: more control over device types
- Re: [PATCH v2 4/4] v2v: in-place: request caps based on source config
- Re: [PATCH 3/4] v2v: take requested caps into account when converting