[Libguestfs] [PATCH] v2v: adding input -i ova

Shahar Havivi shaharh at redhat.com
Thu Sep 4 08:44:07 UTC 2014


Adding ability for v2v to get Libvirt ova file as an input.

Signed-off-by: Shahar Havivi <shaharh at 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_ResourceAllocationSettingData" xmlns:vmw="http://www.vmware.com/schema/ovf" xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" 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.html#streamOptimized" 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




More information about the Libguestfs mailing list