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

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

作者: 58bc06151329 | 来源:发表于2018-10-12 15:56 被阅读10次

    文前说明

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

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

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

    • engine 中的业务执行大部分都是通过 GWT-RPC 执行后端 Command 命令实现的。
      • 通过 Backend 提供的 runInternalActionrunMultipleActions 等方法执行。
      • 例如运行虚拟机为 RunVmCommand、删除虚拟机为 RemoveVmCommand 等。
    • 执行每一个 Command 命令前,都会对执行命令的前置条件进行验证操作。
      • 3.4 中为 canDoAction
      • 4.2 中为 validate
    • 不同的 Command 的验证方法有不同的实现(多态)。
    // CommandBase.java
    protected boolean validate() {
         return true;
    }
    

    1. 运行虚拟机

    • 运行虚拟机使用了 RunVmCommand 类。
    • 验证实现为 validateImpl 方法。

    1.1 虚拟机为空验证

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

    1.2 虚拟机对象的属性验证

    • 使用了 validation beanHibernate Validator
      • validation bean 是基于JSR-303 标准开发出来的,使用注解方式实现。但是这只是一个接口,没有具体实现。
      • Hibernate Validator 是一个 hibernate 独立的包,可以直接引用,实现了接口同时又做了一些扩展。
    <module name="javax.validation.api"/>
    
    <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-validator</artifactId>
    </dependency>
    
    • javax.validation.constraints 包中包含了验证的注解。
    序号 注解 说明 可修饰对象
    1 @Null 被注解的元素必须为 Null。 任意类型。
    2 @NotNull 被注解的元素不能为 Null。 任意类型。
    3 @AssertTrue 被注解的元素必须为 True。 Boolean、boolean
    4 @AssertFalse 被注解的元素必须为 False。 Boolean、boolean
    5 @Min(value) 被注解的元素必须是一个数字,并且大于等于被指定的值(value)。 BigDecimal、BigInteger、byte、short、int、long 等任何 Number 或CharSequence(存储的是数字)子类型。
    6 @Max(value) 被注解的元素必须是一个数字,并且小于等于被指定的值(value)。 与 @Min 一致。
    7 @DecimalMin(value) 被注解的元素必须是一个数字,并且大于等于被指定的值(value)。 与 @Min 一致。
    8 @DecimalMax(value) 被注解的元素必须是一个数字,并且小于等于被指定的值(value)。 与 @Min 一致。
    9 @Size(max,min) 被注解的元素必须是一个数字,并且在指定范围内。 字符串、Collection、Map、数组等。
    10 @Digits(integer,fraction) 被注解的元素的整数位和小数位限制。 与 @Min 一致。
    11 @Past 被注解的元素(日期类型)比当前时间早。 java.util.Date、java.util.Calendar、Joda Time 类库的日期类型。
    12 @Future 被注解的元素(日期类型)比当前时间晚。 与 @Past 一致。
    13 @Pattern(regexp) 被注解的元素必须符合正则表达式。 String、任何 CharSequence 的子类型。
    • 针对 @Pattern 注解,可以设置 flag 标识不同的模式。
    模式 说明
    UNIX_LINES 只有 " \n " 才被认作一行的中止,并且与 " . "、" ^ " 以及 " $ " 进行匹配。
    CASE_INSENSITIVE 表达式忽略大小写进行匹配。
    COMMENTS 匹配时会忽略(正则表达式里的)空格字符(不是指表达式里的 " \s ",而是指表达式里的空格,tab,回车之类)。
    DOTALL 表达式 " . " 可以匹配任意字符,包括表示一行的结束符。默认情况下,表达式 " . " 不匹配行的结束符。
    MULTILINE " ^ " 和 " " 分别匹配一行的开始和结束。此外," ^ " 仍然匹配字符串的开始," " 也匹配字符串的结束。默认情况下,这两个表达式仅仅匹配字符串的开始和结束。
    UNICODE_CASE 如果还启用了 CASE_INSENSITIVE 模式,那么会对 Unicode 字符进行大小写不明感的匹配。默认大小写不敏感的匹配只适用于 US-ASCII 字符集。
    • Hibernate validator 在 JSR-303 的基础上对校验注解进行了扩展。
    序号 注解 说明 可修饰对象
    1 @Email(regexp) 注解的元素是 Email,也可以通过 regexp 和 flag 指定自定义的 email 格式。 CharSequence子类型(如 String)。
    2 @Length(min,max) 注解的元素长度在 min 和 max 区间内。 CharSequence 子类型。
    3 @NotEmpty 注解的元素不为 Null 且不为空、字符串长度不能为 0、集合大小不能为 0) CharSequence 子类型、Collection、Map、数组。
    4 @Range(min,max) 注解的元素在最小值和最大值之间 BigDecimal、BigInteger、CharSequence、byte、short、int、 long 等原子类型和包装类型。
    • 自定义注解
    @Target({ ANNOTATION_TYPE, METHOD, FIELD, CONSTRUCTOR, PARAMETER })
    @Retention(RetentionPolicy.RUNTIME)
    @Pattern(regexp = ValidationUtils.NO_SPECIAL_CHARACTERS_I18N)
    @Constraint(validatedBy = {})
    @ReportAsSingleViolation
    public @interface ValidI18NName {
        String message() default "VALIDATION_FIELD_CONTAINS_SPECIAL_CHARACTERS";
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    }
    
    • 属性验证
    if (!validateObject(vm.getStaticData())) {
          return false;
    }
    
    序号 属性 说明
    1 validatedBy 指定验证规则的实现类。
    2 message 自定义验证未通过的错误信息。
    3 groups 自定义组(用于不同业务场景的验证分组)。如 CreateEntity 和 UpdateEntity 分别为创建和修改时的验证。

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

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

    1.4 虚拟机版本验证

    if (getVm().getCustomCompatibilityVersion() != null && vm.getCustomCompatibilityVersion().less(getStoragePool().getCompatibilityVersion())) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_COMATIBILITY_VERSION_NOT_SUPPORTED,
                        String.format("$VmName %1$s", getVm().getName()),
                        String.format("$VmVersion %1$s", getVm().getCustomCompatibilityVersion().toString()),
                        String.format("$DcVersion %1$s", getStoragePool().getCompatibilityVersion()));
    }
    

    1.5 虚拟机可运行验证

    1.5.1 普通运行验证

    1.5.1.1 虚拟机自定义属性验证

    • 自定义属性从 PredefinedVMPropertiesUserDefinedVMProperties 获取。
    validateVmProperties(vm, messages)
    

    1.5.1.2 引导序列的驱动验证

    • 验证硬盘启动,硬盘是否为空。
    • 验证网卡启动,是否设置了虚拟机网络。
    validateBootSequence(vm, getVmDisks())
    

    1.5.1.3 系统图形显示支持验证

    private ValidationResult validateDisplayType() {
            if (!vmValidationUtils.isGraphicsAndDisplaySupported(vm.getOs(),
                    vm.getCompatibilityVersion(),
                    getVmActiveGraphics(),
                    vm.getDefaultDisplayType())) {
                    return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_ILLEGAL_VM_DISPLAY_TYPE_IS_NOT_SUPPORTED_BY_OS);
            }
    
            return ValidationResult.VALID;
    }
    

    1.5.1.4 虚拟机锁验证

    • 虚拟机对象是否被资源加锁。
    new VmValidator(vm).vmNotLocked()
    

    1.5.1.5 虚拟机快照锁验证。

    snapshotsValidator.vmNotDuringSnapshot(vm.getId())
    

    1.5.1.6 虚拟机状态验证

    • 验证虚拟机现阶段状态是否为可以运行的状态。
    private ValidationResult validateVmStatusUsingMatrix(VM vm) {
            if (!ActionUtils.canExecute(Collections.singletonList(vm), VM.class,
                    ActionType.RunVm)) {
                return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_VM_STATUS_ILLEGAL, LocalizedVmStatus.from(vm.getStatus()));
            }
    
            return ValidationResult.VALID;
    }
    

    1.5.1.7 数据中心状态验证

    • 直接验证通过
      • 虚拟机没有磁盘。
      • 虚拟机设置为高可用。
    • 验证数据中心状态是否为启用状态。
    validateStoragePoolUp(vm, storagePool, getVmImageDisks())
    

    1.5.1.8 ISO 与软盘文件路径验证

    validateIsoPath(vm, runVmParam.getDiskPath(), runVmParam.getFloppyPath(), activeIsoDomainId)
    

    1.5.1.9 虚拟机是否正在启动验证

    • 验证是否包含在虚拟机运行列表中。
    vmDuringInitialization(vm)
    
    Set<Guid> asyncRunningVms = Collections.newSetFromMap(new ConcurrentHashMap<>());
    

    1.5.1.10 虚拟机无状态验证

    • 如果虚拟机不是无状态的,则直接通过验证。
    • 无状态虚拟机不能设置高可用。
    • 无状态虚拟机必须有足够的空间创建快照。
    validateStatelessVm(vm, runVmParam.getRunAsStateless())
    

    1.5.1.11 软盘设备系统支持验证

    private ValidationResult validateFloppy() {
    
            if (StringUtils.isNotEmpty(runVmParam.getFloppyPath())
                    && !vmValidationUtils.isFloppySupported(vm.getOs(), vm.getCompatibilityVersion())) {
                return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_ILLEGAL_FLOPPY_IS_NOT_SUPPORTED_BY_OS);
            }
    
            return ValidationResult.VALID;
    }
    

    1.5.1.12 存储域验证

    • 是否存在激活状态的存储域。
    • 存储域空间是否低于最小要求。
    validateStorageDomains(vm, isInternalExecution, filterReadOnlyAndPreallocatedDisks(getVmImageDisks()))
    

    1.5.1.13 虚拟机磁盘镜像锁验证

    private ValidationResult validateImagesForRunVm(VM vm, List<DiskImage> vmDisks) {
            if (vmDisks.isEmpty()) {
                return ValidationResult.VALID;
            }
    
            return !vm.isAutoStartup() ?
                    new DiskImagesValidator(vmDisks).diskImagesNotLocked() : ValidationResult.VALID;
    }
    

    1.5.1.14 磁盘擦除功能支持验证

    • 只有 VirtIO-SCSI 和 IDE 磁盘接口支持。
    validateDisksPassDiscard(vm)
    

    1.5.1.15 虚拟机内存验证

    • 内存大小不能超过集群版本所支持的最大内存。
    protected ValidationResult validateMemorySize(VM vm) {
            int maxSize = VmCommonUtils.maxMemorySizeWithHotplugInMb(vm);
            if (vm.getMemSizeMb() > maxSize) {
                return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_MEMORY_EXCEEDS_SUPPORTED_LIMIT);
            }
            return ValidationResult.VALID;
    }
    

    1.5.1.16 可运行的主机验证

    • 根据群集策略选择可运行主机,没有则给出错误提示。
    !getSchedulingManager().canSchedule(cluster, vm, vdsBlackList, vdsWhiteList, messages).isEmpty()
    

    1.5.2 暂停后运行

    • 暂停后运行只需要验证主机状态。
      • 主机必须为启动状态。
    private ValidationResult validateVdsStatus(VM vm) {
            if (vm.getStatus() == VMStatus.Paused && vm.getRunOnVds() != null &&
                    getVdsDynamic(vm.getRunOnVds()).getStatus() != VDSStatus.Up) {
                return new ValidationResult(
                        EngineMessage.ACTION_TYPE_FAILED_VDS_STATUS_ILLEGAL,
                        EngineMessage.VAR__HOST_STATUS__UP.toString());
            }
    
            return ValidationResult.VALID;
    }
    

    1.5.3 挂起后运行

    • 挂起后运行与普通运行的验证基本一致。
      • 不执行虚拟机自定义属性验证。
      • 不执行引导序列的驱动验证。
      • 不执行系统图形显示支持验证。
      • 不执行 ISO 与软盘文件路径验证。
      • 不执行虚拟机无状态验证。
      • 不执行软盘设备系统支持验证。
      • 不执行虚拟机内存验证。

    1.6 虚拟机网络验证

    • 验证配置的虚拟网络是否属于所在群集。
    • 配置的网络必须为存在的虚拟网络。
    if (!validate(runVmValidator.validateNetworkInterfaces())) {
         return false;
    }
    

    1.7 虚拟机租赁验证

    • 虚拟机租赁的目标存储域状态必须存在并激活。
    • 选择了租赁目标存储域,则必须包含租赁信息。
    public ValidationResult validateVmLease() {
            if (vm.getLeaseStorageDomainId() == null) {
                return ValidationResult.VALID;
            }
    
            if (vm.getLeaseInfo() == null) {
                return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_INVALID_VM_LEASE);
            }
            StorageDomain leaseStorageDomain =
                    storageDomainDao.getForStoragePool(vm.getLeaseStorageDomainId(), vm.getStoragePoolId());
            StorageDomainValidator storageDomainValidator = new StorageDomainValidator(leaseStorageDomain);
            ValidationResult validationResult = storageDomainValidator.isDomainExistAndActive();
            if (!validationResult.isValid()) {
                return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_INVALID_VM_LEASE_STORAGE_DOMAIN_STATUS,
                        String.format("$LeaseStorageDomainName %1$s", leaseStorageDomain.getName()));
            }
    
            return ValidationResult.VALID;
    }
    

    1.8 随机数生成器支持验证

    • 所在集群是否支持随机数生成器。
    if (!checkRngDeviceClusterCompatibility()) {
            return failValidation(EngineMessage.ACTION_TYPE_FAILED_RNG_SOURCE_NOT_SUPPORTED);
    }
    

    1.9 备份存储验证

    • 正在运行的虚拟机不能包括存储在备份存储域中的磁盘。
    protected ValidationResult checkDisksInBackupStorage() {
            return new MultipleStorageDomainsValidator(getVm().getStoragePoolId(),
                    Stream.concat(getVm().getDiskMap()
                            .values()
                            .stream()
                            .filter(DisksFilter.ONLY_PLUGGED)
                            .filter(DisksFilter.ONLY_IMAGES)
                            .map(DiskImage.class::cast)
                            .flatMap(vmDisk -> vmDisk.getStorageIds().stream()),
                            Stream.of(getVm().getLeaseStorageDomainId()).filter(Objects::nonNull))
                    .collect(Collectors.toSet()))
                    .allDomainsNotBackupDomains();
    }
    

    1.10 Cloud-init 功能验证

    • CD-ROM Payload 或 Cloud-init 使用时,使用 ISE 或 sPAPR VSCSI 总线的数量有个数限制。
    类型 限制数量
    X86_64 3
    PPC64 7
    S390X 4 * 65536

    1.11 CPU 类型支持验证

    • 虚拟机操作系统是否支持设置的 CPU 类型。
    if (!validate(vmHandler.isCpuSupported(
                    getVm().getVmOsId(),
                    getVm().getCompatibilityVersion(),
                    getCluster().getCpuName()))) {
                return false;
    }
    

    1.12 运行虚拟机的主机设备验证

    try {
                acquireHostDevicesLock();
                if (!checkRequiredHostDevicesAvailability()) {
                    return failValidation(EngineMessage.ACTION_TYPE_FAILED_HOST_DEVICE_NOT_AVAILABLE);
                }
    } finally {
                releaseHostDevicesLock();
    }
    

    1.13 虚拟机 USB 设备验证

    • 未管理的 USB 控制器不能超过一个。
    if (!validate(runVmValidator.validateUsbDevices(getVm().getStaticData()))) {
          return false;
    }
    

    2. 删除虚拟机

    • 删除虚拟机使用了 RemoveVmCommand 类。
    • 验证实现为 validate 方法。

    2.1 虚拟机为空验证

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

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

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

    2.3 删除保护限制

    if (getVm().isDeleteProtected()) {
           return failValidation(EngineMessage.ACTION_TYPE_FAILED_DELETE_PROTECTION_ENABLED);
    }
    

    2.4 磁盘分离验证

    • 基于模板创建的虚拟机,不能取消 " 删除磁盘 " 选项。
    • 有创建快照的虚拟机,不能取消 " 删除磁盘 " 选项。
    if (!getParameters().isRemoveDisks() && !canRemoveVmWithDetachDisks()) {
          return false;
    }
    

    2.5 虚拟机状态验证

    • 挂起的虚拟机不能删除。
    • 内部 HostedEngine 虚拟机不能删除。
    • 运行相关状态的虚拟机不能删除。
    return (getVm().isHostedEngine() && isInternalExecution()) || failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_IS_RUNNING);
    

    2.6 池虚拟机验证

    • 池中虚拟机不能删除。
    if (getVm().getVmPoolId() != null) {
          return failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_ATTACHED_TO_POOL);
    }
    

    2.7 虚拟机快照锁验证

    if (!validate(snapshotsValidator.vmNotDuringSnapshot(getVmId()))) {
           return false;
    }
    

    2.8 数据中心中虚拟机验证

    • 运行的数据中心中运行的虚拟机不能删除。
    Collection<Disk> vmDisks = getVm().getDiskMap().values();
    List<DiskImage> vmImages = DisksFilter.filterImageDisks(vmDisks, ONLY_NOT_SHAREABLE, ONLY_ACTIVE);
    if (!vmImages.isEmpty() && !validate(new StoragePoolValidator(getStoragePool()).existsAndUp())) {
         return false;
    }
    

    2.9 存储域验证

    • 所在存储域不是运行状态不能删除虚拟机。
    • 未强制删除且磁盘加锁的虚拟机不能删除。
    vmImages.addAll(DisksFilter.filterCinderDisks(vmDisks));
            if (!vmImages.isEmpty()) {
                Set<Guid> storageIds = ImagesHandler.getAllStorageIdsForImageIds(vmImages);
                MultipleStorageDomainsValidator storageValidator = new MultipleStorageDomainsValidator(getVm().getStoragePoolId(), storageIds);
                if (!validate(storageValidator.allDomainsExistAndActive())) {
                    return false;
                }
    
                DiskImagesValidator diskImagesValidator = new DiskImagesValidator(vmImages);
                if (!getParameters().getForce() && !validate(diskImagesValidator.diskImagesNotLocked())) {
                    return false;
                }
    }
    

    2.10 虚拟机租赁验证

    • 虚拟机租赁的目标存储域状态必须存在并激活。
    if (getVm().getLeaseStorageDomainId() != null) {
                StorageDomain leaseStorageDomain =
                        storageDomainDao.getForStoragePool(getVm().getLeaseStorageDomainId(), getVm().getStoragePoolId());
                StorageDomainValidator storageDomainValidator = new StorageDomainValidator(leaseStorageDomain);
                if (!validate(storageDomainValidator.isDomainExistAndActive())) {
                    return failValidation(EngineMessage.ACTION_TYPE_FAILED_INVALID_VM_LEASE_STORAGE_DOMAIN_STATUS,
                            String.format("$LeaseStorageDomainName %1$s", leaseStorageDomain.getName()));
                }
    }
    

    2.11 镜像锁定虚拟机验证

    • 未设置强制删除虚拟机不能删除。
    • 当有任务运行时,不能强制删除虚拟机。
    VmValidator vmValidator = new VmValidator(getVm());
            ValidationResult vmLockedValidatorResult = vmValidator.vmNotLocked();
            if (!vmLockedValidatorResult.isValid()) {
                // without force remove, we can't remove the VM
                if (!getParameters().getForce()) {
                    return failValidation(vmLockedValidatorResult.getMessages());
                }
    
                // If it is force, we cannot remove if there are task
                if (commandCoordinatorUtil.hasTasksByStoragePoolId(getVm().getStoragePoolId())) {
                    return failValidation(EngineMessage.VM_CANNOT_REMOVE_HAS_RUNNING_TASKS);
                }
    }
    

    2.12 勾选 " 删除磁盘 " 选项验证

    • 需要删除的磁盘不能附加到其他的虚拟机上。
    if (getParameters().isRemoveDisks() && !validate(vmValidator.vmNotHavingDeviceSnapshotsAttachedToOtherVms(false))) {
                return false;
    }
    

    3 关闭虚拟机

    • 关闭虚拟机使用了 StopVmCommandBase 类。
    • 验证实现为 validate 方法。

    3.1 虚拟机状态验证

    • 虚拟机状态为关机状态直接验证通过。
    if (shouldSkipCommandExecutionCached()) {
           return true;
    }
    
    • 处于 saving/restoring 状态虚拟机不能关机。
    • 不是运行相关状态的虚拟机不能关机。
    if (!getVm().isRunning() && getVm().getStatus() != VMStatus.Paused
                    && getVm().getStatus() != VMStatus.NotResponding && getVm().getStatus() != VMStatus.Suspended) {
                return failValidation(
                        (getVm().getStatus().isHibernating() || getVm().getStatus() == VMStatus.RestoringState) ?
                                EngineMessage.ACTION_TYPE_FAILED_VM_IS_SAVING_RESTORING
                                : EngineMessage.ACTION_TYPE_FAILED_VM_IS_NOT_RUNNING);
    }
    

    3.2 虚拟机为空验证

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

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

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

    4 暂停虚拟机

    • 暂停虚拟机使用了 PauseVmCommand 类。
    • 验证实现为 validate 方法。

    4.1 虚拟机为空验证

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

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

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

    4.3 虚拟机状态验证

    • 虚拟机 WaitForLaunch、MigratingFrom、NotResponding 状态不能暂停。
    if (retValue && (vm.getStatus() == VMStatus.WaitForLaunch || vm.getStatus() == VMStatus.MigratingFrom || vm.getStatus() == VMStatus.NotResponding)) {
          retValue = failVmStatusIllegal();
    
    • 非运行状态不能暂停。
    ......
    else if (!vm.isRunning()) {
                    retValue = false;
                    addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_VM_IS_NOT_RUNNING);
    }
    

    5 重启虚拟机

    • 重启虚拟机使用了 RebootVmCommand 类。
    • 验证实现为 validate 方法。

    5.1 虚拟机为空验证

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

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

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

    5.3 虚拟机状态验证

    • 非关机和正在关机状态不能重启。
    if (getVm().getStatus() != VMStatus.Up && getVm().getStatus() != VMStatus.PoweringUp) {
          return failVmStatusIllegal();
    }
    

    6 创建虚拟机

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

    6.1 相关资源对象验证

    • 群集为空验证。
    if (getCluster() == null) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_CLUSTER_CAN_NOT_BE_EMPTY);
    }
    
    • 模板为空验证。
    if (getVmTemplate() == null) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_DOES_NOT_EXIST);
    }
    
    • 模板禁用验证。
      • 创建虚拟机模板不能处于禁用状态。
    if (getVmTemplate().isDisabled()) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_IS_DISABLED);
    }
    
    • 数据中心存在验证。
    StoragePoolValidator spValidator = new StoragePoolValidator(getStoragePool());
    if (!validate(spValidator.exists())) {
          return false;
    }
    
    • 创建内部虚拟机,数据中心必须处于运行状态。
    if (!isExternalVM() && !validate(spValidator.isInStatus(StoragePoolStatus.Up))) {
          return false;
    }
    
    • 虚拟机模板必须属于当前所在数据中心。
    if (!isTemplateInValidDc()) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_NOT_EXISTS_IN_CURRENT_DC);
    }
    
    • 虚拟机名称为空验证。
    if (StringUtils.isEmpty(vmFromParams.getName())) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_NAME_MAY_NOT_BE_EMPTY);
    }
    
    • 虚拟机名称长度验证。
      • MaxVmNameLength 定义了虚拟机名称最大长度(默认为 64)
    if (!isVmNameValidLength(vmFromParams)) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_NAME_LENGTH_IS_TOO_LONG);
    }
    

    6.2 磁盘格式验证

    • Thin provisioned 模板磁盘不能被定义为 Raw。
    protected boolean isDisksVolumeFormatValid() {
            if (diskInfoDestinationMap.values().stream()
                    .anyMatch(d -> d.getDiskStorageType() != DiskStorageType.CINDER &&
                            d.getVolumeFormat() != VolumeFormat.COW)) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_THIN_TEMPLATE_DISKS_SHOULD_ONLY_BE_COW);
            }
            return true;
    }
    

    6.3 自定义兼容版本支持验证

    • 支持群集版本。
    Version customCompatibilityVersionFromParams = getParameters().getVmStaticData().getCustomCompatibilityVersion();
            if (customCompatibilityVersionFromParams != null && !isCompatibilityVersionSupportedByCluster(customCompatibilityVersionFromParams)) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_CUSTOM_COMPATIBILITY_VERSION_NOT_SUPPORTED,
            String.format("$Ccv %s", customCompatibilityVersionFromParams));
    }
    

    6.4 群集架构支持验证

    • 群集不具有定义的架构。
    if (getCluster().getArchitecture() == ArchitectureType.undefined) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_CLUSTER_UNDEFINED_ARCHITECTURE);
    }
    
    • 所选的模板和集群架构不兼容。
    if (!getVmTemplate().getId().equals(VmTemplateHandler.BLANK_VM_TEMPLATE_ID) && getCluster().getArchitecture() != getVmTemplate().getClusterArch()) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_IS_INCOMPATIBLE);
    }
    
    • 群集架构支持内存气球验证
    if (isBalloonEnabled() && !osRepository.isBalloonEnabled(getParameters().getVmStaticData().getOsId(),
                    getEffectiveCompatibilityVersion())) {
                addValidationMessageVariable("clusterArch", getCluster().getArchitecture());
                return failValidation(EngineMessage.BALLOON_REQUESTED_ON_NOT_SUPPORTED_ARCH);
    }
    
    • 群集架构支持音频设备验证
    if (isSoundDeviceEnabled() && !osRepository.isSoundDeviceEnabled(getParameters().getVmStaticData().getOsId(),
                    getEffectiveCompatibilityVersion())) {
                addValidationMessageVariable("clusterArch", getCluster().getArchitecture());
                return failValidation(EngineMessage.SOUND_DEVICE_REQUESTED_ON_NOT_SUPPORTED_ARCH);
    }
    
    • 群集架构支持操作系统验证
    if (!validate(vmHandler.isOsTypeSupported(vmFromParams.getOs(), getCluster().getArchitecture()))) {
                return false;
    }
    
    • 群集架构支持迁移验证
    if (!FeatureSupported.isMigrationSupported(getCluster().getArchitecture(), getEffectiveCompatibilityVersion())
                    && vmFromParams.getMigrationSupport() != MigrationSupport.PINNED_TO_HOST) {
                return failValidation(EngineMessage.VM_MIGRATION_IS_NOT_SUPPORTED);
    }
    

    6.5 兼容版本支持高性能虚拟机验证

    if (getParameters().getVmStaticData().getVmType() == VmType.HighPerformance
                    && !FeatureSupported.isHighPerformanceTypeSupported(getEffectiveCompatibilityVersion())) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_HIGH_PERFORMANCE_IS_NOT_SUPPORTED,
               String.format("$Version %s", getEffectiveCompatibilityVersion()));
    }
    

    6.6 配额验证

    if (!validateQuota(getParameters().getVmStaticData().getQuotaId())) {
          return false;
    }
    

    6.7 CPU Pinning 验证

    • 可迁移的虚拟机不能固定到 CPU。
    boolean validatePinningAndMigration() {
            final boolean cpuPinMigrationEnabled = Boolean.TRUE.equals(Config.<Boolean> getValue(ConfigValues.CpuPinMigrationEnabled));
            VmStatic vmStaticData = getParameters().getVmStaticData();
            if (!cpuPinMigrationEnabled
                    && (vmStaticData.getMigrationSupport() == MigrationSupport.MIGRATABLE
                    || vmStaticData.getMigrationSupport() == MigrationSupport.IMPLICITLY_NON_MIGRATABLE)
                    && StringUtils.isNotEmpty(getParameters().getVm().getCpuPinning())) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_CANNOT_BE_PINNED_TO_CPU_AND_MIGRATABLE);
            }
            return true;
    }
    
    • 带有主机 CPU 标记的虚拟机必须被固定到主机上。
    if (vmFromParams.isUseHostCpuFlags()
                    && vmFromParams.getMigrationSupport() != MigrationSupport.PINNED_TO_HOST) {
                return failValidation(EngineMessage.VM_HOSTCPU_MUST_BE_PINNED_TO_HOST);
    }
    
    • CPU 固定格式无效。
    • 未选择主机时无法设置主机 CPU 固定。
    • CPU 固定检验失败 - 虚拟机里不存在虚拟 CPU。
    • 无法在相同的 vCPU 上配置两次 CPU 固定。
    • 无法将 vCPU 固定到非 pCPU 上。
    if (!validate(isCpuPinningValid(vmFromParams.getCpuPinning(), vmFromParams.getStaticData()))) {
                return false;
    }
    
    • 带有主机 CPU 标记的虚拟机必须被固定到主机上。
    if (vmFromParams.isUseHostCpuFlags()
                    && vmFromParams.getMigrationSupport() != MigrationSupport.PINNED_TO_HOST) {
                return failValidation(EngineMessage.VM_HOSTCPU_MUST_BE_PINNED_TO_HOST);
    }
    
    • 架构不支持主机 CPU 透传。
    if (vmFromParams.isUseHostCpuFlags() && (ArchitectureType.ppc == getCluster().getArchitecture().getFamily())) {
                return failValidation(EngineMessage.USE_HOST_CPU_REQUESTED_ON_UNSUPPORTED_ARCH);
    }
    

    6.8 监控器数量验证

    图像类型 支持数量
    VNC <=1
    SPICE <=ValidNumOfMonitors(默认值为 4)
    protected boolean checkNumberOfMonitors() {
            if (getParameters().getVmStaticData().getDefaultDisplayType() == DisplayType.none) {
                return true;
            }
            Collection<GraphicsType> graphicsTypes = vmHandler.getResultingVmGraphics(
                    getVmDeviceUtils().getGraphicsTypesOfEntity(getVmTemplateId()),
                    getParameters().getGraphicsDevices());
            int numOfMonitors = getParameters().getVmStaticData().getNumOfMonitors();
            return validate(vmHandler.isNumOfMonitorsLegal(graphicsTypes, numOfMonitors));
    }
    

    6.9 显示设备验证

    • 不能通过 VNC 设置单个显示设备。
    • 不能在非 Linux 操作系统上设置单个显示设备。
    protected boolean checkSingleQxlDisplay() {
            if (!getParameters().getVmStaticData().getSingleQxlPci() || getParameters().getVmStaticData().getDefaultDisplayType() == DisplayType.none) {
                return true;
            }
            return validate(vmHandler.isSingleQxlDeviceLegal(getParameters().getVm().getDefaultDisplayType(), getParameters().getVm().getOs()));
    }
    

    6.10 PCI 和 IDE 数量支持验证

    validate(VmValidator.checkPciAndIdeLimit(getParameters().getVm().getOs(),
                            getEffectiveCompatibilityVersion(),
                            getParameters().getVmStaticData().getNumOfMonitors(),
                            getVmInterfaces(),
                            getDiskVmElements(),
                            isVirtioScsiEnabled(),
                            hasWatchdog(),
                            isBalloonEnabled(),
                            isSoundDeviceEnabled()))
    

    6.11 虚拟机名称重复验证

    if (isVmWithSameNameExists(name, storagePoolId)) {
          return failValidation(EngineMessage.ACTION_TYPE_FAILED_NAME_ALREADY_USED);
    }
    

    6.12 Mac 池地址范围验证

    if (!validate(vmHandler.verifyMacPool(getVmInterfaces().size(), getMacPool()))) {
         return false;
    }
    

    6.13 虚拟机优先级值范围验证

    • 优先级 >=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));
    }
    

    6.14 虚拟机模板使用验证

    protected boolean checkTemplateImages() {
            if (getParameters().getParentCommand() == ActionType.AddVmPool) {
                return true;
            }
    
            for (StorageDomain storage : destStorages.values()) {
                if (!validate(vmTemplateHandler.isVmTemplateImagesReady(vmDisksSource, storage.getId(),
                        false, false, true, true,
                        storageToDisksMap.get(storage.getId())))) {
                    return false;
                }
            }
            return true;
    }
    

    6.15 自定义属性验证

    if (!validateCustomProperties(vmStaticFromParams)) {
          return false;
    }
    

    6.16 存储域验证

    • 存储域必须所属同样的数据中心。
    • 数据中心至少有一个可用的存储域。
    • 存储域使用空间验证。
    if (!getStoragePoolId().equals(getStoragePoolIdFromSourceImageContainer())) {
                    return failValidation(EngineMessage.ACTION_TYPE_FAILED_STORAGE_POOL_NOT_MATCH);
    }
    for (StorageDomain domain : destStorages) {
                   StorageDomainValidator storageDomainValidator = new StorageDomainValidator(domain);
                   if (!validate(storageDomainValidator.isDomainExistAndActive())) {
                       return false;
                   }
    }
    ......
    protected boolean validateFreeSpace(StorageDomainValidator storageDomainValidator, List<DiskImage> disksList) {
            Collection<DiskImage> disks = ImagesHandler.getDisksDummiesForStorageAllocations(disksList);
            return validate(storageDomainValidator.hasSpaceForNewDisks(disks));
    }
    

    6.17 虚拟机 Payload 验证

    • 支持 Payload 的类型只有 CDROM 和 FLOPPY。
    • Payload 最大限制为 PayloadSize(默认值为 8192)
    if (getParameters().getVmPayload() != null) {
                if (!checkPayload(getParameters().getVmPayload())) {
                    return false;
                }
    
                // otherwise, we save the content in base64 string
                for (Map.Entry<String, String> entry : getParameters().getVmPayload().getFiles().entrySet()) {
                    entry.setValue(new String(BASE_64.encode(entry.getValue().getBytes()), StandardCharsets.UTF_8));
                }
    }
    

    6.18 虚拟机看门狗兼容性验证

    if (getParameters().getWatchdog() != null) {
                if (!validate(new VmWatchdogValidator(vmFromParams.getOs(),
                        getParameters().getWatchdog(),
                        getEffectiveCompatibilityVersion()).isValid())) {
                    return false;
                }
    }
    

    6.19 虚拟机 CPU 架构支持验证

    public ValidationResult isCpuSupported(int osId, Version version, String cpuName) {
            String cpuId = cpuFlagsManagerHandler.getCpuId(cpuName, version);
            if (cpuId == null) {
                return new ValidationResult(EngineMessage.CPU_TYPE_UNKNOWN);
            }
            if (!osRepository.isCpuSupported(
                    osId,
                    version,
                    cpuId)) {
                String unsupportedCpus = osRepository.getUnsupportedCpus(osId, version).toString();
                return new ValidationResult(EngineMessage.CPU_TYPE_UNSUPPORTED_FOR_THE_GUEST_OS,
                        "$unsupportedCpus " + StringUtils.strip(unsupportedCpus, "[]"));
            }
            return ValidationResult.VALID;
    }
    

    6.20 虚拟机图形显示支持验证

    if (!validate(vmHandler.isGraphicsAndDisplaySupported(getParameters().getVmStaticData().getOsId(),
                    vmHandler.getResultingVmGraphics(
                            getVmDeviceUtils().getGraphicsTypesOfEntity(getVmTemplateId()),
                            getParameters().getGraphicsDevices()),
                    vmFromParams.getDefaultDisplayType(),
                    getEffectiveCompatibilityVersion()))) {
                return false;
    }
    

    6.21 虚拟机智能卡支持验证

    • 高性能虚拟机类型禁用 USB 时,不支持启用智能卡设备。
    if (!validate(vmHandler.validateSmartCardDevice(getParameters().getVmStaticData()))) {
          return false;
    }
    

    6.22 内存验证

    • ppc 系统架构上,内存的大小需要是 256 的倍数。
    if (!validateMemoryAlignment(getParameters().getVmStaticData())) {
           return false;
    }
    

    6.23 实例类型为空验证

    if (getInstanceTypeId() != null && getInstanceType() == null) {
                // invalid instance type
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_INSTANCE_TYPE_DOES_NOT_EXIST);
    }
    

    6.24 镜像类型为空验证

    if (imageTypeId != null && getImageType() == null) {
                // invalid image type
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_IMAGE_TYPE_DOES_NOT_EXIST);
    }
    

    6.25 CPU 数量验证

    if (!validate(VmValidator.validateCpuSockets(getParameters().getVmStaticData(), getEffectiveCompatibilityVersion()))) {
          return false;
    }
    

    6.26 CPU 共享验证

    • 范围值必须是 0 到 262144 之间。
    if (!isCpuSharesValid(vmFromParams)) {
                return failValidation(EngineMessage.QOS_CPU_SHARES_OUT_OF_RANGE);
    }
    

    6.27 CPU 内核线程验证

    if (!VmCpuCountHelper.validateCpuCounts(vmFromParams)) {
            return failValidation(EngineMessage.TOO_MANY_CPU_COMPONENTS);
    }
    

    6.28 系统 VirtIO-SCSI 支持验证

    public ValidationResult isOsTypeSupportedForVirtioScsi(int osId, Version clusterVersion) {
            return ValidationResult
                    .failWith(EngineMessage.ACTION_TYPE_FAILED_ILLEGAL_OS_TYPE_DOES_NOT_SUPPORT_VIRTIO_SCSI)
                    .unless(vmValidationUtils.isDiskInterfaceSupportedByOs(osId, clusterVersion, DiskInterface.VirtIO_SCSI));
    }
    

    6.29 虚拟机物理内存验证

    • 虚拟机物理内存不能超过内存总量。
    if (vmFromParams.getMinAllocatedMem() > vmFromParams.getMemSizeMb()) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_MIN_MEMORY_CANNOT_EXCEED_MEMORY_SIZE);
    }
    

    6.30 磁盘配置集验证

    • 用户没有权限为磁盘附加磁盘配置集。
    • 必须有一个在存储域中定义的配置集。
    private boolean setAndValidateDiskProfiles() {
            if (diskInfoDestinationMap != null && !diskInfoDestinationMap.isEmpty()) {
                Map<DiskImage, Guid> map = new HashMap<>();
                List<DiskImage> diskImages = DisksFilter.filterImageDisks(diskInfoDestinationMap.values(),
                        ONLY_NOT_SHAREABLE,
                        ONLY_ACTIVE);
                for (DiskImage diskImage : diskImages) {
                    map.put(diskImage, diskImage.getStorageIds().get(0));
                }
                return validate(diskProfileHelper.setAndValidateDiskProfiles(map, getCurrentUser()));
            }
            return true;
    }
    

    6.31 CPU 配置集验证

    • 指定 ID 的 CPU 配置集不存在。
    • CPU 配置集与集群不匹配。
    • 用户没有权限把指定 ID 的配置集分配给 VM。
    protected boolean setAndValidateCpuProfile() {
            return validate(cpuProfileHelper.setAndValidateCpuProfile(
                    getParameters().getVm().getStaticData(),
                    getUserIdIfExternal().orElse(null)));
    }
    

    6.32 Cinder 磁盘验证

    List<CinderDisk> cinderDisks = DisksFilter.filterCinderDisks(diskInfoDestinationMap.values());
            CinderDisksValidator cinderDisksValidator = new CinderDisksValidator(cinderDisks);
    if (!validate(cinderDisksValidator.validateCinderDiskLimits())) {
                return false;
    }
    

    6.33 虚拟机图标验证

    • 自定义图标验证
    if (getParameters().getVmLargeIcon() != null && !validate(IconValidator.validate(
                    IconValidator.DimensionsType.LARGE_CUSTOM_ICON,
                    getParameters().getVmLargeIcon()))) {
                return false;
    }
    
    • 小图标验证
    if (getSmallIconId() != null
                    && getParameters().getVmLargeIcon() == null // icon id is ignored if large icon is sent
                    && !validate(IconValidator.validateIconId(getSmallIconId(), "Small"))) {
                return false;
    }
    
    • 大图标验证
    if (getLargeIconId() != null
                    && getParameters().getVmLargeIcon() == null // icon id is ignored if large icon is sent
                    && !validate(IconValidator.validateIconId(getLargeIconId(), "Large"))) {
                return false;
    }
    

    6.34 numa 节点验证

    if (!validate(getNumaValidator().checkVmNumaNodesIntegrity(
                    getParameters().getVm(),
                    getParameters().getVm().getvNumaNodeList()))) {
                return false;
    }
    

    6.35 群集升级模式验证

    if (getCluster().isInUpgradeMode()) {
                getParameters().getVm().setClusterCompatibilityVersion(getCluster().getCompatibilityVersion());
                if (!validate(getClusterUpgradeValidator().isVmReadyForUpgrade(getParameters().getVm()))) {
                    return false;
                }
    }
    

    6.36 虚拟机最大内存验证

    • 内存大小不能超过最大内存。
    • 最大内存不能超过平台的限制。
    if (!validate(vmHandler.validateMaxMemorySize(
                    getParameters().getVmStaticData(),
                    getEffectiveCompatibilityVersion()))) {
                return false;
    }
    

    6.37 虚拟机租赁验证

    • 虚拟机兼容性版本是否支持虚拟机租赁。
    • 一个虚拟机租赁已被定义,但高可用性被设置为 false。
    if (shouldAddLease(getParameters().getVmStaticData()) && !canAddLease()) {
                return false;
    }
    

    6.38 虚拟机 cloud-init 验证

    • cloud-init 配置中的 Start On Boot 选择无效。只支持 " true "。
    • cloud-init 配置中需要静态 IPv4 地址。
    • cloud-init 配置中需要静态 IPv6 地址。
    • cloud-init 配置中的选项 'autoconf' 不被支持。
    List<EngineMessage> msgs = openStackMetadataAdapter.validate(getParameters().getVmStaticData().getVmInit());
    if (!CollectionUtils.isEmpty(msgs)) {
           return failValidation(msgs);
    }
    

    7 添加磁盘

    • 添加磁盘使用了 AddDiskCommand 类。
    • 验证实现为 validate 方法。

    7.1 磁盘数据验证

    protected boolean validateDiskVmData() {
            if (getDiskVmElement() == null || getDiskVmElement().getId() == null ||
                    !Objects.equals(getDiskVmElement().getId().getVmId(), getVmId())) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_DISK_VM_DATA_MISSING);
            }
            return true;
    }
    

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

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

    7.3 引导磁盘验证

    • 虚拟机只能包含一个引导磁盘。
    if (getDiskVmElement().isBoot() && !validate(diskValidator.isVmNotContainsBootDisk(vm))) {
                    return false;
    }
    

    7.4 磁盘擦除支持验证

    • PassDiscardSupported 版本支持情况。
    if (!validatePassDiscardSupported(diskVmElementValidator)) {
         return false;
    }
    

    7.5 PCI 和 IDE 数量支持验证

    VmValidator.checkPciAndIdeLimit(getVm().getOs(),
                    getVm().getCompatibilityVersion(),
                    getVm().getNumOfMonitors(),
                    vmInterfaces,
                    diskVmElements,
                    isVirtioScsiControllerAttached(getVmId()),
                    hasWatchdog(getVmId()),
                    isBalloonEnabled(getVmId()),
                    isSoundDeviceEnabled(getVmId()))
    ......
    

    7.6 只读磁盘验证

    • IDE 磁盘不能是只读的。
    • 只读磁盘不支持 SCSI 设备透传。
    if (!validate(diskVmElementValidator.isReadOnlyPropertyCompatibleWithInterface())) {
         return false;
    }
    

    7.7 配额验证

    protected boolean validateQuota() {
            if (!getParameters().getDiskInfo().getDiskStorageType().isInternal()) {
                return true;
            }
    
            return validateQuota(((DiskImage) getParameters().getDiskInfo()).getQuotaId());
    }
    

    7.8 磁盘配置集验证

    • 与 6.30 一致。

    7.9 Lun 类型磁盘验证

    • Lun 连接对象验证。
      • 提供的 lun 没有有效的 lun 类型。
      • 提供的 LUN 丢缺失了至少一个连接参数(address/port/iqn)。
    if (!validate(diskValidator.validateConnectionsInLun(lun.getLunType()))) {
                return false;
    }
    
    • 是否已使用验证。
    if (!validate(diskValidator.validateLunAlreadyInUse())) {
                return false;
    }
    
    • 虚拟机锁验证。
    getVm()).vmNotLocked()
    
    • 快照相关验证。
      • 快照锁验证。
      • 快照不能处于预览状态。
    isVmNotInPreviewSnapshot()
    
    • 虚拟机必须启用 VirtIO-SCSI。
    if (!validate(diskVmElementValidator.isVirtIoScsiValid(getVm()))) {
           return false;
    }
    
    • 磁盘接口是否被操作系统支持。
    if (!validate(diskVmElementValidator.isDiskInterfaceSupported(getVm()))) {
           return false;
    }
    
    • 存储服务器是否连接验证
    if (getVds() != null) {
                lunFromStorage = getLunDisk(lun, getVds());
                if (lunFromStorage == null) {
                    return failValidation(EngineMessage.ACTION_TYPE_FAILED_DISK_LUN_INVALID);
                }
    }
    
    • SCSI 预留验证
      • SCSI 预留只能在 SGIO 没有被过滤的情况下设置。
    if (!validate(diskValidator.isUsingScsiReservationValid(getVm(), getDiskVmElement(), lunDisk))) {
                return false;
    }
    

    7.10 存储域验证

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

    7.11 Cinder 磁盘验证

    • 超过了允许的最大卷数量不能在存储域中创建 Cinder 磁盘。
    cinderDisksValidator.validateCinderDiskLimits()
    

    7.12 Cinder 卷验证

    • Cinder 卷类型不存在。
    cinderDisksValidator.validateCinderVolumeTypesExist()
    

    8 删除磁盘

    • 删除磁盘使用了 RemoveDiskCommand 类。
    • 验证实现为 validate 方法。

    8.1 磁盘为空验证

    if (getDisk() == null) {
                return failValidation(EngineMessage.ACTION_TYPE_FAILED_VM_IMAGE_DOES_NOT_EXIST);
    }
    

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

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

    8.3 挂载磁盘虚拟机验证

    • 挂载该磁盘的虚拟机必须都关机。
    private boolean validateAllVmsForDiskAreDown() {
            if (getDisk().getVmEntityType() != null && getDisk().getVmEntityType().isVmType()) {
                for (VM vm : getVmsForDiskId()) {
                    if (vm.getStatus() != VMStatus.Down && !vm.isHostedEngine()) {
                        VmDevice vmDevice = vmDeviceDao.get(new VmDeviceId(getDisk().getId(), vm.getId()));
                        if (vmDevice.isPlugged()) {
                            addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_VM_IS_NOT_DOWN);
                            return false;
                        }
                    }
                }
            }
    
            return true;
    }
    

    8.4 存储域验证

    • 删除一个模板的磁盘副本时,必须指定存储域。
    • 提供的存储域错误,它和磁盘没有关联。
    canRemoveDiskBasedOnImageStorageCheck()
    

    9 激活磁盘

    • 激活磁盘使用了 HotPlugDiskToVmCommand 类。
    • 验证实现为 validate 方法。

    9.1 虚拟机验证

    • 虚拟机必须存在。
    VmValidator(getVm()).isVmExists())
    
    • 虚拟机状态验证
      • 虚拟机必须为 Up、Down 或者 Paused 状态。
    protected boolean isVmInUpPausedDownStatus() {
            if (getVm().getStatus() != VMStatus.Up && getVm().getStatus() != VMStatus.Down
                    && getVm().getStatus() != VMStatus.Paused) {
                return failVmStatusIllegal();
            }
            return true;
    }
    

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

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

    9.3 磁盘附加验证

    protected boolean isDiskExistAndAttachedToVm(Disk disk) {
            DiskValidator diskValidator = getDiskValidator(disk);
            return validate(diskValidator.isDiskExists()) && validate(diskValidator.isDiskAttachedToVm(getVm()));
    }
    

    9.4 磁盘接口支持验证

    private boolean interfaceDiskValidation() {
            DiskVmElementValidator diskVmElementValidator = getDiskVmElementValidator(disk, getDiskVmElement());
            return validate(diskVmElementValidator.isDiskInterfaceSupported(getVm()));
    }
    

    9.5 磁盘已激活验证

    • 该磁盘不能处于已激活状态。
    if (getPlugAction() == VDSCommandType.HotPlugDisk && oldVmDevice.isPlugged()) {
                return failValidation(EngineMessage.HOT_PLUG_DISK_IS_NOT_UNPLUGGED);
    }
    

    9.6 快照验证

    • 快照锁验证。
    • 快照不能处于预览状态。
    protected boolean isVmNotInPreviewSnapshot() {
            return
                    getVmId() != null &&
                    validate(snapshotsValidator.vmNotDuringSnapshot(getVmId())) &&
                    validate(snapshotsValidator.vmNotInPreview(getVmId()));
    }
    

    9.7 存储域验证

    • 至少有一个激活的存储域。
    storageDomainValidator.isDomainExistAndActive()
    
    • 正在运行的虚拟机不能包括存储在备份存储域中的磁盘。
    storageDomainValidator.isNotBackupDomain()
    

    9.8 VirtIO-SCSI 启用验证

    private boolean virtIoScsiDiskValidation() {
            DiskVmElementValidator diskVmElementValidator = getDiskVmElementValidator(disk, getDiskVmElement());
            return validate(diskVmElementValidator.isVirtIoScsiValid(getVm()));
    }
    

    9.9 磁盘擦除支持验证

    • 与 7.4 一致。

    10 取消激活磁盘

    • 与激活磁盘的验证流程一致。
      • 9.6 更改为磁盘已未取消激活验证。
        • 该磁盘不能处于取消激活状态
    if (getPlugAction() == VDSCommandType.HotUnPlugDisk && !oldVmDevice.isPlugged()) {
                return failValidation(EngineMessage.HOT_UNPLUG_DISK_IS_NOT_PLUGGED);
    }
    

    相关文章

      网友评论

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

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