mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
refactor snapshot
This commit is contained in:
parent
37cbe8890f
commit
2f689171e0
@ -60,6 +60,9 @@ public interface Snapshot extends ControlledEntity, Identity, InternalIdentity,
|
||||
CreatedOnPrimary,
|
||||
BackingUp,
|
||||
BackedUp,
|
||||
Copying,
|
||||
Destroying,
|
||||
Destroyed,//it's a state, user can't see the snapshot from ui, while the snapshot may still exist on the storage
|
||||
Error;
|
||||
|
||||
public String toString() {
|
||||
@ -76,6 +79,8 @@ public interface Snapshot extends ControlledEntity, Identity, InternalIdentity,
|
||||
OperationNotPerformed,
|
||||
BackupToSecondary,
|
||||
BackedupToSecondary,
|
||||
DestroyRequested,
|
||||
CopyingRequested,
|
||||
OperationSucceeded,
|
||||
OperationFailed
|
||||
}
|
||||
|
||||
@ -80,6 +80,9 @@ public interface VolumeApiService {
|
||||
|
||||
Volume detachVolumeFromVM(DetachVolumeCmd cmmd);
|
||||
|
||||
Snapshot takeSnapshot(Long volumeId, Long policyId)
|
||||
Snapshot takeSnapshot(Long volumeId, Long policyId, Long snapshotId, Account account)
|
||||
throws ResourceAllocationException;
|
||||
|
||||
Snapshot allocSnapshot(Long volumeId, Long policyId)
|
||||
throws ResourceAllocationException;
|
||||
}
|
||||
|
||||
@ -152,7 +152,7 @@ public class CreateSnapshotCmd extends BaseAsyncCreateCmd {
|
||||
|
||||
@Override
|
||||
public void create() throws ResourceAllocationException {
|
||||
Snapshot snapshot = _snapshotService.allocSnapshot(getVolumeId(), getPolicyId());
|
||||
Snapshot snapshot = this._volumeService.allocSnapshot(getVolumeId(), getPolicyId());
|
||||
if (snapshot != null) {
|
||||
this.setEntityId(snapshot.getId());
|
||||
this.setEntityUuid(snapshot.getUuid());
|
||||
@ -164,14 +164,20 @@ public class CreateSnapshotCmd extends BaseAsyncCreateCmd {
|
||||
@Override
|
||||
public void execute() {
|
||||
UserContext.current().setEventDetails("Volume Id: "+getVolumeId());
|
||||
Snapshot snapshot = _snapshotService.createSnapshot(getVolumeId(), getPolicyId(), getEntityId(), _accountService.getAccount(getEntityOwnerId()));
|
||||
if (snapshot != null) {
|
||||
SnapshotResponse response = _responseGenerator.createSnapshotResponse(snapshot);
|
||||
response.setResponseName(getCommandName());
|
||||
this.setResponseObject(response);
|
||||
} else {
|
||||
Snapshot snapshot;
|
||||
try {
|
||||
snapshot = _volumeService.takeSnapshot(this.getVolumeId(), this.getPolicyId(), this.getEntityId(), _accountService.getAccount(getEntityOwnerId()));
|
||||
if (snapshot != null) {
|
||||
SnapshotResponse response = _responseGenerator.createSnapshotResponse(snapshot);
|
||||
response.setResponseName(getCommandName());
|
||||
this.setResponseObject(response);
|
||||
} else {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create snapshot due to an internal error creating snapshot for volume " + volumeId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create snapshot due to an internal error creating snapshot for volume " + volumeId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -3,9 +3,14 @@ package org.apache.cloudstack.engine.subsystem.api.storage;
|
||||
import com.cloud.storage.Snapshot;
|
||||
|
||||
|
||||
|
||||
public interface SnapshotStrategy {
|
||||
public SnapshotInfo takeSnapshot(SnapshotInfo snapshot);
|
||||
public SnapshotInfo backupSnapshot(SnapshotInfo snapshot);
|
||||
public boolean deleteSnapshot(Long snapshotId);
|
||||
public boolean canHandle(Snapshot snapshot);
|
||||
/**
|
||||
* @param snapshot
|
||||
* @return
|
||||
*/
|
||||
boolean canHandle(Snapshot snapshot);
|
||||
}
|
||||
|
||||
@ -22,4 +22,11 @@ package org.apache.cloudstack.engine.subsystem.api.storage;
|
||||
public interface StorageCacheManager {
|
||||
public DataStore getCacheStorage(Scope scope);
|
||||
public DataObject createCacheObject(DataObject data, Scope scope);
|
||||
/** only create cache object in db
|
||||
* @param data
|
||||
* @param scope
|
||||
* @return
|
||||
*/
|
||||
DataObject getCacheObject(DataObject data, Scope scope);
|
||||
DataObject deleteCacheObject(DataObject data);
|
||||
}
|
||||
|
||||
@ -27,4 +27,5 @@ public interface VolumeInfo extends DataObject, Volume {
|
||||
public Object getpayload();
|
||||
public HypervisorType getHypervisorType();
|
||||
public Long getLastPoolId();
|
||||
public String getAttachedVmName();
|
||||
}
|
||||
|
||||
@ -23,12 +23,12 @@ import com.cloud.agent.api.Command;
|
||||
public class CopyCommand extends Command implements StorageSubSystemCommand {
|
||||
private DataTO srcTO;
|
||||
private DataTO destTO;
|
||||
private DataTO cacheTO;
|
||||
|
||||
|
||||
public CopyCommand(DataTO srcUri, DataTO destUri, int timeout) {
|
||||
public CopyCommand(DataTO srcData, DataTO destData, int timeout) {
|
||||
super();
|
||||
this.srcTO = srcUri;
|
||||
this.destTO = destUri;
|
||||
this.srcTO = srcData;
|
||||
this.destTO = destData;
|
||||
this.setWait(timeout);
|
||||
}
|
||||
|
||||
@ -45,4 +45,12 @@ public class CopyCommand extends Command implements StorageSubSystemCommand {
|
||||
return true;
|
||||
}
|
||||
|
||||
public DataTO getCacheTO() {
|
||||
return cacheTO;
|
||||
}
|
||||
|
||||
public void setCacheTO(DataTO cacheTO) {
|
||||
this.cacheTO = cacheTO;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,21 +2,43 @@ package org.apache.cloudstack.storage.to;
|
||||
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
|
||||
|
||||
import com.cloud.agent.api.to.DataStoreTO;
|
||||
|
||||
public class SnapshotObjectTO implements DataTO {
|
||||
private String path;
|
||||
private VolumeObjectTO volume;
|
||||
private String parentSnapshotPath;
|
||||
private DataStoreTO dataStore;
|
||||
private String vmName;
|
||||
private String name;
|
||||
private long id;
|
||||
|
||||
public SnapshotObjectTO() {
|
||||
|
||||
}
|
||||
|
||||
public SnapshotObjectTO(SnapshotInfo snapshot) {
|
||||
this.path = snapshot.getPath();
|
||||
this.setId(snapshot.getId());
|
||||
this.volume = (VolumeObjectTO)snapshot.getBaseVolume().getTO();
|
||||
this.setVmName(snapshot.getBaseVolume().getAttachedVmName());
|
||||
if (snapshot.getParent() != null) {
|
||||
this.parentSnapshotPath = snapshot.getParent().getPath();
|
||||
}
|
||||
this.dataStore = snapshot.getDataStore().getTO();
|
||||
this.setName(snapshot.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataObjectType getObjectType() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
return DataObjectType.SNAPSHOT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStoreTO getDataStore() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
return this.dataStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -27,4 +49,44 @@ public class SnapshotObjectTO implements DataTO {
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public VolumeObjectTO getVolume() {
|
||||
return volume;
|
||||
}
|
||||
|
||||
public void setVolume(VolumeObjectTO volume) {
|
||||
this.volume = volume;
|
||||
}
|
||||
|
||||
public String getParentSnapshotPath() {
|
||||
return parentSnapshotPath;
|
||||
}
|
||||
|
||||
public void setParentSnapshotPath(String parentSnapshotPath) {
|
||||
this.parentSnapshotPath = parentSnapshotPath;
|
||||
}
|
||||
|
||||
public String getVmName() {
|
||||
return vmName;
|
||||
}
|
||||
|
||||
public void setVmName(String vmName) {
|
||||
this.vmName = vmName;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,6 +32,7 @@ public class VolumeObjectTO implements DataTO {
|
||||
private String name;
|
||||
private long size;
|
||||
private String path;
|
||||
private Long volumeId;
|
||||
|
||||
public VolumeObjectTO() {
|
||||
|
||||
@ -49,6 +50,7 @@ public class VolumeObjectTO implements DataTO {
|
||||
}
|
||||
//this.name = volume.getName();
|
||||
this.size = volume.getSize();
|
||||
this.setVolumeId(volume.getId());
|
||||
}
|
||||
|
||||
public String getUuid() {
|
||||
@ -103,4 +105,12 @@ public class VolumeObjectTO implements DataTO {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public Long getVolumeId() {
|
||||
return volumeId;
|
||||
}
|
||||
|
||||
public void setVolumeId(Long volumeId) {
|
||||
this.volumeId = volumeId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -164,10 +164,24 @@ public class StorageCacheManagerImpl implements StorageCacheManager, Manager {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataObject getCacheObject(DataObject data, Scope scope) {
|
||||
DataStore cacheStore = this.getCacheStorage(scope);
|
||||
DataObject objOnCacheStore = cacheStore.create(data);
|
||||
|
||||
return objOnCacheStore;
|
||||
}
|
||||
|
||||
protected Void createCacheObjectCallBack(AsyncCallbackDispatcher<StorageCacheManagerImpl, CopyCommandResult> callback,
|
||||
CreateCacheObjectContext<CopyCommandResult> context) {
|
||||
AsyncCallFuture<CopyCommandResult> future = context.future;
|
||||
future.complete(callback.getResult());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataObject deleteCacheObject(DataObject data) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -60,6 +60,8 @@ import com.cloud.agent.api.UpgradeSnapshotCommand;
|
||||
import com.cloud.agent.api.storage.CopyVolumeAnswer;
|
||||
import com.cloud.agent.api.storage.CopyVolumeCommand;
|
||||
import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
|
||||
import com.cloud.agent.api.to.DataStoreTO;
|
||||
import com.cloud.agent.api.to.NfsTO;
|
||||
import com.cloud.agent.api.to.S3TO;
|
||||
import com.cloud.agent.api.to.SwiftTO;
|
||||
import com.cloud.configuration.Config;
|
||||
@ -127,10 +129,6 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
||||
@Inject
|
||||
VolumeManager volumeMgr;
|
||||
@Inject
|
||||
private SwiftManager _swiftMgr;
|
||||
@Inject
|
||||
private S3Manager _s3Mgr;
|
||||
@Inject
|
||||
StorageCacheManager cacheMgr;
|
||||
|
||||
@Override
|
||||
@ -179,112 +177,55 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
|
||||
protected Answer copyFromSnapshot(DataObject snapObj, DataObject volObj) {
|
||||
SnapshotVO snapshot = this.snapshotDao.findById(snapObj.getId());
|
||||
StoragePool pool = (StoragePool) volObj.getDataStore();
|
||||
String vdiUUID = null;
|
||||
Long snapshotId = snapshot.getId();
|
||||
Long volumeId = snapshot.getVolumeId();
|
||||
Long dcId = snapshot.getDataCenterId();
|
||||
String secondaryStoragePoolUrl = this.snapshotMgr
|
||||
.getSecondaryStorageURL(snapshot);
|
||||
long accountId = snapshot.getAccountId();
|
||||
|
||||
String backedUpSnapshotUuid = snapshot.getBackupSnapshotId();
|
||||
snapshot = snapshotDao.findById(snapshotId);
|
||||
if (snapshot.getVersion().trim().equals("2.1")) {
|
||||
VolumeVO volume = this.volDao.findByIdIncludingRemoved(volumeId);
|
||||
if (volume == null) {
|
||||
throw new CloudRuntimeException("failed to upgrade snapshot "
|
||||
+ snapshotId + " due to unable to find orignal volume:"
|
||||
+ volumeId + ", try it later ");
|
||||
}
|
||||
if (volume.getTemplateId() == null) {
|
||||
snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2");
|
||||
} else {
|
||||
VMTemplateVO template = templateDao
|
||||
.findByIdIncludingRemoved(volume.getTemplateId());
|
||||
if (template == null) {
|
||||
throw new CloudRuntimeException(
|
||||
"failed to upgrade snapshot "
|
||||
+ snapshotId
|
||||
+ " due to unalbe to find orignal template :"
|
||||
+ volume.getTemplateId()
|
||||
+ ", try it later ");
|
||||
}
|
||||
Long templateId = template.getId();
|
||||
Long tmpltAccountId = template.getAccountId();
|
||||
if (!snapshotDao.lockInLockTable(snapshotId.toString(), 10)) {
|
||||
throw new CloudRuntimeException(
|
||||
"failed to upgrade snapshot "
|
||||
+ snapshotId
|
||||
+ " due to this snapshot is being used, try it later ");
|
||||
}
|
||||
UpgradeSnapshotCommand cmd = new UpgradeSnapshotCommand(null,
|
||||
secondaryStoragePoolUrl, dcId, accountId, volumeId,
|
||||
templateId, tmpltAccountId, null,
|
||||
snapshot.getBackupSnapshotId(), snapshot.getName(),
|
||||
"2.1");
|
||||
Answer answer = null;
|
||||
try {
|
||||
answer = this.storageMgr.sendToPool(pool, cmd);
|
||||
} catch (StorageUnavailableException e) {
|
||||
} finally {
|
||||
snapshotDao.unlockFromLockTable(snapshotId.toString());
|
||||
}
|
||||
if ((answer != null) && answer.getResult()) {
|
||||
snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2");
|
||||
} else {
|
||||
throw new CloudRuntimeException("Unable to upgrade snapshot from 2.1 to 2.2 for "
|
||||
+ snapshot.getId());
|
||||
}
|
||||
|
||||
protected DataObject cacheSnapshotChain(SnapshotInfo snapshot) {
|
||||
DataObject leafData = null;
|
||||
while(snapshot != null) {
|
||||
DataObject cacheData = cacheMgr.createCacheObject(snapshot, snapshot.getDataStore().getScope());
|
||||
if (leafData == null) {
|
||||
leafData = cacheData;
|
||||
}
|
||||
snapshot = snapshot.getParent();
|
||||
}
|
||||
return leafData;
|
||||
}
|
||||
|
||||
protected void deleteSnapshotCacheChain(SnapshotInfo snapshot) {
|
||||
|
||||
}
|
||||
|
||||
protected Answer copyVolumeFromSnapshot(DataObject snapObj, DataObject volObj) {
|
||||
SnapshotInfo snapshot = (SnapshotInfo)snapObj;
|
||||
StoragePool pool = (StoragePool) volObj.getDataStore();
|
||||
|
||||
String basicErrMsg = "Failed to create volume from "
|
||||
+ snapshot.getName() + " on pool " + pool;
|
||||
|
||||
DataStore store = snapObj.getDataStore();
|
||||
DataStoreTO storTO = store.getTO();
|
||||
DataObject srcData = snapObj;
|
||||
try {
|
||||
if (snapshot.getSwiftId() != null && snapshot.getSwiftId() != 0) {
|
||||
snapshotMgr.downloadSnapshotsFromSwift(snapshot);
|
||||
} else if (snapshot.getS3Id() != null && snapshot.getS3Id() != 0) {
|
||||
snapshotMgr.downloadSnapshotsFromS3(snapshot);
|
||||
if (!(storTO instanceof NfsTO)) {
|
||||
srcData = cacheSnapshotChain(snapshot);
|
||||
}
|
||||
|
||||
String value = configDao
|
||||
.getValue(Config.CreateVolumeFromSnapshotWait.toString());
|
||||
int _createVolumeFromSnapshotWait = NumbersUtil.parseInt(value,
|
||||
Integer.parseInt(Config.CreateVolumeFromSnapshotWait
|
||||
.getDefaultValue()));
|
||||
CreateVolumeFromSnapshotCommand createVolumeFromSnapshotCommand = new CreateVolumeFromSnapshotCommand(
|
||||
pool, secondaryStoragePoolUrl, dcId, accountId, volumeId,
|
||||
backedUpSnapshotUuid, snapshot.getName(),
|
||||
_createVolumeFromSnapshotWait);
|
||||
CreateVolumeFromSnapshotAnswer answer;
|
||||
if (!snapshotDao.lockInLockTable(snapshotId.toString(), 10)) {
|
||||
throw new CloudRuntimeException("failed to create volume from "
|
||||
+ snapshotId
|
||||
+ " due to this snapshot is being used, try it later ");
|
||||
}
|
||||
answer = (CreateVolumeFromSnapshotAnswer) this.storageMgr
|
||||
.sendToPool(pool, createVolumeFromSnapshotCommand);
|
||||
if (answer != null && answer.getResult()) {
|
||||
vdiUUID = answer.getVdi();
|
||||
VolumeVO vol = this.volDao.findById(volObj.getId());
|
||||
vol.setPath(vdiUUID);
|
||||
this.volDao.update(vol.getId(), vol);
|
||||
return null;
|
||||
} else {
|
||||
s_logger.error(basicErrMsg + " due to "
|
||||
+ ((answer == null) ? "null" : answer.getDetails()));
|
||||
throw new CloudRuntimeException(basicErrMsg);
|
||||
}
|
||||
|
||||
CopyCommand cmd = new CopyCommand(srcData.getTO(), volObj.getTO(), _createVolumeFromSnapshotWait);
|
||||
|
||||
|
||||
Answer answer = this.storageMgr
|
||||
.sendToPool(pool, cmd);
|
||||
return answer;
|
||||
} catch (StorageUnavailableException e) {
|
||||
s_logger.error(basicErrMsg, e);
|
||||
throw new CloudRuntimeException(basicErrMsg);
|
||||
} finally {
|
||||
if (snapshot.getSwiftId() != null) {
|
||||
snapshotMgr.deleteSnapshotsDirForVolume(
|
||||
secondaryStoragePoolUrl, dcId, accountId, volumeId);
|
||||
if (!(storTO instanceof NfsTO)) {
|
||||
deleteSnapshotCacheChain((SnapshotInfo)srcData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -328,7 +269,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
||||
answer = copyTemplate(srcData, destData);
|
||||
} else if (srcData.getType() == DataObjectType.SNAPSHOT
|
||||
&& destData.getType() == DataObjectType.VOLUME) {
|
||||
answer = copyFromSnapshot(srcData, destData);
|
||||
answer = copyVolumeFromSnapshot(srcData, destData);
|
||||
} else if (srcData.getType() == DataObjectType.SNAPSHOT
|
||||
&& destData.getType() == DataObjectType.TEMPLATE) {
|
||||
answer = createTemplateFromSnapshot(srcData, destData);
|
||||
@ -359,49 +300,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
||||
@DB
|
||||
protected Answer createTemplateFromSnapshot(DataObject srcData,
|
||||
DataObject destData) {
|
||||
long snapshotId = srcData.getId();
|
||||
SnapshotVO snapshot = snapshotDao.findById(snapshotId);
|
||||
if (snapshot == null) {
|
||||
throw new CloudRuntimeException("Unable to find Snapshot for Id "
|
||||
+ srcData.getId());
|
||||
}
|
||||
Long zoneId = snapshot.getDataCenterId();
|
||||
DataStore secStore = destData.getDataStore();
|
||||
/*
|
||||
HostVO secondaryStorageHost = this.templateMgr
|
||||
.getSecondaryStorageHost(zoneId);
|
||||
*/
|
||||
String secondaryStorageURL = snapshotMgr
|
||||
.getSecondaryStorageURL(snapshot);
|
||||
VMTemplateVO template = this.templateDao.findById(destData.getId());
|
||||
String name = template.getName();
|
||||
String backupSnapshotUUID = snapshot.getBackupSnapshotId();
|
||||
if (backupSnapshotUUID == null) {
|
||||
throw new CloudRuntimeException(
|
||||
"Unable to create private template from snapshot "
|
||||
+ snapshotId
|
||||
+ " due to there is no backupSnapshotUUID for this snapshot");
|
||||
}
|
||||
|
||||
Long dcId = snapshot.getDataCenterId();
|
||||
Long accountId = snapshot.getAccountId();
|
||||
Long volumeId = snapshot.getVolumeId();
|
||||
|
||||
String origTemplateInstallPath = null;
|
||||
List<StoragePoolVO> pools = this.storageMgr
|
||||
.ListByDataCenterHypervisor(zoneId,
|
||||
snapshot.getHypervisorType());
|
||||
if (pools == null || pools.size() == 0) {
|
||||
throw new CloudRuntimeException(
|
||||
"Unable to find storage pools in zone " + zoneId);
|
||||
}
|
||||
StoragePoolVO poolvo = pools.get(0);
|
||||
StoragePool pool = (StoragePool) this.dataStoreMgr.getDataStore(
|
||||
poolvo.getId(), DataStoreRole.Primary);
|
||||
|
||||
if (snapshot.getSwiftId() != null && snapshot.getSwiftId() != 0) {
|
||||
snapshotMgr.downloadSnapshotsFromSwift(snapshot);
|
||||
}
|
||||
|
||||
String value = configDao
|
||||
.getValue(Config.CreatePrivateTemplateFromSnapshotWait
|
||||
.toString());
|
||||
@ -410,172 +309,71 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
||||
.parseInt(Config.CreatePrivateTemplateFromSnapshotWait
|
||||
.getDefaultValue()));
|
||||
|
||||
CreatePrivateTemplateFromSnapshotCommand cmd = new CreatePrivateTemplateFromSnapshotCommand(
|
||||
pool, secondaryStorageURL, dcId, accountId,
|
||||
snapshot.getVolumeId(), backupSnapshotUUID, snapshot.getName(),
|
||||
origTemplateInstallPath, template.getId(), name,
|
||||
_createprivatetemplatefromsnapshotwait);
|
||||
|
||||
return sendCommand(cmd, pool, template.getId(), dcId, secStore);
|
||||
}
|
||||
|
||||
@DB
|
||||
protected Answer sendCommand(Command cmd, StoragePool pool,
|
||||
long templateId, long zoneId, DataStore secStore) {
|
||||
|
||||
CreatePrivateTemplateAnswer answer = null;
|
||||
try {
|
||||
answer = (CreatePrivateTemplateAnswer) this.storageMgr.sendToPool(
|
||||
pool, cmd);
|
||||
} catch (StorageUnavailableException e) {
|
||||
throw new CloudRuntimeException(
|
||||
"Failed to execute CreatePrivateTemplateFromSnapshotCommand",
|
||||
e);
|
||||
if (srcData.getDataStore().getRole() != DataStoreRole.ImageCache && destData.getDataStore().getRole() != DataStoreRole.ImageCache) {
|
||||
SnapshotInfo snapshot = (SnapshotInfo)srcData;
|
||||
srcData = cacheSnapshotChain(snapshot);
|
||||
}
|
||||
|
||||
if (answer == null || !answer.getResult()) {
|
||||
return answer;
|
||||
}
|
||||
|
||||
VMTemplateVO privateTemplate = templateDao.findById(templateId);
|
||||
String answerUniqueName = answer.getUniqueName();
|
||||
if (answerUniqueName != null) {
|
||||
privateTemplate.setUniqueName(answerUniqueName);
|
||||
}
|
||||
ImageFormat format = answer.getImageFormat();
|
||||
if (format != null) {
|
||||
privateTemplate.setFormat(format);
|
||||
} else {
|
||||
// This never occurs.
|
||||
// Specify RAW format makes it unusable for snapshots.
|
||||
privateTemplate.setFormat(ImageFormat.RAW);
|
||||
}
|
||||
|
||||
String checkSum = this.templateMgr
|
||||
.getChecksum(secStore, answer.getPath());
|
||||
|
||||
Transaction txn = Transaction.currentTxn();
|
||||
|
||||
txn.start();
|
||||
|
||||
privateTemplate.setChecksum(checkSum);
|
||||
templateDao.update(privateTemplate.getId(), privateTemplate);
|
||||
|
||||
// add template zone ref for this template
|
||||
templateDao.addTemplateToZone(privateTemplate, zoneId);
|
||||
TemplateDataStoreVO templateHostVO = new TemplateDataStoreVO(secStore.getId(),
|
||||
privateTemplate.getId());
|
||||
templateHostVO.setDownloadPercent(100);
|
||||
templateHostVO.setDownloadState(Status.DOWNLOADED);
|
||||
templateHostVO.setInstallPath(answer.getPath());
|
||||
templateHostVO.setLastUpdated(new Date());
|
||||
templateHostVO.setSize(answer.getVirtualSize());
|
||||
templateHostVO.setPhysicalSize(answer.getphysicalSize());
|
||||
templateStoreDao.persist(templateHostVO);
|
||||
txn.close();
|
||||
CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _createprivatetemplatefromsnapshotwait);
|
||||
EndPoint ep = selector.select(srcData, destData);
|
||||
Answer answer = ep.sendMessage(cmd);
|
||||
return answer;
|
||||
}
|
||||
|
||||
private Answer createTemplateFromVolume(DataObject srcObj,
|
||||
DataObject destObj) {
|
||||
long volumeId = srcObj.getId();
|
||||
VolumeVO volume = this.volDao.findById(volumeId);
|
||||
if (volume == null) {
|
||||
throw new CloudRuntimeException("Unable to find volume for Id "
|
||||
+ volumeId);
|
||||
}
|
||||
long accountId = volume.getAccountId();
|
||||
|
||||
String vmName = this.volumeMgr.getVmNameOnVolume(volume);
|
||||
Long zoneId = volume.getDataCenterId();
|
||||
DataStore secStore = destObj.getDataStore();
|
||||
String secondaryStorageURL = secStore.getUri();
|
||||
VMTemplateVO template = this.templateDao.findById(destObj.getId());
|
||||
StoragePool pool = (StoragePool) this.dataStoreMgr.getDataStore(
|
||||
volume.getPoolId(), DataStoreRole.Primary);
|
||||
private Answer createTemplateFromVolume(DataObject srcData,
|
||||
DataObject destData) {
|
||||
|
||||
String value = configDao
|
||||
.getValue(Config.CreatePrivateTemplateFromVolumeWait.toString());
|
||||
int _createprivatetemplatefromvolumewait = NumbersUtil.parseInt(value,
|
||||
Integer.parseInt(Config.CreatePrivateTemplateFromVolumeWait
|
||||
.getDefaultValue()));
|
||||
|
||||
CreatePrivateTemplateFromVolumeCommand cmd = new CreatePrivateTemplateFromVolumeCommand(
|
||||
pool, secondaryStorageURL, destObj.getId(), accountId,
|
||||
template.getName(), template.getUniqueName(), volume.getPath(),
|
||||
vmName, _createprivatetemplatefromvolumewait);
|
||||
|
||||
return sendCommand(cmd, pool, template.getId(), zoneId, secStore);
|
||||
}
|
||||
|
||||
private DataStore getSecHost(long volumeId, long dcId) {
|
||||
Long id = snapshotDao.getSecHostId(volumeId);
|
||||
if ( id != null) {
|
||||
return this.dataStoreMgr.getDataStore(id, DataStoreRole.Image);
|
||||
|
||||
if (srcData.getDataStore().getRole() != DataStoreRole.ImageCache && destData.getDataStore().getRole() != DataStoreRole.ImageCache) {
|
||||
//need to copy it to image cache store
|
||||
DataObject cacheData = cacheMgr.createCacheObject(srcData, destData.getDataStore().getScope());
|
||||
CopyCommand cmd = new CopyCommand(cacheData.getTO(), destData.getTO(), _createprivatetemplatefromvolumewait);
|
||||
EndPoint ep = selector.select(cacheData, destData);
|
||||
Answer answer = ep.sendMessage(cmd);
|
||||
return answer;
|
||||
} else {
|
||||
//handle copy it to/from cache store
|
||||
CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _createprivatetemplatefromvolumewait);
|
||||
EndPoint ep = selector.select(srcData, destData);
|
||||
Answer answer = ep.sendMessage(cmd);
|
||||
return answer;
|
||||
}
|
||||
return this.dataStoreMgr.getImageStore(dcId);
|
||||
}
|
||||
|
||||
protected Answer copySnapshot(DataObject srcObject, DataObject destObject) {
|
||||
SnapshotInfo srcSnapshot = (SnapshotInfo)srcObject;
|
||||
VolumeInfo baseVolume = srcSnapshot.getBaseVolume();
|
||||
Long dcId = baseVolume.getDataCenterId();
|
||||
Long accountId = baseVolume.getAccountId();
|
||||
protected Answer copySnapshot(DataObject srcData, DataObject destData) {
|
||||
String value = configDao.getValue(Config.BackupSnapshotWait.toString());
|
||||
int _backupsnapshotwait = NumbersUtil.parseInt(value, Integer.parseInt(Config.BackupSnapshotWait.getDefaultValue()));
|
||||
|
||||
DataStore secStore = getSecHost(baseVolume.getId(), baseVolume.getDataCenterId());
|
||||
Long secHostId = secStore.getId();
|
||||
String secondaryStoragePoolUrl = secStore.getUri();
|
||||
String snapshotUuid = srcSnapshot.getPath();
|
||||
// In order to verify that the snapshot is not empty,
|
||||
// we check if the parent of the snapshot is not the same as the parent of the previous snapshot.
|
||||
// We pass the uuid of the previous snapshot to the plugin to verify this.
|
||||
SnapshotVO prevSnapshot = null;
|
||||
String prevSnapshotUuid = null;
|
||||
String prevBackupUuid = null;
|
||||
|
||||
|
||||
SwiftTO swift = _swiftMgr.getSwiftTO();
|
||||
S3TO s3 = _s3Mgr.getS3TO();
|
||||
|
||||
long prevSnapshotId = srcSnapshot.getPrevSnapshotId();
|
||||
if (prevSnapshotId > 0) {
|
||||
prevSnapshot = snapshotDao.findByIdIncludingRemoved(prevSnapshotId);
|
||||
if ( prevSnapshot.getBackupSnapshotId() != null && swift == null) {
|
||||
if (prevSnapshot.getVersion() != null && prevSnapshot.getVersion().equals("2.2")) {
|
||||
prevBackupUuid = prevSnapshot.getBackupSnapshotId();
|
||||
prevSnapshotUuid = prevSnapshot.getPath();
|
||||
}
|
||||
} else if ((prevSnapshot.getSwiftId() != null && swift != null)
|
||||
|| (prevSnapshot.getS3Id() != null && s3 != null)) {
|
||||
prevBackupUuid = prevSnapshot.getBackupSnapshotId();
|
||||
prevSnapshotUuid = prevSnapshot.getPath();
|
||||
}
|
||||
}
|
||||
boolean isVolumeInactive = this.volumeMgr.volumeInactive(baseVolume);
|
||||
String vmName = this.volumeMgr.getVmNameOnVolume(baseVolume);
|
||||
StoragePool srcPool = (StoragePool)dataStoreMgr.getPrimaryDataStore(baseVolume.getPoolId());
|
||||
String value = configDao.getValue(Config.BackupSnapshotWait.toString());
|
||||
int _backupsnapshotwait = NumbersUtil.parseInt(value, Integer.parseInt(Config.BackupSnapshotWait.getDefaultValue()));
|
||||
BackupSnapshotCommand backupSnapshotCommand = new BackupSnapshotCommand(secondaryStoragePoolUrl, dcId, accountId, baseVolume.getId(), srcSnapshot.getId(), secHostId, baseVolume.getPath(), srcPool, snapshotUuid,
|
||||
srcSnapshot.getName(), prevSnapshotUuid, prevBackupUuid, isVolumeInactive, vmName, _backupsnapshotwait);
|
||||
|
||||
if ( swift != null ) {
|
||||
backupSnapshotCommand.setSwift(swift);
|
||||
} else if (s3 != null) {
|
||||
backupSnapshotCommand.setS3(s3);
|
||||
}
|
||||
BackupSnapshotAnswer answer = (BackupSnapshotAnswer) this.snapshotMgr.sendToPool(baseVolume, backupSnapshotCommand);
|
||||
if (answer != null && answer.getResult()) {
|
||||
SnapshotVO snapshotVO = this.snapshotDao.findById(srcSnapshot.getId());
|
||||
snapshotVO.setBackupSnapshotId(answer.getBackupSnapshotName());
|
||||
// persist an entry in snapshot_store_ref
|
||||
SnapshotDataStoreVO snapshotStore = new SnapshotDataStoreVO(secStore.getId(), snapshotVO.getId());
|
||||
this._snapshotStoreDao.persist(snapshotStore);
|
||||
if (answer.isFull()) {
|
||||
snapshotVO.setPrevSnapshotId(0L);
|
||||
}
|
||||
this.snapshotDao.update(srcSnapshot.getId(), snapshotVO);
|
||||
}
|
||||
return answer;
|
||||
DataObject cacheData = null;
|
||||
try {
|
||||
if (destData.getDataStore().getRole() != DataStoreRole.ImageCache) {
|
||||
cacheData = cacheMgr.getCacheObject(srcData, destData.getDataStore().getScope());
|
||||
|
||||
CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _backupsnapshotwait);
|
||||
cmd.setCacheTO(cacheData.getTO());
|
||||
EndPoint ep = selector.select(srcData, destData);
|
||||
Answer answer = ep.sendMessage(cmd);
|
||||
return answer;
|
||||
} else {
|
||||
CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _backupsnapshotwait);
|
||||
EndPoint ep = selector.select(srcData, destData);
|
||||
Answer answer = ep.sendMessage(cmd);
|
||||
return answer;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
s_logger.debug("copy snasphot failed: " + e.toString());
|
||||
if (cacheData != null) {
|
||||
cacheMgr.deleteCacheObject(cacheData);
|
||||
}
|
||||
throw new CloudRuntimeException(e.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -30,6 +30,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat;
|
||||
import org.apache.cloudstack.storage.command.CopyCmdAnswer;
|
||||
import org.apache.cloudstack.storage.command.CreateObjectAnswer;
|
||||
import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
|
||||
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
|
||||
@ -234,6 +235,13 @@ public class SnapshotObject implements SnapshotInfo {
|
||||
SnapshotObjectTO snapshotTO = (SnapshotObjectTO)((CreateObjectAnswer) answer).getData();
|
||||
snapshotStore.setInstallPath(snapshotTO.getPath());
|
||||
this.snapshotStore.update(snapshotStore.getId(), snapshotStore);
|
||||
} else if (answer instanceof CopyCmdAnswer) {
|
||||
SnapshotObjectTO snapshotTO = (SnapshotObjectTO)((CopyCmdAnswer) answer).getNewData();
|
||||
snapshotStore.setInstallPath(snapshotTO.getPath());
|
||||
if (snapshotTO.getParentSnapshotPath() == null) {
|
||||
snapshotStore.setParentSnapshotId(0L);
|
||||
}
|
||||
this.snapshotStore.update(snapshotStore.getId(), snapshotStore);
|
||||
} else {
|
||||
throw new CloudRuntimeException("Unknown answer: " + answer.getClass());
|
||||
}
|
||||
|
||||
@ -399,7 +399,7 @@ public class SnapshotServiceImpl implements SnapshotService {
|
||||
|
||||
@Override
|
||||
public boolean deleteSnapshot(SnapshotInfo snapInfo) {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -44,6 +44,12 @@ SnapshotStateMachineManager {
|
||||
stateMachine.addTransition(Snapshot.State.CreatedOnPrimary, Event.BackupToSecondary, Snapshot.State.BackingUp);
|
||||
stateMachine.addTransition(Snapshot.State.BackingUp, Event.OperationSucceeded, Snapshot.State.BackedUp);
|
||||
stateMachine.addTransition(Snapshot.State.BackingUp, Event.OperationFailed, Snapshot.State.CreatedOnPrimary);
|
||||
stateMachine.addTransition(Snapshot.State.BackedUp, Event.DestroyRequested, Snapshot.State.Destroying);
|
||||
stateMachine.addTransition(Snapshot.State.BackedUp, Event.CopyingRequested, Snapshot.State.Copying);
|
||||
stateMachine.addTransition(Snapshot.State.Copying, Event.OperationSucceeded, Snapshot.State.BackedUp);
|
||||
stateMachine.addTransition(Snapshot.State.Copying, Event.OperationFailed, Snapshot.State.BackedUp);
|
||||
stateMachine.addTransition(Snapshot.State.Destroying, Event.OperationSucceeded, Snapshot.State.Destroyed);
|
||||
stateMachine.addTransition(Snapshot.State.Destroying, Event.OperationFailed, Snapshot.State.Error);
|
||||
|
||||
stateMachine.registerListener(new SnapshotStateListener());
|
||||
}
|
||||
|
||||
@ -9,9 +9,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy;
|
||||
public abstract class SnapshotStrategyBase implements SnapshotStrategy {
|
||||
@Inject
|
||||
SnapshotService snapshotSvr;
|
||||
//the default strategy is:
|
||||
//create snapshot,
|
||||
//backup, then delete snapshot on primary storage
|
||||
|
||||
@Override
|
||||
public SnapshotInfo takeSnapshot(SnapshotInfo snapshot) {
|
||||
return snapshotSvr.takeSnapshot(snapshot).getSnashot();
|
||||
|
||||
@ -27,6 +27,7 @@ import com.cloud.storage.DataStoreRole;
|
||||
import com.cloud.storage.Snapshot;
|
||||
import com.cloud.storage.SnapshotVO;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.dao.SnapshotDao;
|
||||
import com.cloud.storage.snapshot.SnapshotManager;
|
||||
import com.cloud.utils.NumbersUtil;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
@ -48,6 +49,8 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase {
|
||||
@Inject
|
||||
ConfigurationDao configDao;
|
||||
@Inject
|
||||
SnapshotDao snapshotDao;
|
||||
@Inject
|
||||
SnapshotDataFactory snapshotDataFactory;
|
||||
|
||||
@Override
|
||||
@ -114,82 +117,72 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase {
|
||||
snapshot.addPayload(fullBackup);
|
||||
return this.snapshotSvr.backupSnapshot(snapshot);
|
||||
}
|
||||
|
||||
protected void deleteSnapshotChain(SnapshotInfo snapshot) {
|
||||
while(snapshot != null) {
|
||||
SnapshotInfo child = snapshot.getChild();
|
||||
SnapshotInfo parent = snapshot.getParent();
|
||||
if (child == null) {
|
||||
if (!parent.getPath().equalsIgnoreCase(snapshot.getPath())) {
|
||||
this.snapshotSvr.deleteSnapshot(snapshot);
|
||||
snapshot = parent;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteSnapshot(SnapshotInfo snapshot) {
|
||||
Long snapshotId = snapshot.getId();
|
||||
SnapshotObject snapObj = (SnapshotObject)snapshot;
|
||||
|
||||
if (!Snapshot.State.BackedUp.equals(snapshot.getState()) || !Snapshot) {
|
||||
public boolean deleteSnapshot(Long snapshotId) {
|
||||
SnapshotVO snapshotVO = snapshotDao.findById(snapshotId);
|
||||
if (snapshotVO.getState() == Snapshot.State.Destroyed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Snapshot.State.BackedUp.equals(snapshotVO.getState())) {
|
||||
throw new InvalidParameterValueException("Can't delete snapshotshot " + snapshotId + " due to it is not in BackedUp Status");
|
||||
}
|
||||
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Calling deleteSnapshot for snapshotId: " + snapshotId);
|
||||
}
|
||||
SnapshotVO lastSnapshot = null;
|
||||
if (snapshot.getPrevSnapshotId() != null) {
|
||||
List<SnapshotVO> snaps = _snapshotDao.listByBackupUuid(snapshot.getVolumeId(), snapshot.getBackupSnapshotId());
|
||||
if (snaps != null && snaps.size() > 1) {
|
||||
snapshot.setBackupSnapshotId(null);
|
||||
SnapshotVO snapshotVO = this._snapshotDao.findById(snapshotId);
|
||||
_snapshotDao.update(snapshot.getId(), snapshotVO);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//firt mark the snapshot as destroyed, so that ui can't see it, but we may not destroy the snapshot on the storage, as other snaphosts may depend on it.
|
||||
SnapshotInfo snapshotOnPrimary = this.snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Primary);
|
||||
SnapshotObject obj = (SnapshotObject)snapshotOnPrimary;
|
||||
try {
|
||||
obj.processEvent(Snapshot.Event.DestroyRequested);
|
||||
} catch (NoTransitionException e) {
|
||||
s_logger.debug("Failed to destroy snapshot: " + e.toString());
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (snapshotOnPrimary != null) {
|
||||
deleteSnapshotChain(snapshotOnPrimary);
|
||||
}
|
||||
|
||||
_snapshotDao.remove(snapshotId);
|
||||
|
||||
long lastId = snapshotId;
|
||||
boolean destroy = false;
|
||||
while (true) {
|
||||
lastSnapshot = _snapshotDao.findNextSnapshot(lastId);
|
||||
if (lastSnapshot == null) {
|
||||
// if all snapshots after this snapshot in this chain are removed, remove those snapshots.
|
||||
destroy = true;
|
||||
break;
|
||||
}
|
||||
if (lastSnapshot.getRemoved() == null) {
|
||||
// if there is one child not removed, then can not remove back up snapshot.
|
||||
break;
|
||||
}
|
||||
lastId = lastSnapshot.getId();
|
||||
}
|
||||
if (destroy) {
|
||||
lastSnapshot = _snapshotDao.findByIdIncludingRemoved(lastId);
|
||||
while (lastSnapshot.getRemoved() != null) {
|
||||
String BackupSnapshotId = lastSnapshot.getBackupSnapshotId();
|
||||
if (BackupSnapshotId != null) {
|
||||
List<SnapshotVO> snaps = _snapshotDao.listByBackupUuid(lastSnapshot.getVolumeId(), BackupSnapshotId);
|
||||
if (snaps != null && snaps.size() > 1) {
|
||||
lastSnapshot.setBackupSnapshotId(null);
|
||||
_snapshotDao.update(lastSnapshot.getId(), lastSnapshot);
|
||||
} else {
|
||||
if (destroySnapshotBackUp(lastSnapshot)) {
|
||||
|
||||
} else {
|
||||
s_logger.debug("Destroying snapshot backup failed " + lastSnapshot);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
lastId = lastSnapshot.getPrevSnapshotId();
|
||||
if (lastId == 0) {
|
||||
break;
|
||||
}
|
||||
lastSnapshot = _snapshotDao.findByIdIncludingRemoved(lastId);
|
||||
}
|
||||
SnapshotInfo snapshotOnImage = this.snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Image);
|
||||
if (snapshotOnImage != null) {
|
||||
deleteSnapshotChain(snapshotOnImage);
|
||||
}
|
||||
|
||||
obj.processEvent(Snapshot.Event.OperationSucceeded);
|
||||
} catch (Exception e) {
|
||||
s_logger.debug("Failed to delete snapshot: " + e.toString());
|
||||
try {
|
||||
obj.processEvent(Snapshot.Event.OperationFailed);
|
||||
} catch (NoTransitionException e1) {
|
||||
s_logger.debug("Failed to change snapshot state: " + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canHandle(SnapshotInfo snapshot) {
|
||||
if (snapshot.getHypervisorType() == HypervisorType.XenServer) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SnapshotInfo takeSnapshot(SnapshotInfo snapshot) {
|
||||
@ -197,4 +190,13 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase {
|
||||
//TODO: add async
|
||||
return this.backupSnapshot(snapshot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canHandle(Snapshot snapshot) {
|
||||
if (snapshot.getHypervisorType() == HypervisorType.XenServer) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,33 +84,17 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager {
|
||||
|
||||
public ObjectInDataStoreManagerImpl() {
|
||||
stateMachines = new StateMachine2<State, Event, DataObjectInStore>();
|
||||
stateMachines.addTransition(State.Allocated, Event.CreateRequested,
|
||||
stateMachines.addTransition(State.Allocated, Event.CreateOnlyRequested,
|
||||
State.Creating);
|
||||
stateMachines.addTransition(State.Creating, Event.OperationSuccessed,
|
||||
State.Created);
|
||||
stateMachines.addTransition(State.Creating, Event.OperationFailed,
|
||||
State.Failed);
|
||||
stateMachines.addTransition(State.Failed, Event.CreateRequested,
|
||||
State.Creating);
|
||||
stateMachines.addTransition(State.Ready, Event.DestroyRequested,
|
||||
State.Destroying);
|
||||
stateMachines.addTransition(State.Destroying, Event.OperationSuccessed,
|
||||
State.Destroyed);
|
||||
stateMachines.addTransition(State.Destroying, Event.OperationFailed,
|
||||
State.Destroying);
|
||||
stateMachines.addTransition(State.Destroying, Event.DestroyRequested,
|
||||
State.Destroying);
|
||||
stateMachines.addTransition(State.Created, Event.CopyingRequested,
|
||||
State.Allocated);
|
||||
stateMachines.addTransition(State.Creating, Event.OperationSuccessed,
|
||||
State.Ready);
|
||||
stateMachines.addTransition(State.Ready, Event.CopyingRequested,
|
||||
State.Copying);
|
||||
stateMachines.addTransition(State.Copying, Event.OperationFailed,
|
||||
State.Created);
|
||||
stateMachines.addTransition(State.Copying, Event.OperationSuccessed,
|
||||
State.Ready);
|
||||
stateMachines.addTransition(State.Allocated, Event.CreateOnlyRequested,
|
||||
State.Creating2);
|
||||
stateMachines.addTransition(State.Creating2, Event.OperationFailed,
|
||||
State.Allocated);
|
||||
stateMachines.addTransition(State.Creating2, Event.OperationSuccessed,
|
||||
stateMachines.addTransition(State.Copying, Event.OperationFailed,
|
||||
State.Ready);
|
||||
}
|
||||
|
||||
|
||||
@ -149,4 +149,10 @@ public class SnapshotDataStoreDaoImpl extends GenericDaoBase<SnapshotDataStoreVO
|
||||
sc.setParameters("store_role", role);
|
||||
return findOneBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SnapshotDataStoreVO findByStoreSnapshot(long storeId, long snapshotId, boolean lock) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,12 +87,6 @@ public class SnapshotEntityImpl implements SnapshotEntity {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
@ -46,6 +46,8 @@ import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.utils.fsm.NoTransitionException;
|
||||
import com.cloud.utils.fsm.StateMachine2;
|
||||
import com.cloud.utils.storage.encoding.EncodingType;
|
||||
import com.cloud.vm.VMInstanceVO;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
|
||||
public class VolumeObject implements VolumeInfo {
|
||||
private static final Logger s_logger = Logger.getLogger(VolumeObject.class);
|
||||
@ -58,6 +60,8 @@ public class VolumeObject implements VolumeInfo {
|
||||
VolumeDataStoreDao volumeStoreDao;
|
||||
@Inject
|
||||
ObjectInDataStoreManager ojbectInStoreMgr;
|
||||
@Inject
|
||||
VMInstanceDao vmInstanceDao;
|
||||
private Object payload;
|
||||
|
||||
public VolumeObject() {
|
||||
@ -74,6 +78,19 @@ public class VolumeObject implements VolumeInfo {
|
||||
vo.configure(dataStore, volumeVO);
|
||||
return vo;
|
||||
}
|
||||
|
||||
public String getAttachedVmName() {
|
||||
Long vmId = this.volumeVO.getInstanceId();
|
||||
if (vmId != null) {
|
||||
VMInstanceVO vm = vmInstanceDao.findById(vmId);
|
||||
|
||||
if (vm == null) {
|
||||
return null;
|
||||
}
|
||||
return vm.getInstanceName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUuid() {
|
||||
|
||||
@ -408,15 +408,17 @@ public class VolumeServiceImpl implements VolumeService {
|
||||
private final AsyncCallFuture<VolumeApiResult> future;
|
||||
private final DataStore primaryStore;
|
||||
private final DataObject templateOnStore;
|
||||
private final SnapshotInfo snapshot;
|
||||
public CreateVolumeFromBaseImageContext(AsyncCompletionCallback<T> callback, VolumeObject vo,
|
||||
DataStore primaryStore,
|
||||
DataObject templateOnStore,
|
||||
AsyncCallFuture<VolumeApiResult> future) {
|
||||
AsyncCallFuture<VolumeApiResult> future, SnapshotInfo snapshot) {
|
||||
super(callback);
|
||||
this.vo = vo;
|
||||
this.future = future;
|
||||
this.primaryStore = primaryStore;
|
||||
this.templateOnStore = templateOnStore;
|
||||
this.snapshot = snapshot;
|
||||
}
|
||||
|
||||
|
||||
@ -428,7 +430,7 @@ public class VolumeServiceImpl implements VolumeService {
|
||||
@DB
|
||||
protected void createVolumeFromBaseImageAsync(VolumeInfo volume, DataObject templateOnPrimaryStore, PrimaryDataStore pd, AsyncCallFuture<VolumeApiResult> future) {
|
||||
VolumeObject vo = (VolumeObject)volume;
|
||||
CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null, vo, pd, templateOnPrimaryStore, future);
|
||||
CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null, vo, pd, templateOnPrimaryStore, future, null);
|
||||
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
|
||||
caller.setCallback(caller.getTarget().createVolumeFromBaseImageCallBack(null, null))
|
||||
.setContext(context);
|
||||
@ -497,8 +499,9 @@ public class VolumeServiceImpl implements VolumeService {
|
||||
try {
|
||||
DataObject volumeOnStore = store.create(volume);
|
||||
volume.processEvent(Event.CreateOnlyRequested);
|
||||
snapshot.processEvent(Event.CopyingRequested);
|
||||
CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null,
|
||||
(VolumeObject)volume, store, volumeOnStore, future);
|
||||
(VolumeObject)volume, store, volumeOnStore, future, snapshot);
|
||||
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
|
||||
caller.setCallback(caller.getTarget().createVolumeFromSnapshotCallback(null, null))
|
||||
.setContext(context);
|
||||
@ -517,6 +520,7 @@ public class VolumeServiceImpl implements VolumeService {
|
||||
CreateVolumeFromBaseImageContext<VolumeApiResult> context) {
|
||||
CopyCommandResult result = callback.getResult();
|
||||
VolumeInfo volume = context.vo;
|
||||
SnapshotInfo snapshot = context.snapshot;
|
||||
VolumeApiResult apiResult = new VolumeApiResult(volume);
|
||||
Event event = null;
|
||||
if (result.isFailed()) {
|
||||
@ -528,6 +532,7 @@ public class VolumeServiceImpl implements VolumeService {
|
||||
|
||||
try {
|
||||
volume.processEvent(event);
|
||||
snapshot.processEvent(event);
|
||||
} catch (Exception e) {
|
||||
s_logger.debug("create volume from snapshot failed", e);
|
||||
apiResult.setResult(e.toString());
|
||||
|
||||
@ -3620,7 +3620,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
||||
return false;
|
||||
}
|
||||
|
||||
private void swiftBackupSnapshot(Connection conn, SwiftTO swift, String srUuid, String snapshotUuid, String container, Boolean isISCSI, int wait) {
|
||||
public void swiftBackupSnapshot(Connection conn, SwiftTO swift, String srUuid, String snapshotUuid, String container, Boolean isISCSI, int wait) {
|
||||
String lfilename;
|
||||
String ldir;
|
||||
if ( isISCSI ) {
|
||||
|
||||
@ -18,12 +18,20 @@
|
||||
*/
|
||||
package com.cloud.hypervisor.xen.resource;
|
||||
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -43,6 +51,7 @@ import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
|
||||
import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol;
|
||||
import org.apache.cloudstack.storage.to.ImageStoreTO;
|
||||
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
|
||||
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
|
||||
import org.apache.cloudstack.storage.to.TemplateObjectTO;
|
||||
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
||||
import org.apache.http.HttpEntity;
|
||||
@ -54,18 +63,25 @@ import org.apache.log4j.Logger;
|
||||
import org.apache.xmlrpc.XmlRpcException;
|
||||
|
||||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.BackupSnapshotAnswer;
|
||||
import com.cloud.agent.api.Command;
|
||||
import com.cloud.agent.api.ManageSnapshotAnswer;
|
||||
import com.cloud.agent.api.ManageSnapshotCommand;
|
||||
import com.cloud.agent.api.storage.CopyVolumeAnswer;
|
||||
import com.cloud.agent.api.storage.CreateAnswer;
|
||||
import com.cloud.agent.api.storage.DeleteVolumeCommand;
|
||||
import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
|
||||
import com.cloud.agent.api.to.DataStoreTO;
|
||||
import com.cloud.agent.api.to.NfsTO;
|
||||
import com.cloud.agent.api.to.S3TO;
|
||||
import com.cloud.agent.api.to.StorageFilerTO;
|
||||
import com.cloud.agent.api.to.SwiftTO;
|
||||
import com.cloud.agent.api.to.VolumeTO;
|
||||
import com.cloud.exception.InternalErrorException;
|
||||
import com.cloud.hypervisor.xen.resource.CitrixResourceBase.SRType;
|
||||
import com.cloud.storage.DataStoreRole;
|
||||
import com.cloud.utils.S3Utils;
|
||||
import com.cloud.utils.StringUtils;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.utils.storage.encoding.DecodedDataObject;
|
||||
import com.cloud.utils.storage.encoding.DecodedDataStore;
|
||||
@ -80,8 +96,6 @@ import com.xensource.xenapi.Types.BadServerResponse;
|
||||
import com.xensource.xenapi.Types.XenAPIException;
|
||||
import com.xensource.xenapi.VDI;
|
||||
|
||||
import edu.emory.mathcs.backport.java.util.Arrays;
|
||||
|
||||
public class XenServerStorageResource {
|
||||
private static final Logger s_logger = Logger.getLogger(XenServerStorageResource.class);
|
||||
protected CitrixResourceBase hypervisorResource;
|
||||
@ -146,12 +160,62 @@ public class XenServerStorageResource {
|
||||
return new CreateObjectAnswer(cmd, templateUrl, size);*/
|
||||
return null;
|
||||
}
|
||||
|
||||
protected CreateObjectAnswer createSnapshot(SnapshotObjectTO snapshotTO) {
|
||||
Connection conn = hypervisorResource.getConnection();
|
||||
long snapshotId = snapshotTO.getId();
|
||||
String snapshotName = snapshotTO.getName();
|
||||
String details = "create snapshot operation Failed for snapshotId: " + snapshotId;
|
||||
String snapshotUUID = null;
|
||||
|
||||
try {
|
||||
String volumeUUID = snapshotTO.getVolume().getPath();
|
||||
VDI volume = VDI.getByUuid(conn, volumeUUID);
|
||||
|
||||
VDI snapshot = volume.snapshot(conn, new HashMap<String, String>());
|
||||
|
||||
if (snapshotName != null) {
|
||||
snapshot.setNameLabel(conn, snapshotName);
|
||||
}
|
||||
|
||||
snapshotUUID = snapshot.getUuid(conn);
|
||||
String preSnapshotUUID = snapshotTO.getPath();
|
||||
//check if it is a empty snapshot
|
||||
if( preSnapshotUUID != null) {
|
||||
SR sr = volume.getSR(conn);
|
||||
String srUUID = sr.getUuid(conn);
|
||||
String type = sr.getType(conn);
|
||||
Boolean isISCSI = IsISCSI(type);
|
||||
String snapshotParentUUID = getVhdParent(conn, srUUID, snapshotUUID, isISCSI);
|
||||
|
||||
String preSnapshotParentUUID = getVhdParent(conn, srUUID, preSnapshotUUID, isISCSI);
|
||||
if( snapshotParentUUID != null && snapshotParentUUID.equals(preSnapshotParentUUID)) {
|
||||
// this is empty snapshot, remove it
|
||||
snapshot.destroy(conn);
|
||||
snapshotUUID = preSnapshotUUID;
|
||||
}
|
||||
}
|
||||
SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
|
||||
newSnapshot.setPath(snapshotUUID);
|
||||
return new CreateObjectAnswer(newSnapshot);
|
||||
} catch (XenAPIException e) {
|
||||
details += ", reason: " + e.toString();
|
||||
s_logger.warn(details, e);
|
||||
} catch (Exception e) {
|
||||
details += ", reason: " + e.toString();
|
||||
s_logger.warn(details, e);
|
||||
}
|
||||
|
||||
return new CreateObjectAnswer(details);
|
||||
}
|
||||
protected CreateObjectAnswer execute(CreateObjectCommand cmd) {
|
||||
DataTO data = cmd.getData();
|
||||
try {
|
||||
if (data.getObjectType() == DataObjectType.VOLUME) {
|
||||
return createVolume(data);
|
||||
}
|
||||
} else if (data.getObjectType() == DataObjectType.SNAPSHOT) {
|
||||
return createSnapshot((SnapshotObjectTO)data);
|
||||
}
|
||||
return new CreateObjectAnswer("not supported type");
|
||||
} catch (Exception e) {
|
||||
s_logger.debug("Failed to create object: " + data.getObjectType() + ": " + e.toString());
|
||||
@ -821,6 +885,330 @@ public class XenServerStorageResource {
|
||||
return new CopyCmdAnswer("unsupported protocol");
|
||||
}
|
||||
|
||||
boolean swiftUpload(Connection conn, SwiftTO swift, String container, String ldir, String lfilename, Boolean isISCSI, int wait) {
|
||||
String result = null;
|
||||
try {
|
||||
result = hypervisorResource.callHostPluginAsync(conn, "swiftxen", "swift", wait,
|
||||
"op", "upload", "url", swift.getUrl(), "account", swift.getAccount(),
|
||||
"username", swift.getUserName(), "key", swift.getKey(), "container", container,
|
||||
"ldir", ldir, "lfilename", lfilename, "isISCSI", isISCSI.toString());
|
||||
if( result != null && result.equals("true")) {
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
s_logger.warn("swift upload failed due to " + e.toString(), e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected String deleteSnapshotBackup(Connection conn, String path, String secondaryStorageMountPath, String backupUUID) {
|
||||
|
||||
// If anybody modifies the formatting below again, I'll skin them
|
||||
String result = hypervisorResource.callHostPlugin(conn, "vmopsSnapshot", "deleteSnapshotBackup", "backupUUID", backupUUID, "path", path, "secondaryStorageMountPath", secondaryStorageMountPath);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void swiftBackupSnapshot(Connection conn, SwiftTO swift, String srUuid, String snapshotUuid, String container, Boolean isISCSI, int wait) {
|
||||
String lfilename;
|
||||
String ldir;
|
||||
if ( isISCSI ) {
|
||||
ldir = "/dev/VG_XenStorage-" + srUuid;
|
||||
lfilename = "VHD-" + snapshotUuid;
|
||||
} else {
|
||||
ldir = "/var/run/sr-mount/" + srUuid;
|
||||
lfilename = snapshotUuid + ".vhd";
|
||||
}
|
||||
swiftUpload(conn, swift, container, ldir, lfilename, isISCSI, wait);
|
||||
}
|
||||
|
||||
private static List<String> serializeProperties(final Object object,
|
||||
final Class<?> propertySet) {
|
||||
|
||||
assert object != null;
|
||||
assert propertySet != null;
|
||||
assert propertySet.isAssignableFrom(object.getClass());
|
||||
|
||||
try {
|
||||
|
||||
final BeanInfo beanInfo = Introspector.getBeanInfo(propertySet);
|
||||
final PropertyDescriptor[] descriptors = beanInfo
|
||||
.getPropertyDescriptors();
|
||||
|
||||
final List<String> serializedProperties = new ArrayList<String>();
|
||||
for (final PropertyDescriptor descriptor : descriptors) {
|
||||
|
||||
serializedProperties.add(descriptor.getName());
|
||||
final Object value = descriptor.getReadMethod().invoke(object);
|
||||
serializedProperties.add(value != null ? value.toString()
|
||||
: "null");
|
||||
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(serializedProperties);
|
||||
|
||||
} catch (IntrospectionException e) {
|
||||
s_logger.warn(
|
||||
"Ignored IntrospectionException when serializing class "
|
||||
+ object.getClass().getCanonicalName(), e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
s_logger.warn(
|
||||
"Ignored IllegalArgumentException when serializing class "
|
||||
+ object.getClass().getCanonicalName(), e);
|
||||
} catch (IllegalAccessException e) {
|
||||
s_logger.warn(
|
||||
"Ignored IllegalAccessException when serializing class "
|
||||
+ object.getClass().getCanonicalName(), e);
|
||||
} catch (InvocationTargetException e) {
|
||||
s_logger.warn(
|
||||
"Ignored InvocationTargetException when serializing class "
|
||||
+ object.getClass().getCanonicalName(), e);
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
|
||||
}
|
||||
|
||||
private boolean backupSnapshotToS3(final Connection connection,
|
||||
final S3TO s3, final String srUuid, final String snapshotUuid,
|
||||
final Boolean iSCSIFlag, final int wait) {
|
||||
|
||||
final String filename = iSCSIFlag ? "VHD-" + snapshotUuid
|
||||
: snapshotUuid + ".vhd";
|
||||
final String dir = (iSCSIFlag ? "/dev/VG_XenStorage-"
|
||||
: "/var/run/sr-mount/") + srUuid;
|
||||
final String key = StringUtils.join("/", "snapshots", snapshotUuid);
|
||||
|
||||
try {
|
||||
|
||||
final List<String> parameters = new ArrayList<String>(
|
||||
serializeProperties(s3, S3Utils.ClientOptions.class));
|
||||
parameters.addAll(Arrays.asList("operation", "put", "directory",
|
||||
dir, "filename", filename, "iSCSIFlag",
|
||||
iSCSIFlag.toString(), "key", key));
|
||||
final String result = hypervisorResource.callHostPluginAsync(connection, "s3xen",
|
||||
"s3", wait,
|
||||
parameters.toArray(new String[parameters.size()]));
|
||||
|
||||
if (result != null && result.equals("true")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
s_logger.error(String.format(
|
||||
"S3 upload failed of snapshot %1$s due to %2$s.",
|
||||
snapshotUuid, e.toString()), e);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
protected String backupSnapshot(Connection conn, String primaryStorageSRUuid, String path, String secondaryStorageMountPath, String snapshotUuid, String prevBackupUuid, Boolean isISCSI, int wait) {
|
||||
String backupSnapshotUuid = null;
|
||||
|
||||
if (prevBackupUuid == null) {
|
||||
prevBackupUuid = "";
|
||||
}
|
||||
|
||||
// Each argument is put in a separate line for readability.
|
||||
// Using more lines does not harm the environment.
|
||||
String backupUuid = UUID.randomUUID().toString();
|
||||
String results = hypervisorResource.callHostPluginAsync(conn, "vmopsSnapshot", "backupSnapshot", wait,
|
||||
"primaryStorageSRUuid", primaryStorageSRUuid, "path", path, "secondaryStorageMountPath", secondaryStorageMountPath,
|
||||
"snapshotUuid", snapshotUuid, "prevBackupUuid", prevBackupUuid, "backupUuid", backupUuid, "isISCSI", isISCSI.toString());
|
||||
String errMsg = null;
|
||||
if (results == null || results.isEmpty()) {
|
||||
errMsg = "Could not copy backupUuid: " + backupSnapshotUuid
|
||||
+ " from primary storage " + primaryStorageSRUuid + " to secondary storage "
|
||||
+ secondaryStorageMountPath + " due to null";
|
||||
} else {
|
||||
|
||||
String[] tmp = results.split("#");
|
||||
String status = tmp[0];
|
||||
backupSnapshotUuid = tmp[1];
|
||||
// status == "1" if and only if backupSnapshotUuid != null
|
||||
// So we don't rely on status value but return backupSnapshotUuid as an
|
||||
// indicator of success.
|
||||
if (status != null && status.equalsIgnoreCase("1") && backupSnapshotUuid != null) {
|
||||
s_logger.debug("Successfully copied backupUuid: " + backupSnapshotUuid
|
||||
+ " to secondary storage");
|
||||
return backupSnapshotUuid;
|
||||
} else {
|
||||
errMsg = "Could not copy backupUuid: " + backupSnapshotUuid
|
||||
+ " from primary storage " + primaryStorageSRUuid + " to secondary storage "
|
||||
+ secondaryStorageMountPath + " due to " + tmp[1];
|
||||
}
|
||||
}
|
||||
String source = backupUuid + ".vhd";
|
||||
hypervisorResource.killCopyProcess(conn, source);
|
||||
s_logger.warn(errMsg);
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
private boolean destroySnapshotOnPrimaryStorageExceptThis(Connection conn, String volumeUuid, String avoidSnapshotUuid){
|
||||
try {
|
||||
VDI volume = getVDIbyUuid(conn, volumeUuid);
|
||||
if (volume == null) {
|
||||
throw new InternalErrorException("Could not destroy snapshot on volume " + volumeUuid + " due to can not find it");
|
||||
}
|
||||
Set<VDI> snapshots = volume.getSnapshots(conn);
|
||||
for( VDI snapshot : snapshots ) {
|
||||
try {
|
||||
if(! snapshot.getUuid(conn).equals(avoidSnapshotUuid)) {
|
||||
snapshot.destroy(conn);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String msg = "Destroying snapshot: " + snapshot+ " on primary storage failed due to " + e.toString();
|
||||
s_logger.warn(msg, e);
|
||||
}
|
||||
}
|
||||
s_logger.debug("Successfully destroyed snapshot on volume: " + volumeUuid + " execept this current snapshot "+ avoidSnapshotUuid );
|
||||
return true;
|
||||
} catch (XenAPIException e) {
|
||||
String msg = "Destroying snapshot on volume: " + volumeUuid + " execept this current snapshot "+ avoidSnapshotUuid + " failed due to " + e.toString();
|
||||
s_logger.error(msg, e);
|
||||
} catch (Exception e) {
|
||||
String msg = "Destroying snapshot on volume: " + volumeUuid + " execept this current snapshot "+ avoidSnapshotUuid + " failed due to " + e.toString();
|
||||
s_logger.warn(msg, e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Answer backupSnasphot(DataTO srcData, DataTO destData, DataTO cacheData, int wait) {
|
||||
Connection conn = hypervisorResource.getConnection();
|
||||
PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)srcData.getDataStore();
|
||||
String primaryStorageNameLabel = primaryStore.getUuid();
|
||||
String secondaryStorageUrl = null;
|
||||
NfsTO cacheStore = null;
|
||||
String destPath = null;
|
||||
if (cacheData != null) {
|
||||
cacheStore = (NfsTO)cacheData.getDataStore();
|
||||
secondaryStorageUrl = cacheStore.getUrl();
|
||||
destPath = cacheData.getPath();
|
||||
} else {
|
||||
cacheStore = (NfsTO)destData.getDataStore();
|
||||
secondaryStorageUrl = cacheStore.getUrl();
|
||||
destPath = destData.getPath();
|
||||
}
|
||||
|
||||
SnapshotObjectTO snapshotTO = (SnapshotObjectTO)srcData;
|
||||
SnapshotObjectTO snapshotOnImage = (SnapshotObjectTO)destData;
|
||||
String snapshotUuid = snapshotTO.getPath();
|
||||
|
||||
String prevBackupUuid = snapshotOnImage.getParentSnapshotPath();
|
||||
String prevSnapshotUuid = snapshotTO.getParentSnapshotPath();
|
||||
|
||||
// By default assume failure
|
||||
String details = null;
|
||||
String snapshotBackupUuid = null;
|
||||
boolean fullbackup = true;
|
||||
try {
|
||||
SR primaryStorageSR = hypervisorResource.getSRByNameLabelandHost(conn, primaryStorageNameLabel);
|
||||
if (primaryStorageSR == null) {
|
||||
throw new InternalErrorException("Could not backup snapshot because the primary Storage SR could not be created from the name label: " + primaryStorageNameLabel);
|
||||
}
|
||||
String psUuid = primaryStorageSR.getUuid(conn);
|
||||
Boolean isISCSI = IsISCSI(primaryStorageSR.getType(conn));
|
||||
|
||||
VDI snapshotVdi = getVDIbyUuid(conn, snapshotUuid);
|
||||
String snapshotPaUuid = null;
|
||||
if ( prevBackupUuid != null ) {
|
||||
try {
|
||||
snapshotPaUuid = getVhdParent(conn, psUuid, snapshotUuid, isISCSI);
|
||||
if( snapshotPaUuid != null ) {
|
||||
String snashotPaPaPaUuid = getVhdParent(conn, psUuid, snapshotPaUuid, isISCSI);
|
||||
String prevSnashotPaUuid = getVhdParent(conn, psUuid, prevSnapshotUuid, isISCSI);
|
||||
if (snashotPaPaPaUuid != null && prevSnashotPaUuid!= null && prevSnashotPaUuid.equals(snashotPaPaPaUuid)) {
|
||||
fullbackup = false;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
URI uri = new URI(secondaryStorageUrl);
|
||||
String secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
|
||||
DataStoreTO destStore = destData.getDataStore();
|
||||
String folder = destPath;
|
||||
if (fullbackup) {
|
||||
// the first snapshot is always a full snapshot
|
||||
|
||||
if( !hypervisorResource.createSecondaryStorageFolder(conn, secondaryStorageMountPath, folder)) {
|
||||
details = " Filed to create folder " + folder + " in secondary storage";
|
||||
s_logger.warn(details);
|
||||
return new CopyCmdAnswer(details);
|
||||
}
|
||||
String snapshotMountpoint = secondaryStorageUrl + "/" + folder;
|
||||
SR snapshotSr = null;
|
||||
try {
|
||||
snapshotSr = hypervisorResource.createNfsSRbyURI(conn, new URI(snapshotMountpoint), false);
|
||||
VDI backedVdi = hypervisorResource.cloudVDIcopy(conn, snapshotVdi, snapshotSr, wait);
|
||||
snapshotBackupUuid = backedVdi.getUuid(conn);
|
||||
|
||||
if( destStore instanceof SwiftTO) {
|
||||
try {
|
||||
hypervisorResource.swiftBackupSnapshot(conn, (SwiftTO)destStore, snapshotSr.getUuid(conn), snapshotBackupUuid, "S-" + snapshotTO.getVolume().getVolumeId().toString(), false, wait);
|
||||
snapshotBackupUuid = snapshotBackupUuid + ".vhd";
|
||||
} finally {
|
||||
deleteSnapshotBackup(conn, folder, secondaryStorageMountPath, snapshotBackupUuid);
|
||||
}
|
||||
} else if (destStore instanceof S3TO) {
|
||||
try {
|
||||
backupSnapshotToS3(conn, (S3TO)destStore, snapshotSr.getUuid(conn), snapshotBackupUuid, isISCSI, wait);
|
||||
snapshotBackupUuid = snapshotBackupUuid + ".vhd";
|
||||
} finally {
|
||||
deleteSnapshotBackup(conn, folder, secondaryStorageMountPath, snapshotBackupUuid);
|
||||
}
|
||||
}
|
||||
|
||||
} finally {
|
||||
if( snapshotSr != null) {
|
||||
hypervisorResource.removeSR(conn, snapshotSr);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String primaryStorageSRUuid = primaryStorageSR.getUuid(conn);
|
||||
if( destStore instanceof SwiftTO ) {
|
||||
swiftBackupSnapshot(conn, (SwiftTO)destStore, primaryStorageSRUuid, snapshotPaUuid, "S-" + snapshotTO.getVolume().getVolumeId().toString(), isISCSI, wait);
|
||||
if ( isISCSI ) {
|
||||
snapshotBackupUuid = "VHD-" + snapshotPaUuid;
|
||||
} else {
|
||||
snapshotBackupUuid = snapshotPaUuid + ".vhd";
|
||||
}
|
||||
|
||||
} else if (destStore instanceof S3TO ) {
|
||||
backupSnapshotToS3(conn, (S3TO)destStore, primaryStorageSRUuid, snapshotPaUuid, isISCSI, wait);
|
||||
} else {
|
||||
snapshotBackupUuid = backupSnapshot(conn, primaryStorageSRUuid, folder + File.separator + UUID.nameUUIDFromBytes(secondaryStorageMountPath.getBytes())
|
||||
, secondaryStorageMountPath, snapshotUuid, prevBackupUuid, isISCSI, wait);
|
||||
|
||||
}
|
||||
}
|
||||
String volumeUuid = snapshotTO.getVolume().getPath();
|
||||
destroySnapshotOnPrimaryStorageExceptThis(conn, volumeUuid, snapshotUuid);
|
||||
|
||||
SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
|
||||
newSnapshot.setPath(snapshotBackupUuid);
|
||||
if (fullbackup) {
|
||||
newSnapshot.setParentSnapshotPath(null);
|
||||
} else {
|
||||
newSnapshot.setParentSnapshotPath(prevBackupUuid);
|
||||
}
|
||||
return new CopyCmdAnswer(newSnapshot);
|
||||
} catch (XenAPIException e) {
|
||||
details = "BackupSnapshot Failed due to " + e.toString();
|
||||
s_logger.warn(details, e);
|
||||
} catch (Exception e) {
|
||||
details = "BackupSnapshot Failed due to " + e.getMessage();
|
||||
s_logger.warn(details, e);
|
||||
}
|
||||
|
||||
return new CopyCmdAnswer(details);
|
||||
}
|
||||
|
||||
protected Answer execute(CopyCommand cmd) {
|
||||
DataTO srcData = cmd.getSrcTO();
|
||||
DataTO destData = cmd.getDestTO();
|
||||
@ -838,6 +1226,9 @@ public class XenServerStorageResource {
|
||||
return copyVolumeFromImageCacheToPrimary(srcData, destData, cmd.getWait());
|
||||
} else if (srcData.getObjectType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
|
||||
return copyVolumeFromPrimaryToSecondary(srcData, destData, cmd.getWait());
|
||||
} else if (srcData.getObjectType() == DataObjectType.SNAPSHOT && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
|
||||
DataTO cacheData = cmd.getCacheTO();
|
||||
return backupSnasphot(srcData, destData, cacheData, cmd.getWait());
|
||||
}
|
||||
|
||||
return new Answer(cmd, false, "not implemented yet");
|
||||
|
||||
@ -36,6 +36,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
|
||||
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
|
||||
import org.apache.cloudstack.storage.command.CreateObjectCommand;
|
||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
|
||||
import org.apache.cloudstack.storage.volume.VolumeObject;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
@ -193,24 +194,17 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri
|
||||
AsyncCompletionCallback<CreateCmdResult> callback) {
|
||||
CreateCmdResult result = null;
|
||||
try {
|
||||
VolumeInfo volume = snapshot.getBaseVolume();
|
||||
String vmName = this.volumeMgr.getVmNameOnVolume(volume);
|
||||
SnapshotVO preSnapshotVO = this.snapshotMgr.getParentSnapshot(volume, snapshot);
|
||||
String parentSnapshotPath = null;
|
||||
if (preSnapshotVO != null) {
|
||||
parentSnapshotPath = preSnapshotVO.getPath();
|
||||
DataTO snapshotTO = snapshot.getTO();
|
||||
|
||||
CreateObjectCommand cmd = new CreateObjectCommand(snapshotTO);
|
||||
Answer answer = storageMgr.sendToPool((StoragePool)snapshot.getDataStore(), null, cmd);
|
||||
|
||||
result = new CreateCmdResult(null, answer);
|
||||
if (answer != null && !answer.getResult()) {
|
||||
result.setResult(answer.getDetails());
|
||||
}
|
||||
StoragePool srcPool = (StoragePool)volume.getDataStore();
|
||||
|
||||
ManageSnapshotCommand cmd = new ManageSnapshotCommand(snapshot.getId(), volume.getPath(), srcPool, parentSnapshotPath, snapshot.getName(), vmName);
|
||||
|
||||
ManageSnapshotAnswer answer = (ManageSnapshotAnswer) this.snapshotMgr.sendToPool(volume, cmd);
|
||||
|
||||
if ((answer != null) && answer.getResult()) {
|
||||
result = new CreateCmdResult(answer.getSnapshotPath(), null);
|
||||
} else {
|
||||
result = new CreateCmdResult(null, null);
|
||||
}
|
||||
callback.complete(result);
|
||||
} catch (Exception e) {
|
||||
s_logger.debug("Failed to take snapshot: " + snapshot.getId(), e);
|
||||
result = new CreateCmdResult(null, null);
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
package com.cloud.storage;
|
||||
|
||||
import com.cloud.user.Account;
|
||||
|
||||
public class CreateSnapshotPayload {
|
||||
private Long snapshotPolicyId;
|
||||
private Long snapshotId;
|
||||
private Account account;
|
||||
|
||||
public Long getSnapshotPolicyId() {
|
||||
return snapshotPolicyId;
|
||||
@ -11,4 +15,20 @@ public class CreateSnapshotPayload {
|
||||
this.snapshotPolicyId = snapshotPolicyId;
|
||||
}
|
||||
|
||||
public Long getSnapshotId() {
|
||||
return snapshotId;
|
||||
}
|
||||
|
||||
public void setSnapshotId(Long snapshotId) {
|
||||
this.snapshotId = snapshotId;
|
||||
}
|
||||
|
||||
public Account getAccount() {
|
||||
return account;
|
||||
}
|
||||
|
||||
public void setAccount(Account account) {
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -133,6 +133,7 @@ import com.cloud.storage.dao.VolumeDao;
|
||||
import com.cloud.storage.download.DownloadMonitor;
|
||||
import com.cloud.storage.s3.S3Manager;
|
||||
import com.cloud.storage.secondary.SecondaryStorageVmManager;
|
||||
import com.cloud.storage.snapshot.SnapshotApiService;
|
||||
import com.cloud.storage.snapshot.SnapshotManager;
|
||||
import com.cloud.storage.snapshot.SnapshotScheduler;
|
||||
import com.cloud.tags.dao.ResourceTagDao;
|
||||
@ -307,6 +308,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
TemplateDataFactory tmplFactory;
|
||||
@Inject
|
||||
SnapshotDataFactory snapshotFactory;
|
||||
@Inject
|
||||
SnapshotApiService snapshotMgr;
|
||||
private int _copyvolumewait;
|
||||
@Inject
|
||||
protected HypervisorCapabilitiesDao _hypervisorCapabilitiesDao;
|
||||
@ -526,7 +529,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
|
||||
VolumeInfo vol = this.volFactory.getVolume(volume.getId());
|
||||
DataStore store = this.dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary);
|
||||
SnapshotInfo snapInfo = this.snapshotFactory.getSnapshot(snapshot.getId());
|
||||
SnapshotInfo snapInfo = this.snapshotFactory.getSnapshot(snapshot.getId(), DataStoreRole.Image);
|
||||
AsyncCallFuture<VolumeApiResult> future = this.volService.createVolumeFromSnapshot(vol, store, snapInfo);
|
||||
try {
|
||||
VolumeApiResult result = future.get();
|
||||
@ -2470,8 +2473,26 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
|
||||
|
||||
@Override
|
||||
public Snapshot takeSnapshot(Long volumeId, Long policyId) throws ResourceAllocationException {
|
||||
Account caller = UserContext.current().getCaller();
|
||||
public Snapshot takeSnapshot(Long volumeId, Long policyId, Long snapshotId, Account account) throws ResourceAllocationException {
|
||||
VolumeInfo volume = this.volFactory.getVolume(volumeId);
|
||||
if (volume == null) {
|
||||
throw new InvalidParameterValueException("Creating snapshot failed due to volume:" + volumeId + " doesn't exist");
|
||||
}
|
||||
|
||||
if (volume.getState() != Volume.State.Ready) {
|
||||
throw new InvalidParameterValueException("VolumeId: " + volumeId + " is not in " + Volume.State.Ready + " state but " + volume.getState() + ". Cannot take snapshot.");
|
||||
}
|
||||
|
||||
CreateSnapshotPayload payload = new CreateSnapshotPayload();
|
||||
payload.setSnapshotId(snapshotId);
|
||||
payload.setSnapshotPolicyId(policyId);
|
||||
payload.setAccount(account);
|
||||
return this.volService.takeSnapshot(volume);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Snapshot allocSnapshot(Long volumeId, Long policyId) throws ResourceAllocationException {
|
||||
Account caller = UserContext.current().getCaller();
|
||||
|
||||
VolumeInfo volume = this.volFactory.getVolume(volumeId);
|
||||
if (volume == null) {
|
||||
@ -2502,10 +2523,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
||||
throw new InvalidParameterValueException("VolumeId: " + volumeId + " please attach this volume to a VM before create snapshot for it");
|
||||
}
|
||||
|
||||
CreateSnapshotPayload payload = new CreateSnapshotPayload();
|
||||
payload.setSnapshotPolicyId(policyId);
|
||||
return this.volService.takeSnapshot(volume);
|
||||
|
||||
return this.snapshotMgr.allocSnapshot(volumeId, policyId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -151,7 +151,7 @@ public class SnapshotDaoImpl extends GenericDaoBase<SnapshotVO, Long> implements
|
||||
VolumeIdVersionSearch.and("volumeId", VolumeIdVersionSearch.entity().getVolumeId(), SearchCriteria.Op.EQ);
|
||||
VolumeIdVersionSearch.and("version", VolumeIdVersionSearch.entity().getVersion(), SearchCriteria.Op.EQ);
|
||||
VolumeIdVersionSearch.done();
|
||||
|
||||
/*
|
||||
ParentIdSearch = createSearchBuilder();
|
||||
ParentIdSearch.and("prevSnapshotId", ParentIdSearch.entity().getPrevSnapshotId(), SearchCriteria.Op.EQ);
|
||||
ParentIdSearch.done();
|
||||
@ -159,7 +159,7 @@ public class SnapshotDaoImpl extends GenericDaoBase<SnapshotVO, Long> implements
|
||||
backupUuidSearch = createSearchBuilder();
|
||||
backupUuidSearch.and("backupUuid", backupUuidSearch.entity().getBackupSnapshotId(), SearchCriteria.Op.EQ);
|
||||
backupUuidSearch.done();
|
||||
|
||||
*/
|
||||
AccountIdSearch = createSearchBuilder();
|
||||
AccountIdSearch.and("accountId", AccountIdSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
|
||||
AccountIdSearch.done();
|
||||
|
||||
@ -56,10 +56,6 @@ public interface SnapshotManager {
|
||||
* The account which is to be deleted.
|
||||
*/
|
||||
boolean deleteSnapshotDirsForAccount(long accountId);
|
||||
|
||||
void downloadSnapshotsFromSwift(SnapshotVO ss);
|
||||
|
||||
void downloadSnapshotsFromS3(SnapshotVO snapshot);
|
||||
|
||||
String getSecondaryStorageURL(SnapshotVO snapshot);
|
||||
|
||||
|
||||
@ -349,8 +349,10 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
return this.snapshotSrv.backupSnapshot(snapshot);
|
||||
}
|
||||
|
||||
/*
|
||||
@Override
|
||||
public void downloadSnapshotsFromSwift(SnapshotVO ss) {
|
||||
|
||||
long volumeId = ss.getVolumeId();
|
||||
VolumeVO volume = _volsDao.findById(volumeId);
|
||||
Long dcId = volume.getDataCenterId();
|
||||
@ -432,7 +434,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
e);
|
||||
}
|
||||
|
||||
}
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public SnapshotVO getParentSnapshot(VolumeInfo volume) {
|
||||
@ -974,72 +976,44 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
}
|
||||
@Override
|
||||
public SnapshotInfo takeSnapshot(VolumeInfo volume) throws ResourceAllocationException {
|
||||
Account caller = UserContext.current().getCaller();
|
||||
|
||||
supportedByHypervisor(volume);
|
||||
CreateSnapshotPayload snapInfo = (CreateSnapshotPayload)volume.getpayload();
|
||||
Long policyId = snapInfo.getSnapshotPolicyId();
|
||||
// Verify permissions
|
||||
_accountMgr.checkAccess(caller, null, true, volume);
|
||||
Type snapshotType = getSnapshotType(policyId);
|
||||
Account owner = _accountMgr.getAccount(volume.getAccountId());
|
||||
|
||||
try{
|
||||
_resourceLimitMgr.checkResourceLimit(owner, ResourceType.snapshot);
|
||||
if (backup) {
|
||||
_resourceLimitMgr.checkResourceLimit(owner, ResourceType.secondary_storage, new Long(volume.getSize()));
|
||||
} else {
|
||||
_resourceLimitMgr.checkResourceLimit(owner, ResourceType.primary_storage, new Long(volume.getSize()));
|
||||
}
|
||||
} catch (ResourceAllocationException e) {
|
||||
if (snapshotType != Type.MANUAL){
|
||||
String msg = "Snapshot resource limit exceeded for account id : " + owner.getId() + ". Failed to create recurring snapshots";
|
||||
s_logger.warn(msg);
|
||||
_alertMgr.sendAlert(AlertManager.ALERT_TYPE_UPDATE_RESOURCE_COUNT, 0L, 0L, msg,
|
||||
"Snapshot resource limit exceeded for account id : " + owner.getId() + ". Failed to create recurring snapshots; please use updateResourceLimit to increase the limit");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
// Determine the name for this snapshot
|
||||
// Snapshot Name: VMInstancename + volumeName + timeString
|
||||
String timeString = DateUtil.getDateDisplayString(DateUtil.GMT_TIMEZONE, new Date(), DateUtil.YYYYMMDD_FORMAT);
|
||||
|
||||
VMInstanceVO vmInstance = _vmDao.findById(volume.getInstanceId());
|
||||
String vmDisplayName = "detached";
|
||||
if (vmInstance != null) {
|
||||
vmDisplayName = vmInstance.getHostName();
|
||||
}
|
||||
String snapshotName = vmDisplayName + "_" + volume.getName() + "_" + timeString;
|
||||
|
||||
HypervisorType hypervisorType = volume.getHypervisorType();
|
||||
SnapshotVO snapshotVO = new SnapshotVO(volume.getDataCenterId(), volume.getAccountId(), volume.getDomainId(), volume.getId(), volume.getDiskOfferingId(), snapshotName,
|
||||
(short) snapshotType.ordinal(), snapshotType.name(), volume.getSize(), hypervisorType);
|
||||
|
||||
SnapshotVO snapshot = _snapshotDao.persist(snapshotVO);
|
||||
if (snapshot == null) {
|
||||
throw new CloudRuntimeException("Failed to create snapshot for volume: " + volume.getId());
|
||||
}
|
||||
if (backup) {
|
||||
_resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.secondary_storage,
|
||||
new Long(volume.getSize()));
|
||||
} else {
|
||||
_resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.primary_storage,
|
||||
new Long(volume.getSize()));
|
||||
}
|
||||
SnapshotInfo snap = this.snapshotFactory.getSnapshot(snapshot.getId(), volume.getDataStore());
|
||||
CreateSnapshotPayload payload = (CreateSnapshotPayload)volume.getpayload();
|
||||
Long snapshotId = payload.getSnapshotId();
|
||||
Account snapshotOwner = payload.getAccount();
|
||||
SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotId, volume.getDataStore());
|
||||
boolean processed = false;
|
||||
for (SnapshotStrategy strategy : snapshotStrategies) {
|
||||
if (strategy.canHandle(snap)) {
|
||||
processed = true;
|
||||
snap = strategy.takeSnapshot(snap);
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
for (SnapshotStrategy strategy : snapshotStrategies) {
|
||||
if (strategy.canHandle(snapshot)) {
|
||||
processed = true;
|
||||
snapshot = strategy.takeSnapshot(snapshot);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!processed) {
|
||||
throw new CloudRuntimeException("Can't find snapshot strategy to deal with snapshot:" + snapshotId);
|
||||
}
|
||||
postCreateSnapshot(volume.getId(), snapshotId, payload.getSnapshotPolicyId());
|
||||
|
||||
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_CREATE, snapshot.getAccountId(),
|
||||
snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null,
|
||||
volume.getSize(), snapshot.getClass().getName(), snapshot.getUuid());
|
||||
|
||||
|
||||
_resourceLimitMgr.incrementResourceCount(snapshotOwner.getId(), ResourceType.snapshot);
|
||||
|
||||
} catch(Exception e) {
|
||||
s_logger.debug("Failed to create snapshot", e);
|
||||
if (backup) {
|
||||
_resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), ResourceType.secondary_storage,
|
||||
new Long(volume.getSize()));
|
||||
} else {
|
||||
_resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), ResourceType.primary_storage,
|
||||
new Long(volume.getSize()));
|
||||
}
|
||||
throw new CloudRuntimeException("Failed to create snapshot", e);
|
||||
}
|
||||
if (!processed) {
|
||||
throw new CloudRuntimeException("Can't find snapshot strategy to deal with snapshot:" + snapshot.getId());
|
||||
}
|
||||
return snap;
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1128,4 +1102,61 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Snapshot allocSnapshot(Long volumeId, Long policyId) throws ResourceAllocationException {
|
||||
Account caller = UserContext.current().getCaller();
|
||||
VolumeInfo volume = this.volFactory.getVolume(volumeId);
|
||||
supportedByHypervisor(volume);
|
||||
|
||||
// Verify permissions
|
||||
_accountMgr.checkAccess(caller, null, true, volume);
|
||||
Type snapshotType = getSnapshotType(policyId);
|
||||
Account owner = _accountMgr.getAccount(volume.getAccountId());
|
||||
|
||||
try{
|
||||
_resourceLimitMgr.checkResourceLimit(owner, ResourceType.snapshot);
|
||||
if (backup) {
|
||||
_resourceLimitMgr.checkResourceLimit(owner, ResourceType.secondary_storage, new Long(volume.getSize()));
|
||||
} else {
|
||||
_resourceLimitMgr.checkResourceLimit(owner, ResourceType.primary_storage, new Long(volume.getSize()));
|
||||
}
|
||||
} catch (ResourceAllocationException e) {
|
||||
if (snapshotType != Type.MANUAL){
|
||||
String msg = "Snapshot resource limit exceeded for account id : " + owner.getId() + ". Failed to create recurring snapshots";
|
||||
s_logger.warn(msg);
|
||||
_alertMgr.sendAlert(AlertManager.ALERT_TYPE_UPDATE_RESOURCE_COUNT, 0L, 0L, msg,
|
||||
"Snapshot resource limit exceeded for account id : " + owner.getId() + ". Failed to create recurring snapshots; please use updateResourceLimit to increase the limit");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
// Determine the name for this snapshot
|
||||
// Snapshot Name: VMInstancename + volumeName + timeString
|
||||
String timeString = DateUtil.getDateDisplayString(DateUtil.GMT_TIMEZONE, new Date(), DateUtil.YYYYMMDD_FORMAT);
|
||||
|
||||
VMInstanceVO vmInstance = _vmDao.findById(volume.getInstanceId());
|
||||
String vmDisplayName = "detached";
|
||||
if (vmInstance != null) {
|
||||
vmDisplayName = vmInstance.getHostName();
|
||||
}
|
||||
String snapshotName = vmDisplayName + "_" + volume.getName() + "_" + timeString;
|
||||
|
||||
HypervisorType hypervisorType = volume.getHypervisorType();
|
||||
SnapshotVO snapshotVO = new SnapshotVO(volume.getDataCenterId(), volume.getAccountId(), volume.getDomainId(), volume.getId(), volume.getDiskOfferingId(), snapshotName,
|
||||
(short) snapshotType.ordinal(), snapshotType.name(), volume.getSize(), hypervisorType);
|
||||
|
||||
SnapshotVO snapshot = _snapshotDao.persist(snapshotVO);
|
||||
if (snapshot == null) {
|
||||
throw new CloudRuntimeException("Failed to create snapshot for volume: " + volume.getId());
|
||||
}
|
||||
if (backup) {
|
||||
_resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.secondary_storage,
|
||||
new Long(volume.getSize()));
|
||||
} else {
|
||||
_resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.primary_storage,
|
||||
new Long(volume.getSize()));
|
||||
}
|
||||
return snapshot;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1355,7 +1355,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
||||
}
|
||||
AsyncCallFuture<TemplateApiResult> future = null;
|
||||
if (snapshotId != null) {
|
||||
SnapshotInfo snapInfo = this._snapshotFactory.getSnapshot(snapshotId);
|
||||
SnapshotInfo snapInfo = this._snapshotFactory.getSnapshot(snapshotId, DataStoreRole.Image);
|
||||
future = this._tmpltSvr.createTemplateFromSnapshotAsync(snapInfo, tmplInfo, store.get(0));
|
||||
} else if (volumeId != null) {
|
||||
volume = _volumeDao.findById(volumeId);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user