Adding ability for v2v to get Libvirt ova file as an input. Signed-off-by: Shahar Havivi <shaharh@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