|
|
a30de4 |
From e43fe85f28ba6fb184e6894db019668f0515c38d Mon Sep 17 00:00:00 2001
|
|
|
90a56e |
From: "Richard W.M. Jones" <rjones@redhat.com>
|
|
|
90a56e |
Date: Mon, 10 Apr 2017 15:24:26 +0100
|
|
|
90a56e |
Subject: [PATCH] v2v: Implement -i vmx to read VMware vmx files directly
|
|
|
90a56e |
(RHBZ#1441197).
|
|
|
90a56e |
|
|
|
90a56e |
This is a mostly complete implementation of a VMX parser and input
|
|
|
90a56e |
class for virt-v2v. It parses the name, memory size, CPU topology,
|
|
|
90a56e |
firmware, video, sound, hard disks, removable disks and network
|
|
|
90a56e |
interfaces from the VMX file. It only omits support for floppies and
|
|
|
90a56e |
SCSI CD-ROMs.
|
|
|
90a56e |
|
|
|
90a56e |
The input class is split into two major parts: a generic VMX file
|
|
|
90a56e |
parser (Parse_vmx), and the Input_vmx module which translates the VMX
|
|
|
90a56e |
tree into the source device model.
|
|
|
90a56e |
|
|
|
90a56e |
This also contains tests. There are simple unit tests of the
|
|
|
90a56e |
Parse_vmx module, and also some more complete parsing tests taken from
|
|
|
90a56e |
real guests.
|
|
|
90a56e |
|
|
|
90a56e |
(cherry picked from commit ca40078cdda9167d4658ddfe24c828c7ee76be37)
|
|
|
90a56e |
---
|
|
|
90a56e |
v2v/Makefile.am | 15 ++
|
|
|
90a56e |
v2v/cmdline.ml | 12 +-
|
|
|
90a56e |
v2v/input_vmx.ml | 349 ++++++++++++++++++++++++++++++++++++++
|
|
|
90a56e |
v2v/input_vmx.mli | 22 +++
|
|
|
90a56e |
v2v/name_from_disk.ml | 2 +-
|
|
|
90a56e |
v2v/parse_vmx.ml | 381 ++++++++++++++++++++++++++++++++++++++++++
|
|
|
90a56e |
v2v/parse_vmx.mli | 89 ++++++++++
|
|
|
a30de4 |
v2v/test-v2v-i-vmx-1.expected | 39 +++++
|
|
|
90a56e |
v2v/test-v2v-i-vmx-1.vmx | 172 +++++++++++++++++++
|
|
|
a30de4 |
v2v/test-v2v-i-vmx-2.expected | 19 +++
|
|
|
90a56e |
v2v/test-v2v-i-vmx-2.vmx | 84 ++++++++++
|
|
|
a30de4 |
v2v/test-v2v-i-vmx-3.expected | 19 +++
|
|
|
90a56e |
v2v/test-v2v-i-vmx-3.vmx | 91 ++++++++++
|
|
|
a30de4 |
v2v/test-v2v-i-vmx-4.expected | 19 +++
|
|
|
90a56e |
v2v/test-v2v-i-vmx-4.vmx | 88 ++++++++++
|
|
|
90a56e |
v2v/test-v2v-i-vmx.sh | 48 ++++++
|
|
|
90a56e |
v2v/v2v_unit_tests.ml | 143 ++++++++++++++++
|
|
|
90a56e |
v2v/virt-v2v.pod | 72 +++++++-
|
|
|
a30de4 |
18 files changed, 1655 insertions(+), 9 deletions(-)
|
|
|
90a56e |
create mode 100644 v2v/input_vmx.ml
|
|
|
90a56e |
create mode 100644 v2v/input_vmx.mli
|
|
|
90a56e |
create mode 100644 v2v/parse_vmx.ml
|
|
|
90a56e |
create mode 100644 v2v/parse_vmx.mli
|
|
|
90a56e |
create mode 100644 v2v/test-v2v-i-vmx-1.expected
|
|
|
90a56e |
create mode 100644 v2v/test-v2v-i-vmx-1.vmx
|
|
|
90a56e |
create mode 100644 v2v/test-v2v-i-vmx-2.expected
|
|
|
90a56e |
create mode 100644 v2v/test-v2v-i-vmx-2.vmx
|
|
|
90a56e |
create mode 100644 v2v/test-v2v-i-vmx-3.expected
|
|
|
90a56e |
create mode 100644 v2v/test-v2v-i-vmx-3.vmx
|
|
|
90a56e |
create mode 100644 v2v/test-v2v-i-vmx-4.expected
|
|
|
90a56e |
create mode 100644 v2v/test-v2v-i-vmx-4.vmx
|
|
|
90a56e |
create mode 100755 v2v/test-v2v-i-vmx.sh
|
|
|
90a56e |
|
|
|
90a56e |
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
|
|
|
46ce2f |
index 297406496..0df759eca 100644
|
|
|
90a56e |
--- a/v2v/Makefile.am
|
|
|
90a56e |
+++ b/v2v/Makefile.am
|
|
|
90a56e |
@@ -38,6 +38,7 @@ SOURCES_MLI = \
|
|
|
90a56e |
input_libvirt_xen_ssh.mli \
|
|
|
90a56e |
input_libvirtxml.mli \
|
|
|
90a56e |
input_ova.mli \
|
|
|
90a56e |
+ input_vmx.mli \
|
|
|
90a56e |
inspect_source.mli \
|
|
|
90a56e |
libvirt_utils.mli \
|
|
|
90a56e |
linux.mli \
|
|
|
90a56e |
@@ -55,6 +56,7 @@ SOURCES_MLI = \
|
|
|
90a56e |
OVF.mli \
|
|
|
90a56e |
parse_ovf_from_ova.mli \
|
|
|
90a56e |
parse_libvirt_xml.mli \
|
|
|
90a56e |
+ parse_vmx.mli \
|
|
|
90a56e |
qemu_command.mli \
|
|
|
90a56e |
target_bus_assignment.mli \
|
|
|
90a56e |
types.mli \
|
|
|
90a56e |
@@ -80,6 +82,7 @@ SOURCES_ML = \
|
|
|
90a56e |
windows_virtio.ml \
|
|
|
90a56e |
modules_list.ml \
|
|
|
90a56e |
input_disk.ml \
|
|
|
90a56e |
+ parse_vmx.ml \
|
|
|
90a56e |
parse_libvirt_xml.ml \
|
|
|
90a56e |
create_libvirt_xml.ml \
|
|
|
90a56e |
qemu_command.ml \
|
|
|
90a56e |
@@ -89,6 +92,7 @@ SOURCES_ML = \
|
|
|
90a56e |
input_libvirt_xen_ssh.ml \
|
|
|
90a56e |
input_libvirt.ml \
|
|
|
90a56e |
input_ova.ml \
|
|
|
90a56e |
+ input_vmx.ml \
|
|
|
90a56e |
linux_bootloaders.ml \
|
|
|
90a56e |
linux_kernels.ml \
|
|
|
90a56e |
convert_linux.ml \
|
|
|
90a56e |
@@ -268,6 +272,7 @@ TESTS = \
|
|
|
90a56e |
test-v2v-i-ova-subfolders.sh \
|
|
|
90a56e |
test-v2v-i-ova-tar.sh \
|
|
|
90a56e |
test-v2v-i-ova-two-disks.sh \
|
|
|
90a56e |
+ test-v2v-i-vmx.sh \
|
|
|
90a56e |
test-v2v-bad-networks-and-bridges.sh
|
|
|
90a56e |
|
|
|
90a56e |
if HAVE_LIBVIRT
|
|
|
90a56e |
@@ -411,6 +416,15 @@ EXTRA_DIST += \
|
|
|
90a56e |
test-v2v-i-ova.ovf \
|
|
|
90a56e |
test-v2v-i-ova.sh \
|
|
|
90a56e |
test-v2v-i-ova.xml \
|
|
|
90a56e |
+ test-v2v-i-vmx.sh \
|
|
|
90a56e |
+ test-v2v-i-vmx-1.expected \
|
|
|
90a56e |
+ test-v2v-i-vmx-2.expected \
|
|
|
90a56e |
+ test-v2v-i-vmx-3.expected \
|
|
|
90a56e |
+ test-v2v-i-vmx-4.expected \
|
|
|
90a56e |
+ test-v2v-i-vmx-1.vmx \
|
|
|
90a56e |
+ test-v2v-i-vmx-2.vmx \
|
|
|
90a56e |
+ test-v2v-i-vmx-3.vmx \
|
|
|
90a56e |
+ test-v2v-i-vmx-4.vmx \
|
|
|
90a56e |
test-v2v-machine-readable.sh \
|
|
|
90a56e |
test-v2v-networks-and-bridges-expected.xml \
|
|
|
90a56e |
test-v2v-networks-and-bridges.sh \
|
|
|
90a56e |
@@ -450,6 +464,7 @@ v2v_unit_tests_BOBJECTS = \
|
|
|
90a56e |
windows.cmo \
|
|
|
90a56e |
windows_virtio.cmo \
|
|
|
90a56e |
linux.cmo \
|
|
|
90a56e |
+ parse_vmx.cmo \
|
|
|
90a56e |
v2v_unit_tests.cmo
|
|
|
90a56e |
v2v_unit_tests_XOBJECTS = $(v2v_unit_tests_BOBJECTS:.cmo=.cmx)
|
|
|
90a56e |
|
|
|
90a56e |
diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
|
|
|
a30de4 |
index 3e3d5c312..db2346a38 100644
|
|
|
90a56e |
--- a/v2v/cmdline.ml
|
|
|
90a56e |
+++ b/v2v/cmdline.ml
|
|
|
90a56e |
@@ -86,6 +86,7 @@ let parse_cmdline () =
|
|
|
90a56e |
| "libvirt" -> input_mode := `Libvirt
|
|
|
90a56e |
| "libvirtxml" -> input_mode := `LibvirtXML
|
|
|
90a56e |
| "ova" -> input_mode := `OVA
|
|
|
90a56e |
+ | "vmx" -> input_mode := `VMX
|
|
|
90a56e |
| s ->
|
|
|
90a56e |
error (f_"unknown -i option: %s") s
|
|
|
90a56e |
in
|
|
|
a30de4 |
@@ -333,7 +334,16 @@ read the man page virt-v2v(1).
|
|
|
90a56e |
| [filename] -> filename
|
|
|
90a56e |
| _ ->
|
|
|
90a56e |
error (f_"expecting an OVA file name on the command line") in
|
|
|
90a56e |
- Input_ova.input_ova filename in
|
|
|
90a56e |
+ Input_ova.input_ova filename
|
|
|
90a56e |
+
|
|
|
90a56e |
+ | `VMX ->
|
|
|
90a56e |
+ (* -i vmx: Expecting an vmx filename. *)
|
|
|
90a56e |
+ let filename =
|
|
|
90a56e |
+ match args with
|
|
|
90a56e |
+ | [filename] -> filename
|
|
|
90a56e |
+ | _ ->
|
|
|
90a56e |
+ error (f_"expecting a VMX file name on the command line") in
|
|
|
90a56e |
+ Input_vmx.input_vmx filename in
|
|
|
90a56e |
|
|
|
90a56e |
(* Prevent use of --in-place option in RHEL. *)
|
|
|
90a56e |
if in_place then
|
|
|
90a56e |
diff --git a/v2v/input_vmx.ml b/v2v/input_vmx.ml
|
|
|
90a56e |
new file mode 100644
|
|
|
46ce2f |
index 000000000..bb09f0bf8
|
|
|
90a56e |
--- /dev/null
|
|
|
90a56e |
+++ b/v2v/input_vmx.ml
|
|
|
90a56e |
@@ -0,0 +1,349 @@
|
|
|
90a56e |
+(* virt-v2v
|
|
|
90a56e |
+ * Copyright (C) 2017 Red Hat Inc.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * This program is free software; you can redistribute it and/or modify
|
|
|
90a56e |
+ * it under the terms of the GNU General Public License as published by
|
|
|
90a56e |
+ * the Free Software Foundation; either version 2 of the License, or
|
|
|
90a56e |
+ * (at your option) any later version.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * This program is distributed in the hope that it will be useful,
|
|
|
90a56e |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
90a56e |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
90a56e |
+ * GNU General Public License for more details.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * You should have received a copy of the GNU General Public License along
|
|
|
90a56e |
+ * with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
90a56e |
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
90a56e |
+ *)
|
|
|
90a56e |
+
|
|
|
90a56e |
+open Printf
|
|
|
90a56e |
+open Scanf
|
|
|
90a56e |
+
|
|
|
90a56e |
+open Common_gettext.Gettext
|
|
|
90a56e |
+open Common_utils
|
|
|
90a56e |
+
|
|
|
90a56e |
+open Types
|
|
|
90a56e |
+open Utils
|
|
|
90a56e |
+open Name_from_disk
|
|
|
90a56e |
+
|
|
|
90a56e |
+external identity : 'a -> 'a = "%identity"
|
|
|
90a56e |
+
|
|
|
90a56e |
+let rec find_disks vmx vmx_filename =
|
|
|
90a56e |
+ find_scsi_disks vmx vmx_filename @ find_ide_disks vmx vmx_filename
|
|
|
90a56e |
+
|
|
|
90a56e |
+(* Find all SCSI hard disks.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * In the VMX file:
|
|
|
90a56e |
+ * scsi0.virtualDev = "pvscsi" # or may be "lsilogic" etc.
|
|
|
90a56e |
+ * scsi0:0.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+ * scsi0:0.fileName = "guest.vmdk"
|
|
|
90a56e |
+ *)
|
|
|
90a56e |
+and find_scsi_disks vmx vmx_filename =
|
|
|
90a56e |
+ let get_scsi_controller_target ns =
|
|
|
90a56e |
+ sscanf ns "scsi%d:%d" (fun c t -> c, t)
|
|
|
90a56e |
+ in
|
|
|
90a56e |
+ let is_scsi_controller_target ns =
|
|
|
90a56e |
+ try ignore (get_scsi_controller_target ns); true
|
|
|
90a56e |
+ with Scanf.Scan_failure _ | End_of_file | Failure _ -> false
|
|
|
90a56e |
+ in
|
|
|
90a56e |
+ let scsi_device_types = [ "scsi-harddisk" ] in
|
|
|
90a56e |
+ let scsi_controller = Source_SCSI in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ find_hdds vmx vmx_filename
|
|
|
90a56e |
+ get_scsi_controller_target is_scsi_controller_target
|
|
|
90a56e |
+ scsi_device_types scsi_controller
|
|
|
90a56e |
+
|
|
|
90a56e |
+(* Find all IDE hard disks.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * In the VMX file:
|
|
|
90a56e |
+ * ide0:0.deviceType = "ata-hardDisk"
|
|
|
90a56e |
+ * ide0:0.fileName = "guest.vmdk"
|
|
|
90a56e |
+ *)
|
|
|
90a56e |
+and find_ide_disks vmx vmx_filename =
|
|
|
90a56e |
+ let get_ide_controller_target ns =
|
|
|
90a56e |
+ sscanf ns "ide%d:%d" (fun c t -> c, t)
|
|
|
90a56e |
+ in
|
|
|
90a56e |
+ let is_ide_controller_target ns =
|
|
|
90a56e |
+ try ignore (get_ide_controller_target ns); true
|
|
|
90a56e |
+ with Scanf.Scan_failure _ | End_of_file | Failure _ -> false
|
|
|
90a56e |
+ in
|
|
|
90a56e |
+ let ide_device_types = [ "ata-harddisk" ] in
|
|
|
90a56e |
+ let ide_controller = Source_IDE in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ find_hdds vmx vmx_filename
|
|
|
90a56e |
+ get_ide_controller_target is_ide_controller_target
|
|
|
90a56e |
+ ide_device_types ide_controller
|
|
|
90a56e |
+
|
|
|
90a56e |
+and find_hdds vmx vmx_filename
|
|
|
90a56e |
+ get_controller_target is_controller_target
|
|
|
90a56e |
+ device_types controller =
|
|
|
90a56e |
+ (* Find namespaces matching '(ide|scsi)X:Y' with suitable deviceType. *)
|
|
|
90a56e |
+ let hdds =
|
|
|
90a56e |
+ Parse_vmx.select_namespaces (
|
|
|
90a56e |
+ function
|
|
|
90a56e |
+ | [ns] ->
|
|
|
90a56e |
+ (* Check the namespace is '(ide|scsi)X:Y' *)
|
|
|
90a56e |
+ if not (is_controller_target ns) then false
|
|
|
90a56e |
+ else (
|
|
|
90a56e |
+ (* Check the deviceType is one we are looking for. *)
|
|
|
90a56e |
+ match Parse_vmx.get_string vmx [ns; "deviceType"] with
|
|
|
90a56e |
+ | Some str ->
|
|
|
90a56e |
+ let str = String.lowercase_ascii str in
|
|
|
90a56e |
+ List.mem str device_types
|
|
|
90a56e |
+ | None -> false
|
|
|
90a56e |
+ )
|
|
|
90a56e |
+ | _ -> false
|
|
|
90a56e |
+ ) vmx in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* Map the subset to a list of disks. *)
|
|
|
90a56e |
+ let hdds =
|
|
|
90a56e |
+ Parse_vmx.map (
|
|
|
90a56e |
+ fun path v ->
|
|
|
90a56e |
+ match path, v with
|
|
|
90a56e |
+ | [ns; "filename"], Some filename ->
|
|
|
90a56e |
+ let c, t = get_controller_target ns in
|
|
|
90a56e |
+ let s = { s_disk_id = (-1);
|
|
|
90a56e |
+ s_qemu_uri = qemu_uri_of_filename vmx_filename filename;
|
|
|
90a56e |
+ s_format = Some "vmdk";
|
|
|
90a56e |
+ s_controller = Some controller } in
|
|
|
90a56e |
+ Some (c, t, s)
|
|
|
90a56e |
+ | _ -> None
|
|
|
90a56e |
+ ) hdds in
|
|
|
90a56e |
+ let hdds = filter_map identity hdds in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* We don't have a way to return the controllers and targets, so
|
|
|
90a56e |
+ * just make sure the disks are sorted into order, since Parse_vmx
|
|
|
90a56e |
+ * won't return them in any particular order.
|
|
|
90a56e |
+ *)
|
|
|
90a56e |
+ let hdds = List.sort compare hdds in
|
|
|
90a56e |
+ let hdds = List.map (fun (_, _, source) -> source) hdds in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* Set the s_disk_id field to an incrementing number. *)
|
|
|
90a56e |
+ let hdds = mapi (fun i source -> { source with s_disk_id = i }) hdds in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ hdds
|
|
|
90a56e |
+
|
|
|
90a56e |
+(* The filename can be an absolute path, but is more often a
|
|
|
90a56e |
+ * path relative to the location of the vmx file.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * Note that we always end up with an absolute path, which is
|
|
|
90a56e |
+ * also useful because it means we won't have any paths that
|
|
|
90a56e |
+ * could be misinterpreted by qemu.
|
|
|
90a56e |
+ *)
|
|
|
90a56e |
+and qemu_uri_of_filename vmx_filename filename =
|
|
|
90a56e |
+ if not (Filename.is_relative filename) then
|
|
|
90a56e |
+ filename
|
|
|
90a56e |
+ else (
|
|
|
90a56e |
+ let dir = Filename.dirname (absolute_path vmx_filename) in
|
|
|
90a56e |
+ dir // filename
|
|
|
90a56e |
+ )
|
|
|
90a56e |
+
|
|
|
90a56e |
+(* Find all removable disks.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * In the VMX file:
|
|
|
90a56e |
+ * ide1:0.deviceType = "cdrom-image"
|
|
|
90a56e |
+ * ide1:0.fileName = "boot.iso"
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * XXX This only supports IDE CD-ROMs, but we could support SCSI
|
|
|
90a56e |
+ * CD-ROMs and floppies in future.
|
|
|
90a56e |
+ *)
|
|
|
90a56e |
+and find_removables vmx =
|
|
|
90a56e |
+ let get_ide_controller_target ns =
|
|
|
90a56e |
+ sscanf ns "ide%d:%d" (fun c t -> c, t)
|
|
|
90a56e |
+ in
|
|
|
90a56e |
+ let is_ide_controller_target ns =
|
|
|
90a56e |
+ try ignore (get_ide_controller_target ns); true
|
|
|
90a56e |
+ with Scanf.Scan_failure _ | End_of_file | Failure _ -> false
|
|
|
90a56e |
+ in
|
|
|
90a56e |
+ let device_types = [ "atapi-cdrom";
|
|
|
90a56e |
+ "cdrom-image"; "cdrom-raw" ] in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* Find namespaces matching 'ideX:Y' with suitable deviceType. *)
|
|
|
90a56e |
+ let devs =
|
|
|
90a56e |
+ Parse_vmx.select_namespaces (
|
|
|
90a56e |
+ function
|
|
|
90a56e |
+ | [ns] ->
|
|
|
90a56e |
+ (* Check the namespace is 'ideX:Y' *)
|
|
|
90a56e |
+ if not (is_ide_controller_target ns) then false
|
|
|
90a56e |
+ else (
|
|
|
90a56e |
+ (* Check the deviceType is one we are looking for. *)
|
|
|
90a56e |
+ match Parse_vmx.get_string vmx [ns; "deviceType"] with
|
|
|
90a56e |
+ | Some str ->
|
|
|
90a56e |
+ let str = String.lowercase_ascii str in
|
|
|
90a56e |
+ List.mem str device_types
|
|
|
90a56e |
+ | None -> false
|
|
|
90a56e |
+ )
|
|
|
90a56e |
+ | _ -> false
|
|
|
90a56e |
+ ) vmx in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* Map the subset to a list of CD-ROMs. *)
|
|
|
90a56e |
+ let devs =
|
|
|
90a56e |
+ Parse_vmx.map (
|
|
|
90a56e |
+ fun path v ->
|
|
|
90a56e |
+ match path, v with
|
|
|
90a56e |
+ | [ns], None ->
|
|
|
90a56e |
+ let c, t = get_ide_controller_target ns in
|
|
|
90a56e |
+ let s = { s_removable_type = CDROM;
|
|
|
90a56e |
+ s_removable_controller = Some Source_IDE;
|
|
|
90a56e |
+ s_removable_slot = Some (ide_slot c t) } in
|
|
|
90a56e |
+ Some s
|
|
|
90a56e |
+ | _ -> None
|
|
|
90a56e |
+ ) devs in
|
|
|
90a56e |
+ let devs = filter_map identity devs in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* Sort by slot. *)
|
|
|
90a56e |
+ let devs =
|
|
|
90a56e |
+ List.sort
|
|
|
90a56e |
+ (fun { s_removable_slot = s1 } { s_removable_slot = s2 } ->
|
|
|
90a56e |
+ compare s1 s2)
|
|
|
90a56e |
+ devs in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ devs
|
|
|
90a56e |
+
|
|
|
90a56e |
+and ide_slot c t =
|
|
|
90a56e |
+ (* Assuming the old master/slave arrangement. *)
|
|
|
90a56e |
+ c * 2 + t
|
|
|
90a56e |
+
|
|
|
90a56e |
+(* Find all ethernet cards.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * In the VMX file:
|
|
|
90a56e |
+ * ethernet0.virtualDev = "vmxnet3"
|
|
|
90a56e |
+ * ethernet0.networkName = "VM Network"
|
|
|
90a56e |
+ * ethernet0.generatedAddress = "00:01:02:03:04:05"
|
|
|
90a56e |
+ * ethernet0.connectionType = "bridged" # also: "custom", "nat" or not present
|
|
|
90a56e |
+ *)
|
|
|
90a56e |
+and find_nics vmx =
|
|
|
90a56e |
+ let get_ethernet_port ns =
|
|
|
90a56e |
+ sscanf ns "ethernet%d" (fun p -> p)
|
|
|
90a56e |
+ in
|
|
|
90a56e |
+ let is_ethernet_port ns =
|
|
|
90a56e |
+ try ignore (get_ethernet_port ns); true
|
|
|
90a56e |
+ with Scanf.Scan_failure _ | End_of_file | Failure _ -> false
|
|
|
90a56e |
+ in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* Find namespaces matching 'ethernetX'. *)
|
|
|
90a56e |
+ let nics =
|
|
|
90a56e |
+ Parse_vmx.select_namespaces (
|
|
|
90a56e |
+ function
|
|
|
90a56e |
+ | [ns] -> is_ethernet_port ns
|
|
|
90a56e |
+ | _ -> false
|
|
|
90a56e |
+ ) vmx in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* Map the subset to a list of NICs. *)
|
|
|
90a56e |
+ let nics =
|
|
|
90a56e |
+ Parse_vmx.map (
|
|
|
90a56e |
+ fun path v ->
|
|
|
90a56e |
+ match path, v with
|
|
|
90a56e |
+ | [ns], None ->
|
|
|
90a56e |
+ let port = get_ethernet_port ns in
|
|
|
90a56e |
+ let mac = Parse_vmx.get_string vmx [ns; "generatedAddress"] in
|
|
|
90a56e |
+ let model = Parse_vmx.get_string vmx [ns; "virtualDev"] in
|
|
|
90a56e |
+ let model =
|
|
|
90a56e |
+ match model with
|
|
|
90a56e |
+ | Some m when String.lowercase_ascii m = "e1000" ->
|
|
|
90a56e |
+ Some Source_e1000
|
|
|
90a56e |
+ | Some model ->
|
|
|
90a56e |
+ Some (Source_other_nic (String.lowercase_ascii model))
|
|
|
90a56e |
+ | None -> None in
|
|
|
90a56e |
+ let vnet = Parse_vmx.get_string vmx [ns; "networkName"] in
|
|
|
90a56e |
+ let vnet =
|
|
|
90a56e |
+ match vnet with
|
|
|
90a56e |
+ | Some vnet -> vnet
|
|
|
90a56e |
+ | None -> ns (* "ethernetX" *) in
|
|
|
90a56e |
+ let vnet_type =
|
|
|
90a56e |
+ match Parse_vmx.get_string vmx [ns; "connectionType"] with
|
|
|
90a56e |
+ | Some b when String.lowercase_ascii b = "bridged" ->
|
|
|
90a56e |
+ Bridge
|
|
|
90a56e |
+ | Some _ | None -> Network in
|
|
|
90a56e |
+ Some (port,
|
|
|
90a56e |
+ { s_mac = mac; s_nic_model = model;
|
|
|
90a56e |
+ s_vnet = vnet; s_vnet_orig = vnet;
|
|
|
90a56e |
+ s_vnet_type = vnet_type })
|
|
|
90a56e |
+ | _ -> None
|
|
|
90a56e |
+ ) nics in
|
|
|
90a56e |
+ let nics = filter_map identity nics in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* Sort by port. *)
|
|
|
90a56e |
+ let nics = List.sort compare nics in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ let nics = List.map (fun (_, source) -> source) nics in
|
|
|
90a56e |
+ nics
|
|
|
90a56e |
+
|
|
|
90a56e |
+class input_vmx vmx_filename = object
|
|
|
90a56e |
+ inherit input
|
|
|
90a56e |
+
|
|
|
90a56e |
+ method as_options = "-i vmx " ^ vmx_filename
|
|
|
90a56e |
+
|
|
|
90a56e |
+ method source () =
|
|
|
90a56e |
+ (* Parse the VMX file. *)
|
|
|
90a56e |
+ let vmx = Parse_vmx.parse_file vmx_filename in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ let name =
|
|
|
90a56e |
+ match Parse_vmx.get_string vmx ["displayName"] with
|
|
|
90a56e |
+ | None ->
|
|
|
90a56e |
+ warning (f_"no displayName key found in VMX file");
|
|
|
90a56e |
+ name_from_disk vmx_filename
|
|
|
90a56e |
+ | Some s -> s in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ let memory_mb =
|
|
|
90a56e |
+ match Parse_vmx.get_int64 vmx ["memSize"] with
|
|
|
90a56e |
+ | None -> 32_L (* default is really 32 MB! *)
|
|
|
90a56e |
+ | Some i -> i in
|
|
|
90a56e |
+ let memory = memory_mb *^ 1024L *^ 1024L in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ let vcpu =
|
|
|
90a56e |
+ match Parse_vmx.get_int vmx ["numvcpus"] with
|
|
|
90a56e |
+ | None -> 1
|
|
|
90a56e |
+ | Some i -> i in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ let firmware =
|
|
|
90a56e |
+ match Parse_vmx.get_string vmx ["firmware"] with
|
|
|
90a56e |
+ | None -> BIOS
|
|
|
90a56e |
+ | Some "efi" -> UEFI
|
|
|
90a56e |
+ (* Other values are not documented for this field ... *)
|
|
|
90a56e |
+ | Some fw ->
|
|
|
90a56e |
+ warning (f_"unknown firmware value '%s', assuming BIOS") fw;
|
|
|
90a56e |
+ BIOS in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ let video =
|
|
|
90a56e |
+ if Parse_vmx.namespace_present vmx ["svga"] then
|
|
|
90a56e |
+ (* We could also parse svga.vramSize. *)
|
|
|
90a56e |
+ Some (Source_other_video "vmvga")
|
|
|
90a56e |
+ else
|
|
|
90a56e |
+ None in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ let sound =
|
|
|
90a56e |
+ match Parse_vmx.get_string vmx ["sound"; "virtualDev"] with
|
|
|
90a56e |
+ | Some ("sb16") -> Some { s_sound_model = SB16 }
|
|
|
90a56e |
+ | Some ("es1371") -> Some { s_sound_model = ES1370 (* hmmm ... *) }
|
|
|
90a56e |
+ | Some "hdaudio" -> Some { s_sound_model = ICH6 (* intel-hda *) }
|
|
|
90a56e |
+ | Some model ->
|
|
|
90a56e |
+ warning (f_"unknown sound device '%s' ignored") model;
|
|
|
90a56e |
+ None
|
|
|
90a56e |
+ | None -> None in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ let disks = find_disks vmx vmx_filename in
|
|
|
90a56e |
+ let removables = find_removables vmx in
|
|
|
90a56e |
+ let nics = find_nics vmx in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ let source = {
|
|
|
90a56e |
+ s_hypervisor = VMware;
|
|
|
90a56e |
+ s_name = name;
|
|
|
90a56e |
+ s_orig_name = name;
|
|
|
90a56e |
+ s_memory = memory;
|
|
|
90a56e |
+ s_vcpu = vcpu;
|
|
|
90a56e |
+ s_features = [];
|
|
|
90a56e |
+ s_firmware = firmware;
|
|
|
90a56e |
+ s_display = None;
|
|
|
90a56e |
+ s_video = video;
|
|
|
90a56e |
+ s_sound = sound;
|
|
|
90a56e |
+ s_disks = disks;
|
|
|
90a56e |
+ s_removables = removables;
|
|
|
90a56e |
+ s_nics = nics;
|
|
|
90a56e |
+ } in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ source
|
|
|
90a56e |
+end
|
|
|
90a56e |
+
|
|
|
90a56e |
+let input_vmx = new input_vmx
|
|
|
90a56e |
+let () = Modules_list.register_input_module "vmx"
|
|
|
90a56e |
diff --git a/v2v/input_vmx.mli b/v2v/input_vmx.mli
|
|
|
90a56e |
new file mode 100644
|
|
|
46ce2f |
index 000000000..f236f8716
|
|
|
90a56e |
--- /dev/null
|
|
|
90a56e |
+++ b/v2v/input_vmx.mli
|
|
|
90a56e |
@@ -0,0 +1,22 @@
|
|
|
90a56e |
+(* virt-v2v
|
|
|
90a56e |
+ * Copyright (C) 2017 Red Hat Inc.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * This program is free software; you can redistribute it and/or modify
|
|
|
90a56e |
+ * it under the terms of the GNU General Public License as published by
|
|
|
90a56e |
+ * the Free Software Foundation; either version 2 of the License, or
|
|
|
90a56e |
+ * (at your option) any later version.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * This program is distributed in the hope that it will be useful,
|
|
|
90a56e |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
90a56e |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
90a56e |
+ * GNU General Public License for more details.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * You should have received a copy of the GNU General Public License along
|
|
|
90a56e |
+ * with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
90a56e |
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
90a56e |
+ *)
|
|
|
90a56e |
+
|
|
|
90a56e |
+(** [-i vmx] source. *)
|
|
|
90a56e |
+
|
|
|
90a56e |
+val input_vmx : string -> Types.input
|
|
|
90a56e |
+(** [input_vmx filename] sets up an input from vmware vmx file. *)
|
|
|
90a56e |
diff --git a/v2v/name_from_disk.ml b/v2v/name_from_disk.ml
|
|
|
46ce2f |
index 82f09250a..452d9462c 100644
|
|
|
90a56e |
--- a/v2v/name_from_disk.ml
|
|
|
90a56e |
+++ b/v2v/name_from_disk.ml
|
|
|
90a56e |
@@ -24,7 +24,7 @@ let name_from_disk disk =
|
|
|
90a56e |
(* Remove the extension (or suffix), only if it's one usually
|
|
|
90a56e |
* used for disk images. *)
|
|
|
90a56e |
let suffixes = [
|
|
|
90a56e |
- ".img"; ".ova"; ".qcow2"; ".raw"; ".vmdk";
|
|
|
90a56e |
+ ".img"; ".ova"; ".qcow2"; ".raw"; ".vmdk"; ".vmx";
|
|
|
90a56e |
"-sda";
|
|
|
90a56e |
] in
|
|
|
90a56e |
let rec loop = function
|
|
|
90a56e |
diff --git a/v2v/parse_vmx.ml b/v2v/parse_vmx.ml
|
|
|
90a56e |
new file mode 100644
|
|
|
46ce2f |
index 000000000..33ec17d3d
|
|
|
90a56e |
--- /dev/null
|
|
|
90a56e |
+++ b/v2v/parse_vmx.ml
|
|
|
90a56e |
@@ -0,0 +1,381 @@
|
|
|
90a56e |
+(* virt-v2v
|
|
|
90a56e |
+ * Copyright (C) 2017 Red Hat Inc.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * This program is free software; you can redistribute it and/or modify
|
|
|
90a56e |
+ * it under the terms of the GNU General Public License as published by
|
|
|
90a56e |
+ * the Free Software Foundation; either version 2 of the License, or
|
|
|
90a56e |
+ * (at your option) any later version.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * This program is distributed in the hope that it will be useful,
|
|
|
90a56e |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
90a56e |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
90a56e |
+ * GNU General Public License for more details.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * You should have received a copy of the GNU General Public License along
|
|
|
90a56e |
+ * with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
90a56e |
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
90a56e |
+ *)
|
|
|
90a56e |
+
|
|
|
90a56e |
+open Printf
|
|
|
90a56e |
+
|
|
|
90a56e |
+open Common_utils
|
|
|
90a56e |
+open Common_gettext.Gettext
|
|
|
90a56e |
+
|
|
|
90a56e |
+(* As far as I can tell the VMX format is totally unspecified.
|
|
|
90a56e |
+ * However libvirt has a useful selection of .vmx files in the
|
|
|
90a56e |
+ * sources which explore some of the darker regions of this
|
|
|
90a56e |
+ * format.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * So here are some facts about VMX derived from libvirt and
|
|
|
90a56e |
+ * other places:
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * - Keys are compared case insensitively. We assume here
|
|
|
90a56e |
+ * that keys are 7-bit ASCII.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * - Multiple keys with the same name are not allowed.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * - Escaping in the value string is possible using a very weird
|
|
|
90a56e |
+ * escape format: "|22" means the character '\x22'. To write
|
|
|
90a56e |
+ * a pipe character you must use "|7C".
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * - Boolean values are written "TRUE", "FALSE", "True", "true", etc.
|
|
|
90a56e |
+ * Because of the quotes they cannot be distinguished from strings.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * - Comments (#...) and blank lines are ignored. Some files start
|
|
|
90a56e |
+ * with a hash-bang path, but we ignore those as comments. This
|
|
|
90a56e |
+ * parser also ignores any other line which it doesn't understand,
|
|
|
90a56e |
+ * but will print a warning.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * - Multi-line values are not permitted.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * - Keys are namespaced using dots, eg. scsi0:0.deviceType has
|
|
|
90a56e |
+ * the namespace "scsi0:0" and the key name "deviceType".
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * - Using namespace.present = "FALSE" means that all other keys
|
|
|
90a56e |
+ * in and under the namespace are ignored.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * - You cannot have a namespace and a key with the same name, eg.
|
|
|
90a56e |
+ * this is not allowed:
|
|
|
90a56e |
+ * namespace = "some value"
|
|
|
90a56e |
+ * namespace.foo = "another value"
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * - The Hashicorp packer VMX writer considers some special keys
|
|
|
90a56e |
+ * as not requiring any quotes around their values, but I'm
|
|
|
90a56e |
+ * ignoring that for now.
|
|
|
90a56e |
+ *)
|
|
|
90a56e |
+
|
|
|
90a56e |
+(* This VMX file:
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * foo.a = "abc"
|
|
|
90a56e |
+ * foo.b = "def"
|
|
|
90a56e |
+ * foo.bar.c = "abc"
|
|
|
90a56e |
+ * foo.bar.d = "def"
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * would be represented by this structure:
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * "foo" => Namespace ( # "foo" is a namespace
|
|
|
90a56e |
+ * "a" => Key "abc"; # "foo.a" is a key with value "abc"
|
|
|
90a56e |
+ * "b" => Key "def";
|
|
|
90a56e |
+ * "bar" => Namespace ( # "foo.bar" is another namespace
|
|
|
90a56e |
+ * "c" => Key "abc";
|
|
|
90a56e |
+ * "d" => Key "def";
|
|
|
90a56e |
+ * )
|
|
|
90a56e |
+ * )
|
|
|
90a56e |
+ * ‘( => )’s represent the StringMap type.
|
|
|
90a56e |
+ *)
|
|
|
90a56e |
+type t = key StringMap.t
|
|
|
90a56e |
+
|
|
|
90a56e |
+and key =
|
|
|
90a56e |
+ | Key of string
|
|
|
90a56e |
+ | Namespace of t
|
|
|
90a56e |
+
|
|
|
90a56e |
+let empty = StringMap.empty
|
|
|
90a56e |
+
|
|
|
90a56e |
+(* Compare two trees for equality. *)
|
|
|
90a56e |
+let rec equal vmx1 vmx2 =
|
|
|
90a56e |
+ let cmp k1 k2 =
|
|
|
90a56e |
+ match k1, k2 with
|
|
|
90a56e |
+ | Key v1, Key v2 -> v1 = v2
|
|
|
90a56e |
+ | Key _, Namespace _ -> false
|
|
|
90a56e |
+ | Namespace _, Key _ -> false
|
|
|
90a56e |
+ | Namespace vmx1, Namespace vmx2 -> equal vmx1 vmx2
|
|
|
90a56e |
+ in
|
|
|
90a56e |
+ StringMap.equal cmp vmx1 vmx2
|
|
|
90a56e |
+
|
|
|
90a56e |
+(* Higher-order functions. *)
|
|
|
90a56e |
+let rec select_namespaces pred vmx =
|
|
|
90a56e |
+ _select_namespaces [] pred vmx
|
|
|
90a56e |
+
|
|
|
90a56e |
+and _select_namespaces path pred vmx =
|
|
|
90a56e |
+ StringMap.fold (
|
|
|
90a56e |
+ fun k v new_vmx ->
|
|
|
90a56e |
+ let path = path @ [k] in
|
|
|
90a56e |
+ match v with
|
|
|
90a56e |
+ | Key _ -> new_vmx
|
|
|
90a56e |
+ | Namespace _ when pred path ->
|
|
|
90a56e |
+ StringMap.add k v new_vmx
|
|
|
90a56e |
+ | Namespace t ->
|
|
|
90a56e |
+ let t = _select_namespaces path pred t in
|
|
|
90a56e |
+ if not (equal t empty) then
|
|
|
90a56e |
+ StringMap.add k (Namespace t) new_vmx
|
|
|
90a56e |
+ else
|
|
|
90a56e |
+ new_vmx
|
|
|
90a56e |
+ ) vmx empty
|
|
|
90a56e |
+
|
|
|
90a56e |
+let rec map f vmx =
|
|
|
90a56e |
+ _map [] f vmx
|
|
|
90a56e |
+
|
|
|
90a56e |
+and _map path f vmx =
|
|
|
90a56e |
+ StringMap.fold (
|
|
|
90a56e |
+ fun k v r ->
|
|
|
90a56e |
+ let path = path @ [k] in
|
|
|
90a56e |
+ match v with
|
|
|
90a56e |
+ | Key v -> r @ [ f path (Some v) ]
|
|
|
90a56e |
+ | Namespace t -> r @ [ f path None ] @ _map path f t
|
|
|
90a56e |
+ ) vmx []
|
|
|
90a56e |
+
|
|
|
90a56e |
+let rec namespace_present vmx = function
|
|
|
90a56e |
+ | [] -> false
|
|
|
90a56e |
+ | [ns] ->
|
|
|
90a56e |
+ let ns = String.lowercase_ascii ns in
|
|
|
90a56e |
+ (try
|
|
|
90a56e |
+ let v = StringMap.find ns vmx in
|
|
|
90a56e |
+ match v with
|
|
|
90a56e |
+ | Key _ -> false
|
|
|
90a56e |
+ | Namespace _ -> true
|
|
|
90a56e |
+ with
|
|
|
90a56e |
+ Not_found -> false
|
|
|
90a56e |
+ )
|
|
|
90a56e |
+ | ns :: path ->
|
|
|
90a56e |
+ let ns = String.lowercase_ascii ns in
|
|
|
90a56e |
+ (try
|
|
|
90a56e |
+ let v = StringMap.find ns vmx in
|
|
|
90a56e |
+ match v with
|
|
|
90a56e |
+ | Key _ -> false
|
|
|
90a56e |
+ | Namespace vmx -> namespace_present vmx path
|
|
|
90a56e |
+ with
|
|
|
90a56e |
+ Not_found -> false
|
|
|
90a56e |
+ )
|
|
|
90a56e |
+
|
|
|
90a56e |
+(* Dump the vmx structure to [chan]. Used for debugging. *)
|
|
|
90a56e |
+let rec print chan indent vmx =
|
|
|
90a56e |
+ StringMap.iter (print_key chan indent) vmx
|
|
|
90a56e |
+
|
|
|
90a56e |
+and print_key chan indent k = function
|
|
|
90a56e |
+ | Key v ->
|
|
|
90a56e |
+ output_spaces chan indent;
|
|
|
90a56e |
+ fprintf chan "%s = \"%s\"\n" k v
|
|
|
90a56e |
+ | Namespace vmx ->
|
|
|
90a56e |
+ output_spaces chan indent;
|
|
|
90a56e |
+ fprintf chan "namespace '%s':\n" k;
|
|
|
90a56e |
+ print chan (indent+4) vmx
|
|
|
90a56e |
+
|
|
|
90a56e |
+(* As above, but creates a string instead. *)
|
|
|
90a56e |
+let rec to_string indent vmx =
|
|
|
90a56e |
+ StringMap.fold (fun k v str -> str ^ to_string_key indent k v) vmx ""
|
|
|
90a56e |
+
|
|
|
90a56e |
+and to_string_key indent k = function
|
|
|
90a56e |
+ | Key v ->
|
|
|
90a56e |
+ String.spaces indent ^ sprintf "%s = \"%s\"\n" k v
|
|
|
90a56e |
+ | Namespace vmx ->
|
|
|
90a56e |
+ String.spaces indent ^ sprintf "namespace '%s':\n" k ^
|
|
|
90a56e |
+ to_string (indent+4) vmx
|
|
|
90a56e |
+
|
|
|
90a56e |
+(* Access keys in the tree. *)
|
|
|
90a56e |
+let rec get_string vmx = function
|
|
|
90a56e |
+ | [] -> None
|
|
|
90a56e |
+ | [k] ->
|
|
|
90a56e |
+ let k = String.lowercase_ascii k in
|
|
|
90a56e |
+ (try
|
|
|
90a56e |
+ let v = StringMap.find k vmx in
|
|
|
90a56e |
+ match v with
|
|
|
90a56e |
+ | Key v -> Some v
|
|
|
90a56e |
+ | Namespace _ -> None
|
|
|
90a56e |
+ with Not_found -> None
|
|
|
90a56e |
+ )
|
|
|
90a56e |
+ | ns :: path ->
|
|
|
90a56e |
+ let ns = String.lowercase_ascii ns in
|
|
|
90a56e |
+ (try
|
|
|
90a56e |
+ let v = StringMap.find ns vmx in
|
|
|
90a56e |
+ match v with
|
|
|
90a56e |
+ | Key v -> None
|
|
|
90a56e |
+ | Namespace vmx -> get_string vmx path
|
|
|
90a56e |
+ with
|
|
|
90a56e |
+ Not_found -> None
|
|
|
90a56e |
+ )
|
|
|
90a56e |
+
|
|
|
90a56e |
+let get_int64 vmx path =
|
|
|
90a56e |
+ match get_string vmx path with
|
|
|
90a56e |
+ | None -> None
|
|
|
90a56e |
+ | Some i -> Some (Int64.of_string i)
|
|
|
90a56e |
+
|
|
|
90a56e |
+let get_int vmx path =
|
|
|
90a56e |
+ match get_string vmx path with
|
|
|
90a56e |
+ | None -> None
|
|
|
90a56e |
+ | Some i -> Some (int_of_string i)
|
|
|
90a56e |
+
|
|
|
90a56e |
+let rec get_bool vmx path =
|
|
|
90a56e |
+ match get_string vmx path with
|
|
|
90a56e |
+ | None -> None
|
|
|
90a56e |
+ | Some t -> Some (vmx_bool_of_string t)
|
|
|
90a56e |
+
|
|
|
90a56e |
+and vmx_bool_of_string t =
|
|
|
90a56e |
+ if String.lowercase_ascii t = "true" then true
|
|
|
90a56e |
+ else if String.lowercase_ascii t = "false" then false
|
|
|
90a56e |
+ else failwith "bool_of_string"
|
|
|
90a56e |
+
|
|
|
90a56e |
+(* Regular expression used to match key = "value" in VMX file. *)
|
|
|
90a56e |
+let rex = Str.regexp "^\\([^ \t=]+\\)[ \t]*=[ \t]*\"\\(.*\\)\"$"
|
|
|
90a56e |
+
|
|
|
90a56e |
+(* Remove the weird escapes used in value strings. See description above. *)
|
|
|
90a56e |
+let remove_vmx_escapes str =
|
|
|
90a56e |
+ let len = String.length str in
|
|
|
90a56e |
+ let out = Bytes.make len '\000' in
|
|
|
90a56e |
+ let j = ref 0 in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ let rec loop i =
|
|
|
90a56e |
+ if i >= len then ()
|
|
|
90a56e |
+ else (
|
|
|
90a56e |
+ let c = String.unsafe_get str i in
|
|
|
90a56e |
+ if i <= len-3 && c = '|' then (
|
|
|
90a56e |
+ let c1 = str.[i+1] and c2 = str.[i+2] in
|
|
|
90a56e |
+ if Char.isxdigit c1 && Char.isxdigit c2 then (
|
|
|
90a56e |
+ let x = Char.hexdigit c1 * 0x10 + Char.hexdigit c2 in
|
|
|
90a56e |
+ Bytes.set out !j (Char.chr x);
|
|
|
90a56e |
+ incr j;
|
|
|
90a56e |
+ loop (i+3)
|
|
|
90a56e |
+ )
|
|
|
90a56e |
+ else (
|
|
|
90a56e |
+ Bytes.set out !j c;
|
|
|
90a56e |
+ incr j;
|
|
|
90a56e |
+ loop (i+1)
|
|
|
90a56e |
+ )
|
|
|
90a56e |
+ )
|
|
|
90a56e |
+ else (
|
|
|
90a56e |
+ Bytes.set out !j c;
|
|
|
90a56e |
+ incr j;
|
|
|
90a56e |
+ loop (i+1)
|
|
|
90a56e |
+ )
|
|
|
90a56e |
+ )
|
|
|
90a56e |
+ in
|
|
|
90a56e |
+ loop 0;
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* Truncate the output string to its real size and return it
|
|
|
90a56e |
+ * as an immutable string.
|
|
|
90a56e |
+ *)
|
|
|
90a56e |
+ Bytes.sub_string out 0 !j
|
|
|
90a56e |
+
|
|
|
90a56e |
+(* Parsing. *)
|
|
|
90a56e |
+let rec parse_file vmx_filename =
|
|
|
90a56e |
+ (* Read the whole file as a list of lines. *)
|
|
|
90a56e |
+ let str = read_whole_file vmx_filename in
|
|
|
90a56e |
+ if verbose () then eprintf "VMX file:\n%s\n" str;
|
|
|
90a56e |
+ parse_string str
|
|
|
90a56e |
+
|
|
|
90a56e |
+and parse_string str =
|
|
|
90a56e |
+ let lines = String.nsplit "\n" str in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* I've never seen any VMX file with CR-LF endings, and VMware
|
|
|
90a56e |
+ * itself is Linux-based, but to be on the safe side ...
|
|
|
90a56e |
+ *)
|
|
|
90a56e |
+ let lines = List.map (String.trimr ~test:((=) '\r')) lines in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* Ignore blank lines and comments. *)
|
|
|
90a56e |
+ let lines = List.filter (
|
|
|
90a56e |
+ fun line ->
|
|
|
90a56e |
+ let line = String.triml line in
|
|
|
90a56e |
+ let len = String.length line in
|
|
|
90a56e |
+ len > 0 && line.[0] != '#'
|
|
|
90a56e |
+ ) lines in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* Parse the lines into key = "value". *)
|
|
|
90a56e |
+ let lines = filter_map (
|
|
|
90a56e |
+ fun line ->
|
|
|
90a56e |
+ if Str.string_match rex line 0 then (
|
|
|
90a56e |
+ let key = Str.matched_group 1 line in
|
|
|
90a56e |
+ let key = String.lowercase_ascii key in
|
|
|
90a56e |
+ let value = Str.matched_group 2 line in
|
|
|
90a56e |
+ let value = remove_vmx_escapes value in
|
|
|
90a56e |
+ Some (key, value)
|
|
|
90a56e |
+ )
|
|
|
90a56e |
+ else (
|
|
|
90a56e |
+ warning (f_"vmx parser: cannot parse this line, ignoring: %s") line;
|
|
|
90a56e |
+ None
|
|
|
90a56e |
+ )
|
|
|
90a56e |
+ ) lines in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* Split the keys into namespace paths. *)
|
|
|
90a56e |
+ let lines =
|
|
|
90a56e |
+ List.map (fun (key, value) -> String.nsplit "." key, value) lines in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* Build a tree from the flat list and return it. This is horribly
|
|
|
90a56e |
+ * inefficient, at least O(n²), possibly even O(n².log n). Hope
|
|
|
90a56e |
+ * there are no large VMX files! (XXX)
|
|
|
90a56e |
+ *)
|
|
|
90a56e |
+ let vmx =
|
|
|
90a56e |
+ List.fold_left (
|
|
|
90a56e |
+ fun vmx (path, value) -> insert vmx value path
|
|
|
90a56e |
+ ) empty lines in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* If we're verbose, dump the parsed VMX for debugging purposes. *)
|
|
|
90a56e |
+ if verbose () then (
|
|
|
90a56e |
+ eprintf "parsed VMX tree:\n";
|
|
|
90a56e |
+ print stderr 0 vmx
|
|
|
90a56e |
+ );
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* Drop all present = "FALSE" namespaces. *)
|
|
|
90a56e |
+ let vmx = drop_not_present vmx in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ vmx
|
|
|
90a56e |
+
|
|
|
90a56e |
+and insert vmx value = function
|
|
|
90a56e |
+ | [] -> assert false
|
|
|
90a56e |
+ | [k] ->
|
|
|
90a56e |
+ if StringMap.mem k vmx then (
|
|
|
90a56e |
+ warning (f_"vmx parser: duplicate key '%s' ignored") k;
|
|
|
90a56e |
+ vmx
|
|
|
90a56e |
+ ) else
|
|
|
90a56e |
+ StringMap.add k (Key value) vmx
|
|
|
90a56e |
+ | ns :: path ->
|
|
|
90a56e |
+ let v =
|
|
|
90a56e |
+ try
|
|
|
90a56e |
+ (match StringMap.find ns vmx with
|
|
|
90a56e |
+ | Namespace vmx -> Some vmx
|
|
|
90a56e |
+ | Key _ -> None
|
|
|
90a56e |
+ )
|
|
|
90a56e |
+ with Not_found -> None in
|
|
|
90a56e |
+ let v =
|
|
|
90a56e |
+ match v with
|
|
|
90a56e |
+ | None ->
|
|
|
90a56e |
+ (* Completely new namespace. *)
|
|
|
90a56e |
+ insert empty value path
|
|
|
90a56e |
+ | Some v ->
|
|
|
90a56e |
+ (* Insert the subkey into the previously created namespace. *)
|
|
|
90a56e |
+ insert v value path in
|
|
|
90a56e |
+ StringMap.add ns (Namespace v) vmx
|
|
|
90a56e |
+
|
|
|
90a56e |
+(* Find any "present" keys. If we find present = "FALSE", then
|
|
|
90a56e |
+ * drop the containing namespace and all subkeys and subnamespaces.
|
|
|
90a56e |
+ *)
|
|
|
90a56e |
+and drop_not_present vmx =
|
|
|
90a56e |
+ StringMap.fold (
|
|
|
90a56e |
+ fun k v new_vmx ->
|
|
|
90a56e |
+ match v with
|
|
|
90a56e |
+ | Key _ ->
|
|
|
90a56e |
+ StringMap.add k v new_vmx
|
|
|
90a56e |
+ | Namespace vmx when contains_key_present_false vmx ->
|
|
|
90a56e |
+ (* drop this namespace and all sub-spaces *)
|
|
|
90a56e |
+ new_vmx
|
|
|
90a56e |
+ | Namespace v ->
|
|
|
90a56e |
+ (* recurse into sub-namespace and do the same check *)
|
|
|
90a56e |
+ let v = drop_not_present v in
|
|
|
90a56e |
+ StringMap.add k (Namespace v) new_vmx
|
|
|
90a56e |
+ ) vmx empty
|
|
|
90a56e |
+
|
|
|
90a56e |
+and contains_key_present_false vmx =
|
|
|
90a56e |
+ try
|
|
|
90a56e |
+ match StringMap.find "present" vmx with
|
|
|
90a56e |
+ | Key v when vmx_bool_of_string v = false -> true
|
|
|
90a56e |
+ | Key _ | Namespace _ -> false
|
|
|
90a56e |
+ with
|
|
|
90a56e |
+ Failure _ | Not_found -> false
|
|
|
90a56e |
diff --git a/v2v/parse_vmx.mli b/v2v/parse_vmx.mli
|
|
|
90a56e |
new file mode 100644
|
|
|
46ce2f |
index 000000000..0e4f21f07
|
|
|
90a56e |
--- /dev/null
|
|
|
90a56e |
+++ b/v2v/parse_vmx.mli
|
|
|
90a56e |
@@ -0,0 +1,89 @@
|
|
|
90a56e |
+(* virt-v2v
|
|
|
90a56e |
+ * Copyright (C) 2017 Red Hat Inc.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * This program is free software; you can redistribute it and/or modify
|
|
|
90a56e |
+ * it under the terms of the GNU General Public License as published by
|
|
|
90a56e |
+ * the Free Software Foundation; either version 2 of the License, or
|
|
|
90a56e |
+ * (at your option) any later version.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * This program is distributed in the hope that it will be useful,
|
|
|
90a56e |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
90a56e |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
90a56e |
+ * GNU General Public License for more details.
|
|
|
90a56e |
+ *
|
|
|
90a56e |
+ * You should have received a copy of the GNU General Public License along
|
|
|
90a56e |
+ * with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
90a56e |
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
90a56e |
+ *)
|
|
|
90a56e |
+
|
|
|
90a56e |
+(** A simple parser for VMware [.vmx] files. *)
|
|
|
90a56e |
+
|
|
|
90a56e |
+type t
|
|
|
90a56e |
+
|
|
|
90a56e |
+val parse_file : string -> t
|
|
|
90a56e |
+(** [parse_file filename] parses a VMX file. *)
|
|
|
90a56e |
+
|
|
|
90a56e |
+val parse_string : string -> t
|
|
|
90a56e |
+(** [parse_string s] parses VMX from a string. *)
|
|
|
90a56e |
+
|
|
|
90a56e |
+val get_string : t -> string list -> string option
|
|
|
90a56e |
+(** Find a key and return it as a string. If not present, returns [None].
|
|
|
90a56e |
+
|
|
|
90a56e |
+ Note that if [namespace.present = "FALSE"] is found in the file
|
|
|
90a56e |
+ then all keys in [namespace] and below it are ignored. This
|
|
|
90a56e |
+ applies to all [get_*] functions. *)
|
|
|
90a56e |
+
|
|
|
90a56e |
+val get_int64 : t -> string list -> int64 option
|
|
|
90a56e |
+(** Find a key and return it as an [int64].
|
|
|
90a56e |
+ If not present, returns [None].
|
|
|
90a56e |
+
|
|
|
90a56e |
+ Raises [Failure _] if the key is present but was not parseable
|
|
|
90a56e |
+ as an integer. *)
|
|
|
90a56e |
+
|
|
|
90a56e |
+val get_int : t -> string list -> int option
|
|
|
90a56e |
+(** Find a key and return it as an [int].
|
|
|
90a56e |
+ If not present, returns [None].
|
|
|
90a56e |
+
|
|
|
90a56e |
+ Raises [Failure _] if the key is present but was not parseable
|
|
|
90a56e |
+ as an integer. *)
|
|
|
90a56e |
+
|
|
|
90a56e |
+val get_bool : t -> string list -> bool option
|
|
|
90a56e |
+(** Find a key and return it as a boolean.
|
|
|
90a56e |
+
|
|
|
90a56e |
+ You cannot return [namespace.present = "FALSE"] booleans this way.
|
|
|
90a56e |
+ They are processed by the parser and the namespace and anything
|
|
|
90a56e |
+ below it are removed from the tree.
|
|
|
90a56e |
+
|
|
|
90a56e |
+ Raises [Failure _] if the key is present but was not parseable
|
|
|
90a56e |
+ as a boolean. *)
|
|
|
90a56e |
+
|
|
|
90a56e |
+val namespace_present : t -> string list -> bool
|
|
|
90a56e |
+(** Returns true iff the namespace ({b note:} not key) is present. *)
|
|
|
90a56e |
+
|
|
|
90a56e |
+val select_namespaces : (string list -> bool) -> t -> t
|
|
|
90a56e |
+(** Filter the VMX file, selecting exactly namespaces (and their
|
|
|
90a56e |
+ keys) matching the predicate. The predicate is a function which
|
|
|
90a56e |
+ is called on each {i namespace} path ({b note:} not on
|
|
|
90a56e |
+ namespace + key paths). If the predicate matches a
|
|
|
90a56e |
+ namespace, then all sub-namespaces under that namespace are
|
|
|
90a56e |
+ selected implicitly. *)
|
|
|
90a56e |
+
|
|
|
90a56e |
+val map : (string list -> string option -> 'a) -> t -> 'a list
|
|
|
90a56e |
+(** Map all the entries in the VMX file into a list using the
|
|
|
90a56e |
+ map function. The map function takes two arguments. The
|
|
|
90a56e |
+ first is the path to the namespace or key, and the second
|
|
|
90a56e |
+ is the key value (or [None] if the path refers to a namespace). *)
|
|
|
90a56e |
+
|
|
|
90a56e |
+val equal : t -> t -> bool
|
|
|
90a56e |
+(** Compare two VMX files for equality. This is mainly used for
|
|
|
90a56e |
+ testing the parser. *)
|
|
|
90a56e |
+
|
|
|
90a56e |
+val empty : t
|
|
|
90a56e |
+(** An empty VMX file. *)
|
|
|
90a56e |
+
|
|
|
90a56e |
+val print : out_channel -> int -> t -> unit
|
|
|
90a56e |
+(** [print chan indent] prints the VMX file to the output channel.
|
|
|
90a56e |
+ [indent] is the indentation applied to each line of output. *)
|
|
|
90a56e |
+
|
|
|
90a56e |
+val to_string : int -> t -> string
|
|
|
90a56e |
+(** Same as {!print} but it creates a printable (multiline) string. *)
|
|
|
90a56e |
diff --git a/v2v/test-v2v-i-vmx-1.expected b/v2v/test-v2v-i-vmx-1.expected
|
|
|
90a56e |
new file mode 100644
|
|
|
a30de4 |
index 000000000..c7ef1f5d5
|
|
|
90a56e |
--- /dev/null
|
|
|
90a56e |
+++ b/v2v/test-v2v-i-vmx-1.expected
|
|
|
a30de4 |
@@ -0,0 +1,39 @@
|
|
|
90a56e |
+[ 0.0] Opening the source -i vmx test-v2v-i-vmx-1.vmx
|
|
|
90a56e |
+Source guest information (--print-source option):
|
|
|
90a56e |
+
|
|
|
90a56e |
+ source name: BZ1308535_21disks
|
|
|
90a56e |
+hypervisor type: vmware
|
|
|
90a56e |
+ memory: 2147483648 (bytes)
|
|
|
90a56e |
+ nr vCPUs: 1
|
|
|
90a56e |
+ CPU features:
|
|
|
90a56e |
+ firmware: bios
|
|
|
90a56e |
+ display:
|
|
|
90a56e |
+ video: vmvga
|
|
|
90a56e |
+ sound:
|
|
|
90a56e |
+disks:
|
|
|
90a56e |
+ /BZ1308535_21disks.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+ /BZ1308535_21disks_1.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+ /BZ1308535_21disks_2.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+ /BZ1308535_21disks_3.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+ /BZ1308535_21disks_4.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+ /BZ1308535_21disks_5.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+ /BZ1308535_21disks_6.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+ /BZ1308535_21disks_7.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+ /BZ1308535_21disks_8.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+ /BZ1308535_21disks_9.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+ /BZ1308535_21disks_10.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+ /BZ1308535_21disks_11.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+ /BZ1308535_21disks_12.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+ /BZ1308535_21disks_13.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+ /BZ1308535_21disks_14.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+ /BZ1308535_21disks_15.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+ /BZ1308535_21disks_16.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+ /BZ1308535_21disks_17.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+ /BZ1308535_21disks_18.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+ /BZ1308535_21disks_19.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+ /BZ1308535_21disks_20.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+removable media:
|
|
|
90a56e |
+ CD-ROM [ide] in slot 2
|
|
|
90a56e |
+NICs:
|
|
|
90a56e |
+ Network "VM Network" mac: 00:0c:29:36:ef:31 [vmxnet3]
|
|
|
90a56e |
+
|
|
|
90a56e |
diff --git a/v2v/test-v2v-i-vmx-1.vmx b/v2v/test-v2v-i-vmx-1.vmx
|
|
|
90a56e |
new file mode 100644
|
|
|
46ce2f |
index 000000000..3f2f060a5
|
|
|
90a56e |
--- /dev/null
|
|
|
90a56e |
+++ b/v2v/test-v2v-i-vmx-1.vmx
|
|
|
90a56e |
@@ -0,0 +1,172 @@
|
|
|
90a56e |
+.encoding = "UTF-8"
|
|
|
90a56e |
+config.version = "8"
|
|
|
90a56e |
+virtualHW.version = "8"
|
|
|
90a56e |
+nvram = "BZ1308535_21disks.nvram"
|
|
|
90a56e |
+pciBridge0.present = "TRUE"
|
|
|
90a56e |
+svga.present = "TRUE"
|
|
|
90a56e |
+pciBridge4.present = "TRUE"
|
|
|
90a56e |
+pciBridge4.virtualDev = "pcieRootPort"
|
|
|
90a56e |
+pciBridge4.functions = "8"
|
|
|
90a56e |
+pciBridge5.present = "TRUE"
|
|
|
90a56e |
+pciBridge5.virtualDev = "pcieRootPort"
|
|
|
90a56e |
+pciBridge5.functions = "8"
|
|
|
90a56e |
+pciBridge6.present = "TRUE"
|
|
|
90a56e |
+pciBridge6.virtualDev = "pcieRootPort"
|
|
|
90a56e |
+pciBridge6.functions = "8"
|
|
|
90a56e |
+pciBridge7.present = "TRUE"
|
|
|
90a56e |
+pciBridge7.virtualDev = "pcieRootPort"
|
|
|
90a56e |
+pciBridge7.functions = "8"
|
|
|
90a56e |
+vmci0.present = "TRUE"
|
|
|
90a56e |
+hpet0.present = "TRUE"
|
|
|
90a56e |
+displayName = "BZ1308535_21disks"
|
|
|
90a56e |
+extendedConfigFile = "BZ1308535_21disks.vmxf"
|
|
|
90a56e |
+virtualHW.productCompatibility = "hosted"
|
|
|
90a56e |
+memSize = "2048"
|
|
|
90a56e |
+sched.cpu.units = "mhz"
|
|
|
90a56e |
+powerType.powerOff = "soft"
|
|
|
90a56e |
+powerType.suspend = "hard"
|
|
|
90a56e |
+powerType.reset = "soft"
|
|
|
90a56e |
+scsi0.virtualDev = "pvscsi"
|
|
|
90a56e |
+scsi0.present = "TRUE"
|
|
|
90a56e |
+scsi1.virtualDev = "pvscsi"
|
|
|
90a56e |
+scsi1.present = "TRUE"
|
|
|
90a56e |
+ide1:0.deviceType = "cdrom-image"
|
|
|
90a56e |
+ide1:0.fileName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/ISOs/RHEL-7.1-20150219.1-Server-x86_64-boot.iso"
|
|
|
90a56e |
+ide1:0.present = "TRUE"
|
|
|
90a56e |
+floppy0.startConnected = "FALSE"
|
|
|
90a56e |
+floppy0.clientDevice = "TRUE"
|
|
|
90a56e |
+floppy0.fileName = "vmware-null-remote-floppy"
|
|
|
90a56e |
+ethernet0.virtualDev = "vmxnet3"
|
|
|
90a56e |
+ethernet0.networkName = "VM Network"
|
|
|
90a56e |
+ethernet0.addressType = "generated"
|
|
|
90a56e |
+ethernet0.present = "TRUE"
|
|
|
90a56e |
+scsi0:0.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi0:0.fileName = "BZ1308535_21disks.vmdk"
|
|
|
90a56e |
+scsi0:0.present = "TRUE"
|
|
|
90a56e |
+scsi0:1.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi0:1.fileName = "BZ1308535_21disks_1.vmdk"
|
|
|
90a56e |
+scsi0:1.present = "TRUE"
|
|
|
90a56e |
+scsi0:2.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi0:2.fileName = "BZ1308535_21disks_2.vmdk"
|
|
|
90a56e |
+scsi0:2.present = "TRUE"
|
|
|
90a56e |
+scsi0:3.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi0:3.fileName = "BZ1308535_21disks_3.vmdk"
|
|
|
90a56e |
+scsi0:3.present = "TRUE"
|
|
|
90a56e |
+scsi0:4.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi0:4.fileName = "BZ1308535_21disks_4.vmdk"
|
|
|
90a56e |
+scsi0:4.present = "TRUE"
|
|
|
90a56e |
+scsi0:5.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi0:5.fileName = "BZ1308535_21disks_5.vmdk"
|
|
|
90a56e |
+scsi0:5.present = "TRUE"
|
|
|
90a56e |
+scsi0:6.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi0:6.fileName = "BZ1308535_21disks_6.vmdk"
|
|
|
90a56e |
+scsi0:6.present = "TRUE"
|
|
|
90a56e |
+scsi0:8.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi0:8.fileName = "BZ1308535_21disks_7.vmdk"
|
|
|
90a56e |
+scsi0:8.present = "TRUE"
|
|
|
90a56e |
+scsi0:9.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi0:9.fileName = "BZ1308535_21disks_8.vmdk"
|
|
|
90a56e |
+scsi0:9.present = "TRUE"
|
|
|
90a56e |
+scsi0:10.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi0:10.fileName = "BZ1308535_21disks_9.vmdk"
|
|
|
90a56e |
+scsi0:10.present = "TRUE"
|
|
|
90a56e |
+scsi0:11.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi0:11.fileName = "BZ1308535_21disks_10.vmdk"
|
|
|
90a56e |
+scsi0:11.present = "TRUE"
|
|
|
90a56e |
+scsi0:12.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi0:12.fileName = "BZ1308535_21disks_11.vmdk"
|
|
|
90a56e |
+scsi0:12.present = "TRUE"
|
|
|
90a56e |
+scsi0:13.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi0:13.fileName = "BZ1308535_21disks_12.vmdk"
|
|
|
90a56e |
+scsi0:13.present = "TRUE"
|
|
|
90a56e |
+scsi0:14.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi0:14.fileName = "BZ1308535_21disks_13.vmdk"
|
|
|
90a56e |
+scsi0:14.present = "TRUE"
|
|
|
90a56e |
+scsi0:15.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi0:15.fileName = "BZ1308535_21disks_14.vmdk"
|
|
|
90a56e |
+scsi0:15.present = "TRUE"
|
|
|
90a56e |
+scsi1:0.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi1:0.fileName = "BZ1308535_21disks_15.vmdk"
|
|
|
90a56e |
+scsi1:0.present = "TRUE"
|
|
|
90a56e |
+scsi1:1.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi1:1.fileName = "BZ1308535_21disks_16.vmdk"
|
|
|
90a56e |
+scsi1:1.present = "TRUE"
|
|
|
90a56e |
+scsi1:2.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi1:2.fileName = "BZ1308535_21disks_17.vmdk"
|
|
|
90a56e |
+scsi1:2.present = "TRUE"
|
|
|
90a56e |
+scsi1:3.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi1:3.fileName = "BZ1308535_21disks_18.vmdk"
|
|
|
90a56e |
+scsi1:3.present = "TRUE"
|
|
|
90a56e |
+scsi1:4.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi1:4.fileName = "BZ1308535_21disks_19.vmdk"
|
|
|
90a56e |
+scsi1:4.present = "TRUE"
|
|
|
90a56e |
+scsi1:5.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi1:5.fileName = "BZ1308535_21disks_20.vmdk"
|
|
|
90a56e |
+scsi1:5.present = "TRUE"
|
|
|
90a56e |
+guestOS = "rhel6-64"
|
|
|
90a56e |
+toolScripts.afterPowerOn = "TRUE"
|
|
|
90a56e |
+toolScripts.afterResume = "TRUE"
|
|
|
90a56e |
+toolScripts.beforeSuspend = "TRUE"
|
|
|
90a56e |
+toolScripts.beforePowerOff = "TRUE"
|
|
|
90a56e |
+uuid.bios = "56 4d 96 af e6 46 bd 86-5c 4d 65 4e 77 36 ef 31"
|
|
|
90a56e |
+uuid.location = "56 4d 96 af e6 46 bd 86-5c 4d 65 4e 77 36 ef 31"
|
|
|
90a56e |
+vc.uuid = "52 31 cb fc c1 3f 96 32-83 c0 bb 70 6c 90 5c fd"
|
|
|
90a56e |
+chipset.onlineStandby = "FALSE"
|
|
|
90a56e |
+sched.cpu.min = "0"
|
|
|
90a56e |
+sched.cpu.shares = "normal"
|
|
|
90a56e |
+sched.mem.min = "0"
|
|
|
90a56e |
+sched.mem.minSize = "0"
|
|
|
90a56e |
+sched.mem.shares = "normal"
|
|
|
90a56e |
+svga.vramSize = "8388608"
|
|
|
90a56e |
+sched.swap.derivedName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/BZ1308535_21disks/BZ1308535_21disks-6a024f8a.vswp"
|
|
|
90a56e |
+replay.supported = "FALSE"
|
|
|
90a56e |
+replay.filename = ""
|
|
|
90a56e |
+scsi0:0.redo = ""
|
|
|
90a56e |
+scsi0:1.redo = ""
|
|
|
90a56e |
+scsi0:2.redo = ""
|
|
|
90a56e |
+scsi0:3.redo = ""
|
|
|
90a56e |
+scsi0:4.redo = ""
|
|
|
90a56e |
+scsi0:5.redo = ""
|
|
|
90a56e |
+scsi0:6.redo = ""
|
|
|
90a56e |
+scsi0:8.redo = ""
|
|
|
90a56e |
+scsi0:9.redo = ""
|
|
|
90a56e |
+scsi0:10.redo = ""
|
|
|
90a56e |
+scsi0:11.redo = ""
|
|
|
90a56e |
+scsi0:12.redo = ""
|
|
|
90a56e |
+scsi0:13.redo = ""
|
|
|
90a56e |
+scsi0:14.redo = ""
|
|
|
90a56e |
+scsi0:15.redo = ""
|
|
|
90a56e |
+scsi1:0.redo = ""
|
|
|
90a56e |
+scsi1:1.redo = ""
|
|
|
90a56e |
+scsi1:2.redo = ""
|
|
|
90a56e |
+scsi1:3.redo = ""
|
|
|
90a56e |
+scsi1:4.redo = ""
|
|
|
90a56e |
+scsi1:5.redo = ""
|
|
|
90a56e |
+pciBridge0.pciSlotNumber = "17"
|
|
|
90a56e |
+pciBridge4.pciSlotNumber = "21"
|
|
|
90a56e |
+pciBridge5.pciSlotNumber = "22"
|
|
|
90a56e |
+pciBridge6.pciSlotNumber = "23"
|
|
|
90a56e |
+pciBridge7.pciSlotNumber = "24"
|
|
|
90a56e |
+scsi0.pciSlotNumber = "160"
|
|
|
90a56e |
+scsi1.pciSlotNumber = "192"
|
|
|
90a56e |
+ethernet0.pciSlotNumber = "224"
|
|
|
90a56e |
+vmci0.pciSlotNumber = "32"
|
|
|
90a56e |
+scsi0.sasWWID = "50 05 05 6f e6 46 bd 80"
|
|
|
90a56e |
+scsi1.sasWWID = "50 05 05 6f e6 46 bc 80"
|
|
|
90a56e |
+ethernet0.generatedAddress = "00:0c:29:36:ef:31"
|
|
|
90a56e |
+ethernet0.generatedAddressOffset = "0"
|
|
|
90a56e |
+vmci0.id = "2000088881"
|
|
|
90a56e |
+hostCPUID.0 = "0000000d756e65476c65746e49656e69"
|
|
|
90a56e |
+hostCPUID.1 = "000206a700100800179ae3bfbfebfbff"
|
|
|
90a56e |
+hostCPUID.80000001 = "00000000000000000000000128100800"
|
|
|
90a56e |
+guestCPUID.0 = "0000000d756e65476c65746e49656e69"
|
|
|
90a56e |
+guestCPUID.1 = "000206a700010800969822030fabfbff"
|
|
|
90a56e |
+guestCPUID.80000001 = "00000000000000000000000128100800"
|
|
|
90a56e |
+userCPUID.0 = "0000000d756e65476c65746e49656e69"
|
|
|
90a56e |
+userCPUID.1 = "000206a700100800169822030fabfbff"
|
|
|
90a56e |
+userCPUID.80000001 = "00000000000000000000000128100800"
|
|
|
90a56e |
+evcCompatibilityMode = "FALSE"
|
|
|
90a56e |
+vmotion.checkpointFBSize = "8388608"
|
|
|
90a56e |
+cleanShutdown = "TRUE"
|
|
|
90a56e |
+softPowerOff = "TRUE"
|
|
|
90a56e |
+tools.remindInstall = "TRUE"
|
|
|
90a56e |
diff --git a/v2v/test-v2v-i-vmx-2.expected b/v2v/test-v2v-i-vmx-2.expected
|
|
|
90a56e |
new file mode 100644
|
|
|
a30de4 |
index 000000000..a04bd0f62
|
|
|
90a56e |
--- /dev/null
|
|
|
90a56e |
+++ b/v2v/test-v2v-i-vmx-2.expected
|
|
|
a30de4 |
@@ -0,0 +1,19 @@
|
|
|
90a56e |
+[ 0.0] Opening the source -i vmx test-v2v-i-vmx-2.vmx
|
|
|
90a56e |
+Source guest information (--print-source option):
|
|
|
90a56e |
+
|
|
|
90a56e |
+ source name: Fedora 20
|
|
|
90a56e |
+hypervisor type: vmware
|
|
|
90a56e |
+ memory: 2147483648 (bytes)
|
|
|
90a56e |
+ nr vCPUs: 1
|
|
|
90a56e |
+ CPU features:
|
|
|
90a56e |
+ firmware: bios
|
|
|
90a56e |
+ display:
|
|
|
90a56e |
+ video: vmvga
|
|
|
90a56e |
+ sound:
|
|
|
90a56e |
+disks:
|
|
|
90a56e |
+ /Fedora 20.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+removable media:
|
|
|
90a56e |
+
|
|
|
90a56e |
+NICs:
|
|
|
90a56e |
+ Network "VM Network" mac: 00:50:56:9b:5f:0d [vmxnet3]
|
|
|
90a56e |
+
|
|
|
90a56e |
diff --git a/v2v/test-v2v-i-vmx-2.vmx b/v2v/test-v2v-i-vmx-2.vmx
|
|
|
90a56e |
new file mode 100644
|
|
|
46ce2f |
index 000000000..d9dcf3a5c
|
|
|
90a56e |
--- /dev/null
|
|
|
90a56e |
+++ b/v2v/test-v2v-i-vmx-2.vmx
|
|
|
90a56e |
@@ -0,0 +1,84 @@
|
|
|
90a56e |
+.encoding = "UTF-8"
|
|
|
90a56e |
+config.version = "8"
|
|
|
90a56e |
+virtualHW.version = "10"
|
|
|
90a56e |
+nvram = "Fedora 20.nvram"
|
|
|
90a56e |
+pciBridge0.present = "TRUE"
|
|
|
90a56e |
+svga.present = "TRUE"
|
|
|
90a56e |
+pciBridge4.present = "TRUE"
|
|
|
90a56e |
+pciBridge4.virtualDev = "pcieRootPort"
|
|
|
90a56e |
+pciBridge4.functions = "8"
|
|
|
90a56e |
+pciBridge5.present = "TRUE"
|
|
|
90a56e |
+pciBridge5.virtualDev = "pcieRootPort"
|
|
|
90a56e |
+pciBridge5.functions = "8"
|
|
|
90a56e |
+pciBridge6.present = "TRUE"
|
|
|
90a56e |
+pciBridge6.virtualDev = "pcieRootPort"
|
|
|
90a56e |
+pciBridge6.functions = "8"
|
|
|
90a56e |
+pciBridge7.present = "TRUE"
|
|
|
90a56e |
+pciBridge7.virtualDev = "pcieRootPort"
|
|
|
90a56e |
+pciBridge7.functions = "8"
|
|
|
90a56e |
+vmci0.present = "TRUE"
|
|
|
90a56e |
+hpet0.present = "TRUE"
|
|
|
90a56e |
+displayName = "Fedora 20"
|
|
|
90a56e |
+extendedConfigFile = "Fedora 20.vmxf"
|
|
|
90a56e |
+virtualHW.productCompatibility = "hosted"
|
|
|
90a56e |
+svga.vramSize = "8388608"
|
|
|
90a56e |
+memSize = "2048"
|
|
|
90a56e |
+sched.cpu.units = "mhz"
|
|
|
90a56e |
+sched.cpu.affinity = "all"
|
|
|
90a56e |
+powerType.powerOff = "soft"
|
|
|
90a56e |
+powerType.suspend = "hard"
|
|
|
90a56e |
+powerType.reset = "soft"
|
|
|
90a56e |
+scsi0.virtualDev = "pvscsi"
|
|
|
90a56e |
+scsi0.present = "TRUE"
|
|
|
90a56e |
+sata0.present = "TRUE"
|
|
|
90a56e |
+scsi0:0.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi0:0.fileName = "Fedora 20.vmdk"
|
|
|
90a56e |
+sched.scsi0:0.shares = "normal"
|
|
|
90a56e |
+sched.scsi0:0.throughputCap = "off"
|
|
|
90a56e |
+scsi0:0.present = "TRUE"
|
|
|
90a56e |
+ethernet0.virtualDev = "vmxnet3"
|
|
|
90a56e |
+ethernet0.networkName = "VM Network"
|
|
|
90a56e |
+ethernet0.addressType = "vpx"
|
|
|
90a56e |
+ethernet0.generatedAddress = "00:50:56:9b:5f:0d"
|
|
|
90a56e |
+ethernet0.present = "TRUE"
|
|
|
90a56e |
+sata0:0.startConnected = "FALSE"
|
|
|
90a56e |
+sata0:0.deviceType = "cdrom-image"
|
|
|
90a56e |
+sata0:0.fileName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/ISOs/Fedora-20-x86_64-netinst.iso"
|
|
|
90a56e |
+sata0:0.present = "TRUE"
|
|
|
90a56e |
+floppy0.startConnected = "FALSE"
|
|
|
90a56e |
+floppy0.clientDevice = "TRUE"
|
|
|
90a56e |
+floppy0.fileName = "vmware-null-remote-floppy"
|
|
|
90a56e |
+vmci.filter.enable = "TRUE"
|
|
|
90a56e |
+guestOS = "rhel7-64"
|
|
|
90a56e |
+toolScripts.afterPowerOn = "TRUE"
|
|
|
90a56e |
+toolScripts.afterResume = "TRUE"
|
|
|
90a56e |
+toolScripts.beforeSuspend = "TRUE"
|
|
|
90a56e |
+toolScripts.beforePowerOff = "TRUE"
|
|
|
90a56e |
+uuid.bios = "42 1b 4b 87 e6 b7 d8 81-07 a0 c9 d2 21 cd 3c 6b"
|
|
|
90a56e |
+vc.uuid = "50 1b 1f 1b 73 00 32 bf-93 a1 1c b2 b4 e6 17 d6"
|
|
|
90a56e |
+sched.cpu.min = "0"
|
|
|
90a56e |
+sched.cpu.shares = "normal"
|
|
|
90a56e |
+sched.mem.min = "0"
|
|
|
90a56e |
+sched.mem.minSize = "0"
|
|
|
90a56e |
+sched.mem.shares = "normal"
|
|
|
90a56e |
+sched.swap.derivedName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/Fedora 20/Fedora 20-c71e4118.vswp"
|
|
|
90a56e |
+uuid.location = "56 4d 0f 53 00 63 d5 55-41 01 4c f7 55 ce 03 0e"
|
|
|
90a56e |
+replay.supported = "TRUE"
|
|
|
90a56e |
+replay.filename = ""
|
|
|
90a56e |
+scsi0:0.redo = ""
|
|
|
90a56e |
+pciBridge0.pciSlotNumber = "17"
|
|
|
90a56e |
+pciBridge4.pciSlotNumber = "21"
|
|
|
90a56e |
+pciBridge5.pciSlotNumber = "22"
|
|
|
90a56e |
+pciBridge6.pciSlotNumber = "23"
|
|
|
90a56e |
+pciBridge7.pciSlotNumber = "24"
|
|
|
90a56e |
+scsi0.pciSlotNumber = "160"
|
|
|
90a56e |
+ethernet0.pciSlotNumber = "192"
|
|
|
90a56e |
+vmci0.pciSlotNumber = "32"
|
|
|
90a56e |
+sata0.pciSlotNumber = "33"
|
|
|
90a56e |
+scsi0.sasWWID = "50 05 05 67 e6 b7 d8 80"
|
|
|
90a56e |
+vmci0.id = "567098475"
|
|
|
90a56e |
+vmotion.checkpointFBSize = "8388608"
|
|
|
90a56e |
+cleanShutdown = "TRUE"
|
|
|
90a56e |
+softPowerOff = "TRUE"
|
|
|
90a56e |
+sata0:0.allowGuestConnectionControl = "TRUE"
|
|
|
90a56e |
+tools.syncTime = "FALSE"
|
|
|
90a56e |
diff --git a/v2v/test-v2v-i-vmx-3.expected b/v2v/test-v2v-i-vmx-3.expected
|
|
|
90a56e |
new file mode 100644
|
|
|
a30de4 |
index 000000000..64808a77b
|
|
|
90a56e |
--- /dev/null
|
|
|
90a56e |
+++ b/v2v/test-v2v-i-vmx-3.expected
|
|
|
a30de4 |
@@ -0,0 +1,19 @@
|
|
|
90a56e |
+[ 0.0] Opening the source -i vmx test-v2v-i-vmx-3.vmx
|
|
|
90a56e |
+Source guest information (--print-source option):
|
|
|
90a56e |
+
|
|
|
90a56e |
+ source name: RHEL 7.1 UEFI
|
|
|
90a56e |
+hypervisor type: vmware
|
|
|
90a56e |
+ memory: 2147483648 (bytes)
|
|
|
90a56e |
+ nr vCPUs: 1
|
|
|
90a56e |
+ CPU features:
|
|
|
90a56e |
+ firmware: uefi
|
|
|
90a56e |
+ display:
|
|
|
90a56e |
+ video: vmvga
|
|
|
90a56e |
+ sound:
|
|
|
90a56e |
+disks:
|
|
|
90a56e |
+ /RHEL 7.1 UEFI.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+removable media:
|
|
|
90a56e |
+ CD-ROM [ide] in slot 2
|
|
|
90a56e |
+NICs:
|
|
|
90a56e |
+ Network "VM Network" mac: 00:0c:29:4b:2b:8c [vmxnet3]
|
|
|
90a56e |
+
|
|
|
90a56e |
diff --git a/v2v/test-v2v-i-vmx-3.vmx b/v2v/test-v2v-i-vmx-3.vmx
|
|
|
90a56e |
new file mode 100644
|
|
|
46ce2f |
index 000000000..c39215555
|
|
|
90a56e |
--- /dev/null
|
|
|
90a56e |
+++ b/v2v/test-v2v-i-vmx-3.vmx
|
|
|
90a56e |
@@ -0,0 +1,91 @@
|
|
|
90a56e |
+.encoding = "UTF-8"
|
|
|
90a56e |
+config.version = "8"
|
|
|
90a56e |
+virtualHW.version = "8"
|
|
|
90a56e |
+nvram = "RHEL 7.1 UEFI.nvram"
|
|
|
90a56e |
+pciBridge0.present = "TRUE"
|
|
|
90a56e |
+svga.present = "TRUE"
|
|
|
90a56e |
+pciBridge4.present = "TRUE"
|
|
|
90a56e |
+pciBridge4.virtualDev = "pcieRootPort"
|
|
|
90a56e |
+pciBridge4.functions = "8"
|
|
|
90a56e |
+pciBridge5.present = "TRUE"
|
|
|
90a56e |
+pciBridge5.virtualDev = "pcieRootPort"
|
|
|
90a56e |
+pciBridge5.functions = "8"
|
|
|
90a56e |
+pciBridge6.present = "TRUE"
|
|
|
90a56e |
+pciBridge6.virtualDev = "pcieRootPort"
|
|
|
90a56e |
+pciBridge6.functions = "8"
|
|
|
90a56e |
+pciBridge7.present = "TRUE"
|
|
|
90a56e |
+pciBridge7.virtualDev = "pcieRootPort"
|
|
|
90a56e |
+pciBridge7.functions = "8"
|
|
|
90a56e |
+vmci0.present = "TRUE"
|
|
|
90a56e |
+hpet0.present = "TRUE"
|
|
|
90a56e |
+displayName = "RHEL 7.1 UEFI"
|
|
|
90a56e |
+extendedConfigFile = "RHEL 7.1 UEFI.vmxf"
|
|
|
90a56e |
+virtualHW.productCompatibility = "hosted"
|
|
|
90a56e |
+memSize = "2048"
|
|
|
90a56e |
+firmware = "efi"
|
|
|
90a56e |
+sched.cpu.units = "mhz"
|
|
|
90a56e |
+powerType.powerOff = "soft"
|
|
|
90a56e |
+powerType.suspend = "hard"
|
|
|
90a56e |
+powerType.reset = "soft"
|
|
|
90a56e |
+scsi0.virtualDev = "pvscsi"
|
|
|
90a56e |
+scsi0.present = "TRUE"
|
|
|
90a56e |
+ide1:0.startConnected = "FALSE"
|
|
|
90a56e |
+ide1:0.deviceType = "cdrom-image"
|
|
|
90a56e |
+ide1:0.fileName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/ISOs/RHEL-7.1-20150219.1-Server-x86_64-boot.iso"
|
|
|
90a56e |
+ide1:0.present = "TRUE"
|
|
|
90a56e |
+floppy0.startConnected = "FALSE"
|
|
|
90a56e |
+floppy0.clientDevice = "TRUE"
|
|
|
90a56e |
+floppy0.fileName = "vmware-null-remote-floppy"
|
|
|
90a56e |
+ethernet0.virtualDev = "vmxnet3"
|
|
|
90a56e |
+ethernet0.networkName = "VM Network"
|
|
|
90a56e |
+ethernet0.addressType = "generated"
|
|
|
90a56e |
+ethernet0.present = "TRUE"
|
|
|
90a56e |
+scsi0:0.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi0:0.fileName = "RHEL 7.1 UEFI.vmdk"
|
|
|
90a56e |
+scsi0:0.present = "TRUE"
|
|
|
90a56e |
+guestOS = "rhel6-64"
|
|
|
90a56e |
+toolScripts.afterPowerOn = "TRUE"
|
|
|
90a56e |
+toolScripts.afterResume = "TRUE"
|
|
|
90a56e |
+toolScripts.beforeSuspend = "TRUE"
|
|
|
90a56e |
+toolScripts.beforePowerOff = "TRUE"
|
|
|
90a56e |
+uuid.bios = "56 4d 99 89 a7 21 91 0d-cc 28 e2 db d5 4b 2b 8c"
|
|
|
90a56e |
+uuid.location = "56 4d 99 89 a7 21 91 0d-cc 28 e2 db d5 4b 2b 8c"
|
|
|
90a56e |
+vc.uuid = "52 3f 29 10 d3 81 16 43-fa b0 e3 af 3b ba 36 e5"
|
|
|
90a56e |
+chipset.onlineStandby = "FALSE"
|
|
|
90a56e |
+sched.cpu.min = "0"
|
|
|
90a56e |
+sched.cpu.shares = "normal"
|
|
|
90a56e |
+sched.mem.min = "0"
|
|
|
90a56e |
+sched.mem.minSize = "0"
|
|
|
90a56e |
+sched.mem.shares = "normal"
|
|
|
90a56e |
+svga.vramSize = "8388608"
|
|
|
90a56e |
+sched.swap.derivedName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/RHEL 7.1 UEFI/RHEL 7.1 UEFI-58ff6e6f.vswp"
|
|
|
90a56e |
+replay.supported = "FALSE"
|
|
|
90a56e |
+replay.filename = ""
|
|
|
90a56e |
+scsi0:0.redo = ""
|
|
|
90a56e |
+pciBridge0.pciSlotNumber = "17"
|
|
|
90a56e |
+pciBridge4.pciSlotNumber = "21"
|
|
|
90a56e |
+pciBridge5.pciSlotNumber = "22"
|
|
|
90a56e |
+pciBridge6.pciSlotNumber = "23"
|
|
|
90a56e |
+pciBridge7.pciSlotNumber = "24"
|
|
|
90a56e |
+scsi0.pciSlotNumber = "160"
|
|
|
90a56e |
+ethernet0.pciSlotNumber = "192"
|
|
|
90a56e |
+vmci0.pciSlotNumber = "32"
|
|
|
90a56e |
+scsi0.sasWWID = "50 05 05 69 a7 21 91 00"
|
|
|
90a56e |
+ethernet0.generatedAddress = "00:0c:29:4b:2b:8c"
|
|
|
90a56e |
+ethernet0.generatedAddressOffset = "0"
|
|
|
90a56e |
+vmci0.id = "-716493940"
|
|
|
90a56e |
+hostCPUID.0 = "0000000d756e65476c65746e49656e69"
|
|
|
90a56e |
+hostCPUID.1 = "000206a700100800179ae3bfbfebfbff"
|
|
|
90a56e |
+hostCPUID.80000001 = "00000000000000000000000128100800"
|
|
|
90a56e |
+guestCPUID.0 = "0000000d756e65476c65746e49656e69"
|
|
|
90a56e |
+guestCPUID.1 = "000206a700010800969822030fabfbff"
|
|
|
90a56e |
+guestCPUID.80000001 = "00000000000000000000000128100800"
|
|
|
90a56e |
+userCPUID.0 = "0000000d756e65476c65746e49656e69"
|
|
|
90a56e |
+userCPUID.1 = "000206a700100800169822030fabfbff"
|
|
|
90a56e |
+userCPUID.80000001 = "00000000000000000000000128100800"
|
|
|
90a56e |
+evcCompatibilityMode = "FALSE"
|
|
|
90a56e |
+vmotion.checkpointFBSize = "8388608"
|
|
|
90a56e |
+cleanShutdown = "TRUE"
|
|
|
90a56e |
+softPowerOff = "TRUE"
|
|
|
90a56e |
+ide1:0.allowGuestConnectionControl = "TRUE"
|
|
|
90a56e |
+tools.syncTime = "FALSE"
|
|
|
90a56e |
diff --git a/v2v/test-v2v-i-vmx-4.expected b/v2v/test-v2v-i-vmx-4.expected
|
|
|
90a56e |
new file mode 100644
|
|
|
a30de4 |
index 000000000..208920b29
|
|
|
90a56e |
--- /dev/null
|
|
|
90a56e |
+++ b/v2v/test-v2v-i-vmx-4.expected
|
|
|
a30de4 |
@@ -0,0 +1,19 @@
|
|
|
90a56e |
+[ 0.0] Opening the source -i vmx test-v2v-i-vmx-4.vmx
|
|
|
90a56e |
+Source guest information (--print-source option):
|
|
|
90a56e |
+
|
|
|
90a56e |
+ source name: Windows 7 x64
|
|
|
90a56e |
+hypervisor type: vmware
|
|
|
90a56e |
+ memory: 2147483648 (bytes)
|
|
|
90a56e |
+ nr vCPUs: 1
|
|
|
90a56e |
+ CPU features:
|
|
|
90a56e |
+ firmware: bios
|
|
|
90a56e |
+ display:
|
|
|
90a56e |
+ video: vmvga
|
|
|
90a56e |
+ sound:
|
|
|
90a56e |
+disks:
|
|
|
90a56e |
+ /Windows 7 x64.vmdk (vmdk) [scsi]
|
|
|
90a56e |
+removable media:
|
|
|
90a56e |
+ CD-ROM [ide] in slot 2
|
|
|
90a56e |
+NICs:
|
|
|
90a56e |
+ Network "VM Network" mac: 00:0c:29:94:89:23 [e1000]
|
|
|
90a56e |
+
|
|
|
90a56e |
diff --git a/v2v/test-v2v-i-vmx-4.vmx b/v2v/test-v2v-i-vmx-4.vmx
|
|
|
90a56e |
new file mode 100644
|
|
|
46ce2f |
index 000000000..7756cf248
|
|
|
90a56e |
--- /dev/null
|
|
|
90a56e |
+++ b/v2v/test-v2v-i-vmx-4.vmx
|
|
|
90a56e |
@@ -0,0 +1,88 @@
|
|
|
90a56e |
+.encoding = "UTF-8"
|
|
|
90a56e |
+config.version = "8"
|
|
|
90a56e |
+virtualHW.version = "8"
|
|
|
90a56e |
+nvram = "Windows 7 x64.nvram"
|
|
|
90a56e |
+pciBridge0.present = "TRUE"
|
|
|
90a56e |
+svga.present = "TRUE"
|
|
|
90a56e |
+pciBridge4.present = "TRUE"
|
|
|
90a56e |
+pciBridge4.virtualDev = "pcieRootPort"
|
|
|
90a56e |
+pciBridge4.functions = "8"
|
|
|
90a56e |
+pciBridge5.present = "TRUE"
|
|
|
90a56e |
+pciBridge5.virtualDev = "pcieRootPort"
|
|
|
90a56e |
+pciBridge5.functions = "8"
|
|
|
90a56e |
+pciBridge6.present = "TRUE"
|
|
|
90a56e |
+pciBridge6.virtualDev = "pcieRootPort"
|
|
|
90a56e |
+pciBridge6.functions = "8"
|
|
|
90a56e |
+pciBridge7.present = "TRUE"
|
|
|
90a56e |
+pciBridge7.virtualDev = "pcieRootPort"
|
|
|
90a56e |
+pciBridge7.functions = "8"
|
|
|
90a56e |
+vmci0.present = "TRUE"
|
|
|
90a56e |
+hpet0.present = "TRUE"
|
|
|
90a56e |
+displayName = "Windows 7 x64"
|
|
|
90a56e |
+extendedConfigFile = "Windows 7 x64.vmxf"
|
|
|
90a56e |
+virtualHW.productCompatibility = "hosted"
|
|
|
90a56e |
+memSize = "2048"
|
|
|
90a56e |
+sched.cpu.units = "mhz"
|
|
|
90a56e |
+powerType.powerOff = "soft"
|
|
|
90a56e |
+powerType.suspend = "hard"
|
|
|
90a56e |
+powerType.reset = "soft"
|
|
|
90a56e |
+scsi0.virtualDev = "lsisas1068"
|
|
|
90a56e |
+scsi0.present = "TRUE"
|
|
|
90a56e |
+ide1:0.deviceType = "cdrom-image"
|
|
|
90a56e |
+ide1:0.fileName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/ISOs/en_windows_7_ultimate_with_sp1_x64_dvd_u_677332.iso"
|
|
|
90a56e |
+ide1:0.present = "TRUE"
|
|
|
90a56e |
+floppy0.startConnected = "FALSE"
|
|
|
90a56e |
+floppy0.clientDevice = "TRUE"
|
|
|
90a56e |
+floppy0.fileName = "vmware-null-remote-floppy"
|
|
|
90a56e |
+ethernet0.virtualDev = "e1000"
|
|
|
90a56e |
+ethernet0.networkName = "VM Network"
|
|
|
90a56e |
+ethernet0.addressType = "generated"
|
|
|
90a56e |
+ethernet0.present = "TRUE"
|
|
|
90a56e |
+scsi0:0.deviceType = "scsi-hardDisk"
|
|
|
90a56e |
+scsi0:0.fileName = "Windows 7 x64.vmdk"
|
|
|
90a56e |
+scsi0:0.present = "TRUE"
|
|
|
90a56e |
+guestOS = "windows7-64"
|
|
|
90a56e |
+toolScripts.afterPowerOn = "TRUE"
|
|
|
90a56e |
+toolScripts.afterResume = "TRUE"
|
|
|
90a56e |
+toolScripts.beforeSuspend = "TRUE"
|
|
|
90a56e |
+toolScripts.beforePowerOff = "TRUE"
|
|
|
90a56e |
+uuid.bios = "56 4d 6f ca 63 a5 a8 3e-13 ec 73 89 1d 94 89 23"
|
|
|
90a56e |
+uuid.location = "56 4d 6f ca 63 a5 a8 3e-13 ec 73 89 1d 94 89 23"
|
|
|
90a56e |
+vc.uuid = "52 7a 63 e1 2c 2f 50 46-91 66 3a e8 fa f9 c4 65"
|
|
|
90a56e |
+chipset.onlineStandby = "FALSE"
|
|
|
90a56e |
+sched.cpu.min = "0"
|
|
|
90a56e |
+sched.cpu.shares = "normal"
|
|
|
90a56e |
+sched.mem.min = "0"
|
|
|
90a56e |
+sched.mem.minSize = "0"
|
|
|
90a56e |
+sched.mem.shares = "normal"
|
|
|
90a56e |
+svga.vramSize = "8388608"
|
|
|
90a56e |
+sched.swap.derivedName = "/vmfs/volumes/5458b680-34ec3500-9f36-001320f5f6ca/Windows 7 x64/Windows 7 x64-8e3b0929.vswp"
|
|
|
90a56e |
+replay.supported = "FALSE"
|
|
|
90a56e |
+replay.filename = ""
|
|
|
90a56e |
+scsi0:0.redo = ""
|
|
|
90a56e |
+pciBridge0.pciSlotNumber = "17"
|
|
|
90a56e |
+pciBridge4.pciSlotNumber = "21"
|
|
|
90a56e |
+pciBridge5.pciSlotNumber = "22"
|
|
|
90a56e |
+pciBridge6.pciSlotNumber = "23"
|
|
|
90a56e |
+pciBridge7.pciSlotNumber = "24"
|
|
|
90a56e |
+scsi0.pciSlotNumber = "160"
|
|
|
90a56e |
+ethernet0.pciSlotNumber = "32"
|
|
|
90a56e |
+vmci0.pciSlotNumber = "33"
|
|
|
90a56e |
+scsi0.sasWWID = "50 05 05 6a 63 a5 a8 30"
|
|
|
90a56e |
+ethernet0.generatedAddress = "00:0c:29:94:89:23"
|
|
|
90a56e |
+ethernet0.generatedAddressOffset = "0"
|
|
|
90a56e |
+vmci0.id = "496273699"
|
|
|
90a56e |
+hostCPUID.0 = "0000000b756e65476c65746e49656e69"
|
|
|
90a56e |
+hostCPUID.1 = "000206c220200800029ee3ffbfebfbff"
|
|
|
90a56e |
+hostCPUID.80000001 = "0000000000000000000000012c100800"
|
|
|
90a56e |
+guestCPUID.0 = "0000000b756e65476c65746e49656e69"
|
|
|
90a56e |
+guestCPUID.1 = "000206c200010800829822030fabfbff"
|
|
|
90a56e |
+guestCPUID.80000001 = "00000000000000000000000128100800"
|
|
|
90a56e |
+userCPUID.0 = "0000000b756e65476c65746e49656e69"
|
|
|
90a56e |
+userCPUID.1 = "000206c220200800029822030fabfbff"
|
|
|
90a56e |
+userCPUID.80000001 = "00000000000000000000000128100800"
|
|
|
90a56e |
+evcCompatibilityMode = "FALSE"
|
|
|
90a56e |
+vmotion.checkpointFBSize = "8388608"
|
|
|
90a56e |
+cleanShutdown = "TRUE"
|
|
|
90a56e |
+softPowerOff = "TRUE"
|
|
|
90a56e |
+tools.remindInstall = "TRUE"
|
|
|
90a56e |
diff --git a/v2v/test-v2v-i-vmx.sh b/v2v/test-v2v-i-vmx.sh
|
|
|
90a56e |
new file mode 100755
|
|
|
46ce2f |
index 000000000..5353e7e2a
|
|
|
90a56e |
--- /dev/null
|
|
|
90a56e |
+++ b/v2v/test-v2v-i-vmx.sh
|
|
|
90a56e |
@@ -0,0 +1,48 @@
|
|
|
90a56e |
+#!/bin/bash -
|
|
|
90a56e |
+# libguestfs virt-v2v test script
|
|
|
90a56e |
+# Copyright (C) 2017 Red Hat Inc.
|
|
|
90a56e |
+#
|
|
|
90a56e |
+# This program is free software; you can redistribute it and/or modify
|
|
|
90a56e |
+# it under the terms of the GNU General Public License as published by
|
|
|
90a56e |
+# the Free Software Foundation; either version 2 of the License, or
|
|
|
90a56e |
+# (at your option) any later version.
|
|
|
90a56e |
+#
|
|
|
90a56e |
+# This program is distributed in the hope that it will be useful,
|
|
|
90a56e |
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
90a56e |
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
90a56e |
+# GNU General Public License for more details.
|
|
|
90a56e |
+#
|
|
|
90a56e |
+# You should have received a copy of the GNU General Public License
|
|
|
90a56e |
+# along with this program; if not, write to the Free Software
|
|
|
90a56e |
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
90a56e |
+
|
|
|
90a56e |
+# Test -i ova option.
|
|
|
90a56e |
+
|
|
|
90a56e |
+set -e
|
|
|
90a56e |
+
|
|
|
90a56e |
+$TEST_FUNCTIONS
|
|
|
90a56e |
+skip_if_skipped
|
|
|
90a56e |
+skip_if_backend uml
|
|
|
90a56e |
+
|
|
|
90a56e |
+export VIRT_TOOLS_DATA_DIR="$top_srcdir/test-data/fake-virt-tools"
|
|
|
90a56e |
+export VIRTIO_WIN="$top_srcdir/test-data/fake-virtio-win"
|
|
|
90a56e |
+
|
|
|
90a56e |
+rm -f test-v2v-i-vmx-*.actual
|
|
|
90a56e |
+
|
|
|
90a56e |
+for i in 1 2 3 4; do
|
|
|
90a56e |
+ $VG virt-v2v --debug-gc \
|
|
|
90a56e |
+ -i vmx test-v2v-i-vmx-$i.vmx \
|
|
|
90a56e |
+ --print-source > test-v2v-i-vmx-$i.actual
|
|
|
90a56e |
+
|
|
|
90a56e |
+ # Normalize the print-source output.
|
|
|
90a56e |
+ mv test-v2v-i-vmx-$i.actual test-v2v-i-vmx-$i.actual.old
|
|
|
90a56e |
+ sed \
|
|
|
90a56e |
+ -e "s,$(pwd),," \
|
|
|
90a56e |
+ < test-v2v-i-vmx-$i.actual.old > test-v2v-i-vmx-$i.actual
|
|
|
90a56e |
+ rm test-v2v-i-vmx-$i.actual.old
|
|
|
90a56e |
+
|
|
|
90a56e |
+ # Check the output.
|
|
|
90a56e |
+ diff -u test-v2v-i-vmx-$i.expected test-v2v-i-vmx-$i.actual
|
|
|
90a56e |
+done
|
|
|
90a56e |
+
|
|
|
90a56e |
+rm test-v2v-i-vmx-*.actual
|
|
|
90a56e |
diff --git a/v2v/v2v_unit_tests.ml b/v2v/v2v_unit_tests.ml
|
|
|
a30de4 |
index 873610a7c..1b4332a9e 100644
|
|
|
90a56e |
--- a/v2v/v2v_unit_tests.ml
|
|
|
90a56e |
+++ b/v2v/v2v_unit_tests.ml
|
|
|
90a56e |
@@ -787,6 +787,148 @@ let test_qemu_img_supports ctx =
|
|
|
90a56e |
*)
|
|
|
90a56e |
ignore (Utils.qemu_img_supports_offset_and_size ())
|
|
|
90a56e |
|
|
|
90a56e |
+(* Test the VMX file parser in the Parse_vmx module. *)
|
|
|
90a56e |
+let test_vmx_parse_string ctx =
|
|
|
90a56e |
+ let cmp = Parse_vmx.equal in
|
|
|
90a56e |
+ let printer = Parse_vmx.to_string 0 in
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* This should be identical to the empty file. *)
|
|
|
90a56e |
+ let t = Parse_vmx.parse_string "\
|
|
|
90a56e |
+test.foo = \"a\"
|
|
|
90a56e |
+test.bar = \"b\"
|
|
|
90a56e |
+test.present = \"FALSE\"
|
|
|
90a56e |
+" in
|
|
|
90a56e |
+ assert_equal ~cmp ~printer Parse_vmx.empty t;
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* Test weird escapes. *)
|
|
|
90a56e |
+ let t1 = Parse_vmx.parse_string "\
|
|
|
90a56e |
+foo = \"a|20|21b\"
|
|
|
90a56e |
+" in
|
|
|
90a56e |
+ let t2 = Parse_vmx.parse_string "\
|
|
|
90a56e |
+foo = \"a !b\"
|
|
|
90a56e |
+" in
|
|
|
90a56e |
+ assert_equal ~cmp ~printer t1 t2;
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* Test case insensitivity. *)
|
|
|
90a56e |
+ let t1 = Parse_vmx.parse_string "\
|
|
|
90a56e |
+foo = \"abc\"
|
|
|
90a56e |
+" in
|
|
|
90a56e |
+ let t2 = Parse_vmx.parse_string "\
|
|
|
90a56e |
+fOO = \"abc\"
|
|
|
90a56e |
+" in
|
|
|
90a56e |
+ assert_equal ~cmp ~printer t1 t2;
|
|
|
90a56e |
+ let t = Parse_vmx.parse_string "\
|
|
|
90a56e |
+flag = \"true\"
|
|
|
90a56e |
+" in
|
|
|
90a56e |
+ assert_bool "parse_vmx: failed case insensitivity test for booleans #1"
|
|
|
90a56e |
+ (Parse_vmx.get_bool t ["FLAG"] = Some true);
|
|
|
90a56e |
+ let t = Parse_vmx.parse_string "\
|
|
|
90a56e |
+flag = \"TRUE\"
|
|
|
90a56e |
+" in
|
|
|
90a56e |
+ assert_bool "parse_vmx: failed case insensitivity test for booleans #2"
|
|
|
90a56e |
+ (Parse_vmx.get_bool t ["Flag"] = Some true);
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* Missing keys. *)
|
|
|
90a56e |
+ let t = Parse_vmx.parse_string "\
|
|
|
90a56e |
+foo = \"a\"
|
|
|
90a56e |
+" in
|
|
|
90a56e |
+ assert_bool "parse_vmx: failed missing key test"
|
|
|
90a56e |
+ (Parse_vmx.get_string t ["bar"] = None);
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* namespace_present function *)
|
|
|
90a56e |
+ let t = Parse_vmx.parse_string "\
|
|
|
90a56e |
+foo.bar.present = \"TRUE\"
|
|
|
90a56e |
+foo.baz.present = \"FALSE\"
|
|
|
90a56e |
+foo.a.b = \"abc\"
|
|
|
90a56e |
+foo.a.c = \"abc\"
|
|
|
90a56e |
+foo.b = \"abc\"
|
|
|
90a56e |
+foo.c.a = \"abc\"
|
|
|
90a56e |
+foo.c.b = \"abc\"
|
|
|
90a56e |
+" in
|
|
|
90a56e |
+ assert_bool "parse_vmx: namespace_present #1"
|
|
|
90a56e |
+ (Parse_vmx.namespace_present t ["foo"] = true);
|
|
|
90a56e |
+ assert_bool "parse_vmx: namespace_present #2"
|
|
|
90a56e |
+ (Parse_vmx.namespace_present t ["foo"; "bar"] = true);
|
|
|
90a56e |
+ assert_bool "parse_vmx: namespace_present #3"
|
|
|
90a56e |
+ (* this whole namespace should have been culled *)
|
|
|
90a56e |
+ (Parse_vmx.namespace_present t ["foo"; "baz"] = false);
|
|
|
90a56e |
+ assert_bool "parse_vmx: namespace_present #4"
|
|
|
90a56e |
+ (Parse_vmx.namespace_present t ["foo"; "a"] = true);
|
|
|
90a56e |
+ assert_bool "parse_vmx: namespace_present #5"
|
|
|
90a56e |
+ (* this is a key, not a namespace *)
|
|
|
90a56e |
+ (Parse_vmx.namespace_present t ["foo"; "a"; "b"] = false);
|
|
|
90a56e |
+ assert_bool "parse_vmx: namespace_present #6"
|
|
|
90a56e |
+ (Parse_vmx.namespace_present t ["foo"; "b"] = false);
|
|
|
90a56e |
+ assert_bool "parse_vmx: namespace_present #7"
|
|
|
90a56e |
+ (Parse_vmx.namespace_present t ["foo"; "c"] = true);
|
|
|
90a56e |
+ assert_bool "parse_vmx: namespace_present #8"
|
|
|
90a56e |
+ (Parse_vmx.namespace_present t ["foo"; "d"] = false);
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* map function *)
|
|
|
90a56e |
+ let t = Parse_vmx.parse_string "\
|
|
|
90a56e |
+foo.bar.present = \"TRUE\"
|
|
|
90a56e |
+foo.baz.present = \"FALSE\"
|
|
|
90a56e |
+foo.a.b = \"abc\"
|
|
|
90a56e |
+foo.a.c = \"abc\"
|
|
|
90a56e |
+foo.b = \"abc\"
|
|
|
90a56e |
+foo.c.a = \"abc\"
|
|
|
90a56e |
+foo.c.b = \"abc\"
|
|
|
90a56e |
+" in
|
|
|
90a56e |
+ let xs =
|
|
|
90a56e |
+ Parse_vmx.map (
|
|
|
90a56e |
+ fun path ->
|
|
|
90a56e |
+ let path = String.concat "." path in
|
|
|
90a56e |
+ function
|
|
|
90a56e |
+ | None -> sprintf "%s.present = \"true\"\n" path
|
|
|
90a56e |
+ | Some v -> sprintf "%s = \"%s\"\n" path v
|
|
|
90a56e |
+ ) t in
|
|
|
90a56e |
+ let xs = List.sort compare xs in
|
|
|
90a56e |
+ let s = String.concat "" xs in
|
|
|
90a56e |
+ assert_equal ~printer:identity "\
|
|
|
90a56e |
+foo.a.b = \"abc\"
|
|
|
90a56e |
+foo.a.c = \"abc\"
|
|
|
90a56e |
+foo.a.present = \"true\"
|
|
|
90a56e |
+foo.b = \"abc\"
|
|
|
90a56e |
+foo.bar.present = \"TRUE\"
|
|
|
90a56e |
+foo.bar.present = \"true\"
|
|
|
90a56e |
+foo.c.a = \"abc\"
|
|
|
90a56e |
+foo.c.b = \"abc\"
|
|
|
90a56e |
+foo.c.present = \"true\"
|
|
|
90a56e |
+foo.present = \"true\"
|
|
|
90a56e |
+" s;
|
|
|
90a56e |
+
|
|
|
90a56e |
+ (* select_namespaces function *)
|
|
|
90a56e |
+ let t1 = Parse_vmx.parse_string "\
|
|
|
90a56e |
+foo.bar.present = \"TRUE\"
|
|
|
90a56e |
+foo.a.b = \"abc\"
|
|
|
90a56e |
+foo.a.c = \"abc\"
|
|
|
90a56e |
+foo.b = \"abc\"
|
|
|
90a56e |
+foo.c.a = \"abc\"
|
|
|
90a56e |
+foo.c.b = \"abc\"
|
|
|
90a56e |
+" in
|
|
|
90a56e |
+ let t2 =
|
|
|
90a56e |
+ Parse_vmx.select_namespaces
|
|
|
90a56e |
+ (function ["foo"] -> true | _ -> false) t1 in
|
|
|
90a56e |
+ assert_equal ~cmp ~printer t1 t2;
|
|
|
90a56e |
+
|
|
|
90a56e |
+ let t1 = Parse_vmx.parse_string "\
|
|
|
90a56e |
+foo.bar.present = \"TRUE\"
|
|
|
90a56e |
+foo.a.b = \"abc\"
|
|
|
90a56e |
+foo.a.c = \"abc\"
|
|
|
90a56e |
+foo.b = \"abc\"
|
|
|
90a56e |
+foo.c.a = \"abc\"
|
|
|
90a56e |
+foo.c.b = \"abc\"
|
|
|
90a56e |
+foo.c.c.d.e.f = \"abc\"
|
|
|
90a56e |
+" in
|
|
|
90a56e |
+ let t1 =
|
|
|
90a56e |
+ Parse_vmx.select_namespaces
|
|
|
90a56e |
+ (function ["foo"; "a"] -> true | _ -> false) t1 in
|
|
|
90a56e |
+ let t2 = Parse_vmx.parse_string "\
|
|
|
90a56e |
+foo.a.b = \"abc\"
|
|
|
90a56e |
+foo.a.c = \"abc\"
|
|
|
90a56e |
+" in
|
|
|
90a56e |
+ assert_equal ~cmp ~printer t2 t1
|
|
|
90a56e |
+
|
|
|
90a56e |
(* Suites declaration. *)
|
|
|
90a56e |
let suite =
|
|
|
90a56e |
"virt-v2v" >:::
|
|
|
90a56e |
@@ -798,6 +940,7 @@ let suite =
|
|
|
90a56e |
test_virtio_iso_path_matches_guest_os;
|
|
|
90a56e |
"Utils.shell_unquote" >:: test_shell_unquote;
|
|
|
90a56e |
"Utils.qemu_img_supports" >:: test_qemu_img_supports;
|
|
|
90a56e |
+ "Parse_vmx.parse_string" >::test_vmx_parse_string;
|
|
|
90a56e |
]
|
|
|
90a56e |
|
|
|
90a56e |
let () =
|
|
|
90a56e |
diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
|
|
|
a30de4 |
index 709075fba..7ed5c5d86 100644
|
|
|
90a56e |
--- a/v2v/virt-v2v.pod
|
|
|
90a56e |
+++ b/v2v/virt-v2v.pod
|
|
|
90a56e |
@@ -41,7 +41,8 @@ libguestfs E<ge> 1.28.
|
|
|
90a56e |
... ───▶│ (default) │ │ │ ──┐ └────────────┘
|
|
|
90a56e |
└────────────┘ │ │ ─┐└──────▶ -o glance
|
|
|
90a56e |
-i libvirtxml ─────────▶ │ │ ┐└─────────▶ -o rhv
|
|
|
90a56e |
- └────────────┘ └──────────▶ -o vdsm
|
|
|
90a56e |
+ -i vmx ────────────────▶ │ │ └──────────▶ -o vdsm
|
|
|
90a56e |
+ └────────────┘
|
|
|
90a56e |
|
|
|
90a56e |
Virt-v2v has a number of possible input and output modes, selected
|
|
|
90a56e |
using the I<-i> and I<-o> options. Only one input and output mode can
|
|
|
90a56e |
@@ -60,6 +61,8 @@ method used by L<virt-p2v(1)> behind the scenes.
|
|
|
90a56e |
|
|
|
90a56e |
I<-i ova> is used for reading from a VMware ova source file.
|
|
|
90a56e |
|
|
|
90a56e |
+I<-i vmx> is used for reading from a VMware vmx file.
|
|
|
90a56e |
+
|
|
|
90a56e |
I<-o glance> is used for writing to OpenStack Glance.
|
|
|
90a56e |
|
|
|
90a56e |
I<-o libvirt> is used for writing to any libvirt target. Libvirt can
|
|
|
a30de4 |
@@ -228,6 +231,14 @@ ova manifest file and check the vmdk volumes for validity (checksums)
|
|
|
90a56e |
as well as analyzing the ovf file, and then convert the guest. See
|
|
|
90a56e |
L</INPUT FROM VMWARE OVA> below
|
|
|
90a56e |
|
|
|
90a56e |
+=item B<-i> B<vmx>
|
|
|
90a56e |
+
|
|
|
90a56e |
+Set the input method to I<vmx>.
|
|
|
90a56e |
+
|
|
|
90a56e |
+In this mode you can read a VMware vmx file directly. This is useful
|
|
|
90a56e |
+when VMware VMs are stored on an NFS server which you can mount
|
|
|
90a56e |
+directly. See L</INPUT FROM VMWARE VMX> below
|
|
|
90a56e |
+
|
|
|
90a56e |
=item B<-ic> libvirtURI
|
|
|
90a56e |
|
|
|
90a56e |
Specify a libvirt connection URI to use when reading the guest. This
|
|
|
a30de4 |
@@ -859,9 +870,10 @@ I<--bridge> option instead. For example:
|
|
|
90a56e |
|
|
|
90a56e |
Virt-v2v is able to import guests from VMware vCenter Server.
|
|
|
90a56e |
|
|
|
90a56e |
-vCenter E<ge> 5.0 is required. If you don't have vCenter, using OVA
|
|
|
90a56e |
-is recommended instead (see L</INPUT FROM VMWARE OVA> below), or if
|
|
|
90a56e |
-that is not possible then see L</INPUT FROM VMWARE ESXi HYPERVISOR>.
|
|
|
90a56e |
+vCenter E<ge> 5.0 is required. If you don’t have vCenter, using OVA
|
|
|
90a56e |
+or VMX is recommended instead (see L</INPUT FROM VMWARE OVA> and/or
|
|
|
90a56e |
+L</INPUT FROM VMWARE VMX> below), or if that is not possible then see
|
|
|
90a56e |
+L</INPUT FROM VMWARE ESXi HYPERVISOR>.
|
|
|
90a56e |
|
|
|
90a56e |
Virt-v2v uses libvirt for access to vCenter, and therefore the input
|
|
|
90a56e |
mode should be I<-i libvirt>. As this is the default, you don't need
|
|
|
a30de4 |
@@ -1132,12 +1144,58 @@ directory containing the files:
|
|
|
90a56e |
|
|
|
90a56e |
$ virt-v2v -i ova /path/to/files -o local -os /var/tmp
|
|
|
90a56e |
|
|
|
90a56e |
+=head1 INPUT FROM VMWARE VMX
|
|
|
90a56e |
+
|
|
|
90a56e |
+Virt-v2v is able to import guests from VMware’s vmx files. This is
|
|
|
90a56e |
+useful where VMware virtual machines are stored on a separate NFS
|
|
|
90a56e |
+server and you are able to mount the NFS storage directly.
|
|
|
90a56e |
+
|
|
|
90a56e |
+If you find a folder of files called F<I<guest>.vmx>,
|
|
|
90a56e |
+F<I<guest>.vmxf>, F<I<guest>.nvram> and one or more F<.vmdk> disk
|
|
|
90a56e |
+images, then you can use this method.
|
|
|
90a56e |
+
|
|
|
90a56e |
+=head2 VMX: REMOVE VMWARE TOOLS FROM WINDOWS GUESTS
|
|
|
90a56e |
+
|
|
|
90a56e |
+For Windows guests, you should remove VMware tools before conversion.
|
|
|
90a56e |
+Although this is not strictly necessary, and the guest will still be
|
|
|
90a56e |
+able to run, if you don't do this then the converted guest will
|
|
|
90a56e |
+complain on every boot. The tools cannot be removed after conversion
|
|
|
90a56e |
+because the uninstaller checks if it is running on VMware and refuses
|
|
|
90a56e |
+to start (which is also the reason that virt-v2v cannot remove them).
|
|
|
90a56e |
+
|
|
|
90a56e |
+This is not necessary for Linux guests, as virt-v2v is able to remove
|
|
|
90a56e |
+VMware tools.
|
|
|
90a56e |
+
|
|
|
90a56e |
+=head2 VMX: GUEST MUST BE SHUT DOWN
|
|
|
90a56e |
+
|
|
|
90a56e |
+B<The guest must be shut down before conversion starts>. If you don't
|
|
|
90a56e |
+shut it down, you will end up with a corrupted VM disk on the target.
|
|
|
90a56e |
+With other methods, virt-v2v tries to prevent concurrent access, but
|
|
|
90a56e |
+because the I<-i vmx> method works directly against the storage,
|
|
|
90a56e |
+checking for concurrent access is not possible.
|
|
|
90a56e |
+
|
|
|
90a56e |
+=head2 VMX: MOUNT THE NFS STORAGE ON THE CONVERSION SERVER
|
|
|
90a56e |
+
|
|
|
90a56e |
+Virt-v2v must be able to access the F<.vmx> file and any local
|
|
|
90a56e |
+F<.vmdk> disks. Normally this means you must mount the NFS storage
|
|
|
90a56e |
+containing these files.
|
|
|
90a56e |
+
|
|
|
90a56e |
+=head2 VMX: IMPORTING A GUEST
|
|
|
90a56e |
+
|
|
|
90a56e |
+To import a vmx file, do:
|
|
|
90a56e |
+
|
|
|
90a56e |
+ $ virt-v2v -i vmx guest.vmx -o local -os /var/tmp
|
|
|
90a56e |
+
|
|
|
90a56e |
+Virt-v2v processes the vmx file and uses it to find the location of
|
|
|
90a56e |
+any vmdk disks.
|
|
|
90a56e |
+
|
|
|
90a56e |
=head1 INPUT FROM VMWARE ESXi HYPERVISOR
|
|
|
90a56e |
|
|
|
90a56e |
Virt-v2v cannot access an ESXi hypervisor directly. You should use
|
|
|
90a56e |
-the OVA method above (see L</INPUT FROM VMWARE OVA>) if possible, as
|
|
|
90a56e |
-it is much faster and requires much less disk space than the method
|
|
|
90a56e |
-described in this section.
|
|
|
90a56e |
+the OVA or VMX methods above (see L</INPUT FROM VMWARE OVA> and/or
|
|
|
90a56e |
+L</INPUT FROM VMWARE VMX>) if possible, as it is much faster and
|
|
|
90a56e |
+requires much less disk space than the method described in this
|
|
|
90a56e |
+section.
|
|
|
90a56e |
|
|
|
90a56e |
You can use the L<virt-v2v-copy-to-local(1)> tool to copy the guest
|
|
|
90a56e |
off the hypervisor into a local file, and then convert it.
|
|
|
90a56e |
--
|
|
|
a30de4 |
2.14.3
|
|
|
90a56e |
|