Adding ability for v2v to get Libvirt ova file as an input.
Signed-off-by: Shahar Havivi <shaharh(a)redhat.com>
---
po/POTFILES-ml | 1 +
v2v/Makefile.am | 3 +
v2v/cmdline.ml | 12 ++-
v2v/input_ova.ml | 220 +++++++++++++++++++++++++++++++++++++++++++++++++
v2v/input_ova.mli | 22 +++++
v2v/test-v2v-i-ova.ovf | 147 +++++++++++++++++++++++++++++++++
v2v/test-v2v-i-ova.sh | 73 ++++++++++++++++
v2v/virt-v2v.pod | 14 +++-
8 files changed, 489 insertions(+), 3 deletions(-)
create mode 100644 v2v/input_ova.ml
create mode 100644 v2v/input_ova.mli
create mode 100644 v2v/test-v2v-i-ova.ovf
create mode 100755 v2v/test-v2v-i-ova.sh
diff --git a/po/POTFILES-ml b/po/POTFILES-ml
index 53a7bfb..4b33dd9 100644
--- a/po/POTFILES-ml
+++ b/po/POTFILES-ml
@@ -90,6 +90,7 @@ v2v/domainxml.ml
v2v/input_disk.ml
v2v/input_libvirt.ml
v2v/input_libvirtxml.ml
+v2v/input_ova.ml
v2v/lib_esx.ml
v2v/lib_linux.ml
v2v/modules_list.ml
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
index b74325e..ae65046 100644
--- a/v2v/Makefile.am
+++ b/v2v/Makefile.am
@@ -38,6 +38,7 @@ SOURCES_MLI = \
lib_linux.mli \
modules_list.mli \
output_glance.mli \
+ input_ova.mli \
output_libvirt.mli \
output_local.mli \
output_RHEV.mli \
@@ -57,6 +58,7 @@ SOURCES_ML = \
input_disk.ml \
input_libvirtxml.ml \
input_libvirt.ml \
+ input_ova.ml \
convert_linux.ml \
convert_windows.ml \
output_glance.ml \
@@ -195,6 +197,7 @@ TESTS_ENVIRONMENT = $(top_builddir)/run --test
if ENABLE_APPLIANCE
TESTS = \
+ test-v2v-i-ova.sh \
test-v2v-i-disk.sh \
test-v2v-machine-readable.sh \
test-v2v-networks-and-bridges.sh \
diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
index 6a72aeb..affe36f 100644
--- a/v2v/cmdline.ml
+++ b/v2v/cmdline.ml
@@ -54,6 +54,7 @@ let parse_cmdline () =
| "disk" | "local" -> input_mode := `Disk
| "libvirt" -> input_mode := `Libvirt
| "libvirtxml" -> input_mode := `LibvirtXML
+ | "ova" -> input_mode := `OVA
| s ->
error (f_"unknown -i option: %s") s
in
@@ -241,7 +242,16 @@ read the man page virt-v2v(1).
| [filename] -> filename
| _ ->
error (f_"expecting a libvirt XML file name on the command line") in
- Input_libvirtxml.input_libvirtxml verbose filename in
+ Input_libvirtxml.input_libvirtxml verbose filename
+
+ | `OVA ->
+ (* -i ova: Expecting an ova filename (tar file). *)
+ let filename =
+ match args with
+ | [filename] -> filename
+ | _ ->
+ error (f_"expecting an OVA file name on the command line") in
+ Input_ova.input_ova verbose filename in
(* Parse the output mode. *)
let output =
diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml
new file mode 100644
index 0000000..2737718
--- /dev/null
+++ b/v2v/input_ova.ml
@@ -0,0 +1,220 @@
+(* 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
+
+class input_ova verbose ova =
+ let tmpdir =
+ let base_dir = (new Guestfs.guestfs ())#get_cachedir () in
+ let t = Mkdtemp.temp_dir ~base_dir "ova." "" in
+ rmdir_on_exit t;
+ t in
+object
+ inherit input verbose
+
+ method as_options = "-i ova " ^ ova
+
+ method source () =
+
+ (* extract ova (tar) file *)
+ let cmd = sprintf "tar -xf %s -C %s" (quote ova) (quote tmpdir) in
+
+ if Sys.command cmd <> 0 then
+ error (f_"error running command: %s") cmd;
+
+ let files = Sys.readdir tmpdir in
+ let mf = ref "" in
+ let ovf = ref "" in
+ (* search for the ovf file *)
+ Array.iter (fun file ->
+ if Filename.check_suffix file ".ovf" then
+ ovf := file
+ else if Filename.check_suffix file ".mf" then
+ mf := file
+ ) files;
+
+ (* verify sha1 from manifest file *)
+ let mf = tmpdir // !mf in
+ let rex = Str.regexp "SHA1(\\(.*\\))= \\(.*?\\)\r\\?$" in
+ let lines = read_whole_file mf in
+ let lines = string_nsplit "\n" lines in
+ List.iter (
+ fun line ->
+ if Str.string_match rex line 0 then
+ let file = Str.matched_group 1 line in
+ let sha1 = Str.matched_group 2 line in
+ let cmd = sprintf "sha1sum %s" (quote (tmpdir // file)) in
+ let out = external_command ~prog cmd in
+ (match out with
+ | [] -> error (f_"no output from sha1sum command, see previous
errors")
+ | [line] ->
+ let hash, _ = string_split " " line in
+ if hash <> sha1 then
+ error (f_"Checksum of %s does not match manifest sha1 %s") file
sha1;
+ | _::_ -> error (f_"cannot parse output of sha1sum command")
+ );
+ ) lines;
+
+ (* parse the ovf file *)
+ let xml = read_whole_file (tmpdir // !ovf) in
+ let doc = Xml.parse_memory xml in
+ let xpathctx = Xml.xpath_new_context doc in
+ Xml.xpath_register_ns xpathctx "ovf"
"http://schemas.dmtf.org/ovf/envelope/1";
+ Xml.xpath_register_ns xpathctx "rasd"
"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData";
+ Xml.xpath_register_ns xpathctx "vssd"
"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData";
+
+ let xpath_to_string expr default =
+ let obj = Xml.xpath_eval_expression xpathctx expr in
+ if Xml.xpathobj_nr_nodes obj < 1 then default
+ else (
+ let node = Xml.xpathobj_node doc obj 0 in
+ Xml.node_as_string node
+ )
+ and xpath_to_int expr default =
+ let obj = Xml.xpath_eval_expression xpathctx expr in
+ if Xml.xpathobj_nr_nodes obj < 1 then default
+ else (
+ let node = Xml.xpathobj_node doc obj 0 in
+ let str = Xml.node_as_string node in
+ try int_of_string str
+ with Failure "int_of_string" ->
+ error (f_"expecting XML expression to return an integer (expression:
%s)")
+ expr
+ )
+ in
+
+ let disks = ref [] in
+ let removables = ref [] in
+
+ (* resources hard-disk, CD-ROMs and floppy *)
+ let add_resource id =
+ let expr = sprintf
"/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:ResourceType/text()=%d]"
id in
+ let obj = Xml.xpath_eval_expression xpathctx expr in
+ let nr_nodes = Xml.xpathobj_nr_nodes obj in
+ for i = 0 to nr_nodes-1 do
+ let n = Xml.xpathobj_node doc obj i in
+ Xml.xpathctx_set_current_context xpathctx n;
+ let address = xpath_to_int "rasd:AddressOnParent/text()" 0 in
+ let parent_id = xpath_to_int "rasd:Parent/text()" 0 in
+ (* prob the parent controller *)
+ let expr = sprintf
"/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:InstanceId/text()=%d]/rasd:ResourceType/text()"
parent_id in
+ let controller = xpath_to_int expr 0 in
+ (* 6: iscsi controller, 5: ide. assueming scsi or ide *)
+ let target_dev =
+ match controller with
+ | 6 -> "sd"
+ | 0 | 5 | _ -> "hd" in
+ (*FIXME in floppy should be 'fd'??? *)
+
+ let target_dev = sprintf "%s%c" target_dev (Char.chr(48+address)) in
+
+ (* add disk(17)/removables to its collections *)
+ if id = 17 then (
+ Xml.xpathctx_set_current_context xpathctx n;
+ let file_id = xpath_to_string "rasd:HostResource/text()" ""
in
+ let rex = Str.regexp "^ovf:/disk/\\(.*\\)" in
+ if Str.string_match rex file_id 0 then (
+ let file_id = Str.matched_group 1 file_id in
+ let expr = sprintf
"/ovf:Envelope/ovf:DiskSection/ovf:Disk[@ovf:diskId='%s']/@ovf:fileRef"
file_id in
+ let file_ref = xpath_to_string expr "" in
+ if file_ref == "" then error (f_"Error parsing disk
fileRef");
+ let expr = sprintf
"/ovf:Envelope/ovf:References/ovf:File[@ovf:id='%s']/@ovf:href" file_ref
in
+ let file_name = xpath_to_string expr "" in
+ let disk = { s_qemu_uri=(tmpdir // file_name); s_format=Some
"vmdk"; s_target_dev=Some target_dev } in
+ disks := disk :: !disks;
+ ) else
+ error (f_"could not parse disk rasd:HostResource from OVF
document");
+ )
+ else (
+ (* 14: Floppy 15: CD 16: CDROM*)
+ let typ =
+ match id with
+ | 14 -> `Floppy
+ | 15 | 16 -> `CDROM
+ | _ -> assert false in
+ let disk = { s_removable_type = typ; s_removable_target_dev = Some target_dev }
in
+ removables := disk :: !removables;
+ )
+ done;
+ in
+
+ (* search for vm name *)
+ let name = xpath_to_string
"/ovf:Envelope/ovf:VirtualSystem/ovf:Name/text()" "" in
+ if name = "" then
+ error (f_"could not parse ovf:Name from OVF document");
+
+ (* search for memory *)
+ let memory = xpath_to_int
"/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:ResourceType/text()=4]/rasd:VirtualQuantity/text()"
(1024 * 1024) in
+ let memory = Int64.of_int (memory * 1024 * 1024) in
+
+ (* search for cpu *)
+ let cpu = xpath_to_int
"/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:ResourceType/text()=3]/rasd:VirtualQuantity/text()"
1 in
+
+ (* search for floopy *)
+ add_resource 14;
+
+ (* search for cd *)
+ add_resource 15;
+
+ (* search for cdrom *)
+ add_resource 16;
+
+ (* search for hard-disk *)
+ add_resource 17;
+
+ (* serch for networks ResourceType: 10*)
+ let nics = ref [] in
+ let obj = Xml.xpath_eval_expression xpathctx
"/ovf:Envelope/ovf:VirtualSystem/ovf:VirtualHardwareSection/ovf:Item[rasd:ResourceType/text()=10]"
in
+ let nr_nodes = Xml.xpathobj_nr_nodes obj in
+ for i = 0 to nr_nodes-1 do
+ let n = Xml.xpathobj_node doc obj i in
+ Xml.xpathctx_set_current_context xpathctx n;
+ let vnet = xpath_to_string "rasd:ElementName/text()"
(sprintf"eth%d" i) in
+ let nic = {
+ s_mac = None;
+ s_vnet = vnet;
+ s_vnet_orig = vnet;
+ s_vnet_type = Network;
+ } in
+ nics := nic :: !nics
+ done;
+
+ let source = {
+ s_dom_type = "vmware";
+ s_name = name;
+ s_orig_name = name;
+ s_memory = memory;
+ s_vcpu = cpu;
+ s_arch = "x86_64"; (* XXX: no architucture in ovf, this entry will be
overritten at os inspection via libguestfs *)
+ s_features = []; (* FIXME: *)
+ s_display = None; (* FIXME: *)
+ s_disks = !disks;
+ s_removables = !removables;
+ s_nics = !nics;
+ } in
+ source
+end
+
+let input_ova = new input_ova
+let () = Modules_list.register_input_module "ova"
diff --git a/v2v/input_ova.mli b/v2v/input_ova.mli
new file mode 100644
index 0000000..d4c347e
--- /dev/null
+++ b/v2v/input_ova.mli
@@ -0,0 +1,22 @@
+(* 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 ova] source. *)
+
+val input_ova : bool -> string -> Types.input
+(** [input_ova filename] sets up an input from vmware ova file. *)
diff --git a/v2v/test-v2v-i-ova.ovf b/v2v/test-v2v-i-ova.ovf
new file mode 100644
index 0000000..a950645
--- /dev/null
+++ b/v2v/test-v2v-i-ova.ovf
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Envelope vmw:buildId="build-1623387"
xmlns="http://schemas.dmtf.org/ovf/envelope/1"
xmlns:cim="http://schemas.dmtf.org/wbem/wscim/1/common"
xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"
xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_Re...
xmlns:vmw="http://www.vmware.com/schema/ovf"
xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_Vi...
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <References>
+ <File ovf:href="test-ova.vmdk" ovf:id="file1"
ovf:size="349405696" />
+ </References>
+ <DiskSection>
+ <Info>Virtual disk information</Info>
+ <Disk ovf:capacity="32" ovf:capacityAllocationUnits="byte *
2^30" ovf:diskId="vmdisk1" ovf:fileRef="file1"
ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.htm...
ovf:populatedSize="1008926720" />
+ </DiskSection>
+ <NetworkSection>
+ <Info>The list of logical networks</Info>
+ <Network ovf:name="VM Network">
+ <Description>The VM Network network</Description>
+ </Network>
+ </NetworkSection>
+ <VirtualSystem ovf:id="TestOva">
+ <Info>A virtual machine</Info>
+ <Name>TestOva</Name>
+ <OperatingSystemSection ovf:id="74"
vmw:osType="windows7_64Guest">
+ <Info>The kind of installed guest operating system</Info>
+ </OperatingSystemSection>
+ <VirtualHardwareSection>
+ <Info>Virtual hardware requirements</Info>
+ <System>
+ <vssd:ElementName>Virtual Hardware Family</vssd:ElementName>
+ <vssd:InstanceID>0</vssd:InstanceID>
+ <vssd:VirtualSystemIdentifier>TestOva</vssd:VirtualSystemIdentifier>
+ <vssd:VirtualSystemType>vmx-08</vssd:VirtualSystemType>
+ </System>
+ <Item>
+ <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>
+ <rasd:Description>Number of Virtual CPUs</rasd:Description>
+ <rasd:ElementName>1 virtual CPU(s)</rasd:ElementName>
+ <rasd:InstanceID>1</rasd:InstanceID>
+ <rasd:ResourceType>3</rasd:ResourceType>
+ <rasd:VirtualQuantity>1</rasd:VirtualQuantity>
+ </Item>
+ <Item>
+ <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>
+ <rasd:Description>Memory Size</rasd:Description>
+ <rasd:ElementName>2048MB of memory</rasd:ElementName>
+ <rasd:InstanceID>2</rasd:InstanceID>
+ <rasd:ResourceType>4</rasd:ResourceType>
+ <rasd:VirtualQuantity>2048</rasd:VirtualQuantity>
+ </Item>
+ <Item>
+ <rasd:Address>0</rasd:Address>
+ <rasd:Description>SCSI Controller</rasd:Description>
+ <rasd:ElementName>SCSI Controller 0</rasd:ElementName>
+ <rasd:InstanceID>3</rasd:InstanceID>
+ <rasd:ResourceSubType>lsilogicsas</rasd:ResourceSubType>
+ <rasd:ResourceType>6</rasd:ResourceType>
+ <vmw:Config ovf:required="false"
vmw:key="slotInfo.pciSlotNumber" vmw:value="160" />
+ </Item>
+ <Item>
+ <rasd:Address>1</rasd:Address>
+ <rasd:Description>IDE Controller</rasd:Description>
+ <rasd:ElementName>VirtualIDEController 1</rasd:ElementName>
+ <rasd:InstanceID>4</rasd:InstanceID>
+ <rasd:ResourceType>5</rasd:ResourceType>
+ </Item>
+ <Item>
+ <rasd:Address>0</rasd:Address>
+ <rasd:Description>IDE Controller</rasd:Description>
+ <rasd:ElementName>VirtualIDEController 0</rasd:ElementName>
+ <rasd:InstanceID>5</rasd:InstanceID>
+ <rasd:ResourceType>5</rasd:ResourceType>
+ </Item>
+ <Item ovf:required="false">
+ <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+ <rasd:ElementName>VirtualVideoCard</rasd:ElementName>
+ <rasd:InstanceID>6</rasd:InstanceID>
+ <rasd:ResourceType>24</rasd:ResourceType>
+ <vmw:Config ovf:required="false" vmw:key="enable3DSupport"
vmw:value="false" />
+ <vmw:Config ovf:required="false"
vmw:key="enableMPTSupport" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="use3dRenderer"
vmw:value="automatic" />
+ <vmw:Config ovf:required="false" vmw:key="useAutoDetect"
vmw:value="false" />
+ <vmw:Config ovf:required="false"
vmw:key="videoRamSizeInKB" vmw:value="8192" />
+ </Item>
+ <Item ovf:required="false">
+ <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+ <rasd:ElementName>VirtualVMCIDevice</rasd:ElementName>
+ <rasd:InstanceID>7</rasd:InstanceID>
+ <rasd:ResourceSubType>vmware.vmci</rasd:ResourceSubType>
+ <rasd:ResourceType>1</rasd:ResourceType>
+ <vmw:Config ovf:required="false"
vmw:key="allowUnrestrictedCommunication" vmw:value="false" />
+ <vmw:Config ovf:required="false"
vmw:key="slotInfo.pciSlotNumber" vmw:value="33" />
+ </Item>
+ <Item ovf:required="false">
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+ <rasd:ElementName>CD-ROM 1</rasd:ElementName>
+ <rasd:InstanceID>8</rasd:InstanceID>
+ <rasd:Parent>4</rasd:Parent>
+ <rasd:ResourceSubType>vmware.cdrom.iso</rasd:ResourceSubType>
+ <rasd:ResourceType>15</rasd:ResourceType>
+ </Item>
+ <Item>
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:ElementName>Hard Disk 1</rasd:ElementName>
+ <rasd:HostResource>ovf:/disk/vmdisk1</rasd:HostResource>
+ <rasd:InstanceID>9</rasd:InstanceID>
+ <rasd:Parent>3</rasd:Parent>
+ <rasd:ResourceType>17</rasd:ResourceType>
+ <vmw:Config ovf:required="false"
vmw:key="backing.writeThrough" vmw:value="false" />
+ </Item>
+ <Item ovf:required="false">
+ <rasd:AddressOnParent>0</rasd:AddressOnParent>
+ <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
+ <rasd:Description>Floppy Drive</rasd:Description>
+ <rasd:ElementName>Floppy 1</rasd:ElementName>
+ <rasd:InstanceID>10</rasd:InstanceID>
+
<rasd:ResourceSubType>vmware.floppy.remotedevice</rasd:ResourceSubType>
+ <rasd:ResourceType>14</rasd:ResourceType>
+ </Item>
+ <Item>
+ <rasd:AddressOnParent>7</rasd:AddressOnParent>
+ <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
+ <rasd:Connection>VM Network</rasd:Connection>
+ <rasd:Description>E1000 ethernet adapter on "VM
Network"</rasd:Description>
+ <rasd:ElementName>Ethernet 1</rasd:ElementName>
+ <rasd:InstanceID>11</rasd:InstanceID>
+ <rasd:ResourceSubType>E1000</rasd:ResourceSubType>
+ <rasd:ResourceType>10</rasd:ResourceType>
+ <vmw:Config ovf:required="false"
vmw:key="slotInfo.pciSlotNumber" vmw:value="32" />
+ <vmw:Config ovf:required="false"
vmw:key="wakeOnLanEnabled" vmw:value="true" />
+ </Item>
+ <vmw:Config ovf:required="false" vmw:key="cpuHotAddEnabled"
vmw:value="false" />
+ <vmw:Config ovf:required="false"
vmw:key="cpuHotRemoveEnabled" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="firmware"
vmw:value="bios" />
+ <vmw:Config ovf:required="false"
vmw:key="virtualICH7MPresent" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="virtualSMCPresent"
vmw:value="false" />
+ <vmw:Config ovf:required="false"
vmw:key="memoryHotAddEnabled" vmw:value="false" />
+ <vmw:Config ovf:required="false" vmw:key="nestedHVEnabled"
vmw:value="false" />
+ <vmw:Config ovf:required="false"
vmw:key="powerOpInfo.powerOffType" vmw:value="soft" />
+ <vmw:Config ovf:required="false"
vmw:key="powerOpInfo.resetType" vmw:value="soft" />
+ <vmw:Config ovf:required="false"
vmw:key="powerOpInfo.standbyAction" vmw:value="checkpoint" />
+ <vmw:Config ovf:required="false"
vmw:key="powerOpInfo.suspendType" vmw:value="hard" />
+ <vmw:Config ovf:required="false"
vmw:key="tools.afterPowerOn" vmw:value="true" />
+ <vmw:Config ovf:required="false" vmw:key="tools.afterResume"
vmw:value="true" />
+ <vmw:Config ovf:required="false"
vmw:key="tools.beforeGuestShutdown" vmw:value="true" />
+ <vmw:Config ovf:required="false"
vmw:key="tools.beforeGuestStandby" vmw:value="true" />
+ <vmw:Config ovf:required="false"
vmw:key="tools.syncTimeWithHost" vmw:value="false" />
+ <vmw:Config ovf:required="false"
vmw:key="tools.toolsUpgradePolicy" vmw:value="manual" />
+ </VirtualHardwareSection>
+ </VirtualSystem>
+</Envelope>
diff --git a/v2v/test-v2v-i-ova.sh b/v2v/test-v2v-i-ova.sh
new file mode 100755
index 0000000..018d03b
--- /dev/null
+++ b/v2v/test-v2v-i-ova.sh
@@ -0,0 +1,73 @@
+#!/bin/bash -
+# libguestfs virt-v2v test script
+# Copyright (C) 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.
+
+# Test -i ova option.
+
+unset CDPATH
+export LANG=C
+set -e
+
+if [ -n "$SKIP_TEST_V2V_I_OVA_SH" ]; then
+ echo "$0: test skipped because environment variable is set"
+ exit 77
+fi
+
+if [ "$(../fish/guestfish get-backend)" = "uml" ]; then
+ echo "$0: test skipped because UML backend does not support network"
+ exit 77
+fi
+
+f=../tests/guests/windows.img
+if ! test -f $f || ! test -s $f; then
+ echo "$0: test skipped because phony Windows image was not created"
+ exit 77
+fi
+
+d=test-v2v-i-ova.d
+rm -rf $d
+mkdir $d
+
+vmdk=test-ova.vmdk
+ovf=test-v2v-i-ova.ovf
+mf=test-ova.mf
+ova=test-ova.ova
+xml=TestOva.xml
+raw=TestOva-sda
+
+qemu-img convert $f -O vmdk $d/$vmdk
+cp $ovf $d/$ovf
+sha1=`sha1sum $d/$ovf | awk '{print $1}'`
+echo "SHA1($ovf)= $sha1" > $d/$mf
+sha1=`sha1sum $d/$vmdk | awk '{print $1}'`
+echo "SHA1($vmdk)= $sha1" >> $d/$mf
+
+pushd .
+cd $d
+tar -cf $ova $ovf $mf $vmdk
+rm -rf $ovf $mf $vmdk
+popd
+
+$VG ./virt-v2v --debug-gc \
+ -i ova $d/$ova \
+ -o local -of raw -os $d
+
+# Test the libvirt XML metadata and a disk was created.
+test -f $d/$raw
+test -f $d/$xml
+
+rm -rf $d
diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
index cb7fec8..3c07841 100644
--- a/v2v/virt-v2v.pod
+++ b/v2v/virt-v2v.pod
@@ -32,8 +32,8 @@ libguestfs E<ge> 1.28.
┌────────────┐
-i disk ───────────┐ │ │ ┌───────▶ -o local
- │ │ virt-v2v │ │
- └──▶ │ conversion │ ──┘
+ └──▶ │ virt-v2v │ │
+ -i ova ──────────────▶ │ conversion │ ──┘
-i libvirt ───────────▶ │ server │ ────────▶ -o libvirt
(default) ┌──▶ │ │ ──┐ (default)
│ │ │ ─┐└──────▶ -o glance
@@ -52,6 +52,8 @@ option selects the precise libvirt source.
I<-i disk> is used for reading from local disk images (mainly for
testing).
+I<-i ova> is used for reading from libvirt ova source file.
+
I<-i libvirtxml> is used to read from libvirt XML files. This is the
method used by L<virt-p2v(1)> behind the scenes.
@@ -158,6 +160,14 @@ usually adequate but you can get finer control (eg. of memory and
vCPUs) by using I<-i libvirtxml> instead. Only guests that use a single
disk can be imported this way.
+=item B<-i ova>
+
+Set the input method to I<ova>.
+
+In this mode you can read a vmware ova file (tar format).
+virt-v2v tries to read the ova manifest file and check the ova files
+for validity (checksum) as well as analyzing the ovf file.
+
=item B<-i libvirt>
Set the input method to I<libvirt>. This is the default.
--
1.9.3