美文网首页Ovirt程序员
【Ovirt 笔记】虚拟机相关业务验证分析与整理(2)

【Ovirt 笔记】虚拟机相关业务验证分析与整理(2)

作者: 58bc06151329 | 来源:发表于2018-11-07 15:16 被阅读1次

    文前说明

    作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。

    本文仅供学习交流使用,侵权必删。
    不用于商业目的,转载请注明出处。

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

    11 创建快照

    • 创建快照使用了 CreateSnapshotCommand 类。
    • 验证实现为 validate 方法。
    protected boolean validate() {
            return true;
    }
    

    12 删除快照

    • 删除快照使用了 RemoveSnapshotCommand 类。
    • 验证实现为 validate 方法。

    12.1 虚拟机为空验证

    • 为空返回错误信息 ACTION_TYPE_FAILED_VM_NOT_FOUND
    if (vm == null) {
          return failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_NOT_FOUND);
    }
    

    12.2 Host 虚拟机和外部虚拟机验证

    if (!canRunActionOnNonManagedVm()) {
          return false;
    }
    

    12.3 数据中心验证

    • 所在数据中心必须存在且状态为启动。
    new StoragePoolValidator(getStoragePool()).existsAndUp()
    

    12.4 镜像相关验证

    • 正在执行快照相关操作验证。
    public ValidationResult vmSnapshotDisksNotDuringMerge(Guid vmId, Guid mergedSnapshotId) {
            Set<Guid> mergedSnapshotDisksIds = getSnapshotDiskIds(mergedSnapshotId).collect(Collectors.toSet());
            boolean isVmDuringSnapshot =
                    !mergedSnapshotDisksIds.isEmpty() &&
                    getAllVmLockedSnapshotIds(vmId).flatMap(this::getSnapshotDiskIds).anyMatch(mergedSnapshotDisksIds::contains);
    
            return isVmDuringSnapshot ? new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_VM_IS_DURING_SNAPSHOT) :
                    ValidationResult.VALID;
    }
    
    • 正在预览快照验证。
    public ValidationResult vmNotInPreview(Guid vmId) {
            return vmNotInStatus(vmId, SnapshotStatus.IN_PREVIEW, EngineMessage.ACTION_TYPE_FAILED_VM_IN_PREVIEW);
    }
    
    • 快照是否存在验证。
    private ValidationResult createSnapshotExistsResult(boolean snapshotExists) {
            return snapshotExists
                    ? ValidationResult.VALID
                    : new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_VM_SNAPSHOT_DOES_NOT_EXIST);
    }
    
    • 快照类型验证。
      • 只能操作一般规则类型快照。(REGULAR)
    快照类型 说明
    REGULAR 一般规则的
    ACTIVE 激活正在使用的
    STATELESS 无状态的
    PREVIEW 预览的
    NEXT_RUN 接下来运行的
    public ValidationResult isRegularSnapshot(Snapshot snapshot) {
            if (SnapshotType.REGULAR != snapshot.getType()) {
                return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_VM_SNAPSHOT_TYPE_NOT_REGULAR);
            }
            return ValidationResult.VALID;
    }
    
    • 虚拟机的磁盘快照附加到了其他虚拟机验证。
    public ValidationResult vmNotHavingDeviceSnapshotsAttachedToOtherVms(boolean onlyPlugged) {
            List<Disk> vmDisks = getDbFacade().getDiskDao().getAllForVm(vm.getId());
            ValidationResult result =
                    new DiskImagesValidator(DisksFilter.filterImageDisks(vmDisks, ONLY_NOT_SHAREABLE, ONLY_ACTIVE))
                            .diskImagesSnapshotsNotAttachedToOtherVms(onlyPlugged);
            if (result != ValidationResult.VALID) {
                return result;
            }
            return ValidationResult.VALID;
    }
    

    12.5 虚拟机状态验证

    • 虚拟机必须处于 Down、Up 或 Paused 状态。
    public ValidationResult vmQualifiedForSnapshotMerge() {
            if (!vm.isQualifiedForSnapshotMerge()) {
                return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_VM_IS_NOT_DOWN_OR_UP,
                        String.format("$VmName %s", vm.getName()));
            }
            return ValidationResult.VALID;
    }
    

    12.6 镜像验证

    • 镜像锁定验证。
    private boolean validateImagesNotLocked(DiskImagesValidator diskImagesValidator) {
            return !getParameters().isNeedsLocking() || validate(diskImagesValidator.diskImagesNotLocked());
    }
    
    • 镜像状态验证。
    getVm().isQualifiedForLiveSnapshotMerge()
    
    • 磁盘非法验证。
    public ValidationResult diskImagesNotIllegal() {
            return diskImagesNotInStatus(ImageStatus.ILLEGAL, EngineMessage.ACTION_TYPE_FAILED_DISKS_ILLEGAL);
    }
    
    • 磁盘拔出验证。
    private boolean validateSnapshotDisksArePlugged() {
            Map<Guid, Disk> vmDisks = diskDao.getAllForVm(getVmId())
                    .stream()
                    .collect(Collectors.toMap(Disk::getId, Function.identity()));
    
            // If there is an unattached disk, it will not be included in vmDisks, hence it is
            // retrieved by the diskDao. This is less likely to happen as it is not possible
            // to unattach disks with snapshots.
            String unpluggedDisks = getSourceImages()
                    .stream()
                    .map(DiskImage::getId)
                    .map(vmDiskId -> vmDisks.getOrDefault(vmDiskId, diskDao.get(vmDiskId)))
                    .filter(disk -> !disk.getPlugged())
                    .map(Disk::getDiskAlias)
                    .collect(Collectors.joining(System.lineSeparator()));
    
            if (!unpluggedDisks.isEmpty()) {
                return validate(new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_VM_SNAPSHOT_HAS_UNPLUGGED_OR_UNATTACHED_DISKS,
                        String.format("$diskAliases %s", unpluggedDisks)));
            }
            return true;
    }
    

    12.7 模板快照验证

    • 不允许删除模板快照。
    if (!validateImageNotInTemplate()) {
                    return failValidation(EngineMessage.ACTION_TYPE_FAILED_CANNOT_REMOVE_IMAGE_TEMPLATE);
    }
    

    12.8 存储域验证

    • 至少存在一个激活的存储域。
    storageDomainsValidator.allDomainsExistAndActive()
    
    • 存储域中可用的磁盘空间过低。
    public ValidationResult allDomainsWithinThresholds() {
            return validOrFirstFailure(entry -> getStorageDomainValidator(entry).isDomainWithinThresholds());
    }
    ......
    public ValidationResult hasSpaceForMerge(List<SubchainInfo> subchains, ActionType snapshotActionType) {
            if (storageDomain.getStorageType().isCinderDomain()) {
                return ValidationResult.VALID;
            }
            Long availableSize = storageDomain.getAvailableDiskSizeInBytes();
            double totalSizeForDisks = getTotalSizeForMerge(subchains, snapshotActionType);
    
            return validateRequiredSpace(availableSize, totalSizeForDisks);
    }
    

    13 恢复快照

    • 恢复快照使用了 RestoreAllSnapshotsCommand 类。
    • 验证实现为 validate 方法。

    13.1 虚拟机为空验证

    • 为空返回错误信息 ACTION_TYPE_FAILED_VM_NOT_FOUND
    if (vm == null) {
          return failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_NOT_FOUND);
    }
    

    13.2 Host 虚拟机和外部虚拟机验证

    if (!canRunActionOnNonManagedVm()) {
          return false;
    }
    

    13.3 数据中心验证

    • 所在数据中心必须存在且状态为启动。
    new StoragePoolValidator(getStoragePool()).existsAndUp()
    

    13.4 快照相关验证

    • 快照是否存在验证。
    snapshotsValidator.snapshotExists(getSnapshot())
    
    • 虚拟机中该快照是否存在验证。
    snapshotsValidator.snapshotExists(getVmId(), getSnapshot().getId())
    
    • 快照 ID 是否存在验证。
    if (Guid.Empty.equals(getSnapshot().getId())) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_CORRUPTED_VM_SNAPSHOT_ID);
    }
    
    • 快照状态验证。
      • 快照没有处于预览状态。
    if (getSnapshot().getType() == SnapshotType.REGULAR
                    && getSnapshot().getStatus() != SnapshotStatus.IN_PREVIEW) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_SNAPSHOT_NOT_IN_PREVIEW);
    }
    

    13.5 存储域验证

    • 至少存在一个激活的存储域。
    storageDomainsValidator.allDomainsExistAndActive()
    

    13.6 镜像锁验证

    protected boolean performImagesChecks() {
            List<DiskImage> diskImagesToCheck =
                    DisksFilter.filterImageDisks(getImagesList(), ONLY_NOT_SHAREABLE, ONLY_ACTIVE);
            DiskImagesValidator diskImagesValidator = new DiskImagesValidator(diskImagesToCheck);
            return validate(diskImagesValidator.diskImagesNotLocked());
    }
    

    13.7 虚拟机状态验证

    • 虚拟机必须为 Down 状态。
    public ValidationResult vmDown() {
            if (!vm.isDown()) {
                return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_VM_IS_NOT_DOWN);
            }
            return ValidationResult.VALID;
    }
    
    • 虚拟机的磁盘快照附加到了其他虚拟机验证。
    public ValidationResult vmNotHavingDeviceSnapshotsAttachedToOtherVms(boolean onlyPlugged) {
            List<Disk> vmDisks = getDbFacade().getDiskDao().getAllForVm(vm.getId());
            ValidationResult result =
                    new DiskImagesValidator(DisksFilter.filterImageDisks(vmDisks, ONLY_NOT_SHAREABLE, ONLY_ACTIVE))
                            .diskImagesSnapshotsNotAttachedToOtherVms(onlyPlugged);
            if (result != ValidationResult.VALID) {
                return result;
            }
            return ValidationResult.VALID;
    }
    

    13.8 MAC 池范围验证

    • MAC 地址池里没有足够的 MAC 地址。
    private boolean canRestoreVmConfigFromSnapshot() {
            Snapshot snapshot = getSnapshot();
            return snapshot.getType() == SnapshotType.PREVIEW ?
                    getSnapshotsManager().canRestoreVmConfigurationFromSnapshot(getVm(),
                            snapshot,
                            new VmInterfaceManager(getMacPool()))
                    : true;
    }
    

    14 提交快照

    • 与恢复快照一致。

    15 快照克隆虚拟机

    • 恢复快照使用了 AddVmFromSnapshotCommand 类。
    • 验证实现为 validate 方法。

    15.1 快照相关验证

    • 快照是否存在验证。
    snapshotsValidator.snapshotExists(getSnapshot())
    
    • 正在执行快照相关操作验证。
    public ValidationResult vmNotDuringSnapshot(Guid vmId) {
            return vmNotInStatus(vmId, SnapshotStatus.LOCKED, EngineMessage.ACTION_TYPE_FAILED_VM_IS_DURING_SNAPSHOT);
    }
    
    • 快照可用配置验证。
    public ValidationResult snapshotVmConfigurationBroken(Snapshot snapshot, String vmName) {
            return !snapshot.isVmConfigurationBroken()
                    ? ValidationResult.VALID
                    : new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_VM_SNAPSHOT_HAS_NO_CONFIGURATION,
                    String.format("$VmName %1$s", vmName),
                    String.format("$SnapshotName %1$s", snapshot.getDescription()));
    }
    
    vmFromConfiguration = getVmFromConfiguration();
            if (vmFromConfiguration == null) {
                addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_VM_SNAPSHOT_HAS_NO_CONFIGURATION);
                addValidationMessageVariable("VmName", getVmName());
                addValidationMessageVariable("SnapshotName", getSnapshotName());
    
                return false;
    }
    

    15.2 镜像锁验证

    public ValidationResult diskImagesNotLocked() {
            return diskImagesNotInStatus(ImageStatus.LOCKED, EngineMessage.ACTION_TYPE_FAILED_DISKS_LOCKED);
    }
    

    15.3 存储域验证

    • 至少存在一个激活的存储域。
    storageDomainsValidator.allDomainsExistAndActive()
    
    • 磁盘配置与存储域类型不兼容。
    public ValidationResult snapshotVmConfigurationBroken(Snapshot snapshot, String vmName) {
            return !snapshot.isVmConfigurationBroken()
                    ? ValidationResult.VALID
                    : new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_VM_SNAPSHOT_HAS_NO_CONFIGURATION,
                    String.format("$VmName %1$s", vmName),
                    String.format("$SnapshotName %1$s", snapshot.getDescription()));
    }
    

    15.4 虚拟机锁验证

    public ValidationResult vmNotLocked() {
            if (vm.getStatus() == VMStatus.ImageLocked) {
                return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_VM_IS_LOCKED);
            }
            return ValidationResult.VALID;
    }
    

    15.4 创建虚拟机验证

    • 与创建虚拟机一致。

    15.5 VirtIO-SCSI 磁盘验证

    protected boolean checkCanDisableVirtIoScsi() {
            VmValidator vmValidator = createVmValidator(getVmFromConfiguration());
            if (Boolean.FALSE.equals(getParameters().isVirtioScsiEnabled()) &&
                    !validate(vmValidator.canDisableVirtioScsi(getAdjustedDiskImagesFromConfiguration()))) {
                return false;
            } else {
                return true;
            }
    }
    

    16 创建模板

    • 恢复快照使用了 AddVmTemplateCommand 类。
    • 验证实现为 validate 方法。

    16.1 群集验证

    • 群集 ID 不存在验证。
    boolean isInstanceType = getParameters().getTemplateType() == VmEntityType.INSTANCE_TYPE;
    if (getCluster() == null && !isInstanceType) {
        return failValidation(EngineMessage.VDS_CLUSTER_IS_NOT_VALID);
    }
    
    • 群集不具有定义的架构。
    if (getCluster().getArchitecture() == ArchitectureType.undefined) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_CLUSTER_UNDEFINED_ARCHITECTURE);
    }
    
    • 架构操作系统支持。
    if (!validate(vmHandler.isOsTypeSupported(getParameters().getMasterVm().getOsId(), getCluster().getArchitecture()))) {
           return false;
    }
    
    • 图形显示支持。
    Guid srcId = isVmInDb ? getVmId() : VmTemplateHandler.BLANK_VM_TEMPLATE_ID;
    if (!validate(vmHandler.isGraphicsAndDisplaySupported(getParameters().getMasterVm().getOsId(), vmHandler.getResultingVmGraphics(getVmDeviceUtils().getGraphicsTypesOfEntity(srcId), getParameters().getGraphicsDevices()), getParameters().getMasterVm().getDefaultDisplayType(), getVm().getCompatibilityVersion()))) {
           return false;
    }
    
    • 单显示设备验证。
      • 不能通过 VNC 设置单个显示设备。
      • 不能在非 Linux 操作系统上设置单个显示设备。
    if (getParameters().getVm().getSingleQxlPci() &&
                    !validate(vmHandler.isSingleQxlDeviceLegal(
                            getParameters().getVm().getDefaultDisplayType(), getParameters().getVm().getOs()))) {
                return false;
    }
    
    • 智能卡验证。
    if (!validate(vmHandler.validateSmartCardDevice(getParameters().getMasterVm()))) {
         return false;
    }
    
    • 系统看门狗支持。
    // Check if the watchdog model is supported
            if (getParameters().getWatchdog() != null) {
                if (!validate(new VmWatchdogValidator.VmWatchdogClusterDependentValidator(getParameters().getMasterVm().getOsId(),
                        getParameters().getWatchdog(),
                        getVm().getCompatibilityVersion()).isValid())) {
                    return false;
                }
    }
    
    • 所属数据中心验证。
    if (!getStoragePoolId().equals(getCluster().getStoragePoolId())) {
                addValidationMessage(EngineMessage.VDS_CLUSTER_ON_DIFFERENT_STORAGE_POOL);
           return false;
    }
    
    • 虚拟机属性验证。
    if (!VmPropertiesUtils.getInstance().validateVmProperties(getVm().getCompatibilityVersion(), getParameters().getMasterVm().getCustomProperties(), getReturnValue().getValidationMessages())) {
          return false;
    }
    

    16.2 虚拟机优先级范围验证

    • 优先级范围 >=0 且 <=VmPriorityMaxValue。(默认值为 100)
    public ValidationResult isVmPriorityValueLegal(int value) {
            return ValidationResult.failWith(
                    EngineMessage.VM_OR_TEMPLATE_ILLEGAL_PRIORITY_VALUE,
                    String.format("$MaxValue %1$s", Config.<Integer> getValue(ConfigValues.VmPriorityMaxValue))
            ).unless(value >= 0 && value <= Config.<Integer> getValue(ConfigValues.VmPriorityMaxValue));
    }
    

    16.3 虚拟机是否锁定运行验证

    if (isVmInDb && !isVmStatusValid(getVm().getStatus())) {
                return failValidation(EngineMessage.VMT_CANNOT_CREATE_TEMPLATE_FROM_DOWN_VM);
    }
    

    16.4 名称重复验证

    if (!isTemplateVersion()) {
                if (isInstanceType) {
                    if (isInstanceWithSameNameExists(getVmTemplateName())) {
                        return failValidation(EngineMessage.ACTION_TYPE_FAILED_NAME_ALREADY_USED);
                    }
                } else {
                    if (isVmTemplateWithSameNameExist(getVmTemplateName(), getCluster().getStoragePoolId())) {
                        return failValidation(EngineMessage.ACTION_TYPE_FAILED_NAME_ALREADY_USED);
                    }
                }
    }
    

    16.5 基础模板验证

    • 基础模板是否存在。
    • 基础模板是否可用。
    if (isTemplateVersion()) {
                VmTemplate userSelectedBaseTemplate = getBaseTemplate();
                if (userSelectedBaseTemplate == null) {
                    return failValidation(EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_DOES_NOT_EXIST);
                } else if (!userSelectedBaseTemplate.isBaseTemplate()) {
                    // currently template version cannot be base template
                    return failValidation(EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_VERSION_CANNOT_BE_BASE_TEMPLATE);
    
                }
    }
    
    • 空模板不能有子模板。
    if (isTemplateVersion() && getBaseTemplate().isBlank()) {
                return failValidation(EngineMessage.BLANK_TEMPLATE_CANT_HAVE_SUBTEMPLATES);
    }
    

    16.6 磁盘配置集设置验证

    protected boolean setAndValidateDiskProfiles() {
            if (diskInfoDestinationMap != null && !diskInfoDestinationMap.isEmpty()) {
                Map<DiskImage, Guid> map = diskInfoDestinationMap.values().stream()
                        .filter(DisksFilter.ONLY_IMAGES)
                        .collect(Collectors.toMap(Function.identity(), d -> d.getStorageIds().get(0)));
                return validate(diskProfileHelper.setAndValidateDiskProfiles(map, getCurrentUser()));
            }
            return true;
    }
    
    • 是否有配置集设置权限。
    if (!updateDiskProfileForBackwardCompatibility(diskImage, diskProfilesList, permittedDiskProfilesIds, user)) {
           return new ValidationResult(EngineMessage.USER_NOT_AUTHORIZED_TO_ATTACH_DISK_PROFILE);
    }
    
    • 存储中没有查询到定义的磁盘配置集。
    DiskProfile diskProfile = updateDiskImageProfilesList(diskImage, storageDomainId);
                    if (diskProfile == null) {
                        return new ValidationResult(EngineMessage.ACTION_TYPE_DISK_PROFILE_NOT_FOUND_FOR_STORAGE_DOMAIN,
                                String.format("$storageDomainId %s", storageDomainId));
    }
    
    • 是否有权限为磁盘附加配置集。
    ValidationResult result = isDiskProfileParentEntityValid(diskProfile, storageDomainId);
    if (result != ValidationResult.VALID) {
            return result;
    }
    if (!isDiskProfilePermitted(diskProfile, permittedDiskProfilesIds, user)) {
            return new ValidationResult(EngineMessage.USER_NOT_AUTHORIZED_TO_ATTACH_DISK_PROFILE);
    }
    

    16.7 CPU 配置集设置验证

    protected boolean setAndValidateCpuProfile() {
            // cpu profile isn't supported for instance types.
            if (getParameters().getTemplateType() == VmEntityType.INSTANCE_TYPE) {
                return true;
            }
            return validate(cpuProfileHelper.setAndValidateCpuProfile(
                    getParameters().getMasterVm(),
                    getUserIdIfExternal().orElse(null)));
    }
    
    • 有无 CPU 配置集。
    if (vmBase.getCpuProfileId() == null) {
          return assignFirstCpuProfile(vmBase, userId);
    }
    
    • 群集不存在。
    Guid clusterId =  vmBase.getClusterId();
    if (clusterId == null) {
         return new ValidationResult(EngineMessage.ACTION_TYPE_CPU_PROFILE_CLUSTER_NOT_PROVIDED);
    }
    
    • 通过 ID 查询不到 CPU 配置集。
    CpuProfile fetchedCpuProfile = cpuProfileDao.get(vmBase.getCpuProfileId());
    if (fetchedCpuProfile == null) {
          return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_CPU_PROFILE_NOT_FOUND);
    }
    
    • CPU 配置集与群集不匹配。
    if (!clusterId.equals(fetchedCpuProfile.getClusterId())) {
        return new ValidationResult(EngineMessage.ACTION_TYPE_CPU_PROFILE_NOT_MATCH_CLUSTER);
    }
    
    • 有无权限分配 CPU 配置集给虚拟机。
    if (!checkPermissions(vmBase.getCpuProfileId(), userId)) {
                return new ValidationResult(EngineMessage.ACTION_TYPE_NO_PERMISSION_TO_ASSIGN_CPU_PROFILE,
                        String.format("$cpuProfileId %s",
                                vmBase.getCpuProfileId()),
                        String.format("$cpuProfileName %s",
                                fetchedCpuProfile.getName()));
    }
    

    16.8 空磁盘别名验证

    protected boolean isDisksAliasNotEmpty() {
            // Check that all the template's allocated disk's aliases are not an empty string.
            for (DiskImage diskImage : diskInfoDestinationMap.values()) {
                if (StringUtils.isEmpty(diskImage.getDiskAlias())) {
                    return failValidation(EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_CANNOT_BE_CREATED_WITH_EMPTY_DISK_ALIAS);
                }
            }
            return true;
    }
    

    16.9 虚拟机图标验证

    • 图标是否存在。
    • 格式是否正确。
    • 图标类型是否未知。
    • 图标是否能够读取。
    • 图标 mime 类型与镜像数据是否匹配。
    • 图标维度验证。

    16.9.1 大图标验证。

    if (getParameters().getVmLargeIcon() != null && !validate(IconValidator.validate(IconValidator.DimensionsType.LARGE_CUSTOM_ICON, getParameters().getVmLargeIcon()))) {
         return false;
    }
    
    if (getParameters().getMasterVm().getLargeIconId() != null
                    && getParameters().getVmLargeIcon() == null // icon id is ignored if large icon is sent
                    && !validate(IconValidator.validateIconId(getParameters().getMasterVm().getLargeIconId(), "Large"))) {
                return false;
    }
    

    16.9.2 小图标验证。

    if (getParameters().getMasterVm().getSmallIconId() != null
                    && getParameters().getVmLargeIcon() == null // icon id is ignored if large icon is sent
                    && !validate(IconValidator.validateIconId(getParameters().getMasterVm().getSmallIconId(), "Small"))) {
                return false;
    }
    

    16.10 看门狗验证

    if (getParameters().getWatchdog() != null) {
                if (!validate(new VmWatchdogValidator.VmWatchdogClusterIndependentValidator(
                                getParameters().getWatchdog()).isValid())) {
                    return false;
                }
    }
    

    16.11 内存验证

    • 最大内存限制。
    if (vmBase.getMaxMemorySizeMb() < vmBase.getMemSizeMb()) {
                return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_MAX_MEMORY_CANNOT_BE_SMALLER_THAN_MEMORY_SIZE,
                        ReplacementUtils.createSetVariableString("maxMemory", vmBase.getMaxMemorySizeMb()),
                        ReplacementUtils.createSetVariableString("memory", vmBase.getMemSizeMb()));
    }
    
    • 平台限制最大内存。
      • 32 位操作系统 VM32BitMaxMemorySizeInMB,默认 20480 M。
      • 64 位 PPC 架构 VMPpc64BitMaxMemorySizeInMB,默认 1048576 M。
      • 64 位其他架构 VM64BitMaxMemorySizeInMB,默认 4194304 M。
    final int maxMemoryUpperBound = VmCommonUtils.maxMemorySizeWithHotplugInMb(vmBase.getOsId(), effectiveCompatibilityVersion);
    if (vmBase.getMaxMemorySizeMb() > maxMemoryUpperBound) {
           return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_MAX_MEMORY_CANNOT_EXCEED_PLATFORM_LIMIT, ReplacementUtils.createSetVariableString("maxMemory", vmBase.getMaxMemorySizeMb()), ReplacementUtils.createSetVariableString("platformLimit", maxMemoryUpperBound));
    }
    

    16.12 封装 Windows 验证

    if (getParameters().isSealTemplate() && vmHandler.isWindowsVm(getVm())) {
          return failValidation(EngineMessage.VM_TEMPLATE_CANNOT_SEAL_WINDOWS);
    }
    

    16.13 镜像验证

    • 快照是否锁定验证。
    if (!validateVmNotDuringSnapshot()) {
           return false;
    }
    
    • 存在启动的数据中心。
    if (!validate(new StoragePoolValidator(getStoragePool()).existsAndUp())) {
          return false;
    }
    
    • Cinder 磁盘最大卷数量验证。
    List<CinderDisk> cinderDisks = getCinderDisks();
    CinderDisksValidator cinderDisksValidator = new CinderDisksValidator(cinderDisks);
    if (!validate(cinderDisksValidator.validateCinderDiskLimits())) {
          return false;
    }
    
    • 磁盘擦除支持。
    protected ValidationResult isPassDiscardSupportedForImagesDestSds() {
            Map<Disk, DiskVmElement> diskToDiskVmElement = diskHandler.getDiskToDiskVmElementMap(
                    getVm().getId(), diskInfoDestinationMap);
            Map<Guid, Guid> diskIdToDestSdId = diskInfoDestinationMap.values().stream()
                    .collect(Collectors.toMap(DiskImage::getId, diskImage -> diskImage.getStorageIds().get(0)));
    
            MultipleDiskVmElementValidator multipleDiskVmElementValidator =
                    createMultipleDiskVmElementValidator(diskToDiskVmElement);
            return multipleDiskVmElementValidator.isPassDiscardSupportedForDestSds(diskIdToDestSdId);
    }
    
    • 磁盘锁和损坏验证。
    List<DiskImage> diskImagesToCheck = DisksFilter.filterImageDisks(images, ONLY_NOT_SHAREABLE, ONLY_ACTIVE); 
    diskImagesToCheck.addAll(cinderDisks);
    DiskImagesValidator diskImagesValidator = new DiskImagesValidator(diskImagesToCheck);
    if (!validate(diskImagesValidator.diskImagesNotIllegal()) || !validate(diskImagesValidator.diskImagesNotLocked())) {
            return false;
    }
    

    16.13.1 存储域验证

    • 存储域激活验证。
    MultipleStorageDomainsValidator storageDomainsValidator =
                        getStorageDomainsValidator(getStoragePoolId(), sourceImageDomainsImageMap.keySet());
    if (!validate(storageDomainsValidator.allDomainsExistAndActive())) {
             return false;
    }
    
    • 存储域存在和存储域所属数据中心一致验证。
    if (storageDomainStaticDao.get(destImageDomain) == null) {
               addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_STORAGE_DOMAIN_NOT_EXIST);
    } else {
               addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_STORAGE_DOMAIN_NOT_IN_STORAGE_POOL);
    }
    return false;
    
    • 存储域非法验证。
    if (storage.getStatus() == null || storage.getStatus() != StorageDomainStatus.Active) {
                        addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_STORAGE_DOMAIN_STATUS_ILLEGAL);
                        return false;
                    }
    
                    if (storage.getStorageDomainType().isIsoOrImportExportDomain()) {
    
                        addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_STORAGE_DOMAIN_TYPE_ILLEGAL);
                        return false;
    }
    

    16.14 CPU 核数验证

    • 不同的 CPU 架构不同的核数限制。
    public static ValidationResult validateCpuSockets(VmBase vmBase, Version compatibilityVersion) {
            int num_of_sockets = vmBase.getNumOfSockets();
            int cpu_per_socket = vmBase.getCpuPerSocket();
            int threadsPerCpu = vmBase.getThreadsPerCpu();
    
            String version = compatibilityVersion.toString();
    
            if ((num_of_sockets * cpu_per_socket * threadsPerCpu) >
                    Config.<Integer> getValue(ConfigValues.MaxNumOfVmCpus, version)) {
                return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_MAX_NUM_CPU);
            }
            if (num_of_sockets > Config.<Integer> getValue(ConfigValues.MaxNumOfVmSockets, version)) {
                return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_MAX_NUM_SOCKETS);
            }
            if (cpu_per_socket > Config.<Integer> getValue(ConfigValues.MaxNumOfCpuPerSocket, version)) {
                return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_MAX_CPU_PER_SOCKET);
            }
            if (threadsPerCpu > Config.<Integer> getValue(ConfigValues.MaxNumOfThreadsPerCpu, version)) {
                return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_MAX_THREADS_PER_CPU);
            }
            if (cpu_per_socket < 1) {
                return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_MIN_CPU_PER_SOCKET);
            }
            if (num_of_sockets < 1) {
                return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_MIN_NUM_SOCKETS);
            }
            if (threadsPerCpu < 1) {
                return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_MIN_THREADS_PER_CPU);
            }
            return ValidationResult.VALID;
    }
    

    17 模板创建虚拟机

    • 模板创建虚拟机使用了 AddVmFromTemplateCommand 类。
    • 验证实现为 validate 方法。

    17.1 创建虚拟机验证。

    • 与 6 创建虚拟机验证一致。

    17.2 磁盘配置与存储域类型兼容验证

    List<DiskImage> templateDiskImages = DisksFilter.filterImageDisks(getVmTemplate().getDiskTemplateMap().values(), ONLY_NOT_SHAREABLE);
    for (DiskImage dit : templateDiskImages) {
                DiskImage diskImage = diskInfoDestinationMap.get(dit.getId());
                if (!ImagesHandler.checkImageConfiguration(
                        destStorages.get(diskImage.getStorageIds().get(0)).getStorageStaticData(),
                        diskImage,
                        getReturnValue().getValidationMessages())) {
                    return false;
                }
    }
    

    18 导出虚拟机

    • 导出虚拟机使用了 ExportVmCommand 类。
    • 验证实现为 validate 方法。

    18.1 虚拟机为空验证

    if (getVm() == null) {
           return failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_NOT_FOUND);
    }
    

    18.2 存储域验证

    • 存储域存在并激活验证。
    StorageDomainValidator targetstorageDomainValidator = new StorageDomainValidator(getStorageDomain());
    if (!validate(targetstorageDomainValidator.isDomainExistAndActive())) {
           return false;
    }
    

    18.3 镜像加锁验证

    List<DiskImage> disksForExport = getDisksBasedOnImage();
    DiskImagesValidator diskImagesValidator = new DiskImagesValidator(disksForExport);
    if (!validate(diskImagesValidator.diskImagesNotIllegal()) || !validate(diskImagesValidator.diskImagesNotLocked())) {
        return false;
    }
    

    18.4 存储域验证

    • 目标存储域不在数据中心内。
    // check that the target and source domain are in the same storage_pool
    if (storagePoolIsoMapDao.get(new StoragePoolIsoMapId(getStorageDomain().getId(), getVm().getStoragePoolId())) == null) {
         return failValidation(EngineMessage.ACTION_TYPE_FAILED_STORAGE_POOL_NOT_MATCH);
    }
    

    18.4 模板验证

    • 模板不存在导出域中。
      • 如果只导出虚拟机,而不导出依赖的模板,那么需要设置 TemplateMustExists=false
    if (getParameters().getTemplateMustExists()) {
                if (!checkTemplateInStorageDomain(getVm().getStoragePoolId(), getParameters().getStorageDomainId(),
                        getVm().getVmtGuid(), getContext().getEngineContext())) {
                    return failValidation(EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_NOT_FOUND_ON_EXPORT_DOMAIN,
                            String.format("$TemplateName %1$s", getVm().getVmtName()));
                }
    }
    

    18.5 导出格式验证

    • 在导出虚拟机上无法把格式修改为 RAW
    Map<Guid, ? extends Disk> images = getVm().getDiskMap();
            if (getParameters().getCopyCollapse()) {
                for (DiskImage img : disksForExport) {
                    if (images.containsKey(img.getId())) {
                        // check that no RAW format exists (we are in collapse mode)
                        if (((DiskImage) images.get(img.getId())).getVolumeFormat() == VolumeFormat.RAW
                                && img.getVolumeFormat() != VolumeFormat.RAW) {
                            return failValidation(EngineMessage.VM_CANNOT_EXPORT_RAW_FORMAT);
                        }
                    }
                }
    }
    

    18.6 导出域验证

    • 指定的域不是一个导出域。
    if (getStorageDomain().getStorageDomainType() != StorageDomainType.ImportExport) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_SPECIFY_DOMAIN_IS_NOT_EXPORT_DOMAIN, String.format("$storageDomainName %1$s", getStorageDomainName()));
    }
    
    • 存储域剩余空间验证。
    private boolean handleDestStorageDomain(List<DiskImage> disksList) {
            ensureDomainMap(disksList, getStorageDomainId());
            List<DiskImage> dummiesDisksList = createDiskDummiesForSpaceValidations(disksList);
            dummiesDisksList.addAll(getMemoryVolumes());
            return validateSpaceRequirements(dummiesDisksList);
    }
    
    • 虚拟机名称重复验证
    protected boolean checkVmInStorageDomain() {
            GetAllFromExportDomainQueryParameters tempVar = new GetAllFromExportDomainQueryParameters(getVm()
                    .getStoragePoolId(), getParameters().getStorageDomainId());
            QueryReturnValue qretVal = runInternalQuery(QueryType.GetVmsFromExportDomain,
                    tempVar);
    
            if (qretVal.getSucceeded()) {
                List<VM> vms = qretVal.getReturnValue();
                for (VM vm : vms) {
                    if (vm.getId().equals(getVm().getId())) {
                        if (!getParameters().getForceOverride()) {
                            return failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_GUID_ALREADY_EXIST);
                        }
                    } else if (vm.getName().equals(getVm().getName())) {
                        return failValidation(EngineMessage.ACTION_TYPE_FAILED_NAME_ALREADY_USED);
                    }
                }
            }
            return true;
    }
    
    • 存储域必须存在并激活状态。
    new MultipleStorageDomainsValidator(getVm().getStoragePoolId(), ImagesHandler.getAllStorageIdsForImageIds(disksForExport)).allDomainsExistAndActive()))
    

    18.7 数据中心验证

    • 数据中心必须存在并处于激活状态。
    new StoragePoolValidator(getStoragePool()).existsAndUp()
    

    18.8 快照验证

    • 镜像是否正在被使用。
    snapshotsValidator.vmNotDuringSnapshot(getVmId())
    
    • 不存在预览状态的快照。
    snapshotsValidator.vmNotInPreview(getVmId())
    

    18.9 虚拟机状态验证

    • 虚拟机是否存于关机状态。
    new VmValidator(getVm()).vmDown()
    

    19 导入虚拟机

    • 导入虚拟机使用了 ImportVmCommand 类。
    • 验证实现为 validate 方法。

    19.1 虚拟机为空验证

    if (getVm() == null) {
           return failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_NOT_FOUND);
    }
    

    19.2 群集验证

    • 群集是否存在。
    if (getCluster() == null) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_CLUSTER_CAN_NOT_BE_EMPTY);
    }
    
    • 群集 ID 是否存在。
    if (getParameters().getStoragePoolId() != null
                    && !getParameters().getStoragePoolId().equals(getCluster().getStoragePoolId())) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_CLUSTER_IS_NOT_VALID);
    }
    

    19.3 MAC 池验证

    • 不允许导入可能会在目标 MAC 池中造成重复的虚拟机。
    List<VmNetworkInterface> nicsUnableToBeImported = getVm().getInterfaces()
                    .stream()
                    .filter(this::ifaceMacCannotBeAddedToMacPool)
                    .collect(Collectors.toList());
    
            if (!nicsUnableToBeImported.isEmpty()) {
                EngineMessage engineMessage = EngineMessage.ACTION_TYPE_FAILED_CANNOT_ADD_IFACE_DUE_TO_MAC_DUPLICATES;
                Collection<String> replacements =
                        ReplacementUtils.getListVariableAssignmentString(engineMessage, nicsUnableToBeImported);
    
                return validate(new ValidationResult(engineMessage, replacements));
    }
    
    • 导入后 MAC 地址池里没有足够的 MAC 地址。
    if (getParameters().isImportAsNewEntity()) {
                initImportClonedVm();
    
                if (getVm().getInterfaces().size() > getMacPool().getAvailableMacsCount()) {
                    return failValidation(EngineMessage.MAC_POOL_NOT_ENOUGH_MAC_ADDRESSES);
                }
    }
    

    19.4 cloud-init 配置验证

    • cloud-init 配置中的 Start On Boot 只支持 true。
    • cloud-init 配置中缺少了静态 IPv4 地址。
    • cloud-init 配置中缺少了静态 IPv6 地址。
    • cloud-init 配置中的选项 'autoconf' 不被支持。
    public List<EngineMessage> validate(VmInit vmInit) {
            if (vmInit == null || vmInit.getNetworks() == null) {
                return null;
            }
    
            List<EngineMessage> msgs = new LinkedList<>();
            List<VmInitNetwork> vmInitNetworks = vmInit.getNetworks();
            for (VmInitNetwork vmInitNetwork : vmInitNetworks) {
                if (!isStartOnBoot(vmInitNetwork)) {
                    msgs.add(EngineMessage.VALIDATION_CLOUD_INIT_START_ON_BOOT_INVALID);
                }
                if (isStaticIPv4AndAddressMissing(vmInitNetwork)) {
                    msgs.add(EngineMessage.VALIDATION_CLOUD_INIT_STATIC_IPV4_ADDRESS_MISSING);
                }
                if (isStaticIPv6AndAddressMissing(vmInitNetwork)) {
                    msgs.add(EngineMessage.VALIDATION_CLOUD_INIT_STATIC_IPV6_ADDRESS_MISSING);
                }
                if (isAutoConfIPv6(vmInitNetwork)) {
                    msgs.add(EngineMessage.VALIDATION_CLOUD_INIT_IPV6_AUTOCONF_UNSUPPORTED);
                }
            }
            return msgs;
    }
    

    19.5 导入前验证

    Map<Guid, StorageDomain> domainsMap = new HashMap<>();
    if (!validateBeforeCloneVm(domainsMap)) {
           return false;
    }
    

    19.5.1 数据中心验证

    • 数据中心存在并激活状态。
    StoragePoolValidator spValidator = new StoragePoolValidator(getStoragePool());
    if (!validate(spValidator.existsAndUp())) {
           return false;
    }
    

    19.5.2 存储域验证

    • 存储域存在并激活状态。
    • 目的域类型非法。
    Set<Guid> destGuids = new HashSet<>(imageToDestinationDomainMap.values());
            for (Guid destGuid : destGuids) {
                StorageDomain storageDomain = getStorageDomain(destGuid);
                StorageDomainValidator validator = new StorageDomainValidator(storageDomain);
                if (!validate(validator.isDomainExistAndActive()) || !validate(validator.domainIsValidDestination())) {
                    return false;
                }
    
                domainsMap.put(destGuid, storageDomain);
    }
    

    19.5.3 快照验证

    • 导出域中虚拟机存在快照的情况,需要考虑存在被 collapse 的快照。
    if (!isImagesAlreadyOnTarget() && getParameters().isImportAsNewEntity()
                    && isCopyCollapseDisabledWithSnapshotsOrWithTemplate()) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_IMPORT_CLONE_NOT_COLLAPSED,
                        String.format("$VmName %1$s", getVmName()));
    }
    
    • 没有注册的虚拟机不能被 collapse。
    if (isImagesAlreadyOnTarget() && getParameters().getCopyCollapse()) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_IMPORT_UNREGISTERED_NOT_COLLAPSED);
    }
    

    19.5.4 导出域验证

    • 非法存储域类型。
    • 导出域中不包含该虚拟机。
    if (!isImagesAlreadyOnTarget()) {
                setSourceDomainId(getParameters().getSourceDomainId());
                StorageDomainValidator validator = new StorageDomainValidator(getSourceDomain());
                if (validator.isDomainExistAndActive().isValid()
                        && getSourceDomain().getStorageDomainType() != StorageDomainType.ImportExport) {
                    return failValidation(EngineMessage.ACTION_TYPE_FAILED_STORAGE_DOMAIN_TYPE_ILLEGAL);
                }
                if (!validateAndSetVmFromExportDomain()) {
                    return failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_NOT_FOUND_ON_EXPORT_DOMAIN);
                }
    }
    

    19.5.5 镜像验证

    if (!validateImages(domainsMap)) {
            return false;
    }
    

    19.6 内存气球支持

    protected boolean validateBallonDevice() {
            if (!VmDeviceCommonUtils.isBalloonDeviceExists(getVm().getManagedVmDeviceMap().values())) {
                return true;
            }
    
            if (!osRepository.isBalloonEnabled(getVm().getStaticData().getOsId(),
                    getEffectiveCompatibilityVersion())) {
                addValidationMessageVariable("clusterArch", getCluster().getArchitecture());
                return failValidation(EngineMessage.BALLOON_REQUESTED_ON_NOT_SUPPORTED_ARCH);
            }
    
            return true;
    }
    

    19.7 音频设备支持

    protected boolean validateSoundDevice() {
            if (!VmDeviceCommonUtils.isSoundDeviceExists(getVm().getManagedVmDeviceMap().values())) {
                return true;
            }
    
            if (!osRepository.isSoundDeviceEnabled(getVm().getStaticData().getOsId(),
                    getEffectiveCompatibilityVersion())) {
                addValidationMessageVariable("clusterArch", getCluster().getArchitecture());
                return failValidation(EngineMessage.SOUND_DEVICE_REQUESTED_ON_NOT_SUPPORTED_ARCH);
            }
    
            return true;
    }
    

    19.8 内存验证

    • 与 16.11 内存验证一致。

    19.9 导入后验证

    19.9.1 虚拟机 ID 是否存在

    if (!validateNoDuplicateVm()) {
                return false;
    }
    

    19.9.2 磁盘是否存在

    public ValidationResult diskImagesAlreadyExist() {
    
            List<String> existingDisksAliases = new ArrayList<>();
            for (DiskImage diskImage : diskImages) {
                DiskImage existingDisk = getExistingDisk(diskImage.getId());
                if (existingDisk != null) {
                    existingDisksAliases.add(diskImage.getDiskAlias().isEmpty() ? existingDisk.getDiskAlias() : diskImage.getDiskAlias());
                }
            }
    
            if (!existingDisksAliases.isEmpty()) {
                return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_IMPORT_DISKS_ALREADY_EXIST,
                        String.format("$diskAliases %s", StringUtils.join(existingDisksAliases, ", ")));
            }
    
            return ValidationResult.VALID;
    }
    

    19.9.3 模板验证

    • 模板是否存在。
    private boolean templateExists() {
            if (getVmTemplate() == null && !getParameters().getCopyCollapse()) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_DOES_NOT_EXIST);
            }
            return true;
    }
    
    • 所选的存储域是否包含虚拟机模板。
    protected boolean checkTemplateInStorageDomain() {
            boolean retValue = validate(getImportValidator().verifyDisks(imageList, imageToDestinationDomainMap));
            if (retValue && !VmTemplateHandler.BLANK_VM_TEMPLATE_ID.equals(getVm().getVmtGuid())
                    && !getParameters().getCopyCollapse()) {
                List<StorageDomain> domains = runInternalQuery(QueryType.GetStorageDomainsByVmTemplateId,
                        new IdQueryParameters(getVm().getVmtGuid())).getReturnValue();
                Set<Guid> domainsId = domains.stream().map(StorageDomain::getId).collect(Collectors.toSet());
    
                if (!domainsId.isEmpty() && Collections.disjoint(domainsId, imageToDestinationDomainMap.values())) {
                    return failValidation(EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_NOT_FOUND_ON_DESTINATION_DOMAIN);
                }
            }
            return retValue;
    }
    
    • 模板锁验证。
    if (!VmTemplateHandler.BLANK_VM_TEMPLATE_ID.equals(getVm().getVmtGuid())
                    && getVmTemplate() != null
                    && getVmTemplate().getStatus() == VmTemplateStatus.Locked) {
                return failValidation(EngineMessage.VM_TEMPLATE_IMAGE_IS_LOCKED);
    }
    
    • 缺失导出域中模板。
    if (getParameters().getCopyCollapse() && !isTemplateExistsOnExportDomain()) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_IMPORTED_TEMPLATE_IS_MISSING,
                        String.format("$DomainName %1$s",
                                storageDomainStaticDao.get(getParameters().getSourceDomainId()).getStorageName()));
    }
    

    19.9.4 镜像验证

    • 虚拟机镜像是否存在。
    protected boolean checkImagesGUIDsLegal() {
            for (DiskImage image : new ArrayList<>(getImages())) {
                Guid imageGUID = image.getImageId();
                Guid storagePoolId = image.getStoragePoolId() != null ? image.getStoragePoolId()
                        : Guid.Empty;
                Guid storageDomainId = getSourceDomainId(image);
                Guid imageGroupId = image.getId() != null ? image.getId() : Guid.Empty;
    
                VDSReturnValue retValue = runVdsCommand(
                        VDSCommandType.GetImageInfo,
                        new GetImageInfoVDSCommandParameters(storagePoolId, storageDomainId, imageGroupId,
                                imageGUID));
    
                if (!retValue.getSucceeded()) {
                    if (!getParameters().isAllowPartialImport()) {
                        return failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_IMAGE_DOES_NOT_EXIST);
                    }
                    log.warn("Disk image '{}/{}' doesn't exist on storage domain '{}'. Ignoring since force flag in on",
                            imageGroupId,
                            imageGUID,
                            storageDomainId);
                    getVm().getImages().remove(image);
                    failedDisksToImportForAuditLog.putIfAbsent(image.getId(), image.getDiskAlias());
                }
            }
            return true;
    }
    

    19.9.5 虚拟机名称验证

    • 虚拟机名称重复。
    protected boolean validateUniqueVmName() {
            return vmHandler.isVmWithSameNameExistStatic(getVm().getName(), getStoragePoolId()) ?
                    failValidation(EngineMessage.VM_CANNOT_IMPORT_VM_NAME_EXISTS)
                    : true;
    }
    

    19.9.6 Lun 磁盘验证

    if (!validateLunDisksForVm(vmFromParams)) {
          return false;
    }
    

    19.9.7 磁盘配置与存储域类型兼容验证

    • 与 17.2 磁盘配置与存储域类型兼容验证一致。

    19.9.8 虚拟机架构验证

    protected boolean validateVmArchitecture () {
            return getVm().getClusterArch() == ArchitectureType.undefined ?
                failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_CANNOT_IMPORT_VM_WITH_NOT_SUPPORTED_ARCHITECTURE)
                : true;
    }
    

    19.9.9 群集验证

    • 群集是否存在。
    • 群集是否支持虚拟机架构。
    protected boolean validateVdsCluster() {
            Cluster cluster = clusterDao.get(getClusterId());
            return cluster == null ?
                    failValidation(EngineMessage.VDS_CLUSTER_IS_NOT_VALID)
                    : cluster.getArchitecture() != getVm().getClusterArch() ?
                            failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_CANNOT_IMPORT_VM_ARCHITECTURE_NOT_SUPPORTED_BY_CLUSTER)
                            : true;
    }
    

    19.9.10 目的域空间验证

    protected boolean handleDestStorageDomains() {
            List<DiskImage> dummiesDisksList = createDiskDummiesForSpaceValidations(imageList);
            if (getParameters().getCopyCollapse()) {
                Snapshot activeSnapshot = getActiveSnapshot();
                if (activeSnapshot != null && activeSnapshot.containsMemory()) {
                    // Checking space for memory volume of the active image (if there is one)
                    StorageDomain storageDomain = findDomainForMemoryImagesAndCreateDummies(dummiesDisksList);
                    if (storageDomain == null) {
                        return failValidation(EngineMessage.ACTION_TYPE_FAILED_NO_SUITABLE_DOMAIN_FOUND);
                    }
                }
            } else { // Check space for all the snapshot's memory volumes
                if (!determineDomainsForMemoryImagesAndCreateDummies(dummiesDisksList)) {
                    return false;
                }
            }
            return validate(getImportValidator().validateSpaceRequirements(dummiesDisksList));
    }
    

    19.9.11 图形显示验证

    protected boolean validateGraphicsAndDisplay() {
            return validate(vmHandler.isGraphicsAndDisplaySupported(getParameters().getVm().getOs(),
                    getGraphicsTypesForVm(),
                    getVm().getDefaultDisplayType(),
                    getEffectiveCompatibilityVersion()));
    }
    

    19.9.12 磁盘配置集设置验证

    • 与 16.6 磁盘配置集设置验证一致。

    19.9.13 CPU 配置集设置验证

    • 与 16.7 CPU 配置集设置验证一致。

    19.9.14 MAC 地址格式验证

    if (!getParameters().isImportAsNewEntity()) {
                List<VmNetworkInterface> vmNetworkInterfaces = getVm().getInterfaces();
                if (!validate(vmNicMacsUtils.validateThereIsEnoughOfFreeMacs(vmNetworkInterfaces,
                        getMacPool(),
                        getVnicRequiresNewMacPredicate()))) {
                    return false;
                }
    
                if (!validate(vmNicMacsUtils.validateMacAddress(vmNetworkInterfaces))) {
                    return false;
                }
    }
    

    20 导出模板

    • 导出模板使用了 ImportVmTemplateCommand 类。
    • 验证实现为 validate 方法。

    20.1 模板是否存在验证

    if (getVmTemplate() == null) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_DOES_NOT_EXIST);
    }
    

    20.2 存储域验证

    • 存储域存在并且激活状态。
    StorageDomainValidator storageDomainValidator = new StorageDomainValidator(getStorageDomain());
    if (!validate(storageDomainValidator.isDomainExistAndActive())) {
           return false;
    }
    
    • 存储域磁盘空间验证。
    sdValidator.isDomainWithinThresholds()
    
    • 存储域已经包含了目标磁盘。
    checkIfDisksExist(getTemplateDisks()))
    
    • 目的域空间是否足够。
    validateFreeSpaceOnDestinationDomain(sdValidator, getTemplateDisks())
    
    • 指定的域不是一个导出域。
    if (getStorageDomain().getStorageDomainType() != StorageDomainType.ImportExport) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_SPECIFY_DOMAIN_IS_NOT_EXPORT_DOMAIN);
    }
    

    20.3 镜像验证

    • 镜像是否存在。
    • 镜像是否加锁。
    • 镜像是否损坏。
    vmTemplateHandler.isVmTemplateImagesReady(getVmTemplate(), null, true, true, true, false, getTemplateDisks()))
    

    20.4 模板验证

    • 目标域中未包含该模板。
    if (storagePoolIsoMapDao.get(new StoragePoolIsoMapId(getStorageDomain().getId(),
                                getVmTemplate().getStoragePoolId())) == null) {
                    return failValidation(EngineMessage.ACTION_TYPE_FAILED_STORAGE_POOL_NOT_MATCH);
    }
    
    • 目标域中模板名称重复。
    if (!getParameters().getForceOverride()) {
                if (ExportVmCommand.checkTemplateInStorageDomain(getVmTemplate().getStoragePoolId(),
                        getParameters().getStorageDomainId(), getVmTemplateId(), getContext().getEngineContext())) {
                    return failValidation(EngineMessage.ACTION_TYPE_FAILED_NAME_ALREADY_USED);
                }
    }
    

    21 导入模板

    • 导入模板使用了 ImportVmTemplateCommand 类。
    • 验证实现为 validate 方法。

    21.1 模板是否存在验证

    if (getVmTemplate() == null) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_DOES_NOT_EXIST);
    }
    

    21.2 群集验证

    • 群集是否存在验证。
    if (getCluster() == null) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_CLUSTER_CAN_NOT_BE_EMPTY);
    }
    
    • 群集 ID 是否存在验证。
    if (!getCluster().getStoragePoolId().equals(getStoragePoolId())) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_CLUSTER_IS_NOT_VALID);
    }
    

    21.3 数据中心验证

    • 数据中心存在并且激活状态。
    createStoragePoolValidator().existsAndUp()
    

    21.4 模板架构验证

    • 模板架构验证。
    protected boolean validateTemplateArchitecture () {
            if (getVmTemplate().getClusterArch() == ArchitectureType.undefined) {
                addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_VM_CANNOT_IMPORT_TEMPLATE_WITH_NOT_SUPPORTED_ARCHITECTURE);
                return false;
            }
            return true;
    }
    
    • 群集是否支持该模板架构验证。
    protected boolean isClusterCompatible () {
            if (getCluster().getArchitecture() != getVmTemplate().getClusterArch()) {
                addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_VM_CANNOT_IMPORT_TEMPLATE_ARCHITECTURE_NOT_SUPPORTED_BY_CLUSTER);
                return false;
            }
            return true;
    }
    

    21.5 源存储域验证

    setSourceDomainId(getParameters().getSourceDomainId());
    if (!validateSourceStorageDomain()) {
            return false;
    }
    

    21.6 模板验证

    • 模板名称重复。
    if (getVmTemplate().isBaseTemplate() && isVmTemplateWithSameNameExist()) {
                return failValidation(EngineMessage.VM_CANNOT_IMPORT_TEMPLATE_NAME_EXISTS);
    }
    
    • 模板 ID 重复。
    VmTemplate duplicateTemplate = vmTemplateDao.get(getParameters().getVmTemplate().getId());
            // check that the template does not exists in the target domain
            if (duplicateTemplate != null) {
                return failValidation(EngineMessage.VMT_CANNOT_IMPORT_TEMPLATE_EXISTS,
                        String.format("$TemplateName %1$s", duplicateTemplate.getName()));
    }
    

    21.7 磁盘空间验证

    if (!validateNoDuplicateDiskImages(getImages())) {
           return false;
    }
    

    21.8 存储域空间验证

    if (getImages() != null && !getImages().isEmpty() && !getParameters().isImagesExistOnTargetStorageDomain()) {
                if (!validateSpaceRequirements(getImages())) {
                    return false;
                }
    }
    

    21.9 MAC 地址格式验证

    List<VmNetworkInterface> vmNetworkInterfaces = getVmTemplate().getInterfaces();
    vmNicMacsUtils.replaceInvalidEmptyStringMacAddressesWithNull(vmNetworkInterfaces);
    if (!validate(vmNicMacsUtils.validateMacAddress(vmNetworkInterfaces))) {
                return false;
    }
    

    21.10 基础模板验证

    • 缺失模板的基础模板。
    if (!getVmTemplate().isBaseTemplate()) {
                VmTemplate baseTemplate = vmTemplateDao.get(getVmTemplate().getBaseTemplateId());
                if (baseTemplate == null) {
                    return failValidation(EngineMessage.VMT_CANNOT_IMPORT_TEMPLATE_VERSION_MISSING_BASE);
                }
    }
    

    21.11 磁盘配置集设置验证

    • 与 16.6 磁盘配置集设置验证一致。

    21.12 CPU 配置集设置验证

    • 与 16.7 CPU 配置集设置验证一致。

    21.13 内存验证

    • 与 16.11 内存验证一致。

    21.14 cloud-init 配置验证

    • 与 19.4 cloud-init 配置验证一致。

    相关文章

      网友评论

        本文标题:【Ovirt 笔记】虚拟机相关业务验证分析与整理(2)

        本文链接:https://www.haomeiwen.com/subject/blhgaftx.html