mrc0mmand / rpms / libguestfs

Forked from rpms/libguestfs 3 years ago
Clone
Blob Blame History Raw
From 9583ab8900194694359cbefe403209f73fd08a47 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Mon, 20 Oct 2014 20:41:29 +0100
Subject: [PATCH] v2v: Inline and simplify Xen and vCenter input methods.

Take the opportunity presented by the refactoring in the previous
commit to inline and simplify functions in these input subclasses.

This finally removes the map_source* functions.

(cherry picked from commit b8f826b7ac1e7f90f670f474c3582b56063cdef6)
---
 v2v/input_libvirt_vcenter_https.ml | 249 +++++++++++++++++++------------------
 v2v/input_libvirt_xen_ssh.ml       |  93 +++++++-------
 2 files changed, 171 insertions(+), 171 deletions(-)

diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml
index 7dde9be..5d98a86 100644
--- a/v2v/input_libvirt_vcenter_https.ml
+++ b/v2v/input_libvirt_vcenter_https.ml
@@ -28,11 +28,107 @@ open Input_libvirt_other
 
 open Printf
 
-let esx_re = Str.regexp "^\\[\\(.*\\)\\] \\(.*\\)\\.vmdk$"
+(* 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 verbose scheme uri sslverify url ->
+    if !session_cookie <> "" then
+      Some !session_cookie
+    else (
+      let cmd =
+        sprintf "curl -s%s%s%s -I %s ||:"
+          (if not sslverify then " --insecure" else "")
+          (match uri.uri_user with Some _ -> " -u" | None -> "")
+          (match uri.uri_user with Some user -> " " ^ quote user | None -> "")
+          (quote url) in
+      let lines = external_command ~prog cmd in
 
-let session_cookie = ref ""
+      let dump_response chan =
+        fprintf chan "%s\n" cmd;
+        List.iter (fun x -> fprintf chan "%s\n" x) lines
+      in
 
-(* Map an ESX <source/> to a qemu URI using the cURL driver
+      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_"esx: 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_"esx: incorrect username or password")
+        else
+          error (f_"esx: 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_"esx: URL not found: %s") url
+      );
+
+      if status <> "200" then (
+        dump_response stderr;
+        error (f_"esx: 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 ~prog (f_"esx: 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
+    )
+
+(* Helper function to extract the datacenter from a URI. *)
+let get_datacenter uri scheme =
+  let default_dc = "ha-datacenter" in
+  match scheme with
+  | "vpx" ->           (* Hopefully the first part of the path. *)
+    (match uri.uri_path with
+    | None ->
+      warning ~prog (f_"esx: URI (-ic parameter) contains no path, so we cannot determine the datacenter name");
+      default_dc
+    | Some path ->
+      let path =
+        let len = String.length path in
+        if len > 0 && path.[0] = '/' then
+          String.sub path 1 (len-1)
+        else path in
+      let len =
+        try String.index 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
  *
  *   "[datastore1] Fedora 20/Fedora 20.vmdk"
@@ -46,9 +142,11 @@ let session_cookie = ref ""
  * XXX Need to handle templates.  The file is called "-delta.vmdk" in
  * place of "-flat.vmdk".
  *)
-let rec map_path_to_uri verbose uri scheme server ?readahead path format =
-  if not (Str.string_match esx_re path 0) then
-    path, format
+let source_re = Str.regexp "^\\[\\(.*\\)\\] \\(.*\\)\\.vmdk$"
+
+let map_source_to_uri ?readahead verbose uri scheme server path =
+  if not (Str.string_match source_re path 0) then
+    path
   else (
     let datastore = Str.matched_group 1 path
     and path = Str.matched_group 2 path in
@@ -111,105 +209,7 @@ let rec map_path_to_uri verbose uri scheme server ?readahead path format =
      *)
     let qemu_uri = "json: " ^ JSON.string_of_doc json_params in
 
-    (* The libvirt ESX driver doesn't normally specify a format, but
-     * the format of the -flat file is *always* raw, so force it here.
-     *)
-    qemu_uri, Some "raw"
-  )
-
-and get_datacenter uri scheme =
-  let default_dc = "ha-datacenter" in
-  match scheme with
-  | "vpx" ->           (* Hopefully the first part of the path. *)
-    (match uri.uri_path with
-    | None ->
-      warning ~prog (f_"esx: URI (-ic parameter) contains no path, so we cannot determine the datacenter name");
-      default_dc
-    | Some path ->
-      let path =
-        let len = String.length path in
-        if len > 0 && path.[0] = '/' then
-          String.sub path 1 (len-1)
-        else path in
-      let len =
-        try String.index 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
-
-and get_session_cookie verbose scheme uri sslverify url =
-  (* Memoize the session cookie. *)
-  if !session_cookie <> "" then
-    Some !session_cookie
-  else (
-    let cmd =
-      sprintf "curl -s%s%s%s -I %s ||:"
-        (if not sslverify then " --insecure" else "")
-        (match uri.uri_user with Some _ -> " -u" | None -> "")
-        (match uri.uri_user with Some user -> " " ^ quote user | None -> "")
-        (quote url) in
-    let lines = external_command ~prog cmd in
-
-    let dump_response chan =
-      fprintf chan "%s\n" cmd;
-      List.iter (fun x -> fprintf chan "%s\n" x) lines
-    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_"esx: 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_"esx: incorrect username or password")
-      else
-        error (f_"esx: 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_"esx: URL not found: %s") url
-    );
-
-    if status <> "200" then (
-      dump_response stderr;
-      error (f_"esx: 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 ~prog (f_"esx: 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
+    qemu_uri
   )
 
 (* Subclass specialized for handling VMware vCenter over https. *)
@@ -218,11 +218,12 @@ class input_libvirt_vcenter_https
 object
   inherit input_libvirt verbose libvirt_uri guest
 
-  val mutable mapf = fun ?readahead uri format -> uri, format
-  val saved_uri = Hashtbl.create 13
+  val saved_source_paths = Hashtbl.create 13
 
   method source () =
-    if verbose then printf "input_libvirt_vcenter_https: source()\n%!";
+    if verbose then
+      printf "input_libvirt_vcenter_https: source: scheme %s server %s\n%!"
+        scheme server;
 
     error_if_libvirt_backend ();
 
@@ -233,38 +234,42 @@ object
     let { s_disks = disks } as source =
       Input_libvirtxml.parse_libvirt_xml ~verbose xml in
 
-    (* Save the mapf function and the original s_qemu_uri fields, so
-     * we can get them in the adjust_overlay_parameters method below.
+    (* Save the original source paths, so that we can remap them again
+     * in [#adjust_overlay_parameters].
      *)
-    mapf <- map_path_to_uri verbose parsed_uri scheme server;
     List.iter (
-      fun disk ->
-        Hashtbl.add saved_uri disk.s_disk_id (disk.s_qemu_uri, disk.s_format)
+      fun { s_disk_id = id; s_qemu_uri = path } ->
+        Hashtbl.add saved_source_paths id path
     ) disks;
 
     let disks = List.map (
-      fun ({ s_qemu_uri = uri; s_format = format } as disk) ->
-        let uri, format = mapf uri format in
-        { disk with s_qemu_uri = uri; s_format = format }
+      fun ({ s_qemu_uri = path } as disk) ->
+        let qemu_uri = map_source_to_uri verbose parsed_uri scheme server path in
+
+        (* The libvirt ESX driver doesn't normally specify a format, but
+         * the format of the -flat file is *always* raw, so force it here.
+         *)
+        { disk with s_qemu_uri = qemu_uri; s_format = Some "raw" }
     ) disks in
 
     { source with s_disks = disks }
 
   (* See RHBZ#1151033 and RHBZ#1153589 for why this is necessary. *)
   method adjust_overlay_parameters overlay =
-    let orig_uri, orig_format =
-      try Hashtbl.find saved_uri overlay.ov_source.s_disk_id
+    let orig_path =
+      try Hashtbl.find saved_source_paths overlay.ov_source.s_disk_id
       with Not_found -> failwith "internal error in adjust_overlay_parameters" in
-    let backing_file, _ =
-      mapf ~readahead:(64 * 1024 * 1024) orig_uri orig_format in
+    let backing_qemu_uri =
+      map_source_to_uri ~readahead:(64 * 1024 * 1024)
+        verbose parsed_uri scheme server orig_path in
 
     (* Rebase the qcow2 overlay to adjust the readahead parameter. *)
     let cmd =
       sprintf "qemu-img rebase -u -b %s %s"
-        (quote backing_file) (quote overlay.ov_overlay_file) in
+        (quote backing_qemu_uri) (quote overlay.ov_overlay_file) in
     if verbose then printf "%s\n%!" cmd;
     if Sys.command cmd <> 0 then
-      warning ~prog (f_"qemu-img rebase failed, see earlier errors")
+      warning ~prog (f_"qemu-img rebase failed (ignored)")
 end
 
 let input_libvirt_vcenter_https = new input_libvirt_vcenter_https
diff --git a/v2v/input_libvirt_xen_ssh.ml b/v2v/input_libvirt_xen_ssh.ml
index 081317d..8b836a5 100644
--- a/v2v/input_libvirt_xen_ssh.ml
+++ b/v2v/input_libvirt_xen_ssh.ml
@@ -28,57 +28,15 @@ open Input_libvirt_other
 
 open Printf
 
-(* Map a Xen <source/> to a qemu URI using the SSH driver in qemu.
- * This code assumes (and the caller checks) that the Xen URI is
- * remotely accessible over ssh, so we can map the path to the qemu
- * URI:
- *
- * json: {
- *   "file.driver": "ssh",
- *   "file.user": "username",
- *   "file.host": "xen-host",
- *   "file.port": 123,
- *   "file.path": "path",
- *   "file.host_key_check": "no"
- * }
- *)
-let map_path_to_uri verbose uri scheme server path format =
-  (* Construct the JSON parameters. *)
-  let json_params = [
-    "file.driver", JSON.String "ssh";
-    "file.path", JSON.String path;
-    "file.host", JSON.String server;
-    "file.host_key_check", JSON.String "no";
-  ] in
-
-  let json_params =
-    match uri.uri_port with
-    | 0 | 22 -> json_params
-    (* qemu will actually assert-fail if you send the port number as a
-     * string ...
-     *)
-    | i -> ("file.port", JSON.Int i) :: json_params in
-
-  let json_params =
-    match uri.uri_user with
-    | None -> json_params
-    | Some user -> ("file.user", JSON.String user) :: json_params in
-
-  if verbose then
-    printf "ssh: json parameters: %s\n" (JSON.string_of_doc json_params);
-
-  (* Turn the JSON parameters into a 'json:' protocol string. *)
-  let qemu_uri = "json: " ^ JSON.string_of_doc json_params in
-
-  qemu_uri, format
-
 (* Subclass specialized for handling Xen over SSH. *)
 class input_libvirt_xen_ssh verbose libvirt_uri parsed_uri scheme server guest =
 object
   inherit input_libvirt verbose libvirt_uri guest
 
   method source () =
-    if verbose then printf "input_libvirt_xen_ssh: source()\n%!";
+    if verbose then
+      printf "input_libvirt_xen_ssh: source: scheme %s server %s\n%!"
+        scheme server;
 
     error_if_libvirt_backend ();
     error_if_no_ssh_agent ();
@@ -90,11 +48,48 @@ object
     let { s_disks = disks } as source =
       Input_libvirtxml.parse_libvirt_xml ~verbose xml in
 
-    let mapf = map_path_to_uri verbose parsed_uri scheme server in
+    (* Map the <source/> filename (which is relative to the remote
+     * Xen server) to an ssh URI.  This is a JSON URI looking something
+     * like this:
+     *
+     * json: {
+     *   "file.driver": "ssh",
+     *   "file.user": "username",
+     *   "file.host": "xen-host",
+     *   "file.port": 1022,
+     *   "file.path": "path",
+     *   "file.host_key_check": "no"
+     *)
     let disks = List.map (
-      fun ({ s_qemu_uri = uri; s_format = format } as disk) ->
-        let uri, format = mapf uri format in
-        { disk with s_qemu_uri = uri; s_format = format }
+      fun ({ s_qemu_uri = path } as disk) ->
+        (* Construct the JSON parameters. *)
+        let json_params = [
+          "file.driver", JSON.String "ssh";
+          "file.path", JSON.String path;
+          "file.host", JSON.String server;
+          "file.host_key_check", JSON.String "no";
+        ] in
+
+        let json_params =
+          match parsed_uri.uri_port with
+          | 0 | 22 -> json_params
+          (* qemu will actually assert-fail if you send the port
+           * number as a string ...
+           *)
+          | i -> ("file.port", JSON.Int i) :: json_params in
+
+        let json_params =
+          match parsed_uri.uri_user with
+          | None -> json_params
+          | Some user -> ("file.user", JSON.String user) :: json_params in
+
+        if verbose then
+          printf "ssh: json parameters: %s\n" (JSON.string_of_doc json_params);
+
+        (* Turn the JSON parameters into a 'json:' protocol string. *)
+        let qemu_uri = "json: " ^ JSON.string_of_doc json_params in
+
+        { disk with s_qemu_uri = qemu_uri }
     ) disks in
 
     { source with s_disks = disks }
-- 
1.8.3.1