|
|
a30de4 |
From f00bde700faf0708c8af440efdcc6b48e93f3ce4 Mon Sep 17 00:00:00 2001
|
|
|
a30de4 |
From: "Richard W.M. Jones" <rjones@redhat.com>
|
|
|
a30de4 |
Date: Fri, 13 Oct 2017 16:30:16 +0100
|
|
|
a30de4 |
Subject: [PATCH] v2v: vCenter: Refactor the API to this module.
|
|
|
a30de4 |
|
|
|
a30de4 |
This module had a selection of functions taking a different mix of
|
|
|
a30de4 |
parameters and doing slightly different things. You could call one
|
|
|
a30de4 |
function to return an https://... URL, or another function to return a
|
|
|
a30de4 |
qemu URL, and there was a third function to get the session cookie but
|
|
|
a30de4 |
you generally had to call that anyway (and it was implicitly called
|
|
|
a30de4 |
when making the qemu URL!)
|
|
|
a30de4 |
|
|
|
a30de4 |
Integrate these into a single function which returns a struct
|
|
|
a30de4 |
returning all possible values.
|
|
|
a30de4 |
|
|
|
a30de4 |
This is conceptually refactoring, except that the session cookie is no
|
|
|
a30de4 |
longer memoized, but we didn't use this feature (of calling
|
|
|
a30de4 |
get_session_cookie multiple times) anyway.
|
|
|
a30de4 |
|
|
|
a30de4 |
(cherry picked from commit fb79fcde2947ff7e73f96343e8311e43b22a6f66)
|
|
|
a30de4 |
---
|
|
|
a30de4 |
v2v/copy_to_local.ml | 12 +-
|
|
|
a30de4 |
v2v/input_libvirt_vcenter_https.ml | 12 +-
|
|
|
a30de4 |
v2v/vCenter.ml | 319 +++++++++++++++++++------------------
|
|
|
a30de4 |
v2v/vCenter.mli | 66 +++++---
|
|
|
a30de4 |
4 files changed, 211 insertions(+), 198 deletions(-)
|
|
|
a30de4 |
|
|
|
a30de4 |
diff --git a/v2v/copy_to_local.ml b/v2v/copy_to_local.ml
|
|
|
a30de4 |
index ca5578f3f..5fb1b79ff 100644
|
|
|
a30de4 |
--- a/v2v/copy_to_local.ml
|
|
|
a30de4 |
+++ b/v2v/copy_to_local.ml
|
|
|
a30de4 |
@@ -151,14 +151,10 @@ read the man page virt-v2v-copy-to-local(1).
|
|
|
a30de4 |
error (f_"vcenter: <vmware:datacenterpath> was not found in the XML. You need to upgrade to libvirt ≥ 1.2.20.") in
|
|
|
a30de4 |
List.map (
|
|
|
a30de4 |
fun (remote_disk, local_disk) ->
|
|
|
a30de4 |
- let url, sslverify =
|
|
|
a30de4 |
- VCenter.map_source_to_https dcpath parsed_uri
|
|
|
a30de4 |
- server remote_disk in
|
|
|
a30de4 |
- debug "esxi: source disk %s (sslverify=%b)" url sslverify;
|
|
|
a30de4 |
- let cookie =
|
|
|
a30de4 |
- VCenter.get_session_cookie password "esx"
|
|
|
a30de4 |
- parsed_uri sslverify url in
|
|
|
a30de4 |
- (url, local_disk, sslverify, cookie)
|
|
|
a30de4 |
+ let { VCenter.https_url; sslverify; session_cookie } =
|
|
|
a30de4 |
+ VCenter.map_source dcpath parsed_uri "esx" server remote_disk in
|
|
|
a30de4 |
+ debug "esxi: source disk %s (sslverify=%b)" https_url sslverify;
|
|
|
a30de4 |
+ (https_url, local_disk, sslverify, session_cookie)
|
|
|
a30de4 |
) disks
|
|
|
a30de4 |
| Test | Xen_ssh _ ->
|
|
|
a30de4 |
List.map (fun (remote_disk, local_disk) ->
|
|
|
a30de4 |
diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml
|
|
|
a30de4 |
index 497caca4f..1153e74a3 100644
|
|
|
a30de4 |
--- a/v2v/input_libvirt_vcenter_https.ml
|
|
|
a30de4 |
+++ b/v2v/input_libvirt_vcenter_https.ml
|
|
|
a30de4 |
@@ -102,9 +102,9 @@ object
|
|
|
a30de4 |
| { p_source = P_source_dev _ } -> assert false
|
|
|
a30de4 |
| { p_source_disk = disk; p_source = P_dont_rewrite } -> disk
|
|
|
a30de4 |
| { p_source_disk = disk; p_source = P_source_file path } ->
|
|
|
a30de4 |
- let qemu_uri =
|
|
|
a30de4 |
- VCenter.map_source_to_uri readahead dcPath password
|
|
|
a30de4 |
- parsed_uri scheme server path in
|
|
|
a30de4 |
+ let { VCenter.qemu_uri } =
|
|
|
a30de4 |
+ VCenter.map_source ?readahead ?password
|
|
|
a30de4 |
+ dcPath parsed_uri scheme server path in
|
|
|
a30de4 |
|
|
|
a30de4 |
(* The libvirt ESX driver doesn't normally specify a format, but
|
|
|
a30de4 |
* the format of the -flat file is *always* raw, so force it here.
|
|
|
a30de4 |
@@ -123,9 +123,9 @@ object
|
|
|
a30de4 |
| None -> ()
|
|
|
a30de4 |
| Some orig_path ->
|
|
|
a30de4 |
let readahead = readahead_for_copying in
|
|
|
a30de4 |
- let backing_qemu_uri =
|
|
|
a30de4 |
- VCenter.map_source_to_uri readahead dcPath password
|
|
|
a30de4 |
- parsed_uri scheme server orig_path in
|
|
|
a30de4 |
+ let { VCenter.qemu_uri = backing_qemu_uri } =
|
|
|
a30de4 |
+ VCenter.map_source ?readahead ?password
|
|
|
a30de4 |
+ dcPath parsed_uri scheme server orig_path in
|
|
|
a30de4 |
|
|
|
a30de4 |
(* Rebase the qcow2 overlay to adjust the readahead parameter. *)
|
|
|
a30de4 |
let cmd = [ "qemu-img"; "rebase"; "-u"; "-b"; backing_qemu_uri;
|
|
|
a30de4 |
diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml
|
|
|
a30de4 |
index 2f7e32ad6..341a40b25 100644
|
|
|
a30de4 |
--- a/v2v/vCenter.ml
|
|
|
a30de4 |
+++ b/v2v/vCenter.ml
|
|
|
a30de4 |
@@ -38,167 +38,168 @@ let uri_quote str =
|
|
|
a30de4 |
done;
|
|
|
a30de4 |
String.concat "" (List.rev !xs)
|
|
|
a30de4 |
|
|
|
a30de4 |
-(* Memoized session cookie. *)
|
|
|
a30de4 |
-let session_cookie = ref ""
|
|
|
a30de4 |
-
|
|
|
a30de4 |
-let get_session_cookie password scheme uri sslverify url =
|
|
|
a30de4 |
- if !session_cookie <> "" then
|
|
|
a30de4 |
- Some !session_cookie
|
|
|
a30de4 |
- else (
|
|
|
a30de4 |
- let curl_args = ref [
|
|
|
a30de4 |
- "head", None;
|
|
|
a30de4 |
- "silent", None;
|
|
|
a30de4 |
- "url", Some url;
|
|
|
a30de4 |
- ] in
|
|
|
a30de4 |
- (match uri.uri_user, password with
|
|
|
a30de4 |
- | None, None -> ()
|
|
|
a30de4 |
- | None, Some _ ->
|
|
|
a30de4 |
- warning (f_"--password-file parameter ignored because 'user@' was not given in the URL")
|
|
|
a30de4 |
- | Some user, None ->
|
|
|
a30de4 |
- push_back curl_args ("user", Some user)
|
|
|
a30de4 |
- | Some user, Some password ->
|
|
|
a30de4 |
- push_back curl_args ("user", Some (user ^ ":" ^ password))
|
|
|
a30de4 |
- );
|
|
|
a30de4 |
- if not sslverify then push_back curl_args ("insecure", None);
|
|
|
a30de4 |
-
|
|
|
a30de4 |
- let curl_h = Curl.create !curl_args in
|
|
|
a30de4 |
- let lines = Curl.run curl_h in
|
|
|
a30de4 |
-
|
|
|
a30de4 |
- let dump_response chan =
|
|
|
a30de4 |
- Curl.print chan curl_h;
|
|
|
a30de4 |
-
|
|
|
a30de4 |
- (* Dump out the output of the command. *)
|
|
|
a30de4 |
- List.iter (fun x -> fprintf chan "%s\n" x) lines;
|
|
|
a30de4 |
- flush chan
|
|
|
a30de4 |
- in
|
|
|
a30de4 |
-
|
|
|
a30de4 |
- if verbose () then dump_response stderr;
|
|
|
a30de4 |
-
|
|
|
a30de4 |
- (* Look for the last HTTP/x.y NNN status code in the output. *)
|
|
|
a30de4 |
- let status = ref "" in
|
|
|
a30de4 |
- List.iter (
|
|
|
a30de4 |
- fun line ->
|
|
|
a30de4 |
- let len = String.length line in
|
|
|
a30de4 |
- if len >= 12 && String.sub line 0 5 = "HTTP/" then
|
|
|
a30de4 |
- status := String.sub line 9 3
|
|
|
a30de4 |
- ) lines;
|
|
|
a30de4 |
- let status = !status in
|
|
|
a30de4 |
- if status = "" then (
|
|
|
a30de4 |
- dump_response stderr;
|
|
|
a30de4 |
- error (f_"vcenter: no status code in output of 'curl' command. Is 'curl' installed?")
|
|
|
a30de4 |
- );
|
|
|
a30de4 |
-
|
|
|
a30de4 |
- if status = "401" then (
|
|
|
a30de4 |
- dump_response stderr;
|
|
|
a30de4 |
- if uri.uri_user <> None then
|
|
|
a30de4 |
- error (f_"vcenter: incorrect username or password")
|
|
|
a30de4 |
- else
|
|
|
a30de4 |
- error (f_"vcenter: incorrect username or password. You might need to specify the username in the URI like this: %s://USERNAME@[etc]")
|
|
|
a30de4 |
- scheme
|
|
|
a30de4 |
- );
|
|
|
a30de4 |
-
|
|
|
a30de4 |
- if status = "404" then (
|
|
|
a30de4 |
- dump_response stderr;
|
|
|
a30de4 |
- error (f_"vcenter: URL not found: %s") url
|
|
|
a30de4 |
- );
|
|
|
a30de4 |
-
|
|
|
a30de4 |
- if status <> "200" then (
|
|
|
a30de4 |
- dump_response stderr;
|
|
|
a30de4 |
- error (f_"vcenter: invalid response from server")
|
|
|
a30de4 |
- );
|
|
|
a30de4 |
-
|
|
|
a30de4 |
- (* Get the cookie. *)
|
|
|
a30de4 |
- List.iter (
|
|
|
a30de4 |
- fun line ->
|
|
|
a30de4 |
- let len = String.length line in
|
|
|
a30de4 |
- if len >= 12 && String.sub line 0 12 = "Set-Cookie: " then (
|
|
|
a30de4 |
- let line = String.sub line 12 (len-12) in
|
|
|
a30de4 |
- let cookie, _ = String.split ";" line in
|
|
|
a30de4 |
- session_cookie := cookie
|
|
|
a30de4 |
- )
|
|
|
a30de4 |
- ) lines;
|
|
|
a30de4 |
- if !session_cookie = "" then (
|
|
|
a30de4 |
- dump_response stderr;
|
|
|
a30de4 |
- 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");
|
|
|
a30de4 |
- None
|
|
|
a30de4 |
- )
|
|
|
a30de4 |
- else
|
|
|
a30de4 |
- Some !session_cookie
|
|
|
a30de4 |
- )
|
|
|
a30de4 |
+type remote_resource = {
|
|
|
a30de4 |
+ https_url : string;
|
|
|
a30de4 |
+ qemu_uri : string;
|
|
|
a30de4 |
+ session_cookie : string option;
|
|
|
a30de4 |
+ sslverify : bool;
|
|
|
a30de4 |
+}
|
|
|
a30de4 |
|
|
|
a30de4 |
let source_re = Str.regexp "^\\[\\(.*\\)\\] \\(.*\\)\\.vmdk$"
|
|
|
a30de4 |
|
|
|
a30de4 |
-let map_source_to_https dcPath uri server path =
|
|
|
a30de4 |
- if not (Str.string_match source_re path 0) then
|
|
|
a30de4 |
- (path, true)
|
|
|
a30de4 |
- else (
|
|
|
a30de4 |
- let datastore = Str.matched_group 1 path
|
|
|
a30de4 |
- and path = Str.matched_group 2 path in
|
|
|
a30de4 |
-
|
|
|
a30de4 |
- let port =
|
|
|
a30de4 |
- match uri.uri_port with
|
|
|
a30de4 |
- | 443 -> ""
|
|
|
a30de4 |
- | n when n >= 1 -> ":" ^ string_of_int n
|
|
|
a30de4 |
- | _ -> "" in
|
|
|
a30de4 |
-
|
|
|
a30de4 |
- (* XXX Old virt-v2v could also handle snapshots, ie:
|
|
|
a30de4 |
- * "[datastore1] Fedora 20/Fedora 20-NNNNNN.vmdk"
|
|
|
a30de4 |
- * XXX Need to handle templates. The file is called "-delta.vmdk" in
|
|
|
a30de4 |
- * place of "-flat.vmdk".
|
|
|
a30de4 |
- *)
|
|
|
a30de4 |
- let url =
|
|
|
a30de4 |
- sprintf
|
|
|
a30de4 |
- "https://%s%s/folder/%s-flat.vmdk?dcPath=%s&dsName=%s"
|
|
|
a30de4 |
- server port
|
|
|
a30de4 |
- (uri_quote path) (uri_quote dcPath) (uri_quote datastore) in
|
|
|
a30de4 |
-
|
|
|
a30de4 |
- (* If no_verify=1 was passed in the libvirt URI, then we have to
|
|
|
a30de4 |
- * turn off certificate verification here too.
|
|
|
a30de4 |
- *)
|
|
|
a30de4 |
- let sslverify =
|
|
|
a30de4 |
- match uri.uri_query_raw with
|
|
|
a30de4 |
- | None -> true
|
|
|
a30de4 |
- | Some query ->
|
|
|
a30de4 |
- (* XXX only works if the query string is not URI-quoted *)
|
|
|
a30de4 |
- String.find query "no_verify=1" = -1 in
|
|
|
a30de4 |
-
|
|
|
a30de4 |
- (url, sslverify)
|
|
|
a30de4 |
- )
|
|
|
a30de4 |
-
|
|
|
a30de4 |
-let map_source_to_uri readahead dcPath password uri scheme server path =
|
|
|
a30de4 |
- let url, sslverify = map_source_to_https dcPath uri server path in
|
|
|
a30de4 |
-
|
|
|
a30de4 |
- (* Now we have to query the server to get the session cookie. *)
|
|
|
a30de4 |
- let session_cookie = get_session_cookie password scheme uri sslverify url in
|
|
|
a30de4 |
-
|
|
|
a30de4 |
- (* Construct the JSON parameters. *)
|
|
|
a30de4 |
- let json_params = [
|
|
|
a30de4 |
- "file.driver", JSON.String "https";
|
|
|
a30de4 |
- "file.url", JSON.String url;
|
|
|
a30de4 |
- (* https://bugzilla.redhat.com/show_bug.cgi?id=1146007#c10 *)
|
|
|
a30de4 |
- "file.timeout", JSON.Int 2000;
|
|
|
a30de4 |
- ] in
|
|
|
a30de4 |
-
|
|
|
a30de4 |
- let json_params =
|
|
|
a30de4 |
- match readahead with
|
|
|
a30de4 |
- | None -> json_params
|
|
|
a30de4 |
- | Some readahead ->
|
|
|
a30de4 |
- ("file.readahead", JSON.Int readahead) :: json_params in
|
|
|
a30de4 |
-
|
|
|
a30de4 |
- let json_params =
|
|
|
a30de4 |
- if sslverify then json_params
|
|
|
a30de4 |
- else ("file.sslverify", JSON.String "off") :: json_params in
|
|
|
a30de4 |
-
|
|
|
a30de4 |
- let json_params =
|
|
|
a30de4 |
- match session_cookie with
|
|
|
a30de4 |
- | None -> json_params
|
|
|
a30de4 |
- | Some cookie -> ("file.cookie", JSON.String cookie) :: json_params in
|
|
|
a30de4 |
-
|
|
|
a30de4 |
- debug "vcenter: json parameters: %s" (JSON.string_of_doc json_params);
|
|
|
a30de4 |
-
|
|
|
a30de4 |
- (* Turn the JSON parameters into a 'json:' protocol string.
|
|
|
a30de4 |
- * Note this requires qemu-img >= 2.1.0.
|
|
|
a30de4 |
+let rec map_source ?readahead ?password dcPath uri scheme server path =
|
|
|
a30de4 |
+ (* If no_verify=1 was passed in the libvirt URI, then we have to
|
|
|
a30de4 |
+ * turn off certificate verification here too.
|
|
|
a30de4 |
*)
|
|
|
a30de4 |
- let qemu_uri = "json: " ^ JSON.string_of_doc json_params in
|
|
|
a30de4 |
+ let sslverify =
|
|
|
a30de4 |
+ match uri.uri_query_raw with
|
|
|
a30de4 |
+ | None -> true
|
|
|
a30de4 |
+ | Some query ->
|
|
|
a30de4 |
+ (* XXX only works if the query string is not URI-quoted *)
|
|
|
a30de4 |
+ String.find query "no_verify=1" = -1 in
|
|
|
a30de4 |
|
|
|
a30de4 |
- qemu_uri
|
|
|
a30de4 |
+ let https_url =
|
|
|
a30de4 |
+ if not (Str.string_match source_re path 0) then
|
|
|
a30de4 |
+ path
|
|
|
a30de4 |
+ else (
|
|
|
a30de4 |
+ let datastore = Str.matched_group 1 path
|
|
|
a30de4 |
+ and path = Str.matched_group 2 path in
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ let port =
|
|
|
a30de4 |
+ match uri.uri_port with
|
|
|
a30de4 |
+ | 443 -> ""
|
|
|
a30de4 |
+ | n when n >= 1 -> ":" ^ string_of_int n
|
|
|
a30de4 |
+ | _ -> "" in
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ (* XXX Old virt-v2v could also handle snapshots, ie:
|
|
|
a30de4 |
+ * "[datastore1] Fedora 20/Fedora 20-NNNNNN.vmdk"
|
|
|
a30de4 |
+ * XXX Need to handle templates. The file is called "-delta.vmdk" in
|
|
|
a30de4 |
+ * place of "-flat.vmdk".
|
|
|
a30de4 |
+ *)
|
|
|
a30de4 |
+ sprintf "https://%s%s/folder/%s-flat.vmdk?dcPath=%s&dsName=%s"
|
|
|
a30de4 |
+ server port
|
|
|
a30de4 |
+ (uri_quote path) (uri_quote dcPath) (uri_quote datastore)
|
|
|
a30de4 |
+ ) in
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ let session_cookie =
|
|
|
a30de4 |
+ get_session_cookie password scheme uri sslverify https_url in
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ let qemu_uri =
|
|
|
a30de4 |
+ (* Construct the JSON parameters for the qemu URI. *)
|
|
|
a30de4 |
+ let json_params = [
|
|
|
a30de4 |
+ "file.driver", JSON.String "https";
|
|
|
a30de4 |
+ "file.url", JSON.String https_url;
|
|
|
a30de4 |
+ (* https://bugzilla.redhat.com/show_bug.cgi?id=1146007#c10 *)
|
|
|
a30de4 |
+ "file.timeout", JSON.Int 2000;
|
|
|
a30de4 |
+ ] in
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ let json_params =
|
|
|
a30de4 |
+ match readahead with
|
|
|
a30de4 |
+ | None -> json_params
|
|
|
a30de4 |
+ | Some readahead ->
|
|
|
a30de4 |
+ ("file.readahead", JSON.Int readahead) :: json_params in
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ let json_params =
|
|
|
a30de4 |
+ if sslverify then json_params
|
|
|
a30de4 |
+ else ("file.sslverify", JSON.String "off") :: json_params in
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ let json_params =
|
|
|
a30de4 |
+ match session_cookie with
|
|
|
a30de4 |
+ | None -> json_params
|
|
|
a30de4 |
+ | Some cookie -> ("file.cookie", JSON.String cookie) :: json_params in
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ debug "vcenter: json parameters: %s" (JSON.string_of_doc json_params);
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ (* Turn the JSON parameters into a 'json:' protocol string.
|
|
|
a30de4 |
+ * Note this requires qemu-img >= 2.1.0.
|
|
|
a30de4 |
+ *)
|
|
|
a30de4 |
+ let qemu_uri = "json: " ^ JSON.string_of_doc json_params in
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ qemu_uri in
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ (* Return the struct. *)
|
|
|
a30de4 |
+ { https_url = https_url;
|
|
|
a30de4 |
+ qemu_uri = qemu_uri;
|
|
|
a30de4 |
+ session_cookie = session_cookie;
|
|
|
a30de4 |
+ sslverify = sslverify }
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+and get_session_cookie password scheme uri sslverify https_url =
|
|
|
a30de4 |
+ let curl_args = ref [
|
|
|
a30de4 |
+ "head", None;
|
|
|
a30de4 |
+ "silent", None;
|
|
|
a30de4 |
+ "url", Some https_url;
|
|
|
a30de4 |
+ ] in
|
|
|
a30de4 |
+ (match uri.uri_user, password with
|
|
|
a30de4 |
+ | None, None -> ()
|
|
|
a30de4 |
+ | None, Some _ ->
|
|
|
a30de4 |
+ warning (f_"--password-file parameter ignored because 'user@' was not given in the URL")
|
|
|
a30de4 |
+ | Some user, None ->
|
|
|
a30de4 |
+ push_back curl_args ("user", Some user)
|
|
|
a30de4 |
+ | Some user, Some password ->
|
|
|
a30de4 |
+ push_back curl_args ("user", Some (user ^ ":" ^ password))
|
|
|
a30de4 |
+ );
|
|
|
a30de4 |
+ if not sslverify then push_back curl_args ("insecure", None);
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ let curl_h = Curl.create !curl_args in
|
|
|
a30de4 |
+ let lines = Curl.run curl_h in
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ let dump_response chan =
|
|
|
a30de4 |
+ Curl.print chan curl_h;
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ (* Dump out the output of the command. *)
|
|
|
a30de4 |
+ List.iter (fun x -> fprintf chan "%s\n" x) lines;
|
|
|
a30de4 |
+ flush chan
|
|
|
a30de4 |
+ in
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ if verbose () then dump_response stderr;
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ (* Look for the last HTTP/x.y NNN status code in the output. *)
|
|
|
a30de4 |
+ let status = ref "" in
|
|
|
a30de4 |
+ List.iter (
|
|
|
a30de4 |
+ fun line ->
|
|
|
a30de4 |
+ let len = String.length line in
|
|
|
a30de4 |
+ if len >= 12 && String.sub line 0 5 = "HTTP/" then
|
|
|
a30de4 |
+ status := String.sub line 9 3
|
|
|
a30de4 |
+ ) lines;
|
|
|
a30de4 |
+ let status = !status in
|
|
|
a30de4 |
+ if status = "" then (
|
|
|
a30de4 |
+ dump_response stderr;
|
|
|
a30de4 |
+ error (f_"vcenter: no status code in output of ‘curl’ command. Is ‘curl’ installed?")
|
|
|
a30de4 |
+ );
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ if status = "401" then (
|
|
|
a30de4 |
+ dump_response stderr;
|
|
|
a30de4 |
+ if uri.uri_user <> None then
|
|
|
a30de4 |
+ error (f_"vcenter: incorrect username or password")
|
|
|
a30de4 |
+ else
|
|
|
a30de4 |
+ error (f_"vcenter: incorrect username or password. You might need to specify the username in the URI like this: %s://USERNAME@[etc]")
|
|
|
a30de4 |
+ scheme
|
|
|
a30de4 |
+ );
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ if status = "404" then (
|
|
|
a30de4 |
+ dump_response stderr;
|
|
|
a30de4 |
+ error (f_"vcenter: URL not found: %s") https_url
|
|
|
a30de4 |
+ );
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ if status <> "200" then (
|
|
|
a30de4 |
+ dump_response stderr;
|
|
|
a30de4 |
+ error (f_"vcenter: invalid response from server")
|
|
|
a30de4 |
+ );
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ (* Get the cookie. *)
|
|
|
a30de4 |
+ let rec loop = function
|
|
|
a30de4 |
+ | [] ->
|
|
|
a30de4 |
+ dump_response stderr;
|
|
|
a30de4 |
+ 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");
|
|
|
a30de4 |
+ None
|
|
|
a30de4 |
+ | line :: lines ->
|
|
|
a30de4 |
+ let len = String.length line in
|
|
|
a30de4 |
+ if len >= 12 && String.sub line 0 12 = "Set-Cookie: " then (
|
|
|
a30de4 |
+ let line = String.sub line 12 (len-12) in
|
|
|
a30de4 |
+ let cookie, _ = String.split ";" line in
|
|
|
a30de4 |
+ Some cookie
|
|
|
a30de4 |
+ )
|
|
|
a30de4 |
+ else
|
|
|
a30de4 |
+ loop lines
|
|
|
a30de4 |
+ in
|
|
|
a30de4 |
+ loop lines
|
|
|
a30de4 |
diff --git a/v2v/vCenter.mli b/v2v/vCenter.mli
|
|
|
a30de4 |
index 55d70b486..03749966f 100644
|
|
|
a30de4 |
--- a/v2v/vCenter.mli
|
|
|
a30de4 |
+++ b/v2v/vCenter.mli
|
|
|
a30de4 |
@@ -18,35 +18,51 @@
|
|
|
a30de4 |
|
|
|
a30de4 |
(** Functions for dealing with VMware vCenter. *)
|
|
|
a30de4 |
|
|
|
a30de4 |
-val get_session_cookie : string option -> string -> Xml.uri -> bool -> string -> string option
|
|
|
a30de4 |
-(** [get_session_cookie password scheme uri sslverify url]
|
|
|
a30de4 |
- contacts the vCenter server, logs in, and gets the session cookie,
|
|
|
a30de4 |
- which can later be passed back to the server instead of having to
|
|
|
a30de4 |
- log in each time (this is also more efficient since it avoids
|
|
|
a30de4 |
- vCenter running out of authentication sessions).
|
|
|
a30de4 |
+type remote_resource = {
|
|
|
a30de4 |
+ https_url : string;
|
|
|
a30de4 |
+ (** The full URL of the remote disk as an https link on the vCenter
|
|
|
a30de4 |
+ server. It will have the general form
|
|
|
a30de4 |
+ [https://vcenter/folder/.../guest-flat.vmdk?dcPath=...&...] *)
|
|
|
a30de4 |
|
|
|
a30de4 |
- Returns [None] if the session cookie could not be read (but
|
|
|
a30de4 |
- authentication was successful). You can proceed without the
|
|
|
a30de4 |
- session cookie in this case, but there is an unavoidable
|
|
|
a30de4 |
- danger of running out of authentication sessions. If the
|
|
|
a30de4 |
- session cookie could not be read, this function prints a
|
|
|
a30de4 |
- warning.
|
|
|
a30de4 |
+ qemu_uri : string;
|
|
|
a30de4 |
+ (** The remote disk as a QEMU URI. This opaque blob (usually a
|
|
|
a30de4 |
+ [json:] URL) can be passed to [qemu] or [qemu-img] as a backing
|
|
|
a30de4 |
+ file. *)
|
|
|
a30de4 |
|
|
|
a30de4 |
- The session cookie is memoized so you can call this function as
|
|
|
a30de4 |
- often as you want, and only a single log in is made. *)
|
|
|
a30de4 |
+ session_cookie : string option;
|
|
|
a30de4 |
+ (** When creating the URLs above, the module contacts the vCenter
|
|
|
a30de4 |
+ server, logs in, and gets the session cookie, which can later
|
|
|
a30de4 |
+ be passed back to the server instead of having to log in each
|
|
|
a30de4 |
+ time (this is also more efficient since it avoids vCenter
|
|
|
a30de4 |
+ running out of authentication sessions).
|
|
|
a30de4 |
|
|
|
a30de4 |
-val map_source_to_uri : int option -> string -> string option -> Xml.uri -> string -> string -> string -> string
|
|
|
a30de4 |
-(** [map_source_to_uri readahead dcPath password uri scheme server path]
|
|
|
a30de4 |
- maps the [<source path=...>] string to a qemu URI.
|
|
|
a30de4 |
+ This can be [None] if the session cookie could not be read (but
|
|
|
a30de4 |
+ authentication was successful). You can proceed without the
|
|
|
a30de4 |
+ session cookie in this case, but there is an unavoidable
|
|
|
a30de4 |
+ danger of running out of authentication sessions. If the
|
|
|
a30de4 |
+ session cookie could not be read, this function prints a
|
|
|
a30de4 |
+ warning.
|
|
|
a30de4 |
|
|
|
a30de4 |
- The [path] will be something like:
|
|
|
a30de4 |
+ If authentication {i failed} then the {!map_source} function
|
|
|
a30de4 |
+ would exit with an error, so [None] does not indicate auth
|
|
|
a30de4 |
+ failure. *)
|
|
|
a30de4 |
|
|
|
a30de4 |
+ sslverify : bool;
|
|
|
a30de4 |
+ (** This is true except when the libvirt URI had [?no_verify=1] in
|
|
|
a30de4 |
+ the parameters. *)
|
|
|
a30de4 |
+}
|
|
|
a30de4 |
+(** The "remote resource" is the structure returned by the {!map_source}
|
|
|
a30de4 |
+ function. *)
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+val map_source : ?readahead:int -> ?password:string -> string -> Xml.uri -> string -> string -> string -> remote_resource
|
|
|
a30de4 |
+(** [map_source ?readahead ?password dcPath uri scheme server path]
|
|
|
a30de4 |
+ maps the [<source path=...>] string to a {!remote_resource}
|
|
|
a30de4 |
+ structure containing both an [https://] URL and a qemu URI,
|
|
|
a30de4 |
+ both pointing the guest disk.
|
|
|
a30de4 |
+
|
|
|
a30de4 |
+ The input [path] comes from libvirt and will be something like:
|
|
|
a30de4 |
["[datastore1] Fedora 20/Fedora 20.vmdk"]
|
|
|
a30de4 |
+ (including those literal spaces in the string).
|
|
|
a30de4 |
|
|
|
a30de4 |
- including those literal spaces in the string. *)
|
|
|
a30de4 |
-
|
|
|
a30de4 |
-val map_source_to_https : string -> Xml.uri -> string -> string -> string * bool
|
|
|
a30de4 |
-(** [map_source_to_https dcPath uri server path] is the same as
|
|
|
a30de4 |
- {!map_source_to_uri} but it produces a regular [https://...] URL.
|
|
|
a30de4 |
- The returned boolean is whether TLS certificate verification
|
|
|
a30de4 |
- should be done. *)
|
|
|
a30de4 |
+ This checks that the disk exists and that authentication is
|
|
|
a30de4 |
+ correct, otherwise it will fail. *)
|
|
|
a30de4 |
--
|
|
|
a30de4 |
2.14.3
|
|
|
a30de4 |
|