1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
|
(* virt-v2v
* Copyright (C) 2009-2020 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 Std_utils
open Tools_utils
open Common_gettext.Gettext
open Xml
open Utils
let source_re = PCRE.compile "^\\[(.*)\\] (.*)\\.vmdk$"
let snapshot_re = PCRE.compile "^(.*)-\\d{6}(\\.vmdk)$"
let rec start_nbdkit_for_path ?bandwidth ?cor ?password_file
dcPath uri server path
socket =
(* If no_verify=1 was passed in the libvirt URI, then we have to
* turn off certificate verification here too.
*)
let sslverify =
match uri.uri_query_raw with
| None -> true
| Some query ->
(* XXX only works if the query string is not URI-quoted *)
String.find query "no_verify=1" = -1 in
(* Check the URL exists and authentication info is correct. *)
let https_url =
let https_url = get_https_url dcPath uri server path in
let status, dump_response =
fetch_headers_from_url password_file uri sslverify https_url in
(* If a disk is actually a snapshot image it will have '-00000n'
* appended to its name, e.g.:
* [yellow:storage1] RHEL4-X/RHEL4-X-000003.vmdk
* The flat storage is still called RHEL4-X-flat, however. If we got
* a 404 and the vmdk name looks like it might be a snapshot, try
* again without the snapshot suffix.
*)
let https_url, status, dump_response =
if status = "404" && PCRE.matches snapshot_re path then (
let path = PCRE.sub 1 ^ PCRE.sub 2 in
let https_url = get_https_url dcPath uri server path in
let status, dump_response =
fetch_headers_from_url password_file uri sslverify https_url in
https_url, status, dump_response
)
else (https_url, status, dump_response) in
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: \
[vpx|esx|..]://USERNAME@[etc]")
);
if status = "404" then (
dump_response stderr;
error (f_"vcenter: URL not found: %s") https_url
);
if status <> "200" then (
dump_response stderr;
error (f_"vcenter: invalid response from server: %s") status
);
https_url in
(* Write a cookie script to retrieve the session cookie.
* See nbdkit-curl-plugin(1) "Example: VMware ESXi cookies"
*)
let cookie_script, chan =
Filename.open_temp_file ~perms:0o700 "v2vcs" ".sh" in
On_exit.unlink cookie_script;
let fpf fs = fprintf chan fs in
fpf "#!/bin/sh -\n";
fpf "\n";
fpf "curl --head -s";
if not sslverify then fpf " --insecure";
(match uri.uri_user, password_file with
| None, None -> ()
| Some user, None -> fpf " -u %s" (quote user)
| None, Some password_file ->
fpf " -u \"$LOGNAME\":\"$(cat %s)\"" (quote password_file)
| Some user, Some password_file ->
fpf " -u %s:\"$(cat %s)\"" (quote user) (quote password_file)
);
fpf " %s" (quote https_url);
fpf " |\n";
fpf "\tsed -ne %s\n" (quote "{ s/^Set-Cookie: \\([^;]*\\);.*/\\1/ip }");
close_out chan;
(* VMware authentication expires after 30 minutes so we must renew
* after < 30 minutes.
*)
let cookie_script_renew = 25*60 in
let nbdkit =
Nbdkit_curl.create_curl ?bandwidth ?cor
~cookie_script ~cookie_script_renew
~sslverify https_url in
let _, pid = Nbdkit.run_unix socket nbdkit in
pid
and get_https_url dcPath uri server path =
if not (PCRE.matches source_re path) then
path
else (
let datastore = PCRE.sub 1 and path = PCRE.sub 2 in
let port =
match uri.uri_port with
| 443 -> ""
| n when n >= 1 -> ":" ^ string_of_int n
| _ -> "" in
(* XXX Need to handle templates. The file is called "-delta.vmdk" in
* place of "-flat.vmdk".
*)
sprintf "https://%s%s/folder/%s-flat.vmdk?dcPath=%s&dsName=%s"
server port
(uri_quote path) (uri_quote dcPath) (uri_quote datastore)
)
(* Fetch the status from a URL. *)
and fetch_headers_from_url password_file uri sslverify https_url =
let curl_args = ref [
"head", None;
"silent", None;
] in
(match uri.uri_user, password_file with
| None, None -> ()
| None, Some _ ->
warning (f_"-ip PASSWORD_FILE parameter ignored because \
'user@' was not given in the URL")
| Some user, None ->
List.push_back curl_args ("user", Some user)
| Some user, Some password_file ->
let password = read_first_line_from_file password_file in
List.push_back curl_args ("user", Some (user ^ ":" ^ password))
);
if not sslverify then List.push_back curl_args ("insecure", None);
let curl_h = Curl.create !curl_args https_url in
let lines = Curl.run curl_h in
let dump_response chan =
Curl.print chan curl_h;
(* 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 stderr;
let statuses, headers =
List.partition (
fun line ->
let len = String.length line in
len >= 12 && String.sub line 0 5 = "HTTP/"
) lines in
(* Look for the last HTTP/x.y NNN status code in the output. *)
let status =
match statuses with
| [] ->
dump_response stderr;
error (f_"vcenter: no status code in output of ‘curl’ command.")
| ss ->
let s = List.hd (List.rev ss) in
String.sub s (String.index s ' ' + 1) 3 in
status, dump_response
|