[Libguestfs] [PATCH v6 3/3] v2v: ova: don't extract files from OVA if it's not needed

Cedric Bosdonnat cbosdonnat at suse.com
Tue Jan 31 08:39:38 UTC 2017


On Mon, 2017-01-30 at 22:43 +0100, Tomáš Golembiovský wrote:
> We don't have to always extract all files from the OVA archive. The OVA,
> as defined in the standard, is plain tar. We can work directly over the
> tar archive if we use correct 'offset' and 'size' options when defining
> the backing file for QEMU. This puts much lower requirement on available
> disk space.
> 
> Since the virt-v2v behaviour for OVA input now depends on QEMU version
> available this affects some of the tests. The affected tests will have
> two *.expect files and the expected result also has to depend on the
> QEMU used.
> 
> Signed-off-by: Tomáš Golembiovský <tgolembi at redhat.com>
> ---
>  test-data/test-utils.sh                 |  20 ++++
>  v2v/Makefile.am                         |   2 +
>  v2v/input_ova.ml                        | 189 +++++++++++++++++++++++++++++---
>  v2v/test-v2v-i-ova-formats.sh           |   5 +-
>  v2v/test-v2v-i-ova-subfolders.expected2 |  18 +++
>  v2v/test-v2v-i-ova-subfolders.sh        |  13 ++-
>  v2v/test-v2v-i-ova-tar.expected         |  18 +++
>  v2v/test-v2v-i-ova-tar.expected2        |  18 +++
>  v2v/test-v2v-i-ova-tar.ovf              | 138 +++++++++++++++++++++++
>  v2v/test-v2v-i-ova-tar.sh               |  72 ++++++++++++
>  v2v/test-v2v-i-ova-two-disks.expected2  |  19 ++++
>  v2v/test-v2v-i-ova-two-disks.sh         |  13 ++-
>  12 files changed, 502 insertions(+), 23 deletions(-)
>  create mode 100644 v2v/test-v2v-i-ova-subfolders.expected2
>  create mode 100644 v2v/test-v2v-i-ova-tar.expected
>  create mode 100644 v2v/test-v2v-i-ova-tar.expected2
>  create mode 100644 v2v/test-v2v-i-ova-tar.ovf
>  create mode 100755 v2v/test-v2v-i-ova-tar.sh
>  create mode 100644 v2v/test-v2v-i-ova-two-disks.expected2
> 
> diff --git a/test-data/test-utils.sh b/test-data/test-utils.sh
> index 86a5aaf12..04e833308 100755
> --- a/test-data/test-utils.sh
> +++ b/test-data/test-utils.sh
> @@ -54,3 +54,23 @@ do_sha256 ()
>        ;;
>    esac
>  }
> +
> +# Returns 0 if QEMU version is greater or equal to the arguments
> +qemu_is_version() {
> +    if [ $# -ne 2 ] ; then
> +        echo "Usage: $0 <major_version> <minor_version>" >&2
> +        return 3
> +    fi
> +
> +    QV=$(expr match "$(qemu-img --version)" 'qemu-img version \([0-9]\+\.[0-9]\+\)')
> +    [ -z "$QV" ] && return 2
> +
> +    QMAJ=$(echo "$QV" | cut -d. -f1)
> +    QMIN=$(echo "$QV" | cut -d. -f2)
> +
> +    if [ \( $QMAJ -gt $1 \) -o \( $QMAJ -eq $1 -a $QMIN -ge $2 \) ] ; then
> +        return 0
> +    fi
> +
> +    return 1
> +}
> diff --git a/v2v/Makefile.am b/v2v/Makefile.am
> index 9189aaf12..d62ac477e 100644
> --- a/v2v/Makefile.am
> +++ b/v2v/Makefile.am
> @@ -260,6 +260,7 @@ TESTS_ENVIRONMENT = $(top_builddir)/run --test
>  
>  TESTS = \
>  	test-v2v-docs.sh \
> +	test-v2v-i-ova-tar.sh \
>  	test-v2v-i-ova-formats.sh \
>  	test-v2v-i-ova-gz.sh \
>  	test-v2v-i-ova-subfolders.sh \
> @@ -359,6 +360,7 @@ EXTRA_DIST += \
>  	test-v2v-i-ova-subfolders.expected \
>  	test-v2v-i-ova-subfolders.ovf \
>  	test-v2v-i-ova-subfolders.sh \
> +	test-v2v-i-ova-tar.sh \
>  	test-v2v-i-ova-two-disks.expected \
>  	test-v2v-i-ova-two-disks.ovf \
>  	test-v2v-i-ova-two-disks.sh \
> diff --git a/v2v/input_ova.ml b/v2v/input_ova.ml
> index 40f723633..01ba80686 100644
> --- a/v2v/input_ova.ml
> +++ b/v2v/input_ova.ml
> @@ -39,17 +39,23 @@ object
>  
>    method source () =
>  
> -    let untar ?(format = "") file outdir =
> -      let cmd = [ "tar"; sprintf "-x%sf" format; file; "-C"; outdir ] in
> +    (* Untar part or all files from tar archive. If [paths] is specified it is
> +     * a list of paths in the tar archive.
> +     *)
> +    let untar ?(format = "") ?paths file outdir =
> +      let cmd =
> +        [ "tar"; sprintf "-x%sf" format; file; "-C"; outdir ]
> +        @ (match paths with None -> [] | Some p -> p)
> +      in
>        if run_command cmd <> 0 then
>          error (f_"error unpacking %s, see earlier error messages") ova in
>  
>      (* Extract ova file. *)
> -    let exploded =
> +    let exploded, partial =
>        (* The spec allows a directory to be specified as an ova.  This
>         * is also pretty convenient.
>         *)
> -      if is_directory ova then ova
> +      if is_directory ova then ova, false
>        else (
>          let uncompress_head zcat file =
>            let cmd = sprintf "%s %s" zcat (quote file) in
> @@ -67,11 +73,56 @@ object
>  
>            tmpfile in
>  
> +        (* Untar only ovf and manifest from the archive *)
> +        let untar_metadata ova outdir =
> +          let files =
> +            external_command (sprintf "tar -tf %s" (Filename.quote ova)) in
> +          let files =
> +            filter_map (fun f ->
> +              if Filename.check_suffix f ".ovf" ||
> +                  Filename.check_suffix f ".mf" then
> +                Some f
> +              else None
> +            ) files in
> +          untar ~paths:files ova outdir in
> +
> +        let qemu_img_version () =
> +          let lines = external_command "qemu-img --version" in
> +          match lines with
> +          | [] -> error ("'qemu-img --version' returned no output")
> +          | line :: _ ->
> +              let rex = Str.regexp
> +                "qemu-img version \\([0-9]+\\)\\.\\([0-9]+\\)" in
> +              if Str.string_match rex line 0 then (
> +                try
> +                  int_of_string (Str.matched_group 1 line),
> +                  int_of_string (Str.matched_group 2 line)
> +                with Failure _ ->
> +                  warning (f_"failed to parse qemu-img version(%S), assuming 0.9")
> +                    line;
> +                  0, 9
> +              ) else (
> +                warning (f_"failed to read qemu-img version(%S), assuming 0.9")
> +                  line;
> +                0, 9
> +              )
> +        in
> +
>          match detect_file_type ova with
>          | `Tar ->
>            (* Normal ovas are tar file (not compressed). *)
> -          untar ova tmpdir;
> -          tmpdir
> +          let qmajor, qminor = qemu_img_version () in
> +          if qmajor > 2 || (qmajor == 2 && qminor >= 8) then (
> +            (* If QEMU is recent enough we don't have to extract everything.
> +             * We can access disks inside the tar archive.
> +             *)
> +            untar_metadata ova tmpdir;
> +            tmpdir, true
> +          ) else (
> +            untar ova tmpdir;
> +            tmpdir, false
> +          )
> +
>          | `Zip ->
>            (* However, although not permitted by the spec, people ship
>             * zip files as ova too.
> @@ -81,7 +132,7 @@ object
>              [ "-j"; "-d"; tmpdir; ova ] in
>            if run_command cmd <> 0 then
>              error (f_"error unpacking %s, see earlier error messages") ova;
> -          tmpdir
> +          tmpdir, false
>          | (`GZip|`XZ) as format ->
>            let zcat, tar_fmt =
>              match format with
> @@ -94,7 +145,7 @@ object
>            (match tmpfiletype with
>            | `Tar ->
>              untar ~format:tar_fmt ova tmpdir;
> -            tmpdir
> +            tmpdir, false
>            | `Zip | `GZip | `XZ | `Unknown ->
>              error (f_"%s: unsupported file format\n\nFormats which we currently understand for '-i ova' are: tar
> (uncompressed, compress with gzip or xz), zip") ova
>            )
> @@ -135,6 +186,68 @@ object
>        loop [dir]
>      in
>  
> +    (* Find file in [tar] archive and return at which byte it starts and how
> +     * long it is.
> +     *)
> +    let find_file_in_tar tar filename =
> +      let lines = external_command (sprintf "tar tRvf %s" (Filename.quote tar)) in
> +      let rec loop lines =
> +        match lines with
> +        | [] -> raise Not_found
> +        | line :: lines -> (
> +          (* Lines have the form:
> +           * block <offset>: <perms> <owner>/<group> <size> <mdate> <mtime> <file>
> +           *)
> +          let elems = String.nsplit ~keep_empty:false ~count:7 " " line in
> +          if List.length elems = 8 && List.hd elems = "block" then (
> +            let elems = Array.of_list elems in
> +            let offset = elems.(1) in
> +            let size = elems.(4) in
> +            let fname = elems.(7) in
> +
> +            if fname <> filename then
> +              loop lines
> +            else (
> +              let offset =
> +                try
> +                  (* There should be a colon at the end *)
> +                  let i = String.rindex offset ':' in
> +                  if i == (String.length offset)-1 then
> +                    Int64.of_string (String.sub offset 0 i)
> +                  else
> +                    raise (Failure "colon at wrong position")
> +                with Failure _ | Not_found ->
> +                  error (f_"invalid offset returned by tar: %S") offset in
> +
> +              let size =
> +                try Int64.of_string size
> +                with Failure _ ->
> +                  error (f_"invalid size returned by tar: %S") size in
> +
> +              (* Note: Offset is actualy block number and there is a single
> +               * block with tar header at the beginning of the file. So skip
> +               * the header and convert the block number to bytes before
> +               * returning.
> +               *)
> +              (offset +^ 1L) *^ 512L, size
> +            )
> +          ) else
> +            error (f_"failed to parse line returned by tar: %S") line
> +        )
> +      in
> +      loop lines
> +    in
> +
> +    let subfolder folder parent =
> +      if folder = parent then
> +        ""
> +      else if String.is_prefix folder (parent // "") then
> +        let len = String.length parent in
> +        String.sub folder (len+1) (String.length folder-len-1)
> +      else
> +        assert false
> +    in
> +

It would be good to get this function in mllib rather since it
could (and will) be reused by other code.

--
Cedric

>      (* Search for the ovf file. *)
>      let ovf = find_files exploded ".ovf" in
>      let ovf =
> @@ -152,6 +265,7 @@ object
>        fun mf ->
>          debug "processing manifest %s" mf;
>          let mf_folder = Filename.dirname mf in
> +        let mf_subfolder = subfolder mf_folder exploded in
>          let chan = open_in mf in
>          let rec loop () =
>            let line = input_line chan in
> @@ -160,7 +274,11 @@ object
>              let disk = Str.matched_group 2 line in
>              let expected = Str.matched_group 3 line in
>              let csum = Checksums.of_string mode expected in
> -            try Checksums.verify_checksum csum (mf_folder // disk)
> +            try
> +              if partial then
> +                Checksums.verify_checksum csum ~tar:ova (mf_subfolder // disk)
> +              else
> +                Checksums.verify_checksum csum (mf_folder // disk)
>              with Checksums.Mismatched_checksum (_, actual) ->
>                error (f_"checksum of disk %s does not match manifest %s (actual %s(%s) = %s, expected %s(%s) = %s)")
>                  disk mf mode disk actual mode disk expected;
> @@ -283,9 +401,25 @@ object
>              | Some "gzip" -> true
>              | Some s -> error (f_"unsupported compression in OVF: %s") s in
>  
> -          (* Does the file exist and is it readable? *)
> -          let filename = ovf_folder // filename in
> -          Unix.access filename [Unix.R_OK];
> +          let partial =
> +            if compressed && partial then (
> +              (* We cannot access compressed disk inside the tar; we have to
> +               * extract it *)
> +              untar ~paths:[(subfolder ovf_folder exploded) // filename]
> +                ova tmpdir;
> +              false
> +            )
> +            else
> +              partial in
> +
> +          let filename =
> +            if partial then
> +              (subfolder ovf_folder exploded) // filename
> +            else (
> +              (* Does the file exist and is it readable? *)
> +              Unix.access (ovf_folder // filename) [Unix.R_OK];
> +              ovf_folder // filename
> +            ) in
>  
>            (* The spec allows the file to be gzip-compressed, in which case
>             * we must uncompress it into the tmpdir.
> @@ -302,9 +436,38 @@ object
>              )
>              else filename in
>  
> +          let qemu_uri =
> +            if not partial then (
> +              filename
> +            )
> +            else (
> +              let offset, size =
> +                try find_file_in_tar ova filename
> +                with Not_found ->
> +                  error (f_"file '%s' not found in the ova") filename
> +              in
> +              (* QEMU requires size aligned to 512 bytes. This is safe because
> +               * tar also works with 512 byte blocks.
> +               *)
> +              let size = roundup64 size 512L in
> +              let doc = [
> +                "file", JSON.Dict [
> +                  "driver", JSON.String "raw";
> +                  "offset", JSON.Int64 offset;
> +                  "size", JSON.Int64 size;
> +                  "file", JSON.Dict [
> +                    "filename", JSON.String ova]
> +                  ]
> +                ] in
> +              let x =
> +              sprintf "json:%s" (JSON.string_of_doc ~fmt:Compact doc)
> +              in
> +              (debug "json: %s" x; x)
> +            ) in
> +
>            let disk = {
>              s_disk_id = i;
> -            s_qemu_uri = filename;
> +            s_qemu_uri = qemu_uri;
>              s_format = Some "vmdk";
>              s_controller = controller;
>            } in
> diff --git a/v2v/test-v2v-i-ova-formats.sh b/v2v/test-v2v-i-ova-formats.sh
> index bd3e30ee8..0eec600eb 100755
> --- a/v2v/test-v2v-i-ova-formats.sh
> +++ b/v2v/test-v2v-i-ova-formats.sh
> @@ -22,7 +22,7 @@ unset CDPATH
>  export LANG=C
>  set -e
>  
> -formats="tar zip tar-gz tar-xz"
> +formats="zip tar-gz tar-xz"
>  
>  if [ -n "$SKIP_TEST_V2V_I_OVA_FORMATS_SH" ]; then
>      echo "$0: test skipped because environment variable is set"
> @@ -63,9 +63,6 @@ cp ../test-v2v-i-ova-formats.ovf .
>  
>  for format in $formats; do
>      case "$format" in
> -        tar)
> -            tar -cf test-$format.ova test-v2v-i-ova-formats.ovf disk1.vmdk disk1.mf
> -            ;;
>          zip)
>              zip -r test test-v2v-i-ova-formats.ovf disk1.vmdk disk1.mf
>              mv test.zip test-$format.ova
> diff --git a/v2v/test-v2v-i-ova-subfolders.expected2 b/v2v/test-v2v-i-ova-subfolders.expected2
> new file mode 100644
> index 000000000..87996d202
> --- /dev/null
> +++ b/v2v/test-v2v-i-ova-subfolders.expected2
> @@ -0,0 +1,18 @@
> +Source guest information (--print-source option):
> +
> +    source name: 2K8R2EESP1_2_Medium
> +hypervisor type: vmware
> +         memory: 1073741824 (bytes)
> +       nr vCPUs: 1
> +   CPU features: 
> +       firmware: uefi
> +        display: 
> +          video: 
> +          sound: 
> +disks:
> +	json:{ "file": { "driver": "raw", "offset": 2048, "size": 10240, "file": { "filename": "test.ova" } } }
> (vmdk) [scsi]
> +removable media:
> +	CD-ROM [ide] in slot 0
> +NICs:
> +	Network "Network adapter 1"
> +
> diff --git a/v2v/test-v2v-i-ova-subfolders.sh b/v2v/test-v2v-i-ova-subfolders.sh
> index 4fd1acea3..422959036 100755
> --- a/v2v/test-v2v-i-ova-subfolders.sh
> +++ b/v2v/test-v2v-i-ova-subfolders.sh
> @@ -56,10 +56,17 @@ popd
>  # normalize the output.
>  $VG virt-v2v --debug-gc --quiet \
>      -i ova $d/test.ova \
> -    --print-source |
> -sed 's,[^ \t]*\(subfolder/disk.*\.vmdk\),\1,' > $d/source
> +    --print-source > $d/source
>  
>  # Check the parsed source is what we expect.
> -diff -u test-v2v-i-ova-subfolders.expected $d/source
> +if qemu_is_version 2 8 ; then
> +    # normalize the output
> +    sed -i -e "s,\"$d/,\"," $d/source
> +    diff -u test-v2v-i-ova-subfolders.expected2 $d/source
> +else
> +    # normalize the output
> +    sed -i -e 's,[^ \t]*\(subfolder/disk.*\.vmdk\),\1,' $d/source
> +    diff -u test-v2v-i-ova-subfolders.expected $d/source
> +fi
>  
>  rm -rf $d
> diff --git a/v2v/test-v2v-i-ova-tar.expected b/v2v/test-v2v-i-ova-tar.expected
> new file mode 100644
> index 000000000..7049aeecc
> --- /dev/null
> +++ b/v2v/test-v2v-i-ova-tar.expected
> @@ -0,0 +1,18 @@
> +Source guest information (--print-source option):
> +
> +    source name: 2K8R2EESP1_2_Medium
> +hypervisor type: vmware
> +         memory: 1073741824 (bytes)
> +       nr vCPUs: 1
> +   CPU features: 
> +       firmware: uefi
> +        display: 
> +          video: 
> +          sound: 
> +disks:
> +	disk1.vmdk (vmdk) [scsi]
> +removable media:
> +	CD-ROM [ide] in slot 0
> +NICs:
> +	Network "Network adapter 1"
> +
> diff --git a/v2v/test-v2v-i-ova-tar.expected2 b/v2v/test-v2v-i-ova-tar.expected2
> new file mode 100644
> index 000000000..1aa54dc37
> --- /dev/null
> +++ b/v2v/test-v2v-i-ova-tar.expected2
> @@ -0,0 +1,18 @@
> +Source guest information (--print-source option):
> +
> +    source name: 2K8R2EESP1_2_Medium
> +hypervisor type: vmware
> +         memory: 1073741824 (bytes)
> +       nr vCPUs: 1
> +   CPU features: 
> +       firmware: uefi
> +        display: 
> +          video: 
> +          sound: 
> +disks:
> +	json:{ "file": { "driver": "raw", "offset": 9216, "size": 10240, "file": { "filename": "test-tar.ova" } } }
> (vmdk) [scsi]
> +removable media:
> +	CD-ROM [ide] in slot 0
> +NICs:
> +	Network "Network adapter 1"
> +
> diff --git a/v2v/test-v2v-i-ova-tar.ovf b/v2v/test-v2v-i-ova-tar.ovf
> new file mode 100644
> index 000000000..4827c7e9b
> --- /dev/null
> +++ b/v2v/test-v2v-i-ova-tar.ovf
> @@ -0,0 +1,138 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<Envelope vmw:buildId="build-1750787" 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="disk1.vmdk" ovf:id="file1" ovf:size="7804077568"/>
> +  </References>
> +  <DiskSection>
> +    <Info>Virtual disk information</Info>
> +    <Disk ovf:capacity="50" ovf:capacityAllocationUnits="byte * 2^30" ovf:diskId="vmdisk1" ovf:fileRef="file1"
> ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized"
> ovf:populatedSize="18975752192"/>
> +  </DiskSection>
> +  <NetworkSection>
> +    <Info>The list of logical networks</Info>
> +    <Network ovf:name="PG-VLAN60">
> +      <Description>The PG-VLAN60 network</Description>
> +    </Network>
> +  </NetworkSection>
> +  <VirtualSystem ovf:id="2K8R2EESP1_2_Medium">
> +    <Info>A virtual machine</Info>
> +    <Name>2K8R2EESP1_2_Medium</Name>
> +    <OperatingSystemSection ovf:id="103" vmw:osType="windows7Server64Guest">
> +      <Info>The kind of installed guest operating system</Info>
> +      <Description>Microsoft Windows Server 2008 R2 (64-bit)</Description>
> +    </OperatingSystemSection>
> +    <VirtualHardwareSection>
> +      <Info>Virtual hardware requirements</Info>
> +      <System>
> +        <vssd:ElementName>Virtual Hardware Family</vssd:ElementName>
> +        <vssd:InstanceID>0</vssd:InstanceID>
> +        <vssd:VirtualSystemIdentifier>2K8R2EESP1_2_Medium</vssd:VirtualSystemIdentifier>
> +        <vssd:VirtualSystemType>vmx-10</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>1024MB of memory</rasd:ElementName>
> +        <rasd:InstanceID>2</rasd:InstanceID>
> +        <rasd:ResourceType>4</rasd:ResourceType>
> +        <rasd:VirtualQuantity>1024</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>IDE 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>IDE 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>Video card</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="use3dRenderer" vmw:value="automatic"/>
> +        <vmw:Config ovf:required="false" vmw:key="useAutoDetect" vmw:value="true"/>
> +        <vmw:Config ovf:required="false" vmw:key="videoRamSizeInKB" vmw:value="4096"/>
> +      </Item>
> +      <Item ovf:required="false">
> +        <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
> +        <rasd:ElementName>VMCI device</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="32"/>
> +      </Item>
> +      <Item ovf:required="false">
> +        <rasd:AddressOnParent>0</rasd:AddressOnParent>
> +        <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
> +        <rasd:ElementName>CD/DVD drive 1</rasd:ElementName>
> +        <rasd:InstanceID>8</rasd:InstanceID>
> +        <rasd:Parent>4</rasd:Parent>
> +        <rasd:ResourceSubType>vmware.cdrom.atapi</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>
> +        <rasd:AddressOnParent>7</rasd:AddressOnParent>
> +        <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
> +        <rasd:Connection>PG-VLAN60</rasd:Connection>
> +        <rasd:Description>E1000 ethernet adapter on "PG-VLAN60"</rasd:Description>
> +        <rasd:ElementName>Network adapter 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="33"/>
> +        <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="efi"/>
> +      <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="upgradeAtPowerCycle"/>
> +    </VirtualHardwareSection>
> +  </VirtualSystem>
> +</Envelope>                                 
> diff --git a/v2v/test-v2v-i-ova-tar.sh b/v2v/test-v2v-i-ova-tar.sh
> new file mode 100755
> index 000000000..c3b0588f4
> --- /dev/null
> +++ b/v2v/test-v2v-i-ova-tar.sh
> @@ -0,0 +1,72 @@
> +#!/bin/bash -
> +# libguestfs virt-v2v test script
> +# Copyright (C) 2014-2016 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 with ova file compressed in different ways
> +
> +unset CDPATH
> +export LANG=C
> +set -e
> +
> +if [ -n "$SKIP_TEST_V2V_I_OVA_FORMATS_SH" ]; then
> +    echo "$0: test skipped because environment variable is set"
> +    exit 77
> +fi
> +
> +if [ "$(guestfish get-backend)" = "uml" ]; then
> +    echo "$0: test skipped because UML backend does not support network"
> +    exit 77
> +fi
> +
> +export VIRT_TOOLS_DATA_DIR="$srcdir/../test-data/fake-virt-tools"
> +
> +. $srcdir/../test-data/test-utils.sh
> +
> +d=test-v2v-i-ova-tar.d
> +rm -rf $d
> +mkdir $d
> +
> +pushd $d
> +
> +# Create a phony OVA.  This is only a test of source parsing, not
> +# conversion, so the contents of the disks doesn't matter.
> +truncate -s 10k disk1.vmdk
> +sha=`do_sha1 disk1.vmdk`
> +echo -e "SHA1(disk1.vmdk)= $sha\r" > disk1.mf
> +cp ../test-v2v-i-ova-tar.ovf .
> +tar -cf test-tar.ova test-v2v-i-ova-tar.ovf disk1.vmdk disk1.mf
> +
> +popd
> +
> +# Run virt-v2v but only as far as the --print-source stage
> +$VG virt-v2v --debug-gc --quiet \
> +    -i ova $d/test-tar.ova \
> +    --print-source > $d/source
> +
> +# Check the parsed source is what we expect.
> +if qemu_is_version 2 8 ; then
> +    # normalize the output
> +    sed -i -e "s,\"$d/,\"," $d/source
> +    diff -u test-v2v-i-ova-tar.expected2 $d/source
> +else
> +    # normalize the output
> +    sed -i -e 's,[^ \t]*\(disk.*.vmdk\),\1,' $d/source
> +    diff -u test-v2v-i-ova-tar.expected $d/source
> +fi
> +
> +
> +rm -rf $d
> diff --git a/v2v/test-v2v-i-ova-two-disks.expected2 b/v2v/test-v2v-i-ova-two-disks.expected2
> new file mode 100644
> index 000000000..b12ca1bd6
> --- /dev/null
> +++ b/v2v/test-v2v-i-ova-two-disks.expected2
> @@ -0,0 +1,19 @@
> +Source guest information (--print-source option):
> +
> +    source name: 2K8R2EESP1_2_Medium
> +hypervisor type: vmware
> +         memory: 1073741824 (bytes)
> +       nr vCPUs: 1
> +   CPU features: 
> +       firmware: bios
> +        display: 
> +          video: 
> +          sound: 
> +disks:
> +	json:{ "file": { "driver": "raw", "offset": 9728, "size": 10240, "file": { "filename": "test.ova" } } }
> (vmdk) [scsi]
> +	json:{ "file": { "driver": "raw", "offset": 21504, "size": 102400, "file": { "filename": "test.ova" } } }
> (vmdk) [scsi]
> +removable media:
> +	CD-ROM [ide] in slot 0
> +NICs:
> +	Network "Network adapter 1"
> +
> diff --git a/v2v/test-v2v-i-ova-two-disks.sh b/v2v/test-v2v-i-ova-two-disks.sh
> index 26dd19860..310aff1b9 100755
> --- a/v2v/test-v2v-i-ova-two-disks.sh
> +++ b/v2v/test-v2v-i-ova-two-disks.sh
> @@ -60,10 +60,17 @@ popd
>  # normalize the output.
>  $VG virt-v2v --debug-gc --quiet \
>      -i ova $d/test.ova \
> -    --print-source |
> -sed 's,[^ \t]*\(disk.*.vmdk\),\1,' > $d/source
> +    --print-source  > $d/source
>  
>  # Check the parsed source is what we expect.
> -diff -u test-v2v-i-ova-two-disks.expected $d/source
> +if qemu_is_version 2 8 ; then
> +    # normalize the output
> +    sed -i -e "s,\"$d/,\"," $d/source
> +    diff -u test-v2v-i-ova-two-disks.expected2 $d/source
> +else
> +    # normalize the output
> +    sed -i -e 's,[^ \t]*\(disk.*.vmdk\),\1,' $d/source
> +    diff -u test-v2v-i-ova-two-disks.expected $d/source
> +fi
>  
>  rm -rf $d




More information about the Libguestfs mailing list