VirtualBox

Changeset 78602 in vbox for trunk/src/VBox


Ignore:
Timestamp:
May 20, 2019 4:26:10 PM (6 years ago)
Author:
vboxsync
Message:

bugref:9416. The second part of OCI import - the local part of import - extracting, conversion the images, creating VM.

Location:
trunk/src/VBox/Main
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/include/ovfreader.h

    r76562 r78602  
    664664{
    665665public:
     666    OVFReader();
    666667    OVFReader(const void *pvBuf, size_t cbSize, const RTCString &path);
    667668    OVFReader(const RTCString &path);
  • trunk/src/VBox/Main/src-server/ApplianceImplImport.cpp

    r78430 r78602  
    5151#include "ApplianceImplPrivate.h"
    5252#include "CertificateImpl.h"
     53#include "ovfreader.h"
    5354
    5455#include <VBox/param.h>
     
    11951196    {
    11961197        Utf8Str strBasename(pTask->locInfo.strPath);
    1197         RTCList<RTCString, RTCString *> parts = strBasename.split("/");
     1198        RTCList<RTCString, RTCString *> parts = strBasename.split("/" );
    11981199        if (parts.size() != 2)//profile + instance id
    11991200        {
     
    12501251                             Bstr(profileName).raw(),
    12511252                             Bstr(profileName).raw());
    1252         // set name
    1253         Utf8Str strSetting = "cloud VM (";
    1254         strSetting.append(parts.at(1)).append(")");
     1253
     1254        Utf8StrFmt strSetting("VM with id %s imported from the cloud provider %s",
     1255                              parts.at(1).c_str(), strProviderName.c_str());
    12551256        // set description
    1256         strSetting = "VM with id ";
    1257         strSetting.append(parts.at(1)).append(" imported from the cloud provider ").append(strProviderName);
    1258 
    1259         // description
    12601257        instanceDescription->AddDescription(VirtualSystemDescriptionType_Description,
    12611258                             Bstr(strSetting).raw(),
     
    12851282    LogFlowFunc(("Appliance %p\n", this));
    12861283
     1284    int vrc = VINF_SUCCESS;
     1285    HRESULT hrc = S_OK;
     1286    Utf8Str strLastActualErrorDesc("No errors");
     1287
    12871288    /* Change the appliance state so we can safely leave the lock while doing
    12881289     * time-consuming operations; also the below method calls do all kinds of
    12891290     * locking which conflicts with the appliance object lock. */
    12901291    AutoWriteLock writeLock(this COMMA_LOCKVAL_SRC_POS);
     1292
    12911293    /* Check if the appliance is currently busy. */
    12921294    if (!i_isApplianceIdle())
     
    12941296    /* Set the internal state to importing. */
    12951297    m->state = Data::ApplianceImporting;
    1296 
    1297     HRESULT hrc = S_OK;
     1298    writeLock.release();
    12981299
    12991300    /* Clear the list of imported machines, if any */
    13001301    m->llGuidsMachinesCreated.clear();
    1301 
    1302     /*
    1303      * Actual code for the cloud import
    1304      *
    1305     */
    13061302
    13071303    ComPtr<ICloudProviderManager> cpm;
     
    13181314        return setErrorVrc(VERR_COM_OBJECT_NOT_FOUND, tr("%s: Cloud provider object wasn't found", __FUNCTION__));
    13191315
     1316    /* Get the actual VSD, only one VSD object can be there for now so just call the function front() */
    13201317    ComPtr<IVirtualSystemDescription> vsd = m->virtualSystemDescriptions.front();
    13211318
     1319    Utf8Str vsdData;
    13221320    com::SafeArray<VirtualSystemDescriptionType_T> retTypes;
    13231321    com::SafeArray<BSTR> aRefs;
     
    13261324    com::SafeArray<BSTR> aExtraConfigValues;
    13271325
    1328     hrc = vsd->GetDescriptionByType(VirtualSystemDescriptionType_CloudProfileName,
    1329                              ComSafeArrayAsOutParam(retTypes),
    1330                              ComSafeArrayAsOutParam(aRefs),
    1331                              ComSafeArrayAsOutParam(aOvfValues),
    1332                              ComSafeArrayAsOutParam(aVBoxValues),
    1333                              ComSafeArrayAsOutParam(aExtraConfigValues));
    1334     if (FAILED(hrc))
    1335         return hrc;
     1326/*
     1327 * local #define  for better reading the code
     1328 * uses only the previously locally declared variable names
     1329 * set hrc as the result of operation
     1330 */
     1331#define GET_VSD_DESCRIPTION_BY_TYPE(aParamType) \
     1332    retTypes.setNull(); \
     1333    aRefs.setNull(); \
     1334    aOvfValues.setNull(); \
     1335    aVBoxValues.setNull(); \
     1336    aExtraConfigValues.setNull(); \
     1337    vsd->GetDescriptionByType(aParamType, \
     1338        ComSafeArrayAsOutParam(retTypes), \
     1339        ComSafeArrayAsOutParam(aRefs), \
     1340        ComSafeArrayAsOutParam(aOvfValues), \
     1341        ComSafeArrayAsOutParam(aVBoxValues), \
     1342        ComSafeArrayAsOutParam(aExtraConfigValues)); \
     1343
     1344
     1345    GET_VSD_DESCRIPTION_BY_TYPE(VirtualSystemDescriptionType_CloudProfileName)
     1346    if (aVBoxValues.size() == 0)
     1347        return setErrorVrc(VERR_NOT_FOUND, tr("%s: Cloud user profile name wasn't found", __FUNCTION__));
    13361348
    13371349    Utf8Str profileName(aVBoxValues[0]);
    13381350    if (profileName.isEmpty())
    1339         return setErrorVrc(VBOX_E_OBJECT_NOT_FOUND, tr("%s: Cloud user profile name wasn't found", __FUNCTION__));
     1351        return setErrorVrc(VERR_INVALID_STATE, tr("%s: Cloud user profile name is empty", __FUNCTION__));
    13401352
    13411353    hrc = cloudProvider->GetProfileByName(aVBoxValues[0], cloudProfile.asOutParam());
     
    13481360        return setErrorVrc(VERR_COM_OBJECT_NOT_FOUND, tr("%s: Cloud client object wasn't found", __FUNCTION__));
    13491361
     1362    ComPtr<IProgress> pProgress;
     1363    hrc = pTask->pProgress.queryInterfaceTo(pProgress.asOutParam());
     1364    if (FAILED(hrc))
     1365        return hrc;
     1366
     1367    Utf8Str strOsType;
     1368    ComPtr<IGuestOSType> pGuestOSType;
     1369    {
     1370        GET_VSD_DESCRIPTION_BY_TYPE(VirtualSystemDescriptionType_OS)//aVBoxValues is set in this #define
     1371        if (aVBoxValues.size() != 0)
     1372            strOsType = aVBoxValues[0];
     1373        else
     1374            return setErrorVrc(VERR_NOT_FOUND, "%s: OS type wasn't found", __FUNCTION__);
     1375        LogRel(("%s: OS type is %s\n", __FUNCTION__, strOsType.c_str()));
     1376
     1377        /* Check the OS type and get the structure with the some default settings for this OS type */
     1378        uint32_t const idxOSType = Global::getOSTypeIndexFromId(strOsType.c_str());
     1379        VBOXOSTYPE guestOsType = idxOSType < Global::cOSTypes ? Global::sOSTypes[idxOSType].osType : VBOXOSTYPE_Unknown;
     1380        if (guestOsType == VBOXOSTYPE_Unknown)
     1381            return setErrorVrc(VERR_NOT_SUPPORTED, "%s: OS type is unknown", __FUNCTION__);
     1382
     1383        /* We can get some default settings from GuestOSType when it's needed */
     1384        mVirtualBox->GetGuestOSType(Bstr(strOsType).raw(), pGuestOSType.asOutParam());
     1385    }
     1386
     1387    /* Should be defined here because it's used later, at least when ComposeMachineFilename() is called */
     1388    Utf8Str strVMName("VM_exported_from_cloud");
     1389
    13501390    if (m->virtualSystemDescriptions.size() == 1)
    13511391    {
     
    13531393        {
    13541394            ComPtr<IVirtualBox> VBox(mVirtualBox);
    1355             retTypes.setNull();
    1356             aRefs.setNull();
    1357             aOvfValues.setNull();
    1358             aVBoxValues.setNull();
    1359             aExtraConfigValues.setNull();
    1360             hrc = vsd->GetDescriptionByType(VirtualSystemDescriptionType_CloudInstanceId,
    1361                                             ComSafeArrayAsOutParam(retTypes),
    1362                                             ComSafeArrayAsOutParam(aRefs),
    1363                                             ComSafeArrayAsOutParam(aOvfValues),
    1364                                             ComSafeArrayAsOutParam(aVBoxValues),
    1365                                             ComSafeArrayAsOutParam(aExtraConfigValues));
    1366             if (FAILED(hrc))
     1395
     1396            {
     1397                GET_VSD_DESCRIPTION_BY_TYPE(VirtualSystemDescriptionType_Name)//aVBoxValues is set in this #define
     1398                if (aVBoxValues.size() != 0)//paranoia but anyway...
     1399                    strVMName = aVBoxValues[0];
     1400                LogRel(("%s: VM name is %s\n", __FUNCTION__, strVMName.c_str()));
     1401            }
     1402
     1403//          i_searchUniqueVMName(strVMName);//internally calls setError() in the case of absent the registered VM with such name
     1404
     1405            ComPtr<IMachine> machine;
     1406            hrc = mVirtualBox->FindMachine(Bstr(strVMName.c_str()).raw(), machine.asOutParam());
     1407            if (SUCCEEDED(hrc))
     1408            {
     1409                //what to do? create a new name from the old one with some suffix?
     1410                com::Guid newId;
     1411                newId.create();
     1412                strVMName.append("__").append(newId.toString());
     1413                vsd->RemoveDescriptionByType(VirtualSystemDescriptionType_Name);
     1414                vsd->AddDescription(VirtualSystemDescriptionType_Name,
     1415                                    Bstr(strVMName).raw(),
     1416                                    Bstr(strVMName).raw());
     1417                //No check again because it would be weird if a VM with such unique name exists
     1418            }
     1419
     1420            Utf8Str strInsId;
     1421            GET_VSD_DESCRIPTION_BY_TYPE(VirtualSystemDescriptionType_CloudInstanceId)//aVBoxValues is set in this #define
     1422            if (aVBoxValues.size() == 0)
     1423            {
     1424                hrc = setErrorVrc(VERR_NOT_FOUND, "%s: Cloud Instance Id wasn't found", __FUNCTION__);         
    13671425                break;
    1368 
    1369             ComPtr<IProgress> pProgress;
    1370             pTask->pProgress.queryInterfaceTo(pProgress.asOutParam());
     1426            }
     1427            strInsId = aVBoxValues[0];
    13711428
    13721429            LogRel(("%s: calling CloudClient::ImportInstance\n", __FUNCTION__));
     1430
     1431            /* Here it's strongly supposed that cloud import produces ONE object on the disk.
     1432               Because it much easier to manage one object in any case.
     1433               In the case when cloud import creates several object on the disk all of them
     1434               must be combined together into one object by cloud client.
     1435               The most simple way is to create a TAR archive. */
    13731436            hrc = cloudClient->ImportInstance(m->virtualSystemDescriptions.front(),
    13741437                                              aVBoxValues[0],
    13751438                                              VBox,
    13761439                                              pProgress);
    1377             Bstr instId(aVBoxValues[0]);
    1378             Utf8Str strInsId(instId);
     1440
     1441            hrc = S_OK;
    13791442            if (FAILED(hrc))
    13801443            {
    1381                 hrc = setError(hrc, "%s: Import cloud instance \'%s\' failed\n", __FUNCTION__, strInsId.c_str());
     1444                strLastActualErrorDesc = Utf8StrFmt("%s: Cloud import (cloud phase) failed. "
     1445                        "Used cloud instance is \'%s\'\n", __FUNCTION__, strInsId.c_str());
     1446
     1447                LogRel((strLastActualErrorDesc.c_str()));
     1448                hrc = setError(hrc, strLastActualErrorDesc.c_str());
    13821449                break;
    13831450            }
    13841451
    1385             Utf8Str vsdData;
    1386 
    1387             retTypes.setNull();
    1388             aRefs.setNull();
    1389             aOvfValues.setNull();
    1390             aVBoxValues.setNull();
    1391             aExtraConfigValues.setNull();
    1392             hrc = vsd->GetDescriptionByType(VirtualSystemDescriptionType_CPU,
    1393                                             ComSafeArrayAsOutParam(retTypes),
    1394                                             ComSafeArrayAsOutParam(aRefs),
    1395                                             ComSafeArrayAsOutParam(aOvfValues),
    1396                                             ComSafeArrayAsOutParam(aVBoxValues),
    1397                                             ComSafeArrayAsOutParam(aExtraConfigValues));
    1398             if (FAILED(hrc))
    1399                 break;
    1400             vsdData = aVBoxValues[0];
    1401             if (vsdData.isEmpty())
    1402                 LogRel(("%s: Number of CPUs wasn't found\n", __FUNCTION__));
     1452        } while (0);
     1453    }
     1454    else
     1455    {
     1456        vrc = VERR_NOT_SUPPORTED;
     1457        hrc = setErrorVrc(vrc, tr("Import from Cloud isn't supported for more than one VM instance."));
     1458
     1459        /* Reset the state so others can call methods again */
     1460        m->state = Data::ApplianceIdle;
     1461        return hrc;
     1462    }
     1463   
     1464    if (FAILED(hrc))
     1465    {
     1466        HRESULT temp_hrc = hrc;//save the original result
     1467        Utf8Str generalRollBackErrorMessage("Rollback action for Import Cloud operation failed."
     1468                                            "Some leavings may exist on the local disk or in the Cloud.");
     1469        /*
     1470         * Roll-back actions.
     1471         * we finish here if:
     1472         * 1. The getting the object form the Cloud has been failed.
     1473         * 2. Something is wrong with getting data from ComPtr<IVirtualSystemDescription> vsd.
     1474         * 3. More than 1 VirtualSystemDescription is presented in the list m->virtualSystemDescriptions.
     1475         * Maximum what we have there are:
     1476         * 1. The downloaded object, so just check the presence and delete it if one exists
     1477         * 2. Some leftovers in the Cloud. Also delete them too if it's possible.
     1478         *    Should they be deleted in the OCICloudClient::importInstance()?
     1479         *    Because deleting them here is not easy as it in the importInstance().
     1480         */
     1481
     1482        {
     1483            /* small explanation here, the image here points out to the whole downloaded object (not to the image only)
     1484             * filled during the first cloud import stage (in the ICloudClient::importInstance()) */
     1485            GET_VSD_DESCRIPTION_BY_TYPE(VirtualSystemDescriptionType_HardDiskImage)//aVBoxValues is set in this #define
     1486            if (aVBoxValues.size() == 0)
     1487                hrc = setErrorVrc(VERR_NOT_FOUND, generalRollBackErrorMessage.c_str());
    14031488            else
    1404                 LogRel(("%s: Number of CPUs is %s\n", __FUNCTION__, vsdData.c_str()));
    1405 
    1406             retTypes.setNull();
    1407             aRefs.setNull();
    1408             aOvfValues.setNull();
    1409             aVBoxValues.setNull();
    1410             aExtraConfigValues.setNull();
    1411             hrc = vsd->GetDescriptionByType(VirtualSystemDescriptionType_Memory,
    1412                                             ComSafeArrayAsOutParam(retTypes),
    1413                                             ComSafeArrayAsOutParam(aRefs),
    1414                                             ComSafeArrayAsOutParam(aOvfValues),
    1415                                             ComSafeArrayAsOutParam(aVBoxValues),
    1416                                             ComSafeArrayAsOutParam(aExtraConfigValues));
    1417             if (FAILED(hrc))
    1418                 break;
    1419             vsdData = aVBoxValues[0];
    1420             if (vsdData.isEmpty())
    1421                 LogRel(("%s: Size of RAM wasn't found\n", __FUNCTION__));
     1489            {
     1490                vsdData = aVBoxValues[0];
     1491                //try to delete the downloaded object
     1492                bool fExist = RTPathExists(vsdData.c_str());
     1493                if (fExist)
     1494                {
     1495                    vrc = RTFileDelete(vsdData.c_str());
     1496                    if (RT_FAILURE(vrc))
     1497                    {
     1498                        hrc = setErrorVrc(vrc, generalRollBackErrorMessage.c_str());
     1499                        LogRel(("%s: Rollback action - the object %s hasn't been deleted\n", __FUNCTION__, vsdData.c_str()));
     1500                    }
     1501                    else
     1502                        LogRel(("%s: Rollback action - the object %s has been deleted\n", __FUNCTION__, vsdData.c_str()));
     1503                }
     1504            }
     1505        }
     1506
     1507        {
     1508            GET_VSD_DESCRIPTION_BY_TYPE(VirtualSystemDescriptionType_CloudInstanceId)//aVBoxValues is set in this #define
     1509            if (aVBoxValues.size() == 0)
     1510                hrc = setErrorVrc(VERR_NOT_FOUND, generalRollBackErrorMessage.c_str());
    14221511            else
    1423                 LogRel(("%s: Size of RAM is %sMB\n", __FUNCTION__, vsdData.c_str()));
    1424 
    1425             retTypes.setNull();
    1426             aRefs.setNull();
    1427             aOvfValues.setNull();
    1428             aVBoxValues.setNull();
    1429             aExtraConfigValues.setNull();
    1430             hrc = vsd->GetDescriptionByType(VirtualSystemDescriptionType_OS,
    1431                                             ComSafeArrayAsOutParam(retTypes),
    1432                                             ComSafeArrayAsOutParam(aRefs),
    1433                                             ComSafeArrayAsOutParam(aOvfValues),
    1434                                             ComSafeArrayAsOutParam(aVBoxValues),
    1435                                             ComSafeArrayAsOutParam(aExtraConfigValues));
    1436             if (FAILED(hrc))
    1437                 break;
    1438             vsdData = aVBoxValues[0];
    1439             if (vsdData.isEmpty())
    1440                 LogRel(("%s: OS type wasn't found", __FUNCTION__));
    1441             else
    1442                 LogRel(("%s: OS type is %s\n", __FUNCTION__, vsdData.c_str()));
    1443 
    1444             retTypes.setNull();
    1445             aRefs.setNull();
    1446             aOvfValues.setNull();
    1447             aVBoxValues.setNull();
    1448             aExtraConfigValues.setNull();
    1449             hrc = vsd->GetDescriptionByType(VirtualSystemDescriptionType_Name,
    1450                                             ComSafeArrayAsOutParam(retTypes),
    1451                                             ComSafeArrayAsOutParam(aRefs),
    1452                                             ComSafeArrayAsOutParam(aOvfValues),
    1453                                             ComSafeArrayAsOutParam(aVBoxValues),
    1454                                             ComSafeArrayAsOutParam(aExtraConfigValues));
    1455             if (FAILED(hrc))
    1456                 break;
    1457             vsdData = aVBoxValues[0];
    1458             if (vsdData.isEmpty())
    1459                 LogRel(("%s: VM name wasn't found", __FUNCTION__));
    1460             else
    1461                 LogRel(("%s: VM name is %s\n", __FUNCTION__, vsdData.c_str()));
    1462         } while (0);
     1512            {
     1513                vsdData = aVBoxValues[0];
     1514                //hrc = cloud.EliminateImportLeavings(aVBoxValues[0], pProgress);//future function
     1515                if (FAILED(hrc))
     1516                {
     1517                    hrc = setErrorVrc(VERR_INVALID_STATE, generalRollBackErrorMessage.c_str());
     1518                    LogRel(("%s: Rollback action - the leavings in the %s after import the "
     1519                            "instance %s may not have been deleted\n",
     1520                            __FUNCTION__, strProviderName.c_str(), vsdData.c_str()));
     1521                }
     1522                else
     1523                    LogRel(("%s: Rollback action - the leavings in the %s after import the "
     1524                            "instance %s have been deleted\n",
     1525                            __FUNCTION__, strProviderName.c_str(), vsdData.c_str()));
     1526            }
     1527        }
     1528
     1529        /* Because during the rollback phase the hrc may have the good result
     1530         * Thus we restore the original error in the case when the rollback phase was successful
     1531         * Otherwise we return not the original error but the last error in the rollback phase */
     1532        if (SUCCEEDED(hrc))
     1533            hrc = setError(temp_hrc, strLastActualErrorDesc.c_str());//restore the original result
    14631534    }
    14641535    else
    1465         hrc = setErrorVrc(VERR_MISMATCH, tr("Import from Cloud isn't supported for more than one VM instance."));
    1466 
    1467     if (FAILED(hrc))
    1468     {
    1469         //some roll-back actions
    1470     }
    1471     else
    1472     {
    1473         //continue and create new VM using data from VSD and downloaded image as base image
    1474         //The downloaded image should be converted to VDI/VMDK if it has another format
     1536    {
     1537
     1538        /* Small explanation here, the image here points out to the whole downloaded object (not to the image only)
     1539         * filled during the first cloud import stage (in the ICloudClient::importInstance()) */
     1540        GET_VSD_DESCRIPTION_BY_TYPE(VirtualSystemDescriptionType_HardDiskImage)//aVBoxValues is set in this #define
     1541        if (aVBoxValues.size() == 0)
     1542            throw setErrorVrc(VERR_NOT_FOUND, "%s: The description of the downloaded object wasn't found", __FUNCTION__);
     1543
     1544        Utf8Str strAbsSrcPath(aVBoxValues[0]);
     1545
     1546        /* Put all VFS* declaration here because they are needed to be release by the corresponding
     1547           RTVfs***Release functions in the case of exception */
     1548        RTVFSOBJ     hVfsObj;
     1549        RTVFSFSSTREAM hVfsFssObject;
     1550        RTVFSIOSTREAM hVfsIosCurr;
     1551
     1552        /* Continue and create new VM using data from VSD and downloaded object.
     1553         * The downloaded images should be converted to VDI/VMDK if they have another format */
     1554        try
     1555        {
     1556            Utf8Str strInstId("default cloud instance id");
     1557            {
     1558                GET_VSD_DESCRIPTION_BY_TYPE(VirtualSystemDescriptionType_CloudInstanceId)//aVBoxValues is set in this #define
     1559                if (aVBoxValues.size() != 0)//paranoia but anyway...
     1560                    strInstId = aVBoxValues[0];
     1561                LogRel(("%s: Importing cloud instance %s\n", __FUNCTION__, strInstId.c_str()));
     1562            }
     1563
     1564            Utf8Str strGroup("/");//default VM group
     1565            Utf8Str strTargetFormat("VMDK");//default image format
     1566
     1567            /* Based on the VM name, create a target machine path. */
     1568            Bstr bstrSettingsFilename;
     1569            hrc = mVirtualBox->ComposeMachineFilename(Bstr(strVMName).raw(),
     1570                                                      Bstr(strGroup).raw(),
     1571                                                      NULL /* aCreateFlags */,
     1572                                                      NULL /* aBaseFolder */,
     1573                                                      bstrSettingsFilename.asOutParam());
     1574            if (FAILED(hrc)) throw hrc;
     1575
     1576            Utf8Str strMachineFolder(bstrSettingsFilename);
     1577            strMachineFolder.stripFilename();
     1578
     1579            /* Get the system properties. */
     1580            SystemProperties *pSysProps = mVirtualBox->i_getSystemProperties();
     1581
     1582            ComObjPtr<MediumFormat> trgFormat;
     1583            trgFormat = pSysProps->i_mediumFormatFromExtension(strTargetFormat);
     1584
     1585            /* Processing the downloaded object (prepare for the local import) */
     1586            RTVFSIOSTREAM hVfsIosSrc;
     1587            vrc = RTVfsIoStrmOpenNormal(strAbsSrcPath.c_str(), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, &hVfsIosSrc);
     1588            if (RT_FAILURE(vrc))
     1589            {
     1590                strLastActualErrorDesc = Utf8StrFmt("Error opening '%s' for reading (%Rrc)\n", strAbsSrcPath.c_str(), vrc);
     1591                throw setErrorVrc(vrc, strLastActualErrorDesc.c_str());
     1592            }
     1593
     1594            vrc = RTZipTarFsStreamFromIoStream(hVfsIosSrc, 0 /*fFlags*/, &hVfsFssObject);
     1595            RTVfsIoStrmRelease(hVfsIosSrc);
     1596            if (RT_FAILURE(vrc))
     1597            {
     1598                strLastActualErrorDesc = Utf8StrFmt("Error reading the downloaded file '%s' (%Rrc)", strAbsSrcPath.c_str(), vrc);
     1599                throw setErrorVrc(vrc, strLastActualErrorDesc.c_str());
     1600            }
     1601
     1602            /* Create an empty ovf::OVFReader for manual filling it.
     1603             * It's not a normal usage case, but we try to re-use some OVF stuff to friend
     1604             * the cloud import with OVF import.
     1605             * In the standard case the ovf::OVFReader is created earlier.*/
     1606            m->pReader = new ovf::OVFReader();
     1607
     1608            /* Create a new virtual system and work directly on the list copy. */
     1609            m->pReader->m_llVirtualSystems.push_back(ovf::VirtualSystem());
     1610            ovf::VirtualSystem &vsys = m->pReader->m_llVirtualSystems.back();
     1611
     1612            /* Try to re-use some OVF stuff here */
     1613            {
     1614                vsys.strName = strVMName;
     1615                uint32_t cpus = 1;
     1616                {
     1617                    GET_VSD_DESCRIPTION_BY_TYPE(VirtualSystemDescriptionType_CPU)//aVBoxValues is set in this #define
     1618                    if (aVBoxValues.size() != 0)
     1619                    {
     1620                        vsdData = aVBoxValues[0];
     1621                        cpus = vsdData.toUInt32();
     1622                    }
     1623                    vsys.cCPUs = (uint16_t)cpus;
     1624                    LogRel(("%s: Number of CPUs is %s\n", __FUNCTION__, vsdData.c_str()));
     1625                }
     1626
     1627                ULONG memory;//Mb
     1628                pGuestOSType->COMGETTER(RecommendedRAM)(&memory);
     1629                {
     1630                    GET_VSD_DESCRIPTION_BY_TYPE(VirtualSystemDescriptionType_Memory)//aVBoxValues is set in this #define
     1631                    if (aVBoxValues.size() != 0)
     1632                    {
     1633                        vsdData = aVBoxValues[0];
     1634                        memory = vsdData.toUInt32();
     1635                    }
     1636                    vsys.ullMemorySize = memory;
     1637                    LogRel(("%s: Size of RAM is %sMB\n", __FUNCTION__, vsdData.c_str()));
     1638                }
     1639
     1640                {
     1641                    GET_VSD_DESCRIPTION_BY_TYPE(VirtualSystemDescriptionType_Description)//aVBoxValues is set in this #define
     1642                    if (aVBoxValues.size() != 0)
     1643                    {
     1644                        vsdData = aVBoxValues[0];
     1645                        vsys.strDescription = vsdData;
     1646                    }
     1647                    LogRel(("%s: VM description \'%s\'\n", __FUNCTION__, vsdData.c_str()));
     1648                }
     1649
     1650                {
     1651                    GET_VSD_DESCRIPTION_BY_TYPE(VirtualSystemDescriptionType_OS)//aVBoxValues is set in this #define
     1652                    if (aVBoxValues.size() != 0)
     1653                        strOsType = aVBoxValues[0];
     1654                    vsys.strTypeVBox = strOsType;     
     1655                    LogRel(("%s: OS type is %s\n", __FUNCTION__, strOsType.c_str()));
     1656                }
     1657
     1658                ovf::EthernetAdapter ea;
     1659                {
     1660                    GET_VSD_DESCRIPTION_BY_TYPE(VirtualSystemDescriptionType_NetworkAdapter)//aVBoxValues is set in this #define
     1661                    if (aVBoxValues.size() != 0)
     1662                    {
     1663                        ea.strAdapterType = (Utf8Str)(aVBoxValues[0]);
     1664                        ea.strNetworkName = "NAT";//default
     1665                        vsys.llEthernetAdapters.push_back(ea);
     1666                        LogRel(("%s: Network adapter type is %s\n", __FUNCTION__, ea.strAdapterType.c_str()));
     1667                    }
     1668                    else
     1669                    {
     1670                        NetworkAdapterType_T defaultAdapterType = NetworkAdapterType_Am79C970A;
     1671                        pGuestOSType->COMGETTER(AdapterType)(&defaultAdapterType);
     1672                        Utf8StrFmt dat("%RU32", (uint32_t)defaultAdapterType);
     1673                        vsd->AddDescription(VirtualSystemDescriptionType_NetworkAdapter,
     1674                                            Bstr(dat).raw(),
     1675                                            Bstr(Utf8Str("NAT")).raw());
     1676                    }
     1677                }
     1678
     1679                ovf::HardDiskController hdc;
     1680                {
     1681                    //It's thought that SATA is supported by any OS types
     1682                    hdc.system = ovf::HardDiskController::SATA;
     1683                    hdc.idController = 0;
     1684
     1685                    GET_VSD_DESCRIPTION_BY_TYPE(VirtualSystemDescriptionType_HardDiskControllerSATA)//aVBoxValues is set in this #define
     1686                    if (aVBoxValues.size() != 0)
     1687                        hdc.strControllerType = (Utf8Str)(aVBoxValues[0]);
     1688                    else
     1689                        hdc.strControllerType = "AHCI";
     1690
     1691                    LogRel(("%s: Hard disk controller type is %s\n", __FUNCTION__, hdc.strControllerType.c_str()));
     1692                    vsys.mapControllers[hdc.idController] = hdc;
     1693
     1694                    if (aVBoxValues.size() == 0)
     1695                    {
     1696                        /* we should do it here because it'll be used later in the OVF logic (inside i_importMachines()) */
     1697                        vsd->AddDescription(VirtualSystemDescriptionType_HardDiskControllerSATA,
     1698                                            Bstr(hdc.strControllerType).raw(),
     1699                                            Bstr(hdc.strControllerType).raw());
     1700                    }
     1701                }
     1702
     1703                {
     1704                    GET_VSD_DESCRIPTION_BY_TYPE(VirtualSystemDescriptionType_SoundCard)//aVBoxValues is set in this #define
     1705                    if (aVBoxValues.size() != 0)
     1706                        vsys.strSoundCardType  = (Utf8Str)(aVBoxValues[0]);
     1707                    else
     1708                    {
     1709                        AudioControllerType_T defaultAudioController;
     1710                        pGuestOSType->COMGETTER(RecommendedAudioController)(&defaultAudioController);
     1711                        vsys.strSoundCardType = Utf8StrFmt("%RU32", (uint32_t)defaultAudioController);//"ensoniq1371";//"AC97";
     1712                        vsd->AddDescription(VirtualSystemDescriptionType_SoundCard,
     1713                                            Bstr(vsys.strSoundCardType).raw(),
     1714                                            Bstr(vsys.strSoundCardType).raw());
     1715                    }
     1716
     1717                    LogRel(("%s: Sound card is %s\n", __FUNCTION__, vsys.strSoundCardType.c_str()));
     1718                }
     1719
     1720                vsys.fHasFloppyDrive = false;
     1721                vsys.fHasCdromDrive = false;
     1722                vsys.fHasUsbController = true;
     1723            }
     1724
     1725            unsigned currImageObjectNum = 0;
     1726            hrc = S_OK;
     1727            do
     1728            {
     1729                char *pszName = NULL;
     1730                RTVFSOBJTYPE enmType;
     1731                vrc = RTVfsFsStrmNext(hVfsFssObject, &pszName, &enmType, &hVfsObj);
     1732                if (RT_FAILURE(vrc))
     1733                {
     1734                    if (vrc != VERR_EOF)
     1735                    {
     1736                        hrc = setErrorVrc(vrc, tr("%s: Error reading '%s' (%Rrc)"), __FUNCTION__, strAbsSrcPath.c_str(), vrc);
     1737                        throw hrc;
     1738                    }
     1739                    break;
     1740                }
     1741
     1742                /* We only care about entries that are files. Get the I/O stream handle for them. */
     1743                if (   enmType  == RTVFSOBJTYPE_IO_STREAM
     1744                    || enmType  == RTVFSOBJTYPE_FILE)
     1745                {
     1746                    /* Find the suffix and check if this is a possibly interesting file. */
     1747                    char *pszSuffix = RTStrToLower(strrchr(pszName, '.'));
     1748
     1749                    /* Get the I/O stream. */
     1750                    hVfsIosCurr = RTVfsObjToIoStream(hVfsObj);
     1751                    Assert(hVfsIosCurr != NIL_RTVFSIOSTREAM);
     1752
     1753                    /* Get the source medium format */
     1754                    ComObjPtr<MediumFormat> srcFormat;
     1755                    srcFormat = pSysProps->i_mediumFormatFromExtension(pszSuffix + 1);
     1756
     1757                    /* unknown image format so just extract a file without any processing */
     1758                    if (srcFormat == NULL)
     1759                    {
     1760                        /* Read the file into a memory buffer */
     1761                        void  *pvBuffered;
     1762                        size_t cbBuffered;
     1763                        RTVFSFILE hVfsDstFile;
     1764                        try
     1765                        {
     1766                            vrc = RTVfsIoStrmReadAll(hVfsIosCurr, &pvBuffered, &cbBuffered);
     1767                            RTVfsIoStrmRelease(hVfsIosCurr);
     1768                            hVfsIosCurr = NIL_RTVFSIOSTREAM;
     1769                            if (RT_FAILURE(vrc))
     1770                                throw  setErrorVrc(vrc, tr("Could not read the file '%s' (%Rrc)"), strAbsSrcPath.c_str(), vrc);
     1771
     1772                            Utf8StrFmt strAbsDstPath("%s%s%s", strMachineFolder.c_str(), RTPATH_SLASH_STR, pszName);
     1773
     1774                            /* Simple logic - just try to get dir info, in case of absent try to create one.
     1775                               No deep errors analysis */
     1776                            RTFSOBJINFO dirInfo;
     1777                            vrc = RTPathQueryInfo(strMachineFolder.c_str(), &dirInfo, RTFSOBJATTRADD_NOTHING);
     1778                            if (RT_FAILURE(vrc))
     1779                            {
     1780                                if (vrc == VERR_FILE_NOT_FOUND || vrc == VERR_PATH_NOT_FOUND)
     1781                                {
     1782                                    vrc = RTDirCreate(strMachineFolder.c_str(), 0755, 0);
     1783                                    if (RT_FAILURE(vrc))
     1784                                        throw  setErrorVrc(vrc, tr("Could not create the directory '%s' (%Rrc)"),
     1785                                                           strMachineFolder.c_str(), vrc);
     1786                                }
     1787                                else
     1788                                    throw  setErrorVrc(vrc, tr("Error during getting info about the directory '%s' (%Rrc)"),
     1789                                                       strMachineFolder.c_str(), vrc);
     1790                            }
     1791
     1792                            /* Write the file on the disk */
     1793                            vrc = RTVfsFileOpenNormal(strAbsDstPath.c_str(),
     1794                                                      RTFILE_O_WRITE | RTFILE_O_DENY_ALL | RTFILE_O_CREATE,
     1795                                                      &hVfsDstFile);
     1796                            if (RT_FAILURE(vrc))
     1797                                throw  setErrorVrc(vrc, tr("Could not create the file '%s' (%Rrc)"), strAbsDstPath.c_str(), vrc);
     1798
     1799                            size_t cbWritten;
     1800                            RTVfsFileWrite(hVfsDstFile, pvBuffered, cbBuffered, &cbWritten);
     1801                            if (RT_FAILURE(vrc))
     1802                                throw  setErrorVrc(vrc, tr("Could not write into the file '%s' (%Rrc)"), strAbsDstPath.c_str(), vrc);
     1803                        }
     1804                        catch (HRESULT aRc)
     1805                        {
     1806                            hrc = aRc;
     1807                        }
     1808                        catch (...)
     1809                        {
     1810                            hrc = VERR_UNEXPECTED_EXCEPTION;
     1811                        }
     1812
     1813                        /* Don't forget to release all resources */
     1814                        RTVfsFileRelease(hVfsDstFile);
     1815                        RTVfsIoStrmReadAllFree(pvBuffered, cbBuffered);
     1816
     1817                        /*re-throw the error */
     1818                        if (FAILED(hrc))
     1819                            throw hrc;
     1820
     1821                    }
     1822                    else
     1823                    {
     1824                        /* Image format is supported by VBox so extract the file and try to convert
     1825                         * one to the default format (which is VMDK for now) */
     1826                        Utf8Str z(bstrSettingsFilename);
     1827                        Utf8StrFmt strAbsDstPath("%s_%d.%s",
     1828                                     z.stripSuffix().c_str(),
     1829                                     currImageObjectNum,
     1830                                     strTargetFormat.c_str());
     1831
     1832                        hrc = mVirtualBox->i_findHardDiskByLocation(strAbsDstPath, false, NULL);
     1833                        if (SUCCEEDED(hrc))
     1834                            throw setError(VERR_ALREADY_EXISTS, tr("The hard disk '%s' already exists."), strAbsDstPath.c_str());
     1835
     1836                        /* Create an IMedium object. */
     1837                        ComObjPtr<Medium> pTargetMedium;
     1838                        pTargetMedium.createObject();
     1839                        hrc = pTargetMedium->init(mVirtualBox,
     1840                                                 strTargetFormat,
     1841                                                 strAbsDstPath,
     1842                                                 Guid::Empty /* media registry: none yet */,
     1843                                                 DeviceType_HardDisk);
     1844                        if (FAILED(hrc))
     1845                            throw hrc;
     1846
     1847                        pTask->pProgress->SetNextOperation(BstrFmt(tr("Importing virtual disk image '%s'",pszName)).raw(),
     1848                                                           200);
     1849                        ComObjPtr<Medium> nullParent;
     1850                        ComPtr<IProgress> pProgressImport;
     1851                        ComObjPtr<Progress> pProgressImportTmp;
     1852                        hrc = pProgressImportTmp.createObject();
     1853                        if (FAILED(hrc))
     1854                            throw hrc;
     1855
     1856                        hrc = pProgressImportTmp->init(mVirtualBox,
     1857                                                      static_cast<IAppliance*>(this),
     1858                                                      Utf8StrFmt(tr("Importing medium '%s'"),
     1859                                                                 pszName),
     1860                                                      TRUE);
     1861                        if (FAILED(hrc))
     1862                            throw hrc;
     1863
     1864                        pProgressImportTmp.queryInterfaceTo(pProgressImport.asOutParam());
     1865
     1866                        hrc = pTargetMedium->i_importFile(pszName,
     1867                                                          srcFormat,
     1868                                                          MediumVariant_Standard,
     1869                                                          hVfsIosCurr,
     1870                                                          nullParent,
     1871                                                          pProgressImportTmp,
     1872                                                          true /* aNotify */);
     1873                        RTVfsIoStrmRelease(hVfsIosCurr);
     1874                        hVfsIosCurr = NIL_RTVFSIOSTREAM;
     1875                        /* Now wait for the background import operation to complete;
     1876                         * this throws HRESULTs on error. */
     1877                        pTask->pProgress->WaitForOtherProgressCompletion(pProgressImport, 0 /* indefinite wait */);
     1878
     1879                        /* Try to re-use some OVF stuff here */
     1880                        {
     1881                            /* Small trick here.
     1882                             * We add new item into the actual VSD after successful conversion.
     1883                             * There is no need to delete any previous records describing the images in the VSD
     1884                             * because later in the code the search of the images in the VSD will use such records
     1885                             * with the actual image id (d.strDiskId = pTargetMedium->i_getId().toString()) which is
     1886                             * used as a key for m->pReader->m_mapDisks, vsys.mapVirtualDisks.
     1887                             * So all 3 objects are tied via the image id.
     1888                             * In the OVF case we already have all such records in the VSD after reading OVF
     1889                             * description file (read() and interpret() functions).*/
     1890                            ovf::DiskImage d;
     1891                            d.strDiskId = pTargetMedium->i_getId().toString();
     1892                            d.strHref = pTargetMedium->i_getLocationFull();
     1893                            d.strFormat = pTargetMedium->i_getFormat();
     1894                            d.iSize = pTargetMedium->i_getSize();
     1895                            d.ulSuggestedSizeMB = (uint32_t)(pTargetMedium->i_getSize()/_1M);
     1896
     1897                            m->pReader->m_mapDisks[d.strDiskId] = d;
     1898
     1899                            ComObjPtr<VirtualSystemDescription> vsdescThis = m->virtualSystemDescriptions.front();
     1900
     1901                            /* It's needed here to use the internal function i_addEntry() instead of the API function
     1902                             * addDescription() because we should pass the d.strDiskId for the proper handling this
     1903                             * disk later in the i_importMachineGeneric():
     1904                             * - find the line like this "if (vsdeHD->strRef == diCurrent.strDiskId)".
     1905                             *  if those code can be eliminated then addDescription() will be used. */
     1906                            vsdescThis->i_addEntry(VirtualSystemDescriptionType_HardDiskImage,
     1907                                                   d.strDiskId,
     1908                                                   d.strHref,
     1909                                                   d.strHref,
     1910                                                   d.ulSuggestedSizeMB);
     1911
     1912                            ovf::VirtualDisk vd;
     1913                            vd.idController = vsys.mapControllers[0].idController;
     1914                            vd.ulAddressOnParent = 0;
     1915                            vd.strDiskId = d.strDiskId;
     1916                            vsys.mapVirtualDisks[vd.strDiskId] = vd;
     1917
     1918                        }
     1919
     1920                        ++currImageObjectNum;
     1921                    }
     1922
     1923                    RTVfsIoStrmRelease(hVfsIosCurr);
     1924                    hVfsIosCurr = NIL_RTVFSIOSTREAM;
     1925                }
     1926
     1927                RTVfsObjRelease(hVfsObj);
     1928                hVfsObj = NIL_RTVFSOBJ;
     1929
     1930                RTStrFree(pszName);
     1931
     1932            } while (SUCCEEDED(hrc));
     1933
     1934            RTVfsFsStrmRelease(hVfsFssObject);
     1935            hVfsFssObject = NIL_RTVFSFSSTREAM;
     1936
     1937            pTask->pProgress->SetNextOperation(BstrFmt(tr("Creating new VM '%s'", strVMName.c_str())).raw(), 50);
     1938            /* Create the import stack to comply OVF logic.
     1939             * Before we filled some other data structures which are needed by OVF logic too.*/
     1940            ImportStack stack(pTask->locInfo, m->pReader->m_mapDisks, pTask->pProgress, NIL_RTVFSFSSTREAM);
     1941            i_importMachines(stack);
     1942
     1943        }
     1944        catch (HRESULT aRc)
     1945        {
     1946            LogRel(("%s: Cloud import (local phase) - exception occured (%Rrc).\n", __FUNCTION__, aRc));
     1947            hrc = aRc;
     1948        }
     1949        catch (...)
     1950        {
     1951            hrc = VERR_UNRESOLVED_ERROR;
     1952            LogRel(("%s: Cloud import (local phase) - Unknown exception occured.\n", __FUNCTION__));
     1953        }
     1954
     1955        if (FAILED(hrc))
     1956        {
     1957            /* Try to free VFS stuff because some of them might not be released due to the exception */
     1958            if (hVfsIosCurr != NIL_RTVFSIOSTREAM)
     1959                RTVfsIoStrmRelease(hVfsIosCurr);
     1960            if (hVfsObj != NIL_RTVFSOBJ)
     1961                RTVfsObjRelease(hVfsObj);
     1962            if (hVfsFssObject != NIL_RTVFSFSSTREAM)
     1963                RTVfsFsStrmRelease(hVfsFssObject);
     1964
     1965            LogRel(("%s: Cloud import (local phase): original error was \'%s\'.\n", __FUNCTION__, strLastActualErrorDesc.c_str()));
     1966
     1967            /* What to do here?
     1968             * Delete or not the downloaded object?
     1969             * For now:
     1970             *  - check the list of imported images, detach them and next delete.
     1971             *  - check the registration of created VM and delete one.
     1972             *  - check some other leavings if they may exist and delete them too.
     1973             */
     1974
     1975            /* Small explanation here.
     1976             * After adding extracted files into the actual VSD the returned list will contain not only the
     1977             * record about the downloaded object but also the records about the extracted files from this object.
     1978             * It's needed to go through this list to find the record about the downloaded object.
     1979             * But it was the first record added into the list, so aVBoxValues[0] should be correct here.
     1980             */
     1981            GET_VSD_DESCRIPTION_BY_TYPE(VirtualSystemDescriptionType_HardDiskImage)//aVBoxValues is set in this #define
     1982            if (aVBoxValues.size() != 0)
     1983                hrc = setError(hrc, "%s: Cloud import (local phase) failed. Find the root cause in the log file. "
     1984                                    "But the first phase was successful and the downloaded object was stored as \'%s\'\n",
     1985                                    __FUNCTION__, Utf8Str(aVBoxValues[0]).c_str());
     1986        }
    14751987    }
    14761988
     
    23372849        else if (mode == ImportCloud)
    23382850        {
    2339             /*
    2340              1. Create a custom imaghe from the instance
    2341              2. Import the custom image into the Object Storage (OCI format - TAR file with QCOW2 image and JSON file)
    2342              3. Download the object from the Object Storage
    2343              4. Open the object, extract QCOW2 image and convert one QCOW2->VDI
    2344              5. Create VM with user settings and attach the converted image to VM
    2345              6. Lauch VM.
    2346             */
    23472851            progress.createObject();
    23482852            if (locInfo.strProvider.equals("OCI"))
    23492853            {
     2854                /*
     2855                 * 1. Create a custom image from the instance
     2856                 *  - 2 operations (starting and waiting)
     2857                 * 2. Import the custom image into the Object Storage (OCI format - TAR file with QCOW2 image and JSON file)
     2858                 *  - 2 operations (starting and waiting)
     2859                 * 3. Download the object from the Object Storage
     2860                 *  - 2 operations (starting and waiting)
     2861                 * 4. Open the object, extract QCOW2 image and convert one QCOW2->VDI
     2862                 *  - 1 operation (extracting and conversion are piped)
     2863                 * 5. Create VM with user settings and attach the converted image to VM
     2864                 *  - 1 operation.
     2865                 *  sum up = 2+2+2+1+1 = 8 op
     2866                */
     2867
     2868                /*
     2869                 * See src/VBox/ExtPacks/Puel/OCI/OCICloudClient.h.
     2870                 * Weight of cloud import operations (1-3 items from above):
     2871                 * Total = 750 = 10+40+50+50+200x2+200.
     2872                 * 
     2873                 * Weight of local import operations (4-5 items from above):
     2874                 * Total = 250 = 200 (extract and convert) + 50 (create VM, attach disks)
     2875                 */
    23502876                progress->init(mVirtualBox, static_cast<IAppliance*>(this),
    23512877                             Bstr("Importing VM from Cloud...").raw(),
    23522878                             TRUE /* aCancelable */,
    2353                              6, // ULONG cOperations,
    2354                              750, // ULONG ulTotalOperationsWeight,
     2879                             8, // ULONG cOperations,
     2880                             1000, // ULONG ulTotalOperationsWeight,
    23552881                             Bstr("Importing VM from Cloud...").raw(), // aFirstOperationDescription
    23562882                             10); // ULONG ulFirstOperationWeight
     
    36984224
    36994225                ComObjPtr<Medium> pTargetMedium;
    3700                 i_importOneDiskImage(diCurrent,
    3701                                      vsdeTargetHD->strVBoxCurrent,
    3702                                      pTargetMedium,
    3703                                      stack);
     4226                if (stack.locInfo.storageType == VFSType_Cloud)
     4227                {
     4228                    //we have already all disks prepared (converted and registered in the VBox)
     4229                    //and in the correct place (VM machine folder).
     4230                    //so what is needed is to get the disk uuid from VirtualDisk::strDiskId
     4231                    //and find the Medium object with this uuid.
     4232                    //next just attach the Medium object to new VM.
     4233                    //VirtualDisk::strDiskId is filled in the
     4234
     4235                    Guid id(ovfVdisk.strDiskId);
     4236                    rc = mVirtualBox->i_findHardDiskById(id, false, &pTargetMedium);
     4237                    if (FAILED(rc))
     4238                        throw rc;
     4239                }
     4240                else
     4241                {
     4242                    i_importOneDiskImage(diCurrent,
     4243                                         vsdeTargetHD->strVBoxCurrent,
     4244                                         pTargetMedium,
     4245                                         stack);
     4246                }
    37044247
    37054248                // now use the new uuid to attach the medium to our new machine
  • trunk/src/VBox/Main/xml/ovfreader.cpp

    r76553 r78602  
    3333//
    3434////////////////////////////////////////////////////////////////////////////////
     35
     36/**
     37 * Default Constructor.
     38 * Should be used if you don't have an OVF file, but want to fill the data
     39 * m_mapDisks, m_llVirtualSystems manually
     40 */
     41OVFReader::OVFReader() 
     42{
     43}
    3544
    3645/**
Note: See TracChangeset for help on using the changeset viewer.

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