refactor snapshot

This commit is contained in:
Edison Su 2013-04-29 18:50:46 -07:00
parent 37cbe8890f
commit 2f689171e0
30 changed files with 894 additions and 505 deletions

View File

@ -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
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -27,4 +27,5 @@ public interface VolumeInfo extends DataObject, Volume {
public Object getpayload();
public HypervisorType getHypervisorType();
public Long getLastPoolId();
public String getAttachedVmName();
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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());
}
}
}

View File

@ -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());
}

View File

@ -399,7 +399,7 @@ public class SnapshotServiceImpl implements SnapshotService {
@Override
public boolean deleteSnapshot(SnapshotInfo snapInfo) {
return true;
}

View File

@ -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());
}

View File

@ -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();

View File

@ -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;
}
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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() {

View File

@ -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());

View File

@ -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 ) {

View File

@ -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");

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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);