bug CS-14785: Improvements to volumes sync so that it can recover from any error. Introduced new state UploadOp which signifies that the volume os on secondary and the status would be picked up from volume host ref table.

This commit is contained in:
Nitin Mehta 2012-05-11 11:38:07 +05:30
parent 562dd29bfb
commit 838d01754b
6 changed files with 36 additions and 52 deletions

View File

@ -135,7 +135,6 @@ public class DownloadCommand extends AbstractDownloadCommand {
//this.hvm = volume.isRequiresHvm();
this.checksum = checkSum;
this.id = volume.getId();
//this.description = volume.get;
this.setSecUrl(secUrl);
this.maxDownloadSizeInBytes = maxDownloadSizeInBytes;
this.resourceType = ResourceType.VOLUME;

View File

@ -32,9 +32,7 @@ public interface Volume extends ControlledEntity, BasedOn, StateObject<Volume.St
Snapshotting("There is a snapshot created on this volume, not backed up to secondary storage yet"),
Expunging("The volume is being expunging"),
Destroy("The volume is destroyed, and can't be recovered."),
Uploading ("The volume upload is in progress"),
Uploaded ("The volume is uploaded and present on secondary storage"),
UploadError ("The volume couldnt be uploaded");
UploadOp ("The volume upload operation is in progress");
String _description;
@ -59,15 +57,9 @@ public interface Volume extends ControlledEntity, BasedOn, StateObject<Volume.St
s_fsm.addTransition(Creating, Event.OperationSucceeded, Ready);
s_fsm.addTransition(Creating, Event.DestroyRequested, Destroy);
s_fsm.addTransition(Creating, Event.CreateRequested, Creating);
s_fsm.addTransition(Allocated, Event.UploadRequested, Uploading);
s_fsm.addTransition(Uploading, Event.UploadSucceeded, Uploaded);
s_fsm.addTransition(Uploading, Event.OperationFailed, UploadError);
s_fsm.addTransition(UploadError, Event.DestroyRequested, Destroy);
s_fsm.addTransition(Uploaded, Event.UploadSucceeded, Uploaded);
s_fsm.addTransition(Uploaded, Event.CopyRequested, Creating);
s_fsm.addTransition(Uploaded, Event.DestroyRequested, Destroy);
s_fsm.addTransition(Allocated, Event.UploadRequested, UploadOp);
s_fsm.addTransition(Creating, Event.CopySucceeded, Ready);
s_fsm.addTransition(Creating, Event.CopyFailed, Uploaded);
s_fsm.addTransition(UploadOp, Event.CopySucceeded, Ready);
s_fsm.addTransition(Ready, Event.DestroyRequested, Destroy);
s_fsm.addTransition(Destroy, Event.ExpungingRequested, Expunging);
s_fsm.addTransition(Ready, Event.SnapshotRequested, Snapshotting);
@ -89,7 +81,6 @@ public interface Volume extends ControlledEntity, BasedOn, StateObject<Volume.St
OperationSucceeded,
OperationRetry,
UploadRequested,
UploadSucceeded,
MigrationRequested,
SnapshotRequested,
DestroyRequested,

View File

@ -1019,7 +1019,7 @@ public class ApiResponseHelper implements ResponseGenerator {
volResponse.setCreated(volume.getCreated());
volResponse.setState(volume.getState().toString());
if(volume.getState() == Volume.State.Uploading || volume.getState() == Volume.State.Uploaded){
if(volume.getState() == Volume.State.UploadOp){
com.cloud.storage.VolumeHostVO volumeHostRef = ApiDBUtils.findVolumeHostRef(volume.getId(), volume.getDataCenterId());
volResponse.setSize(volumeHostRef.getSize());
volResponse.setCreated(volumeHostRef.getCreated());
@ -1031,12 +1031,19 @@ public class ApiResponseHelper implements ResponseGenerator {
} else {
volumeStatus = volumeHostRef.getDownloadPercent() + "% Uploaded";
}
volResponse.setState("Uploading");
} else {
volumeStatus = volumeHostRef.getErrorString();
if(volumeHostRef.getDownloadState() == VMTemplateHostVO.Status.NOT_DOWNLOADED){
volResponse.setState("UploadNotStarted");
}else {
volResponse.setState("UploadError");
}
}
volResponse.setStatus(volumeStatus);
} else if (volumeHostRef.getDownloadState() == VMTemplateHostVO.Status.DOWNLOADED) {
volResponse.setStatus("Upload Complete");
volResponse.setState("Uploaded");
} else {
volResponse.setStatus("Successfully Installed");
}
@ -1047,7 +1054,7 @@ public class ApiResponseHelper implements ResponseGenerator {
String storageType;
try {
if (volume.getPoolId() == null) {
if (volume.getState() == Volume.State.Allocated || volume.getState() == Volume.State.Uploaded || volume.getState() == Volume.State.Uploading) {
if (volume.getState() == Volume.State.Allocated || volume.getState() == Volume.State.UploadOp) {
/* set it as shared, so the UI can attach it to VM */
storageType = "shared";
} else {

View File

@ -724,8 +724,7 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
// Find a suitable storage to create volume on
StoragePoolVO destPool = findStoragePool(dskCh, dc, pod, clusterId, vm, avoidPools);
// Copy the volume from secondary storage to the destination storage pool
stateTransitTo(volume, Event.CopyRequested);
// Copy the volume from secondary storage to the destination storage pool
VolumeHostVO volumeHostVO = _volumeHostDao.findByVolumeId(volume.getId());
HostVO secStorage = _hostDao.findById(volumeHostVO.getHostId());
String secondaryStorageURL = secStorage.getStorageUrl();
@ -1754,10 +1753,10 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
throw new InvalidParameterValueException("Please specify a valid " + format.toLowerCase());
}
if ((format.equalsIgnoreCase("vhd") && (!url.toLowerCase().endsWith("vhd") && !url.toLowerCase().endsWith("vhd.zip") && !url.toLowerCase().endsWith("vhd.bz2") && !url.toLowerCase().endsWith("vhd.gz") ))
|| (format.equalsIgnoreCase("qcow2") && (!url.toLowerCase().endsWith("qcow2") && !url.toLowerCase().endsWith("qcow2.zip") && !url.toLowerCase().endsWith("qcow2.bz2") && !url.toLowerCase().endsWith("qcow2.gz") ))
|| (format.equalsIgnoreCase("ova") && (!url.toLowerCase().endsWith("ova") && !url.toLowerCase().endsWith("ova.zip") && !url.toLowerCase().endsWith("ova.bz2") && !url.toLowerCase().endsWith("ova.gz")))
|| (format.equalsIgnoreCase("raw") && (!url.toLowerCase().endsWith("img") && !url.toLowerCase().endsWith("raw")))) {
if ((format.equalsIgnoreCase("vhd") && (!url.toLowerCase().endsWith(".vhd") && !url.toLowerCase().endsWith("vhd.zip") && !url.toLowerCase().endsWith("vhd.bz2") && !url.toLowerCase().endsWith("vhd.gz") ))
|| (format.equalsIgnoreCase("qcow2") && (!url.toLowerCase().endsWith(".qcow2") && !url.toLowerCase().endsWith("qcow2.zip") && !url.toLowerCase().endsWith("qcow2.bz2") && !url.toLowerCase().endsWith("qcow2.gz") ))
|| (format.equalsIgnoreCase("ova") && (!url.toLowerCase().endsWith(".ova") && !url.toLowerCase().endsWith("ova.zip") && !url.toLowerCase().endsWith("ova.bz2") && !url.toLowerCase().endsWith("ova.gz")))
|| (format.equalsIgnoreCase("raw") && (!url.toLowerCase().endsWith(".img") && !url.toLowerCase().endsWith("raw")))) {
throw new InvalidParameterValueException("Please specify a valid URL. URL:" + url + " is an invalid for the format " + format.toLowerCase());
}
validateUrl(url);

View File

@ -542,13 +542,6 @@ public class DownloadMonitorImpl implements DownloadMonitor {
txn.start();
if (dnldStatus == Status.DOWNLOADED) {
// Do the volume state transition
try {
_storageMgr.stateTransitTo(volume, Event.UploadSucceeded);
} catch (NoTransitionException e) {
e.printStackTrace();
}
//Create usage event
long size = -1;
@ -563,13 +556,7 @@ public class DownloadMonitorImpl implements DownloadMonitor {
UsageEventVO usageEvent = new UsageEventVO(eventType, volume.getAccountId(), host.getDataCenterId(), volume.getId(), volume.getName(), null, 0l , size);
_usageEventDao.persist(usageEvent);
}
}else if (dnldStatus == Status.DOWNLOAD_ERROR){
//Transistion the volume state
try {
_storageMgr.stateTransitTo(volume, Volume.Event.OperationFailed);
} catch (NoTransitionException e) {
throw new CloudRuntimeException("Unable to update the failure on a volume: " + volume, e);
}
}else if (dnldStatus == Status.DOWNLOAD_ERROR || dnldStatus == Status.ABANDONED || dnldStatus == Status.UNKNOWN){
//Decrement the volume count
_resourceLimitMgr.decrementResourceCount(volume.getAccountId(), com.cloud.configuration.Resource.ResourceType.volume);
}
@ -737,27 +724,25 @@ public class DownloadMonitorImpl implements DownloadMonitor {
toBeDownloaded.add(volumeHost);
}
} else {
} else { // Put them in right status
volumeHost.setDownloadPercent(100);
volumeHost.setDownloadState(Status.DOWNLOADED);
volumeHost.setInstallPath(volInfo.getInstallPath());
volumeHost.setSize(volInfo.getSize());
volumeHost.setPhysicalSize(volInfo.getPhysicalSize());
volumeHost.setLastUpdated(new Date());
if (volume.getState() == Volume.State.Uploading){
try {
_storageMgr.stateTransitTo(volume, Event.UploadSucceeded);
} catch (NoTransitionException e) {
e.printStackTrace();
}
}
volumeHost.setLastUpdated(new Date());
_volumeHostDao.update(volumeHost.getId(), volumeHost);
}
continue;
}
// Volume is not on secondary but we should download.
if (volumeHost.getDownloadState() != Status.DOWNLOADED) {
s_logger.info("Volume Sync did not find " + volume.getName() + " ready on server " + sserverId + ", will request download to start/resume shortly");
toBeDownloaded.add(volumeHost);
}
}
//Download volumes which havent been downloaded yet.
//Download volumes which haven't been downloaded yet.
if (toBeDownloaded.size() > 0) {
for (VolumeHostVO volumeHost : toBeDownloaded) {
if (volumeHost.getDownloadUrl() == null) { // If url is null we can't initiate the download

View File

@ -556,16 +556,19 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
boolean volumeOnSec = false;
VolumeHostVO volHostVO = _volumeHostDao.findByVolumeId(volume.getId());
if (volHostVO != null){
volumeOnSec = true;
volumeOnSec = true;
if( !(volHostVO.getDownloadState() == Status.DOWNLOADED) ){
throw new InvalidParameterValueException("Volume is not uploaded yet. Please try this operation once the volume is uploaded");
}
}
// Check that the volume is stored on shared storage
if (!(Volume.State.Allocated.equals(volume.getState()) || Volume.State.Uploaded.equals(volume.getState())) && !_storageMgr.volumeOnSharedStoragePool(volume)) {
//If the volume is Ready, check that the volume is stored on shared storage
if (!(Volume.State.Allocated.equals(volume.getState()) || Volume.State.UploadOp.equals(volume.getState())) && !_storageMgr.volumeOnSharedStoragePool(volume)) {
throw new InvalidParameterValueException("Please specify a volume that has been created on a shared storage pool.");
}
if ( !(Volume.State.Allocated.equals(volume.getState()) || Volume.State.Ready.equals(volume.getState()) || Volume.State.Uploaded.equals(volume.getState())) ) {
throw new InvalidParameterValueException("Volume state must be in Allocated, Ready or Uploaded state");
if ( !(Volume.State.Allocated.equals(volume.getState()) || Volume.State.Ready.equals(volume.getState())) ) {
throw new InvalidParameterValueException("Volume state must be in Allocated or Ready state");
}
VolumeVO rootVolumeOfVm = null;
@ -578,7 +581,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
HypervisorType rootDiskHyperType = _volsDao.getHypervisorType(rootVolumeOfVm.getId());
if (volume.getState().equals(Volume.State.Allocated) || volume.getState().equals(Volume.State.Uploaded)) {
if (volume.getState().equals(Volume.State.Allocated) || volume.getState().equals(Volume.State.UploadOp)) {
/* Need to create the volume */
VMTemplateVO rootDiskTmplt = _templateDao.findById(vm.getTemplateId());
DataCenterVO dcVO = _dcDao.findById(vm.getDataCenterIdToDeployIn());