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,
|
CreatedOnPrimary,
|
||||||
BackingUp,
|
BackingUp,
|
||||||
BackedUp,
|
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;
|
Error;
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
@ -76,6 +79,8 @@ public interface Snapshot extends ControlledEntity, Identity, InternalIdentity,
|
|||||||
OperationNotPerformed,
|
OperationNotPerformed,
|
||||||
BackupToSecondary,
|
BackupToSecondary,
|
||||||
BackedupToSecondary,
|
BackedupToSecondary,
|
||||||
|
DestroyRequested,
|
||||||
|
CopyingRequested,
|
||||||
OperationSucceeded,
|
OperationSucceeded,
|
||||||
OperationFailed
|
OperationFailed
|
||||||
}
|
}
|
||||||
|
|||||||
@ -80,6 +80,9 @@ public interface VolumeApiService {
|
|||||||
|
|
||||||
Volume detachVolumeFromVM(DetachVolumeCmd cmmd);
|
Volume detachVolumeFromVM(DetachVolumeCmd cmmd);
|
||||||
|
|
||||||
Snapshot takeSnapshot(Long volumeId, Long policyId)
|
Snapshot takeSnapshot(Long volumeId, Long policyId, Long snapshotId, Account account)
|
||||||
throws ResourceAllocationException;
|
throws ResourceAllocationException;
|
||||||
|
|
||||||
|
Snapshot allocSnapshot(Long volumeId, Long policyId)
|
||||||
|
throws ResourceAllocationException;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -152,7 +152,7 @@ public class CreateSnapshotCmd extends BaseAsyncCreateCmd {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void create() throws ResourceAllocationException {
|
public void create() throws ResourceAllocationException {
|
||||||
Snapshot snapshot = _snapshotService.allocSnapshot(getVolumeId(), getPolicyId());
|
Snapshot snapshot = this._volumeService.allocSnapshot(getVolumeId(), getPolicyId());
|
||||||
if (snapshot != null) {
|
if (snapshot != null) {
|
||||||
this.setEntityId(snapshot.getId());
|
this.setEntityId(snapshot.getId());
|
||||||
this.setEntityUuid(snapshot.getUuid());
|
this.setEntityUuid(snapshot.getUuid());
|
||||||
@ -164,14 +164,20 @@ public class CreateSnapshotCmd extends BaseAsyncCreateCmd {
|
|||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
UserContext.current().setEventDetails("Volume Id: "+getVolumeId());
|
UserContext.current().setEventDetails("Volume Id: "+getVolumeId());
|
||||||
Snapshot snapshot = _snapshotService.createSnapshot(getVolumeId(), getPolicyId(), getEntityId(), _accountService.getAccount(getEntityOwnerId()));
|
Snapshot snapshot;
|
||||||
if (snapshot != null) {
|
try {
|
||||||
SnapshotResponse response = _responseGenerator.createSnapshotResponse(snapshot);
|
snapshot = _volumeService.takeSnapshot(this.getVolumeId(), this.getPolicyId(), this.getEntityId(), _accountService.getAccount(getEntityOwnerId()));
|
||||||
response.setResponseName(getCommandName());
|
if (snapshot != null) {
|
||||||
this.setResponseObject(response);
|
SnapshotResponse response = _responseGenerator.createSnapshotResponse(snapshot);
|
||||||
} else {
|
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);
|
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;
|
import com.cloud.storage.Snapshot;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public interface SnapshotStrategy {
|
public interface SnapshotStrategy {
|
||||||
public SnapshotInfo takeSnapshot(SnapshotInfo snapshot);
|
public SnapshotInfo takeSnapshot(SnapshotInfo snapshot);
|
||||||
public SnapshotInfo backupSnapshot(SnapshotInfo snapshot);
|
public SnapshotInfo backupSnapshot(SnapshotInfo snapshot);
|
||||||
public boolean deleteSnapshot(Long snapshotId);
|
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 interface StorageCacheManager {
|
||||||
public DataStore getCacheStorage(Scope scope);
|
public DataStore getCacheStorage(Scope scope);
|
||||||
public DataObject createCacheObject(DataObject data, 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 Object getpayload();
|
||||||
public HypervisorType getHypervisorType();
|
public HypervisorType getHypervisorType();
|
||||||
public Long getLastPoolId();
|
public Long getLastPoolId();
|
||||||
|
public String getAttachedVmName();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,12 +23,12 @@ import com.cloud.agent.api.Command;
|
|||||||
public class CopyCommand extends Command implements StorageSubSystemCommand {
|
public class CopyCommand extends Command implements StorageSubSystemCommand {
|
||||||
private DataTO srcTO;
|
private DataTO srcTO;
|
||||||
private DataTO destTO;
|
private DataTO destTO;
|
||||||
|
private DataTO cacheTO;
|
||||||
|
|
||||||
|
public CopyCommand(DataTO srcData, DataTO destData, int timeout) {
|
||||||
public CopyCommand(DataTO srcUri, DataTO destUri, int timeout) {
|
|
||||||
super();
|
super();
|
||||||
this.srcTO = srcUri;
|
this.srcTO = srcData;
|
||||||
this.destTO = destUri;
|
this.destTO = destData;
|
||||||
this.setWait(timeout);
|
this.setWait(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,4 +45,12 @@ public class CopyCommand extends Command implements StorageSubSystemCommand {
|
|||||||
return true;
|
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.DataObjectType;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
|
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;
|
import com.cloud.agent.api.to.DataStoreTO;
|
||||||
|
|
||||||
public class SnapshotObjectTO implements DataTO {
|
public class SnapshotObjectTO implements DataTO {
|
||||||
private String path;
|
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
|
@Override
|
||||||
public DataObjectType getObjectType() {
|
public DataObjectType getObjectType() {
|
||||||
// TODO Auto-generated method stub
|
return DataObjectType.SNAPSHOT;
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataStoreTO getDataStore() {
|
public DataStoreTO getDataStore() {
|
||||||
// TODO Auto-generated method stub
|
return this.dataStore;
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -27,4 +49,44 @@ public class SnapshotObjectTO implements DataTO {
|
|||||||
public void setPath(String path) {
|
public void setPath(String path) {
|
||||||
this.path = 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 String name;
|
||||||
private long size;
|
private long size;
|
||||||
private String path;
|
private String path;
|
||||||
|
private Long volumeId;
|
||||||
|
|
||||||
public VolumeObjectTO() {
|
public VolumeObjectTO() {
|
||||||
|
|
||||||
@ -49,6 +50,7 @@ public class VolumeObjectTO implements DataTO {
|
|||||||
}
|
}
|
||||||
//this.name = volume.getName();
|
//this.name = volume.getName();
|
||||||
this.size = volume.getSize();
|
this.size = volume.getSize();
|
||||||
|
this.setVolumeId(volume.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUuid() {
|
public String getUuid() {
|
||||||
@ -103,4 +105,12 @@ public class VolumeObjectTO implements DataTO {
|
|||||||
this.path = path;
|
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;
|
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,
|
protected Void createCacheObjectCallBack(AsyncCallbackDispatcher<StorageCacheManagerImpl, CopyCommandResult> callback,
|
||||||
CreateCacheObjectContext<CopyCommandResult> context) {
|
CreateCacheObjectContext<CopyCommandResult> context) {
|
||||||
AsyncCallFuture<CopyCommandResult> future = context.future;
|
AsyncCallFuture<CopyCommandResult> future = context.future;
|
||||||
future.complete(callback.getResult());
|
future.complete(callback.getResult());
|
||||||
return null;
|
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.CopyVolumeAnswer;
|
||||||
import com.cloud.agent.api.storage.CopyVolumeCommand;
|
import com.cloud.agent.api.storage.CopyVolumeCommand;
|
||||||
import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
|
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.S3TO;
|
||||||
import com.cloud.agent.api.to.SwiftTO;
|
import com.cloud.agent.api.to.SwiftTO;
|
||||||
import com.cloud.configuration.Config;
|
import com.cloud.configuration.Config;
|
||||||
@ -127,10 +129,6 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
|||||||
@Inject
|
@Inject
|
||||||
VolumeManager volumeMgr;
|
VolumeManager volumeMgr;
|
||||||
@Inject
|
@Inject
|
||||||
private SwiftManager _swiftMgr;
|
|
||||||
@Inject
|
|
||||||
private S3Manager _s3Mgr;
|
|
||||||
@Inject
|
|
||||||
StorageCacheManager cacheMgr;
|
StorageCacheManager cacheMgr;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -180,111 +178,54 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Answer copyFromSnapshot(DataObject snapObj, DataObject volObj) {
|
protected DataObject cacheSnapshotChain(SnapshotInfo snapshot) {
|
||||||
SnapshotVO snapshot = this.snapshotDao.findById(snapObj.getId());
|
DataObject leafData = null;
|
||||||
StoragePool pool = (StoragePool) volObj.getDataStore();
|
while(snapshot != null) {
|
||||||
String vdiUUID = null;
|
DataObject cacheData = cacheMgr.createCacheObject(snapshot, snapshot.getDataStore().getScope());
|
||||||
Long snapshotId = snapshot.getId();
|
if (leafData == null) {
|
||||||
Long volumeId = snapshot.getVolumeId();
|
leafData = cacheData;
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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 "
|
String basicErrMsg = "Failed to create volume from "
|
||||||
+ snapshot.getName() + " on pool " + pool;
|
+ snapshot.getName() + " on pool " + pool;
|
||||||
|
DataStore store = snapObj.getDataStore();
|
||||||
|
DataStoreTO storTO = store.getTO();
|
||||||
|
DataObject srcData = snapObj;
|
||||||
try {
|
try {
|
||||||
if (snapshot.getSwiftId() != null && snapshot.getSwiftId() != 0) {
|
if (!(storTO instanceof NfsTO)) {
|
||||||
snapshotMgr.downloadSnapshotsFromSwift(snapshot);
|
srcData = cacheSnapshotChain(snapshot);
|
||||||
} else if (snapshot.getS3Id() != null && snapshot.getS3Id() != 0) {
|
|
||||||
snapshotMgr.downloadSnapshotsFromS3(snapshot);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String value = configDao
|
String value = configDao
|
||||||
.getValue(Config.CreateVolumeFromSnapshotWait.toString());
|
.getValue(Config.CreateVolumeFromSnapshotWait.toString());
|
||||||
int _createVolumeFromSnapshotWait = NumbersUtil.parseInt(value,
|
int _createVolumeFromSnapshotWait = NumbersUtil.parseInt(value,
|
||||||
Integer.parseInt(Config.CreateVolumeFromSnapshotWait
|
Integer.parseInt(Config.CreateVolumeFromSnapshotWait
|
||||||
.getDefaultValue()));
|
.getDefaultValue()));
|
||||||
CreateVolumeFromSnapshotCommand createVolumeFromSnapshotCommand = new CreateVolumeFromSnapshotCommand(
|
|
||||||
pool, secondaryStoragePoolUrl, dcId, accountId, volumeId,
|
CopyCommand cmd = new CopyCommand(srcData.getTO(), volObj.getTO(), _createVolumeFromSnapshotWait);
|
||||||
backedUpSnapshotUuid, snapshot.getName(),
|
|
||||||
_createVolumeFromSnapshotWait);
|
|
||||||
CreateVolumeFromSnapshotAnswer answer;
|
Answer answer = this.storageMgr
|
||||||
if (!snapshotDao.lockInLockTable(snapshotId.toString(), 10)) {
|
.sendToPool(pool, cmd);
|
||||||
throw new CloudRuntimeException("failed to create volume from "
|
return answer;
|
||||||
+ 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);
|
|
||||||
}
|
|
||||||
} catch (StorageUnavailableException e) {
|
} catch (StorageUnavailableException e) {
|
||||||
s_logger.error(basicErrMsg, e);
|
s_logger.error(basicErrMsg, e);
|
||||||
throw new CloudRuntimeException(basicErrMsg);
|
throw new CloudRuntimeException(basicErrMsg);
|
||||||
} finally {
|
} finally {
|
||||||
if (snapshot.getSwiftId() != null) {
|
if (!(storTO instanceof NfsTO)) {
|
||||||
snapshotMgr.deleteSnapshotsDirForVolume(
|
deleteSnapshotCacheChain((SnapshotInfo)srcData);
|
||||||
secondaryStoragePoolUrl, dcId, accountId, volumeId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -328,7 +269,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
|||||||
answer = copyTemplate(srcData, destData);
|
answer = copyTemplate(srcData, destData);
|
||||||
} else if (srcData.getType() == DataObjectType.SNAPSHOT
|
} else if (srcData.getType() == DataObjectType.SNAPSHOT
|
||||||
&& destData.getType() == DataObjectType.VOLUME) {
|
&& destData.getType() == DataObjectType.VOLUME) {
|
||||||
answer = copyFromSnapshot(srcData, destData);
|
answer = copyVolumeFromSnapshot(srcData, destData);
|
||||||
} else if (srcData.getType() == DataObjectType.SNAPSHOT
|
} else if (srcData.getType() == DataObjectType.SNAPSHOT
|
||||||
&& destData.getType() == DataObjectType.TEMPLATE) {
|
&& destData.getType() == DataObjectType.TEMPLATE) {
|
||||||
answer = createTemplateFromSnapshot(srcData, destData);
|
answer = createTemplateFromSnapshot(srcData, destData);
|
||||||
@ -359,49 +300,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
|||||||
@DB
|
@DB
|
||||||
protected Answer createTemplateFromSnapshot(DataObject srcData,
|
protected Answer createTemplateFromSnapshot(DataObject srcData,
|
||||||
DataObject destData) {
|
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
|
String value = configDao
|
||||||
.getValue(Config.CreatePrivateTemplateFromSnapshotWait
|
.getValue(Config.CreatePrivateTemplateFromSnapshotWait
|
||||||
.toString());
|
.toString());
|
||||||
@ -410,172 +309,71 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
|
|||||||
.parseInt(Config.CreatePrivateTemplateFromSnapshotWait
|
.parseInt(Config.CreatePrivateTemplateFromSnapshotWait
|
||||||
.getDefaultValue()));
|
.getDefaultValue()));
|
||||||
|
|
||||||
CreatePrivateTemplateFromSnapshotCommand cmd = new CreatePrivateTemplateFromSnapshotCommand(
|
if (srcData.getDataStore().getRole() != DataStoreRole.ImageCache && destData.getDataStore().getRole() != DataStoreRole.ImageCache) {
|
||||||
pool, secondaryStorageURL, dcId, accountId,
|
SnapshotInfo snapshot = (SnapshotInfo)srcData;
|
||||||
snapshot.getVolumeId(), backupSnapshotUUID, snapshot.getName(),
|
srcData = cacheSnapshotChain(snapshot);
|
||||||
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 (answer == null || !answer.getResult()) {
|
CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _createprivatetemplatefromsnapshotwait);
|
||||||
return answer;
|
EndPoint ep = selector.select(srcData, destData);
|
||||||
}
|
Answer answer = ep.sendMessage(cmd);
|
||||||
|
|
||||||
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();
|
|
||||||
return answer;
|
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);
|
private Answer createTemplateFromVolume(DataObject srcData,
|
||||||
Long zoneId = volume.getDataCenterId();
|
DataObject destData) {
|
||||||
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);
|
|
||||||
String value = configDao
|
String value = configDao
|
||||||
.getValue(Config.CreatePrivateTemplateFromVolumeWait.toString());
|
.getValue(Config.CreatePrivateTemplateFromVolumeWait.toString());
|
||||||
int _createprivatetemplatefromvolumewait = NumbersUtil.parseInt(value,
|
int _createprivatetemplatefromvolumewait = NumbersUtil.parseInt(value,
|
||||||
Integer.parseInt(Config.CreatePrivateTemplateFromVolumeWait
|
Integer.parseInt(Config.CreatePrivateTemplateFromVolumeWait
|
||||||
.getDefaultValue()));
|
.getDefaultValue()));
|
||||||
|
|
||||||
CreatePrivateTemplateFromVolumeCommand cmd = new CreatePrivateTemplateFromVolumeCommand(
|
if (srcData.getDataStore().getRole() != DataStoreRole.ImageCache && destData.getDataStore().getRole() != DataStoreRole.ImageCache) {
|
||||||
pool, secondaryStorageURL, destObj.getId(), accountId,
|
//need to copy it to image cache store
|
||||||
template.getName(), template.getUniqueName(), volume.getPath(),
|
DataObject cacheData = cacheMgr.createCacheObject(srcData, destData.getDataStore().getScope());
|
||||||
vmName, _createprivatetemplatefromvolumewait);
|
CopyCommand cmd = new CopyCommand(cacheData.getTO(), destData.getTO(), _createprivatetemplatefromvolumewait);
|
||||||
|
EndPoint ep = selector.select(cacheData, destData);
|
||||||
return sendCommand(cmd, pool, template.getId(), zoneId, secStore);
|
Answer answer = ep.sendMessage(cmd);
|
||||||
}
|
return answer;
|
||||||
|
} else {
|
||||||
private DataStore getSecHost(long volumeId, long dcId) {
|
//handle copy it to/from cache store
|
||||||
Long id = snapshotDao.getSecHostId(volumeId);
|
CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _createprivatetemplatefromvolumewait);
|
||||||
if ( id != null) {
|
EndPoint ep = selector.select(srcData, destData);
|
||||||
return this.dataStoreMgr.getDataStore(id, DataStoreRole.Image);
|
Answer answer = ep.sendMessage(cmd);
|
||||||
|
return answer;
|
||||||
}
|
}
|
||||||
return this.dataStoreMgr.getImageStore(dcId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Answer copySnapshot(DataObject srcObject, DataObject destObject) {
|
protected Answer copySnapshot(DataObject srcData, DataObject destData) {
|
||||||
SnapshotInfo srcSnapshot = (SnapshotInfo)srcObject;
|
String value = configDao.getValue(Config.BackupSnapshotWait.toString());
|
||||||
VolumeInfo baseVolume = srcSnapshot.getBaseVolume();
|
int _backupsnapshotwait = NumbersUtil.parseInt(value, Integer.parseInt(Config.BackupSnapshotWait.getDefaultValue()));
|
||||||
Long dcId = baseVolume.getDataCenterId();
|
|
||||||
Long accountId = baseVolume.getAccountId();
|
|
||||||
|
|
||||||
DataStore secStore = getSecHost(baseVolume.getId(), baseVolume.getDataCenterId());
|
DataObject cacheData = null;
|
||||||
Long secHostId = secStore.getId();
|
try {
|
||||||
String secondaryStoragePoolUrl = secStore.getUri();
|
if (destData.getDataStore().getRole() != DataStoreRole.ImageCache) {
|
||||||
String snapshotUuid = srcSnapshot.getPath();
|
cacheData = cacheMgr.getCacheObject(srcData, destData.getDataStore().getScope());
|
||||||
// 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;
|
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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.VolumeDataFactory;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
|
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat;
|
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.command.CreateObjectAnswer;
|
||||||
import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
|
import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
|
||||||
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
|
||||||
@ -234,6 +235,13 @@ public class SnapshotObject implements SnapshotInfo {
|
|||||||
SnapshotObjectTO snapshotTO = (SnapshotObjectTO)((CreateObjectAnswer) answer).getData();
|
SnapshotObjectTO snapshotTO = (SnapshotObjectTO)((CreateObjectAnswer) answer).getData();
|
||||||
snapshotStore.setInstallPath(snapshotTO.getPath());
|
snapshotStore.setInstallPath(snapshotTO.getPath());
|
||||||
this.snapshotStore.update(snapshotStore.getId(), snapshotStore);
|
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 {
|
} else {
|
||||||
throw new CloudRuntimeException("Unknown answer: " + answer.getClass());
|
throw new CloudRuntimeException("Unknown answer: " + answer.getClass());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -399,7 +399,7 @@ public class SnapshotServiceImpl implements SnapshotService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean deleteSnapshot(SnapshotInfo snapInfo) {
|
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.CreatedOnPrimary, Event.BackupToSecondary, Snapshot.State.BackingUp);
|
||||||
stateMachine.addTransition(Snapshot.State.BackingUp, Event.OperationSucceeded, Snapshot.State.BackedUp);
|
stateMachine.addTransition(Snapshot.State.BackingUp, Event.OperationSucceeded, Snapshot.State.BackedUp);
|
||||||
stateMachine.addTransition(Snapshot.State.BackingUp, Event.OperationFailed, Snapshot.State.CreatedOnPrimary);
|
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());
|
stateMachine.registerListener(new SnapshotStateListener());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,9 +9,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy;
|
|||||||
public abstract class SnapshotStrategyBase implements SnapshotStrategy {
|
public abstract class SnapshotStrategyBase implements SnapshotStrategy {
|
||||||
@Inject
|
@Inject
|
||||||
SnapshotService snapshotSvr;
|
SnapshotService snapshotSvr;
|
||||||
//the default strategy is:
|
|
||||||
//create snapshot,
|
|
||||||
//backup, then delete snapshot on primary storage
|
|
||||||
@Override
|
@Override
|
||||||
public SnapshotInfo takeSnapshot(SnapshotInfo snapshot) {
|
public SnapshotInfo takeSnapshot(SnapshotInfo snapshot) {
|
||||||
return snapshotSvr.takeSnapshot(snapshot).getSnashot();
|
return snapshotSvr.takeSnapshot(snapshot).getSnashot();
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import com.cloud.storage.DataStoreRole;
|
|||||||
import com.cloud.storage.Snapshot;
|
import com.cloud.storage.Snapshot;
|
||||||
import com.cloud.storage.SnapshotVO;
|
import com.cloud.storage.SnapshotVO;
|
||||||
import com.cloud.storage.VolumeVO;
|
import com.cloud.storage.VolumeVO;
|
||||||
|
import com.cloud.storage.dao.SnapshotDao;
|
||||||
import com.cloud.storage.snapshot.SnapshotManager;
|
import com.cloud.storage.snapshot.SnapshotManager;
|
||||||
import com.cloud.utils.NumbersUtil;
|
import com.cloud.utils.NumbersUtil;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
@ -48,6 +49,8 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase {
|
|||||||
@Inject
|
@Inject
|
||||||
ConfigurationDao configDao;
|
ConfigurationDao configDao;
|
||||||
@Inject
|
@Inject
|
||||||
|
SnapshotDao snapshotDao;
|
||||||
|
@Inject
|
||||||
SnapshotDataFactory snapshotDataFactory;
|
SnapshotDataFactory snapshotDataFactory;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -115,86 +118,85 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase {
|
|||||||
return this.snapshotSvr.backupSnapshot(snapshot);
|
return this.snapshotSvr.backupSnapshot(snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
protected void deleteSnapshotChain(SnapshotInfo snapshot) {
|
||||||
public boolean deleteSnapshot(SnapshotInfo snapshot) {
|
while(snapshot != null) {
|
||||||
Long snapshotId = snapshot.getId();
|
SnapshotInfo child = snapshot.getChild();
|
||||||
SnapshotObject snapObj = (SnapshotObject)snapshot;
|
SnapshotInfo parent = snapshot.getParent();
|
||||||
|
if (child == null) {
|
||||||
|
if (!parent.getPath().equalsIgnoreCase(snapshot.getPath())) {
|
||||||
|
this.snapshotSvr.deleteSnapshot(snapshot);
|
||||||
|
snapshot = parent;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!Snapshot.State.BackedUp.equals(snapshot.getState()) || !Snapshot) {
|
@Override
|
||||||
|
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");
|
throw new InvalidParameterValueException("Can't delete snapshotshot " + snapshotId + " due to it is not in BackedUp Status");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_logger.isDebugEnabled()) {
|
if (s_logger.isDebugEnabled()) {
|
||||||
s_logger.debug("Calling deleteSnapshot for snapshotId: " + snapshotId);
|
s_logger.debug("Calling deleteSnapshot for snapshotId: " + snapshotId);
|
||||||
}
|
}
|
||||||
SnapshotVO lastSnapshot = null;
|
|
||||||
if (snapshot.getPrevSnapshotId() != null) {
|
|
||||||
List<SnapshotVO> snaps = _snapshotDao.listByBackupUuid(snapshot.getVolumeId(), snapshot.getBackupSnapshotId());
|
//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.
|
||||||
if (snaps != null && snaps.size() > 1) {
|
SnapshotInfo snapshotOnPrimary = this.snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Primary);
|
||||||
snapshot.setBackupSnapshotId(null);
|
SnapshotObject obj = (SnapshotObject)snapshotOnPrimary;
|
||||||
SnapshotVO snapshotVO = this._snapshotDao.findById(snapshotId);
|
try {
|
||||||
_snapshotDao.update(snapshot.getId(), snapshotVO);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canHandle(SnapshotInfo snapshot) {
|
|
||||||
if (snapshot.getHypervisorType() == HypervisorType.XenServer) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SnapshotInfo takeSnapshot(SnapshotInfo snapshot) {
|
public SnapshotInfo takeSnapshot(SnapshotInfo snapshot) {
|
||||||
snapshot = snapshotSvr.takeSnapshot(snapshot).getSnashot();
|
snapshot = snapshotSvr.takeSnapshot(snapshot).getSnashot();
|
||||||
//TODO: add async
|
//TODO: add async
|
||||||
return this.backupSnapshot(snapshot);
|
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() {
|
public ObjectInDataStoreManagerImpl() {
|
||||||
stateMachines = new StateMachine2<State, Event, DataObjectInStore>();
|
stateMachines = new StateMachine2<State, Event, DataObjectInStore>();
|
||||||
stateMachines.addTransition(State.Allocated, Event.CreateRequested,
|
stateMachines.addTransition(State.Allocated, Event.CreateOnlyRequested,
|
||||||
State.Creating);
|
State.Creating);
|
||||||
stateMachines.addTransition(State.Creating, Event.OperationSuccessed,
|
|
||||||
State.Created);
|
|
||||||
stateMachines.addTransition(State.Creating, Event.OperationFailed,
|
stateMachines.addTransition(State.Creating, Event.OperationFailed,
|
||||||
State.Failed);
|
State.Allocated);
|
||||||
stateMachines.addTransition(State.Failed, Event.CreateRequested,
|
stateMachines.addTransition(State.Creating, Event.OperationSuccessed,
|
||||||
State.Creating);
|
State.Ready);
|
||||||
stateMachines.addTransition(State.Ready, Event.DestroyRequested,
|
stateMachines.addTransition(State.Ready, Event.CopyingRequested,
|
||||||
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.Copying);
|
State.Copying);
|
||||||
stateMachines.addTransition(State.Copying, Event.OperationFailed,
|
|
||||||
State.Created);
|
|
||||||
stateMachines.addTransition(State.Copying, Event.OperationSuccessed,
|
stateMachines.addTransition(State.Copying, Event.OperationSuccessed,
|
||||||
State.Ready);
|
State.Ready);
|
||||||
stateMachines.addTransition(State.Allocated, Event.CreateOnlyRequested,
|
stateMachines.addTransition(State.Copying, Event.OperationFailed,
|
||||||
State.Creating2);
|
|
||||||
stateMachines.addTransition(State.Creating2, Event.OperationFailed,
|
|
||||||
State.Allocated);
|
|
||||||
stateMachines.addTransition(State.Creating2, Event.OperationSuccessed,
|
|
||||||
State.Ready);
|
State.Ready);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -149,4 +149,10 @@ public class SnapshotDataStoreDaoImpl extends GenericDaoBase<SnapshotDataStoreVO
|
|||||||
sc.setParameters("store_role", role);
|
sc.setParameters("store_role", role);
|
||||||
return findOneBy(sc);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPath() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
// TODO Auto-generated method stub
|
// 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.NoTransitionException;
|
||||||
import com.cloud.utils.fsm.StateMachine2;
|
import com.cloud.utils.fsm.StateMachine2;
|
||||||
import com.cloud.utils.storage.encoding.EncodingType;
|
import com.cloud.utils.storage.encoding.EncodingType;
|
||||||
|
import com.cloud.vm.VMInstanceVO;
|
||||||
|
import com.cloud.vm.dao.VMInstanceDao;
|
||||||
|
|
||||||
public class VolumeObject implements VolumeInfo {
|
public class VolumeObject implements VolumeInfo {
|
||||||
private static final Logger s_logger = Logger.getLogger(VolumeObject.class);
|
private static final Logger s_logger = Logger.getLogger(VolumeObject.class);
|
||||||
@ -58,6 +60,8 @@ public class VolumeObject implements VolumeInfo {
|
|||||||
VolumeDataStoreDao volumeStoreDao;
|
VolumeDataStoreDao volumeStoreDao;
|
||||||
@Inject
|
@Inject
|
||||||
ObjectInDataStoreManager ojbectInStoreMgr;
|
ObjectInDataStoreManager ojbectInStoreMgr;
|
||||||
|
@Inject
|
||||||
|
VMInstanceDao vmInstanceDao;
|
||||||
private Object payload;
|
private Object payload;
|
||||||
|
|
||||||
public VolumeObject() {
|
public VolumeObject() {
|
||||||
@ -75,6 +79,19 @@ public class VolumeObject implements VolumeInfo {
|
|||||||
return vo;
|
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
|
@Override
|
||||||
public String getUuid() {
|
public String getUuid() {
|
||||||
return volumeVO.getUuid();
|
return volumeVO.getUuid();
|
||||||
|
|||||||
@ -408,15 +408,17 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
private final AsyncCallFuture<VolumeApiResult> future;
|
private final AsyncCallFuture<VolumeApiResult> future;
|
||||||
private final DataStore primaryStore;
|
private final DataStore primaryStore;
|
||||||
private final DataObject templateOnStore;
|
private final DataObject templateOnStore;
|
||||||
|
private final SnapshotInfo snapshot;
|
||||||
public CreateVolumeFromBaseImageContext(AsyncCompletionCallback<T> callback, VolumeObject vo,
|
public CreateVolumeFromBaseImageContext(AsyncCompletionCallback<T> callback, VolumeObject vo,
|
||||||
DataStore primaryStore,
|
DataStore primaryStore,
|
||||||
DataObject templateOnStore,
|
DataObject templateOnStore,
|
||||||
AsyncCallFuture<VolumeApiResult> future) {
|
AsyncCallFuture<VolumeApiResult> future, SnapshotInfo snapshot) {
|
||||||
super(callback);
|
super(callback);
|
||||||
this.vo = vo;
|
this.vo = vo;
|
||||||
this.future = future;
|
this.future = future;
|
||||||
this.primaryStore = primaryStore;
|
this.primaryStore = primaryStore;
|
||||||
this.templateOnStore = templateOnStore;
|
this.templateOnStore = templateOnStore;
|
||||||
|
this.snapshot = snapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -428,7 +430,7 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
@DB
|
@DB
|
||||||
protected void createVolumeFromBaseImageAsync(VolumeInfo volume, DataObject templateOnPrimaryStore, PrimaryDataStore pd, AsyncCallFuture<VolumeApiResult> future) {
|
protected void createVolumeFromBaseImageAsync(VolumeInfo volume, DataObject templateOnPrimaryStore, PrimaryDataStore pd, AsyncCallFuture<VolumeApiResult> future) {
|
||||||
VolumeObject vo = (VolumeObject)volume;
|
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);
|
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
|
||||||
caller.setCallback(caller.getTarget().createVolumeFromBaseImageCallBack(null, null))
|
caller.setCallback(caller.getTarget().createVolumeFromBaseImageCallBack(null, null))
|
||||||
.setContext(context);
|
.setContext(context);
|
||||||
@ -497,8 +499,9 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
try {
|
try {
|
||||||
DataObject volumeOnStore = store.create(volume);
|
DataObject volumeOnStore = store.create(volume);
|
||||||
volume.processEvent(Event.CreateOnlyRequested);
|
volume.processEvent(Event.CreateOnlyRequested);
|
||||||
|
snapshot.processEvent(Event.CopyingRequested);
|
||||||
CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null,
|
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);
|
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
|
||||||
caller.setCallback(caller.getTarget().createVolumeFromSnapshotCallback(null, null))
|
caller.setCallback(caller.getTarget().createVolumeFromSnapshotCallback(null, null))
|
||||||
.setContext(context);
|
.setContext(context);
|
||||||
@ -517,6 +520,7 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
CreateVolumeFromBaseImageContext<VolumeApiResult> context) {
|
CreateVolumeFromBaseImageContext<VolumeApiResult> context) {
|
||||||
CopyCommandResult result = callback.getResult();
|
CopyCommandResult result = callback.getResult();
|
||||||
VolumeInfo volume = context.vo;
|
VolumeInfo volume = context.vo;
|
||||||
|
SnapshotInfo snapshot = context.snapshot;
|
||||||
VolumeApiResult apiResult = new VolumeApiResult(volume);
|
VolumeApiResult apiResult = new VolumeApiResult(volume);
|
||||||
Event event = null;
|
Event event = null;
|
||||||
if (result.isFailed()) {
|
if (result.isFailed()) {
|
||||||
@ -528,6 +532,7 @@ public class VolumeServiceImpl implements VolumeService {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
volume.processEvent(event);
|
volume.processEvent(event);
|
||||||
|
snapshot.processEvent(event);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
s_logger.debug("create volume from snapshot failed", e);
|
s_logger.debug("create volume from snapshot failed", e);
|
||||||
apiResult.setResult(e.toString());
|
apiResult.setResult(e.toString());
|
||||||
|
|||||||
@ -3620,7 +3620,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
|
|||||||
return false;
|
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 lfilename;
|
||||||
String ldir;
|
String ldir;
|
||||||
if ( isISCSI ) {
|
if ( isISCSI ) {
|
||||||
|
|||||||
@ -18,12 +18,20 @@
|
|||||||
*/
|
*/
|
||||||
package com.cloud.hypervisor.xen.resource;
|
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.BufferedOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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.datastore.protocol.DataStoreProtocol;
|
||||||
import org.apache.cloudstack.storage.to.ImageStoreTO;
|
import org.apache.cloudstack.storage.to.ImageStoreTO;
|
||||||
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
|
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.TemplateObjectTO;
|
||||||
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
||||||
import org.apache.http.HttpEntity;
|
import org.apache.http.HttpEntity;
|
||||||
@ -54,18 +63,25 @@ import org.apache.log4j.Logger;
|
|||||||
import org.apache.xmlrpc.XmlRpcException;
|
import org.apache.xmlrpc.XmlRpcException;
|
||||||
|
|
||||||
import com.cloud.agent.api.Answer;
|
import com.cloud.agent.api.Answer;
|
||||||
|
import com.cloud.agent.api.BackupSnapshotAnswer;
|
||||||
import com.cloud.agent.api.Command;
|
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.CopyVolumeAnswer;
|
||||||
import com.cloud.agent.api.storage.CreateAnswer;
|
import com.cloud.agent.api.storage.CreateAnswer;
|
||||||
import com.cloud.agent.api.storage.DeleteVolumeCommand;
|
import com.cloud.agent.api.storage.DeleteVolumeCommand;
|
||||||
import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
|
import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
|
||||||
import com.cloud.agent.api.to.DataStoreTO;
|
import com.cloud.agent.api.to.DataStoreTO;
|
||||||
import com.cloud.agent.api.to.NfsTO;
|
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.StorageFilerTO;
|
||||||
|
import com.cloud.agent.api.to.SwiftTO;
|
||||||
import com.cloud.agent.api.to.VolumeTO;
|
import com.cloud.agent.api.to.VolumeTO;
|
||||||
import com.cloud.exception.InternalErrorException;
|
import com.cloud.exception.InternalErrorException;
|
||||||
import com.cloud.hypervisor.xen.resource.CitrixResourceBase.SRType;
|
import com.cloud.hypervisor.xen.resource.CitrixResourceBase.SRType;
|
||||||
import com.cloud.storage.DataStoreRole;
|
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.exception.CloudRuntimeException;
|
||||||
import com.cloud.utils.storage.encoding.DecodedDataObject;
|
import com.cloud.utils.storage.encoding.DecodedDataObject;
|
||||||
import com.cloud.utils.storage.encoding.DecodedDataStore;
|
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.Types.XenAPIException;
|
||||||
import com.xensource.xenapi.VDI;
|
import com.xensource.xenapi.VDI;
|
||||||
|
|
||||||
import edu.emory.mathcs.backport.java.util.Arrays;
|
|
||||||
|
|
||||||
public class XenServerStorageResource {
|
public class XenServerStorageResource {
|
||||||
private static final Logger s_logger = Logger.getLogger(XenServerStorageResource.class);
|
private static final Logger s_logger = Logger.getLogger(XenServerStorageResource.class);
|
||||||
protected CitrixResourceBase hypervisorResource;
|
protected CitrixResourceBase hypervisorResource;
|
||||||
@ -146,11 +160,61 @@ public class XenServerStorageResource {
|
|||||||
return new CreateObjectAnswer(cmd, templateUrl, size);*/
|
return new CreateObjectAnswer(cmd, templateUrl, size);*/
|
||||||
return null;
|
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) {
|
protected CreateObjectAnswer execute(CreateObjectCommand cmd) {
|
||||||
DataTO data = cmd.getData();
|
DataTO data = cmd.getData();
|
||||||
try {
|
try {
|
||||||
if (data.getObjectType() == DataObjectType.VOLUME) {
|
if (data.getObjectType() == DataObjectType.VOLUME) {
|
||||||
return createVolume(data);
|
return createVolume(data);
|
||||||
|
} else if (data.getObjectType() == DataObjectType.SNAPSHOT) {
|
||||||
|
return createSnapshot((SnapshotObjectTO)data);
|
||||||
}
|
}
|
||||||
return new CreateObjectAnswer("not supported type");
|
return new CreateObjectAnswer("not supported type");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -821,6 +885,330 @@ public class XenServerStorageResource {
|
|||||||
return new CopyCmdAnswer("unsupported protocol");
|
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) {
|
protected Answer execute(CopyCommand cmd) {
|
||||||
DataTO srcData = cmd.getSrcTO();
|
DataTO srcData = cmd.getSrcTO();
|
||||||
DataTO destData = cmd.getDestTO();
|
DataTO destData = cmd.getDestTO();
|
||||||
@ -838,6 +1226,9 @@ public class XenServerStorageResource {
|
|||||||
return copyVolumeFromImageCacheToPrimary(srcData, destData, cmd.getWait());
|
return copyVolumeFromImageCacheToPrimary(srcData, destData, cmd.getWait());
|
||||||
} else if (srcData.getObjectType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
|
} else if (srcData.getObjectType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
|
||||||
return copyVolumeFromPrimaryToSecondary(srcData, destData, cmd.getWait());
|
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");
|
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.framework.async.AsyncCompletionCallback;
|
||||||
import org.apache.cloudstack.storage.command.CreateObjectCommand;
|
import org.apache.cloudstack.storage.command.CreateObjectCommand;
|
||||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
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.cloudstack.storage.volume.VolumeObject;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
@ -193,24 +194,17 @@ public class CloudStackPrimaryDataStoreDriverImpl implements PrimaryDataStoreDri
|
|||||||
AsyncCompletionCallback<CreateCmdResult> callback) {
|
AsyncCompletionCallback<CreateCmdResult> callback) {
|
||||||
CreateCmdResult result = null;
|
CreateCmdResult result = null;
|
||||||
try {
|
try {
|
||||||
VolumeInfo volume = snapshot.getBaseVolume();
|
DataTO snapshotTO = snapshot.getTO();
|
||||||
String vmName = this.volumeMgr.getVmNameOnVolume(volume);
|
|
||||||
SnapshotVO preSnapshotVO = this.snapshotMgr.getParentSnapshot(volume, snapshot);
|
CreateObjectCommand cmd = new CreateObjectCommand(snapshotTO);
|
||||||
String parentSnapshotPath = null;
|
Answer answer = storageMgr.sendToPool((StoragePool)snapshot.getDataStore(), null, cmd);
|
||||||
if (preSnapshotVO != null) {
|
|
||||||
parentSnapshotPath = preSnapshotVO.getPath();
|
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);
|
callback.complete(result);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
s_logger.debug("Failed to take snapshot: " + snapshot.getId(), e);
|
s_logger.debug("Failed to take snapshot: " + snapshot.getId(), e);
|
||||||
result = new CreateCmdResult(null, null);
|
result = new CreateCmdResult(null, null);
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
package com.cloud.storage;
|
package com.cloud.storage;
|
||||||
|
|
||||||
|
import com.cloud.user.Account;
|
||||||
|
|
||||||
public class CreateSnapshotPayload {
|
public class CreateSnapshotPayload {
|
||||||
private Long snapshotPolicyId;
|
private Long snapshotPolicyId;
|
||||||
|
private Long snapshotId;
|
||||||
|
private Account account;
|
||||||
|
|
||||||
public Long getSnapshotPolicyId() {
|
public Long getSnapshotPolicyId() {
|
||||||
return snapshotPolicyId;
|
return snapshotPolicyId;
|
||||||
@ -11,4 +15,20 @@ public class CreateSnapshotPayload {
|
|||||||
this.snapshotPolicyId = snapshotPolicyId;
|
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.download.DownloadMonitor;
|
||||||
import com.cloud.storage.s3.S3Manager;
|
import com.cloud.storage.s3.S3Manager;
|
||||||
import com.cloud.storage.secondary.SecondaryStorageVmManager;
|
import com.cloud.storage.secondary.SecondaryStorageVmManager;
|
||||||
|
import com.cloud.storage.snapshot.SnapshotApiService;
|
||||||
import com.cloud.storage.snapshot.SnapshotManager;
|
import com.cloud.storage.snapshot.SnapshotManager;
|
||||||
import com.cloud.storage.snapshot.SnapshotScheduler;
|
import com.cloud.storage.snapshot.SnapshotScheduler;
|
||||||
import com.cloud.tags.dao.ResourceTagDao;
|
import com.cloud.tags.dao.ResourceTagDao;
|
||||||
@ -307,6 +308,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
|||||||
TemplateDataFactory tmplFactory;
|
TemplateDataFactory tmplFactory;
|
||||||
@Inject
|
@Inject
|
||||||
SnapshotDataFactory snapshotFactory;
|
SnapshotDataFactory snapshotFactory;
|
||||||
|
@Inject
|
||||||
|
SnapshotApiService snapshotMgr;
|
||||||
private int _copyvolumewait;
|
private int _copyvolumewait;
|
||||||
@Inject
|
@Inject
|
||||||
protected HypervisorCapabilitiesDao _hypervisorCapabilitiesDao;
|
protected HypervisorCapabilitiesDao _hypervisorCapabilitiesDao;
|
||||||
@ -526,7 +529,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
|||||||
|
|
||||||
VolumeInfo vol = this.volFactory.getVolume(volume.getId());
|
VolumeInfo vol = this.volFactory.getVolume(volume.getId());
|
||||||
DataStore store = this.dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary);
|
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);
|
AsyncCallFuture<VolumeApiResult> future = this.volService.createVolumeFromSnapshot(vol, store, snapInfo);
|
||||||
try {
|
try {
|
||||||
VolumeApiResult result = future.get();
|
VolumeApiResult result = future.get();
|
||||||
@ -2470,8 +2473,26 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Snapshot takeSnapshot(Long volumeId, Long policyId) throws ResourceAllocationException {
|
public Snapshot takeSnapshot(Long volumeId, Long policyId, Long snapshotId, Account account) throws ResourceAllocationException {
|
||||||
Account caller = UserContext.current().getCaller();
|
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);
|
VolumeInfo volume = this.volFactory.getVolume(volumeId);
|
||||||
if (volume == null) {
|
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");
|
throw new InvalidParameterValueException("VolumeId: " + volumeId + " please attach this volume to a VM before create snapshot for it");
|
||||||
}
|
}
|
||||||
|
|
||||||
CreateSnapshotPayload payload = new CreateSnapshotPayload();
|
return this.snapshotMgr.allocSnapshot(volumeId, policyId);
|
||||||
payload.setSnapshotPolicyId(policyId);
|
|
||||||
return this.volService.takeSnapshot(volume);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -151,7 +151,7 @@ public class SnapshotDaoImpl extends GenericDaoBase<SnapshotVO, Long> implements
|
|||||||
VolumeIdVersionSearch.and("volumeId", VolumeIdVersionSearch.entity().getVolumeId(), SearchCriteria.Op.EQ);
|
VolumeIdVersionSearch.and("volumeId", VolumeIdVersionSearch.entity().getVolumeId(), SearchCriteria.Op.EQ);
|
||||||
VolumeIdVersionSearch.and("version", VolumeIdVersionSearch.entity().getVersion(), SearchCriteria.Op.EQ);
|
VolumeIdVersionSearch.and("version", VolumeIdVersionSearch.entity().getVersion(), SearchCriteria.Op.EQ);
|
||||||
VolumeIdVersionSearch.done();
|
VolumeIdVersionSearch.done();
|
||||||
|
/*
|
||||||
ParentIdSearch = createSearchBuilder();
|
ParentIdSearch = createSearchBuilder();
|
||||||
ParentIdSearch.and("prevSnapshotId", ParentIdSearch.entity().getPrevSnapshotId(), SearchCriteria.Op.EQ);
|
ParentIdSearch.and("prevSnapshotId", ParentIdSearch.entity().getPrevSnapshotId(), SearchCriteria.Op.EQ);
|
||||||
ParentIdSearch.done();
|
ParentIdSearch.done();
|
||||||
@ -159,7 +159,7 @@ public class SnapshotDaoImpl extends GenericDaoBase<SnapshotVO, Long> implements
|
|||||||
backupUuidSearch = createSearchBuilder();
|
backupUuidSearch = createSearchBuilder();
|
||||||
backupUuidSearch.and("backupUuid", backupUuidSearch.entity().getBackupSnapshotId(), SearchCriteria.Op.EQ);
|
backupUuidSearch.and("backupUuid", backupUuidSearch.entity().getBackupSnapshotId(), SearchCriteria.Op.EQ);
|
||||||
backupUuidSearch.done();
|
backupUuidSearch.done();
|
||||||
|
*/
|
||||||
AccountIdSearch = createSearchBuilder();
|
AccountIdSearch = createSearchBuilder();
|
||||||
AccountIdSearch.and("accountId", AccountIdSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
|
AccountIdSearch.and("accountId", AccountIdSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
|
||||||
AccountIdSearch.done();
|
AccountIdSearch.done();
|
||||||
|
|||||||
@ -57,10 +57,6 @@ public interface SnapshotManager {
|
|||||||
*/
|
*/
|
||||||
boolean deleteSnapshotDirsForAccount(long accountId);
|
boolean deleteSnapshotDirsForAccount(long accountId);
|
||||||
|
|
||||||
void downloadSnapshotsFromSwift(SnapshotVO ss);
|
|
||||||
|
|
||||||
void downloadSnapshotsFromS3(SnapshotVO snapshot);
|
|
||||||
|
|
||||||
String getSecondaryStorageURL(SnapshotVO snapshot);
|
String getSecondaryStorageURL(SnapshotVO snapshot);
|
||||||
|
|
||||||
void deleteSnapshotsDirForVolume(String secondaryStoragePoolUrl, Long dcId, Long accountId, Long volumeId);
|
void deleteSnapshotsDirForVolume(String secondaryStoragePoolUrl, Long dcId, Long accountId, Long volumeId);
|
||||||
|
|||||||
@ -349,8 +349,10 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
|||||||
return this.snapshotSrv.backupSnapshot(snapshot);
|
return this.snapshotSrv.backupSnapshot(snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
@Override
|
@Override
|
||||||
public void downloadSnapshotsFromSwift(SnapshotVO ss) {
|
public void downloadSnapshotsFromSwift(SnapshotVO ss) {
|
||||||
|
|
||||||
long volumeId = ss.getVolumeId();
|
long volumeId = ss.getVolumeId();
|
||||||
VolumeVO volume = _volsDao.findById(volumeId);
|
VolumeVO volume = _volsDao.findById(volumeId);
|
||||||
Long dcId = volume.getDataCenterId();
|
Long dcId = volume.getDataCenterId();
|
||||||
@ -432,7 +434,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
|||||||
e);
|
e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SnapshotVO getParentSnapshot(VolumeInfo volume) {
|
public SnapshotVO getParentSnapshot(VolumeInfo volume) {
|
||||||
@ -974,72 +976,44 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
|||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public SnapshotInfo takeSnapshot(VolumeInfo volume) throws ResourceAllocationException {
|
public SnapshotInfo takeSnapshot(VolumeInfo volume) throws ResourceAllocationException {
|
||||||
Account caller = UserContext.current().getCaller();
|
CreateSnapshotPayload payload = (CreateSnapshotPayload)volume.getpayload();
|
||||||
|
Long snapshotId = payload.getSnapshotId();
|
||||||
supportedByHypervisor(volume);
|
Account snapshotOwner = payload.getAccount();
|
||||||
CreateSnapshotPayload snapInfo = (CreateSnapshotPayload)volume.getpayload();
|
SnapshotInfo snapshot = this.snapshotFactory.getSnapshot(snapshotId, volume.getDataStore());
|
||||||
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());
|
|
||||||
boolean processed = false;
|
boolean processed = false;
|
||||||
for (SnapshotStrategy strategy : snapshotStrategies) {
|
|
||||||
if (strategy.canHandle(snap)) {
|
try {
|
||||||
processed = true;
|
for (SnapshotStrategy strategy : snapshotStrategies) {
|
||||||
snap = strategy.takeSnapshot(snap);
|
if (strategy.canHandle(snapshot)) {
|
||||||
break;
|
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) {
|
return snapshot;
|
||||||
throw new CloudRuntimeException("Can't find snapshot strategy to deal with snapshot:" + snapshot.getId());
|
|
||||||
}
|
|
||||||
return snap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1128,4 +1102,61 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
|
|||||||
}
|
}
|
||||||
return true;
|
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;
|
AsyncCallFuture<TemplateApiResult> future = null;
|
||||||
if (snapshotId != 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));
|
future = this._tmpltSvr.createTemplateFromSnapshotAsync(snapInfo, tmplInfo, store.get(0));
|
||||||
} else if (volumeId != null) {
|
} else if (volumeId != null) {
|
||||||
volume = _volumeDao.findById(volumeId);
|
volume = _volumeDao.findById(volumeId);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user