[Libguestfs] [PATCH] v2v: Allow libvirt >= 2.1.0 to be used for Xen and vCenter conversions.

Richard W.M. Jones rjones at redhat.com
Wed Aug 24 14:01:23 UTC 2016


Libvirt >= 2.1.0 now allows you to open files which have a "json:"
QEMU pseudo-URL as backingfile, whereas previously it would fail hard
in this case (RHBZ#1134878).

When virt-v2v performs conversions from Xen (over SSH) or vCenter
(over HTTPS) it uses these pseudo-URLs as backingfiles.  We had to
tell people to use LIBGUESTFS_BACKEND=direct to avoid libvirt in this
situation.

This commit narrows the check so it will now only print the error if
libvirt < 2.1.0 and LIBGUESTFS_BACKEND=direct is not set.  Also the
error is modified to tell users they can either upgrade libvirt or set
LIBGUESTFS_BACKEND=direct to work around the problem.

Note there is not an easy way apart from checking the version number
of libvirt to tell if the json pseudo-URL is supported.

As a side-effect, this commit also prints the libvirt version number
in debugging output when virt-v2v starts up, which is sometimes useful
information for narrowing down bugs (it is in fact already printed by
libguestfs, so this is duplicate information, but it's a bit easier to
find when it's at the top of the debug).

Thanks: Peter Krempa.
---
 v2v/domainxml-c.c                  | 38 ++++++++++++++++++++++++++++++++++++++
 v2v/domainxml.ml                   |  3 +++
 v2v/domainxml.mli                  |  4 ++++
 v2v/input_libvirt_other.ml         | 16 ++++++++++++----
 v2v/input_libvirt_other.mli        |  2 +-
 v2v/input_libvirt_vcenter_https.ml |  2 +-
 v2v/input_libvirt_xen_ssh.ml       |  2 +-
 v2v/v2v.ml                         | 12 ++++++++++++
 8 files changed, 72 insertions(+), 7 deletions(-)

diff --git a/v2v/domainxml-c.c b/v2v/domainxml-c.c
index 3b00cad..eb6deab 100644
--- a/v2v/domainxml-c.c
+++ b/v2v/domainxml-c.c
@@ -487,6 +487,43 @@ v2v_domain_exists (value connv, value domnamev)
   CAMLreturn (Val_bool (domain_exists));
 }
 
+/* XXX This function is stuffed here for convenience (accessing
+ * libvirt), not because it belongs logically with the rest of the
+ * functions in this file.
+ */
+value
+v2v_libvirt_get_version (value unitv)
+{
+  CAMLparam1 (unitv);
+  CAMLlocal1 (rv);
+  int major, minor, release;
+  /* We have to assemble the error on the stack because a dynamic
+   * string couldn't be freed.
+   */
+  char errmsg[ERROR_MESSAGE_LEN];
+  unsigned long ver;
+  virErrorPtr err;
+
+  if (virGetVersion (&ver, NULL, NULL) == -1) {
+    err = virGetLastError ();
+    snprintf (errmsg, sizeof errmsg,
+              _("cannot get libvirt library version: %s"),
+              err->message);
+    caml_invalid_argument (errmsg);
+  }
+
+  major = ver / 1000000UL;
+  minor = ver / 1000UL % 1000UL;
+  release = ver % 1000UL;
+
+  rv = caml_alloc (3, 0);
+  Store_field (rv, 0, Val_int (major));
+  Store_field (rv, 1, Val_int (minor));
+  Store_field (rv, 2, Val_int (release));
+
+  CAMLreturn (rv);
+}
+
 #else /* !HAVE_LIBVIRT */
 
 #define NO_LIBVIRT(proto)                                               \
@@ -501,5 +538,6 @@ NO_LIBVIRT (value v2v_pool_dumpxml (value connv, value poolv))
 NO_LIBVIRT (value v2v_vol_dumpxml (value connv, value poolnamev, value volnamev))
 NO_LIBVIRT (value v2v_capabilities (value connv, value unitv))
 NO_LIBVIRT (value v2v_domain_exists (value connv, value domnamev))
+NO_LIBVIRT (value v2v_libvirt_get_version (value unitv))
 
 #endif /* !HAVE_LIBVIRT */
diff --git a/v2v/domainxml.ml b/v2v/domainxml.ml
index af053a5..b9d547d 100644
--- a/v2v/domainxml.ml
+++ b/v2v/domainxml.ml
@@ -26,3 +26,6 @@ external vol_dumpxml : ?conn:string -> string -> string -> string = "v2v_vol_dum
 external capabilities : ?conn:string -> unit -> string = "v2v_capabilities"
 
 external domain_exists : ?conn:string -> string -> bool = "v2v_domain_exists"
+
+external libvirt_get_version : unit -> int * int * int
+  = "v2v_libvirt_get_version"
diff --git a/v2v/domainxml.mli b/v2v/domainxml.mli
index 17289bb..6d933e4 100644
--- a/v2v/domainxml.mli
+++ b/v2v/domainxml.mli
@@ -49,3 +49,7 @@ val domain_exists : ?conn:string -> string -> bool
     the libvirt XML domain [dom] exists.
     The optional [?conn] parameter is the libvirt connection URI.
     [dom] may be a guest name, but not a UUID. *)
