[Libguestfs] [PATCH] RFC: v2v: add and use libvirt connection objects

Pino Toscano ptoscano at redhat.com
Fri Sep 8 15:44:17 UTC 2017


Enhance the Libvirt_utils module with libvirt connection objects,
and read-only and read-writen open functions for them; adapt the rest of
the mini-binding to use these objects, instead of opening + closing
libvirt connections every time.  This has different improvements:
a) a libvirt connection is reused for different API calls, improving
   the communication with remote (input) servers
b) because of (a), there is way less need to pass libvirt_uri and
   password variables all around

The hierarchy of input_libvirt* classes is changed to take a Lazy object
with the libvirt connection, accessing it through a "proctected" method:
this way, the connection is opened only at the first access.
---
 v2v/copy_to_local.ml                |   3 +-
 v2v/input_libvirt.ml                |  13 +-
 v2v/input_libvirt_other.ml          |  24 ++--
 v2v/input_libvirt_other.mli         |   5 +-
 v2v/input_libvirt_vcenter_https.ml  |  10 +-
 v2v/input_libvirt_vcenter_https.mli |   2 +-
 v2v/input_libvirt_vddk.ml           |  18 +--
 v2v/input_libvirt_vddk.mli          |   4 +-
 v2v/input_libvirt_xen_ssh.ml        |  10 +-
 v2v/input_libvirt_xen_ssh.mli       |   2 +-
 v2v/input_libvirtxml.ml             |   3 +-
 v2v/libvirt_utils-c.c               | 259 +++++++++++++++++++-----------------
 v2v/libvirt_utils.ml                |  16 ++-
 v2v/libvirt_utils.mli               |  44 +++---
 v2v/output_libvirt.ml               |   8 +-
 v2v/parse_libvirt_xml.ml            |   4 +-
 v2v/parse_libvirt_xml.mli           |   2 +-
 17 files changed, 233 insertions(+), 194 deletions(-)

diff --git a/v2v/copy_to_local.ml b/v2v/copy_to_local.ml
index 0a2b7ed75..828b5b490 100644
--- a/v2v/copy_to_local.ml
+++ b/v2v/copy_to_local.ml
@@ -131,7 +131,8 @@ read the man page virt-v2v-copy-to-local(1).
 
   (* Get the remote libvirt XML. *)
   message (f_"Fetching the remote libvirt XML metadata ...");
-  let xml = Libvirt_utils.dumpxml ?password ~conn:input_conn guest_name in
+  let conn = Libvirt_utils.connect_rw ?password ~conn:input_conn () in
+  let xml = Libvirt_utils.dumpxml conn guest_name in
 
   debug "libvirt XML from remote server:\n%s" xml;
 
diff --git a/v2v/input_libvirt.ml b/v2v/input_libvirt.ml
index e8143b6ad..6baac7d5f 100644
--- a/v2v/input_libvirt.ml
+++ b/v2v/input_libvirt.ml
@@ -28,9 +28,10 @@ open Utils
 
 (* Choose the right subclass based on the URI. *)
 let input_libvirt dcpath vddk_options password libvirt_uri guest =
+  let conn = lazy (Libvirt_utils.connect_rw ?password ?conn:libvirt_uri ()) in
   match libvirt_uri with
   | None ->
-    Input_libvirt_other.input_libvirt_other password libvirt_uri guest
+    Input_libvirt_other.input_libvirt_other conn guest
 
   | Some orig_uri ->
     let { Xml.uri_server = server; uri_scheme = scheme } as parsed_uri =
@@ -45,7 +46,7 @@ let input_libvirt dcpath vddk_options password libvirt_uri guest =
 
     | Some _, None                      (* No scheme? *)
     | Some _, Some "" ->
