package org.ovirt.engine.core.bll.storage.disk; import javax.inject.Inject; import org.ovirt.engine.core.bll.context.CommandContext; import org.ovirt.engine.core.bll.validator.VmValidator; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.action.AttachDetachVmDiskParameters; import org.ovirt.engine.core.common.businessentities.VMStatus; import org.ovirt.engine.core.common.businessentities.VmDevice; import org.ovirt.engine.core.common.businessentities.VmDeviceId; 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.DiskVmElement; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.common.vdscommands.VDSCommandType; import org.ovirt.engine.core.dao.DiskImageDao; import org.ovirt.engine.core.dao.DiskVmElementDao; import org.ovirt.engine.core.dao.ImageDao; import org.ovirt.engine.core.dao.VmDeviceDao; import org.ovirt.engine.core.dao.VmStaticDao; public class DetachDiskFromVmCommand<T extends AttachDetachVmDiskParameters> extends AbstractDiskVmCommand<T> { @Inject private DiskHandler diskHandler; @Inject private VmDeviceDao vmDeviceDao; @Inject private DiskImageDao diskImageDao; @Inject private DiskVmElementDao diskVmElementDao; @Inject private ImageDao imageDao; @Inject private VmStaticDao vmStaticDao; private Disk disk; private VmDevice vmDevice; private DiskVmElement dveFromDb; public DetachDiskFromVmCommand(T parameters, CommandContext cmdContext) { super(parameters, cmdContext); } @Override protected boolean validate() { if (!validate(new VmValidator(getVm()).isVmExists()) || !canRunActionOnNonManagedVm()) { return false; } if (getVm().getStatus() != VMStatus.Up && getVm().getStatus() != VMStatus.Down) { return failVmStatusIllegal(); } disk = diskHandler.loadDiskFromSnapshot(getDiskVmElement().getDiskId(), getParameters().getSnapshotId()); if (!isDiskExistAndAttachedToVm(disk)) { return false; } vmDevice = vmDeviceDao.get(new VmDeviceId(disk.getId(), getVmId())); if (vmDevice == null) { return failValidation(EngineMessage.ACTION_TYPE_FAILED_DISK_ALREADY_DETACHED); } if (vmDevice.getSnapshotId() != null) { disk = diskHandler.loadDiskFromSnapshot(disk.getId(), vmDevice.getSnapshotId()); } if (vmDevice.isPlugged() && getVm().getStatus() != VMStatus.Down) { if (!isDiskSupportedForPlugUnPlug(getDiskVmElement(), disk.getDiskAlias())) { return false; } } // Check if disk has no snapshots before detaching it. if (disk.getDiskStorageType().isInternal()) { // A "regular" disk cannot be detached if it's part of the vm snapshots // when a disk snapshot is being detached, it will always be part of snapshots - but of it's "original" vm, // therefore for attached disk snapshot it shouldn't be checked whether it has snapshots or not. if (vmDevice.getSnapshotId() == null && diskImageDao.getAllSnapshotsForImageGroup(disk.getId()).size() > 1) { return failValidation(EngineMessage.ERROR_CANNOT_DETACH_DISK_WITH_SNAPSHOT); } } return true; } @Override protected void setActionMessageParameters() { addValidationMessage(EngineMessage.VAR__ACTION__DETACH_ACTION_TO); addValidationMessage(EngineMessage.VAR__TYPE__DISK); } @Override protected void executeVmCommand() { if (diskShouldBeUnPlugged()) { performPlugCommand(VDSCommandType.HotUnPlugDisk, disk, vmDevice); } vmDeviceDao.remove(vmDevice.getId()); diskVmElementDao.remove(vmDevice.getId()); if (!disk.isDiskSnapshot() && disk.getDiskStorageType().isInternal()) { // clears snapshot ID imageDao.updateImageVmSnapshotId(((DiskImage) disk).getImageId(), null); } // update cached image vmHandler.updateDisksFromDb(getVm()); vmStaticDao.incrementDbGeneration(getVm().getId()); setSucceeded(true); } private boolean diskShouldBeUnPlugged() { return Boolean.TRUE.equals(getParameters().isPlugUnPlug() && vmDevice.isPlugged() && getVm().getStatus() != VMStatus.Down); } @Override public AuditLogType getAuditLogTypeValue() { return getSucceeded() ? AuditLogType.USER_DETACH_DISK_FROM_VM : AuditLogType.USER_FAILED_DETACH_DISK_FROM_VM; } @Override public String getDiskAlias() { return disk.getDiskAlias(); } @Override protected DiskVmElement getDiskVmElement() { // When detaching a disk from running VMs a hot unplug is needed, in that case we need the interface info from // the DB, since the parameters pass only the VM and disk ID we need to load the rest of the data from the DB if (dveFromDb == null) { dveFromDb = diskVmElementDao.get(super.getDiskVmElement().getId()); } return dveFromDb; } }