文前说明
作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。
本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。
分析整理的版本为 Ovirt 4.2.3 版本。
- engine 中的业务执行大部分都是通过 GWT-RPC 执行后端 Command 命令实现的。
- 通过 Backend 提供的 runInternalAction、runMultipleActions 等方法执行。
- 例如运行虚拟机为 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 bean 和 Hibernate 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 虚拟机自定义属性验证
- 自定义属性从 PredefinedVMProperties 和 UserDefinedVMProperties 获取。
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 类型支持验证
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 设备验证
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 验证
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);
}
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 共享验证
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 磁盘配置集验证
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()
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 卷验证
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 磁盘擦除支持验证
10 取消激活磁盘
if (getPlugAction() == VDSCommandType.HotUnPlugDisk && !oldVmDevice.isPlugged()) {
return failValidation(EngineMessage.HOT_UNPLUG_DISK_IS_NOT_PLUGGED);
}