-      Input_libvirt_other.input_libvirt_other password libvirt_uri guest
+      Input_libvirt_other.input_libvirt_other conn guest
 
     (* vCenter over https, or
      * vCenter or ESXi using nbdkit vddk plugin
@@ -54,16 +55,16 @@ let input_libvirt dcpath vddk_options password libvirt_uri guest =
        (match vddk_options with
         | None ->
            Input_libvirt_vcenter_https.input_libvirt_vcenter_https
-             dcpath password libvirt_uri parsed_uri scheme server guest
+             dcpath conn password parsed_uri scheme server guest
         | Some vddk_options ->
            Input_libvirt_vddk.input_libvirt_vddk vddk_options password
-                                                 libvirt_uri parsed_uri guest
+                                                 conn parsed_uri guest
        )
 
     (* Xen over SSH *)
     | Some server, Some ("xen+ssh" as scheme) ->
       Input_libvirt_xen_ssh.input_libvirt_xen_ssh
-        password libvirt_uri parsed_uri scheme server guest
+        conn parsed_uri scheme server guest
 
     (* Old virt-v2v also supported qemu+ssh://.  However I am
      * deliberately not supporting this in new virt-v2v.  Don't
@@ -74,6 +75,6 @@ let input_libvirt dcpath vddk_options password libvirt_uri guest =
     | Some _, Some _ ->
       warning (f_"no support for remote libvirt connections to '-ic %s'.  The conversion may fail when it tries to read the source disks.")
         orig_uri;
-      Input_libvirt_other.input_libvirt_other password libvirt_uri guest
+      Input_libvirt_other.input_libvirt_other conn guest
 
 let () = Modules_list.register_input_module "libvirt"
diff --git a/v2v/input_libvirt_other.ml b/v2v/input_libvirt_other.ml
index 05923e952..cd466a2c5 100644
--- a/v2v/input_libvirt_other.ml
+++ b/v2v/input_libvirt_other.ml
@@ -49,24 +49,24 @@ let error_if_no_ssh_agent () =
     error (f_"ssh-agent authentication has not been set up ($SSH_AUTH_SOCK is not set).  Please read \"INPUT FROM RHEL 5 XEN\" in the virt-v2v(1) man page.")
 
 (* Superclass. *)
-class virtual input_libvirt (password : string option) libvirt_uri guest =
-object
+class virtual input_libvirt lazy_conn guest =
+  let conn_obj = lazy_conn in
+object (self)
   inherit input
 
   method as_options =
-    sprintf "-i libvirt%s %s"
-      (match libvirt_uri with
-      | None -> ""
-      | Some uri -> " -ic " ^ uri)
-      guest
+    sprintf "-i libvirt -ic %s %s" (Libvirt_utils.get_uri self#conn) guest
+
+  method private conn =
+    Lazy.force conn_obj
 end
 
 (* Subclass specialized for handling anything that's *not* VMware vCenter
  * or Xen.
  *)
-class input_libvirt_other password libvirt_uri guest =
-object
-  inherit input_libvirt password libvirt_uri guest
+class input_libvirt_other lazy_conn guest =
+object (self)
+  inherit input_libvirt lazy_conn guest
 
   method source () =
     debug "input_libvirt_other: source()";
@@ -74,9 +74,9 @@ object
     (* Get the libvirt XML.  This also checks (as a side-effect)
      * that the domain is not running.  (RHBZ#1138586)
      *)
-    let xml = Libvirt_utils.dumpxml ?password ?conn:libvirt_uri guest in
+    let xml = Libvirt_utils.dumpxml self#conn guest in
 
-    let source, disks = parse_libvirt_xml ?conn:libvirt_uri xml in
+    let source, disks = parse_libvirt_xml self#conn xml in
     let disks = List.map (fun { p_source_disk = disk } -> disk) disks in
     { source with s_disks = disks }
 end
diff --git a/v2v/input_libvirt_other.mli b/v2v/input_libvirt_other.mli
index 603fd3dd2..9645aa5af 100644
--- a/v2v/input_libvirt_other.mli
+++ b/v2v/input_libvirt_other.mli
@@ -21,10 +21,11 @@
 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
+class virtual input_libvirt : Libvirt_utils.conn Lazy.t -> string -> object
   method as_options : string
   method virtual source : unit -> Types.source
   method adjust_overlay_parameters : Types.overlay -> unit
+  method private conn : Libvirt_utils.conn
 end
 
-val input_libvirt_other : string option -> string option -> string -> Types.input
+val input_libvirt_other : Libvirt_utils.conn Lazy.t -> string -> Types.input
diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml
index 8b6856c7e..54370b954 100644
--- a/v2v/input_libvirt_vcenter_https.ml
+++ b/v2v/input_libvirt_vcenter_https.ml
@@ -36,9 +36,9 @@ let readahead_for_copying = Some (64 * 1024 * 1024)
 
 (* Subclass specialized for handling VMware vCenter over https. *)
 class input_libvirt_vcenter_https
-  cmdline_dcPath password libvirt_uri parsed_uri scheme server guest =
-object
-  inherit input_libvirt password libvirt_uri guest
+  cmdline_dcPath lazy_conn password parsed_uri scheme server guest =
+object (self)
+  inherit input_libvirt lazy_conn guest
 
   val saved_source_paths = Hashtbl.create 13
   val mutable dcPath = ""
@@ -64,8 +64,8 @@ object
     (* Get the libvirt XML.  This also checks (as a side-effect)
      * that the domain is not running.  (RHBZ#1138586)
      *)
-    let xml = Libvirt_utils.dumpxml ?password ?conn:libvirt_uri guest in
-    let source, disks = parse_libvirt_xml ?conn:libvirt_uri xml in
+    let xml = Libvirt_utils.dumpxml self#conn guest in
+    let source, disks = parse_libvirt_xml self#conn xml in
 
     (* Find the <vmware:datacenterpath> element from the XML, if it
      * exists.  This was added in libvirt >= 1.2.20.
diff --git a/v2v/input_libvirt_vcenter_https.mli b/v2v/input_libvirt_vcenter_https.mli
index 840b5a90f..6f848f2f0 100644
--- a/v2v/input_libvirt_vcenter_https.mli
+++ b/v2v/input_libvirt_vcenter_https.mli
@@ -18,4 +18,4 @@
 
 (** [-i libvirt] when the source is VMware vCenter *)
 
-val input_libvirt_vcenter_https : string option -> string option -> string option -> Xml.uri -> string -> string -> string -> Types.input
+val input_libvirt_vcenter_https : string option -> Libvirt_utils.conn Lazy.t -> string option -> Xml.uri -> string -> string -> string -> Types.input
diff --git a/v2v/input_libvirt_vddk.ml b/v2v/input_libvirt_vddk.ml
index b6a57d374..a09c0b55b 100644
--- a/v2v/input_libvirt_vddk.ml
+++ b/v2v/input_libvirt_vddk.ml
@@ -34,7 +34,7 @@ open Xpath_helpers
 open Printf
 
 (* Subclass specialized for handling VMware via nbdkit vddk plugin. *)
-class input_libvirt_vddk vddk_options password libvirt_uri parsed_uri guest =
+class input_libvirt_vddk vddk_options password lazy_conn parsed_uri guest =
 
   (* The VDDK path. *)
   let libdir = vddk_options.vddk_libdir in
@@ -102,8 +102,8 @@ See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") library_path
       error (f_"You must pass the ‘--vddk-thumbprint’ option with the SSL thumbprint of the VMware server.  To find the thumbprint, see the nbdkit-vddk-plugin(1) manual.  See also \"INPUT FROM VDDK\" in the virt-v2v(1) manual.")
   in
 
-object
-  inherit input_libvirt password libvirt_uri guest
+object (self)
+  inherit input_libvirt lazy_conn guest
 
   method source () =
     error_unless_vddk_libdir ();
@@ -114,8 +114,8 @@ object
     (* Get the libvirt XML.  This also checks (as a side-effect)
      * that the domain is not running.  (RHBZ#1138586)
      *)
-    let xml = Libvirt_utils.dumpxml ?password ?conn:libvirt_uri guest in
-    let source, disks = parse_libvirt_xml ?conn:libvirt_uri xml in
+    let xml = Libvirt_utils.dumpxml self#conn guest in
+    let source, disks = parse_libvirt_xml self#conn xml in
 
     (* Find the <vmware:moref> element from the XML.  This was added
      * in libvirt >= 3.7 and is required.
@@ -163,12 +163,8 @@ object
         match parsed_uri.Xml.uri_server with
         | Some server -> server
         | None ->
-           match libvirt_uri with
-           | Some libvirt_uri ->
-              error (f_"‘-ic %s’ URL does not contain a host name field")
-                    libvirt_uri
-           | None ->
-              error (f_"you must use the ‘-ic’ parameter.  See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") in
+           (* XXX *)
+            error (f_"you must use the ‘-ic’ parameter.  See \"INPUT FROM VDDK\" in the virt-v2v(1) manual.") in
 
       (* Similar to above, we also need a username to pass. *)
       let user =
diff --git a/v2v/input_libvirt_vddk.mli b/v2v/input_libvirt_vddk.mli
index 19a34c202..3017488b5 100644
--- a/v2v/input_libvirt_vddk.mli
+++ b/v2v/input_libvirt_vddk.mli
@@ -18,7 +18,7 @@
 
 (** [-i libvirt] when the source is VMware via nbdkit vddk plugin *)
 
-val input_libvirt_vddk : Types.vddk_options -> string option -> string option -> Xml.uri -> string -> Types.input
-(** [input_libvirt_vddk vddk_options password libvirt_uri parsed_uri guest]
+val input_libvirt_vddk : Types.vddk_options -> string option -> Libvirt_utils.conn Lazy.t -> Xml.uri -> string -> Types.input
+(** [input_libvirt_vddk vddk_options password conn parsed_uri guest]
     creates and returns a {!Types.input} object specialized for reading
     the guest disks using the nbdkit vddk plugin. *)
diff --git a/v2v/input_libvirt_xen_ssh.ml b/v2v/input_libvirt_xen_ssh.ml
index fd3da2c44..9d3005855 100644
--- a/v2v/input_libvirt_xen_ssh.ml
+++ b/v2v/input_libvirt_xen_ssh.ml
@@ -30,9 +30,9 @@ open Input_libvirt_other
 open Printf
 
 (* Subclass specialized for handling Xen over SSH. *)
-class input_libvirt_xen_ssh password libvirt_uri parsed_uri scheme server guest =
-object
-  inherit input_libvirt password libvirt_uri guest
+class input_libvirt_xen_ssh lazy_conn parsed_uri scheme server guest =
+object (self)
+  inherit input_libvirt lazy_conn guest
 
   method source () =
     debug "input_libvirt_xen_ssh: source: scheme %s server %s"
@@ -47,8 +47,8 @@ object
     (* Get the libvirt XML.  This also checks (as a side-effect)
      * that the domain is not running.  (RHBZ#1138586)
      *)
-    let xml = Libvirt_utils.dumpxml ?password ?conn:libvirt_uri guest in
-    let source, disks = parse_libvirt_xml ?conn:libvirt_uri xml in
+    let xml = Libvirt_utils.dumpxml self#conn guest in
+    let source, disks = parse_libvirt_xml self#conn xml in
 
     (* Map the <source/> filename (which is relative to the remote
      * Xen server) to an ssh URI.  This is a JSON URI looking something
diff --git a/v2v/input_libvirt_xen_ssh.mli b/v2v/input_libvirt_xen_ssh.mli
index 85213241a..bde0ff65a 100644
--- a/v2v/input_libvirt_xen_ssh.mli
+++ b/v2v/input_libvirt_xen_ssh.mli
@@ -18,4 +18,4 @@
 
 (** [-i libvirt] when the source is Xen *)
 
-val input_libvirt_xen_ssh : string option -> string option -> Xml.uri -> string -> string -> string -> Types.input
+val input_libvirt_xen_ssh : Libvirt_utils.conn Lazy.t -> Xml.uri -> string -> string -> string -> Types.input
diff --git a/v2v/input_libvirtxml.ml b/v2v/input_libvirtxml.ml
index 570541d7d..5d13faee6 100644
--- a/v2v/input_libvirtxml.ml
+++ b/v2v/input_libvirtxml.ml
@@ -34,7 +34,8 @@ object
   method source () =
     let xml = read_whole_file file in
 
-    let source, disks = parse_libvirt_xml xml in
+    let conn = Libvirt_utils.connect_ro () in
+    let source, disks = parse_libvirt_xml conn xml in
 
     (* When reading libvirt XML from a file (-i libvirtxml) we allow
      * paths to disk images in the libvirt XML to be relative (to the XML
diff --git a/v2v/libvirt_utils-c.c b/v2v/libvirt_utils-c.c
index 93ee5208e..fec14356b 100644
--- a/v2v/libvirt_utils-c.c
+++ b/v2v/libvirt_utils-c.c
@@ -31,6 +31,7 @@
 #include <libintl.h>
 
 #include <caml/alloc.h>
+#include <caml/custom.h>
 #include <caml/fail.h>
 #include <caml/memory.h>
 #include <caml/mlvalues.h>
@@ -49,6 +50,39 @@
 
 #define ERROR_MESSAGE_LEN 512
 
+/* Wrap and unwrap virConnectPtr, with a finalizer. */
+#define Libvirtconn_val(rv) (*(virConnectPtr *)Data_custom_val(rv))
+
+static void
+libvirtconn_finalize (value rev)
+{
+  virConnectPtr conn = Libvirtconn_val (rev);
+  if (conn)
+    virConnectClose (conn);
+}
+
+static struct custom_operations custom_operations = {
+  (char *) "libvirtconn_custom_operations",
+  libvirtconn_finalize,
+  custom_compare_default,
+  custom_hash_default,
+  custom_serialize_default,
+  custom_deserialize_default
+};
+
+static value
+Val_libvirtconn (virConnectPtr conn)
+{
+  CAMLparam0 ();
+  CAMLlocal1 (rv);
+
+  rv = caml_alloc_custom (&custom_operations, sizeof (virConnectPtr), 0, 1);
+  Libvirtconn_val (rv) = conn;
+
+  CAMLreturn (rv);
+}
+
+
 static void
 ignore_errors (void *ignore, virErrorPtr ignore2)
 {
@@ -111,11 +145,10 @@ libvirt_auth_default_wrapper (virConnectCredentialPtr cred,
   }
 }
 
-virStoragePoolPtr
+static virStoragePoolPtr
 connect_and_load_pool (value connv, value poolnamev)
 {
   CAMLparam2 (connv, poolnamev);
-  const char *conn_uri = NULL;
   const char *poolname;
   /* We have to assemble the error on the stack because a dynamic
    * string couldn't be freed.
@@ -125,31 +158,8 @@ connect_and_load_pool (value connv, value poolnamev)
   virConnectPtr conn;
   virStoragePoolPtr pool;
 
-  if (connv != Val_int (0))
-    conn_uri = String_val (Field (connv, 0)); /* Some conn */
-
-  /* We have to call the default authentication handler, not least
-   * since it handles all the PolicyKit crap.  However it also makes
-   * coding this simpler.
-   */
-  conn = virConnectOpenAuth (conn_uri, virConnectAuthPtrDefault,
-                             VIR_CONNECT_RO);
-  if (conn == NULL) {
-    if (conn_uri)
-      snprintf (errmsg, sizeof errmsg,
-                _("cannot open libvirt connection ‘%s’"), conn_uri);
-    else
-      snprintf (errmsg, sizeof errmsg, _("cannot open libvirt connection"));
-    caml_invalid_argument (errmsg);
-  }
-
-  /* Suppress default behaviour of printing errors to stderr.  Note
-   * you can't set this to NULL to ignore errors; setting it to NULL
-   * restores the default error handler ...
-   */
-  virConnSetErrorFunc (conn, NULL, ignore_errors);
-
   /* Look up the pool. */
+  conn = Libvirtconn_val (connv);
   poolname = String_val (poolnamev);
 
   pool = virStoragePoolLookupByUUIDString (conn, poolname);
@@ -162,48 +172,72 @@ connect_and_load_pool (value connv, value poolnamev)
     snprintf (errmsg, sizeof errmsg,
               _("cannot find libvirt pool ‘%s’: %s\n\nUse ‘virsh pool-list --all’ to list all available pools, and ‘virsh pool-dumpxml <pool>’ to display details about a particular pool.\n\nTo set the pool which virt-v2v uses, add the ‘-os <pool>’ option."),
               poolname, err->message);
-    virConnectClose (conn);
     caml_invalid_argument (errmsg);
   }
 
   CAMLreturnT (virStoragePoolPtr, pool);
 }
 
+
 value
-v2v_dumpxml (value passwordv, value connv, value domnamev)
+v2v_libvirt_connect_ro (value connv, value unitv)
 {
-  CAMLparam3 (passwordv, connv, domnamev);
-  CAMLlocal1 (retv);
+  CAMLparam2 (connv, unitv);
+  const char *conn_uri = NULL;
+  char errmsg[ERROR_MESSAGE_LEN];
+  virConnectPtr conn;
+
+  if (connv != Val_int (0))
+    conn_uri = String_val (Field (connv, 0)); /* Some conn */
+
+  /* We have to call the default authentication handler, not least
+   * since it handles all the PolicyKit crap.  However it also makes
+   * coding this simpler.
+   */
+  conn = virConnectOpenAuth (conn_uri, virConnectAuthPtrDefault,
+                             VIR_CONNECT_RO);
+  if (conn == NULL) {
+    if (conn_uri)
+      snprintf (errmsg, sizeof errmsg,
+                _("cannot open libvirt connection ‘%s’"), conn_uri);
+    else
+      snprintf (errmsg, sizeof errmsg, _("cannot open libvirt connection"));
+    caml_invalid_argument (errmsg);
+  }
+
+  /* Suppress default behaviour of printing errors to stderr.  Note
+   * you can't set this to NULL to ignore errors; setting it to NULL
+   * restores the default error handler ...
+   */
+  virConnSetErrorFunc (conn, NULL, ignore_errors);
+
+  CAMLreturn (Val_libvirtconn (conn));
+}
+
+value
+v2v_libvirt_connect_rw (value passwordv, value connv, value unitv)
+{
+  CAMLparam3 (passwordv, connv, unitv);
   const char *password = NULL;
   const char *conn_uri = NULL;
-  const char *domname;
   virConnectAuth authdata;
   /* We have to assemble the error on the stack because a dynamic
    * string couldn't be freed.
    */
   char errmsg[ERROR_MESSAGE_LEN];
-  virErrorPtr err;
   virConnectPtr conn;
-  virDomainPtr dom;
-  int is_test_uri = 0;
-  char *xml;
 
   if (passwordv != Val_int (0))
     password = String_val (Field (passwordv, 0)); /* Some password */
 
-  if (connv != Val_int (0)) {
+  if (connv != Val_int (0))
     conn_uri = String_val (Field (connv, 0)); /* Some conn */
-    is_test_uri = STRPREFIX (conn_uri, "test:");
-  }
 
   /* Set up authentication wrapper. */
   authdata = *virConnectAuthPtrDefault;
   authdata.cb = libvirt_auth_default_wrapper;
   authdata.cbdata = (void *) password;
 
-  /* Note this cannot be a read-only connection since we need to use
-   * the VIR_DOMAIN_XML_SECURE flag below.
-   */
   conn = virConnectOpenAuth (conn_uri, &authdata, 0);
   if (conn == NULL) {
     if (conn_uri)
@@ -220,6 +254,26 @@ v2v_dumpxml (value passwordv, value connv, value domnamev)
    */
   virConnSetErrorFunc (conn, NULL, ignore_errors);
 
+  CAMLreturn (Val_libvirtconn (conn));
+}
+
+value
+v2v_libvirt_dumpxml (value connv, value domnamev)
+{
+  CAMLparam2 (connv, domnamev);
+  CAMLlocal1 (retv);
+  const char *domname;
+  /* We have to assemble the error on the stack because a dynamic
+   * string couldn't be freed.
+   */
+  char errmsg[ERROR_MESSAGE_LEN];
+  virErrorPtr err;
+  virConnectPtr conn;
+  virDomainPtr dom;
+  int is_test_uri = 0;
+  char *xml;
+
+  conn = Libvirtconn_val (connv);
   /* Look up the domain. */
   domname = String_val (domnamev);
 
@@ -232,10 +286,11 @@ v2v_dumpxml (value passwordv, value connv, value domnamev)
     err = virGetLastError ();
     snprintf (errmsg, sizeof errmsg,
               _("cannot find libvirt domain ‘%s’: %s"), domname, err->message);
-    virConnectClose (conn);
     caml_invalid_argument (errmsg);
   }
 
+  is_test_uri = STRPREFIX (virConnectGetURI (conn), "test:");
+
   /* As a side-effect we check that the domain is shut down.  Of course
    * this is only appropriate for virt-v2v.  (RHBZ#1138586)
    */
@@ -249,7 +304,6 @@ v2v_dumpxml (value passwordv, value connv, value domnamev)
                 _("libvirt domain ‘%s’ is running or paused.  It must be shut down in order to perform virt-v2v conversion"),
                 domname);
       virDomainFree (dom);
-      virConnectClose (conn);
       caml_invalid_argument (errmsg);
     }
   }
@@ -262,11 +316,9 @@ v2v_dumpxml (value passwordv, value connv, value domnamev)
               _("cannot fetch XML description of guest ‘%s’: %s"),
               domname, err->message);
     virDomainFree (dom);
-    virConnectClose (conn);
     caml_invalid_argument (errmsg);
   }
   virDomainFree (dom);
-  virConnectClose (conn);
 
   retv = caml_copy_string (xml);
   free (xml);
@@ -275,7 +327,7 @@ v2v_dumpxml (value passwordv, value connv, value domnamev)
 }
 
 value
-v2v_pool_dumpxml (value connv, value poolnamev)
+v2v_libvirt_pool_dumpxml (value connv, value poolnamev)
 {
   CAMLparam2 (connv, poolnamev);
   CAMLlocal1 (retv);
@@ -284,13 +336,11 @@ v2v_pool_dumpxml (value connv, value poolnamev)
    */
   char errmsg[ERROR_MESSAGE_LEN];
   virErrorPtr err;
-  virConnectPtr conn;
   virStoragePoolPtr pool;
   char *xml;
 
   /* Look up the pool. */
   pool = connect_and_load_pool (connv, poolnamev);
-  conn = virStoragePoolGetConnect (pool);
 
   xml = virStoragePoolGetXMLDesc (pool, 0);
   if (xml == NULL) {
@@ -299,11 +349,9 @@ v2v_pool_dumpxml (value connv, value poolnamev)
               _("cannot fetch XML description of pool ‘%s’: %s"),
               String_val (poolnamev), err->message);
     virStoragePoolFree (pool);
-    virConnectClose (conn);
     caml_invalid_argument (errmsg);
   }
   virStoragePoolFree (pool);
-  virConnectClose (conn);
 
   retv = caml_copy_string (xml);
   free (xml);
@@ -312,7 +360,7 @@ v2v_pool_dumpxml (value connv, value poolnamev)
 }
 
 value
-v2v_vol_dumpxml (value connv, value poolnamev, value volnamev)
+v2v_libvirt_vol_dumpxml (value connv, value poolnamev, value volnamev)
 {
   CAMLparam3 (connv, poolnamev, volnamev);
   CAMLlocal1 (retv);
@@ -322,14 +370,12 @@ v2v_vol_dumpxml (value connv, value poolnamev, value volnamev)
    */
   char errmsg[ERROR_MESSAGE_LEN];
   virErrorPtr err;
-  virConnectPtr conn;
   virStoragePoolPtr pool;
   virStorageVolPtr vol;
   char *xml;
 
   /* Look up the pool. */
   pool = connect_and_load_pool (connv, poolnamev);
-  conn = virStoragePoolGetConnect (pool);
 
   /* Look up the volume. */
   volname = String_val (volnamev);
@@ -341,7 +387,6 @@ v2v_vol_dumpxml (value connv, value poolnamev, value volnamev)
     snprintf (errmsg, sizeof errmsg,
               _("cannot find libvirt volume ‘%s’: %s"), volname, err->message);
     virStoragePoolFree (pool);
-    virConnectClose (conn);
     caml_invalid_argument (errmsg);
   }
 
@@ -353,12 +398,10 @@ v2v_vol_dumpxml (value connv, value poolnamev, value volnamev)
               volname, err->message);
     virStorageVolFree (vol);
     virStoragePoolFree (pool);
-    virConnectClose (conn);
     caml_invalid_argument (errmsg);
   }
   virStorageVolFree (vol);
   virStoragePoolFree (pool);
-  virConnectClose (conn);
 
   retv = caml_copy_string (xml);
   free (xml);
@@ -367,11 +410,10 @@ v2v_vol_dumpxml (value connv, value poolnamev, value volnamev)
 }
 
 value
-v2v_capabilities (value connv, value unitv)
+v2v_libvirt_capabilities (value connv)
 {
-  CAMLparam2 (connv, unitv);
+  CAMLparam1 (connv);
   CAMLlocal1 (capabilitiesv);
-  const char *conn_uri = NULL;
   char *capabilities;
   /* We have to assemble the error on the stack because a dynamic
    * string couldn't be freed.
@@ -380,29 +422,7 @@ v2v_capabilities (value connv, value unitv)
   virErrorPtr err;
   virConnectPtr conn;
 
-  if (connv != Val_int (0))
-    conn_uri = String_val (Field (connv, 0)); /* Some conn */
-
-  /* We have to call the default authentication handler, not least
-   * since it handles all the PolicyKit crap.  However it also makes
-   * coding this simpler.
-   */
-  conn = virConnectOpenAuth (conn_uri, virConnectAuthPtrDefault,
-                             VIR_CONNECT_RO);
-  if (conn == NULL) {
-    if (conn_uri)
-      snprintf (errmsg, sizeof errmsg,
-                _("cannot open libvirt connection ‘%s’"), conn_uri);
-    else
-      snprintf (errmsg, sizeof errmsg, _("cannot open libvirt connection"));
-    caml_invalid_argument (errmsg);
-  }
-
-  /* Suppress default behaviour of printing errors to stderr.  Note
-   * you can't set this to NULL to ignore errors; setting it to NULL
-   * restores the default error handler ...
-   */
-  virConnSetErrorFunc (conn, NULL, ignore_errors);
+  conn = Libvirtconn_val (connv);
 
   capabilities = virConnectGetCapabilities (conn);
   if (!capabilities) {
@@ -410,23 +430,19 @@ v2v_capabilities (value connv, value unitv)
     snprintf (errmsg, sizeof errmsg,
               _("cannot get libvirt hypervisor capabilities: %s"),
               err->message);
-    virConnectClose (conn);
     caml_invalid_argument (errmsg);
   }
 
   capabilitiesv = caml_copy_string (capabilities);
   free (capabilities);
 
-  virConnectClose (conn);
-
   CAMLreturn (capabilitiesv);
 }
 
 value
-v2v_domain_exists (value connv, value domnamev)
+v2v_libvirt_domain_exists (value connv, value domnamev)
 {
   CAMLparam2 (connv, domnamev);
-  const char *conn_uri = NULL;
   const char *domname;
   /* We have to assemble the error on the stack because a dynamic
    * string couldn't be freed.
@@ -437,31 +453,8 @@ v2v_domain_exists (value connv, value domnamev)
   virDomainPtr dom;
   int domain_exists;
 
-  if (connv != Val_int (0))
-    conn_uri = String_val (Field (connv, 0)); /* Some conn */
-
-  /* We have to call the default authentication handler, not least
-   * since it handles all the PolicyKit crap.  However it also makes
-   * coding this simpler.
-   */
-  conn = virConnectOpenAuth (conn_uri, virConnectAuthPtrDefault,
-                             VIR_CONNECT_RO);
-  if (conn == NULL) {
-    if (conn_uri)
-      snprintf (errmsg, sizeof errmsg,
-                _("cannot open libvirt connection ‘%s’"), conn_uri);
-    else
-      snprintf (errmsg, sizeof errmsg, _("cannot open libvirt connection"));
-    caml_invalid_argument (errmsg);
-  }
-
-  /* Suppress default behaviour of printing errors to stderr.  Note
-   * you can't set this to NULL to ignore errors; setting it to NULL
-   * restores the default error handler ...
-   */
-  virConnSetErrorFunc (conn, NULL, ignore_errors);
-
   /* Look up the domain. */
+  conn = Libvirtconn_val (connv);
   domname = String_val (domnamev);
   dom = virDomainLookupByName (conn, domname);
 
@@ -477,17 +470,44 @@ v2v_domain_exists (value connv, value domnamev)
       snprintf (errmsg, sizeof errmsg,
                 _("cannot find libvirt domain ‘%s’: %s"),
                 domname, err->message);
-      virConnectClose (conn);
       caml_invalid_argument (errmsg);
     }
   }
 
-  virConnectClose (conn);
-
   CAMLreturn (Val_bool (domain_exists));
 }
 
 value
+v2v_libvirt_get_uri (value connv)
+{
+  CAMLparam1 (connv);
+  CAMLlocal1 (uriv);
+  char *uri;
+  /* We have to assemble the error on the stack because a dynamic
+   * string couldn't be freed.
+   */
+  char errmsg[ERROR_MESSAGE_LEN];
+  virErrorPtr err;
+  virConnectPtr conn;
+
+  conn = Libvirtconn_val (connv);
+
+  uri = virConnectGetURI (conn);
+  if (!uri) {
+    err = virGetLastError ();
+    snprintf (errmsg, sizeof errmsg,
+              _("cannot get libvirt hypervisor URI: %s"),
+              err->message);
+    caml_invalid_argument (errmsg);
+  }
+
+  uriv = caml_copy_string (uri);
+  free (uri);
+
+  CAMLreturn (uriv);
+}
+
+value
 v2v_libvirt_get_version (value unitv)
 {
   CAMLparam1 (unitv);
@@ -529,11 +549,12 @@ v2v_libvirt_get_version (value unitv)
     caml_invalid_argument ("virt-v2v was compiled without libvirt support"); \
   }
 
-NO_LIBVIRT (value v2v_dumpxml (value connv, value domv))
-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_dumpxml (value connv, value domv))
+NO_LIBVIRT (value v2v_libvirt_pool_dumpxml (value connv, value poolv))
+NO_LIBVIRT (value v2v_libvirt_vol_dumpxml (value connv, value poolnamev, value volnamev))
+NO_LIBVIRT (value v2v_libvirt_capabilities (value connv, value unitv))
+NO_LIBVIRT (value v2v_libvirt_domain_exists (value connv, value domnamev))
+NO_LIBVIRT (value v2v_libvirt_get_uri (value connv))
 NO_LIBVIRT (value v2v_libvirt_get_version (value unitv))
 
 #endif /* !HAVE_LIBVIRT */
