Unable to backup a running VM on an Intel host using PrlBackup_Begin

Discussion in 'General Questions' started by MaximT1, Oct 31, 2023.

  1. MaximT1

    MaximT1 Bit poster

    Messages:
    1
    The function fails with PRL_ERR_FAILURE.

    Here's what I found in parallels.log:
    And this is the code that shows the problem. It looks for a running backupable machine and tries to back it up:
    Code:
    #import <ParallelsVirtualizationSDK/Parallels.h>
    #import <ParallelsVirtualizationSDK/PrlApiMacro.h>
    #import <ParallelsVirtualizationSDK/PrlApiCore.h>
    #import <assert.h>
    #import <iostream>
    #import <libgen.h>
    
    namespace
    {
      void CheckPrlResult(PRL_RESULT result)
      {
        if (result == PRL_ERR_SUCCESS)
          return;
    
        std::cout << "Error: " << prl_result_to_string(result) << std::endl;
        assert(false);
      }
    
      PRL_RESULT WaitJobResult(PRL_HANDLE job, PRL_HANDLE_PTR jobResult)
      {
        CheckPrlResult(PrlJob_Wait(job, 60000));
        CheckPrlResult(PrlJob_GetResult(job, jobResult));
        PRL_RESULT jobResultCode;
        CheckPrlResult(PrlJob_GetRetCode(job, &jobResultCode));
        return jobResultCode;
      }
    
      std::string MachineStateToString(VIRTUAL_MACHINE_STATE state)
      {
        switch (state)
        {
          case VMS_UNKNOWN: return "Unknown";
          case VMS_STOPPED: return "Stopped";
          case VMS_STARTING: return "Starting";
          case VMS_RESTORING: return "Restoring";
          case VMS_RUNNING: return "Running";
          case VMS_PAUSED: return "Paused";
          case VMS_SUSPENDING: return "Suspending";
          case VMS_STOPPING: return "Stopping";
          case VMS_COMPACTING: return "Compacting";
          case VMS_SUSPENDED: return "Suspended";
          case VMS_SNAPSHOTING: return "Snapshoting";
          case VMS_RESETTING: return "Resetting";
          case VMS_PAUSING: return "Pausing";
          case VMS_CONTINUING: return "Continuing";
          case VMS_MIGRATING_OBSOLETE: return "Migrating";
          case VMS_DELETING_STATE: return "Deleting";
          case VMS_RESUMING: return "Resuming";
          case VMS_SUSPENDING_SYNC: return "Suspending sync";
          case VMS_RECONNECTING_OBSOLETE: return "Reconnecting";
          case VMS_MOUNTED_OBSOLETE: return "Mounted";
        }
      }
    }
    int main(int argc, const char * argv[])
    {
      CheckPrlResult(PrlApi_InitEx(PARALLELS_API_VER_5, PAM_DESKTOP, 0, 0));
    
      PRL_HANDLE server;
      CheckPrlResult(PrlSrv_Create(&server));
    
      auto loginJob = PrlSrv_LoginLocal(server, nullptr, 0, PSL_NORMAL_SECURITY);
      PRL_HANDLE loginResult;
      CheckPrlResult(WaitJobResult(loginJob, &loginResult));
    
      PRL_HANDLE loginResultParam;
      CheckPrlResult(PrlResult_GetParam(loginResult, &loginResultParam));
    
      PRL_UINT32 bufSize = 0;
      CheckPrlResult(PrlLoginResponse_GetProductVersion(loginResultParam, nullptr, &bufSize));
      char version[bufSize];
      CheckPrlResult(PrlLoginResponse_GetProductVersion(loginResultParam, version, &bufSize));
      std::cout << "Version: " << version << std::endl;
    
      PrlHandle_Free(loginResultParam);
      PrlHandle_Free(loginResult);
      PrlHandle_Free(loginJob);
    
      PRL_HANDLE listJob = PrlSrv_GetBackupVmList(server, 0);
      PRL_HANDLE listResult;
      CheckPrlResult(WaitJobResult(listJob, &listResult));
    
      PRL_UINT32 machineCount;
      CheckPrlResult(PrlResult_GetParamsCount(listResult, &machineCount));
      std::cout << "Machines: " << machineCount << std::endl;
      for (PRL_UINT32 i = 0; i < machineCount; i++)
      {
        std::cout << "Getting machine..." << std::endl;
        PRL_HANDLE machineHandle;
        CheckPrlResult(PrlResult_GetParamByIndex(listResult, i, &machineHandle));
    
        std::cout << "Getting backup info..." << std::endl;
        PRL_HANDLE backupInfo;
        CheckPrlResult(PrlBackup_GetInfo(machineHandle, &backupInfo));
    
        std::cout << "Getting machine state..." << std::endl;
        VIRTUAL_MACHINE_STATE machineState;
        CheckPrlResult(PrlBackupInfo_GetState(backupInfo, &machineState));
        std::cout << "Machine state: " << MachineStateToString(machineState) << std::endl;
        if (machineState == VMS_RUNNING)
        {
          std::cout << "Setting up backup..." << std::endl;
          PRL_HANDLE params;
          CheckPrlResult(PrlBackup_GetParams(machineHandle, &params));
          CheckPrlResult(PrlBackupParam_SetChangeMonitoring(params, PRL_TRUE));
          CheckPrlResult(PrlBackupParam_SetLevel(params, PBL_FULL));
          PRL_UINT32 options = PBOPT_DISABLE_GUEST_FS_SUSPEND;
          CheckPrlResult(PrlBackupParam_SetOptions(params, options));
          CheckPrlResult(PrlBackup_SetParams(machineHandle, params));
    
          std::cout << "Starting backup..." << std::endl;
          PRL_HANDLE backupJob = PrlBackup_Begin(machineHandle, 0);
          PRL_HANDLE backupJobResult;
          CheckPrlResult(WaitJobResult(backupJob, &backupJobResult));
          PrlHandle_Free(backupJobResult);
          PrlHandle_Free(backupJob);
    
          PRL_HANDLE fileList;
          CheckPrlResult(PrlBackup_GetFilesList(machineHandle, &fileList));
    
          PRL_UINT32 fileCount;
          CheckPrlResult(PrlHndlList_GetItemsCount(fileList, &fileCount));
          std::cout << "Files in backup: " << fileCount << std::endl;
          for (PRL_UINT32 j = 0; j < fileCount; j++)
          {
            PRL_HANDLE file;
            CheckPrlResult(PrlHndlList_GetItem(fileList, j, &file));
            PRL_UINT32 filePathSize = 0;
            CheckPrlResult(PrlBackupFile_GetPath(file, nullptr, &filePathSize));
            char filePath[filePathSize];
            CheckPrlResult(PrlBackupFile_GetPath(file, filePath, &filePathSize));
            std::cout << filePath << std::endl;
            PrlHandle_Free(file);
          }
    
          std::cout << "Rolling back..." << std::endl;
          PRL_HANDLE rollbackJob = PrlBackup_Rollback(machineHandle, 0);
          PRL_HANDLE rollbackJobResult;
          CheckPrlResult(WaitJobResult(rollbackJob, &rollbackJobResult));
          PrlHandle_Free(rollbackJobResult);
          PrlHandle_Free(rollbackJob);
        }
        else
        {
          std::cout << "Skipping..." << std::endl;
        }
        PrlHandle_Free(backupInfo);
        PrlHandle_Free(machineHandle);
      }
    
      PrlHandle_Free(listResult);
      PrlHandle_Free(listJob);
    
      PrlHandle_Free(server);
      return 0;
    }
    
     

Share This Page