mirror of https://github.com/apache/cloudstack.git
Extending extract functionlity for volumes to allow download. The
extraction can have two modes FTP_UPLOAD and HTTP_DOWNLOAD. In the former one the user would provide the ftp url where the entity needs to be uploaded and in the later the user would be provided a HTTP URL where from he/she can download the entity. This url would be exposed for a specific time limit and would not function after the time limit
This commit is contained in:
parent
cfdd6999ad
commit
497c60d63d
15
core/src/com/cloud/agent/api/storage/DeleteEntityDownloadURLCommand.java
Normal file → Executable file
15
core/src/com/cloud/agent/api/storage/DeleteEntityDownloadURLCommand.java
Normal file → Executable file
|
|
@ -1,12 +1,16 @@
|
|||
package com.cloud.agent.api.storage;
|
||||
|
||||
import com.cloud.storage.Upload;
|
||||
|
||||
public class DeleteEntityDownloadURLCommand extends AbstractDownloadCommand {
|
||||
|
||||
String path;
|
||||
Upload.Type type;
|
||||
|
||||
public DeleteEntityDownloadURLCommand(String path) {
|
||||
public DeleteEntityDownloadURLCommand(String path, Upload.Type type) {
|
||||
super();
|
||||
this.path = path;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public DeleteEntityDownloadURLCommand() {
|
||||
|
|
@ -20,6 +24,13 @@ public class DeleteEntityDownloadURLCommand extends AbstractDownloadCommand {
|
|||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
|
||||
public Upload.Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(Upload.Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ public class EventTypes {
|
|||
public static final String EVENT_VOLUME_DELETE = "VOLUME.DELETE";
|
||||
public static final String EVENT_VOLUME_ATTACH = "VOLUME.ATTACH";
|
||||
public static final String EVENT_VOLUME_DETACH = "VOLUME.DETACH";
|
||||
public static final String EVENT_VOLUME_EXTRACT = "VOLUME.EXTRACT";
|
||||
public static final String EVENT_VOLUME_UPLOAD = "VOLUME.UPLOAD";
|
||||
|
||||
// Domains
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import com.cloud.agent.api.storage.UploadProgressCommand;
|
|||
import com.cloud.agent.api.storage.UploadCommand;
|
||||
import com.cloud.storage.StorageLayer;
|
||||
import com.cloud.storage.StorageResource;
|
||||
import com.cloud.storage.Upload;
|
||||
import com.cloud.storage.UploadVO;
|
||||
import com.cloud.storage.Storage.ImageFormat;
|
||||
import com.cloud.storage.template.TemplateUploader.UploadCompleteCallback;
|
||||
|
|
@ -338,7 +339,7 @@ public class UploadManagerImpl implements UploadManager {
|
|||
return new CreateEntityDownloadURLAnswer(errorString, CreateEntityDownloadURLAnswer.RESULT_FAILURE);
|
||||
}
|
||||
|
||||
// Create a symbolic link from the actual directory to the template location
|
||||
// Create a symbolic link from the actual directory to the template location. The entity would be directly visible under /var/www/html/
|
||||
cmd.getInstallPath();
|
||||
command = new Script("/bin/bash", s_logger);
|
||||
command.add("-c");
|
||||
|
|
@ -357,6 +358,7 @@ public class UploadManagerImpl implements UploadManager {
|
|||
@Override
|
||||
public DeleteEntityDownloadURLAnswer handleDeleteEntityDownloadURLCommand(DeleteEntityDownloadURLCommand cmd){
|
||||
|
||||
//Delete the soft link
|
||||
s_logger.debug("handleDeleteEntityDownloadURLCommand "+cmd.getPath());
|
||||
Script command = new Script("/bin/bash", s_logger);
|
||||
command.add("-c");
|
||||
|
|
@ -367,6 +369,20 @@ public class UploadManagerImpl implements UploadManager {
|
|||
s_logger.warn(errorString);
|
||||
return new DeleteEntityDownloadURLAnswer(errorString, CreateEntityDownloadURLAnswer.RESULT_FAILURE);
|
||||
}
|
||||
|
||||
// If its a volume also delete the Hard link
|
||||
if(cmd.getType() == Upload.Type.VOLUME){
|
||||
command = new Script("/bin/bash", s_logger);
|
||||
command.add("-c");
|
||||
command.add("rm -f " + publicTemplateRepo + cmd.getPath());
|
||||
result = command.execute();
|
||||
if (result != null) {
|
||||
String errorString = "Error in linking err=" + result;
|
||||
s_logger.warn(errorString);
|
||||
return new DeleteEntityDownloadURLAnswer(errorString, CreateEntityDownloadURLAnswer.RESULT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
return new DeleteEntityDownloadURLAnswer("", CreateEntityDownloadURLAnswer.RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,8 +23,10 @@ import com.cloud.api.ApiDBUtils;
|
|||
import com.cloud.api.BaseAsyncCmd;
|
||||
import com.cloud.api.Implementation;
|
||||
import com.cloud.api.Parameter;
|
||||
import com.cloud.api.BaseCmd.CommandType;
|
||||
import com.cloud.api.response.ExtractResponse;
|
||||
import com.cloud.event.EventTypes;
|
||||
import com.cloud.storage.UploadVO;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.user.Account;
|
||||
|
||||
|
|
@ -39,16 +41,19 @@ public class ExtractVolumeCmd extends BaseAsyncCmd {
|
|||
/////////////////////////////////////////////////////
|
||||
|
||||
//FIXME - add description
|
||||
@Parameter(name="id", type=CommandType.LONG, required=true)
|
||||
@Parameter(name="id", type=CommandType.LONG, required=true, description="the ID of the volume")
|
||||
private Long id;
|
||||
|
||||
//FIXME - add description
|
||||
@Parameter(name="url", type=CommandType.STRING, required=true)
|
||||
@Parameter(name="url", type=CommandType.STRING, required=false, description="the url to which the volume would be extracted")
|
||||
private String url;
|
||||
|
||||
//FIXME - add description
|
||||
@Parameter(name="zoneid", type=CommandType.LONG, required=true)
|
||||
@Parameter(name="zoneid", type=CommandType.LONG, required=true, description="the ID of the zone where the volume is located")
|
||||
private Long zoneId;
|
||||
|
||||
@Parameter(name="mode", type=CommandType.STRING, required=true, description="the mode of extraction - HTTP_DOWNLOAD or FTP_UPLOAD")
|
||||
private String mode;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
|
|
@ -65,12 +70,16 @@ public class ExtractVolumeCmd extends BaseAsyncCmd {
|
|||
public Long getZoneId() {
|
||||
return zoneId;
|
||||
}
|
||||
|
||||
public String getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public String getName() {
|
||||
return s_name;
|
||||
}
|
||||
|
|
@ -79,7 +88,7 @@ public class ExtractVolumeCmd extends BaseAsyncCmd {
|
|||
public long getAccountId() {
|
||||
VolumeVO volume = ApiDBUtils.findVolumeById(getId());
|
||||
if (volume != null) {
|
||||
return volume.getId();
|
||||
return volume.getAccountId();
|
||||
}
|
||||
|
||||
// invalid id, parent this command to SYSTEM so ERROR events are tracked
|
||||
|
|
@ -88,7 +97,7 @@ public class ExtractVolumeCmd extends BaseAsyncCmd {
|
|||
|
||||
@Override
|
||||
public String getEventType() {
|
||||
return EventTypes.EVENT_VOLUME_UPLOAD;
|
||||
return EventTypes.EVENT_VOLUME_EXTRACT;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -98,9 +107,22 @@ public class ExtractVolumeCmd extends BaseAsyncCmd {
|
|||
|
||||
@Override @SuppressWarnings("unchecked")
|
||||
public ExtractResponse getResponse() {
|
||||
ExtractResponse response = (ExtractResponse)getResponseObject();
|
||||
response.setResponseName(getName());
|
||||
return response;
|
||||
Long uploadId = (Long)getResponseObject();
|
||||
UploadVO uploadInfo = ApiDBUtils.findUploadById(uploadId);
|
||||
|
||||
ExtractResponse response = new ExtractResponse();
|
||||
response.setResponseName(getName());
|
||||
response.setId(id);
|
||||
response.setName(ApiDBUtils.findVolumeById(id).getName());
|
||||
response.setZoneId(zoneId);
|
||||
response.setZoneName(ApiDBUtils.findZoneById(zoneId).getName());
|
||||
response.setMode(mode);
|
||||
response.setUploadId(uploadId);
|
||||
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());
|
||||
return response;
|
||||
}
|
||||
|
||||
public static String getStaticName() {
|
||||
|
|
|
|||
|
|
@ -29,13 +29,13 @@ public class ExtractResponse extends BaseResponse {
|
|||
@SerializedName("name") @Param(description="the name of the extracted object")
|
||||
private String name;
|
||||
|
||||
@SerializedName("uploadId") @Param(description="the upload id of extracted object")
|
||||
@SerializedName("extractId") @Param(description="the upload id of extracted object")
|
||||
private Long uploadId;
|
||||
|
||||
@SerializedName("uploadpercentage") @Param(description="the percentage of the entity uploaded to the specified location")
|
||||
private Integer uploadPercent;
|
||||
|
||||
@SerializedName("status") @Param(description="the status of the ")
|
||||
@SerializedName("status") @Param(description="the status of the extraction")
|
||||
private String status;
|
||||
|
||||
@SerializedName("accountid") @Param(description="the account id to which the extracted object belongs")
|
||||
|
|
@ -68,8 +68,20 @@ public class ExtractResponse extends BaseResponse {
|
|||
private String mode;
|
||||
|
||||
@SerializedName("url") @Param(description="if mode = upload then url of the uploaded entity. if mode = download the url from which the entity can be downloaded")
|
||||
private String url;
|
||||
private String url;
|
||||
|
||||
public ExtractResponse(){
|
||||
}
|
||||
|
||||
public ExtractResponse(Long volumeId, String volName, long accountId,
|
||||
String state, Long uploadId) {
|
||||
this.id = volumeId;
|
||||
this.name = volName;
|
||||
this.accountId = accountId;
|
||||
this.state = state;
|
||||
this.uploadId = uploadId;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1207,9 +1207,10 @@ public interface ManagementServer {
|
|||
* @param cmd the command specifying url (where the volume needs to be extracted to), zoneId (zone where the volume exists), id (the id of the volume)
|
||||
* @throws URISyntaxException
|
||||
* @throws InternalErrorException
|
||||
* @throws PermissionDeniedException
|
||||
*
|
||||
*/
|
||||
void extractVolume(ExtractVolumeCmd cmd) throws URISyntaxException, InternalErrorException;
|
||||
Long extractVolume(ExtractVolumeCmd cmd) throws URISyntaxException, InternalErrorException, PermissionDeniedException;
|
||||
|
||||
/**
|
||||
* return an array of available hypervisors
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ import com.cloud.api.commands.UpdateTemplatePermissionsCmd;
|
|||
import com.cloud.api.commands.UpdateUserCmd;
|
||||
import com.cloud.api.commands.UpdateVMGroupCmd;
|
||||
import com.cloud.api.commands.UploadCustomCertificateCmd;
|
||||
import com.cloud.api.response.ExtractResponse;
|
||||
import com.cloud.async.AsyncInstanceCreateStatus;
|
||||
import com.cloud.async.AsyncJobExecutor;
|
||||
import com.cloud.async.AsyncJobManager;
|
||||
|
|
@ -233,6 +234,7 @@ import com.cloud.storage.StorageManager;
|
|||
import com.cloud.storage.StoragePoolHostVO;
|
||||
import com.cloud.storage.StoragePoolVO;
|
||||
import com.cloud.storage.StorageStats;
|
||||
import com.cloud.storage.Upload.Mode;
|
||||
import com.cloud.storage.Upload.Type;
|
||||
import com.cloud.storage.UploadVO;
|
||||
import com.cloud.storage.VMTemplateVO;
|
||||
|
|
@ -6675,41 +6677,66 @@ public class ManagementServerImpl implements ManagementServer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void extractVolume(ExtractVolumeCmd cmd) throws URISyntaxException, InternalErrorException {
|
||||
public Long extractVolume(ExtractVolumeCmd cmd) throws URISyntaxException, InternalErrorException, PermissionDeniedException {
|
||||
Long volumeId = cmd.getId();
|
||||
String url = cmd.getUrl();
|
||||
Long zoneId = cmd.getZoneId();
|
||||
AsyncJobVO job = cmd.getJob();
|
||||
|
||||
String mode = cmd.getMode();
|
||||
Account account = UserContext.current().getAccount();
|
||||
|
||||
VolumeVO volume = _volumeDao.findById(volumeId);
|
||||
if (volume == null) {
|
||||
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Unable to find volume with id " + volumeId);
|
||||
throw new ServerApiException(BaseCmd.PARAM_ERROR, "Unable to find volume with id " + volumeId);
|
||||
}
|
||||
|
||||
URI uri = new URI(url);
|
||||
if ( (uri.getScheme() == null) || (!uri.getScheme().equalsIgnoreCase("ftp") )) {
|
||||
throw new IllegalArgumentException("Unsupported scheme for url: " + url);
|
||||
}
|
||||
|
||||
String host = uri.getHost();
|
||||
try {
|
||||
InetAddress hostAddr = InetAddress.getByName(host);
|
||||
if (hostAddr.isAnyLocalAddress() || hostAddr.isLinkLocalAddress() || hostAddr.isLoopbackAddress() || hostAddr.isMulticastAddress() ) {
|
||||
throw new IllegalArgumentException("Illegal host specified in url");
|
||||
}
|
||||
if (hostAddr instanceof Inet6Address) {
|
||||
throw new IllegalArgumentException("IPV6 addresses not supported (" + hostAddr.getHostAddress() + ")");
|
||||
}
|
||||
} catch (UnknownHostException uhe) {
|
||||
throw new IllegalArgumentException("Unable to resolve " + host);
|
||||
}
|
||||
|
||||
if (_dcDao.findById(zoneId) == null) {
|
||||
throw new IllegalArgumentException("Please specify a valid zone.");
|
||||
throw new ServerApiException(BaseCmd.PARAM_ERROR, "Please specify a valid zone.");
|
||||
}
|
||||
|
||||
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 ");
|
||||
}else{
|
||||
extractMode = mode.equals(Upload.Mode.FTP_UPLOAD.toString()) ? Upload.Mode.FTP_UPLOAD : Upload.Mode.HTTP_DOWNLOAD;
|
||||
}
|
||||
|
||||
if ( _uploadMonitor.isTypeUploadInProgress(volumeId, Type.VOLUME) ){
|
||||
throw new IllegalArgumentException(volume.getName() + " upload is in progress. Please wait for some time to schedule another upload for the same");
|
||||
if (account != null) {
|
||||
if(!isAdmin(account.getType())){
|
||||
if (volume.getAccountId() != account.getId()){
|
||||
throw new PermissionDeniedException("Unable to find volume with ID: " + volumeId + " for account: " + account.getAccountName());
|
||||
}
|
||||
} else {
|
||||
Account userAccount = _accountDao.findById(volume.getAccountId());
|
||||
if((userAccount == null) || !_domainDao.isChildDomain(account.getDomainId(), userAccount.getDomainId())) {
|
||||
throw new PermissionDeniedException("Unable to extract volume:" + volumeId + " - permission denied.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If mode is upload perform extra checks on url and also see if there is an ongoing upload on the same.
|
||||
if (extractMode == Upload.Mode.FTP_UPLOAD){
|
||||
URI uri = new URI(url);
|
||||
if ( (uri.getScheme() == null) || (!uri.getScheme().equalsIgnoreCase("ftp") )) {
|
||||
throw new IllegalArgumentException("Unsupported scheme for url: " + url);
|
||||
}
|
||||
|
||||
String host = uri.getHost();
|
||||
try {
|
||||
InetAddress hostAddr = InetAddress.getByName(host);
|
||||
if (hostAddr.isAnyLocalAddress() || hostAddr.isLinkLocalAddress() || hostAddr.isLoopbackAddress() || hostAddr.isMulticastAddress() ) {
|
||||
throw new IllegalArgumentException("Illegal host specified in url");
|
||||
}
|
||||
if (hostAddr instanceof Inet6Address) {
|
||||
throw new IllegalArgumentException("IPV6 addresses not supported (" + hostAddr.getHostAddress() + ")");
|
||||
}
|
||||
} catch (UnknownHostException uhe) {
|
||||
throw new IllegalArgumentException("Unable to resolve " + host);
|
||||
}
|
||||
|
||||
if ( _uploadMonitor.isTypeUploadInProgress(volumeId, Type.VOLUME) ){
|
||||
throw new IllegalArgumentException(volume.getName() + " upload is in progress. Please wait for some time to schedule another upload for the same");
|
||||
}
|
||||
}
|
||||
|
||||
long userId = UserContext.current().getUserId();
|
||||
|
|
@ -6721,42 +6748,59 @@ public class ManagementServerImpl implements ManagementServer {
|
|||
List<HostVO> storageServers = _hostDao.listByTypeDataCenter(Host.Type.SecondaryStorage, zoneId);
|
||||
HostVO sserver = storageServers.get(0);
|
||||
|
||||
EventUtils.saveStartedEvent(1L, volume.getAccountId(), EventTypes.EVENT_VOLUME_UPLOAD, "Starting upload of " +volume.getName()+ " to " +url, cmd.getStartEventId());
|
||||
UploadVO uploadJob = _uploadMonitor.createNewUploadEntry(sserver.getId(), volumeId, UploadVO.Status.COPY_IN_PROGRESS, 0, Type.VOLUME, null, null, url);
|
||||
uploadJob = _uploadDao.createForUpdate(uploadJob.getId());
|
||||
EventUtils.saveStartedEvent(userId, accountId, EventTypes.EVENT_VOLUME_UPLOAD, "Starting extraction of " +volume.getName()+ " mode:"+mode, cmd.getStartEventId());
|
||||
List<UploadVO> extractURLList = _uploadDao.listByTypeUploadStatus(volumeId, Upload.Type.VOLUME, UploadVO.Status.DOWNLOAD_URL_CREATED);
|
||||
|
||||
// Update the async Job
|
||||
ExtractJobResultObject resultObj = new ExtractJobResultObject(volume.getAccountId(), volume.getName(), UploadVO.Status.COPY_IN_PROGRESS.toString(), 0, uploadJob.getId());
|
||||
_asyncMgr.updateAsyncJobAttachment(job.getId(), Type.VOLUME.toString(), volumeId);
|
||||
_asyncMgr.updateAsyncJobStatus(job.getId(), AsyncJobResult.STATUS_IN_PROGRESS, resultObj);
|
||||
if (extractMode == Upload.Mode.HTTP_DOWNLOAD && extractURLList.size() > 0){
|
||||
return extractURLList.get(0).getId(); // If download url already exists then return
|
||||
}else {
|
||||
UploadVO uploadJob = _uploadMonitor.createNewUploadEntry(sserver.getId(), volumeId, UploadVO.Status.COPY_IN_PROGRESS, 0, Type.VOLUME, null, null, url);
|
||||
uploadJob = _uploadDao.createForUpdate(uploadJob.getId());
|
||||
|
||||
// Update the async Job
|
||||
ExtractResponse resultObj = new ExtractResponse(volumeId, volume.getName(), accountId, UploadVO.Status.COPY_IN_PROGRESS.toString(), uploadJob.getId());
|
||||
_asyncMgr.updateAsyncJobAttachment(job.getId(), Type.VOLUME.toString(), volumeId);
|
||||
_asyncMgr.updateAsyncJobStatus(job.getId(), AsyncJobResult.STATUS_IN_PROGRESS, resultObj);
|
||||
|
||||
// Copy the volume from the source storage pool to secondary storage
|
||||
CopyVolumeCommand cvCmd = new CopyVolumeCommand(volume.getId(), volume.getPath(), srcPool, secondaryStorageURL, true);
|
||||
CopyVolumeAnswer cvAnswer = (CopyVolumeAnswer) _agentMgr.easySend(sourceHostId, cvCmd);
|
||||
|
||||
// Copy the volume from the source storage pool to secondary storage
|
||||
CopyVolumeCommand cvCmd = new CopyVolumeCommand(volume.getId(), volume.getPath(), srcPool, secondaryStorageURL, true);
|
||||
CopyVolumeAnswer cvAnswer = (CopyVolumeAnswer) _agentMgr.easySend(sourceHostId, cvCmd);
|
||||
// Check if you got a valid answer.
|
||||
if (cvAnswer == null || !cvAnswer.getResult()) {
|
||||
String errorString = "Failed to copy the volume from the source primary storage pool to secondary storage.";
|
||||
|
||||
//Update the async job.
|
||||
resultObj.setResultString(errorString);
|
||||
resultObj.setUploadStatus(UploadVO.Status.COPY_ERROR.toString());
|
||||
_asyncMgr.completeAsyncJob(job.getId(), AsyncJobResult.STATUS_FAILED, 0, resultObj);
|
||||
|
||||
//Update the DB that volume couldn't be copied
|
||||
uploadJob.setUploadState(UploadVO.Status.COPY_ERROR);
|
||||
uploadJob.setErrorString(errorString);
|
||||
uploadJob.setLastUpdated(new Date());
|
||||
_uploadDao.update(uploadJob.getId(), uploadJob);
|
||||
|
||||
if (cvAnswer == null || !cvAnswer.getResult()) {
|
||||
EventUtils.saveEvent(userId, accountId, EventTypes.EVENT_VOLUME_UPLOAD, errorString);
|
||||
throw new InternalErrorException(errorString);
|
||||
}
|
||||
|
||||
String errorString = "Failed to copy the volume from the source primary storage pool to secondary storage.";
|
||||
|
||||
resultObj.setResult_string(errorString);
|
||||
resultObj.setUploadStatus(UploadVO.Status.COPY_ERROR.toString());
|
||||
_asyncMgr.completeAsyncJob(job.getId(), AsyncJobResult.STATUS_FAILED, 0, resultObj);
|
||||
|
||||
uploadJob.setUploadState(UploadVO.Status.COPY_ERROR);
|
||||
uploadJob.setErrorString(errorString);
|
||||
String volumeLocalPath = "volumes/"+volume.getId()+"/"+cvAnswer.getVolumePath()+".vhd";
|
||||
//Update the DB that volume is copied
|
||||
uploadJob.setUploadState(UploadVO.Status.COPY_COMPLETE);
|
||||
uploadJob.setLastUpdated(new Date());
|
||||
_uploadDao.update(uploadJob.getId(), uploadJob);
|
||||
|
||||
EventUtils.saveEvent(1L, volume.getAccountId(), EventTypes.EVENT_VOLUME_UPLOAD, errorString);
|
||||
|
||||
throw new InternalErrorException(errorString);
|
||||
if (extractMode == Mode.FTP_UPLOAD){ // Now that the volume is copied perform the actual uploading
|
||||
_uploadMonitor.extractVolume(uploadJob, sserver, volume, url, zoneId, volumeLocalPath, cmd.getStartEventId(), job.getId(), _asyncMgr);
|
||||
return uploadJob.getId();
|
||||
}else{ // Volume is copied now make it visible under apache and create a URL.
|
||||
s_logger.debug("volumepath " +volumeLocalPath);
|
||||
_uploadMonitor.createVolumeDownloadURL(volumeId, volumeLocalPath, Type.VOLUME, zoneId, uploadJob.getId());
|
||||
EventUtils.saveEvent(userId, accountId, EventVO.LEVEL_INFO, cmd.getEventType(), "Completed extraction of "+volume.getName()+ " in mode:" +mode, null, cmd.getStartEventId());
|
||||
return uploadJob.getId();
|
||||
}
|
||||
}
|
||||
String volumeLocalPath = "volumes/"+volume.getId()+"/"+cvAnswer.getVolumePath()+".vhd";
|
||||
uploadJob.setUploadState(UploadVO.Status.COPY_COMPLETE);
|
||||
uploadJob.setLastUpdated(new Date());
|
||||
_uploadDao.update(uploadJob.getId(), uploadJob);
|
||||
|
||||
_uploadMonitor.extractVolume(uploadJob, sserver, volume, url, zoneId, volumeLocalPath, cmd.getStartEventId(), job.getId(), _asyncMgr);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import com.cloud.storage.VMTemplateHostVO;
|
|||
import com.cloud.storage.VMTemplateVO;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.utils.component.Manager;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
||||
/**
|
||||
* Monitor upload progress of all entities.
|
||||
|
|
@ -55,4 +56,7 @@ public interface UploadMonitor extends Manager{
|
|||
UploadVO createEntityDownloadURL(VMTemplateVO template,
|
||||
VMTemplateHostVO vmTemplateHost, Long dataCenterId, long eventId);
|
||||
|
||||
void createVolumeDownloadURL(Long entityId, String path, Type type,
|
||||
Long dataCenterId, Long uploadId) throws CloudRuntimeException;
|
||||
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ import com.cloud.agent.api.storage.CreateEntityDownloadURLCommand;
|
|||
import com.cloud.agent.api.storage.DeleteEntityDownloadURLCommand;
|
||||
import com.cloud.agent.api.storage.UploadCommand;
|
||||
import com.cloud.agent.api.storage.UploadProgressCommand.RequestType;
|
||||
import com.cloud.api.ApiDBUtils;
|
||||
import com.cloud.async.AsyncJobManager;
|
||||
import com.cloud.configuration.dao.ConfigurationDao;
|
||||
import com.cloud.event.EventTypes;
|
||||
|
|
@ -118,7 +119,7 @@ public class UploadMonitorImpl implements UploadMonitor {
|
|||
String errorString, String jobId, String uploadUrl){
|
||||
|
||||
UploadVO uploadObj = new UploadVO(hostId, typeId, new Date(),
|
||||
uploadState, 0, type, null, "jobid0000", uploadUrl);
|
||||
uploadState, 0, type, null, null, uploadUrl);
|
||||
_uploadDao.persist(uploadObj);
|
||||
|
||||
return uploadObj;
|
||||
|
|
@ -175,6 +176,9 @@ public class UploadMonitorImpl implements UploadMonitor {
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public UploadVO createEntityDownloadURL(VMTemplateVO template, VMTemplateHostVO vmTemplateHost, Long dataCenterId, long eventId) {
|
||||
|
||||
|
|
@ -225,10 +229,57 @@ public class UploadMonitorImpl implements UploadMonitor {
|
|||
_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.");
|
||||
throw new CloudRuntimeException("Couldnt find a running SSVM in the zone" + dataCenterId+ ". Couldnt create the extraction URL.");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createVolumeDownloadURL(Long entityId, String path, Type type, Long dataCenterId, Long uploadId) throws CloudRuntimeException{
|
||||
|
||||
List<HostVO> storageServers = _serverDao.listByTypeDataCenter(Host.Type.SecondaryStorage, dataCenterId);
|
||||
if(storageServers == null )
|
||||
throw new CloudRuntimeException("No Storage Server found at the datacenter - " +dataCenterId);
|
||||
|
||||
// Update DB for state = DOWNLOAD_URL_NOT_CREATED.
|
||||
UploadVO uploadJob = _uploadDao.createForUpdate(uploadId);
|
||||
uploadJob.setUploadState(Status.DOWNLOAD_URL_NOT_CREATED);
|
||||
uploadJob.setLastUpdated(new Date());
|
||||
_uploadDao.update(uploadJob.getId(), uploadJob);
|
||||
|
||||
// Create Symlink at ssvm
|
||||
CreateEntityDownloadURLCommand cmd = new CreateEntityDownloadURLCommand(path);
|
||||
long result = send(ApiDBUtils.findUploadById(uploadId).getHostId(), cmd, null);
|
||||
if (result == -1){
|
||||
String errorString = "Unable to create a link for " +type+ " id:"+entityId;
|
||||
s_logger.warn(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) {
|
||||
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(), path);
|
||||
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(uploadId, vo);
|
||||
return;
|
||||
}
|
||||
throw new CloudRuntimeException("Couldnt find a running SSVM in the zone" + dataCenterId+ ". Couldnt create the extraction URL.");
|
||||
|
||||
}
|
||||
|
||||
private String generateCopyUrl(String ipAddress, String path){
|
||||
String hostname = ipAddress;
|
||||
String scheme = "http";
|
||||
|
|
@ -401,7 +452,7 @@ public class UploadMonitorImpl implements UploadMonitor {
|
|||
for (UploadVO extractURL : extractURLs){
|
||||
if( getTimeDiff(extractURL.getLastUpdated()) < EXTRACT_URL_TIME_LIMIT) continue;
|
||||
String path = extractURL.getUploadUrl().substring( (extractURL.getUploadUrl().lastIndexOf("/")) +1 );
|
||||
DeleteEntityDownloadURLCommand cmd = new DeleteEntityDownloadURLCommand(path);
|
||||
DeleteEntityDownloadURLCommand cmd = new DeleteEntityDownloadURLCommand(path, extractURL.getType());
|
||||
long result = send(extractURL.getHostId(), cmd, null);
|
||||
if (result == -1){
|
||||
s_logger.warn("Unable to delete the link for " +extractURL.getType()+ " id=" +extractURL.getTypeId()+ " url="+extractURL.getUploadUrl());
|
||||
|
|
|
|||
|
|
@ -537,10 +537,10 @@ public class TemplateManagerImpl implements TemplateManager {
|
|||
if (vo!=null){
|
||||
ExtractJobResultObject resultObject = new ExtractJobResultObject(template.getAccountId(), template.getName(), Upload.Status.DOWNLOAD_URL_CREATED.toString(), vo.getId(), url);
|
||||
mgr.completeAsyncJob(job.getId(), AsyncJobResult.STATUS_SUCCEEDED, 1, resultObject);
|
||||
EventUtils.saveEvent(userId, accountId, EventVO.LEVEL_INFO, event, "Completed extraction of "+template.getName()+ " in mode:" +extractMode.toString(), null, eventId);
|
||||
EventUtils.saveEvent(userId, accountId, EventVO.LEVEL_INFO, event, "Completed extraction of "+template.getName()+ " in mode:" +mode, null, eventId);
|
||||
return vo.getId();
|
||||
}else{
|
||||
EventUtils.saveEvent(userId, accountId, EventVO.LEVEL_ERROR, event, "Failed extraction of "+template.getName()+ " in mode:" +extractMode.toString(), null, eventId);
|
||||
EventUtils.saveEvent(userId, accountId, EventVO.LEVEL_ERROR, event, "Failed extraction of "+template.getName()+ " in mode:" +mode, null, eventId);
|
||||
mgr.completeAsyncJob(job.getId(), AsyncJobResult.STATUS_FAILED, 2, null);
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue