Richard W.M. Jones
2014-Jun-23 11:32 UTC
[Libguestfs] [PATCH 00/14] Miscellaneous changes and fixes to virt-v2v
Miscellaneous changes to virt-v2v. This is just a dump of the patchset for virt-v2v that I'm working on, minus "the big one" which changes how virtio kernel/grub inspection works which is not ready for primetime yet. Rich.
Richard W.M. Jones
2014-Jun-23 11:32 UTC
[Libguestfs] [PATCH 01/14] v2v: Allow relative paths to appear in -i libvirtxml input.
When writing libvirt XML by hand, or for tests, this is immensely useful. --- mllib/common_utils.ml | 4 ++++ v2v/source_libvirt.ml | 28 ++++++++++++++++++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/mllib/common_utils.ml b/mllib/common_utils.ml index 1aa81fb..60e3812 100644 --- a/mllib/common_utils.ml +++ b/mllib/common_utils.ml @@ -458,3 +458,7 @@ let is_char_device file let is_directory path try Sys.is_directory path with Sys_error _ -> false + +let absolute_path path + if not (Filename.is_relative path) then path + else Sys.getcwd () // path diff --git a/v2v/source_libvirt.ml b/v2v/source_libvirt.ml index 3e252ed..245e0d2 100644 --- a/v2v/source_libvirt.ml +++ b/v2v/source_libvirt.ml @@ -24,7 +24,24 @@ open Common_utils open Types open Utils -let create_xml xml +let create_xml ?dir xml + (* When reading libvirt XML from a file (-i libvirtxml) we allow + * paths to disk images in the libvirt XML to be relative. Relative + * paths are in fact not permitted in real libvirt XML, but they are + * very useful when dealing with test images or when writing the XML + * by hand. + *) + let absolute_path_of_disk path + if not (Filename.is_relative path) then path + else ( + match dir with + | None -> + error (f_"libvirt returned a non-absolute path in the XML (%s)") path + | Some dir -> + dir // path + ) + in + let doc = Xml.parse_memory xml in let xpathctx = Xml.xpath_new_context doc in @@ -87,10 +104,12 @@ let create_xml xml match xpath_to_string "@type" "" with | "block" -> let path = xpath_to_string "source/@dev" "" in - if path <> "" then disks := (path, format) :: !disks + if path <> "" then + disks := (absolute_path_of_disk path, format) :: !disks | "file" -> let path = xpath_to_string "source/@file" "" in - if path <> "" then disks := (path, format) :: !disks + if path <> "" then + disks := (absolute_path_of_disk path, format) :: !disks | "network" -> (* We only handle <source protocol="nbd"> here, and that is * intended only for virt-p2v. Any other network disk is @@ -137,7 +156,8 @@ let create_xml xml let create_from_xml file let xml = read_whole_file file in - create_xml xml + let dir = Filename.dirname (absolute_path file) in + create_xml ~dir xml let create libvirt_uri guest let cmd -- 1.9.0
Richard W.M. Jones
2014-Jun-23 11:32 UTC
[Libguestfs] [PATCH 02/14] run: Add v2v/ subdirectory to $PATH.
--- run.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.in b/run.in index db29451..f09b8fd 100755 --- a/run.in +++ b/run.in @@ -74,7 +74,7 @@ fi # Set the PATH to contain all the libguestfs binaries. There are a # lot of binaries, so a lot of path entries. -PATH="$b/align:$b/builder:$b/cat:$b/customize:$b/df:$b/diff:$b/edit:$b/erlang:$b/fish:$b/format:$b/fuse:$b/inspector:$b/make-fs:$b/rescue:$b/resize:$b/sparsify:$b/sysprep:$b/test-tool:$b/tools:$PATH" +PATH="$b/align:$b/builder:$b/cat:$b/customize:$b/df:$b/diff:$b/edit:$b/erlang:$b/fish:$b/format:$b/fuse:$b/inspector:$b/make-fs:$b/rescue:$b/resize:$b/sparsify:$b/sysprep:$b/test-tool:$b/tools:$b/v2v:$PATH" export PATH # Set LD_LIBRARY_PATH to contain library. -- 1.9.0
Richard W.M. Jones
2014-Jun-23 11:32 UTC
[Libguestfs] [PATCH 03/14] v2v: Print qemu-img source overlay command when using -v.
--- v2v/v2v.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/v2v/v2v.ml b/v2v/v2v.ml index 6157aa3..4e64b99 100644 --- a/v2v/v2v.ml +++ b/v2v/v2v.ml @@ -66,6 +66,7 @@ let rec main () let cmd sprintf "qemu-img create -q -f qcow2 -b %s -o %s %s" (quote qemu_uri) (quote options) overlay in + if verbose then printf "%s\n%!" cmd; if Sys.command cmd <> 0 then error (f_"qemu-img command failed, see earlier errors"); overlay, qemu_uri, format -- 1.9.0
Richard W.M. Jones
2014-Jun-23 11:32 UTC
[Libguestfs] [PATCH 04/14] v2v: string_of_overlay already has trailing \n, don't need to add one.
--- v2v/v2v.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2v/v2v.ml b/v2v/v2v.ml index 4e64b99..fd6c049 100644 --- a/v2v/v2v.ml +++ b/v2v/v2v.ml @@ -162,7 +162,7 @@ let rec main () fun i ov -> msg (f_"Copying disk %d/%d to %s (%s)") (i+1) nr_overlays ov.ov_target_file ov.ov_target_format; - if verbose then printf "%s\n%!" (string_of_overlay ov); + if verbose then printf "%s%!" (string_of_overlay ov); (* It turns out that libguestfs's disk creation code is * considerably more flexible and easier to use than qemu-img, so -- 1.9.0
Richard W.M. Jones
2014-Jun-23 11:32 UTC
[Libguestfs] [PATCH 05/14] v2v: Dump out 'source' structure when debugging.
--- v2v/types.ml | 24 ++++++++++++++++++++++++ v2v/types.mli | 3 +++ v2v/v2v.ml | 2 ++ 3 files changed, 29 insertions(+) diff --git a/v2v/types.ml b/v2v/types.ml index 0f5ae86..9a41f18 100644 --- a/v2v/types.ml +++ b/v2v/types.ml @@ -40,6 +40,30 @@ type source = { } and source_disk = string * string option +let rec string_of_source s + sprintf "\ +s_dom_type = %s +s_name = %s +s_memory = %Ld +s_vcpu = %d +s_arch = %s +s_features = [%s] +s_disks = [%s] +" + s.s_dom_type + s.s_name + s.s_memory + s.s_vcpu + s.s_arch + (String.concat "," s.s_features) + (String.concat "," (List.map string_of_source_disk s.s_disks)) + +and string_of_source_disk (path, format) + path ^ + match format with + | None -> "" + | Some format -> " (" ^ format ^ ")" + type overlay = { ov_overlay : string; ov_target_file : string; diff --git a/v2v/types.mli b/v2v/types.mli index e7e72e0..87ba291 100644 --- a/v2v/types.mli +++ b/v2v/types.mli @@ -43,6 +43,9 @@ type source = { and source_disk = string * string option (** A source file is a qemu URI and a format. *) +val string_of_source : source -> string +val string_of_source_disk : source_disk -> string + type overlay = { ov_overlay : string; (** Local overlay file (qcow2 format). *) ov_target_file : string; (** Destination file (real). *) diff --git a/v2v/v2v.ml b/v2v/v2v.ml index fd6c049..838354f 100644 --- a/v2v/v2v.ml +++ b/v2v/v2v.ml @@ -45,6 +45,8 @@ let rec main () | InputLibvirtXML filename -> Source_libvirt.create_from_xml filename in + if verbose then printf "%s%!" (string_of_source source); + (* Create a qcow2 v3 overlay to protect the source image(s). There * is a specific reason to use the newer qcow2 variant: Because the * L2 table can store zero clusters efficiently, and because -- 1.9.0
Richard W.M. Jones
2014-Jun-23 11:32 UTC
[Libguestfs] [PATCH 06/14] v2v: Print \n after warnings.
Using eprintf so this is not implicit (unlike 'error' function). --- v2v/convert_linux_enterprise.ml | 6 +++--- v2v/convert_linux_grub.ml | 2 +- v2v/source_libvirt.ml | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/v2v/convert_linux_enterprise.ml b/v2v/convert_linux_enterprise.ml index 4313fa3..64eb93d 100644 --- a/v2v/convert_linux_enterprise.ml +++ b/v2v/convert_linux_enterprise.ml @@ -197,7 +197,7 @@ Grub1/grub-legacy error was: %s") Convert_linux_common.augeas_reload verbose g with G.Error msg -> - eprintf (f_"%s: warning: VirtualBox Guest Additions were detected, but uninstallation failed. The error message was: %s (ignored)") + eprintf (f_"%s: warning: VirtualBox Guest Additions were detected, but uninstallation failed. The error message was: %s (ignored)\n%!") prog msg ) @@ -282,7 +282,7 @@ Grub1/grub-legacy error was: %s") Convert_linux_common.augeas_reload verbose g with G.Error msg -> - eprintf (f_"%s: warning: VMware tools was detected, but uninstallation failed. The error message was: %s (ignored)") + eprintf (f_"%s: warning: VMware tools was detected, but uninstallation failed. The error message was: %s (ignored)\n%!") prog msg ) @@ -372,7 +372,7 @@ Grub1/grub-legacy error was: %s") upgrade_package "kernel" (0_l, "2.6.25.5", "1.1") | _ -> - eprintf (f_"%s: warning: don't know how to install virtio drivers for %s %d") + eprintf (f_"%s: warning: don't know how to install virtio drivers for %s %d\n%!") prog distro major_version; false diff --git a/v2v/convert_linux_grub.ml b/v2v/convert_linux_grub.ml index 59dd4f2..1f4d1ae 100644 --- a/v2v/convert_linux_grub.ml +++ b/v2v/convert_linux_grub.ml @@ -272,7 +272,7 @@ object (self) ignore (g#command [| "grub2-mkconfig"; "-o"; config_file |]) with G.Error msg -> - eprintf (f_"%s: warning: could not update grub2 console: %s (ignored)\n") + eprintf (f_"%s: warning: could not update grub2 console: %s (ignored)\n%!") prog msg ) diff --git a/v2v/source_libvirt.ml b/v2v/source_libvirt.ml index 245e0d2..520b1e3 100644 --- a/v2v/source_libvirt.ml +++ b/v2v/source_libvirt.ml @@ -128,11 +128,12 @@ let create_xml ?dir xml ) | "" -> () | protocol -> - eprintf (f_"%s: warning: network <disk> with <source protocol='%s'> was ignored") + eprintf (f_"%s: warning: network <disk> with <source protocol='%s'> was ignored\n%!") prog protocol ) | disk_type -> - eprintf (f_"%s: warning: <disk type='%s'> was ignored") prog disk_type + eprintf (f_"%s: warning: <disk type='%s'> was ignored\n%!") + prog disk_type done; List.rev !disks in -- 1.9.0
Richard W.M. Jones
2014-Jun-23 11:32 UTC
[Libguestfs] [PATCH 07/14] v2v: In -o local mode, name disks <name>-sda instead of disk-sda.
This allows us to use the same shared output directory for multiple parallel tests. --- v2v/target_local.ml | 4 ++-- v2v/target_local.mli | 2 +- v2v/v2v.ml | 12 +++++++++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/v2v/target_local.ml b/v2v/target_local.ml index ed4e5e3..b37b6fa 100644 --- a/v2v/target_local.ml +++ b/v2v/target_local.ml @@ -24,10 +24,10 @@ open Common_utils open Types open Utils -let initialize dir overlays +let initialize dir source overlays List.map ( fun ov -> - let target_file = dir // "disk-" ^ ov.ov_sd in + let target_file = dir // source.s_name ^ "-" ^ ov.ov_sd in { ov with ov_target_file = target_file; ov_target_file_tmp = target_file } ) overlays diff --git a/v2v/target_local.mli b/v2v/target_local.mli index 1833ecb..4907ac1 100644 --- a/v2v/target_local.mli +++ b/v2v/target_local.mli @@ -16,6 +16,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *) -val initialize : string -> Types.overlay list -> Types.overlay list +val initialize : string -> Types.source -> Types.overlay list -> Types.overlay list val create_metadata : string -> Types.source -> Types.overlay list -> Types.guestcaps -> unit diff --git a/v2v/v2v.ml b/v2v/v2v.ml index 838354f..f7d29a3 100644 --- a/v2v/v2v.ml +++ b/v2v/v2v.ml @@ -93,7 +93,8 @@ let rec main () * work. *) let overlays - initialize_target g output output_alloc output_format overlays in + initialize_target g + source output output_alloc output_format output_name overlays in (* Inspection - this also mounts up the filesystems. *) msg (f_"Inspecting the overlay"); @@ -214,7 +215,8 @@ let rec main () if debug_gc then Gc.compact () -and initialize_target g output output_alloc output_format overlays +and initialize_target g + source output output_alloc output_format output_name overlays let overlays mapi ( fun i (overlay, qemu_uri, backing_format) -> @@ -247,9 +249,13 @@ and initialize_target g output output_alloc output_format overlays ov_source_file = qemu_uri; ov_source_format = backing_format; } ) overlays in let overlays + let renamed_source + match output_name with + | None -> source + | Some name -> { source with s_name = name } in match output with | OutputLibvirt oc -> assert false - | OutputLocal dir -> Target_local.initialize dir overlays + | OutputLocal dir -> Target_local.initialize dir renamed_source overlays | OutputRHEV os -> assert false in overlays -- 1.9.0
Richard W.M. Jones
2014-Jun-23 11:32 UTC
[Libguestfs] [PATCH 08/14] v2v: Avoid segfault if xpath expression doesn't match any nodes.
I'm not sure if this indicates that the xpath expression is wrong, but in any case it can be that xpathobj->nodesetval is NULL. In this case, return 0 from xpathobj_nr_nodes instead of segfaulting. --- v2v/xml-c.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/v2v/xml-c.c b/v2v/xml-c.c index a1b796c..cf5bff2 100644 --- a/v2v/xml-c.c +++ b/v2v/xml-c.c @@ -165,7 +165,10 @@ v2v_xml_xpathobj_nr_nodes (value xpathobjv) CAMLparam1 (xpathobjv); xmlXPathObjectPtr xpathobj = Xpathobj_val (xpathobjv); - CAMLreturn (Val_int (xpathobj->nodesetval->nodeNr)); + if (xpathobj->nodesetval == NULL) + CAMLreturn (Val_int (0)); + else + CAMLreturn (Val_int (xpathobj->nodesetval->nodeNr)); } value -- 1.9.0
Richard W.M. Jones
2014-Jun-23 11:32 UTC
[Libguestfs] [PATCH 09/14] v2v: When parsing input libvirt XML, get correct disk image format.
Old Xen PV guests had: <driver name='tap' type='aio'/> The previous xpath expression matched any driver type attribute in order to pick up the format. However we only want to match: <driver name='qemu' type='raw'/> so we need to check the name attribute as well. --- v2v/source_libvirt.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2v/source_libvirt.ml b/v2v/source_libvirt.ml index 520b1e3..4a3c9f1 100644 --- a/v2v/source_libvirt.ml +++ b/v2v/source_libvirt.ml @@ -95,7 +95,7 @@ let create_xml ?dir xml Xml.xpathctx_set_current_context xpathctx node; let format - let format = xpath_to_string "driver/@type" "" in + let format = xpath_to_string "driver[name='qemu']/@type" "" in if format <> "" then Some format else None in (* The <disk type='...'> attribute may be 'block', 'file' or -- 1.9.0
Richard W.M. Jones
2014-Jun-23 11:32 UTC
[Libguestfs] [PATCH 10/14] mllib: Move common code for comparing version strings to library.
--- builder/get_kernel.ml | 26 -------------------------- mllib/common_utils.ml | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/builder/get_kernel.ml b/builder/get_kernel.ml index 25e4293..7f93728 100644 --- a/builder/get_kernel.ml +++ b/builder/get_kernel.ml @@ -23,9 +23,6 @@ module G = Guestfs open Printf -let rex_numbers = Str.regexp "^\\([0-9]+\\)\\(.*\\)$" -let rex_letters = Str.regexp_case_fold "^\\([a-z]+\\)\\(.*\\)$" - (* Originally: * http://rwmj.wordpress.com/2013/09/13/get-kernel-and-initramfs-from-a-disk-image/ *) @@ -96,26 +93,3 @@ let rec get_kernel ~debug ?format ?output disk (* Shutdown. *) g#shutdown (); g#close () - -and compare_version v1 v2 - compare (split_version v1) (split_version v2) - -and split_version = function - | "" -> [] - | str -> - let first, rest - if Str.string_match rex_numbers str 0 then ( - let n = Str.matched_group 1 str in - let rest = Str.matched_group 2 str in - let n - try `Number (int_of_string n) - with Failure "int_of_string" -> `String n in - n, rest - ) - else if Str.string_match rex_letters str 0 then - `String (Str.matched_group 1 str), Str.matched_group 2 str - else ( - let len = String.length str in - `Char str.[0], String.sub str 1 (len-1) - ) in - first :: split_version rest diff --git a/mllib/common_utils.ml b/mllib/common_utils.ml index 60e3812..d4a97a7 100644 --- a/mllib/common_utils.ml +++ b/mllib/common_utils.ml @@ -340,6 +340,33 @@ let display_long_options () ) !long_options; exit 0 +(* Compare two version strings intelligently. *) +let rex_numbers = Str.regexp "^\\([0-9]+\\)\\(.*\\)$" +let rex_letters = Str.regexp_case_fold "^\\([a-z]+\\)\\(.*\\)$" + +let compare_version v1 v2 + let rec split_version = function + | "" -> [] + | str -> + let first, rest + if Str.string_match rex_numbers str 0 then ( + let n = Str.matched_group 1 str in + let rest = Str.matched_group 2 str in + let n + try `Number (int_of_string n) + with Failure "int_of_string" -> `String n in + n, rest + ) + else if Str.string_match rex_letters str 0 then + `String (Str.matched_group 1 str), Str.matched_group 2 str + else ( + let len = String.length str in + `Char str.[0], String.sub str 1 (len-1) + ) in + first :: split_version rest + in + compare (split_version v1) (split_version v2) + (* Run an external command, slurp up the output as a list of lines. *) let external_command ~prog cmd let chan = Unix.open_process_in cmd in -- 1.9.0
Richard W.M. Jones
2014-Jun-23 11:32 UTC
[Libguestfs] [PATCH 11/14] v2v: In convert function, add a hash of app name -> app structure.
For quicker lookups than searching the linear list. --- v2v/convert_linux_enterprise.ml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/v2v/convert_linux_enterprise.ml b/v2v/convert_linux_enterprise.ml index 64eb93d..11627a9 100644 --- a/v2v/convert_linux_enterprise.ml +++ b/v2v/convert_linux_enterprise.ml @@ -32,7 +32,9 @@ open Common_utils open Utils open Types -let rec convert ?(keep_serial_console = true) verbose (g : Guestfs.guestfs) +module StringMap = Map.Make (String) + +let rec convert ?(keep_serial_console = true) verbose (g : G.guestfs) ({ i_root = root; i_apps = apps } as inspect) source let typ = g#inspect_get_type root @@ -52,6 +54,17 @@ let rec convert ?(keep_serial_console = true) verbose (g : Guestfs.guestfs) and is_suse_family (distro = "sles" || distro = "suse-based" || distro = "opensuse") in + (* A map of app2_name -> application2, for easier lookups. Note + * that app names are not unique! (eg. 'kernel' can appear multiple + * times) + *) + let apps_map = List.fold_left ( + fun map app -> + let name = app.G.app2_name in + let vs = try StringMap.find name map with Not_found -> [] in + StringMap.add name (app :: vs) map + ) StringMap.empty apps in + let rec clean_rpmdb () (* Clean RPM database. *) assert (package_format = "rpm"); -- 1.9.0
Richard W.M. Jones
2014-Jun-23 11:32 UTC
[Libguestfs] [PATCH 12/14] v2v: Warn only if virtio packages are missing from the guest.
In this version of virt-v2v you have to install a virtio capable kernel before doing the conversion. --- v2v/convert_linux_enterprise.ml | 92 ++++++++++++++++++++++++++++++----------- v2v/virt-v2v.pod | 34 +++++++++++++++ 2 files changed, 102 insertions(+), 24 deletions(-) diff --git a/v2v/convert_linux_enterprise.ml b/v2v/convert_linux_enterprise.ml index 11627a9..6544b27 100644 --- a/v2v/convert_linux_enterprise.ml +++ b/v2v/convert_linux_enterprise.ml @@ -350,26 +350,28 @@ Grub1/grub-legacy error was: %s") if !updated then g#aug_save (); ) - and install_virtio () - (* How you install virtio depends on the guest type. Note that most - * modern guests already support virtio, so we do nothing for them. - * In Perl virt-v2v this was done via a configuration database - * (virt-v2v.db). This function returns true if virtio is supported - * already or if we managed to install it. + and can_do_virtio () + (* In the previous virt-v2v, this was a function that installed + * virtio, eg. by updating the kernel. However that function + * (which only applied to RHEL <= 5) was very difficult to write + * and maintain. Instead what we do here is to check if the kernel + * supports virtio, warn if it doesn't (and give some hint about + * what to do) and return false. Note that all recent Linux comes + * with virtio drivers. *) match distro, major_version, minor_version with (* RHEL 6+ has always supported virtio. *) | ("rhel"|"centos"|"scientificlinux"|"redhat-based"), v, _ when v >= 6 -> true | ("rhel"|"centos"|"scientificlinux"|"redhat-based"), 5, _ -> - let kernel = upgrade_package "kernel" (0_l, "2.6.18", "128.el5") in - let lvm2 = upgrade_package "lvm2" (0_l, "2.02.40", "6.el5") in + let kernel = check_kernel_package (0_l, "2.6.18", "128.el5") in + let lvm2 = check_package "lvm2" (0_l, "2.02.40", "6.el5") in let selinux - upgrade_package ~ifinstalled:true + check_package ~ifinstalled:true "selinux-policy-targeted" (0_l, "2.4.6", "203.el5") in kernel && lvm2 && selinux | ("rhel"|"centos"|"scientificlinux"|"redhat-based"), 4, _ -> - upgrade_package "kernel" (0_l, "2.6.9", "89.EL") + check_kernel_package (0_l, "2.6.9", "89.EL") (* All supported Fedora versions support virtio. *) | "fedora", _, _ -> true @@ -377,18 +379,71 @@ Grub1/grub-legacy error was: %s") (* SLES 11 supports virtio in the kernel. *) | ("sles"|"suse-based"), v, _ when v >= 11 -> true | ("sles"|"suse-based"), 10, _ -> - upgrade_package "kernel" (0_l, "2.6.16.60", "0.85.1") + check_kernel_package (0_l, "2.6.16.60", "0.85.1") (* OpenSUSE. *) | "opensuse", v, _ when v >= 11 -> true | "opensuse", 10, _ -> - upgrade_package "kernel" (0_l, "2.6.25.5", "1.1") + check_kernel_package (0_l, "2.6.25.5", "1.1") | _ -> eprintf (f_"%s: warning: don't know how to install virtio drivers for %s %d\n%!") prog distro major_version; false + and check_kernel_package minversion + let names = ["kernel"; "kernel-PAE"; "kernel-hugemem"; "kernel-smp"; + "kernel-largesmp"; "kernel-pae"; "kernel-default"] in + let found = List.exists ( + fun name -> check_package ~warn:false name minversion + ) names in + if not found then ( + let _, minversion, minrelease = minversion in + eprintf (f_"%s: warning: cannot enable virtio in this guest.\nTo enable virtio you need to install a kernel >= %s-%s and run %s again.\n%!") + prog minversion minrelease prog + ); + found + + and check_package ?(ifinstalled = false) ?(warn = true) name minversion + let installed + let apps = try StringMap.find name apps_map with Not_found -> [] in + List.rev (List.sort compare_app2_versions apps) in + + match ifinstalled, installed with + (* If the package is not installed, ignore the request. *) + | true, [] -> true + (* Is the package already installed at the minimum version? *) + | _, (installed::_) + when compare_app2_version_min installed minversion >= 0 -> true + (* User will need to install the package to get virtio. *) + | _ -> + if warn then ( + let _, minversion, minrelease = minversion in + eprintf (f_"%s: warning: cannot enable virtio in this guest.\nTo enable virtio you need to upgrade %s >= %s-%s and run %s again.\n%!") + prog name minversion minrelease prog + ); + false + + and compare_app2_versions app1 app2 + let i = compare app1.G.app2_epoch app2.G.app2_epoch in + if i <> 0 then i + else ( + let i = compare_version app1.G.app2_version app2.G.app2_version in + if i <> 0 then i + else + compare_version app1.G.app2_release app2.G.app2_release + ) + + and compare_app2_version_min app1 (min_epoch, min_version, min_release) + let i = compare app1.G.app2_epoch min_epoch in + if i <> 0 then i + else ( + let i = compare_version app1.G.app2_version min_version in + if i <> 0 then i + else + compare_version app1.G.app2_release min_release + ) + and configure_kernel virtio grub let kernels = grub#list_kernels () in @@ -600,17 +655,6 @@ Grub1/grub-legacy error was: %s") g#aug_save () - (* Upgrade 'pkg' to >= minversion. Returns true if that was possible. *) - and upgrade_package ?(ifinstalled = false) name minversion - - - - - - (* XXX *) - true - - in clean_rpmdb (); @@ -623,7 +667,7 @@ Grub1/grub-legacy error was: %s") unconfigure_vmware (); unconfigure_citrix (); - let virtio = install_virtio () in + let virtio = can_do_virtio () in let kernel_version = configure_kernel virtio grub in (*XXX*) ignore kernel_version; if keep_serial_console then ( configure_console (); diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod index 810bed5..b7f4726 100644 --- a/v2v/virt-v2v.pod +++ b/v2v/virt-v2v.pod @@ -208,6 +208,40 @@ Enable tracing of libguestfs API calls. =back +=head1 ENABLING VIRTIO + +"Virtio" is the name for a set of drivers which make disk (block +device), network and other guest operations work much faster on KVM. + +Older versions of virt-v2v could install these drivers for certain +guests. This version of virt-v2v does I<not> attempt to install these +drivers, but will warn you if they are not installed already. + +In order to enable virtio, and hence improve performance of the guest +after conversion, you should ensure that the B<minimum> versions of +packages are installed I<before> conversion, by consulting the table +below. + + RHEL 3 No virtio drivers are available + + RHEL 4 kernel >= 2.5.9-89.EL + + RHEL 5 kernel >= 2.6.18-128.el5 + lvm2 >= 2.02.40-6.el5 + selinux-policy-targeted >= 2.4.6-203.el5 + + RHEL 6+ All versions support virtio + + Fedora All versions support virtio + + SLES 11+ All versions support virtio + + SLES 10 kernel >= 2.6.16.60-0.85.1 + + OpenSUSE 11+ All versions support virtio + + OpenSUSE 10 kernel >= 2.6.25.5-1.1 + =head1 MACHINE READABLE OUTPUT The I<--machine-readable> option can be used to make the output more -- 1.9.0
Richard W.M. Jones
2014-Jun-23 11:32 UTC
[Libguestfs] [PATCH 13/14] mllib: Add an interface for Common_utils library.
It turned out that Common_utils was exporting the 'G' module (an alias for Guestfs). We want any code that uses G as a shortcut to declare: module G = Guestfs at the top, since that avoids confusion for newbie (or experienced) OCaml programmers. --- mllib/Makefile.am | 1 + mllib/common_utils.mli | 116 ++++++++++++++++++++++++++++++++++++++++ sparsify/cmdline.ml | 2 +- v2v/convert_linux_common.ml | 4 +- v2v/convert_linux_enterprise.ml | 2 + 5 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 mllib/common_utils.mli diff --git a/mllib/Makefile.am b/mllib/Makefile.am index 72a032c..7c242fc 100644 --- a/mllib/Makefile.am +++ b/mllib/Makefile.am @@ -26,6 +26,7 @@ CLEANFILES = *~ *.cmi *.cmo *.cmx *.cmxa *.o SOURCES = \ common_gettext.ml \ common_utils.ml \ + common_utils.mli \ common_utils_tests.ml \ config.ml \ fsync-c.c \ diff --git a/mllib/common_utils.mli b/mllib/common_utils.mli new file mode 100644 index 0000000..4368e57 --- /dev/null +++ b/mllib/common_utils.mli @@ -0,0 +1,116 @@ +(* Common utilities for OCaml tools in libguestfs. + * Copyright (C) 2010-2014 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + *) + +val ( // ) : string -> string -> string +(** Concatenate directory and filename. *) + +val ( +^ ) : int64 -> int64 -> int64 +val ( -^ ) : int64 -> int64 -> int64 +val ( *^ ) : int64 -> int64 -> int64 +val ( /^ ) : int64 -> int64 -> int64 +val ( &^ ) : int64 -> int64 -> int64 +val ( ~^ ) : int64 -> int64 +(** Various int64 operators. *) + +val roundup64 : int64 -> int64 -> int64 +val int_of_le32 : string -> int64 +val le32_of_int : int64 -> string + +val wrap : ?chan:out_channel -> ?hanging:int -> string -> unit +(** Wrap text. *) + +val string_prefix : string -> string -> bool +val string_find : string -> string -> int +val replace_str : string -> string -> string -> string +val string_nsplit : string -> string -> string list +val string_split : string -> string -> string * string +val string_random8 : unit -> string +(** Various string functions. *) + +val dropwhile : ('a -> bool) -> 'a list -> 'a list +val takewhile : ('a -> bool) -> 'a list -> 'a list +val filter_map : ('a -> 'b option) -> 'a list -> 'b list +val iteri : (int -> 'a -> 'b) -> 'a list -> unit +val mapi : (int -> 'a -> 'b) -> 'a list -> 'b list +(** Various higher-order functions. *) + +val make_message_function : quiet:bool -> ('a, unit, string, unit) format4 -> 'a +(** Timestamped progress messages. Used for ordinary messages when + not [--quiet]. *) + +val error : prog:string -> ?exit_code:int -> ('a, unit, string, 'b) format4 -> 'a +(** Standard error function. *) + +val read_whole_file : string -> string +(** Read in the whole file as a string. *) + +val parse_size : prog:string -> string -> int64 +(** Parse a size field, eg. [10G] *) + +val parse_resize : prog:string -> int64 -> string -> int64 +(** Parse a size field, eg. [10G], [+20%] etc. Used particularly by + [virt-resize --resize] and [--resize-force] options. *) + +val human_size : int64 -> string +(** Converts a size in bytes to a human-readable string. *) + +val skip_dashes : string -> string +(** Skip any leading '-' characters when comparing command line args. *) + +val compare_command_line_args : string -> string -> int +(** Compare command line arguments for equality, ignoring any leading [-]s. *) + +val long_options : (Arg.key * Arg.spec * Arg.doc) list ref +val display_long_options : unit -> 'a +(** Implements [--long-options]. *) + +val compare_version : string -> string -> int +(** Compare two version strings. *) + +val external_command : prog:string -> string -> string list +(** Run an external command, slurp up the output as a list of lines. *) + +val uuidgen : prog:string -> unit -> string +(** Run uuidgen to return a random UUID. *) + +val unlink_on_exit : string -> unit +(** Unlink a temporary file on exit. *) + +val rmdir_on_exit : string -> unit +(** Remove a temporary directory on exit (using [rm -rf]). *) + +val rm_rf_only_files : Guestfs.guestfs -> string -> unit +(** Using the libguestfs API, recursively remove only files from the + given directory. Useful for cleaning [/var/cache] etc in sysprep + without removing the actual directory structure. Also if [dir] is + not a directory or doesn't exist, ignore it. + + XXX Could be faster with a specific API for doing this. *) + +val detect_compression : string -> [`Unknown | `XZ] +(** Detect compression of a file. + + XXX Only detects the formats we need in virt-builder so far. *) + +val is_block_device : string -> bool +val is_char_device : string -> bool +val is_directory : string -> bool +(** These don't throw exceptions, unlike the [Sys] functions. *) + +val absolute_path : string -> string +(** Convert any path to an absolute path. *) diff --git a/sparsify/cmdline.ml b/sparsify/cmdline.ml index 01f66f1..11e5895 100644 --- a/sparsify/cmdline.ml +++ b/sparsify/cmdline.ml @@ -131,7 +131,7 @@ read the man page virt-sparsify(1). printf "check-tmpdir\n"; printf "in-place\n"; printf "tmp-option\n"; - let g = new G.guestfs () in + let g = new Guestfs.guestfs () in g#add_drive "/dev/null"; g#launch (); if g#feature_available [| "ntfsprogs"; "ntfs3g" |] then diff --git a/v2v/convert_linux_common.ml b/v2v/convert_linux_common.ml index 4922e2f..57a171a 100644 --- a/v2v/convert_linux_common.ml +++ b/v2v/convert_linux_common.ml @@ -96,7 +96,7 @@ and augeas_debug_errors g flush stdout with - G.Error msg -> eprintf "%s: augeas: %s (ignored)\n" prog msg + Guestfs.Error msg -> eprintf "%s: augeas: %s (ignored)\n" prog msg let install verbose g inspect packages assert false @@ -125,7 +125,7 @@ let file_owned verbose g inspect file match package_format with | "rpm" -> let cmd = [| "rpm"; "-qf"; file |] in - (try ignore (g#command cmd); true with G.Error _ -> false) + (try ignore (g#command cmd); true with Guestfs.Error _ -> false) | format -> error (f_"don't know how to find package owner using %s") format diff --git a/v2v/convert_linux_enterprise.ml b/v2v/convert_linux_enterprise.ml index 6544b27..8bf8f33 100644 --- a/v2v/convert_linux_enterprise.ml +++ b/v2v/convert_linux_enterprise.ml @@ -32,6 +32,8 @@ open Common_utils open Utils open Types +module G = Guestfs + module StringMap = Map.Make (String) let rec convert ?(keep_serial_console = true) verbose (g : G.guestfs) -- 1.9.0
Richard W.M. Jones
2014-Jun-23 11:32 UTC
[Libguestfs] [PATCH 14/14] mllib: Add a common 'warning' utility function.
This commit changes many places in OCaml utilities that print warnings to use the warning function instead. --- builder/builder.ml | 7 +++---- customize/customize_run.ml | 11 ++++------- customize/password.ml | 11 ++++------- mllib/common_utils.ml | 7 +++++++ mllib/common_utils.mli | 3 +++ resize/resize.ml | 2 +- sysprep/sysprep_operation_fs_uuids.ml | 6 +++++- v2v/convert_linux_enterprise.ml | 20 ++++++++++---------- v2v/convert_linux_grub.ml | 5 +++-- v2v/source_libvirt.ml | 7 +++---- 10 files changed, 43 insertions(+), 36 deletions(-) diff --git a/builder/builder.ml b/builder/builder.ml index 5c2f6bb..70c9430 100644 --- a/builder/builder.ml +++ b/builder/builder.ml @@ -126,7 +126,7 @@ let main () exit 1 ) else if debug then - eprintf (f_"%s: warning: gpg program is not available\n") prog + warning ~prog (f_"gpg program is not available") ); (* Check that curl works. *) @@ -150,9 +150,8 @@ let main () | Some dir -> try Some (Cache.create ~debug ~directory:dir) with exn -> - eprintf (f_"%s: warning: cache %s: %s\n") prog dir - (Printexc.to_string exn); - eprintf (f_"%s: disabling the cache\n%!") prog; + warning ~prog (f_"cache %s: %s") dir (Printexc.to_string exn); + warning ~prog (f_"disabling the cache"); None in diff --git a/customize/customize_run.ml b/customize/customize_run.ml index 4d83e90..57b888f 100644 --- a/customize/customize_run.ml +++ b/customize/customize_run.ml @@ -149,7 +149,7 @@ exec >>%s 2>&1 (* Set the random seed. *) msg (f_"Setting a random seed"); if not (Random_seed.set_random_seed g root) then - eprintf (f_"%s: warning: random seed could not be set for this type of guest\n%!") prog; + warning ~prog (f_"random seed could not be set for this type of guest"); (* Used for numbering firstboot commands. *) let i = ref 0 in @@ -216,8 +216,7 @@ exec >>%s 2>&1 | `Hostname hostname -> msg (f_"Setting the hostname: %s") hostname; if not (Hostname.set_hostname g root hostname) then - eprintf (f_"%s: warning: hostname could not be set for this type of guest\n%!") - prog + warning ~prog (f_"hostname could not be set for this type of guest") | `InstallPackages pkgs -> msg (f_"Installing packages: %s") (String.concat " " pkgs); @@ -253,8 +252,7 @@ exec >>%s 2>&1 | `Timezone tz -> msg (f_"Setting the timezone: %s") tz; if not (Timezone.set_timezone ~prog g root tz) then - eprintf (f_"%s: warning: timezone could not be set for this type of guest\n%!") - prog + warning ~prog (f_"timezone could not be set for this type of guest") | `Update -> msg (f_"Updating core packages"); @@ -294,8 +292,7 @@ exec >>%s 2>&1 set_linux_passwords ~prog ?password_crypto g root passwords | _ -> - eprintf (f_"%s: warning: passwords could not be set for this type of guest\n%!") - prog + warning ~prog (f_"passwords could not be set for this type of guest") ); if ops.flags.selinux_relabel then ( diff --git a/customize/password.ml b/customize/password.ml index 6527138..d76ebea 100644 --- a/customize/password.ml +++ b/customize/password.ml @@ -84,7 +84,7 @@ let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./" let rec set_linux_passwords ~prog ?password_crypto g root passwords let crypto match password_crypto with - | None -> default_crypto g root + | None -> default_crypto ~prog g root | Some c -> c in (* XXX Would like to use Augeas here, but Augeas doesn't support @@ -145,7 +145,7 @@ and encrypt password crypto * precede this date only support md5, whereas all guests after this * date can support sha512. *) -and default_crypto g root +and default_crypto ~prog g root let distro = g#inspect_get_distro root in let major = g#inspect_get_major_version root in match distro, major with @@ -167,9 +167,6 @@ and default_crypto g root | "ubuntu", _ -> `MD5 | _, _ -> - eprintf (f_"\ -virt-sysprep: password: warning: using insecure md5 password encryption for -guest of type %s version %d. -If this is incorrect, use --password-crypto option and file a bug.\n%!") - distro major; + warning ~prog (f_"password: using insecure md5 password encryption for +guest of type %s version %d.\nIf this is incorrect, use --password-crypto option and file a bug.") distro major; `MD5 diff --git a/mllib/common_utils.ml b/mllib/common_utils.ml index d4a97a7..1ce2abe 100644 --- a/mllib/common_utils.ml +++ b/mllib/common_utils.ml @@ -208,6 +208,13 @@ let error ~prog ?(exit_code = 1) fs in ksprintf display fs +let warning ~prog fs + let display str + wrap ~chan:stderr (sprintf (f_"%s: warning: %s") prog str); + prerr_newline (); + in + ksprintf display fs + let read_whole_file path let buf = Buffer.create 16384 in let chan = open_in path in diff --git a/mllib/common_utils.mli b/mllib/common_utils.mli index 4368e57..16b9dee 100644 --- a/mllib/common_utils.mli +++ b/mllib/common_utils.mli @@ -56,6 +56,9 @@ val make_message_function : quiet:bool -> ('a, unit, string, unit) format4 -> 'a val error : prog:string -> ?exit_code:int -> ('a, unit, string, 'b) format4 -> 'a (** Standard error function. *) +val warning : prog:string -> ('a, unit, string, unit) format4 -> 'a +(** Standard warning function. *) + val read_whole_file : string -> string (** Read in the whole file as a string. *) diff --git a/resize/resize.ml b/resize/resize.ml index c6b6c9e..dec23b1 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -1160,7 +1160,7 @@ read the man page virt-resize(1). (* Sanity check: it contains the NTFS magic. *) let magic = g#pread_device target 8 3L in if magic <> "NTFS " then - eprintf (f_"warning: first partition is NTFS but does not contain NTFS boot loader magic\n%!") + warning ~prog (f_"first partition is NTFS but does not contain NTFS boot loader magic") else ( if not quiet then printf (f_"Fixing first NTFS partition boot record ...\n%!"); diff --git a/sysprep/sysprep_operation_fs_uuids.ml b/sysprep/sysprep_operation_fs_uuids.ml index 32ee67d..57ccd68 100644 --- a/sysprep/sysprep_operation_fs_uuids.ml +++ b/sysprep/sysprep_operation_fs_uuids.ml @@ -19,10 +19,14 @@ open Printf open Sysprep_operation + open Common_gettext.Gettext +open Common_utils module G = Guestfs +let prog = "virt-sysprep" + let rec fs_uuids_perform ~debug ~quiet g root side_effects let fses = g#list_filesystems () in List.iter (function @@ -35,7 +39,7 @@ let rec fs_uuids_perform ~debug ~quiet g root side_effects g#set_uuid dev new_uuid with G.Error msg -> - eprintf (f_"warning: cannot set random UUID on filesystem %s type %s: %s\n") + warning ~prog (f_"cannot set random UUID on filesystem %s type %s: %s") dev typ msg ) fses diff --git a/v2v/convert_linux_enterprise.ml b/v2v/convert_linux_enterprise.ml index 8bf8f33..e3cfab8 100644 --- a/v2v/convert_linux_enterprise.ml +++ b/v2v/convert_linux_enterprise.ml @@ -212,8 +212,8 @@ Grub1/grub-legacy error was: %s") Convert_linux_common.augeas_reload verbose g with G.Error msg -> - eprintf (f_"%s: warning: VirtualBox Guest Additions were detected, but uninstallation failed. The error message was: %s (ignored)\n%!") - prog msg + warning ~prog (f_"VirtualBox Guest Additions were detected, but uninstallation failed. The error message was: %s (ignored)") + msg ) and unconfigure_vmware () @@ -297,8 +297,8 @@ Grub1/grub-legacy error was: %s") Convert_linux_common.augeas_reload verbose g with G.Error msg -> - eprintf (f_"%s: warning: VMware tools was detected, but uninstallation failed. The error message was: %s (ignored)\n%!") - prog msg + warning ~prog (f_"VMware tools was detected, but uninstallation failed. The error message was: %s (ignored)") + msg ) and unconfigure_citrix () @@ -389,8 +389,8 @@ Grub1/grub-legacy error was: %s") check_kernel_package (0_l, "2.6.25.5", "1.1") | _ -> - eprintf (f_"%s: warning: don't know how to install virtio drivers for %s %d\n%!") - prog distro major_version; + warning ~prog (f_"don't know how to install virtio drivers for %s %d\n%!") + distro major_version; false and check_kernel_package minversion @@ -401,8 +401,8 @@ Grub1/grub-legacy error was: %s") ) names in if not found then ( let _, minversion, minrelease = minversion in - eprintf (f_"%s: warning: cannot enable virtio in this guest.\nTo enable virtio you need to install a kernel >= %s-%s and run %s again.\n%!") - prog minversion minrelease prog + warning ~prog (f_"cannot enable virtio in this guest.\nTo enable virtio you need to install a kernel >= %s-%s and run %s again.") + minversion minrelease prog ); found @@ -421,8 +421,8 @@ Grub1/grub-legacy error was: %s") | _ -> if warn then ( let _, minversion, minrelease = minversion in - eprintf (f_"%s: warning: cannot enable virtio in this guest.\nTo enable virtio you need to upgrade %s >= %s-%s and run %s again.\n%!") - prog name minversion minrelease prog + warning ~prog (f_"cannot enable virtio in this guest.\nTo enable virtio you need to upgrade %s >= %s-%s and run %s again.") + name minversion minrelease prog ); false diff --git a/v2v/convert_linux_grub.ml b/v2v/convert_linux_grub.ml index 1f4d1ae..1b02141 100644 --- a/v2v/convert_linux_grub.ml +++ b/v2v/convert_linux_grub.ml @@ -21,6 +21,7 @@ module G = Guestfs open Printf open Common_gettext.Gettext +open Common_utils open Utils open Types @@ -272,8 +273,8 @@ object (self) ignore (g#command [| "grub2-mkconfig"; "-o"; config_file |]) with G.Error msg -> - eprintf (f_"%s: warning: could not update grub2 console: %s (ignored)\n%!") - prog msg + warning ~prog (f_"could not update grub2 console: %s (ignored)") + msg ) method configure_console () = self#update_console ~remove:false diff --git a/v2v/source_libvirt.ml b/v2v/source_libvirt.ml index 4a3c9f1..d9c7b5e 100644 --- a/v2v/source_libvirt.ml +++ b/v2v/source_libvirt.ml @@ -128,12 +128,11 @@ let create_xml ?dir xml ) | "" -> () | protocol -> - eprintf (f_"%s: warning: network <disk> with <source protocol='%s'> was ignored\n%!") - prog protocol + warning ~prog (f_"network <disk> with <source protocol='%s'> was ignored") + protocol ) | disk_type -> - eprintf (f_"%s: warning: <disk type='%s'> was ignored\n%!") - prog disk_type + warning ~prog (f_"<disk type='%s'> was ignored") disk_type done; List.rev !disks in -- 1.9.0