bug 4286: Fixing the extract functionality for Upload after new API framework. Also added a check to avoid system created templates and ISO's from getting extracted as per Mike.

status 4286: resolved fixed
This commit is contained in:
nit 2010-11-04 19:09:38 +05:30
parent 6dea64c63a
commit 7dc7a4838a
11 changed files with 121 additions and 80 deletions

View File

@ -542,8 +542,10 @@ public class UploadManagerImpl implements UploadManager {
case ABORTED:
case NOT_STARTED:
case UNRECOVERABLE_ERROR:
// TODO
uj.cleanup();
// Delete the entity only if its a volume. TO DO - find a better way of finding it a volume.
if(uj.getTemplateUploader().getUploadLocalPath().indexOf("volume") > -1){
uj.cleanup();
}
break;
case UNKNOWN:
return;
@ -567,7 +569,10 @@ public class UploadManagerImpl implements UploadManager {
tu.setStatus(Status.POST_UPLOAD_FINISHED);
tu.setUploadError("Upload completed successfully at " + new SimpleDateFormat().format(new Date()));
}
uj.cleanup();
// Delete the entity only if its a volume. TO DO - find a better way of finding it a volume.
if(uj.getTemplateUploader().getUploadLocalPath().indexOf("volume") > -1){
uj.cleanup();
}
break;
default:
break;

View File

@ -118,11 +118,12 @@ public class ExtractIsoCmd extends BaseAsyncCmd {
response.setState(uploadInfo.getUploadState().toString());
response.setAccountId(getAccountId());
//FIX ME - Need to set the url once the gson jar is upgraded since it is throwing an error right now due to a bug.
//response.setUrl(uploadInfo.getUploadUrl());
//response.setUrl(uploadInfo.getUploadUrl());
response.setUrl(uploadInfo.getUploadUrl().replaceAll("/", "%2F"));
return response;
}
public static String getStaticName() {
return "ExtractIso";
return s_name;
}
}

View File

@ -83,7 +83,7 @@ public class ExtractTemplateCmd extends BaseAsyncCmd {
}
public static String getStaticName() {
return "ExtractTemplate";
return s_name;
}
@Override
@ -124,6 +124,7 @@ public class ExtractTemplateCmd extends BaseAsyncCmd {
response.setAccountId(getAccountId());
//FIX ME - Need to set the url once the gson jar is upgraded since it is throwing an error right now.
//response.setUrl(uploadInfo.getUploadUrl());
response.setUrl(uploadInfo.getUploadUrl().replaceAll("/", "%2F"));
return response;
}
}

View File

@ -121,11 +121,11 @@ public class ExtractVolumeCmd extends BaseAsyncCmd {
response.setState(uploadInfo.getUploadState().toString());
response.setAccountId(getAccountId());
//FIX ME - Need to set the url once the gson jar is upgraded since it is throwing an error right now.
//response.setUrl(uploadInfo.getUploadUrl());
response.setUrl(uploadInfo.getUploadUrl().replaceAll("/", "%2F"));
return response;
}
public static String getStaticName() {
return "ExtractVolume";
return s_name;
}
}

View File

