[Pkg-libvirt-commits] [libguestfs] 04/14: v2v: Modify conversion step to first do proper inspection and data gathering about the guest.

Hilko Bengen bengen at moszumanska.debian.org
Sat Aug 30 08:29:05 UTC 2014


This is an automated email from the git hooks/post-receive script.

bengen pushed a commit to annotated tag upstream/1.27.20
in repository libguestfs.

commit 16e817456cf7e5162ba053c92f1a4df24a4160d5
Author: Richard W.M. Jones <rjones at redhat.com>
Date:   Mon Jun 23 15:17:02 2014 +0100

    v2v: Modify conversion step to first do proper inspection and data
    gathering about the guest.
---
 po/POTFILES-ml             |   1 -
 v2v/Makefile.am            |   2 -
 v2v/convert_linux.ml       | 717 ++++++++++++++++++++++++++++++---------------
 v2v/convert_linux_grub.ml  | 331 ---------------------
 v2v/convert_linux_grub.mli |  43 ---
 v2v/lib_linux.ml           | 100 +------
 v2v/lib_linux.mli          |  10 -
 v2v/utils.ml               |   9 +
 v2v/virt-v2v.pod           |  32 ++
 9 files changed, 518 insertions(+), 727 deletions(-)

diff --git a/po/POTFILES-ml b/po/POTFILES-ml
index c46b187..4a6cd9c 100644
--- a/po/POTFILES-ml
+++ b/po/POTFILES-ml
@@ -83,7 +83,6 @@ sysprep/sysprep_operation_utmp.ml
 sysprep/sysprep_operation_yum_uuid.ml
 v2v/cmdline.ml
 v2v/convert_linux.ml
-v2v/convert_linux_grub.ml
 v2v/convert_windows.ml
 v2v/lib_linux.ml
 v2v/source_libvirt.ml
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
index 7735507..b353fb4 100644
--- a/v2v/Makefile.am
+++ b/v2v/Makefile.am
@@ -25,7 +25,6 @@ CLEANFILES = *~ *.cmi *.cmo *.cmx *.cmxa *.o virt-v2v
 
 SOURCES_MLI = \
 	convert_linux.mli \
-	convert_linux_grub.mli \
 	convert_windows.mli \
 	lib_linux.mli \
 	source_libvirt.mli \
@@ -41,7 +40,6 @@ SOURCES_ML = \
 	lib_linux.ml \
 	cmdline.ml \
 	source_libvirt.ml \
-	convert_linux_grub.ml \
 	convert_linux.ml \
 	convert_windows.ml \
 	target_local.ml \
diff --git a/v2v/convert_linux.ml b/v2v/convert_linux.ml
index 739179b..a869199 100644
--- a/v2v/convert_linux.ml
+++ b/v2v/convert_linux.ml
@@ -34,27 +34,330 @@ open Types
 
 module G = Guestfs
 
+(* Kernel information. *)
+type kernel_info = {
+  ki_app : G.application2;         (* The RPM package data. *)
+  ki_name : string;                (* eg. "kernel-PAE" *)
+  ki_arch : string;                (* Kernel architecture. *)
+  ki_vmlinuz : string;             (* The path of the vmlinuz file. *)
+  ki_vmlinuz_stat : G.stat;        (* stat(2) of vmlinuz *)
+  ki_modpath : string;             (* The module path. *)
+  ki_modules : string list;        (* The list of module names. *)
+  ki_supports_virtio : bool;       (* Kernel has virtio drivers? *)
+  ki_is_xen_kernel : bool;         (* Is a Xen paravirt kernel? *)
+}
+
+let string_of_kernel_info ki =
+  sprintf "(%s, %s, %s, virtio=%b, xen=%b)"
+    ki.ki_name ki.ki_arch ki.ki_vmlinuz
+    ki.ki_supports_virtio ki.ki_is_xen_kernel
+
+(* The conversion function. *)
 let rec convert ?(keep_serial_console = true) verbose (g : G.guestfs)
     ({ i_root = root; i_apps = apps; i_apps_map = apps_map }
         as inspect) source =
-  let typ = g#inspect_get_type root
-  and distro = g#inspect_get_distro root
-  and arch = g#inspect_get_arch root
+  (*----------------------------------------------------------------------*)
+  (* Inspect the guest first.  We already did some basic inspection in
+   * the common v2v.ml code, but that has to deal with generic guests
+   * (anything common to Linux and Windows).  Here we do more detailed
+   * inspection which can make the assumption that we are dealing with
+   * an Enterprise Linux guest using RPM.
+   *)
+
+  (* We use Augeas for inspection and conversion, so initialize it early. *)
+  Lib_linux.augeas_init verbose g;
+
+  (* Basic inspection data available as local variables. *)
+  let typ = g#inspect_get_type root in
+  assert (typ = "linux");
+
+  let distro = g#inspect_get_distro root in
+  let family =
+    match distro with
+    | "rhel" | "centos" | "scientificlinux" | "redhat-based" -> `RHEL_family
+    | "sles" | "suse-based" | "opensuse" -> `SUSE_family
+    | _ -> assert false in
+
+(*
+  let arch = g#inspect_get_arch root
   and major_version = g#inspect_get_major_version root
   and minor_version = g#inspect_get_minor_version root
-  and package_format = g#inspect_get_package_format root
+*)
+  let package_format = g#inspect_get_package_format root
   and package_management = g#inspect_get_package_management root in
 
