VirtualBox

Ignore:
Timestamp:
Feb 20, 2017 10:28:47 AM (8 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
113542
Message:

bugref:8743. Workaround for correct OVF export VMs which share one or more virtual disks among them. This issue is tied with the part <vbox:machine> in the OVF description file.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/src-server/ApplianceImplExport.cpp

    r65530 r65807  
    905905    // might have UUIDs that need fixing after we know the UUIDs of the exported images
    906906    std::list<xml::ElementNode*> llElementsWithUuidAttributes;
    907 
     907    uint32_t ulFile = 1;
    908908    list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
    909909    /* Iterate through all virtual systems of that appliance */
     
    919919                                      enFormat,
    920920                                      stack);         // disks and networks stack
     921
     922        list<Utf8Str> diskList;
     923        list<Utf8Str>::const_iterator itS;
     924
     925        for (itS = stack.mapDiskSequenceForOneVM.begin();
     926             itS != stack.mapDiskSequenceForOneVM.end();
     927             ++itS)
     928        {
     929            const Utf8Str &strDiskID = *itS;
     930            const VirtualSystemDescriptionEntry *pDiskEntry = stack.mapDisks[strDiskID];
     931
     932            // source path: where the VBox image is
     933            const Utf8Str &strSrcFilePath = pDiskEntry->strVBoxCurrent;
     934            Bstr bstrSrcFilePath(strSrcFilePath);
     935
     936            //skip empty Medium. There are no information to add into section <References> or <DiskSection>
     937            if (strSrcFilePath.isEmpty() ||
     938                pDiskEntry->skipIt == true)
     939                continue;
     940
     941            // Do NOT check here whether the file exists. FindMedium will figure
     942            // that out, and filesystem-based tests are simply wrong in the
     943            // general case (think of iSCSI).
     944
     945            // We need some info from the source disks
     946            ComPtr<IMedium> pSourceDisk;
     947            //DeviceType_T deviceType = DeviceType_HardDisk;// by default
     948
     949            Log(("Finding source disk \"%ls\"\n", bstrSrcFilePath.raw()));
     950
     951            HRESULT rc;
     952
     953            if (pDiskEntry->type == VirtualSystemDescriptionType_HardDiskImage)
     954            {
     955                rc = mVirtualBox->OpenMedium(bstrSrcFilePath.raw(),
     956                                             DeviceType_HardDisk,
     957                                             AccessMode_ReadWrite,
     958                                             FALSE /* fForceNewUuid */,
     959                                             pSourceDisk.asOutParam());
     960                if (FAILED(rc))
     961                    throw rc;
     962            }
     963            else if (pDiskEntry->type == VirtualSystemDescriptionType_CDROM)//may be, this is CD/DVD
     964            {
     965                rc = mVirtualBox->OpenMedium(bstrSrcFilePath.raw(),
     966                                             DeviceType_DVD,
     967                                             AccessMode_ReadOnly,
     968                                             FALSE,
     969                                             pSourceDisk.asOutParam());
     970                if (FAILED(rc))
     971                    throw rc;
     972            }
     973
     974            Bstr uuidSource;
     975            rc = pSourceDisk->COMGETTER(Id)(uuidSource.asOutParam());
     976            if (FAILED(rc)) throw rc;
     977            Guid guidSource(uuidSource);
     978
     979            // output filename
     980            const Utf8Str &strTargetFileNameOnly = pDiskEntry->strOvf;
     981            // target path needs to be composed from where the output OVF is
     982            Utf8Str strTargetFilePath(strPath);
     983            strTargetFilePath.stripFilename();
     984            strTargetFilePath.append("/");
     985            strTargetFilePath.append(strTargetFileNameOnly);
     986
     987            // We are always exporting to VMDK stream optimized for now
     988            //Bstr bstrSrcFormat = L"VMDK";//not used
     989
     990            diskList.push_back(strTargetFilePath);
     991
     992            LONG64 cbCapacity = 0;     // size reported to guest
     993            rc = pSourceDisk->COMGETTER(LogicalSize)(&cbCapacity);
     994            if (FAILED(rc)) throw rc;
     995            /// @todo r=poetzsch: wrong it is reported in bytes ...
     996            // capacity is reported in megabytes, so...
     997            //cbCapacity *= _1M;
     998
     999            Guid guidTarget; /* Creates a new uniq number for the target disk. */
     1000            guidTarget.create();
     1001
     1002            // now handle the XML for the disk:
     1003            Utf8StrFmt strFileRef("file%RI32", ulFile++);
     1004            // <File ovf:href="WindowsXpProfessional-disk1.vmdk" ovf:id="file1" ovf:size="1710381056"/>
     1005            xml::ElementNode *pelmFile = pelmReferences->createChild("File");
     1006            pelmFile->setAttribute("ovf:id", strFileRef);
     1007            pelmFile->setAttribute("ovf:href", strTargetFileNameOnly);
     1008            /// @todo the actual size is not available at this point of time,
     1009            // cause the disk will be compressed. The 1.0 standard says this is
     1010            // optional! 1.1 isn't fully clear if the "gzip" format is used.
     1011            // Need to be checked. */
     1012            //            pelmFile->setAttribute("ovf:size", Utf8StrFmt("%RI64", cbFile).c_str());
     1013
     1014            // add disk to XML Disks section
     1015            // <Disk ovf:capacity="8589934592" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="..."/>
     1016            xml::ElementNode *pelmDisk = pelmDiskSection->createChild("Disk");
     1017            pelmDisk->setAttribute("ovf:capacity", Utf8StrFmt("%RI64", cbCapacity).c_str());
     1018            pelmDisk->setAttribute("ovf:diskId", strDiskID);
     1019            pelmDisk->setAttribute("ovf:fileRef", strFileRef);
     1020
     1021            if (pDiskEntry->type == VirtualSystemDescriptionType_HardDiskImage)//deviceType == DeviceType_HardDisk
     1022            {
     1023                pelmDisk->setAttribute("ovf:format",
     1024                                       (enFormat == ovf::OVFVersion_0_9)
     1025                                       ?  "http://www.vmware.com/specifications/vmdk.html#sparse"      // must be sparse or ovftoo
     1026                                       :  "http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized"
     1027                                       // correct string as communicated to us by VMware (public bug #6612)
     1028                                      );
     1029            }
     1030            else //pDiskEntry->type == VirtualSystemDescriptionType_CDROM, deviceType == DeviceType_DVD
     1031            {
     1032                pelmDisk->setAttribute("ovf:format",
     1033                                       "http://www.ecma-international.org/publications/standards/Ecma-119.htm"
     1034                                      );
     1035            }
     1036
     1037            // add the UUID of the newly target image to the OVF disk element, but in the
     1038            // vbox: namespace since it's not part of the standard
     1039            pelmDisk->setAttribute("vbox:uuid", Utf8StrFmt("%RTuuid", guidTarget.raw()).c_str());
     1040
     1041            // now, we might have other XML elements from vbox:Machine pointing to this image,
     1042            // but those would refer to the UUID of the _source_ image (which we created the
     1043            // export image from); those UUIDs need to be fixed to the export image
     1044            Utf8Str strGuidSourceCurly = guidSource.toStringCurly();
     1045            for (std::list<xml::ElementNode*>::iterator eit = llElementsWithUuidAttributes.begin();
     1046                 eit != llElementsWithUuidAttributes.end();
     1047                 ++eit)
     1048            {
     1049                xml::ElementNode *pelmImage = *eit;
     1050                Utf8Str strUUID;
     1051                pelmImage->getAttributeValue("uuid", strUUID);
     1052                if (strUUID == strGuidSourceCurly)
     1053                    // overwrite existing uuid attribute
     1054                    pelmImage->setAttribute("uuid", guidTarget.toStringCurly());
     1055            }
     1056        }
     1057        llElementsWithUuidAttributes.clear();
     1058        stack.mapDiskSequenceForOneVM.clear();
    9211059    }
    9221060
     
    9341072    }
    9351073
    936     // Finally, write out the disk info
    937     list<Utf8Str> diskList;
    938     uint32_t ulFile = 1;
    939     list<Utf8Str>::const_iterator itS;
    940 
    941     for (itS = stack.mapDiskSequence.begin();
    942          itS != stack.mapDiskSequence.end();
    943          ++itS)
    944     {
    945         const Utf8Str &strDiskID = *itS;
    946         const VirtualSystemDescriptionEntry *pDiskEntry = stack.mapDisks[strDiskID];
    947 
    948         // source path: where the VBox image is
    949         const Utf8Str &strSrcFilePath = pDiskEntry->strVBoxCurrent;
    950         Bstr bstrSrcFilePath(strSrcFilePath);
    951 
    952         //skip empty Medium. There are no information to add into section <References> or <DiskSection>
    953         if (strSrcFilePath.isEmpty() ||
    954             pDiskEntry->skipIt == true)
    955             continue;
    956 
    957         // Do NOT check here whether the file exists. FindMedium will figure
    958         // that out, and filesystem-based tests are simply wrong in the
    959         // general case (think of iSCSI).
    960 
    961         // We need some info from the source disks
    962         ComPtr<IMedium> pSourceDisk;
    963         //DeviceType_T deviceType = DeviceType_HardDisk;// by default
    964 
    965         Log(("Finding source disk \"%ls\"\n", bstrSrcFilePath.raw()));
    966 
    967         HRESULT rc;
    968 
    969         if (pDiskEntry->type == VirtualSystemDescriptionType_HardDiskImage)
    970         {
    971             rc = mVirtualBox->OpenMedium(bstrSrcFilePath.raw(),
    972                                          DeviceType_HardDisk,
    973                                          AccessMode_ReadWrite,
    974                                          FALSE /* fForceNewUuid */,
    975                                          pSourceDisk.asOutParam());
    976             if (FAILED(rc))
    977                 throw rc;
    978         }
    979         else if (pDiskEntry->type == VirtualSystemDescriptionType_CDROM)//may be, this is CD/DVD
    980         {
    981             rc = mVirtualBox->OpenMedium(bstrSrcFilePath.raw(),
    982                                          DeviceType_DVD,
    983                                          AccessMode_ReadOnly,
    984                                          FALSE,
    985                                          pSourceDisk.asOutParam());
    986             if (FAILED(rc))
    987                 throw rc;
    988         }
    989 
    990         Bstr uuidSource;
    991         rc = pSourceDisk->COMGETTER(Id)(uuidSource.asOutParam());
    992         if (FAILED(rc)) throw rc;
    993         Guid guidSource(uuidSource);
    994 
    995         // output filename
    996         const Utf8Str &strTargetFileNameOnly = pDiskEntry->strOvf;
    997         // target path needs to be composed from where the output OVF is
    998         Utf8Str strTargetFilePath(strPath);
    999         strTargetFilePath.stripFilename();
    1000         strTargetFilePath.append("/");
    1001         strTargetFilePath.append(strTargetFileNameOnly);
    1002 
    1003         // We are always exporting to VMDK stream optimized for now
    1004         //Bstr bstrSrcFormat = L"VMDK";//not used
    1005 
    1006         diskList.push_back(strTargetFilePath);
    1007 
    1008         LONG64 cbCapacity = 0;     // size reported to guest
    1009         rc = pSourceDisk->COMGETTER(LogicalSize)(&cbCapacity);
    1010         if (FAILED(rc)) throw rc;
    1011         /// @todo r=poetzsch: wrong it is reported in bytes ...
    1012         // capacity is reported in megabytes, so...
    1013         //cbCapacity *= _1M;
    1014 
    1015         Guid guidTarget; /* Creates a new uniq number for the target disk. */
    1016         guidTarget.create();
    1017 
    1018         // now handle the XML for the disk:
    1019         Utf8StrFmt strFileRef("file%RI32", ulFile++);
    1020         // <File ovf:href="WindowsXpProfessional-disk1.vmdk" ovf:id="file1" ovf:size="1710381056"/>
    1021         xml::ElementNode *pelmFile = pelmReferences->createChild("File");
    1022         pelmFile->setAttribute("ovf:id", strFileRef);
    1023         pelmFile->setAttribute("ovf:href", strTargetFileNameOnly);
    1024         /// @todo the actual size is not available at this point of time,
    1025         // cause the disk will be compressed. The 1.0 standard says this is
    1026         // optional! 1.1 isn't fully clear if the "gzip" format is used.
    1027         // Need to be checked. */
    1028         //            pelmFile->setAttribute("ovf:size", Utf8StrFmt("%RI64", cbFile).c_str());
    1029 
    1030         // add disk to XML Disks section
    1031         // <Disk ovf:capacity="8589934592" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="..."/>
    1032         xml::ElementNode *pelmDisk = pelmDiskSection->createChild("Disk");
    1033         pelmDisk->setAttribute("ovf:capacity", Utf8StrFmt("%RI64", cbCapacity).c_str());
    1034         pelmDisk->setAttribute("ovf:diskId", strDiskID);
    1035         pelmDisk->setAttribute("ovf:fileRef", strFileRef);
    1036 
    1037         if (pDiskEntry->type == VirtualSystemDescriptionType_HardDiskImage)//deviceType == DeviceType_HardDisk
    1038         {
    1039             pelmDisk->setAttribute("ovf:format",
    1040                                    (enFormat == ovf::OVFVersion_0_9)
    1041                                    ?  "http://www.vmware.com/specifications/vmdk.html#sparse"      // must be sparse or ovftool ch
    1042                                    :  "http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized"
    1043                                    // correct string as communicated to us by VMware (public bug #6612)
    1044                                   );
    1045         }
    1046         else //pDiskEntry->type == VirtualSystemDescriptionType_CDROM, deviceType == DeviceType_DVD
    1047         {
    1048             pelmDisk->setAttribute("ovf:format",
    1049                                    "http://www.ecma-international.org/publications/standards/Ecma-119.htm"
    1050                                   );
    1051         }
    1052 
    1053         // add the UUID of the newly target image to the OVF disk element, but in the
    1054         // vbox: namespace since it's not part of the standard
    1055         pelmDisk->setAttribute("vbox:uuid", Utf8StrFmt("%RTuuid", guidTarget.raw()).c_str());
    1056 
    1057         // now, we might have other XML elements from vbox:Machine pointing to this image,
    1058         // but those would refer to the UUID of the _source_ image (which we created the
    1059         // export image from); those UUIDs need to be fixed to the export image
    1060         Utf8Str strGuidSourceCurly = guidSource.toStringCurly();
    1061         for (std::list<xml::ElementNode*>::iterator eit = llElementsWithUuidAttributes.begin();
    1062              eit != llElementsWithUuidAttributes.end();
    1063              ++eit)
    1064         {
    1065             xml::ElementNode *pelmImage = *eit;
    1066             Utf8Str strUUID;
    1067             pelmImage->getAttributeValue("uuid", strUUID);
    1068             if (strUUID == strGuidSourceCurly)
    1069                 // overwrite existing uuid attribute
    1070                 pelmImage->setAttribute("uuid", guidTarget.toStringCurly());
    1071         }
    1072     }
    10731074}
    10741075
     
    15531554                        //in the OVF description file.
    15541555                        stack.mapDiskSequence.push_back(strDiskID);
     1556                        stack.mapDiskSequenceForOneVM.push_back(strDiskID);
    15551557                    }
    15561558                    break;
     
    16291631                        //in the OVF description file.
    16301632                        stack.mapDiskSequence.push_back(strDiskID);
     1633                        stack.mapDiskSequenceForOneVM.push_back(strDiskID);
    16311634                        // there is no DVD drive map to update because it is
    16321635                        // handled completely with this entry.
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette