package org.ovirt.engine.core.bll.storage.disk; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import javax.inject.Inject; import org.apache.commons.lang.StringUtils; import org.ovirt.engine.core.bll.ConcurrentChildCommandsExecutionCallback; import org.ovirt.engine.core.bll.DisableInPrepareMode; import org.ovirt.engine.core.bll.LockMessagesMatchUtil; import org.ovirt.engine.core.bll.MultiLevelAdministrationHandler; import org.ovirt.engine.core.bll.NonTransactiveCommandAttribute; import org.ovirt.engine.core.bll.PredefinedRoles; import org.ovirt.engine.core.bll.context.CommandContext; import org.ovirt.engine.core.bll.profiles.DiskProfileHelper; import org.ovirt.engine.core.bll.quota.QuotaConsumptionParameter; import org.ovirt.engine.core.bll.quota.QuotaStorageConsumptionParameter; import org.ovirt.engine.core.bll.quota.QuotaStorageDependent; import org.ovirt.engine.core.bll.storage.disk.image.ImagesHandler; import org.ovirt.engine.core.bll.storage.domain.LunHelper; import org.ovirt.engine.core.bll.tasks.CommandCoordinatorUtil; import org.ovirt.engine.core.bll.tasks.interfaces.CommandCallback; import org.ovirt.engine.core.bll.utils.PermissionSubject; import org.ovirt.engine.core.bll.validator.VmValidator; import org.ovirt.engine.core.bll.validator.storage.CinderDisksValidator; import org.ovirt.engine.core.bll.validator.storage.DiskValidator; import org.ovirt.engine.core.bll.validator.storage.DiskVmElementValidator; import org.ovirt.engine.core.bll.validator.storage.StorageDomainValidator; import org.ovirt.engine.core.bll.validator.storage.StoragePoolValidator; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.FeatureSupported; import org.ovirt.engine.core.common.VdcObjectType; import org.ovirt.engine.core.common.action.AddDiskParameters; import org.ovirt.engine.core.common.action.AddImageFromScratchParameters; import org.ovirt.engine.core.common.action.LockProperties; import org.ovirt.engine.core.common.action.VdcActionParametersBase; import org.ovirt.engine.core.common.action.VdcActionParametersBase.EndProcedure; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.action.VdcReturnValueBase; import org.ovirt.engine.core.common.action.VmDiskOperationParameterBase; import org.ovirt.engine.core.common.asynctasks.EntityInfo; import org.ovirt.engine.core.common.businessentities.ActionGroup; import org.ovirt.engine.core.common.businessentities.Permission; import org.ovirt.engine.core.common.businessentities.Snapshot.SnapshotType; import org.ovirt.engine.core.common.businessentities.StoragePool; import org.ovirt.engine.core.common.businessentities.StoragePoolIsoMapId; import org.ovirt.engine.core.common.businessentities.StorageServerConnections; import org.ovirt.engine.core.common.businessentities.VDS; import org.ovirt.engine.core.common.businessentities.VM; import org.ovirt.engine.core.common.businessentities.VMStatus; import org.ovirt.engine.core.common.businessentities.VmDevice; import org.ovirt.engine.core.common.businessentities.storage.CinderDisk; import org.ovirt.engine.core.common.businessentities.storage.Disk; import org.ovirt.engine.core.common.businessentities.storage.DiskImage; import org.ovirt.engine.core.common.businessentities.storage.DiskLunMap; import org.ovirt.engine.core.common.businessentities.storage.DiskStorageType; import org.ovirt.engine.core.common.businessentities.storage.DiskVmElement; import org.ovirt.engine.core.common.businessentities.storage.LUNs; import org.ovirt.engine.core.common.businessentities.storage.LunDisk; import org.ovirt.engine.core.common.businessentities.storage.ScsiGenericIO; import org.ovirt.engine.core.common.businessentities.storage.StorageType; import org.ovirt.engine.core.common.config.Config; import org.ovirt.engine.core.common.config.ConfigValues; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.common.locks.LockingGroup; import org.ovirt.engine.core.common.utils.Pair; import org.ovirt.engine.core.common.validation.group.UpdateEntity; import org.ovirt.engine.core.common.vdscommands.GetDeviceListVDSCommandParameters; import org.ovirt.engine.core.common.vdscommands.VDSCommandType; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dao.BaseDiskDao; import org.ovirt.engine.core.dao.DiskLunMapDao; import org.ovirt.engine.core.dao.DiskVmElementDao; import org.ovirt.engine.core.dao.SnapshotDao; import org.ovirt.engine.core.dao.StoragePoolIsoMapDao; import org.ovirt.engine.core.utils.transaction.TransactionSupport; @DisableInPrepareMode @NonTransactiveCommandAttribute(forceCompensation = true) public class AddDiskCommand<T extends AddDiskParameters> extends AbstractDiskVmCommand<T> implements QuotaStorageDependent { private LUNs lunFromStorage; @Inject private DiskProfileHelper diskProfileHelper; @Inject private LunHelper lunHelper; @Inject private DiskLunMapDao diskLunMapDao; @Inject private StoragePoolIsoMapDao storagePoolIsoMapDao; @Inject private BaseDiskDao baseDiskDao; @Inject private DiskVmElementDao diskVmElementDao; @Inject private SnapshotDao snapshotDao; /** * Constructor for command creation when compensation is applied on startup */ public AddDiskCommand(Guid commandId) { super(commandId); } public AddDiskCommand(T parameters, CommandContext commandContext) { super(parameters, commandContext); setVdsId(parameters.getVdsId()); } @Override protected LockProperties applyLockProperties(LockProperties lockProperties) { return lockProperties.withScope(LockProperties.Scope.Execution); } @Override protected boolean validateInputs() { return super.validateInputs(); } @Override protected boolean validate() { if (!isFloatingDisk() && (!validate(new VmValidator(getVm()).isVmExists()) || !validateDiskVmData())) { return false; } Disk diskInfo = getParameters().getDiskInfo(); if (diskInfo.getDiskStorageType() == DiskStorageType.IMAGE || diskInfo.getDiskStorageType() == DiskStorageType.CINDER) { getDiskImageInfo().setDiskSnapshot(false); } VM vm = getVm(); DiskValidator diskValidator = getDiskValidator(getParameters().getDiskInfo()); DiskVmElementValidator diskVmElementValidator = getDiskVmElementValidator(getParameters().getDiskInfo(), getDiskVmElement()); if (vm != null) { if (!validateDiskVmData() || !canRunActionOnNonManagedVm()) { return false; } updateDisksFromDb(); if (getDiskVmElement().isBoot() && !validate(diskValidator.isVmNotContainsBootDisk(vm))) { return false; } if (!validatePassDiscardSupported(diskVmElementValidator)) { return false; } // if user sent drive check that its not in use if (!isDiskPassPciAndIdeLimit()) { return false; } if (!validate(diskVmElementValidator.isReadOnlyPropertyCompatibleWithInterface())) { return false; } } else if (Boolean.TRUE.equals(getParameters().getPlugDiskToVm())) { return failValidation(EngineMessage.CANNOT_ADD_FLOATING_DISK_WITH_PLUG_VM_SET); } if (!validateQuota()) { return false; } if (DiskStorageType.IMAGE == getParameters().getDiskInfo().getDiskStorageType()) { if (!checkIfImageDiskCanBeAdded(vm, diskVmElementValidator)) { return false; } return setAndValidateDiskProfiles(); } if (DiskStorageType.LUN == getParameters().getDiskInfo().getDiskStorageType()) { return checkIfLunDiskCanBeAdded(diskValidator); } if (DiskStorageType.CINDER == getParameters().getDiskInfo().getDiskStorageType()) { CinderDisk cinderDisk = (CinderDisk) getParameters().getDiskInfo(); cinderDisk.setStorageIds(new ArrayList<>(Collections.singletonList(getStorageDomainId()))); StorageDomainValidator storageDomainValidator = createStorageDomainValidator(); CinderDisksValidator cinderDisksValidator = new CinderDisksValidator(cinderDisk); return validate(storageDomainValidator.isDomainExistAndActive()) && validate(cinderDisksValidator.validateCinderDiskLimits()) && validate(cinderDisksValidator.validateCinderVolumeTypesExist()); } return true; } protected boolean checkIfLunDiskCanBeAdded(DiskValidator diskValidator) { LunDisk lunDisk = (LunDisk) getParameters().getDiskInfo(); LUNs lun = lunDisk.getLun(); switch (lun.getLunType()) { case UNKNOWN: return failValidation(EngineMessage.ACTION_TYPE_FAILED_DISK_LUN_HAS_NO_VALID_TYPE); case ISCSI: if (lun.getLunConnections() == null || lun.getLunConnections().isEmpty()) { return failValidation(EngineMessage.ACTION_TYPE_FAILED_DISK_LUN_ISCSI_MISSING_CONNECTION_PARAMS); } for (StorageServerConnections conn : lun.getLunConnections()) { if (StringUtils.isEmpty(conn.getIqn()) || StringUtils.isEmpty(conn.getConnection()) || StringUtils.isEmpty(conn.getPort())) { return failValidation(EngineMessage.ACTION_TYPE_FAILED_DISK_LUN_ISCSI_MISSING_CONNECTION_PARAMS); } } break; default: break; } if (diskLunMapDao.getDiskIdByLunId(lun.getLUNId()) != null) { return failValidation(EngineMessage.ACTION_TYPE_FAILED_DISK_LUN_IS_ALREADY_IN_USE); } if (getVm() != null && !(validate(new VmValidator(getVm()).vmNotLocked()) && isVmNotInPreviewSnapshot())) { return false; } DiskVmElementValidator diskVmElementValidator = new DiskVmElementValidator(getParameters().getDiskInfo(), getDiskVmElement()); 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); } } if (!validate(diskValidator.isUsingScsiReservationValid(getVm(), getDiskVmElement(), lunDisk))) { return false; } return true; } /** * Retrieves the specified LUN if it's visible to the specified host, or null otherwise. * * @param lun the LUN to examine. * @param vds the host to query from. * * @return the specified LUN if it's visible to the specified host, or null otherwise. */ protected LUNs getLunDisk(final LUNs lun, VDS vds) { return executeGetDeviceList(vds.getId(), lun.getLunType(), lun.getLUNId()).stream().findFirst().orElse(null); } protected List<LUNs> executeGetDeviceList(Guid vdsId, StorageType storageType, String lunId) { GetDeviceListVDSCommandParameters parameters = new GetDeviceListVDSCommandParameters(vdsId, storageType, false, Collections.singletonList(lunId)); return (List<LUNs>) runVdsCommand(VDSCommandType.GetDeviceList, parameters).getReturnValue(); } protected boolean checkIfImageDiskCanBeAdded(VM vm, DiskVmElementValidator diskVmElementValidator) { if (Guid.Empty.equals(getStorageDomainId())) { return failValidation(EngineMessage.ACTION_TYPE_FAILED_STORAGE_DOMAIN_NOT_SPECIFIED); } boolean returnValue; StorageDomainValidator storageDomainValidator = createStorageDomainValidator(); // vm agnostic checks returnValue = (getParameters().isSkipDomainCheck() || validate(storageDomainValidator.isDomainExistAndActive())) && !isShareableDiskOnGlusterDomain() && checkImageConfiguration() && validate(storageDomainValidator.hasSpaceForNewDisk(getDiskImageInfo())) && validate(storageDomainValidator.isDomainWithinThresholds()) && checkExceedingMaxBlockDiskSize() && canAddShareableDisk() && validate(diskVmElementValidator.isVirtIoScsiValid(vm)) && validate(diskVmElementValidator.isDiskInterfaceSupported(getVm())); if (returnValue && vm != null) { StoragePool sp = getStoragePool(); // Note this is done according to the VM's spId. returnValue = validate(new StoragePoolValidator(sp).isUp()) && isStoragePoolMatching(vm) && validate(new VmValidator(getVm()).vmNotLocked()) && isVmNotInPreviewSnapshot(); } return returnValue; } private boolean isShareableDiskOnGlusterDomain() { if (getParameters().getDiskInfo().isShareable() && getStorageDomain().getStorageType() == StorageType.GLUSTERFS) { addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_SHAREABLE_DISKS_NOT_SUPPORTED_ON_GLUSTER_DOMAIN); return true; } return false; } private boolean canAddShareableDisk() { if (getParameters().getDiskInfo().isShareable()) { if (!isVolumeFormatSupportedForShareable(((DiskImage) getParameters().getDiskInfo()).getVolumeFormat())) { return failValidation(EngineMessage.SHAREABLE_DISK_IS_NOT_SUPPORTED_BY_VOLUME_FORMAT); } } return true; } private boolean checkExceedingMaxBlockDiskSize() { if (isExceedMaxBlockDiskSize()) { addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_DISK_MAX_SIZE_EXCEEDED); getReturnValue().getValidationMessages().add( String.format("$max_disk_size %1$s", Config.<Integer> getValue(ConfigValues.MaxBlockDiskSize))); return false; } return true; } private boolean isStoragePoolMatching(VM vm) { if (storagePoolIsoMapDao.get(new StoragePoolIsoMapId(getStorageDomainId(), vm.getStoragePoolId())) == null) { return failValidation(EngineMessage.ACTION_TYPE_FAILED_STORAGE_POOL_OF_VM_NOT_MATCH); } return true; } /** Checks if the image's configuration is legal */ protected boolean checkImageConfiguration() { return ImagesHandler.checkImageConfiguration( getStorageDomain().getStorageStaticData(), getDiskImageInfo(), getReturnValue().getValidationMessages()); } private double getRequestDiskSpace() { if (getParameters().getDiskInfo().getDiskStorageType().isInternal()) { return getDiskImageInfo().getSizeInGigabytes(); } return 0; } private boolean isFloatingDisk() { return Guid.isNullOrEmpty(getParameters().getVmId()); } /** @return The disk from the parameters, cast to a {@link DiskImage} */ private DiskImage getDiskImageInfo() { return (DiskImage) getParameters().getDiskInfo(); } private boolean isExceedMaxBlockDiskSize() { if (getStorageDomain().getStorageType().isBlockDomain()) { return getRequestDiskSpace() > Config.<Integer> getValue(ConfigValues.MaxBlockDiskSize); } return false; } /** * @return The id of the storage domain where the first encountered VM image disk reside, if the vm doesn't have no * image disks then Guid.Empty will be returned. */ private Guid getDisksStorageDomainId() { for (Disk disk : getVm().getDiskMap().values()) { if (disk.getDiskStorageType() == DiskStorageType.IMAGE) { return ((DiskImage) disk).getStorageIds().get(0); } } return Guid.Empty; } @Override public Guid getStorageDomainId() { if (super.getStorageDomainId() == null) { Guid storageDomainId = getParameters().getStorageDomainId(); if (Guid.Empty.equals(storageDomainId) && getParameters().getDiskInfo().getDiskStorageType() == DiskStorageType.IMAGE && getVm() != null) { updateDisksFromDb(); storageDomainId = getDisksStorageDomainId(); // this set is done so that in case we will execute an async task // the correct storage domain id will be set during the call to the end methods getParameters().setStorageDomainId(storageDomainId); } else if (storageDomainId == null) { storageDomainId = Guid.Empty; // this set is done so that in case we will execute an async task // the correct storage domain id will be set during the call to the end methods getParameters().setStorageDomainId(storageDomainId); } setStorageDomainId(storageDomainId); return storageDomainId; } return super.getStorageDomainId(); } @Override public List<PermissionSubject> getPermissionCheckSubjects() { List<PermissionSubject> listPermissionSubjects; if (isFloatingDisk()) { listPermissionSubjects = new ArrayList<>(); } else { listPermissionSubjects = super.getPermissionCheckSubjects(); } // If the storage domain ID is empty/null, it means we are going to create an external disk // In order to do that we need CREATE_DISK permissions on System level if (getParameters().getStorageDomainId() == null || Guid.Empty.equals(getParameters().getStorageDomainId())) { listPermissionSubjects.add(new PermissionSubject(Guid.SYSTEM, VdcObjectType.System, ActionGroup.CREATE_DISK)); if (getParameters().getDiskInfo().getSgio() == ScsiGenericIO.UNFILTERED) { listPermissionSubjects.add(new PermissionSubject(Guid.SYSTEM, VdcObjectType.System, ActionGroup.CONFIGURE_SCSI_GENERIC_IO)); } } else { listPermissionSubjects.add(new PermissionSubject(getParameters().getStorageDomainId(), VdcObjectType.Storage, ActionGroup.CREATE_DISK)); } return listPermissionSubjects; } @Override protected void setActionMessageParameters() { addValidationMessage(EngineMessage.VAR__ACTION__ADD); addValidationMessage(EngineMessage.VAR__TYPE__DISK); } @Override protected void executeVmCommand() { createNewDiskId(); getParameters().setEntityInfo(new EntityInfo(VdcObjectType.Disk, getParameters().getDiskInfo().getId())); ImagesHandler.setDiskAlias(getParameters().getDiskInfo(), getVm()); switch (getParameters().getDiskInfo().getDiskStorageType()) { case IMAGE: createDiskBasedOnImage(); break; case LUN: createDiskBasedOnLun(); break; case CINDER: createDiskBasedOnCinder(); break; } } private void createNewDiskId() { Guid diskId = getParameters().isUsePassedDiskId() ? getParameters().getDiskInfo().getId() : Guid.newGuid(); getParameters().getDiskInfo().setId(diskId); if (!isFloatingDisk()) { getDiskVmElement().getId().setDeviceId(diskId); } } private void createDiskBasedOnLun() { final LUNs lun; if (lunFromStorage == null) { lun = ((LunDisk) getParameters().getDiskInfo()).getLun(); } else { lun = lunFromStorage; } TransactionSupport.executeInNewTransaction(() -> { lunHelper.proceedLUNInDb(lun, lun.getLunType()); baseDiskDao.save(getParameters().getDiskInfo()); diskLunMapDao.save(new DiskLunMap(getParameters().getDiskInfo().getId(), lun.getLUNId())); if (getVm() != null) { // The disk VM element has to be added before the VM device since as a part of the VM device creation the // boot order is determined so the VM device creation depends on the existence of the disk VM element addDiskVmElementForDisk(getDiskVmElement()); addManagedDeviceForDisk(getParameters().getDiskInfo().getId()); } return null; }); getReturnValue().setActionReturnValue(getParameters().getDiskInfo().getId()); plugDiskToVmIfNeeded(); setSucceeded(true); } protected VmDevice addManagedDeviceForDisk(Guid diskId) { return getVmDeviceUtils().addDiskDevice( getVmId(), diskId, shouldDiskBePlugged(), Boolean.TRUE.equals(getParameters().getDiskVmElement().isReadOnly())); } protected DiskVmElement addDiskVmElementForDisk(DiskVmElement diskVmElement) { diskVmElementDao.save(diskVmElement); return diskVmElement; } protected boolean shouldDiskBePlugged() { return getVm().getStatus() == VMStatus.Down && !Boolean.FALSE.equals(getParameters().getPlugDiskToVm()); } protected boolean useCallback() { return getParameters().getDiskInfo().getDiskStorageType() == DiskStorageType.IMAGE && (parentHasCallback() || !isExecutedAsChildCommand()); } private void createDiskBasedOnImage() { if(!getParameters().getDiskInfo().isWipeAfterDeleteSet()) { getParameters().getDiskInfo().setWipeAfterDelete(getStorageDomain().getWipeAfterDelete()); } // create from blank template, create new vm snapshot id AddImageFromScratchParameters parameters = new AddImageFromScratchParameters(Guid.Empty, getParameters().getVmId(), getDiskImageInfo()); parameters.setQuotaId(getQuotaId()); parameters.setDiskProfileId(getDiskImageInfo().getDiskProfileId()); parameters.setDiskAlias(getDiskAlias()); if (getParameters().isUsePassedImageId()) { parameters.setDestinationImageId(getDiskImageInfo().getImageId()); } parameters.setLeaveLocked(getParameters().isShouldRemainLockedOnSuccesfulExecution()); parameters.setShouldRemainIllegalOnFailedExecution(getParameters().isShouldRemainIllegalOnFailedExecution()); parameters.setStorageDomainId(getStorageDomainId()); if (useCallback()) { parameters.setParentCommand(VdcActionType.AddDisk); parameters.setParentParameters(getParameters()); } else { parameters.setParentCommand(getParameters().getParentCommand()); parameters.setParentParameters(getParameters().getParentParameters()); } parameters.setEntityInfo(getParameters().getEntityInfo()); parameters.setStoragePoolId(getStorageDomain().getStoragePoolId()); setVmSnapshotIdForDisk(parameters); VdcReturnValueBase tmpRetValue = runInternalActionWithTasksContext(VdcActionType.AddImageFromScratch, parameters, getLock()); // Setting lock to null because the lock is released in the child command setLock(null); getTaskIdList().addAll(tmpRetValue.getInternalVdsmTaskIdList()); if (getVm() != null) { // The disk VM element has to be added before the VM device since as a part of the VM device creation the // boot order is determined so the VM device creation depends on the existence of the disk VM element getCompensationContext().snapshotEntity(addDiskVmElementForDisk(getDiskVmElement())); getCompensationContext().snapshotNewEntity(addManagedDeviceForDisk(getParameters().getDiskInfo().getId())); getCompensationContext().stateChanged(); } if (tmpRetValue.getActionReturnValue() != null) { DiskImage diskImage = tmpRetValue.getActionReturnValue(); addDiskPermissions(diskImage); getReturnValue().setActionReturnValue(diskImage.getId()); } getReturnValue().setFault(tmpRetValue.getFault()); setSucceeded(tmpRetValue.getSucceeded()); } @Override public CommandCallback getCallback() { return useCallback() ? new ConcurrentChildCommandsExecutionCallback() : null; } private void createDiskBasedOnCinder() { // ToDo: upon using CoCo infra in this commnad, move this logic. Future<VdcReturnValueBase> future = CommandCoordinatorUtil.executeAsyncCommand( VdcActionType.AddCinderDisk, buildAddCinderDiskParameters(), cloneContextAndDetachFromParent()); try { setReturnValue(future.get()); setSucceeded(getReturnValue().getSucceeded()); } catch (InterruptedException | ExecutionException e) { log.error("Error creating Cinder disk '{}': {}", getParameters().getDiskInfo().getDiskAlias(), e.getMessage()); log.debug("Exception", e); } } private VdcActionParametersBase buildAddCinderDiskParameters() { AddDiskParameters parameters = new AddDiskParameters(new DiskVmElement(null, getVmId()), getParameters().getDiskInfo()); parameters.setPlugDiskToVm(getParameters().getPlugDiskToVm()); parameters.setStorageDomainId(getParameters().getStorageDomainId()); parameters.setQuotaId(getQuotaId()); parameters.setEndProcedure(EndProcedure.COMMAND_MANAGED); if (getVm() != null) { parameters.setVmSnapshotId(snapshotDao.getId(getVmId(), SnapshotType.ACTIVE)); parameters.setDiskVmElement(getParameters().getDiskVmElement()); } return parameters; } /** * If disk is not allow to have snapshot no VM snapshot Id should be updated. */ private void setVmSnapshotIdForDisk(AddImageFromScratchParameters parameters) { if (getVm() == null) { parameters.setVmSnapshotId(getParameters().getVmSnapshotId()); } else if (getParameters().getDiskInfo().isAllowSnapshot()) { parameters.setVmSnapshotId(snapshotDao.getId(getVmId(), SnapshotType.ACTIVE)); } } private void addDiskPermissions(Disk disk) { if (getCurrentUser() != null) { Permission perms = new Permission(getCurrentUser().getId(), PredefinedRoles.DISK_OPERATOR.getId(), disk.getId(), VdcObjectType.Disk); MultiLevelAdministrationHandler.addPermission(perms); } } @Override public AuditLogType getAuditLogTypeValue() { switch (getActionState()) { case EXECUTE: if (isDiskStorageTypeRequiresExecuteState()) { return getExecuteAuditLogTypeValue(getSucceeded()); } else { return getEndSuccessAuditLogTypeValue(getSucceeded()); } case END_SUCCESS: return getEndSuccessAuditLogTypeValue(getSucceeded()); default: return AuditLogType.USER_ADD_DISK_FINISHED_FAILURE; } } private boolean isDiskStorageTypeRequiresExecuteState() { return getParameters().getDiskInfo().getDiskStorageType() == DiskStorageType.IMAGE || getParameters().getDiskInfo().getDiskStorageType() == DiskStorageType.CINDER; } private AuditLogType getExecuteAuditLogTypeValue(boolean successful) { boolean isVmNameExist = StringUtils.isNotEmpty(getVmName()); if (successful) { if (isInternalExecution()) { return AuditLogType.ADD_DISK_INTERNAL; } if (isVmNameExist) { return AuditLogType.USER_ADD_DISK_TO_VM; } else { return AuditLogType.USER_ADD_DISK; } } else { if (isInternalExecution()) { return AuditLogType.ADD_DISK_INTERNAL_FAILURE; } if (isVmNameExist) { return AuditLogType.USER_FAILED_ADD_DISK_TO_VM; } else { return AuditLogType.USER_FAILED_ADD_DISK; } } } protected AuditLogType getEndSuccessAuditLogTypeValue(boolean successful) { boolean isVmNameExist = StringUtils.isNotEmpty(getVmName()); if (successful) { if (isVmNameExist) { return AuditLogType.USER_ADD_DISK_TO_VM_FINISHED_SUCCESS; } else { return AuditLogType.USER_ADD_DISK_FINISHED_SUCCESS; } } else { if (isVmNameExist) { return AuditLogType.USER_ADD_DISK_TO_VM_FINISHED_FAILURE; } else { return AuditLogType.USER_ADD_DISK_FINISHED_FAILURE; } } } @Override protected VdcActionType getChildActionType() { return VdcActionType.AddImageFromScratch; } @Override protected List<Class<?>> getValidationGroups() { // Validation of parameters is only required for VM disks as the rest is validated in the validate() phase if (!isFloatingDisk()) { addValidationGroup(UpdateEntity.class); } return super.getValidationGroups(); } @Override protected Map<String, Pair<String, String>> getExclusiveLocks() { if (!isFloatingDisk() && getDiskVmElement() != null && getDiskVmElement().isBoot()) { return Collections.singletonMap(getParameters().getVmId().toString(), LockMessagesMatchUtil.makeLockingPair(LockingGroup.VM_DISK_BOOT, EngineMessage.ACTION_TYPE_FAILED_OBJECT_LOCKED)); } return null; } @Override protected Map<String, Pair<String, String>> getSharedLocks() { if (!Guid.isNullOrEmpty(getParameters().getVmId()) && !isInternalExecution()) { return Collections.singletonMap(getParameters().getVmId().toString(), LockMessagesMatchUtil.makeLockingPair(LockingGroup.VM, EngineMessage.ACTION_TYPE_FAILED_OBJECT_LOCKED)); } return null; } @Override protected void setLoggingForCommand() { setCommandShouldBeLogged(true); } private Guid getQuotaId() { if (getParameters().getDiskInfo() != null && getParameters().getDiskInfo().getDiskStorageType().isInternal()) { Guid quotaId = ((DiskImage) getParameters().getDiskInfo()).getQuotaId(); return getQuotaManager().getDefaultQuotaIfNull(quotaId, getStoragePoolId()); } return null; } @Override protected void endSuccessfully() { plugDiskToVmIfNeeded(); super.endSuccessfully(); } private void plugDiskToVmIfNeeded() { if (Boolean.TRUE.equals(getParameters().getPlugDiskToVm()) && getVm() != null && getVm().getStatus() != VMStatus.Down) { VmDiskOperationParameterBase params = new VmDiskOperationParameterBase(new DiskVmElement(getParameters().getDiskInfo().getId(), getVmId())); params.setShouldBeLogged(false); VdcReturnValueBase returnValue = runInternalAction(VdcActionType.HotPlugDiskToVm, params); if (!returnValue.getSucceeded()) { auditLogDirector.log(this, AuditLogType.USER_FAILED_HOTPLUG_DISK); } } } protected boolean setAndValidateDiskProfiles() { return validate(diskProfileHelper.setAndValidateDiskProfiles(Collections.singletonMap(getDiskImageInfo(), getStorageDomainId()), getCurrentUser())); } @Override public List<QuotaConsumptionParameter> getQuotaStorageConsumptionParameters() { List<QuotaConsumptionParameter> list = new ArrayList<>(); if (getParameters().getDiskInfo().getDiskStorageType().isInternal()) { list.add(new QuotaStorageConsumptionParameter( getQuotaId(), null, QuotaConsumptionParameter.QuotaAction.CONSUME, getStorageDomainId(), getRequestDiskSpace())); } return list; } protected StorageDomainValidator createStorageDomainValidator() { return new StorageDomainValidator(getStorageDomain()); } private boolean validatePassDiscardSupported(DiskVmElementValidator diskVmElementValidator) { if (getDiskVmElement().isPassDiscard() && !FeatureSupported.passDiscardSupported(getStoragePool().getCompatibilityVersion())) { return failValidation(EngineMessage.ACTION_TYPE_FAILED_PASS_DISCARD_NOT_SUPPORTED_BY_DC_VERSION, String.format("$dataCenterVersion %s", getStoragePool().getCompatibilityVersion().toString())); } return validate(diskVmElementValidator.isPassDiscardSupported(getStorageDomainId())); } }