+
+val libvirt_get_version : unit -> int * int * int
+(** [libvirt_get_version] returns the triple [(major, minor, release)]
+    version number of the libvirt library that we are linked against. *)
diff --git a/v2v/input_libvirt_other.ml b/v2v/input_libvirt_other.ml
index 6fd8d52..b2f3dc0 100644
--- a/v2v/input_libvirt_other.ml
+++ b/v2v/input_libvirt_other.ml
@@ -24,13 +24,21 @@ open Common_utils
 open Types
 open Utils
 
-(* Check the backend is not libvirt.  Works around a libvirt bug
- * (RHBZ#1134592).  This can be removed once the libvirt bug is fixed.
+(* Libvirt < 2.1.0 did not support the "json:" pseudo-URLs that
+ * we use as backingfiles, when accessing Xen over SSH or vCenter
+ * over HTTPS.  Check this and print a workaround.
+ *
+ * We can remove this when/if we ever require libvirt >= 2.1.0 as
+ * a minimum version.
+ *
+ * See also RHBZ#1134878.
  *)
-let error_if_libvirt_backend () =
+let error_if_libvirt_does_not_support_json_backingfile () =
   let libguestfs_backend = (open_guestfs ())#get_backend () in
   if libguestfs_backend = "libvirt" then (
-    error (f_"because of libvirt bug https://bugzilla.redhat.com/show_bug.cgi?id=1134592 you must set this environment variable:\n\nexport LIBGUESTFS_BACKEND=direct\n\nand then rerun the virt-v2v command.")
+    let major, minor, _ = Domainxml.libvirt_get_version () in
+    if major < 2 || (major = 2 && minor < 1) then
+      error (f_"because of libvirt bug https://bugzilla.redhat.com/1134878 you must EITHER upgrade to libvirt >= 2.1.0, OR set this environment variable:\n\nexport LIBGUESTFS_BACKEND=direct\n\nand then rerun the virt-v2v command.")
   )
 
 (* xen+ssh URLs use the SSH driver in CURL.  Currently this requires
diff --git a/v2v/input_libvirt_other.mli b/v2v/input_libvirt_other.mli
index 22cc21c..5b97f2f 100644
--- a/v2v/input_libvirt_other.mli
+++ b/v2v/input_libvirt_other.mli
@@ -18,7 +18,7 @@
 
 (** [-i libvirt] source. *)
 
-val error_if_libvirt_backend : unit -> unit
+val error_if_libvirt_does_not_support_json_backingfile : unit -> unit
 val error_if_no_ssh_agent : unit -> unit
 
 class virtual input_libvirt : string option -> string option -> string -> object
diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml
index 137f3d3..bcedf3f 100644
--- a/v2v/input_libvirt_vcenter_https.ml
+++ b/v2v/input_libvirt_vcenter_https.ml
@@ -45,7 +45,7 @@ object
     debug "input_libvirt_vcenter_https: source: scheme %s server %s"
           scheme server;
 
-    error_if_libvirt_backend ();
+    error_if_libvirt_does_not_support_json_backingfile ();
 
     (* Get the libvirt XML.  This also checks (as a side-effect)
      * that the domain is not running.  (RHBZ#1138586)
diff --git a/v2v/input_libvirt_xen_ssh.ml b/v2v/input_libvirt_xen_ssh.ml
index 310b38b..f9adc58 100644
--- a/v2v/input_libvirt_xen_ssh.ml
+++ b/v2v/input_libvirt_xen_ssh.ml
@@ -38,7 +38,7 @@ object
     debug "input_libvirt_xen_ssh: source: scheme %s server %s"
           scheme server;
 
-    error_if_libvirt_backend ();
+    error_if_libvirt_does_not_support_json_backingfile ();
     error_if_no_ssh_agent ();
 
     (* Get the libvirt XML.  This also checks (as a side-effect)
diff --git a/v2v/v2v.ml b/v2v/v2v.ml
index ccd369c..39054f7 100644
--- a/v2v/v2v.ml
+++ b/v2v/v2v.ml
@@ -44,6 +44,18 @@ let rec main () =
         prog Guestfs_config.package_name
         Guestfs_config.package_version Guestfs_config.host_cpu;
 
+  (* Print the libvirt version if debugging.  Note that if
+   * we're configured --without-libvirt, then this will throw
+   * an exception, but some conversions should still be possible,
+   * hence the try block.
+   *)
+  if verbose () then (
+    try
+      let major, minor, release = Domainxml.libvirt_get_version () in
+      debug "libvirt version: %d.%d.%d" major minor release
+    with _ -> ()
+  );
+
   let source = open_source cmdline input in
   let source = amend_source cmdline source in
 
-- 
2.7.4




More information about the Libguestfs mailing list