[Libguestfs] [PATCH 2/4] v2v: Move VCenter functions to library module.

Richard W.M. Jones rjones at redhat.com
Fri Oct 9 11:53:23 UTC 2015


This refactors useful VCenter functions out of the large
'input_libvirt_vcenter_https.ml' file.
---
 po/POTFILES-ml                     |   1 +
 v2v/Makefile.am                    |   2 +
 v2v/input_libvirt_vcenter_https.ml | 144 +--------------------------------
 v2v/vCenter.ml                     | 160 +++++++++++++++++++++++++++++++++++++
 v2v/vCenter.mli                    |  40 ++++++++++
 5 files changed, 205 insertions(+), 142 deletions(-)
 create mode 100644 v2v/vCenter.ml
 create mode 100644 v2v/vCenter.mli

diff --git a/po/POTFILES-ml b/po/POTFILES-ml
index 239e586..f794f1d 100644
--- a/po/POTFILES-ml
+++ b/po/POTFILES-ml
@@ -126,4 +126,5 @@ v2v/types.ml
 v2v/utils.ml
 v2v/v2v.ml
 v2v/v2v_unit_tests.ml
+v2v/vCenter.ml
 v2v/xml.ml
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
index 6bfdb62..da31aaf 100644
--- a/v2v/Makefile.am
+++ b/v2v/Makefile.am
@@ -69,6 +69,7 @@ SOURCES_MLI = \
 	OVF.mli \
 	stringMap.mli \
 	types.mli \
+	vCenter.mli \
 	xml.mli
 
 SOURCES_ML = \
@@ -77,6 +78,7 @@ SOURCES_ML = \
 	xml.ml \
 	utils.ml \
 	curl.ml \
+	vCenter.ml \
 	domainxml.ml \
 	DOM.ml \
 	kvmuid.ml \
diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml
index 13108c7..0f1a648 100644
--- a/v2v/input_libvirt_vcenter_https.ml
+++ b/v2v/input_libvirt_vcenter_https.ml
@@ -33,146 +33,6 @@ open Printf
 let readahead_for_conversion = None
 let readahead_for_copying = Some (64 * 1024 * 1024)
 
