diff --git a/api/src/main/java/com/cloud/storage/Volume.java b/api/src/main/java/com/cloud/storage/Volume.java index e42c8d4a6bf..95cee3108de 100644 --- a/api/src/main/java/com/cloud/storage/Volume.java +++ b/api/src/main/java/com/cloud/storage/Volume.java @@ -84,6 +84,7 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity, Ba s_fsm.addTransition(new StateMachine2.Transition(Creating, Event.OperationSucceeded, Ready, null)); s_fsm.addTransition(new StateMachine2.Transition(Creating, Event.DestroyRequested, Destroy, null)); s_fsm.addTransition(new StateMachine2.Transition(Creating, Event.CreateRequested, Creating, null)); + s_fsm.addTransition(new StateMachine2.Transition(Ready, Event.CreateRequested, Creating, null)); s_fsm.addTransition(new StateMachine2.Transition(Ready, Event.ResizeRequested, Resizing, null)); s_fsm.addTransition(new StateMachine2.Transition(Resizing, Event.OperationSucceeded, Ready, Arrays.asList(new StateMachine2.Transition.Impact[]{StateMachine2.Transition.Impact.USAGE}))); s_fsm.addTransition(new StateMachine2.Transition(Resizing, Event.OperationFailed, Ready, null)); diff --git a/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java index 664ba62e8cf..7c4601e5417 100644 --- a/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java +++ b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java @@ -29,6 +29,7 @@ import java.util.Random; import javax.inject.Inject; import org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity; +import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; @@ -173,6 +174,8 @@ public class VolumeServiceImpl implements VolumeService { private VolumeDetailsDao _volumeDetailsDao; @Inject private TemplateDataFactory tmplFactory; + @Inject + private VolumeOrchestrationService _volumeMgr; private final static String SNAPSHOT_ID = "SNAPSHOT_ID"; @@ -812,9 +815,15 @@ public class VolumeServiceImpl implements VolumeService { } volDao.update(volume.getId(), volume); + vo.processEvent(Event.OperationSuccessed); } else { - vo.processEvent(Event.DestroyRequested); volResult.setResult(result.getResult()); + + try { + destroyAndReallocateManagedVolume((VolumeInfo) vo); + } catch (CloudRuntimeException ex) { + s_logger.warn("Couldn't destroy managed volume: " + vo.getId()); + } } AsyncCallFuture future = context.getFuture(); @@ -1093,15 +1102,13 @@ public class VolumeServiceImpl implements VolumeService { // Refresh the volume info from the DB. volumeInfo = volFactory.getVolume(volumeInfo.getId(), destPrimaryDataStore); + volumeInfo.processEvent(Event.CreateRequested); CreateVolumeFromBaseImageContext context = new CreateVolumeFromBaseImageContext<>(null, volumeInfo, destPrimaryDataStore, srcTemplateOnPrimary, future, null); - AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); - caller.setCallback(caller.getTarget().createVolumeFromBaseManagedImageCallBack(null, null)); caller.setContext(context); Map details = new HashMap(); - details.put(PrimaryDataStore.MANAGED, Boolean.TRUE.toString()); details.put(PrimaryDataStore.STORAGE_HOST, destPrimaryDataStore.getHostAddress()); details.put(PrimaryDataStore.STORAGE_PORT, String.valueOf(destPrimaryDataStore.getPort())); @@ -1122,16 +1129,12 @@ public class VolumeServiceImpl implements VolumeService { throw e; } catch (Throwable e) { s_logger.debug("Failed to copy managed template on primary storage", e); - String errMsg = e.toString(); - volumeInfo.processEvent(Event.DestroyRequested); + String errMsg = "Failed due to " + e.toString(); try { - AsyncCallFuture expungeVolumeFuture = expungeVolumeAsync(volumeInfo); - VolumeApiResult expungeVolumeResult = expungeVolumeFuture.get(); - if (expungeVolumeResult.isFailed()) { - errMsg += " : Failed to expunge a volume that was created"; - } - } catch (Exception ex) { + destroyAndReallocateManagedVolume(volumeInfo); + } catch (CloudRuntimeException ex) { + s_logger.warn("Failed to destroy managed volume: " + volumeInfo.getId()); errMsg += " : " + ex.getMessage(); } @@ -1148,6 +1151,44 @@ public class VolumeServiceImpl implements VolumeService { } } + private void destroyAndReallocateManagedVolume(VolumeInfo volumeInfo) { + if (volumeInfo == null) { + return; + } + + VolumeVO volume = volDao.findById(volumeInfo.getId()); + if (volume == null) { + return; + } + + if (volume.getState() == State.Allocated) { // Possible states here: Allocated, Ready & Creating + return; + } + + volumeInfo.processEvent(Event.DestroyRequested); + + Volume newVol = _volumeMgr.allocateDuplicateVolume(volume, null); + VolumeVO newVolume = (VolumeVO) newVol; + newVolume.set_iScsiName(null); + volDao.update(newVolume.getId(), newVolume); + s_logger.debug("Allocated new volume: " + newVolume.getId() + " for the VM: " + volume.getInstanceId()); + + try { + AsyncCallFuture expungeVolumeFuture = expungeVolumeAsync(volumeInfo); + VolumeApiResult expungeVolumeResult = expungeVolumeFuture.get(); + if (expungeVolumeResult.isFailed()) { + s_logger.warn("Failed to expunge volume: " + volumeInfo.getId() + " that was created"); + throw new CloudRuntimeException("Failed to expunge volume: " + volumeInfo.getId() + " that was created"); + } + } catch (Exception ex) { + if (canVolumeBeRemoved(volumeInfo.getId())) { + volDao.remove(volumeInfo.getId()); + } + s_logger.warn("Unable to expunge volume: " + volumeInfo.getId() + " due to: " + ex.getMessage()); + throw new CloudRuntimeException("Unable to expunge volume: " + volumeInfo.getId() + " due to: " + ex.getMessage()); + } + } + private void createManagedVolumeCopyTemplateAsync(VolumeInfo volumeInfo, PrimaryDataStore primaryDataStore, TemplateInfo srcTemplateInfo, Host destHost, AsyncCallFuture future) { try { // Create a volume on managed storage. diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java index 4e301d0aa41..33ca12a36a6 100644 --- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java @@ -3093,6 +3093,11 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic volumeToAttach.setPath(volumeToAttach.get_iScsiName()); _volsDao.update(volumeToAttach.getId(), volumeToAttach); } + + if (host != null && volumeToAttachStoragePool.getPoolType() == Storage.StoragePoolType.PowerFlex) { + // Unmap the volume on PowerFlex/ScaleIO pool for stopped VM + volService.revokeAccess(volFactory.getVolume(volumeToAttach.getId()), host, dataStore); + } } // insert record for disk I/O statistics