File: vCenter.ml

package info (click to toggle)
virt-v2v 2.6.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 27,132 kB
  • sloc: ml: 19,674; sh: 7,631; ansic: 6,897; makefile: 3,261; python: 1,114; perl: 852; xml: 114
file content (194 lines) | stat: -rw-r--r-- 6,340 bytes parent folder | download | duplicates (2)
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