-  assert (typ = "linux");
+  assert (package_format = "rpm");
+
+  (* What grub is installed? *)
+  let grub_config, grub =
+    try
+      List.find (
+        fun (grub_config, _) -> g#is_file ~followsymlinks:true grub_config
+      ) [
+        "/boot/grub2/grub.cfg", `Grub2;
+        "/boot/grub/menu.lst", `Grub1;
+        "/boot/grub/grub.conf", `Grub1;
+      ]
+    with
+      Not_found ->
+        error (f_"no grub1/grub-legacy or grub2 configuration file was found") in
+
+  (* Grub prefix?  Usually "/boot". *)
+  let grub_prefix =
+    match grub with
+    | `Grub2 -> ""
+    | `Grub1 ->
+      let mounts = g#inspect_get_mountpoints root in
+      try
+        List.find (
+          fun path -> List.mem_assoc path mounts
+        ) [ "/boot/grub"; "/boot" ]
+      with Not_found -> "" in
+
+  (* EFI? *)
+  let efi =
+    if Array.length (g#glob_expand "/boot/efi/EFI/*/grub.cfg") < 1 then
+      None
+    else (
+      (* Check the first partition of each device looking for an EFI
+       * boot partition. We can't be sure which device is the boot
+       * device, so we just check them all.
+       *)
+      let devs = g#list_devices () in
+      let devs = Array.to_list devs in
+      try
+        Some (
+          List.find (
+            fun dev ->
+              try
+                g#part_get_gpt_type dev 1
+                = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
+              with G.Error _ -> false
+          ) devs
+        )
+      with Not_found -> None
+    ) in
+
+  (* What kernel/kernel-like packages are installed on the current guest? *)
+  let installed_kernels : kernel_info list =
+    let rex = Str.regexp ".*\\.k?o\\(\\.xz\\)?$" in
+    let rex2 = Str.regexp ".*/\\([^/]+\\)\\.k?o\\(\\.xz\\)?$" in
+    filter_map (
+      function
+      | { G.app2_name = name } as app
+          when name = "kernel" || string_prefix name "kernel-" ->
+        (try
+           (* For each kernel, list the files directly owned by the kernel. *)
+           let files = Lib_linux.file_list_of_package verbose g inspect name in
+
+           (* Which of these is the kernel itself? *)
+           let vmlinuz = List.find (
+             fun filename -> string_prefix filename "/boot/vmlinuz-"
+           ) files in
+           (* Which of these is the modpath? *)
+           let modpath = List.find (
+             fun filename ->
+               String.length filename >= 14 &&
+                 string_prefix filename "/lib/modules/"
+           ) files in
+
+           (* Check vmlinuz & modpath exist. *)
+           if not (g#is_dir ~followsymlinks:true modpath) then
+             raise Not_found;
+           let vmlinuz_stat =
+             try g#stat vmlinuz with G.Error _ -> raise Not_found in
+
+           (* Get all modules, which might include custom-installed
+            * modules that don't appear in 'files' list above.
+            *)
+           let modules = g#find modpath in
+           let modules = Array.to_list modules in
+           let modules =
+             List.filter (fun m -> Str.string_match rex m 0) modules in
+           assert (List.length modules > 0);
+
+           (* Determine the kernel architecture by looking at the
+            * architecture of an arbitrary kernel module.
+            *)
+           let arch =
+             let any_module = modpath ^ List.hd modules in
+             g#file_architecture any_module in
+
+           (* Just return the module names, without path or extension. *)
+           let modules = filter_map (
+             fun m ->
+               if Str.string_match rex2 m 0 then
+                 Some (Str.matched_group 1 m)
+               else
+                 None
+           ) modules in
+           assert (List.length modules > 0);
+
+           let supports_virtio = List.mem "virtio_net" modules in
+           let is_xen_kernel = List.mem "xennet" modules in
+
+           Some {
+             ki_app  = app;
+             ki_name = name;
+             ki_arch = arch;
+             ki_vmlinuz = vmlinuz;
+             ki_vmlinuz_stat = vmlinuz_stat;
+             ki_modpath = modpath;
+             ki_modules = modules;
+             ki_supports_virtio = supports_virtio;
+             ki_is_xen_kernel = is_xen_kernel;
+           }
+
+         with Not_found -> None
+        )
+
+      | _ -> None
+    ) apps in
+
+  if verbose then (
+    printf "installed kernel packages in this guest:\n";
+    List.iter (
+      fun kernel -> printf "\t%s\n" (string_of_kernel_info kernel)
+    ) installed_kernels;
+    flush stdout
+  );
+
+  if installed_kernels = [] then
+    error (f_"no installed kernel packages were found.\n\nThis probably indicates that %s was unable to inspect this guest properly.")
+      prog;
+
+  (* Now the difficult bit.  Get the grub kernels.  The first in this
+   * list is the default booting kernel.
+   *)
+  let grub_kernels : kernel_info list =
+    (* Helper function for SUSE: remove (hdX,X) prefix from a path. *)
+    let remove_hd_prefix  =
+      let rex = Str.regexp "^(hd.*)\\(.*\\)" in
+      Str.replace_first rex "\\1"
+    in
+
+    let vmlinuzes =
+      match grub with
+      | `Grub1 ->
+        let paths =
+          let expr = sprintf "/files%s/title/kernel" grub_config in
+          let paths = g#aug_match expr in
+          let paths = Array.to_list paths in
+
+          (* Remove duplicates. *)
+          let paths = remove_duplicates paths in
+
+          (* Get the default kernel from grub if it's set. *)
+          let default =
+            let expr = sprintf "/files%s/default" grub_config in
+            try
+              let idx = g#aug_get expr in
+              let idx = int_of_string idx in
+              (* Grub indices are zero-based, augeas is 1-based. *)
+              let expr =
+                sprintf "/files%s/title[%d]/kernel" grub_config (idx+1) in
+              Some expr
+            with Not_found -> None in
+
+          (* If a default kernel was set, put it at the beginning of the paths
+           * list.  If not set, assume the first kernel always boots (?)
+           *)
+          match default with
+          | None -> paths
+          | Some p -> p :: List.filter ((<>) p) paths in
+
+        (* Resolve the Augeas paths to kernel filenames. *)
+        let vmlinuzes = List.map g#aug_get paths in
+
+        (* Make sure kernel does not begin with (hdX,X). *)
+        let vmlinuzes = List.map remove_hd_prefix vmlinuzes in
+
+        (* Prepend grub filesystem. *)
+        List.map ((^) grub_prefix) vmlinuzes
+
+      | `Grub2 ->
+        let get_default_image () =
+          let cmd =
+            if g#exists "/sbin/grubby" then
+              [| "grubby"; "--default-kernel" |]
+            else
+              [| "/usr/bin/perl"; "-MBootloader::Tools"; "-e"; "
+                    InitLibrary();
+                    my $default = Bootloader::Tools::GetDefaultSection();
+                    print $default->{image};
+                 " |] in
+          match g#command cmd with
+          | "" -> None
+          | k ->
+            let len = String.length k in
+            let k =
+              if len > 0 && k.[len-1] = '\n' then
+                String.sub k 0 (len-1)
+              else k in
+            Some (remove_hd_prefix k)
+        in
+
+        let vmlinuzes =
+          (match get_default_image () with
+          | None -> []
+          | Some k -> [k]) @
+            (* This is how the grub2 config generator enumerates kernels. *)
+            Array.to_list (g#glob_expand "/boot/kernel-*") @
+            Array.to_list (g#glob_expand "/boot/vmlinuz-*") @
+            Array.to_list (g#glob_expand "/vmlinuz-*") in
+        let rex = Str.regexp ".*\\.\\(dpkg-.*|rpmsave|rpmnew\\)$" in
+        let vmlinuzes = List.filter (
+          fun file -> not (Str.string_match rex file 0)
+        ) vmlinuzes in
+        vmlinuzes in
+
+    (* Map these to installed kernels. *)
+    filter_map (
+      fun vmlinuz ->
+        try
+          let statbuf = g#stat vmlinuz in
+          let kernel =
+            List.find (
+              fun { ki_vmlinuz_stat = s } ->
+                statbuf.G.dev = s.G.dev && statbuf.G.ino = s.G.ino
+            ) installed_kernels in
+          Some kernel
+        with Not_found -> None
+    ) vmlinuzes in
+
+  if verbose then (
+    printf "grub kernels in this guest (first in list is default):\n";
+    List.iter (
+      fun kernel -> printf "\t%s\n" (string_of_kernel_info kernel)
+    ) grub_kernels;
+    flush stdout
+  );
+
+  if grub_kernels = [] then
+    error (f_"no kernels were found in the grub configuration.\n\nThis probably indicates that %s was unable to parse the grub configuration of this guest.")
+      prog;
 
-  let is_rhel_family =
-    (distro = "rhel" || distro = "centos"
-            || distro = "scientificlinux" || distro = "redhat-based")
+  (*----------------------------------------------------------------------*)
+  (* Conversion step. *)
 
-  and is_suse_family =
-    (distro = "sles" || distro = "suse-based" || distro = "opensuse") in
+  let rec augeas_grub_configuration () =
+    match grub with
+    | `Grub1 ->
+      (* Ensure Augeas is reading the grub configuration file, and if not
+       * then add it.
+       *)
+      let incls = g#aug_match "/augeas/load/Grub/incl" in
+      let incls = Array.to_list incls in
+      let incls_contains_conf =
+        List.exists (fun incl -> g#aug_get incl = grub_config) incls in
+      if not incls_contains_conf then (
+        g#aug_set "/augeas/load/Grub/incl[last()+1]" grub_config;
+        Lib_linux.augeas_reload verbose g;
+      )
+
+    | `Grub2 -> () (* Not necessary for grub2. *)
 
-  let rec clean_rpmdb () =
+  and clean_rpmdb () =
     (* Clean RPM database. *)
     assert (package_format = "rpm");
     let dbfiles = g#glob_expand "/var/lib/rpm/__db.00?" in
@@ -68,19 +371,6 @@ let rec convert ?(keep_serial_console = true) verbose (g : G.guestfs)
     if g#is_file ~followsymlinks:true "/usr/sbin/load_policy" then
       g#touch "/.autorelabel";
 
-  and get_grub () =
-    (* Detect if grub2 or grub1 is installed by trying to create
-     * an object of each sort.
-     *)
-    try Convert_linux_grub.grub2 verbose g inspect
-    with Failure grub2_error ->
-      try Convert_linux_grub.grub1 verbose g inspect
-      with Failure grub1_error ->
-        error (f_"no grub configuration found in this guest.
-Grub2 error was: %s
-Grub1/grub-legacy error was: %s")
-          grub2_error grub1_error
-
   and unconfigure_xen () =
     (* Remove kmod-xenpv-* (RHEL 3). *)
     let xenmods =
@@ -133,7 +423,7 @@ Grub1/grub-legacy error was: %s")
       );
     );
 
-    if is_suse_family then (
+    if family = `SUSE_family then (
       (* Remove xen modules from INITRD_MODULES and DOMU_INITRD_MODULES. *)
       let variables = ["INITRD_MODULES"; "DOMU_INITRD_MODULES"] in
       let xen_modules = ["xennet"; "xen-vnif"; "xenblk"; "xen-vbd"] in
@@ -339,226 +629,88 @@ Grub1/grub-legacy error was: %s")
       if !updated then g#aug_save ();
     )
 
-  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 = 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 =
-        check_package ~ifinstalled:true
-          "selinux-policy-targeted" (0_l, "2.4.6", "203.el5") in
-      kernel && lvm2 && selinux
-    | ("rhel"|"centos"|"scientificlinux"|"redhat-based"), 4, _ ->
-      check_kernel_package (0_l, "2.6.9", "89.EL")
-
-    (* All supported Fedora versions support virtio. *)
-    | "fedora", _, _ -> true
-
-    (* SLES 11 supports virtio in the kernel. *)
-    | ("sles"|"suse-based"), v, _ when v >= 11 -> true
-    | ("sles"|"suse-based"), 10, _ ->
-      check_kernel_package (0_l, "2.6.16.60", "0.85.1")
-
-    (* OpenSUSE. *)
-    | "opensuse", v, _ when v >= 11 -> true
-    | "opensuse", 10, _ ->
-      check_kernel_package (0_l, "2.6.25.5", "1.1")
-
-    | _ ->
-      warning ~prog (f_"don't know how to install virtio drivers for %s %d\n%!")
-        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
-      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
-
-  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
-        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
+  and unconfigure_efi () =
+    match efi with
+    | None -> ()
+    | Some dev ->
+      match grub with
+      | `Grub1 ->
+        g#cp "/etc/grub.conf" "/boot/grub/grub.conf";
+        g#ln_sf "/boot/grub/grub.conf" "/etc/grub.conf";
 
-  and configure_kernel virtio grub =
-    let kernels = grub#list_kernels () in
+        (* Reload Augeas to pick up new location of grub.conf. *)
+        Lib_linux.augeas_reload verbose g;
 
-    let bootable_kernel =
-      let rec loop =
-        function
-        | [] -> None
-        | path :: paths ->
-          let kernel =
-            Lib_linux.inspect_linux_kernel verbose g inspect path in
-          match kernel with
-          | None -> loop paths
-          | Some kernel when is_hv_kernel kernel -> loop paths
-          | Some kernel when virtio && not (supports_virtio kernel) ->
-            loop paths
-          | Some kernel -> Some kernel
-      in
-      loop kernels in
+        ignore (g#command [| "grub-install"; dev |])
 
-    (* If virtio == true, then a virtio kernel should have been
-     * installed.  If we didn't find one, it indicates a bug in
-     * virt-v2v.
-     *)
-    if virtio && bootable_kernel = None then
-      error (f_"virtio configured, but no virtio kernel found");
-
-    (* No bootable kernel was found.  Install one. *)
-    let bootable_kernel =
-      match bootable_kernel with
-      | Some k -> k
-      | None ->
-        (* Find which kernel is currently used by the guest. *)
-        let current_kernel =
-          let rec loop = function
-            | [] -> "kernel"
-            | path :: paths ->
-              let kernel =
-                Lib_linux.inspect_linux_kernel verbose g inspect
-                  path in
-              match kernel with
-              | None -> loop paths
-              | Some kernel -> kernel.Lib_linux.base_package
-          in
-          loop kernels in
-
-        (* Replace kernel-xen with a suitable kernel. *)
-        let current_kernel =
-          if string_find current_kernel "kernel-xen" >= 0 then
-            xen_replacement_kernel ()
-          else
-            current_kernel in
+      | `Grub2 ->
+        (* EFI systems boot using grub2-efi, and probably don't have the
+         * base grub2 package installed.
+         *)
+        Lib_linux.install verbose g inspect ["grub2"];
+
+        (* Relabel the EFI boot partition as a BIOS boot partition. *)
+        g#part_set_gpt_type dev 1 "21686148-6449-6E6F-744E-656564454649";
+
+        (* Delete the fstab entry for the EFI boot partition. *)
+        let nodes = g#aug_match "/files/etc/fstab/*[file = '/boot/efi']" in
+        let nodes = Array.to_list nodes in
+        List.iter (fun node -> ignore (g#aug_rm node)) nodes;
+        g#aug_save ();
 
-        (* Install the kernel.  However we need a way to detect the
-         * version of the kernel that has just been installed.  A quick
-         * way is to compare /lib/modules before and after.
+        (* Install grub2 in the BIOS boot partition. This overwrites the
+         * previous contents of the EFI boot partition.
          *)
-        let files1 = g#ls "/lib/modules" in
-        let files1 = Array.to_list files1 in
-        Lib_linux.install verbose g inspect [current_kernel];
-        let files2 = g#ls "/lib/modules" in
-        let files2 = Array.to_list files2 in
-
-        (* Note that g#ls is guaranteed to return the strings in order. *)
-        let rec loop files1 files2 =
-          match files1, files2 with
-          | [], [] ->
-            error (f_"tried to install '%s', but no kernel package was installed") current_kernel
-          | (v1 :: _), [] ->
-            error (f_"tried to install '%s', but there are now fewer directories under /lib/modules!") current_kernel
-          | [], (v2 :: _) -> v2
-          | (v1 :: _), (v2 :: _) when v1 <> v2 -> v2
-          | (_ :: v1s), (_ :: v2s) -> loop v1s v2s
-        in
-        let version = loop files1 files2 in
+        ignore (g#command [| "grub2-install"; dev |]);
 
-        { Lib_linux.base_package = current_kernel;
-          version = version; modules = []; arch = "" } in
+        (* Re-generate the grub2 config, and put it in the correct place *)
+        ignore (g#command [| "grub2-mkconfig"; "-o"; "/boot/grub2/grub.cfg" |])
 
-    (* Set /etc/sysconfig/kernel DEFAULTKERNEL to point to the new
-     * kernel package name.
+  and configure_kernel () =
+    (* Previously this function would try to install kernels, but we
+     * don't do that any longer.
      *)
-    if g#is_file ~followsymlinks:true "/etc/sysconfig/kernel" then (
-      let base_package = bootable_kernel.Lib_linux.base_package in
-      let paths =
-        g#aug_match "/files/etc/sysconfig/kernel/DEFAULTKERNEL/value" in
-      let paths = Array.to_list paths in
-      List.iter (fun path -> g#aug_set path base_package) paths;
-      g#aug_save ()
-    );
 
-    (* Return the installed kernel version. *)
-    bootable_kernel.Lib_linux.version
-
-  and supports_virtio { Lib_linux.modules = modules } =
-    List.mem "virtio_blk" modules && List.mem "virtio_net" modules
-
-  (* Is it a hypervisor-specific kernel? *)
-  and is_hv_kernel { Lib_linux.modules = modules } =
-    List.mem "xennet" modules           (* Xen PV kernel. *)
-
-  (* Find a suitable replacement for kernel-xen. *)
-  and xen_replacement_kernel () =
-    if is_rhel_family then (
-      match major_version, arch with
-      | 5, ("i386"|"i486"|"i586"|"i686") -> "kernel-PAE"
-      | 5, _ -> "kernel"
-      | 4, ("i386"|"i486"|"i586"|"i686") ->
-        (* If guest has >= 10GB of RAM, give it a hugemem kernel. *)
-        if source.s_memory >= 10L *^ 1024L *^ 1024L *^ 1024L then
-          "kernel-hugemem"
-        (* SMP kernel for guests with > 1 vCPU. *)
-        else if source.s_vcpu > 1 then
-          "kernel-smp"
-        else
-          "kernel"
-      | 4, _ ->
-        if source.s_vcpu > 8 then "kernel-largesmp"
-        else if source.s_vcpu > 1 then "kernel-smp"
-        else "kernel"
-      | _, _ -> "kernel"
-    )
-    else if is_suse_family then (
-      match distro, major_version, arch with
-      | "opensuse", _, _ -> "kernel-default"
-      | _, v, ("i386"|"i486"|"i586"|"i686") when v >= 11 ->
-        if source.s_memory >= 10L *^ 1024L *^ 1024L *^ 1024L then
-          "kernel-pae"
-        else
-          "kernel"
-      | _, v, _ when v >= 11 -> "kernel-default"
-      | _, 10, ("i386"|"i486"|"i586"|"i686") ->
-        if source.s_memory >= 10L *^ 1024L *^ 1024L *^ 1024L then
-          "kernel-bigsmp"
-        else if source.s_vcpu > 1 then
-          "kernel-smp"
-        else
-          "kernel-default"
-      | _, 10, _ ->
-        if source.s_vcpu > 1 then
-          "kernel-smp"
-        else
-          "kernel-default"
-      | _ -> "kernel-default"
-    )
-    else
-      "kernel" (* conservative default *)
+    (* Check a non-Xen kernel exists. *)
+    let only_xen_kernels = List.for_all (
+      fun { ki_is_xen_kernel = is_xen_kernel } -> is_xen_kernel
+    ) grub_kernels in
+    if only_xen_kernels then
+      error (f_"only Xen kernels are installed in this guest.\n\nRead the %s(1) manual, section \"XEN PARAVIRTUALIZED GUESTS\", to see what to do.") prog;
+
+    (* Enable the best non-Xen kernel, where "best" means the one with
+     * the highest version which supports virtio.
+     *)
+    let best_kernel =
+      let compare_best_kernels k1 k2 =
+        let i = compare k1.ki_supports_virtio k2.ki_supports_virtio in
+        if i <> 0 then i
+        else compare_app2_versions k1.ki_app k2.ki_app
+      in
+      let kernels = grub_kernels in
+      let kernels = List.filter (fun { ki_is_xen_kernel = is_xen_kernel } -> not is_xen_kernel) kernels in
+      let kernels = List.sort compare_best_kernels kernels in
+      let kernels = List.rev kernels (* so best is first *) in
+      List.hd kernels in
+    if best_kernel <> List.hd grub_kernels then
+      grub_set_bootable best_kernel;
+
+    (* Does the best/bootable kernel support virtio? *)
+    best_kernel.ki_supports_virtio
+
+  and grub_set_bootable kernel =
+    let cmd =
+      if g#exists "/sbin/grubby" then
+        [| "grubby"; "--set-kernel"; kernel.ki_vmlinuz |]
+      else
+        [| "/usr/bin/perl"; "-MBootloader::Tools"; "-e"; sprintf "
+              InitLibrary();
+              my @sections = GetSectionList(type=>image, image=>\"%s\");
+              my $section = GetSection(@sections);
+              my $newdefault = $section->{name};
+              SetGlobals(default, \"$newdefault\");
+            " kernel.ki_vmlinuz |] in
+    ignore (g#command cmd)
 
   (* We configure a console on ttyS0. Make sure existing console
    * references use it.  N.B. Note that the RHEL 6 xen guest kernel
@@ -596,6 +748,28 @@ Grub1/grub-legacy error was: %s")
 
     g#aug_save ()
 
+  and grub_configure_console () =
+    match grub with
+    | `Grub1 ->
+      let rex = Str.regexp "\\(.*\\)\\b\\([xh]vc0\\)\\b\\(.*\\)" in
+      let expr = sprintf "/files%s/title/kernel/console" grub_config in
+
+      let paths = g#aug_match expr in
+      let paths = Array.to_list paths in
+      List.iter (
+        fun path ->
+          let console = g#aug_get path in
+          if Str.string_match rex console 0 then (
+            let console = Str.global_replace rex "\\1ttyS0\\3" console in
+            g#aug_set path console
+          )
+      ) paths;
+
+      g#aug_save ()
+
+    | `Grub2 ->
+      grub2_update_console ~remove:false
+
   (* If the target doesn't support a serial console, we want to remove
    * all references to it instead.
    *)
@@ -624,26 +798,84 @@ Grub1/grub-legacy error was: %s")
 
     g#aug_save ()
 
+  and grub_remove_console () =
+    match grub with
+    | `Grub1 ->
+      let rex = Str.regexp "\\(.*\\)\\b\\([xh]vc0\\)\\b\\(.*\\)" in
+      let expr = sprintf "/files%s/title/kernel/console" grub_config in
+
+      let rec loop = function
+        | [] -> ()
+        | path :: paths ->
+          let console = g#aug_get path in
+          if Str.string_match rex console 0 then (
+            ignore (g#aug_rm path);
+            (* All the paths are invalid, restart the loop. *)
+            let paths = g#aug_match expr in
+            let paths = Array.to_list paths in
+            loop paths
+          )
+          else
+            loop paths
+      in
+      let paths = g#aug_match expr in
+      let paths = Array.to_list paths in
+      loop paths;
+
+      g#aug_save ()
+
+    | `Grub2 ->
+      grub2_update_console ~remove:true
+
+  and grub2_update_console ~remove =
+    let rex = Str.regexp "\\(.*\\)\\bconsole=[xh]vc0\\b\\(.*\\)" in
+
+    let grub_cmdline_expr =
+      if g#exists "/etc/sysconfig/grub" then
+        "/files/etc/sysconfig/grub/GRUB_CMDLINE_LINUX"
+      else
+        "/files/etc/default/grub/GRUB_CMDLINE_LINUX_DEFAULT" in
+
+    (try
+       let grub_cmdline = g#aug_get grub_cmdline_expr in
+       let grub_cmdline =
+         if Str.string_match rex grub_cmdline 0 then (
+           if remove then
+             Str.global_replace rex "\\1\\3" grub_cmdline
+           else
+             Str.global_replace rex "\\1console=ttyS0\\3" grub_cmdline
+         )
+         else grub_cmdline in
+       g#aug_set grub_cmdline_expr grub_cmdline;
+       g#aug_save ();
+
+       ignore (g#command [| "grub2-mkconfig"; "-o"; grub_config |])
+     with
+       G.Error msg ->
+         warning ~prog (f_"could not update grub2 console: %s (ignored)")
+           msg
+    )
+
   in
 
+  augeas_grub_configuration ();
   clean_rpmdb ();
   autorelabel ();
-  Lib_linux.augeas_init verbose g;
-  let grub = get_grub () in
 
   unconfigure_xen ();
   unconfigure_vbox ();
   unconfigure_vmware ();
   unconfigure_citrix ();
+  unconfigure_efi ();
+
+  let virtio = configure_kernel () 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 ();
-    grub#configure_console ()
+    grub_configure_console ();
   ) else (
     remove_console ();
-    grub#remove_console ()
+    grub_remove_console ();
   );
 
 
@@ -653,7 +885,6 @@ Grub1/grub-legacy error was: %s")
 
 
 
-
   let guestcaps = {
     gcaps_block_bus = if virtio then "virtio" else "ide";
     gcaps_net_bus = if virtio then "virtio" else "e1000";
diff --git a/v2v/convert_linux_grub.ml b/v2v/convert_linux_grub.ml
deleted file mode 100644
index cb8c5c8..0000000
--- a/v2v/convert_linux_grub.ml
+++ /dev/null
@@ -1,331 +0,0 @@
-(* virt-v2v
- * Copyright (C) 2009-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.
- *)
-
-module G = Guestfs
-
-open Printf
-
-open Common_gettext.Gettext
-open Common_utils
-
-open Utils
-open Types
-
-(* Helper function for SUSE: remove (hdX,X) prefix from a path. *)
-let remove_hd_prefix =
-  let rex = Str.regexp "^(hd.*)\\(.*\\)" in
-  Str.replace_first rex "\\1"
-
-(* Helper function to check if guest is EFI. *)
-let check_efi g =
-  if Array.length (g#glob_expand "/boot/efi/EFI/*/grub.cfg") < 1 then
-    raise Not_found;
-
-  (* Check the first partition of each device looking for an EFI
-   * boot partition. We can't be sure which device is the boot
-   * device, so we just check them all.
-   *)
-  let devs = g#list_devices () in
-  let devs = Array.to_list devs in
-  List.find (
-    fun dev ->
-      try g#part_get_gpt_type dev 1 = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
-      with G.Error _ -> false
-  ) devs
-
-(* Virtual grub superclass. *)
-class virtual grub verbose (g : Guestfs.guestfs) inspect config_file =
-object
-  method virtual list_kernels : unit -> string list
-
-  method virtual configure_console : unit -> unit
-  method virtual remove_console : unit -> unit
-
-  method private get_default_image () =
-    let cmd =
-      if g#exists "/sbin/grubby" then
-        [| "grubby"; "--default-kernel" |]
-      else
-        [| "/usr/bin/perl"; "-MBootloader::Tools"; "-e"; "
-             InitLibrary();
-             my $default = Bootloader::Tools::GetDefaultSection();
-             print $default->{image};
-         " |] in
-    match g#command cmd with
-    | "" -> None
-    | k ->
-      let len = String.length k in
-      let k =
-        if len > 0 && k.[len-1] = '\n' then String.sub k 0 (len-1) else k in
-      Some (remove_hd_prefix k)
-end
-
-(* Concrete implementation for grub1. *)
-class grub1 verbose g inspect config_file grub_fs =
-object (self)
-  inherit grub verbose g inspect config_file
-
-  method private grub_fs = grub_fs      (* grub filesystem prefix *)
-
-  method list_kernels () =
-    let paths =
-      let expr = sprintf "/files%s/title/kernel" config_file in
-      let paths = g#aug_match expr in
-      let paths = Array.to_list paths in
-
-      (* Get the default kernel from grub if it's set. *)
-      let default =
-        let expr = sprintf "/files%s/default" config_file in
-        try
-          let idx = g#aug_get expr in
-          let idx = int_of_string idx in
-          (* Grub indices are zero-based, augeas is 1-based. *)
-          let expr = sprintf "/files%s/title[%d]/kernel" config_file (idx+1) in
-          Some expr
-        with Not_found -> None in
-
-      (* If a default kernel was set, put it at the beginning of the paths
-       * list.
-       *)
-      match default with
-      | None -> paths
-      | Some p -> p :: List.filter ((<>) p) paths in
-
-    (* Remove duplicates. *)
-    let paths =
-      let checked = Hashtbl.create 13 in
-      let rec loop = function
-        | [] -> []
-        | p :: ps when Hashtbl.mem checked p -> ps
-        | p :: ps -> Hashtbl.add checked p true; p :: loop ps
-      in
-      loop paths in
-
-    (* Resolve the Augeas paths to kernel filenames. *)
-    let kernels = List.map g#aug_get paths in
-
-    (* Make sure kernel does not begin with (hdX,X). *)
-    let kernels = List.map remove_hd_prefix kernels in
-
-    (* Prepend grub filesystem. *)
-    let kernels = List.map ((^) grub_fs) kernels in
-
-    (* Check the actual file exists. *)
-    let kernels = List.filter (g#is_file ~followsymlinks:true) kernels in
-
-    kernels
-
-  method configure_console () =
-    let rex = Str.regexp "\\(.*\\)\\b\\([xh]vc0\\)\\b\\(.*\\)" in
-    let expr = sprintf "/files%s/title/kernel/console" config_file in
-
-    let paths = g#aug_match expr in
-    let paths = Array.to_list paths in
-    List.iter (
-      fun path ->
-        let console = g#aug_get path in
-        if Str.string_match rex console 0 then (
-          let console = Str.global_replace rex "\\1ttyS0\\3" console in
-          g#aug_set path console
-        )
-    ) paths;
-
-    g#aug_save ()
-
-  method remove_console () =
-    let rex = Str.regexp "\\(.*\\)\\b\\([xh]vc0\\)\\b\\(.*\\)" in
-    let expr = sprintf "/files%s/title/kernel/console" config_file in
-
-    let rec loop = function
-      | [] -> ()
-      | path :: paths ->
-        let console = g#aug_get path in
-        if Str.string_match rex console 0 then (
-          ignore (g#aug_rm path);
-          (* All the paths are invalid, restart the loop. *)
-          let paths = g#aug_match expr in
-          let paths = Array.to_list paths in
-          loop paths
-        )
-        else
-          loop paths
-    in
-    let paths = g#aug_match expr in
-    let paths = Array.to_list paths in
-    loop paths;
-
-    g#aug_save ()
-
-end
-
-(* Create a grub1 object. *)
-let rec grub1 verbose (g : Guestfs.guestfs) inspect =
-  let root = inspect.i_root in
-
-  (* Look for a grub configuration file. *)
-  let config_file =
-    try
-      List.find (
-        fun file -> g#is_file ~followsymlinks:true file
-      ) ["/boot/grub/menu.lst"; "/boot/grub/grub.conf"]
-    with
-      Not_found ->
-        failwith (s_"no grub/grub1/grub-legacy configuration file was found") in
-
-  (* Check for EFI and convert if found. *)
-  (try let dev = check_efi g in grub1_convert_from_efi verbose g dev
-   with Not_found -> ()
-  );
-
-  (* Find the path that has to be prepended to filenames in grub.conf
-   * in order to make them absolute.
-   *)
-  let grub_fs =
-    let mounts = g#inspect_get_mountpoints root in
-    try
-      List.find (
-        fun path -> List.mem_assoc path mounts
-      ) [ "/boot/grub"; "/boot" ]
-    with Not_found -> "" in
-
-  (* Ensure Augeas is reading the grub configuration file, and if not
-   * then add it.
-   *)
-  let () =
-    let incls = g#aug_match "/augeas/load/Grub/incl" in
-    let incls = Array.to_list incls in
-    let incls_contains_conf =
-      List.exists (fun incl -> g#aug_get incl = config_file) incls in
-    if not incls_contains_conf then (
-      g#aug_set "/augeas/load/Grub/incl[last()+1]" config_file;
-      Lib_linux.augeas_reload verbose g;
-    ) in
-
-  new grub1 verbose g inspect config_file grub_fs
-
-(* Reinstall grub. *)
-and grub1_convert_from_efi verbose g dev =
-  g#cp "/etc/grub.conf" "/boot/grub/grub.conf";
-  g#ln_sf "/boot/grub/grub.conf" "/etc/grub.conf";
-
-  (* Reload Augeas to pick up new location of grub.conf. *)
-  Lib_linux.augeas_reload verbose g;
-
-  ignore (g#command [| "grub-install"; dev |])
-
-(* Concrete implementation for grub2. *)
-class grub2 verbose g inspect config_file =
-object (self)
-  inherit grub verbose g inspect config_file
-
-  method list_kernels () =
-    let files =
-      (match self#get_default_image () with
-      | None -> []
-      | Some k -> [k]) @
-        (* This is how the grub2 config generator enumerates kernels. *)
-        Array.to_list (g#glob_expand "/boot/kernel-*") @
-        Array.to_list (g#glob_expand "/boot/vmlinuz-*") @
-        Array.to_list (g#glob_expand "/vmlinuz-*") in
-    let rex = Str.regexp ".*\\.\\(dpkg-.*|rpmsave|rpmnew\\)$" in
-    let files = List.filter (
-      fun file -> not (Str.string_match rex file 0)
-    ) files in
-    files
-
-  method private update_console ~remove =
-    let rex = Str.regexp "\\(.*\\)\\bconsole=[xh]vc0\\b\\(.*\\)" in
-
-    let grub_cmdline_expr =
-      if g#exists "/etc/sysconfig/grub" then
-        "/files/etc/sysconfig/grub/GRUB_CMDLINE_LINUX"
-      else
-        "/files/etc/default/grub/GRUB_CMDLINE_LINUX_DEFAULT" in
-
-    (try
-       let grub_cmdline = g#aug_get grub_cmdline_expr in
-       let grub_cmdline =
-         if Str.string_match rex grub_cmdline 0 then (
-           if remove then
-             Str.global_replace rex "\\1\\3" grub_cmdline
-           else
-             Str.global_replace rex "\\1console=ttyS0\\3" grub_cmdline
-         )
-         else grub_cmdline in
-       g#aug_set grub_cmdline_expr grub_cmdline;
-       g#aug_save ();
-
-       ignore (g#command [| "grub2-mkconfig"; "-o"; config_file |])
-     with
-       G.Error msg ->
-         warning ~prog (f_"could not update grub2 console: %s (ignored)")
-           msg
-    )
-
-  method configure_console () = self#update_console ~remove:false
-  method remove_console () = self#update_console ~remove:true
-end
-
-let rec grub2 verbose (g : Guestfs.guestfs) inspect =
-  (* Look for a grub2 configuration file. *)
-  let config_file = "/boot/grub2/grub.cfg" in
-  if not (g#is_file ~followsymlinks:true config_file) then (
-    let msg =
-      sprintf (f_"no grub2 configuration file was found (expecting %s)")
-        config_file in
-    failwith msg
-  );
-
-  (* Check for EFI and convert if found. *)
-  (try
-     let dev = check_efi g in
-     grub2_convert_from_efi verbose g inspect dev
-   with Not_found -> ()
-  );
-
-  new grub2 verbose g inspect config_file
-
-(* For grub2:
- * - Turn the EFI partition into a BIOS Boot Partition
- * - Remove the former EFI partition from fstab
- * - Install the non-EFI version of grub
- * - Install grub2 in the BIOS Boot Partition
- * - Regenerate grub.cfg
- *)
-and grub2_convert_from_efi verbose g inspect dev =
-  (* EFI systems boot using grub2-efi, and probably don't have the
-   * base grub2 package installed.
-   *)
-  Lib_linux.install verbose g inspect ["grub2"];
-
-  (* Relabel the EFI boot partition as a BIOS boot partition. *)
-  g#part_set_gpt_type dev 1 "21686148-6449-6E6F-744E-656564454649";
-
-  (* Delete the fstab entry for the EFI boot partition. *)
-  let nodes = g#aug_match "/files/etc/fstab/*[file = '/boot/efi']" in
-  let nodes = Array.to_list nodes in
-  List.iter (fun node -> ignore (g#aug_rm node)) nodes;
-  g#aug_save ();
-
-  (* Install grub2 in the BIOS boot partition. This overwrites the
-   * previous contents of the EFI boot partition.
-   *)
-  ignore (g#command [| "grub2-install"; dev |]);
-
-  (* Re-generate the grub2 config, and put it in the correct place *)
-  ignore (g#command [| "grub2-mkconfig"; "-o"; "/boot/grub2/grub.cfg" |])
diff --git a/v2v/convert_linux_grub.mli b/v2v/convert_linux_grub.mli
deleted file mode 100644
index 324a333..0000000
--- a/v2v/convert_linux_grub.mli
+++ /dev/null
@@ -1,43 +0,0 @@
-(* virt-v2v
- * Copyright (C) 2009-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.
- *)
-
-(** Common code handling grub1 (grub-legacy) and grub2 operations. *)
-
-class type virtual grub = object
-  method virtual list_kernels : unit -> string list
-  (** Return a list of kernels from the grub configuration.  The
-      returned list is a list of filenames. *)
-  method virtual configure_console : unit -> unit
-  (** Reconfigure the grub console. *)
-  method virtual remove_console : unit -> unit
-  (** Remove the grub console configuration. *)
-end
-
-val grub1 : bool -> Guestfs.guestfs -> Types.inspect -> grub
-(** Detect if grub1/grub-legacy is used by this guest and return a
-    grub object if so.
-
-    This raises [Failure] if grub1 is not used by this guest or some
-    other problem happens. *)
-
-val grub2 : bool -> Guestfs.guestfs -> Types.inspect -> grub
-(** Detect if grub2 is used by this guest and return a grub object
-    if so.
-
-    This raises [Failure] if grub2 is not used by this guest or some
-    other problem happens. *)
diff --git a/v2v/lib_linux.ml b/v2v/lib_linux.ml
index 580c5ec..8362d2a 100644
--- a/v2v/lib_linux.ml
+++ b/v2v/lib_linux.ml
@@ -123,7 +123,9 @@ let file_list_of_package verbose (g : Guestfs.guestfs) inspect name =
   | "rpm" ->
     let cmd = [| "rpm"; "-ql"; name |] in
     if verbose then eprintf "%s\n%!" (String.concat " " (Array.to_list cmd));
-    Array.to_list (g#command_lines cmd)
+    let files = g#command_lines cmd in
+    let files = Array.to_list files in
+    List.sort compare files
   | format ->
     error (f_"don't know how to get list of files from package using %s")
       format
@@ -151,99 +153,3 @@ let rec file_owner verbose g inspect path =
 and is_file_owned verbose g inspect path =
   try file_owner verbose g inspect path; true
   with Not_found -> false
-
-type kernel_info = {
-  base_package : string;          (* base package, eg. "kernel-PAE" *)
-  version : string;               (* kernel version *)
-  modules : string list;          (* list of kernel modules *)
-  arch : string;                  (* kernel arch *)
-}
-
-(* There was some crazy SUSE stuff going on in the Perl version
- * of virt-v2v, which I have dropped from this as I couldn't
- * understand what on earth it was doing.  - RWMJ
- *)
-let inspect_linux_kernel verbose (g : Guestfs.guestfs) inspect path =
-  let base_package = file_owner verbose g inspect path in
-
-  (* Try to get kernel version by examination of the binary.
-   * See supermin.git/src/kernel.ml
-   *)
-  let version =
-    try
-      let hdrS = g#pread path 4 514L in
-      if hdrS <> "HdrS" then raise Not_found;
-      let s = g#pread path 2 518L in
-      let s = (Char.code s.[1] lsl 8) lor Char.code s.[0] in
-      if s < 0x1ff then raise Not_found;
-      let offset = g#pread path 2 526L in
-      let offset = (Char.code offset.[1] lsl 8) lor Char.code offset.[0] in
-      if offset < 0 then raise Not_found;
-      let buf = g#pread path (offset + 0x200) 132L in
-      let rec loop i =
-        if i < 132 then (
-          if buf.[i] = '\000' || buf.[i] = ' ' ||
-            buf.[i] = '\t' || buf.[i] = '\n' then
-            String.sub buf 0 i
-          else
-            loop (i+1)
-        )
-        else raise Not_found
-      in
-      let v = loop 0 in
-      (* There must be a corresponding modules directory. *)
-      let modpath = sprintf "/lib/modules/%s" v in
-      if not (g#is_dir modpath) then
-        raise Not_found;
-      Some (v, modpath)
-    with Not_found -> None in
-
-  (* Apparently Xen PV kernels don't contain a version number,
-   * so try to guess the version from the filename.
-   *)
-  let version =
-    match version with
-    | Some v -> Some v
-    | None ->
-      let rex = Str.regexp "^/boot/vmlinuz-\\(.*\\)" in
-      if Str.string_match rex path 0 then (
-        let v = Str.matched_group 1 path in
-        let modpath = sprintf "/lib/modules/%s" v in
-        if g#is_dir modpath then Some (v, modpath) else None
-      )
-      else None in
-
-  (* If we sill didn't find a version, give up here. *)
-  match version with
-  | None -> None
-  | Some (version, modpath) ->
-
-    (* List modules. *)
-    let modules = g#find modpath in
-    let modules = Array.to_list modules in
-    let rex = Str.regexp ".*\\.k?o$" in
-    let modules = List.filter (fun m -> Str.string_match rex m 0) modules in
-
-    assert (List.length modules > 0);
-
-    (* Determine the kernel architecture by looking at the architecture
-     * of an arbitrary kernel module.
-     *)
-    let arch =
-      let any_module = modpath ^ List.hd modules in
-      g#file_architecture any_module in
-
-    (* Just return the module names, without path or extension. *)
-    let rex = Str.regexp ".*/\\([^/]+\\)\\.k?o$/" in
-    let modules = filter_map (
-      fun m ->
-        if Str.string_match rex m 0 then
-          Some (Str.matched_group 1 m)
-        else
-          None
-    ) modules in
-
-    Some { base_package = base_package;
-           version = version;
-           modules = modules;
-           arch = arch }
diff --git a/v2v/lib_linux.mli b/v2v/lib_linux.mli
index 94983c6..e5a3025 100644
--- a/v2v/lib_linux.mli
+++ b/v2v/lib_linux.mli
@@ -39,13 +39,3 @@ val file_owner : bool -> Guestfs.guestfs -> Types.inspect -> string -> string
 
 val is_file_owned : bool -> Guestfs.guestfs -> Types.inspect -> string -> bool
 (** Returns true if the file is owned by an installed package. *)
-
-type kernel_info = {
-  base_package : string;          (* base package, eg. "kernel-PAE" *)
-  version : string;               (* kernel version *)
-  modules : string list;          (* list of kernel modules *)
-  arch : string;                  (* kernel arch *)
-}
-
-val inspect_linux_kernel : bool -> Guestfs.guestfs -> Types.inspect -> string -> kernel_info option
-(** Inspect a Linux kernel (by path) and return various information. *)
diff --git a/v2v/utils.ml b/v2v/utils.ml
index 9870f1b..b58c18d 100644
--- a/v2v/utils.ml
+++ b/v2v/utils.ml
@@ -62,3 +62,12 @@ and compare_app2_version_min app1 (min_epoch, min_version, min_release) =
     else
       compare_version app1.Guestfs.app2_release min_release
   )
+
+let remove_duplicates xs =
+  let h = Hashtbl.create (List.length xs) in
+  let rec loop = function
+    | [] -> []
+    | x :: xs when Hashtbl.mem h x -> xs
+    | x :: xs -> Hashtbl.add h x true; x :: loop xs
+  in
+  loop xs
diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
index b7f4726..c88df5d 100644
--- a/v2v/virt-v2v.pod
+++ b/v2v/virt-v2v.pod
@@ -208,6 +208,38 @@ Enable tracing of libguestfs API calls.
 
 =back
 
+=head1 XEN PARAVIRTUALIZED GUESTS
+
+Older versions of virt-v2v could turn a Xen paravirtualized (PV) guest
+into a KVM guest by installing a new kernel.  This version of virt-v2v
+does I<not> attempt to install any new kernels.  Instead it will give
+you an error if there are I<only> Xen PV kernels available.
+
+Therefore before conversion you should check that a regular kernel is
+installed.  For some older Linux distributions, this means installing
+a kernel from the table below:
+
+ RHEL 3         (Does not apply, as there was no Xen PV kernel)
+ 
+ RHEL 4         i686 with > 10GB of RAM: install 'kernel-hugemem'
+                i686 SMP: install 'kernel-smp'
+                other i686: install 'kernel'
+                x86-64 SMP with > 8 CPUs: install 'kernel-largesmp'
+                x86-64 SMP: install 'kernel-smp'
+                other x86-64: install 'kernel'
+ 
+ RHEL 5         i686: install 'kernel-PAE'
+                x86-64: install 'kernel'
+ 
+ SLES 10        i586 with > 10GB of RAM: install 'kernel-bigsmp'
+                i586 SMP: install 'kernel-smp'
+                other i586: install 'kernel-default'
+                x86-64 SMP: install 'kernel-smp'
+                other x86-64: install 'kernel-default'
+ 
+ SLES 11+       i586: install 'kernel-pae'
+                x86-64: install 'kernel-default'
+
 =head1 ENABLING VIRTIO
 
 "Virtio" is the name for a set of drivers which make disk (block

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-libvirt/libguestfs.git



More information about the Pkg-libvirt-commits mailing list