From e95e92ff06a0ef9edb3d3107e8bbc9acc8748f18 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Mon, 20 Oct 2014 19:35:23 +0100 Subject: [PATCH] v2v: Refactor Xen and vCenter code. This refactors the code into more logical units, based on the previous commits. So Xen + the input_libvirt Xen code is grouped and moved into a new module called Input_libvirt_xen_ssh. Similarly VCenter + input_libvirt vCenter code is moved to Input_libvirt_vcenter_https. There is no change here, purely code motion. (cherry picked from commit a468fde01687914de501f0a95cd5a40986daec29) --- po/POTFILES-ml | 5 +- v2v/Makefile.am | 10 +- v2v/input_libvirt.ml | 145 +------------------ v2v/input_libvirt_other.ml | 76 ++++++++++ v2v/input_libvirt_other.mli | 30 ++++ v2v/input_libvirt_vcenter_https.ml | 270 ++++++++++++++++++++++++++++++++++++ v2v/input_libvirt_vcenter_https.mli | 21 +++ v2v/input_libvirt_xen_ssh.ml | 103 ++++++++++++++ v2v/input_libvirt_xen_ssh.mli | 21 +++ v2v/vCenter.ml | 211 ---------------------------- v2v/vCenter.mli | 23 --- v2v/xen.ml | 71 ---------- v2v/xen.mli | 22 --- 13 files changed, 537 insertions(+), 471 deletions(-) create mode 100644 v2v/input_libvirt_other.ml create mode 100644 v2v/input_libvirt_other.mli create mode 100644 v2v/input_libvirt_vcenter_https.ml create mode 100644 v2v/input_libvirt_vcenter_https.mli create mode 100644 v2v/input_libvirt_xen_ssh.ml create mode 100644 v2v/input_libvirt_xen_ssh.mli delete mode 100644 v2v/vCenter.ml delete mode 100644 v2v/vCenter.mli delete mode 100644 v2v/xen.ml delete mode 100644 v2v/xen.mli diff --git a/po/POTFILES-ml b/po/POTFILES-ml index d919b6f..7403497 100644 --- a/po/POTFILES-ml +++ b/po/POTFILES-ml @@ -91,6 +91,9 @@ v2v/convert_windows.ml v2v/domainxml.ml v2v/input_disk.ml v2v/input_libvirt.ml +v2v/input_libvirt_other.ml +v2v/input_libvirt_vcenter_https.ml +v2v/input_libvirt_xen_ssh.ml v2v/input_libvirtxml.ml v2v/input_ova.ml v2v/kvmuid.ml @@ -107,6 +110,4 @@ v2v/stringMap.ml v2v/types.ml v2v/utils.ml v2v/v2v.ml -v2v/vCenter.ml -v2v/xen.ml v2v/xml.ml diff --git a/v2v/Makefile.am b/v2v/Makefile.am index c311623..921fb93 100644 --- a/v2v/Makefile.am +++ b/v2v/Makefile.am @@ -42,6 +42,9 @@ SOURCES_MLI = \ domainxml.mli \ input_disk.mli \ input_libvirt.mli \ + input_libvirt_other.mli \ + input_libvirt_vcenter_https.mli \ + input_libvirt_xen_ssh.mli \ input_libvirtxml.mli \ input_ova.mli \ kvmuid.mli \ @@ -57,8 +60,6 @@ SOURCES_MLI = \ OVF.mli \ stringMap.mli \ types.mli \ - vCenter.mli \ - xen.mli \ xml.mli SOURCES_ML = \ @@ -69,13 +70,14 @@ SOURCES_ML = \ domainxml.ml \ DOM.ml \ kvmuid.ml \ - vCenter.ml \ - xen.ml \ OVF.ml \ linux.ml \ modules_list.ml \ input_disk.ml \ input_libvirtxml.ml \ + input_libvirt_other.ml \ + input_libvirt_vcenter_https.ml \ + input_libvirt_xen_ssh.ml \ input_libvirt.ml \ input_ova.ml \ convert_linux.ml \ diff --git a/v2v/input_libvirt.ml b/v2v/input_libvirt.ml index 93d96b7..60e88ac 100644 --- a/v2v/input_libvirt.ml +++ b/v2v/input_libvirt.ml @@ -16,6 +16,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *) +(** [-i libvirt] source. *) + open Printf open Common_gettext.Gettext @@ -24,144 +26,11 @@ open Common_utils open Types open Utils -(* Check the backend is not libvirt. Works around a libvirt bug - * (RHBZ#1134592). This can be removed once the libvirt bug is fixed. - *) -let error_if_libvirt_backend () = - let libguestfs_backend = (new Guestfs.guestfs ())#get_backend () in - if libguestfs_backend = "libvirt" then ( - error (f_"because of libvirt bug https://bugzilla.redhat.com/show_bug.cgi?id=1134592 you must set this environment variable:\n\nexport LIBGUESTFS_BACKEND=direct\n\nand then rerun the virt-v2v command.") - ) - -(* xen+ssh URLs use the SSH driver in CURL. Currently this requires - * ssh-agent authentication. Give a clear error if this hasn't been - * set up (RHBZ#1139973). - *) -let error_if_no_ssh_agent () = - try ignore (Sys.getenv "SSH_AUTH_SOCK") - with Not_found -> - error (f_"ssh-agent authentication has not been set up ($SSH_AUTH_SOCK is not set). Please read \"INPUT FROM RHEL 5 XEN\" in the virt-v2v(1) man page.") - -(* Superclass. *) -class virtual input_libvirt verbose libvirt_uri guest = -object - inherit input verbose - - method as_options = - sprintf "-i libvirt%s %s" - (match libvirt_uri with - | None -> "" - | Some uri -> " -ic " ^ uri) - guest -end - -(* Subclass specialized for handling anything that's *not* VMware vCenter - * or Xen. - *) -class input_libvirt_other verbose libvirt_uri guest = -object - inherit input_libvirt verbose libvirt_uri guest - - method source () = - if verbose then printf "input_libvirt_other: source()\n%!"; - - (* Get the libvirt XML. This also checks (as a side-effect) - * that the domain is not running. (RHBZ#1138586) - *) - let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in - - Input_libvirtxml.parse_libvirt_xml ~verbose xml -end - -(* Subclass specialized for handling VMware vCenter over https. *) -class input_libvirt_vcenter_https - verbose libvirt_uri parsed_uri scheme server guest = -object - inherit input_libvirt verbose libvirt_uri guest - - val mutable mapf = fun ?readahead uri format -> uri, format - val saved_uri = Hashtbl.create 13 - - method source () = - if verbose then printf "input_libvirt_vcenter_https: source()\n%!"; - - error_if_libvirt_backend (); - - (* Get the libvirt XML. This also checks (as a side-effect) - * that the domain is not running. (RHBZ#1138586) - *) - let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in - 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. - *) - mapf <- VCenter.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) - ) 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 } - ) 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 - with Not_found -> failwith "internal error in adjust_overlay_parameters" in - let backing_file, _ = - mapf ~readahead:(64 * 1024 * 1024) orig_uri orig_format 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 - if verbose then printf "%s\n%!" cmd; - if Sys.command cmd <> 0 then - warning ~prog (f_"qemu-img rebase failed, see earlier errors") -end - -(* 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%!"; - - error_if_libvirt_backend (); - error_if_no_ssh_agent (); - - (* Get the libvirt XML. This also checks (as a side-effect) - * that the domain is not running. (RHBZ#1138586) - *) - let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in - let { s_disks = disks } as source = - Input_libvirtxml.parse_libvirt_xml ~verbose xml in - - let mapf = Xen.map_path_to_uri verbose parsed_uri scheme server in - 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 } - ) disks in - - { source with s_disks = disks } -end - (* Choose the right subclass based on the URI. *) let input_libvirt verbose libvirt_uri guest = match libvirt_uri with | None -> - new input_libvirt_other verbose libvirt_uri guest + Input_libvirt_other.input_libvirt_other verbose libvirt_uri guest | Some orig_uri -> let { Xml.uri_server = server; uri_scheme = scheme } as parsed_uri = @@ -176,14 +45,14 @@ let input_libvirt verbose libvirt_uri guest = | Some _, None (* No scheme? *) | Some _, Some "" -> - new input_libvirt_other verbose libvirt_uri guest + Input_libvirt_other.input_libvirt_other verbose libvirt_uri guest | Some server, Some ("esx"|"gsx"|"vpx" as scheme) -> (* vCenter over https *) - new input_libvirt_vcenter_https + Input_libvirt_vcenter_https.input_libvirt_vcenter_https verbose libvirt_uri parsed_uri scheme server guest | Some server, Some ("xen+ssh" as scheme) -> (* Xen over SSH *) - new input_libvirt_xen_ssh + Input_libvirt_xen_ssh.input_libvirt_xen_ssh verbose libvirt_uri parsed_uri scheme server guest (* Old virt-v2v also supported qemu+ssh://. However I am @@ -194,6 +63,6 @@ let input_libvirt verbose libvirt_uri guest = | Some _, Some _ -> (* Unknown remote scheme. *) warning ~prog (f_"no support for remote libvirt connections to '-ic %s'. The conversion may fail when it tries to read the source disks.") orig_uri; - new input_libvirt_other verbose libvirt_uri guest + Input_libvirt_other.input_libvirt_other verbose libvirt_uri guest let () = Modules_list.register_input_module "libvirt" diff --git a/v2v/input_libvirt_other.ml b/v2v/input_libvirt_other.ml new file mode 100644 index 0000000..a771aa1 --- /dev/null +++ b/v2v/input_libvirt_other.ml @@ -0,0 +1,76 @@ +(* virt-v2v + * Copyright (C) 2009-2014 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_gettext.Gettext +open Common_utils + +open Types +open Utils + +(* Check the backend is not libvirt. Works around a libvirt bug + * (RHBZ#1134592). This can be removed once the libvirt bug is fixed. + *) +let error_if_libvirt_backend () = + let libguestfs_backend = (new Guestfs.guestfs ())#get_backend () in + if libguestfs_backend = "libvirt" then ( + error (f_"because of libvirt bug https://bugzilla.redhat.com/show_bug.cgi?id=1134592 you must set this environment variable:\n\nexport LIBGUESTFS_BACKEND=direct\n\nand then rerun the virt-v2v command.") + ) + +(* xen+ssh URLs use the SSH driver in CURL. Currently this requires + * ssh-agent authentication. Give a clear error if this hasn't been + * set up (RHBZ#1139973). + *) +let error_if_no_ssh_agent () = + try ignore (Sys.getenv "SSH_AUTH_SOCK") + with Not_found -> + error (f_"ssh-agent authentication has not been set up ($SSH_AUTH_SOCK is not set). Please read \"INPUT FROM RHEL 5 XEN\" in the virt-v2v(1) man page.") + +(* Superclass. *) +class virtual input_libvirt verbose libvirt_uri guest = +object + inherit input verbose + + method as_options = + sprintf "-i libvirt%s %s" + (match libvirt_uri with + | None -> "" + | Some uri -> " -ic " ^ uri) + guest +end + +(* Subclass specialized for handling anything that's *not* VMware vCenter + * or Xen. + *) +class input_libvirt_other verbose libvirt_uri guest = +object + inherit input_libvirt verbose libvirt_uri guest + + method source () = + if verbose then printf "input_libvirt_other: source()\n%!"; + + (* Get the libvirt XML. This also checks (as a side-effect) + * that the domain is not running. (RHBZ#1138586) + *) + let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in + + Input_libvirtxml.parse_libvirt_xml ~verbose xml +end + +let input_libvirt_other = new input_libvirt_other diff --git a/v2v/input_libvirt_other.mli b/v2v/input_libvirt_other.mli new file mode 100644 index 0000000..013d3bb --- /dev/null +++ b/v2v/input_libvirt_other.mli @@ -0,0 +1,30 @@ +(* virt-v2v + * Copyright (C) 2009-2014 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. + *) + +(** [-i libvirt] source. *) + +val error_if_libvirt_backend : unit -> unit +val error_if_no_ssh_agent : unit -> unit + +class virtual input_libvirt : bool -> string option -> string -> object + method as_options : string + method virtual source : unit -> Types.source + method adjust_overlay_parameters : Types.overlay -> unit +end + +val input_libvirt_other : bool -> string option -> string -> Types.input diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml new file mode 100644 index 0000000..7dde9be --- /dev/null +++ b/v2v/input_libvirt_vcenter_https.ml @@ -0,0 +1,270 @@ +(* virt-v2v + * Copyright (C) 2009-2014 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. + *) + +(** [-i libvirt] when the source is VMware vCenter *) + +open Common_gettext.Gettext +open Common_utils + +open Types +open Xml +open Utils +open Input_libvirt_other + +open Printf + +let esx_re = Str.regexp "^\\[\\(.*\\)\\] \\(.*\\)\\.vmdk$" + +let session_cookie = ref "" + +(* Map an ESX to a qemu URI using the cURL driver + * in qemu. The 'path' will be something like + * + * "[datastore1] Fedora 20/Fedora 20.vmdk" + * + * including those literal spaces in the string. + * + * XXX Old virt-v2v could also handle snapshots, ie: + * + * "[datastore1] Fedora 20/Fedora 20-NNNNNN.vmdk" + * + * 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 + else ( + let datastore = Str.matched_group 1 path + and path = Str.matched_group 2 path in + + (* Get the datacenter. *) + let datacenter = get_datacenter uri scheme in + + let port = + match uri.uri_port with + | 443 -> "" + | n when n >= 1 -> ":" ^ string_of_int n + | _ -> "" in + + let url = + sprintf + "https://%s%s/folder/%s-flat.vmdk?dcPath=%s&dsName=%s" + server port + (uri_quote path) (uri_quote datacenter) (uri_quote datastore) in + + (* 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 + + (* Now we have to query the server to get the session cookie. *) + let session_cookie = get_session_cookie verbose scheme uri sslverify url in + + (* Construct the JSON parameters. *) + let json_params = [ + "file.driver", JSON.String "https"; + "file.url", JSON.String url; + "file.timeout", JSON.Int 600; + ] in + + let json_params = + match readahead with + | None -> json_params + | Some readahead -> + ("file.readahead", JSON.Int readahead) :: json_params in + + let json_params = + if sslverify then json_params + else ("file.sslverify", JSON.String "off") :: json_params in + + let json_params = + match session_cookie with + | None -> json_params + | Some cookie -> ("file.cookie", JSON.String cookie) :: json_params in + + if verbose then + printf "esx: json parameters: %s\n" (JSON.string_of_doc json_params); + + (* Turn the JSON parameters into a 'json:' protocol string. + * Note this requires qemu-img >= 2.1.0. + *) + 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 + ) + +(* Subclass specialized for handling VMware vCenter over https. *) +class input_libvirt_vcenter_https + verbose libvirt_uri parsed_uri scheme server guest = +object + inherit input_libvirt verbose libvirt_uri guest + + val mutable mapf = fun ?readahead uri format -> uri, format + val saved_uri = Hashtbl.create 13 + + method source () = + if verbose then printf "input_libvirt_vcenter_https: source()\n%!"; + + error_if_libvirt_backend (); + + (* Get the libvirt XML. This also checks (as a side-effect) + * that the domain is not running. (RHBZ#1138586) + *) + let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in + 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. + *) + 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) + ) 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 } + ) 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 + with Not_found -> failwith "internal error in adjust_overlay_parameters" in + let backing_file, _ = + mapf ~readahead:(64 * 1024 * 1024) orig_uri orig_format 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 + if verbose then printf "%s\n%!" cmd; + if Sys.command cmd <> 0 then + warning ~prog (f_"qemu-img rebase failed, see earlier errors") +end + +let input_libvirt_vcenter_https = new input_libvirt_vcenter_https diff --git a/v2v/input_libvirt_vcenter_https.mli b/v2v/input_libvirt_vcenter_https.mli new file mode 100644 index 0000000..82dce53 --- /dev/null +++ b/v2v/input_libvirt_vcenter_https.mli @@ -0,0 +1,21 @@ +(* virt-v2v + * Copyright (C) 2009-2014 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. + *) + +(** [-i libvirt] when the source is VMware vCenter *) + +val input_libvirt_vcenter_https : bool -> string option -> Xml.uri -> string -> string -> string -> Types.input diff --git a/v2v/input_libvirt_xen_ssh.ml b/v2v/input_libvirt_xen_ssh.ml new file mode 100644 index 0000000..081317d --- /dev/null +++ b/v2v/input_libvirt_xen_ssh.ml @@ -0,0 +1,103 @@ +(* virt-v2v + * Copyright (C) 2009-2014 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. + *) + +(** [-i libvirt] when the source is Xen *) + +open Common_gettext.Gettext +open Common_utils + +open Types +open Xml +open Utils +open Input_libvirt_other + +open Printf + +(* Map a Xen 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%!"; + + error_if_libvirt_backend (); + error_if_no_ssh_agent (); + + (* Get the libvirt XML. This also checks (as a side-effect) + * that the domain is not running. (RHBZ#1138586) + *) + let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in + 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 + 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 } + ) disks in + + { source with s_disks = disks } +end + +let input_libvirt_xen_ssh = new input_libvirt_xen_ssh diff --git a/v2v/input_libvirt_xen_ssh.mli b/v2v/input_libvirt_xen_ssh.mli new file mode 100644 index 0000000..85473ed --- /dev/null +++ b/v2v/input_libvirt_xen_ssh.mli @@ -0,0 +1,21 @@ +(* virt-v2v + * Copyright (C) 2009-2014 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. + *) + +(** [-i libvirt] when the source is Xen *) + +val input_libvirt_xen_ssh : bool -> string option -> Xml.uri -> string -> string -> string -> Types.input diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml deleted file mode 100644 index dc29863..0000000 --- a/v2v/vCenter.ml +++ /dev/null @@ -1,211 +0,0 @@ -(* virt-v2v - * Copyright (C) 2009-2014 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 ESX. *) - -open Common_gettext.Gettext -open Common_utils - -open Xml -open Utils - -open Printf - -let esx_re = Str.regexp "^\\[\\(.*\\)\\] \\(.*\\)\\.vmdk$" - -let session_cookie = ref "" - -(* Map an ESX to a qemu URI using the cURL driver - * in qemu. The 'path' will be something like - * - * "[datastore1] Fedora 20/Fedora 20.vmdk" - * - * including those literal spaces in the string. - * - * XXX Old virt-v2v could also handle snapshots, ie: - * - * "[datastore1] Fedora 20/Fedora 20-NNNNNN.vmdk" - * - * 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 - else ( - let datastore = Str.matched_group 1 path - and path = Str.matched_group 2 path in - - (* Get the datacenter. *) - let datacenter = get_datacenter uri scheme in - - let port = - match uri.uri_port with - | 443 -> "" - | n when n >= 1 -> ":" ^ string_of_int n - | _ -> "" in - - let url = - sprintf - "https://%s%s/folder/%s-flat.vmdk?dcPath=%s&dsName=%s" - server port - (uri_quote path) (uri_quote datacenter) (uri_quote datastore) in - - (* 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 - - (* Now we have to query the server to get the session cookie. *) - let session_cookie = get_session_cookie verbose scheme uri sslverify url in - - (* Construct the JSON parameters. *) - let json_params = [ - "file.driver", JSON.String "https"; - "file.url", JSON.String url; - "file.timeout", JSON.Int 600; - ] in - - let json_params = - match readahead with - | None -> json_params - | Some readahead -> - ("file.readahead", JSON.Int readahead) :: json_params in - - let json_params = - if sslverify then json_params - else ("file.sslverify", JSON.String "off") :: json_params in - - let json_params = - match session_cookie with - | None -> json_params - | Some cookie -> ("file.cookie", JSON.String cookie) :: json_params in - - if verbose then - printf "esx: json parameters: %s\n" (JSON.string_of_doc json_params); - - (* Turn the JSON parameters into a 'json:' protocol string. - * Note this requires qemu-img >= 2.1.0. - *) - 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 - ) diff --git a/v2v/vCenter.mli b/v2v/vCenter.mli deleted file mode 100644 index 06ba452..0000000 --- a/v2v/vCenter.mli +++ /dev/null @@ -1,23 +0,0 @@ -(* virt-v2v - * Copyright (C) 2009-2014 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 ESX. *) - -val map_path_to_uri : bool -> Xml.uri -> string -> string -> ?readahead:int -> string -> string option -> string * string option -(** Map a VMware path like "[datastore1] guest/guest.vmdk" to the - URL where we can fetch the data. *) diff --git a/v2v/xen.ml b/v2v/xen.ml deleted file mode 100644 index 332cdd6..0000000 --- a/v2v/xen.ml +++ /dev/null @@ -1,71 +0,0 @@ -(* virt-v2v - * Copyright (C) 2009-2014 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 Xen. *) - -open Common_gettext.Gettext -open Common_utils - -open Xml -open Utils - -open Printf - -(* Map a Xen 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 rec 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 diff --git a/v2v/xen.mli b/v2v/xen.mli deleted file mode 100644 index 440d226..0000000 --- a/v2v/xen.mli +++ /dev/null @@ -1,22 +0,0 @@ -(* virt-v2v - * Copyright (C) 2009-2014 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 Xen. *) - -val map_path_to_uri : bool -> Xml.uri -> string -> string -> string -> string option -> string * string option -(** Map a Xen path to the SSH URL where we can fetch the data. *) -- 1.8.3.1