@ -74,10 +74,10 @@ public class ExtractResponse extends BaseResponse {
public ExtractResponse(){
}
public ExtractResponse(Long volumeId, String volName, long accountId,
public ExtractResponse(Long typeId, String typeName, long accountId,
String state, Long uploadId) {
this.id = volumeId;
this.name = volName;
this.id = typeId;
this.name = typeName;
this.accountId = accountId;
this.state = state;
this.uploadId = uploadId;

View File

@ -5725,6 +5725,9 @@ public class ManagementServerImpl implements ManagementServer {
if (_dcDao.findById(zoneId) == null) {
throw new ServerApiException(BaseCmd.PARAM_ERROR, "Please specify a valid zone.");
}
if(volume.getPoolId() == null){
throw new ServerApiException(BaseCmd.PARAM_ERROR, "The volume doesnt belong to a storage pool so cant extract it");
}
//Extract activity only for detached volumes or for volumes whose instance is stopped
if(volume.getInstanceId() != null && ApiDBUtils.findVMInstanceById(volume.getInstanceId()).getState() != State.Stopped ){
s_logger.debug("Invalid state of the volume with ID: " + volumeId + ". It should be either detached or the VM should be in stopped state.");

View File

@ -1,6 +1,7 @@
package com.cloud.storage.upload;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@ -21,6 +22,10 @@ import com.cloud.agent.api.storage.UploadAnswer;
import com.cloud.agent.api.storage.UploadCommand;
import com.cloud.agent.api.storage.UploadProgressCommand;
import com.cloud.agent.api.storage.UploadProgressCommand.RequestType;
import com.cloud.api.commands.ExtractIsoCmd;
import com.cloud.api.commands.ExtractTemplateCmd;
import com.cloud.api.commands.ExtractVolumeCmd;
import com.cloud.api.response.ExtractResponse;
import com.cloud.async.AsyncJobManager;
import com.cloud.async.AsyncJobResult;
import com.cloud.async.executor.ExtractJobResultObject;
@ -75,6 +80,15 @@ public class UploadListener implements Listener {
public static final String UPLOAD_ERROR=Status.UPLOAD_ERROR.toString();
public static final String UPLOAD_IN_PROGRESS=Status.UPLOAD_IN_PROGRESS.toString();
public static final String UPLOAD_ABANDONED=Status.ABANDONED.toString();
public static final Map<String,String> responseNameMap;
static{
Map<String, String>tempMap = new HashMap<String, String>();
tempMap.put(Type.ISO.toString(), ExtractIsoCmd.getStaticName());
tempMap.put(Type.TEMPLATE.toString(), ExtractTemplateCmd.getStaticName());
tempMap.put(Type.VOLUME.toString(), ExtractVolumeCmd.getStaticName());
tempMap.put("DEFAULT","extractresponse");
responseNameMap = Collections.unmodifiableMap(tempMap);
}
private HostVO sserver;
@ -101,7 +115,7 @@ public class UploadListener implements Listener {
private long asyncJobId;
private long eventId;
private AsyncJobManager asyncMgr;
private ExtractJobResultObject resultObj;
private ExtractResponse resultObj;
public AsyncJobManager getAsyncMgr() {
return asyncMgr;
@ -131,13 +145,13 @@ public class UploadListener implements Listener {
private Long uploadId;
public UploadListener(HostVO host, Timer _timer, UploadDao uploadDao,
Long uploadId, UploadMonitorImpl uploadMonitor, UploadCommand cmd,
UploadVO uploadObj, UploadMonitorImpl uploadMonitor, UploadCommand cmd,
Long accountId, String typeName, Type type, long eventId, long asyncJobId, AsyncJobManager asyncMgr) {
this.sserver = host;
this.uploadDao = uploadDao;
this.uploadMonitor = uploadMonitor;
this.cmd = cmd;
this.uploadId = uploadId;
this.uploadId = uploadObj.getId();
this.accountId = accountId;
this.typeName = typeName;
this.type = type;
@ -149,7 +163,8 @@ public class UploadListener implements Listener {
this.eventId = eventId;
this.asyncJobId = asyncJobId;
this.asyncMgr = asyncMgr;
this.resultObj = new ExtractJobResultObject(accountId, typeName, Status.NOT_UPLOADED.toString(), 0, uploadId);
this.resultObj = new ExtractResponse(uploadObj.getTypeId(), typeName, accountId, Status.NOT_UPLOADED.toString(), uploadId);
resultObj.setResponseName(responseNameMap.get(type.toString()));
updateDatabase(Status.NOT_UPLOADED, cmd.getUrl(),"");
}
@ -322,7 +337,7 @@ public class UploadListener implements Listener {
}
public void updateDatabase(Status state, String uploadErrorString) {
resultObj.setResult_string(uploadErrorString);
resultObj.setResultString(uploadErrorString);
resultObj.setState(state.toString());
asyncMgr.updateAsyncJobAttachment(asyncJobId, type.toString(), 1L);
asyncMgr.updateAsyncJobStatus(asyncJobId, AsyncJobResult.STATUS_IN_PROGRESS, resultObj);
@ -335,7 +350,7 @@ public class UploadListener implements Listener {
}
public void updateDatabase(Status state, String uploadUrl,String uploadErrorString) {
resultObj.setResult_string(uploadErrorString);
resultObj.setResultString(uploadErrorString);
resultObj.setState(state.toString());
asyncMgr.updateAsyncJobAttachment(asyncJobId, type.toString(), 1L);
asyncMgr.updateAsyncJobStatus(asyncJobId, AsyncJobResult.STATUS_IN_PROGRESS, resultObj);
@ -359,9 +374,9 @@ public class UploadListener implements Listener {
public synchronized void updateDatabase(UploadAnswer answer) {
if(answer.getErrorString().startsWith("553")){
answer.setErrorString(answer.getErrorString().concat(". Please check if the file name already exists."));
answer.setErrorString(answer.getErrorString().concat("Please check if the file name already exists."));
}
resultObj.setResult_string(answer.getErrorString());
resultObj.setResultString(answer.getErrorString());
resultObj.setState(answer.getUploadStatus().toString());
resultObj.setUploadPercent(answer.getUploadPct());
@ -369,6 +384,7 @@ public class UploadListener implements Listener {
asyncMgr.updateAsyncJobAttachment(asyncJobId, type.toString(), 1L);
asyncMgr.updateAsyncJobStatus(asyncJobId, AsyncJobResult.STATUS_IN_PROGRESS, resultObj);
}else if(answer.getUploadStatus() == Status.UPLOADED){
resultObj.setResultString("Success");
asyncMgr.completeAsyncJob(asyncJobId, AsyncJobResult.STATUS_SUCCEEDED, 1, resultObj);
}else{
asyncMgr.completeAsyncJob(asyncJobId, AsyncJobResult.STATUS_FAILED, 2, resultObj);

View File

@ -38,7 +38,7 @@ public interface UploadMonitor extends Manager{
public void cancelAllUploads(Long templateId);
public void extractTemplate(VMTemplateVO template, String url,
public Long extractTemplate(VMTemplateVO template, String url,
VMTemplateHostVO tmpltHostRef,Long dataCenterId, long eventId, long asyncJobId, AsyncJobManager asyncMgr);
boolean isTypeUploadInProgress(Long typeId, Type type);

View File

@ -30,6 +30,7 @@ import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.event.EventTypes;
import com.cloud.event.EventVO;
import com.cloud.event.dao.EventDao;
import com.cloud.exception.InternalErrorException;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
@ -133,7 +134,7 @@ public class UploadMonitorImpl implements UploadMonitor {
start();
UploadCommand ucmd = new UploadCommand(url, volume.getId(), volume.getSize(), installPath, Type.VOLUME);
UploadListener ul = new UploadListener(sserver, _timer, _uploadDao, uploadVolumeObj.getId(), this, ucmd, volume.getAccountId(), volume.getName(), Type.VOLUME, eventId, asyncJobId, asyncMgr);
UploadListener ul = new UploadListener(sserver, _timer, _uploadDao, uploadVolumeObj, this, ucmd, volume.getAccountId(), volume.getName(), Type.VOLUME, eventId, asyncJobId, asyncMgr);
_listenerMap.put(uploadVolumeObj, ul);
long result = send(sserver.getId(), ucmd, ul);
@ -146,7 +147,7 @@ public class UploadMonitorImpl implements UploadMonitor {
}
@Override
public void extractTemplate( VMTemplateVO template, String url,
public Long extractTemplate( VMTemplateVO template, String url,
VMTemplateHostVO vmTemplateHost,Long dataCenterId, long eventId, long asyncJobId, AsyncJobManager asyncMgr){
Type type = (template.getFormat() == ImageFormat.ISO) ? Type.ISO : Type.TEMPLATE ;
@ -161,7 +162,7 @@ public class UploadMonitorImpl implements UploadMonitor {
if(vmTemplateHost != null) {
start();
UploadCommand ucmd = new UploadCommand(template, url, vmTemplateHost);
UploadListener ul = new UploadListener(sserver, _timer, _uploadDao, uploadTemplateObj.getId(), this, ucmd, template.getAccountId(), template.getName(), type, eventId, asyncJobId, asyncMgr);
UploadListener ul = new UploadListener(sserver, _timer, _uploadDao, uploadTemplateObj, this, ucmd, template.getAccountId(), template.getName(), type, eventId, asyncJobId, asyncMgr);
_listenerMap.put(uploadTemplateObj, ul);
long result = send(sserver.getId(), ucmd, ul);
@ -170,16 +171,16 @@ public class UploadMonitorImpl implements UploadMonitor {
ul.setDisconnected();
ul.scheduleStatusCheck(RequestType.GET_OR_RESTART);
}
}
}
return uploadTemplateObj.getId();
}
return null;
}
@Override
public UploadVO createEntityDownloadURL(VMTemplateVO template, VMTemplateHostVO vmTemplateHost, Long dataCenterId, long eventId) {
String errorString = "";
boolean success = false;
List<HostVO> storageServers = _serverDao.listByTypeDataCenter(Host.Type.SecondaryStorage, dataCenterId);
if(storageServers == null )
throw new CloudRuntimeException("No Storage Server found at the datacenter - " +dataCenterId);
@ -197,38 +198,46 @@ public class UploadMonitorImpl implements UploadMonitor {
Status.DOWNLOAD_URL_NOT_CREATED, 0, type, Mode.HTTP_DOWNLOAD);
uploadTemplateObj.setInstallPath(vmTemplateHost.getInstallPath());
_uploadDao.persist(uploadTemplateObj);
// Create Symlink at ssvm
CreateEntityDownloadURLCommand cmd = new CreateEntityDownloadURLCommand(vmTemplateHost.getInstallPath());
long result = send(sserver.getId(), cmd, null);
if (result == -1){
s_logger.warn("Unable to create a link for the template/iso ");
throw new CloudRuntimeException("Unable to create a link at the SSVM");
try{
// Create Symlink at ssvm
CreateEntityDownloadURLCommand cmd = new CreateEntityDownloadURLCommand(vmTemplateHost.getInstallPath());
long result = send(sserver.getId(), cmd, null);
if (result == -1){
errorString = "Unable to create a link for " +type+ " id:"+template.getId();
s_logger.error(errorString);
throw new CloudRuntimeException(errorString);
}
//Construct actual URL locally now that the symlink exists at SSVM
List<SecondaryStorageVmVO> ssVms = _secStorageVmDao.getSecStorageVmListInStates(dataCenterId, State.Running);
if (ssVms.size() > 0) {
SecondaryStorageVmVO ssVm = ssVms.get(0);
if (ssVm.getPublicIpAddress() == null) {
errorString = "A running secondary storage vm has a null public ip?";
s_logger.error(errorString);
throw new CloudRuntimeException(errorString);
}
String extractURL = generateCopyUrl(ssVm.getPublicIpAddress(), vmTemplateHost.getInstallPath());
UploadVO vo = _uploadDao.createForUpdate();
vo.setLastUpdated(new Date());
vo.setUploadUrl(extractURL);
vo.setUploadState(Status.DOWNLOAD_URL_CREATED);
_uploadDao.update(uploadTemplateObj.getId(), vo);
success = true;
return _uploadDao.findById(uploadTemplateObj.getId(), true);
}
errorString = "Couldnt find a running SSVM in the zone" + dataCenterId+ ". Couldnt create the extraction URL.";
throw new CloudRuntimeException(errorString);
}finally{
if(!success){
UploadVO uploadJob = _uploadDao.createForUpdate(uploadTemplateObj.getId());
uploadJob.setLastUpdated(new Date());
uploadJob.setErrorString(errorString);
uploadJob.setUploadState(Status.ERROR);
_uploadDao.update(uploadTemplateObj.getId(), uploadJob);
}
}
//Construct actual URL locally now that the symlink exists at SSVM
List<SecondaryStorageVmVO> ssVms = _secStorageVmDao.getSecStorageVmListInStates(dataCenterId, State.Running);
if (ssVms.size() > 0) {
SecondaryStorageVmVO ssVm = ssVms.get(0);
if (ssVm.getPublicIpAddress() == null) {
s_logger.warn("A running secondary storage vm has a null public ip?");
throw new CloudRuntimeException("SSVM has null public IP - couldnt create the URL");
}
String extractURL = generateCopyUrl(ssVm.getPublicIpAddress(), vmTemplateHost.getInstallPath());
UploadVO vo = _uploadDao.createForUpdate();
vo.setLastUpdated(new Date());
vo.setUploadUrl(extractURL);
vo.setUploadState(Status.DOWNLOAD_URL_CREATED);
if(extractURL == null){
vo.setUploadState(Status.ERROR);
vo.setErrorString("Could not create the download URL");
}
_uploadDao.update(uploadTemplateObj.getId(), vo);
return _uploadDao.findById(uploadTemplateObj.getId(), true);
}
throw new CloudRuntimeException("Couldnt find a running SSVM in the zone" + dataCenterId+ ". Couldnt create the extraction URL.");
}
@Override
@ -350,13 +359,12 @@ public class UploadMonitorImpl implements UploadMonitor {
public String getEvent(Type type){
if(type == Type.TEMPLATE) return EventTypes.EVENT_TEMPLATE_UPLOAD;
if(type == Type.ISO) return EventTypes.EVENT_ISO_UPLOAD;
if(type == Type.VOLUME) return EventTypes.EVENT_VOLUME_UPLOAD;
if(type == Type.TEMPLATE) return EventTypes.EVENT_TEMPLATE_EXTRACT;
if(type == Type.ISO) return EventTypes.EVENT_ISO_EXTRACT;
if(type == Type.VOLUME) return EventTypes.EVENT_VOLUME_EXTRACT;
return null;
}
}
public void handleUploadEvent(HostVO host, Long accountId, String typeName, Type type, Long uploadId, com.cloud.storage.Upload.Status reason, long eventId) {
if ((reason == Upload.Status.UPLOADED) || (reason==Upload.Status.ABANDONED)){

View File

@ -34,6 +34,7 @@ import com.cloud.api.commands.RegisterTemplateCmd;
import com.cloud.async.AsyncJobManager;
import com.cloud.exception.InternalErrorException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.StorageUnavailableException;
import com.cloud.storage.Storage.ImageFormat;
@ -190,7 +191,19 @@ public interface TemplateManager extends Manager {
*/
boolean deleteIso(DeleteIsoCmd cmd);
void extract(VMTemplateVO template, String url, VMTemplateHostVO tmpltHostRef, Long zoneId, long eventId, long asyncJobId, AsyncJobManager asyncMgr);
Long extract(ExtractIsoCmd cmd);
Long extract(ExtractTemplateCmd cmd);
/**
* Extracts an ISO
* @param cmd - the command specifying the mode and id of the ISO
* @return extractId.
* @throws InvalidParameterValueException, InternalErrorException, PermissionDeniedException
*/
Long extract(ExtractIsoCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, InternalErrorException;
/**
* Extracts a Template
* @param cmd - the command specifying the mode and id of the template
* @return extractId.
* @throws InvalidParameterValueException, InternalErrorException, PermissionDeniedException
*/
Long extract(ExtractTemplateCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, InternalErrorException;
}

View File

@ -443,8 +443,8 @@ public class TemplateManagerImpl implements TemplateManager {
if (template == null) {
throw new InvalidParameterValueException("Unable to find " +desc+ " with id " + templateId);
}
if (template.getName().startsWith("xs-tools") ){
throw new InvalidParameterValueException("Unable to extract the ISO " + template.getName() + " It is not allowed");
if (template.getId() < 201 ){
throw new InvalidParameterValueException("Unable to extract the " + desc + " " + template.getName() + " since it is system created and is not available for download");
}
if (isISO) {
if (template.getFormat() != ImageFormat.ISO ){
@ -484,7 +484,7 @@ public class TemplateManagerImpl implements TemplateManager {
Upload.Mode extractMode;
if( mode == null || (!mode.equals(Upload.Mode.FTP_UPLOAD.toString()) && !mode.equals(Upload.Mode.HTTP_DOWNLOAD.toString())) ){
throw new ServerApiException(BaseCmd.PARAM_ERROR, "Please specify a valid extract Mode ");
throw new ServerApiException(BaseCmd.PARAM_ERROR, "Please specify a valid extract Mode "+Upload.Mode.values());
}else{
extractMode = mode.equals(Upload.Mode.FTP_UPLOAD.toString()) ? Upload.Mode.FTP_UPLOAD : Upload.Mode.HTTP_DOWNLOAD;
}
@ -499,7 +499,7 @@ public class TemplateManagerImpl implements TemplateManager {
if ((uri.getScheme() == null) || (!uri.getScheme().equalsIgnoreCase("ftp") )) {
throw new InvalidParameterValueException("Unsupported scheme for url: " + url);
}
} catch (URISyntaxException ex) {
} catch (Exception ex) {
throw new InvalidParameterValueException("Invalid url given: " + url);
}
@ -526,9 +526,8 @@ public class TemplateManagerImpl implements TemplateManager {
// String event = template.getFormat() == ImageFormat.ISO ? EventTypes.EVENT_ISO_UPLOAD : EventTypes.EVENT_TEMPLATE_UPLOAD;
// EventUtils.saveStartedEvent(template.getAccountId(), template.getAccountId(), event, "Starting upload of " +template.getName()+ " to " +url, cmd.getStartEventId());
EventUtils.saveStartedEvent(userId, accountId, event, "Starting extraction of " +template.getName()+ " mode= " +extractMode.toString(), eventId);
extract(template, url, tmpltHostRef, zoneId, eventId, job.getId(), mgr);
return 1L; //FIX ME
EventUtils.saveStartedEvent(userId, accountId, event, "Starting extraction of " +template.getName()+ " mode:" +extractMode.toString(), eventId);
return _uploadMonitor.extractTemplate(template, url, tmpltHostRef, zoneId, eventId, job.getId(), mgr);
}
EventUtils.saveStartedEvent(userId, accountId, event, "Starting extraction of " +template.getName()+ " in mode:" +extractMode.toString(), eventId);
@ -543,12 +542,7 @@ public class TemplateManagerImpl implements TemplateManager {
mgr.completeAsyncJob(job.getId(), AsyncJobResult.STATUS_FAILED, 2, null);
return null;
}
}
@Override
public void extract(VMTemplateVO template, String url, VMTemplateHostVO tmpltHostRef, Long zoneId, long eventId, long asyncJobId, AsyncJobManager asyncMgr){
_uploadMonitor.extractTemplate(template, url, tmpltHostRef, zoneId, eventId, asyncJobId, asyncMgr);
}
}
@Override @DB
public VMTemplateStoragePoolVO prepareTemplateForCreate(VMTemplateVO template, StoragePool pool) {