diff --git a/v2v/libvirt_utils.ml b/v2v/libvirt_utils.ml
index 248d78c72..d813855cd 100644
--- a/v2v/libvirt_utils.ml
+++ b/v2v/libvirt_utils.ml
@@ -19,13 +19,19 @@
 (* This module implements various [virsh]-like commands, but with
     non-broken authentication handling. *)
 
-external dumpxml : ?password:string -> ?conn:string -> string -> string = "v2v_dumpxml"
-external pool_dumpxml : ?conn:string -> string -> string = "v2v_pool_dumpxml"
-external vol_dumpxml : ?conn:string -> string -> string -> string = "v2v_vol_dumpxml"
+type conn
+external connect_ro : ?conn:string -> unit -> conn = "v2v_libvirt_connect_ro"
+external connect_rw : ?password:string -> ?conn:string -> unit -> conn = "v2v_libvirt_connect_rw"
 
-external capabilities : ?conn:string -> unit -> string = "v2v_capabilities"
+external dumpxml : conn -> string -> string = "v2v_libvirt_dumpxml"
+external pool_dumpxml : conn -> string -> string = "v2v_libvirt_pool_dumpxml"
+external vol_dumpxml : conn -> string -> string -> string = "v2v_libvirt_vol_dumpxml"
 