-(* Return the session cookie.  It is memoized, so you can call this
- * as often as required.
- *)
-let get_session_cookie =
-  let session_cookie = ref "" in
-  fun password scheme uri sslverify url ->
-    if !session_cookie <> "" then
-      Some !session_cookie
-    else (
-      let curl_args = [
-        "head", None;
-        "silent", None;
-        "url", Some url;
-      ] in
-      let curl_args =
-        match uri.uri_user, password with
-        | None, None -> curl_args
-        | None, Some _ ->
-          warning (f_"--password-file parameter ignored because 'user@' was not given in the URL");
-          curl_args
-        | Some user, None ->
-          ("user", Some user) :: curl_args
-        | Some user, Some password ->
-          ("user", Some (user ^ ":" ^ password)) :: curl_args in
-      let curl_args =
-        if not sslverify then ("insecure", None) :: curl_args else curl_args in
-
-      let lines = Curl.run curl_args in
-
-      let dump_response chan =
-        Curl.print_curl_command chan curl_args;
-
-        (* Dump out the output of the command. *)
-        List.iter (fun x -> fprintf chan "%s\n" x) lines;
-        flush chan
-      in
-
-      if verbose () then dump_response stdout;
-
-      (* Look for the last HTTP/x.y NNN status code in the output. *)
-      let status = ref "" in
-      List.iter (
-        fun line ->
-          let len = String.length line in
-          if len >= 12 && String.sub line 0 5 = "HTTP/" then
-            status := String.sub line 9 3
-      ) lines;
-      let status = !status in
-      if status = "" then (
-        dump_response stderr;
-        error (f_"vcenter: no status code in output of 'curl' command.  Is 'curl' installed?")
-      );
-
-      if status = "401" then (
-        dump_response stderr;
-        if uri.uri_user <> None then
-          error (f_"vcenter: incorrect username or password")
-        else
-          error (f_"vcenter: incorrect username or password.  You might need to specify the username in the URI like this: %s://USERNAME@[etc]")
-            scheme
-      );
-
-      if status = "404" then (
-        dump_response stderr;
-        error (f_"vcenter: URL not found: %s\n\nThe '--dcpath' parameter may be useful.  See the explanation in the virt-v2v(1) man page OPTIONS section.") url
-      );
-
-      if status <> "200" then (
-        dump_response stderr;
-        error (f_"vcenter: invalid response from server")
-      );
-
-      (* Get the cookie. *)
-      List.iter (
-        fun line ->
-          let len = String.length line in
-          if len >= 12 && String.sub line 0 12 = "Set-Cookie: " then (
-            let line = String.sub line 12 (len-12) in
-            let cookie, _ = String.split ";" line in
-            session_cookie := cookie
-          )
-      ) lines;
-      if !session_cookie = "" then (
-        dump_response stderr;
-        warning (f_"vcenter: could not read session cookie from the vCenter Server, conversion may consume all sessions on the server and fail part way through");
-        None
-      )
-      else
-        Some !session_cookie
-    )
-
-let multiple_slash = Str.regexp "/+"
-
-(* Helper function to extract the dcPath from a URI. *)
-let get_dcPath uri scheme =
-  let default_dc = "ha-datacenter" in
-  match scheme with
-  | "vpx" ->
-    (match uri.uri_path with
-    | None ->
-      warning (f_"vcenter: URI (-ic parameter) contains no path, so we cannot determine the dcPath (datacenter name)");
-      default_dc
-    | Some path ->
-      (* vCenter: URIs are *usually* '/Folder/Datacenter/esxi' so we can
-       * just chop off the first '/' and final '/esxi' to get the dcPath.
-       *
-       * The libvirt driver allows things like '/DC///esxi////' so we also
-       * have to handle trailing slashes and collapse multiple slashes into
-       * single (RHBZ#1258342).
-       *
-       * However if there is a cluster involved then the URI may be
-       * /Folder/Datacenter/Cluster/esxi but dcPath=Folder/Datacenter/Cluster
-       * won't work.  In this case the user has to adjust the path to
-       * remove the Cluster name (which still works in libvirt).  There
-       * should be a way to ask the libvirt vpx driver for the correct
-       * path, but there isn't. XXX  See also RHBZ#1256823.
-       *)
-      (* Collapse multiple slashes to single slash. *)
-      let path = Str.global_replace multiple_slash "/" path in
-      (* Chop off the first and trailing '/' (if found). *)
-      let path =
-        let len = String.length path in
-        if len > 0 && path.[0] = '/' then
-          String.sub path 1 (len-1)
-        else path in
-      let path =
-        let len = String.length path in
-        if len > 0 && path.[len-1] = '/' then
-          String.sub path 0 (len-1)
-        else path in
-      (* Chop off the final element (ESXi hostname). *)
-      let len =
-        try String.rindex path '/' with Not_found -> String.length path in
-      String.sub path 0 len
-    );
-  | "esx" -> (* Connecting to an ESXi hypervisor directly, so it's fixed. *)
-    default_dc
-  | _ ->                            (* Don't know, so guess. *)
-    default_dc
-
 (* Map the <source/> string to a qemu URI using the cURL driver
  * in qemu.  The 'path' will be something like
  *
@@ -200,7 +60,7 @@ let map_source_to_uri ?readahead dcPath password uri scheme server path =
     let dcPath =
       match dcPath with
       | None ->
-         let dcPath = get_dcPath uri scheme in
+         let dcPath = VCenter.guess_dcPath uri scheme in
          if verbose () then
            printf "vcenter: calculated dcPath as: %s\n" dcPath;
          dcPath
@@ -233,7 +93,7 @@ let map_source_to_uri ?readahead dcPath password uri scheme server path =
 
     (* Now we have to query the server to get the session cookie. *)
     let session_cookie =
-      get_session_cookie password scheme uri sslverify url in
+      VCenter.get_session_cookie password scheme uri sslverify url in
 
     (* Construct the JSON parameters. *)
     let json_params = [
diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml
new file mode 100644
index 0000000..20dd964
--- /dev/null
+++ b/v2v/vCenter.ml
@@ -0,0 +1,160 @@
+(* virt-v2v
+ * Copyright (C) 2009-2015 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.
+ *)
+
+open Printf
+
+open Common_utils
+open Common_gettext.Gettext
+
+open Xml
+
+(* Memoized session cookie. *)
+let session_cookie = ref ""
+
+let get_session_cookie password scheme uri sslverify url =
+  if !session_cookie <> "" then
+    Some !session_cookie
+  else (
+    let curl_args = [
+      "head", None;
+      "silent", None;
+      "url", Some url;
+    ] in
+    let curl_args =
+      match uri.uri_user, password with
+      | None, None -> curl_args
+      | None, Some _ ->
+         warning (f_"--password-file parameter ignored because 'user@' was not given in the URL");
+         curl_args
+      | Some user, None ->
+         ("user", Some user) :: curl_args
+      | Some user, Some password ->
+         ("user", Some (user ^ ":" ^ password)) :: curl_args in
+    let curl_args =
+      if not sslverify then ("insecure", None) :: curl_args else curl_args in
+
+    let lines = Curl.run curl_args in
+
+    let dump_response chan =
+      Curl.print_curl_command chan curl_args;
+
+      (* Dump out the output of the command. *)
+      List.iter (fun x -> fprintf chan "%s\n" x) lines;
+      flush chan
+    in
+
+    if verbose () then dump_response stdout;
+
+    (* Look for the last HTTP/x.y NNN status code in the output. *)
+    let status = ref "" in
+    List.iter (
+      fun line ->
+        let len = String.length line in
+        if len >= 12 && String.sub line 0 5 = "HTTP/" then
+          status := String.sub line 9 3
+    ) lines;
+    let status = !status in
+    if status = "" then (
+      dump_response stderr;
+      error (f_"vcenter: no status code in output of 'curl' command.  Is 'curl' installed?")
+    );
+
+    if status = "401" then (
+      dump_response stderr;
+      if uri.uri_user <> None then
+        error (f_"vcenter: incorrect username or password")
+      else
+        error (f_"vcenter: incorrect username or password.  You might need to specify the username in the URI like this: %s://USERNAME@[etc]")
+              scheme
+    );
+
+    if status = "404" then (
+      dump_response stderr;
+      error (f_"vcenter: URL not found: %s\n\nThe '--dcpath' parameter may be useful.  See the explanation in the virt-v2v(1) man page OPTIONS section.") url
+    );
+
+    if status <> "200" then (
+      dump_response stderr;
+      error (f_"vcenter: invalid response from server")
+    );
+
+    (* Get the cookie. *)
+    List.iter (
+      fun line ->
+        let len = String.length line in
+        if len >= 12 && String.sub line 0 12 = "Set-Cookie: " then (
+          let line = String.sub line 12 (len-12) in
+          let cookie, _ = String.split ";" line in
+          session_cookie := cookie
+        )
+    ) lines;
+    if !session_cookie = "" then (
+      dump_response stderr;
+      warning (f_"vcenter: could not read session cookie from the vCenter Server, conversion may consume all sessions on the server and fail part way through");
+      None
+    )
+    else
+      Some !session_cookie
+  )
+
+let multiple_slash = Str.regexp "/+"
+let default_dc = "ha-datacenter"
+
+let guess_dcPath uri = function
+  | "vpx" ->
+     (match uri.uri_path with
+      | None ->
+         warning (f_"vcenter: URI (-ic parameter) contains no path, so we cannot determine the dcPath (datacenter name)");
+         default_dc
+      | Some path ->
+         (* vCenter: URIs are *usually* '/Folder/Datacenter/esxi' so we can
+          * just chop off the first '/' and final '/esxi' to get the dcPath.
+          *
+          * The libvirt driver allows things like '/DC///esxi////' so we also
+          * have to handle trailing slashes and collapse multiple slashes into
+          * single (RHBZ#1258342).
+          *
+          * However if there is a cluster involved then the URI may be
+          * /Folder/Datacenter/Cluster/esxi but dcPath=Folder/Datacenter/Cluster
+          * won't work.  In this case the user has to adjust the path to
+          * remove the Cluster name (which still works in libvirt).  There
+          * should be a way to ask the libvirt vpx driver for the correct
+          * path, but there isn't. XXX  See also RHBZ#1256823.
+          *)
+         (* Collapse multiple slashes to single slash. *)
+         let path = Str.global_replace multiple_slash "/" path in
+         (* Chop off the first and trailing '/' (if found). *)
+         let path =
+           let len = String.length path in
+           if len > 0 && path.[0] = '/' then
+             String.sub path 1 (len-1)
+           else path in
+         let path =
+           let len = String.length path in
+           if len > 0 && path.[len-1] = '/' then
+             String.sub path 0 (len-1)
+           else path in
+         (* Chop off the final element (ESXi hostname). *)
+         let len =
+           try String.rindex path '/' with Not_found -> String.length path in
+         String.sub path 0 len
+     );
+  | "esx" -> (* Connecting to an ESXi hypervisor directly, so it's fixed. *)
+     default_dc
+  | _ ->     (* Don't know, so guess. *)
+     default_dc
diff --git a/v2v/vCenter.mli b/v2v/vCenter.mli
new file mode 100644
index 0000000..10a9657
--- /dev/null
+++ b/v2v/vCenter.mli
@@ -0,0 +1,40 @@
+(* virt-v2v
+ * Copyright (C) 2009-2015 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.
+ *)
+
+(** Functions for dealing with VMware vCenter. *)
+
+val get_session_cookie : string option -> string -> Xml.uri -> bool -> string -> string option
+(** [get_session_cookie password scheme uri sslverify url]
+    contacts the vCenter server, logs in, and gets the session cookie,
+    which can later be passed back to the server instead of having to
+    log in each time (this is also more efficient since it avoids
+    vCenter running out of authentication sessions).
+
+    Returns [None] if the session cookie could not be read (but
+    authentication was successful).  You can proceed without the
+    session cookie in this case, but there is an unavoidable
+    danger of running out of authentication sessions.  If the
+    session cookie could not be read, this function prints a
+    warning.
+
+    The session cookie is memoized so you can call this function as
+    often as you want, and only a single log in is made. *)
+
+val guess_dcPath : Xml.uri -> string -> string
+(** Try to guess the dcPath parameter from a URI.  The mapping is
+    not precise. *)
-- 
2.5.0




More information about the Libguestfs mailing list