虚拟化技术Ovirt程序员

【Ovirt 笔记】虚拟资源管理分析与整理

2017-05-26  本文已影响24人  58bc06151329

分析整理的版本为 Ovirt 3.4.5 版本。

主机

ResourceManager

@Singleton
@Startup
@DependsOn({ "Backend"})
public class InitBackendServicesOnStartupBean implements InitBackendServicesOnStartup{
......
@Override
@PostConstruct
public void create() {
......
ResourceManager.getInstance().init();
......
for (VDS curVds : allVdsList) {
    AddVds(curVds, true);
}
IrsBrokerCommand.init();

AddVds 根据数据库中的主机,初始化一个 vdsManager,而这个 vdsManager 用于管理所有的主机。vdsManager 主要建立了与 vdsmxml-rpc 连接。

VdsManager vdsManager = VdsManager.buildVdsManager(vds);
private void InitVdsBroker() {
    log.infoFormat("Initialize vdsBroker ({0},{1})", _vds.getHostName(), _vds.getPort());

    // Get the values of the timeouts:
    int clientTimeOut = Config.<Integer> getValue(ConfigValues.vdsTimeout) * 1000;
    int connectionTimeOut = Config.<Integer>getValue(ConfigValues.vdsConnectionTimeout) * 1000;
    int clientRetries = Config.<Integer>getValue(ConfigValues.vdsRetries);

    Pair<VdsServerConnector, HttpClient> returnValue =
            XmlRpcUtils.getConnection(_vds.getHostName(),
                    _vds.getPort(),
                    clientTimeOut,
                    connectionTimeOut,
                    clientRetries,
                    VdsServerConnector.class,
                    Config.<Boolean> getValue(ConfigValues.EncryptHostCommunication));
    _vdsProxy = new VdsServerWrapper(returnValue.getFirst(), returnValue.getSecond());
}
public static void init() {
    for (StoragePool sp : DbFacade.getInstance().getStoragePoolDao().getAll()) {
        if (!_irsProxyData.containsKey(sp.getId())) {
            _irsProxyData.put(sp.getId(), new IrsProxyData(sp.getId()));
        }
    }
}
public IrsProxyData(Guid storagePoolId) {
    _storagePoolId = storagePoolId;
    int storagePoolRefreshTime = Config.<Integer> getValue(ConfigValues.StoragePoolRefreshTimeInSeconds);
    storagePoolRefreshJobId = SchedulerUtilQuartzImpl.getInstance().scheduleAFixedDelayJob(this,
            "_updatingTimer_Elapsed", new Class[0], new Object[0], storagePoolRefreshTime,
            storagePoolRefreshTime, TimeUnit.SECONDS);
}
@OnTimerMethodAnnotation("_updatingTimer_Elapsed")
public void _updatingTimer_Elapsed() {
    try {
        synchronized (syncObj) {
            if (!_disposed) {
                StoragePool storagePool = DbFacade.getInstance().getStoragePoolDao()
                        .get(_storagePoolId);

                if (storagePool != null) {
                    // when there are no hosts in status up, it means that there shouldn't be domain monitoring
                    // so all the domains need to move to "unknown" status as otherwise their status won't change.
                    if (DbFacade.getInstance()
                            .getVdsDao()
                            .getAllForStoragePoolAndStatus(_storagePoolId, reportingVdsStatus)
                            .isEmpty()) {
                        StoragePoolDomainHelper.updateApplicablePoolDomainsStatuses(_storagePoolId,
                                StoragePoolDomainHelper.storageDomainMonitoredStatus,
                                StorageDomainStatus.Unknown, "no reporting hosts");
                    }

                    if (storagePool.getStatus() == StoragePoolStatus.Up
                            || storagePool.getStatus() == StoragePoolStatus.NonResponsive || storagePool
                                    .getStatus() == StoragePoolStatus.Contend) {
                        proceedStoragePoolStats(storagePool);
                    }
                }

            }
        }
    } catch (Exception ex) {
    }
}
public boolean AddAsyncRunningVm(Guid vmId) {
    boolean returnValue = false;
    if (_asyncRunningVms.putIfAbsent(vmId, Boolean.TRUE) == null) {
        returnValue = true;
    }
    return returnValue;
}

public void RemoveAsyncRunningVm(Guid vmId) {
    _asyncRunningVms.remove(vmId);
    getEventListener().removeAsyncRunningCommand(vmId);
}

public void succededToRunVm(Guid vmId, Guid vdsId) {
    if (_asyncRunningVms.containsKey(vmId)) {
        getEventListener().runningSucceded(vmId);
    }
    RemoveAsyncRunningVm(vmId);
}
......
private static final String VDSCommandPrefix = "VDSCommand";
......
private static String GetCommandTypeName(VDSCommandType command) {
    String packageName = command.getPackageName();
    String commandName = String.format("%s.%s%s", packageName, command, VDSCommandPrefix);
    return commandName;
}
......
private <P extends VDSParametersBase> VDSCommandBase<P> CreateCommand(
        VDSCommandType commandType, P parameters) {
    try {
        @SuppressWarnings("unchecked")
        Class<VDSCommandBase<P>> type =
                (Class<VDSCommandBase<P>>) Class.forName(GetCommandTypeName(commandType));
        Constructor<VDSCommandBase<P>> constructor =
                ReflectionUtils.findConstructor(type, parameters.getClass());

        if (constructor != null) {
            return constructor.newInstance(new Object[] { parameters });
        }
    } catch (Exception e) {
        if (e.getCause() != null) {
            log.error("CreateCommand failed", e.getCause());
            throw new RuntimeException(e.getCause().getMessage(), e.getCause());
        }
        log.error("CreateCommand failed", e);
    }
    return null;
}
......

VDSBrokerFrontendImpl

_resourceManger = new VDSBrokerFrontendImpl();
public VDSReturnValue RunVdsCommand(VDSCommandType commandType, VDSParametersBase parameters) {
    return VdsHandler.handleVdsResult(getResourceManager().runVdsCommand(commandType, parameters));
}
public VDSReturnValue RunAsyncVdsCommand(VDSCommandType commandType, VdsAndVmIDVDSParametersBase parameters,
                                         IVdsAsyncCommand command) {
    VDSReturnValue result = RunVdsCommand(commandType, parameters);
    if (result.getSucceeded()) {
        // Add async command to cached commands
        IVdsAsyncCommand prevCommand = _asyncRunningCommands.put(parameters.getVmId(), command);
        if (prevCommand != null && !prevCommand.equals(command)) {
            prevCommand.reportCompleted();
        }
    } else {
        throw new VdcBLLException(result.getVdsError().getCode(), result.getExceptionString());
    }

    return result;
}

虚拟机

平台中,虚拟机的状态共 18 种,对应着虚拟机当前的状态,而状态是根据用户的操作以及任务的执行以及 onTimer 中定时任刷新底层 vdsm 的虚拟机状态而后做一些判断共同决定的。

虚拟机对应的操作为开机,关机,断电,休眠,迁移,重启,快照,还有一些涉及磁盘的操作,对应的业务有导入,导出以及创建磁盘等。

平台可以通过界面用户触发或者 API 调用的方式进行虚拟机操作。最终都是通过相应的 command 实现业务逻辑。

业务逻辑中:

运行虚拟机

运行虚拟机,可以分为多种情况,一般是普通运行,还有用于安装系统的只运行一次,运行休眠的虚拟机,以及无状态模式运行也就是运行池中的虚拟机。

虚拟机的运行,会根据集群策略,自动选择一台合适的主机运行。

VMStatus vmStatus = (VMStatus) getBackend()
            .getResourceManager()
            .RunAsyncVdsCommand(VDSCommandType.CreateVm, initCreateVmParams(), this).getReturnValue();
return new CreateVDSCommand<CreateVmVDSCommandParameters>(getParameters());

CreateVDSCommand 根据不同的参数,组装 xml,通过 xml-rpc 执行 vdsmcreate 方法。

mVmReturn = getBroker().create(createInfo);
public OneVmReturnForXmlRpc create(Map createInfo) {
    try {
        Map<String, Object> xmlRpcReturnValue = vdsServer.create(createInfo);
        OneVmReturnForXmlRpc wrapper = new OneVmReturnForXmlRpc(xmlRpcReturnValue);
        return wrapper;
    } catch (UndeclaredThrowableException ute) {
        throw new XmlRpcRunTimeException(ute);
    }
}
def create(self, vmParams):
        """
        Start up a virtual machine.

        :param vmParams: required and optional VM parameters.
        :type vmParams: dict
        """
        vmParams['vmId'] = self._UUID
        try:
            if vmParams.get('vmId') in self._cif.vmContainer:
                self.log.warning('vm %s already exists' % vmParams['vmId'])
                return errCode['exist']

            if 'hiberVolHandle' in vmParams:
                vmParams['restoreState'], paramFilespec = \
                    self._getHibernationPaths(vmParams.pop('hiberVolHandle'))
                try:   # restore saved vm parameters
                    # NOTE: pickled params override command-line params. this
                    # might cause problems if an upgrade took place since the
                    # parmas were stored.
                    fname = self._cif.prepareVolumePath(paramFilespec)
......
ResumeBrokerVDSCommand<VdsAndVmIDVDSParametersBase> command =
                new ResumeBrokerVDSCommand<VdsAndVmIDVDSParametersBase>(parameters);
        command.execute();
mVmReturn = getBroker().resume(mVmId.toString());
proceedProxyReturnValue();
public OneVmReturnForXmlRpc pause(String vmId) {
    try {
        Map<String, Object> xmlRpcReturnValue = vdsServer.pause(vmId);
        OneVmReturnForXmlRpc wrapper = new OneVmReturnForXmlRpc(xmlRpcReturnValue);
        return wrapper;
    } catch (UndeclaredThrowableException ute) {
        throw new XmlRpcRunTimeException(ute);
    }

}
def cont(self):
    v = self._cif.vmContainer.get(self._UUID)
    if not v:
        return errCode['noVM']
    return v.cont()

关机/断电虚拟机

if (canShutdownVm()) {
    // shutting down desktop and waiting for it in a separate thread to
    // become 'down':
    log.infoFormat("Sending shutdown command for VM {0}.", getVmName());

    int secondsToWait = getParameters().getWaitBeforeShutdown() ? Config
            .<Integer> getValue(ConfigValues.VmGracefulShutdownTimeout) : 0;

    // sending a shutdown command to the VM:
    setActionReturnValue(Backend
            .getInstance()
            .getResourceManager()
            .RunVdsCommand(VDSCommandType.DestroyVm,
                    new DestroyVmVDSCommandParameters(getVdsId(), getVmId(), false, true, secondsToWait))
            .getReturnValue());
}
else {
    // cannot shutdown -> send a StopVm command instead ('destroy'):
    // don't log -> log will appear for the StopVmCommand we are about to run:
    setCommandShouldBeLogged(false);

    log.infoFormat("Cannot shutdown VM {0}, status is not up. Stopping instead.", getVmName());

    StopVmParameters stopVmParams = new StopVmParameters(getVmId(), StopVmTypeEnum.CANNOT_SHUTDOWN);
    // stopVmParams.ParametersCurrentUser = CurrentUser;
    stopVmParams.setSessionId(getParameters().getSessionId());
    Backend.getInstance().runInternalAction(VdcActionType.StopVm, stopVmParams);
}
if (getParameters().getGracefully()) {
    status = getBroker().shutdown(getParameters().getVmId().toString(),
            String.valueOf(getParameters().getSecondsToWait()),
            Config.<String> getValue(ConfigValues.VmGracefulShutdownMessage));
} else {
    status = getBroker().destroy(getParameters().getVmId().toString(), getParameters().getDestroyInfo());
}
public StatusOnlyReturnForXmlRpc shutdown(String vmId, String timeout, String message) {
    try {
        Map<String, Object> xmlRpcReturnValue = vdsServer.shutdown(vmId, timeout, message);
        StatusOnlyReturnForXmlRpc wrapper = new StatusOnlyReturnForXmlRpc(xmlRpcReturnValue);
        return wrapper;
    } catch (UndeclaredThrowableException ute) {
        throw new XmlRpcRunTimeException(ute);
    }

}
public StatusOnlyReturnForXmlRpc destroy(String vmId, Map destroyInfo) {
    try {
        Map<String, Object> xmlRpcReturnValue = vdsServer.destroy(vmId, destroyInfo);
        StatusOnlyReturnForXmlRpc wrapper = new StatusOnlyReturnForXmlRpc(xmlRpcReturnValue);
        return wrapper;
    } catch (UndeclaredThrowableException ute) {
        throw new XmlRpcRunTimeException(ute);
    }

}
def shutdown(self, delay=None, message=None, reboot=False, timeout=None,
             force=False):
    """
    Shut a VM down politely.

    :param message: message to be shown to guest user before shutting down
                    his machine.
    :param delay: grace period (seconds) to let guest user close his
                  applications.
    :param reboot: True if reboot is desired, False for shutdown
    :param timeout: number of seconds to wait before trying next
                    shutdown/reboot method
    :param force: True if shutdown/reboot desired by any means necessary
                  (forceful reboot/shutdown if all graceful methods fail)
    """
    try:
        v = self._cif.vmContainer[self._UUID]
    except KeyError:
        return errCode['noVM']
    if not delay:
        delay = config.get('vars', 'user_shutdown_timeout')
    if not message:
        message = USER_SHUTDOWN_MESSAGE
    if not timeout:
        timeout = config.getint('vars', 'sys_shutdown_timeout')
    return v.shutdown(delay, message, reboot, timeout, force)
def destroy(self, hostID, deprecatedSCSIKey):
        return self._irs.destroyStoragePool(self._UUID, hostID)

休眠虚拟机

Backend
        .getInstance()
        .getResourceManager()
        .RunVdsCommand(
                VDSCommandType.CreateImage,
                new CreateImageVDSCommandParameters(
                        getVm().getStoragePoolId(),
                        getStorageDomainId(),
                        image1GroupId,
                        getVm().getTotalMemorySizeInBytes(),
                        getMemoryVolumeType(),
                        VolumeFormat.RAW,
                        hiberVol1,
                        ""));
Backend.getInstance().getResourceManager().RunVdsCommand(VDSCommandType.Hibernate, para);
private VDSReturnValue runHibernateBrokerVDSCommand() {
    HibernateBrokerVDSCommand<HibernateVDSCommandParameters> command =
            new HibernateBrokerVDSCommand<HibernateVDSCommandParameters>(getParameters());
    command.execute();
    return command.getVDSReturnValue();
}

private void changeVmStatusToSavingState() {
    TransactionSupport.executeInNewTransaction(
            new TransactionMethod<Object>() {
                @Override
                public Object runInTransaction() {
                    VmDynamic vmDynamic = DbFacade.getInstance().getVmDynamicDao().get(getParameters().getVmId());
                    vmDynamic.setStatus(VMStatus.SavingState);
                    _vdsManager.updateVmDynamic(vmDynamic);
                    return null;
                }
            });
}
status = getBroker().hibernate(getParameters().getVmId().toString(),
getParameters().getHibernationVolHandle(),
getParameters().getEncryptionInfo());
public StatusOnlyReturnForXmlRpc hibernate(String vmId, String hiberVolHandle, Map<String, Object> encryptionInfo) {
    try {
        Map<String, Object> xmlRpcReturnValue = vdsServer.hibernate(vmId, hiberVolHandle, encryptionInfo);
        StatusOnlyReturnForXmlRpc wrapper = new StatusOnlyReturnForXmlRpc(xmlRpcReturnValue);
        return wrapper;
    } catch (UndeclaredThrowableException ute) {
        throw new XmlRpcRunTimeException(ute);
    }

}
def hibernate(self, hibernationVolHandle, encryptionInfo):
    """
    Hibernate a VM.

    :param hiberVolHandle: opaque string, indicating the location of
                           hibernation images.
    :param encryptionInfo: a map value indicates the vm and template encyption
                            password
    """
    params = {'vmId': self._UUID, 'mode': 'file',
              'hiberVolHandle': hibernationVolHandle,
              'vmMigrateDestPw': encryptionInfo['vmSuspendPw'],
              'tmMigrateDestPw': encryptionInfo['tmSuspendPw'],
              'secretUUID': encryptionInfo['secretUUID']}
    response = self.migrate(params)
    if not response['status']['code']:
        response['status']['message'] = 'Hibernation process starting'
    return response

创建快照(保存内存)

vdsReturnValue =
        Backend
                .getInstance()
                .getResourceManager()
                .RunVdsCommand(
                        VDSCommandType.CreateSnapshot,
                        new CreateSnapshotVDSCommandParameters(getStoragePoolId(),
                                getDestinationStorageDomainId(),
                                getImageGroupId(),
                                getImage().getImageId(),
                                getDiskImage().getSize(),
                                mNewCreatedDiskImage.getVolumeType(),
                                mNewCreatedDiskImage.getVolumeFormat(),
                                getDiskImage().getId(),
                                getDestinationImageId(),
                                ""));
uuidReturn = getIrsProxy().createVolume(getParameters().getStorageDomainId().toString(),
getParameters().getStoragePoolId().toString(),
getParameters().getImageGroupId().toString(),
(Long.valueOf(getParameters().getImageSizeInBytes())).toString(),
getParameters().getVolumeFormat().getValue(),
getParameters().getImageType().getValue(),
2,
getParameters().getNewImageID().toString(),
getParameters().getNewImageDescription(),
getParameters().getSourceImageGroupId().toString(),
getParameters().getImageId().toString());
public OneUuidReturnForXmlRpc createVolume(String sdUUID, String spUUID, String imgGUID, String size,
        int volFormat, int volType, int diskType, String volUUID, String descr, String srcImgGUID, String srcVolUUID) {
    Map<String, Object> xmlRpcReturnValue = irsServer.createVolume(sdUUID, spUUID, imgGUID, size, volFormat,
            volType, diskType, volUUID, descr, srcImgGUID, srcVolUUID);
    OneUuidReturnForXmlRpc wrapper = new OneUuidReturnForXmlRpc(xmlRpcReturnValue);
    return wrapper;
}
class Volume(APIBase):
    ctorArgs = ['volumeID', 'storagepoolID', 'storagedomainID', 'imageID']

    class Types:
        UNKNOWN = storage.volume.UNKNOWN_VOL
        PREALLOCATED = storage.volume.PREALLOCATED_VOL
        SPARSE = storage.volume.SPARSE_VOL

    class Formats:
        UNKNOWN = storage.volume.UNKNOWN_FORMAT
        COW = storage.volume.COW_FORMAT
        RAW = storage.volume.RAW_FORMAT

    class Roles:
        SHARED = storage.volume.SHARED_VOL
        LEAF = storage.volume.LEAF_VOL

    BLANK_UUID = storage.volume.BLANK_UUID
......
    def create(self, size, volFormat, preallocate, diskType, desc,
                   srcImgUUID, srcVolUUID):
        return self._irs.createVolume(self._sdUUID, self._spUUID,
                                      self._imgUUID, size, volFormat,
                                      preallocate, diskType, self._UUID, desc,
                                      srcImgUUID, srcVolUUID)
protected void endVmCommand() {
......
liveSnapshotSucceeded = performLiveSnapshot(createdSnapshot);
......
protected boolean performLiveSnapshot(final Snapshot snapshot) {
    try {
        TransactionSupport.executeInScope(TransactionScopeOption.Suppress, new TransactionMethod<Void>() {
            @Override
            public Void runInTransaction() {
                runVdsCommand(VDSCommandType.Snapshot, buildLiveSnapshotParameters(snapshot));
                return null;
            }
        });
    } catch (VdcBLLException e) {
        handleVdsLiveSnapshotFailure(e);
        return false;
    }
    return true;
}
private StatusOnlyReturnForXmlRpc executeSnapshotVerb() {
    String vmId = getParameters().getVmId().toString();
    return getParameters().isMemoryVolumeExists()
            ? getBroker().snapshot(vmId,
                    createDisksMap(),
                    getParameters().getMemoryVolume(),
                    getParameters().getSnapshotInfo())
            : getBroker().snapshot(vmId, createDisksMap(), getParameters().getSnapshotInfo());
}
public StatusOnlyReturnForXmlRpc snapshot(String vmId,
        Map<String, String>[] disks,
        String memory,
        Map<String, Object> vmEncrypParams) {
    try {
        Map<String, Object> xmlRpcReturnValue = vdsServer.snapshot(vmId, disks, memory, vmEncrypParams);
        StatusOnlyReturnForXmlRpc wrapper = new StatusOnlyReturnForXmlRpc(xmlRpcReturnValue);
        return wrapper;
    } catch (UndeclaredThrowableException ute) {
        throw new XmlRpcRunTimeException(ute);
    }
}
 def snapshot(self, snapDrives, snapMemVolHandle=None, vmEncrypParams={}):
    v = self._cif.vmContainer.get(self._UUID)
    if not v:
        return errCode['noVM']
    memoryParams = {}
    if snapMemVolHandle:
        memoryParams['dst'], memoryParams['dstparams'] = \
            self._getHibernationPaths(snapMemVolHandle)
    return v.snapshot(snapDrives, memoryParams, vmEncrypParams)

迁移虚拟机

setActionReturnValue(Backend
                    .getInstance()
                    .getResourceManager()
                    .RunAsyncVdsCommand(
                            VDSCommandType.Migrate,
                            createMigrateVDSCommandParameters(),
                            this)
                            .getReturnValue());
MigrateBrokerVDSCommand<?> command = new MigrateBrokerVDSCommand<>(getParameters());
        command.execute();
protected void executeVdsBrokerCommand() {
        status = getBroker().migrate(migrationInfo);
        proceedProxyReturnValue();
    }
public StatusOnlyReturnForXmlRpc migrate(Map<String, String> migrationInfo) {
    try {
        Map<String, Object> xmlRpcReturnValue = vdsServer.migrate(migrationInfo);
        StatusOnlyReturnForXmlRpc wrapper = new StatusOnlyReturnForXmlRpc(xmlRpcReturnValue);
        return wrapper;
    } catch (UndeclaredThrowableException ute) {
        throw new XmlRpcRunTimeException(ute);
    }

}
def migrate(self, params):
    """
    Migrate a VM to a remote host.

    :param params: a dictionary containing:
        *dst* - remote host or hibernation image filename
        *dstparams* - hibernation image filename for vdsm parameters
        *mode* - ``remote``/``file``
        *method* - ``online``
        *downtime* - allowed down time during online migration
        *dstqemu* - remote host address dedicated for migration
    """
    params['vmId'] = self._UUID
    self.log.debug(params)
    try:
        v = self._cif.vmContainer[self._UUID]
    except KeyError:
        return errCode['noVM']

    vmParams = v.status()
    if vmParams['status'] in (vmstatus.WAIT_FOR_LAUNCH, vmstatus.DOWN):
        return errCode['noVM']
    if params.get('mode') == 'file':
        if 'dst' not in params:
            params['dst'], params['dstparams'] = \
                self._getHibernationPaths(params['hiberVolHandle'])
    else:
        params['mode'] = 'remote'
    return v.migrate(params)
public void onTimer() {
......
_vdsUpdater = new VdsUpdateRunTimeInfo(VdsManager.this, _vds, monitoringStrategy) _vdsUpdater.refresh();

磁盘资源

场景 VDS 命令 vdsm 接口 VolumeType 存储域 VolumeFormat
创建模板 CopyImageVDSCommand CopyImage Sparse 与虚拟机一致 RAWCOW
/ / / 与虚拟机一致 与虚拟机一致 COW
/ / / Preallocated 与虚拟机一致 RAW
模版 clone 创建 vm CopyImageVDSCommand CopyImage Preallocated 与模板一致 RAW
模版 thin 创建 vm CreateSnapshotVDSCommand createVolume Sparse 与模板一致 COW
创建 vm/增加磁盘 CreateImageVDSCommand createVolume Preallocated/Sparse File RAW
/ / / Sparse Block COW
/ / / Preallocated Block RAW
快照创建 vm CopyImageVDSCommand CopyImage 与快照一致 与快照一致 COW
/ / / Sparse Block RAWCOW
/ / / Preallocated 与快照一致 RAW
创建快照 CreateSnapshotVDSCommand createVolume Sparse 与虚拟机一致 COW
导入导出域中虚拟机 CopyImageVDSCommand copyImage 与导出域一致 与导出域一致 与导出域一致
导入外部供应商 image CopyImageVDSCommand copyImage Preallocated Block RAW
/ / / SparsePreallocated Block RAW
/ / / Sparse File RAW
/ / / Sparse 与外部一致 COW
/ / / PreallocatedSparse 与外部一致 COW
导入模版 CopyImageVDSCommand copyImage Sparse Block RAWCOW
/ / / Sparse File RAW
/ / / Preallocated 与模板一致 与模板一致
导出虚拟机 CopyImageVDSCommand copyImage 与虚拟机一致 与虚拟机一致 与虚拟机一致
导出模版 CopyImageVDSCommand copyImage 与模板一致 与模板一致 与模板一致

创建模板

为了适应软加密,将 VolumeType.SparseVolumeFormat.RAW 并且无论存储域格式,最终将 RAW 转为 COW 格式。

VDSReturnValue vdsReturnValue = Backend
    .getInstance()
    .getResourceManager()
    .RunVdsCommand(
            VDSCommandType.CopyImage,
            new CopyImageVDSCommandParameters(storagePoolId, getParameters().getStorageDomainId(),
                    getParameters().getVmId(), imageGroupId, snapshotId, destinationImageGroupID,
                    getDestinationImageId(), StringUtils.defaultString(newImage.getDescription()), getParameters()
                            .getDestinationStorageDomainId(), CopyVolumeType.SharedVol, targetFormat,
                            newImage.getVolumeType(), getDiskImage().isWipeAfterDelete(), false));

模版 clone 创建 vm

vdsReturnValue = runVdsCommand(VDSCommandType.CopyImage,
                    copyImageParas);

模版 thin 创建 vm

vdsReturnValue =
            Backend
                    .getInstance()
                    .getResourceManager()
                    .RunVdsCommand(
                            VDSCommandType.CreateSnapshot,
                            new CreateSnapshotVDSCommandParameters(getStoragePoolId(),
                                    getDestinationStorageDomainId(),
                                    getImageGroupId(),
                                    getImage().getImageId(),
                                    getDiskImage().getSize(),
                                    mNewCreatedDiskImage.getVolumeType(),
                                    mNewCreatedDiskImage.getVolumeFormat(),
                                    getDiskImage().getId(),
                                    getDestinationImageId(),
                                    ""));

创建 vm/增加磁盘

tmpRetValue = Backend.getInstance().runInternalAction(
VdcActionType.AddImageFromScratch,
tempVar,
ExecutionHandler.createDefaultContexForTasks(getExecutionContext()));
VDSReturnValue vdsReturnValue = runVdsCommand(
VDSCommandType.CreateImage,
new CreateImageVDSCommandParameters(getParameters().getStoragePoolId(), getParameters()
        .getStorageDomainId(), getImageGroupId(), getParameters().getDiskInfo().getSize(),
        getParameters().getDiskInfo().getVolumeType(), getParameters().getDiskInfo()
                .getVolumeFormat(), getDestinationImageId(), ""));

快照创建 vm

protected VdcActionType getChildActionType() {
        return VdcActionType.CopyImageGroup;
    }
protected VdcReturnValueBase executeChildCopyingCommand(VdcActionParametersBase parameters) {
    VdcReturnValueBase result = Backend.getInstance().runInternalAction(
            getChildActionType(),
                    parameters,
                    ExecutionHandler.createDefaultContexForTasks(getExecutionContext()));
    return result;
}
vdsReturnValue = runVdsCommand(
    VDSCommandType.CopyImage,
    copyImageParas);

创建快照

vdsReturnValue =
            Backend
                    .getInstance()
                    .getResourceManager()
                    .RunVdsCommand(
                            VDSCommandType.CreateSnapshot,
                            new CreateSnapshotVDSCommandParameters(getStoragePoolId(),
                                    getDestinationStorageDomainId(),
                                    getImageGroupId(),
                                    getImage().getImageId(),
                                    getDiskImage().getSize(),
                                    mNewCreatedDiskImage.getVolumeType(),
                                    mNewCreatedDiskImage.getVolumeFormat(),
                                    getDiskImage().getId(),
                                    getDestinationImageId(),
                                    ""));
vdsReturnValue = runVdsCommand(
                    VDSCommandType.CopyImage,
                    copyImageParas);

导入导出域中虚拟机

vdcRetValue = Backend.getInstance().runInternalAction(
            VdcActionType.CopyImageGroup,
            buildMoveOrCopyImageGroupParametersForMemoryConfImage(
                    containerId, guids.get(0), guids.get(4), guids.get(5)),
                    ExecutionHandler.createDefaultContexForTasks(getExecutionContext()));
vdsReturnValue = runVdsCommand(
                    VDSCommandType.CopyImage,
                    copyImageParas);

导入模版

VdcReturnValueBase vdcRetValue = Backend.getInstance().runInternalAction(
VdcActionType.CopyImageGroup,
p,
ExecutionHandler.createDefaultContexForTasks(getExecutionContext()));
vdsReturnValue = runVdsCommand(
                    VDSCommandType.CopyImage,
                    copyImageParas);

导出虚拟机

VdcReturnValueBase vdcRetValue = Backend.getInstance().runInternalAction(
VdcActionType.CopyImageGroup,
buildMoveOrCopyImageGroupParametersForMemoryDumpImage(
        containerID, guids.get(0), guids.get(2), guids.get(3)),
ExecutionHandler.createDefaultContexForTasks(getExecutionContext()));
vdsReturnValue = runVdsCommand(
                    VDSCommandType.CopyImage,
                    copyImageParas);

导出模版

VdcReturnValueBase vdcRetValue = Backend.getInstance().runInternalAction(
VdcActionType.CopyImageGroup,
p,
ExecutionHandler.createDefaultContexForTasks(getExecutionContext()));
vdsReturnValue = runVdsCommand(
                    VDSCommandType.CopyImage,
                    copyImageParas);

copyImage

uuidReturn = getIrsProxy().copyImage(getParameters().getStorageDomainId().toString(),
getParameters().getStoragePoolId().toString(),
getParameters().getVmId().toString(),
getParameters().getImageGroupId().toString(),
getParameters().getImageId().toString(),
getParameters().getdstImageGroupId().toString(),
getParameters().getDstImageId().toString(),
getParameters().getCopyImageInfo(), // add by hzy for EncryptInfo
getParameters().getImageDescription(),
getParameters().getDstStorageDomainId().toString(),
getParameters().getCopyVolumeType().getValue(),
getParameters().getVolumeFormat().getValue(),
getParameters().getPreallocate().getValue(),
String.valueOf(getParameters().getPostZero()).toLowerCase(),
String.valueOf(getParameters().getForce()).toLowerCase());
public OneUuidReturnForXmlRpc copyImage(String sdUUID, String spUUID, String vmGUID, String srcImgGUID,
        String srcVolUUID, String dstImgGUID, String dstVolUUID, Map<String, Object> encryption, String descr, String dstSdUUID, int volType,
        int volFormat, int preallocate, String postZero, String force) {
    Map<String, Object> xmlRpcReturnValue = irsServer.copyImage(sdUUID, spUUID, vmGUID, srcImgGUID, srcVolUUID,
            dstImgGUID, dstVolUUID, encryption, descr, dstSdUUID, volType, volFormat, preallocate, postZero, force);
    OneUuidReturnForXmlRpc wrapper = new OneUuidReturnForXmlRpc(xmlRpcReturnValue);
    return wrapper;
}
 def copy(self, dstSdUUID, dstImgUUID, dstVolUUID, encryption, desc, volType,
             volFormat, preallocate, postZero, force):
        vmUUID = ''   # vmUUID is never used
        return self._irs.copyImage(self._sdUUID, self._spUUID, vmUUID,
                                   self._imgUUID, self._UUID, dstImgUUID,
                                   dstVolUUID,encryption, desc, dstSdUUID, volType,
                                   volFormat, preallocate, postZero, force)

createVolume

uuidReturn = getIrsProxy().createVolume(getParameters().getStorageDomainId().toString(),
getParameters().getStoragePoolId().toString(),
getParameters().getImageGroupId().toString(),
(Long.valueOf(getParameters().getImageSizeInBytes())).toString(),
getParameters().getVolumeFormat().getValue(),
getParameters().getImageType().getValue(),
2,
getParameters().getNewImageID().toString(),
getParameters().getNewImageDescription(),
getParameters().getSourceImageGroupId().toString(),
getParameters().getImageId().toString());
public OneUuidReturnForXmlRpc createVolume(String sdUUID, String spUUID, String imgGUID, String size,
        int volFormat, int volType, int diskType, String volUUID, String descr, String srcImgGUID, String srcVolUUID) {
    Map<String, Object> xmlRpcReturnValue = irsServer.createVolume(sdUUID, spUUID, imgGUID, size, volFormat,
            volType, diskType, volUUID, descr, srcImgGUID, srcVolUUID);
    OneUuidReturnForXmlRpc wrapper = new OneUuidReturnForXmlRpc(xmlRpcReturnValue);
    return wrapper;
}
class Volume(APIBase):
    ctorArgs = ['volumeID', 'storagepoolID', 'storagedomainID', 'imageID']

    class Types:
        UNKNOWN = storage.volume.UNKNOWN_VOL
        PREALLOCATED = storage.volume.PREALLOCATED_VOL
        SPARSE = storage.volume.SPARSE_VOL

    class Formats:
        UNKNOWN = storage.volume.UNKNOWN_FORMAT
        COW = storage.volume.COW_FORMAT
        RAW = storage.volume.RAW_FORMAT

    class Roles:
        SHARED = storage.volume.SHARED_VOL
        LEAF = storage.volume.LEAF_VOL

    BLANK_UUID = storage.volume.BLANK_UUID
......
    def create(self, size, volFormat, preallocate, diskType, desc,
                   srcImgUUID, srcVolUUID):
        return self._irs.createVolume(self._sdUUID, self._spUUID,
                                      self._imgUUID, size, volFormat,
                                      preallocate, diskType, self._UUID, desc,
                                      srcImgUUID, srcVolUUID)

SPM

SPM 是存储池管理器,用于管理所在数据中心的所有存储域,运行在数据中心的其中一台主 机上,通过协调存储域中的元数据来控制对存储的访问。虚拟化平台会保证一直有一个 SPM 在正常运行,在 SPM 的主机出现问题时,会选择另外一台主机。

private static Map<Guid, IrsProxyData> _irsProxyData = new ConcurrentHashMap<Guid, IrsProxyData>();
private IIrsServer privatemIrsProxy;

private IIrsServer getmIrsProxy() {
    return privatemIrsProxy;
}
public IIrsServer getIrsProxy() {
    if (getmIrsProxy() == null) {
        final StoragePool storagePool = DbFacade.getInstance().getStoragePoolDao().get(_storagePoolId);
        // don't try to start spm on uninitialized pool
        if (storagePool.getStatus() != StoragePoolStatus.Uninitialized) {
            String host =
                    TransactionSupport.executeInScope(TransactionScopeOption.Suppress,
                            new TransactionMethod<String>() {
                                @Override
                                public String runInTransaction() {
                                    return gethostFromVds();
                                }
                            });

            if (host != null) {
                // Get the values of the timeouts:
                int clientTimeOut = Config.<Integer> getValue(ConfigValues.vdsTimeout) * 1000;
                int connectionTimeOut = Config.<Integer>getValue(ConfigValues.vdsConnectionTimeout) * 1000;
                int clientRetries = Config.<Integer> getValue(ConfigValues.vdsRetries);

                Pair<IrsServerConnector, HttpClient> returnValue =
                        XmlRpcUtils.getConnection(host,
                                getmIrsPort(),
                                clientTimeOut,
                                connectionTimeOut,
                                clientRetries,
                                IrsServerConnector.class,
                                Config.<Boolean> getValue(ConfigValues.EncryptHostCommunication));
                privatemIrsProxy = new IrsServerWrapper(returnValue.getFirst(), returnValue.getSecond());
                runStoragePoolUpEvent(storagePool);
            }
        }
    }
    return getmIrsProxy();
}

一般场景下,一台主机挂掉,另一台主机出现 Connecting 状态,是因为调用接口时,出现网络异常 VDSNetworkException。调用 IrsBrokerCommandfailover 方法。执行失败后,可尝试恢复两次,恢复次数可设置。

private void failover() {
    if ((getParameters().getIgnoreFailoverLimit() || _failoverCounter < Config
            .<Integer> getValue(ConfigValues.SpmCommandFailOverRetries) - 1)
            && getCurrentIrsProxyData().getHasVdssForSpmSelection() && getCurrentIrsProxyData().failover()) {
        _failoverCounter++;
        executeCommand();
    } else {
        getVDSReturnValue().setSucceeded(false);
    }
}
......
public boolean failover() {
    Guid vdsId = mCurrentVdsId;
    nullifyInternalProxies();
    boolean performFailover = false;
    if (vdsId != null) {
        try {
            VDSReturnValue statusResult = ResourceManager.getInstance().runVdsCommand(VDSCommandType.SpmStatus,
                    new SpmStatusVDSCommandParameters(vdsId, _storagePoolId));
            if (statusResult != null
                    && statusResult.getSucceeded()
                    && (((SpmStatusResult) statusResult.getReturnValue()).getSpmStatus() == SpmStatus.SPM || ((SpmStatusResult) statusResult
                            .getReturnValue()).getSpmStatus() == SpmStatus.Contend)) {
                performFailover = ResourceManager
                        .getInstance()
                        .runVdsCommand(VDSCommandType.SpmStop,
                                new SpmStopVDSCommandParameters(vdsId, _storagePoolId)).getSucceeded();
            } else {
                performFailover = true;
            }
        } catch (Exception ex) {
            // try to failover to another host if failed to get spm
            // status or stop spm
            // (in case mCurrentVdsId has wrong id for some reason)
            log.errorFormat("Could not get spm status on host {0} for spmStop.", vdsId);
            performFailover = true;
        }
    }

    if (performFailover) {
        log.infoFormat("Irs placed on server {0} failed. Proceed Failover", vdsId);
        mTriedVdssList.add(vdsId);
        return true;
    } else {
        log.errorFormat("IRS failover failed - cant allocate vds server");
        return false;
    }
}
上一篇 下一篇

猜你喜欢

热点阅读