-external domain_exists : ?conn:string -> string -> bool = "v2v_domain_exists"
+external capabilities : conn -> string = "v2v_libvirt_capabilities"
+
+external domain_exists : conn -> string -> bool = "v2v_libvirt_domain_exists"
+
+external get_uri : conn -> string = "v2v_libvirt_get_uri"
 
 external libvirt_get_version : unit -> int * int * int
   = "v2v_libvirt_get_version"
diff --git a/v2v/libvirt_utils.mli b/v2v/libvirt_utils.mli
index 53dfd48e5..11a83b9a2 100644
--- a/v2v/libvirt_utils.mli
+++ b/v2v/libvirt_utils.mli
@@ -24,32 +24,42 @@
     password prompt to stdout, which is the same place we would be
     reading the XML from.  This file works around this brokenness. *)
 
-val dumpxml : ?password:string -> ?conn:string -> string -> string
-(** [dumpxml ?password ?conn dom] returns the libvirt XML of domain [dom].
-    The optional [?conn] parameter is the libvirt connection URI.
+type conn
+(** The type of a compiled regular expression. *)
+
+val connect_ro : ?conn:string -> unit -> conn
+(** Connect in read-only mode to the specified URI. *)
+
+val connect_rw : ?password:string -> ?conn:string -> unit -> conn
+(** Connect in read-only mode to the specified URI. *)
+
+val dumpxml : conn -> string -> string
+(** [dumpxml conn dom] returns the libvirt XML of domain [dom]
+    in the libvirt connection [conn].
     [dom] may be a guest name or UUID. *)
 
-val pool_dumpxml : ?conn:string -> string -> string
-(** [pool_dumpxml ?conn pool] returns the libvirt XML of pool [pool].
-    The optional [?conn] parameter is the libvirt connection URI.
+val pool_dumpxml : conn -> string -> string
+(** [pool_dumpxml ?conn pool] returns the libvirt XML of pool [pool]
+    in the libvirt connection [conn].
     [pool] may be a pool name or UUID. *)
 
-val vol_dumpxml : ?conn:string -> string -> string -> string
-(** [vol_dumpxml ?conn pool vol] returns the libvirt XML of volume [vol],
-    which is part of the pool [pool].
-    The optional [?conn] parameter is the libvirt connection URI.
+val vol_dumpxml : conn -> string -> string -> string
+(** [vol_dumpxml conn pool vol] returns the libvirt XML of volume [vol],
+    which is part of the pool [pool], in the libvirt connection [conn].
     [pool] may be a pool name or UUID. *)
 
-val capabilities : ?conn:string -> unit -> string
-(** [capabilities ?conn ()] returns the libvirt capabilities XML.
-    The optional [?conn] parameter is the libvirt connection URI. *)
+val capabilities : conn -> string
+(** [capabilities conn] returns the libvirt capabilities XML
+    of the libvirt connection [conn]. *)
 
-val domain_exists : ?conn:string -> string -> bool
-(** [domain_exists ?conn dom] returns a boolean indicating if the
-    the libvirt XML domain [dom] exists.
-    The optional [?conn] parameter is the libvirt connection URI.
+val domain_exists : conn -> string -> bool
+(** [domain_exists conn dom] returns a boolean indicating if the
+    the libvirt XML domain [dom] exists in the libvirt connection [conn].
     [dom] may be a guest name, but not a UUID. *)
 
+val get_uri : conn -> string
+(** [get_uri conn] returns the URI of the libvirt connection [conn]. *)
+
 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/output_libvirt.ml b/v2v/output_libvirt.ml
index b5df8245f..e00cac24b 100644
--- a/v2v/output_libvirt.ml
+++ b/v2v/output_libvirt.ml
@@ -78,8 +78,10 @@ class output_libvirt oc output_pool = object
     | Some uri -> sprintf "-o libvirt -oc %s -os %s" uri output_pool
 
   method prepare_targets source targets =
+    let conn = Libvirt_utils.connect_ro ?conn:oc () in
+
     (* Get the capabilities from libvirt. *)
-    let xml = Libvirt_utils.capabilities ?conn:oc () in
+    let xml = Libvirt_utils.capabilities conn in
     debug "libvirt capabilities XML:\n%s" xml;
 
     (* This just checks that the capabilities XML is well-formed,
@@ -94,7 +96,7 @@ class output_libvirt oc output_pool = object
     capabilities_doc <- Some doc;
 
     (* Does the domain already exist on the target?  (RHBZ#889082) *)
-    if Libvirt_utils.domain_exists ?conn:oc source.s_name then (
+    if Libvirt_utils.domain_exists conn source.s_name then (
       if source.s_hypervisor = Physical then (* virt-p2v user *)
         error (f_"a libvirt domain called ‘%s’ already exists on the target.\n\nIf using virt-p2v, select a different ‘Name’ in the ‘Target properties’. Or delete the existing domain on the target using the ‘virsh undefine’ command.")
               source.s_name
@@ -106,7 +108,7 @@ class output_libvirt oc output_pool = object
     (* Connect to output libvirt instance and check that the pool exists
      * and dump out its XML.
      *)
-    let xml = Libvirt_utils.pool_dumpxml ?conn:oc output_pool in
+    let xml = Libvirt_utils.pool_dumpxml conn output_pool in
     let doc = Xml.parse_memory xml in
     let xpathctx = Xml.xpath_new_context doc in
     let xpath_string = xpath_string xpathctx in
diff --git a/v2v/parse_libvirt_xml.ml b/v2v/parse_libvirt_xml.ml
index c71707000..e3260c429 100644
--- a/v2v/parse_libvirt_xml.ml
+++ b/v2v/parse_libvirt_xml.ml
@@ -71,7 +71,7 @@ let create_curl_qemu_uri driver host port path =
   (* Turn the JSON parameters into a 'json:' protocol string. *)
   "json: " ^ JSON.string_of_doc json_params
 
-let parse_libvirt_xml ?conn xml =
+let parse_libvirt_xml conn xml =
   debug "libvirt xml is:\n%s" xml;
 
   let doc = Xml.parse_memory xml in
@@ -328,7 +328,7 @@ let parse_libvirt_xml ?conn xml =
         (match xpath_string "source/@pool", xpath_string "source/@volume" with
         | None, None | Some _, None | None, Some _ -> ()
         | Some pool, Some vol ->
-          let xml = Libvirt_utils.vol_dumpxml ?conn pool vol in
+          let xml = Libvirt_utils.vol_dumpxml conn pool vol in
           let doc = Xml.parse_memory xml in
           let xpathctx = Xml.xpath_new_context doc in
           let xpath_string = Xpath_helpers.xpath_string xpathctx in
diff --git a/v2v/parse_libvirt_xml.mli b/v2v/parse_libvirt_xml.mli
index 3d4f7b375..1f2a5056e 100644
--- a/v2v/parse_libvirt_xml.mli
+++ b/v2v/parse_libvirt_xml.mli
@@ -27,7 +27,7 @@ and parsed_source =
 | P_source_file of string            (** <source file> *)
 | P_dont_rewrite                     (** s_qemu_uri is already set. *)
 
-val parse_libvirt_xml : ?conn:string -> string -> Types.source * parsed_disk list
+val parse_libvirt_xml : Libvirt_utils.conn -> string -> Types.source * parsed_disk list
 (** Take libvirt XML and parse it into a {!Types.source} structure and a
     list of source disks.
 
-- 
2.13.5




More information about the Libguestfs mailing list