You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ed...@apache.org on 2013/04/30 04:38:13 UTC
[4/5] git commit: updated refs/heads/object_store to 99dcb23
refactor snapshot
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/2f689171
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/2f689171
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/2f689171
Branch: refs/heads/object_store
Commit: 2f689171e0e989982b3391944eee49acf98f98e1
Parents: 37cbe88
Author: Edison Su <su...@gmail.com>
Authored: Mon Apr 29 18:50:46 2013 -0700
Committer: Edison Su <su...@gmail.com>
Committed: Mon Apr 29 18:51:14 2013 -0700
----------------------------------------------------------------------
api/src/com/cloud/storage/Snapshot.java | 5 +
api/src/com/cloud/storage/VolumeApiService.java | 5 +-
.../command/user/snapshot/CreateSnapshotCmd.java | 20 +-
.../subsystem/api/storage/SnapshotStrategy.java | 7 +-
.../subsystem/api/storage/StorageCacheManager.java | 7 +
.../engine/subsystem/api/storage/VolumeInfo.java | 1 +
.../cloudstack/storage/command/CopyCommand.java | 16 +-
.../cloudstack/storage/to/SnapshotObjectTO.java | 70 +++-
.../cloudstack/storage/to/VolumeObjectTO.java | 10 +
.../cache/manager/StorageCacheManagerImpl.java | 14 +
.../storage/motion/AncientDataMotionStrategy.java | 376 ++++-----------
.../storage/snapshot/SnapshotObject.java | 8 +
.../storage/snapshot/SnapshotServiceImpl.java | 2 +-
.../snapshot/SnapshotStateMachineManagerImpl.java | 6 +
.../storage/snapshot/SnapshotStrategyBase.java | 4 +-
.../snapshot/XenserverSnapshotStrategy.java | 132 +++---
.../datastore/ObjectInDataStoreManagerImpl.java | 28 +-
.../storage/image/db/SnapshotDataStoreDaoImpl.java | 6 +
.../storage/snapshot/SnapshotEntityImpl.java | 6 -
.../cloudstack/storage/volume/VolumeObject.java | 17 +
.../storage/volume/VolumeServiceImpl.java | 11 +-
.../xen/resource/CitrixResourceBase.java | 2 +-
.../xen/resource/XenServerStorageResource.java | 397 ++++++++++++++-
.../CloudStackPrimaryDataStoreDriverImpl.java | 26 +-
.../com/cloud/storage/CreateSnapshotPayload.java | 20 +
.../src/com/cloud/storage/VolumeManagerImpl.java | 32 +-
.../src/com/cloud/storage/dao/SnapshotDaoImpl.java | 4 +-
.../cloud/storage/snapshot/SnapshotManager.java | 4 -
.../storage/snapshot/SnapshotManagerImpl.java | 151 ++++---
.../com/cloud/template/TemplateManagerImpl.java | 2 +-
30 files changed, 889 insertions(+), 500 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/api/src/com/cloud/storage/Snapshot.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/storage/Snapshot.java b/api/src/com/cloud/storage/Snapshot.java
index 0d58a14..27a2fe4 100644
--- a/api/src/com/cloud/storage/Snapshot.java
+++ b/api/src/com/cloud/storage/Snapshot.java
@@ -60,6 +60,9 @@ public interface Snapshot extends ControlledEntity, Identity, InternalIdentity,
CreatedOnPrimary,
BackingUp,
BackedUp,
+ Copying,
+ Destroying,
+ Destroyed,//it's a state, user can't see the snapshot from ui, while the snapshot may still exist on the storage
Error;
public String toString() {
@@ -76,6 +79,8 @@ public interface Snapshot extends ControlledEntity, Identity, InternalIdentity,
OperationNotPerformed,
BackupToSecondary,
BackedupToSecondary,
+ DestroyRequested,
+ CopyingRequested,
OperationSucceeded,
OperationFailed
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/api/src/com/cloud/storage/VolumeApiService.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/storage/VolumeApiService.java b/api/src/com/cloud/storage/VolumeApiService.java
index 2f5364f..462ff64 100644
--- a/api/src/com/cloud/storage/VolumeApiService.java
+++ b/api/src/com/cloud/storage/VolumeApiService.java
@@ -80,6 +80,9 @@ public interface VolumeApiService {
Volume detachVolumeFromVM(DetachVolumeCmd cmmd);
- Snapshot takeSnapshot(Long volumeId, Long policyId)
+ Snapshot takeSnapshot(Long volumeId, Long policyId, Long snapshotId, Account account)
throws ResourceAllocationException;
+
+ Snapshot allocSnapshot(Long volumeId, Long policyId)
+ throws ResourceAllocationException;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/api/src/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotCmd.java b/api/src/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotCmd.java
index 95d7659..25cdedd 100644
--- a/api/src/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/snapshot/CreateSnapshotCmd.java
@@ -152,7 +152,7 @@ public class CreateSnapshotCmd extends BaseAsyncCreateCmd {
@Override
public void create() throws ResourceAllocationException {
- Snapshot snapshot = _snapshotService.allocSnapshot(getVolumeId(), getPolicyId());
+ Snapshot snapshot = this._volumeService.allocSnapshot(getVolumeId(), getPolicyId());
if (snapshot != null) {
this.setEntityId(snapshot.getId());
this.setEntityUuid(snapshot.getUuid());
@@ -164,14 +164,20 @@ public class CreateSnapshotCmd extends BaseAsyncCreateCmd {
@Override
public void execute() {
UserContext.current().setEventDetails("Volume Id: "+getVolumeId());
- Snapshot snapshot = _snapshotService.createSnapshot(getVolumeId(), getPolicyId(), getEntityId(), _accountService.getAccount(getEntityOwnerId()));
- if (snapshot != null) {
- SnapshotResponse response = _responseGenerator.createSnapshotResponse(snapshot);
- response.setResponseName(getCommandName());
- this.setResponseObject(response);
- } else {
+ Snapshot snapshot;
+ try {
+ snapshot = _volumeService.takeSnapshot(this.getVolumeId(), this.getPolicyId(), this.getEntityId(), _accountService.getAccount(getEntityOwnerId()));
+ if (snapshot != null) {
+ SnapshotResponse response = _responseGenerator.createSnapshotResponse(snapshot);
+ response.setResponseName(getCommandName());
+ this.setResponseObject(response);
+ } else {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create snapshot due to an internal error creating snapshot for volume " + volumeId);
+ }
+ } catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create snapshot due to an internal error creating snapshot for volume " + volumeId);
}
+
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java
index a642b5e..6b90c31 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java
@@ -3,9 +3,14 @@ package org.apache.cloudstack.engine.subsystem.api.storage;
import com.cloud.storage.Snapshot;
+
public interface SnapshotStrategy {
public SnapshotInfo takeSnapshot(SnapshotInfo snapshot);
public SnapshotInfo backupSnapshot(SnapshotInfo snapshot);
public boolean deleteSnapshot(Long snapshotId);
- public boolean canHandle(Snapshot snapshot);
+ /**
+ * @param snapshot
+ * @return
+ */
+ boolean canHandle(Snapshot snapshot);
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StorageCacheManager.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StorageCacheManager.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StorageCacheManager.java
index 70332c7..0aa30d3 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StorageCacheManager.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/StorageCacheManager.java
@@ -22,4 +22,11 @@ package org.apache.cloudstack.engine.subsystem.api.storage;
public interface StorageCacheManager {
public DataStore getCacheStorage(Scope scope);
public DataObject createCacheObject(DataObject data, Scope scope);
+ /** only create cache object in db
+ * @param data
+ * @param scope
+ * @return
+ */
+ DataObject getCacheObject(DataObject data, Scope scope);
+ DataObject deleteCacheObject(DataObject data);
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java
index 349325a..7165f37 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeInfo.java
@@ -27,4 +27,5 @@ public interface VolumeInfo extends DataObject, Volume {
public Object getpayload();
public HypervisorType getHypervisorType();
public Long getLastPoolId();
+ public String getAttachedVmName();
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/api/src/org/apache/cloudstack/storage/command/CopyCommand.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/command/CopyCommand.java b/engine/api/src/org/apache/cloudstack/storage/command/CopyCommand.java
index 5fe1cbe..5bceb03 100644
--- a/engine/api/src/org/apache/cloudstack/storage/command/CopyCommand.java
+++ b/engine/api/src/org/apache/cloudstack/storage/command/CopyCommand.java
@@ -23,12 +23,12 @@ import com.cloud.agent.api.Command;
public class CopyCommand extends Command implements StorageSubSystemCommand {
private DataTO srcTO;
private DataTO destTO;
+ private DataTO cacheTO;
-
- public CopyCommand(DataTO srcUri, DataTO destUri, int timeout) {
+ public CopyCommand(DataTO srcData, DataTO destData, int timeout) {
super();
- this.srcTO = srcUri;
- this.destTO = destUri;
+ this.srcTO = srcData;
+ this.destTO = destData;
this.setWait(timeout);
}
@@ -45,4 +45,12 @@ public class CopyCommand extends Command implements StorageSubSystemCommand {
return true;
}
+ public DataTO getCacheTO() {
+ return cacheTO;
+ }
+
+ public void setCacheTO(DataTO cacheTO) {
+ this.cacheTO = cacheTO;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java b/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
index 38fea16..6d98045 100644
--- a/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
+++ b/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
@@ -2,21 +2,43 @@ package org.apache.cloudstack.storage.to;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
+import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import com.cloud.agent.api.to.DataStoreTO;
public class SnapshotObjectTO implements DataTO {
private String path;
+ private VolumeObjectTO volume;
+ private String parentSnapshotPath;
+ private DataStoreTO dataStore;
+ private String vmName;
+ private String name;
+ private long id;
+
+ public SnapshotObjectTO() {
+
+ }
+
+ public SnapshotObjectTO(SnapshotInfo snapshot) {
+ this.path = snapshot.getPath();
+ this.setId(snapshot.getId());
+ this.volume = (VolumeObjectTO)snapshot.getBaseVolume().getTO();
+ this.setVmName(snapshot.getBaseVolume().getAttachedVmName());
+ if (snapshot.getParent() != null) {
+ this.parentSnapshotPath = snapshot.getParent().getPath();
+ }
+ this.dataStore = snapshot.getDataStore().getTO();
+ this.setName(snapshot.getName());
+ }
+
@Override
public DataObjectType getObjectType() {
- // TODO Auto-generated method stub
- return null;
+ return DataObjectType.SNAPSHOT;
}
@Override
public DataStoreTO getDataStore() {
- // TODO Auto-generated method stub
- return null;
+ return this.dataStore;
}
@Override
@@ -27,4 +49,44 @@ public class SnapshotObjectTO implements DataTO {
public void setPath(String path) {
this.path = path;
}
+
+ public VolumeObjectTO getVolume() {
+ return volume;
+ }
+
+ public void setVolume(VolumeObjectTO volume) {
+ this.volume = volume;
+ }
+
+ public String getParentSnapshotPath() {
+ return parentSnapshotPath;
+ }
+
+ public void setParentSnapshotPath(String parentSnapshotPath) {
+ this.parentSnapshotPath = parentSnapshotPath;
+ }
+
+ public String getVmName() {
+ return vmName;
+ }
+
+ public void setVmName(String vmName) {
+ this.vmName = vmName;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java b/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
index bf1bb3c..4ca1f9b 100644
--- a/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
+++ b/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
@@ -32,6 +32,7 @@ public class VolumeObjectTO implements DataTO {
private String name;
private long size;
private String path;
+ private Long volumeId;
public VolumeObjectTO() {
@@ -49,6 +50,7 @@ public class VolumeObjectTO implements DataTO {
}
//this.name = volume.getName();
this.size = volume.getSize();
+ this.setVolumeId(volume.getId());
}
public String getUuid() {
@@ -103,4 +105,12 @@ public class VolumeObjectTO implements DataTO {
this.path = path;
}
+ public Long getVolumeId() {
+ return volumeId;
+ }
+
+ public void setVolumeId(Long volumeId) {
+ this.volumeId = volumeId;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java b/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java
index d2aacde..3a445d4 100644
--- a/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java
+++ b/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java
@@ -164,10 +164,24 @@ public class StorageCacheManagerImpl implements StorageCacheManager, Manager {
return null;
}
+ @Override
+ public DataObject getCacheObject(DataObject data, Scope scope) {
+ DataStore cacheStore = this.getCacheStorage(scope);
+ DataObject objOnCacheStore = cacheStore.create(data);
+
+ return objOnCacheStore;
+ }
+
protected Void createCacheObjectCallBack(AsyncCallbackDispatcher<StorageCacheManagerImpl, CopyCommandResult> callback,
CreateCacheObjectContext<CopyCommandResult> context) {
AsyncCallFuture<CopyCommandResult> future = context.future;
future.complete(callback.getResult());
return null;
}
+
+ @Override
+ public DataObject deleteCacheObject(DataObject data) {
+ // TODO Auto-generated method stub
+ return null;
+ }
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
index 79ae289..2075ef6 100644
--- a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
+++ b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
@@ -60,6 +60,8 @@ import com.cloud.agent.api.UpgradeSnapshotCommand;
import com.cloud.agent.api.storage.CopyVolumeAnswer;
import com.cloud.agent.api.storage.CopyVolumeCommand;
import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
+import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.NfsTO;
import com.cloud.agent.api.to.S3TO;
import com.cloud.agent.api.to.SwiftTO;
import com.cloud.configuration.Config;
@@ -127,10 +129,6 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
@Inject
VolumeManager volumeMgr;
@Inject
- private SwiftManager _swiftMgr;
- @Inject
- private S3Manager _s3Mgr;
- @Inject
StorageCacheManager cacheMgr;
@Override
@@ -179,112 +177,55 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
return answer;
}
}
+
+ protected DataObject cacheSnapshotChain(SnapshotInfo snapshot) {
+ DataObject leafData = null;
+ while(snapshot != null) {
+ DataObject cacheData = cacheMgr.createCacheObject(snapshot, snapshot.getDataStore().getScope());
+ if (leafData == null) {
+ leafData = cacheData;
+ }
+ snapshot = snapshot.getParent();
+ }
+ return leafData;
+ }
+
+ protected void deleteSnapshotCacheChain(SnapshotInfo snapshot) {
+
+ }
- protected Answer copyFromSnapshot(DataObject snapObj, DataObject volObj) {
- SnapshotVO snapshot = this.snapshotDao.findById(snapObj.getId());
+ protected Answer copyVolumeFromSnapshot(DataObject snapObj, DataObject volObj) {
+ SnapshotInfo snapshot = (SnapshotInfo)snapObj;
StoragePool pool = (StoragePool) volObj.getDataStore();
- String vdiUUID = null;
- Long snapshotId = snapshot.getId();
- Long volumeId = snapshot.getVolumeId();
- Long dcId = snapshot.getDataCenterId();
- String secondaryStoragePoolUrl = this.snapshotMgr
- .getSecondaryStorageURL(snapshot);
- long accountId = snapshot.getAccountId();
- String backedUpSnapshotUuid = snapshot.getBackupSnapshotId();
- snapshot = snapshotDao.findById(snapshotId);
- if (snapshot.getVersion().trim().equals("2.1")) {
- VolumeVO volume = this.volDao.findByIdIncludingRemoved(volumeId);
- if (volume == null) {
- throw new CloudRuntimeException("failed to upgrade snapshot "
- + snapshotId + " due to unable to find orignal volume:"
- + volumeId + ", try it later ");
- }
- if (volume.getTemplateId() == null) {
- snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2");
- } else {
- VMTemplateVO template = templateDao
- .findByIdIncludingRemoved(volume.getTemplateId());
- if (template == null) {
- throw new CloudRuntimeException(
- "failed to upgrade snapshot "
- + snapshotId
- + " due to unalbe to find orignal template :"
- + volume.getTemplateId()
- + ", try it later ");
- }
- Long templateId = template.getId();
- Long tmpltAccountId = template.getAccountId();
- if (!snapshotDao.lockInLockTable(snapshotId.toString(), 10)) {
- throw new CloudRuntimeException(
- "failed to upgrade snapshot "
- + snapshotId
- + " due to this snapshot is being used, try it later ");
- }
- UpgradeSnapshotCommand cmd = new UpgradeSnapshotCommand(null,
- secondaryStoragePoolUrl, dcId, accountId, volumeId,
- templateId, tmpltAccountId, null,
- snapshot.getBackupSnapshotId(), snapshot.getName(),
- "2.1");
- Answer answer = null;
- try {
- answer = this.storageMgr.sendToPool(pool, cmd);
- } catch (StorageUnavailableException e) {
- } finally {
- snapshotDao.unlockFromLockTable(snapshotId.toString());
- }
- if ((answer != null) && answer.getResult()) {
- snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2");
- } else {
- throw new CloudRuntimeException("Unable to upgrade snapshot from 2.1 to 2.2 for "
- + snapshot.getId());
- }
- }
- }
String basicErrMsg = "Failed to create volume from "
+ snapshot.getName() + " on pool " + pool;
-
+ DataStore store = snapObj.getDataStore();
+ DataStoreTO storTO = store.getTO();
+ DataObject srcData = snapObj;
try {
- if (snapshot.getSwiftId() != null && snapshot.getSwiftId() != 0) {
- snapshotMgr.downloadSnapshotsFromSwift(snapshot);
- } else if (snapshot.getS3Id() != null && snapshot.getS3Id() != 0) {
- snapshotMgr.downloadSnapshotsFromS3(snapshot);
+ if (!(storTO instanceof NfsTO)) {
+ srcData = cacheSnapshotChain(snapshot);
}
+
String value = configDao
.getValue(Config.CreateVolumeFromSnapshotWait.toString());
int _createVolumeFromSnapshotWait = NumbersUtil.parseInt(value,
Integer.parseInt(Config.CreateVolumeFromSnapshotWait
.getDefaultValue()));
- CreateVolumeFromSnapshotCommand createVolumeFromSnapshotCommand = new CreateVolumeFromSnapshotCommand(
- pool, secondaryStoragePoolUrl, dcId, accountId, volumeId,
- backedUpSnapshotUuid, snapshot.getName(),
- _createVolumeFromSnapshotWait);
- CreateVolumeFromSnapshotAnswer answer;
- if (!snapshotDao.lockInLockTable(snapshotId.toString(), 10)) {
- throw new CloudRuntimeException("failed to create volume from "
- + snapshotId
- + " due to this snapshot is being used, try it later ");
- }
- answer = (CreateVolumeFromSnapshotAnswer) this.storageMgr
- .sendToPool(pool, createVolumeFromSnapshotCommand);
- if (answer != null && answer.getResult()) {
- vdiUUID = answer.getVdi();
- VolumeVO vol = this.volDao.findById(volObj.getId());
- vol.setPath(vdiUUID);
- this.volDao.update(vol.getId(), vol);
- return null;
- } else {
- s_logger.error(basicErrMsg + " due to "
- + ((answer == null) ? "null" : answer.getDetails()));
- throw new CloudRuntimeException(basicErrMsg);
- }
+
+ CopyCommand cmd = new CopyCommand(srcData.getTO(), volObj.getTO(), _createVolumeFromSnapshotWait);
+
+
+ Answer answer = this.storageMgr
+ .sendToPool(pool, cmd);
+ return answer;
} catch (StorageUnavailableException e) {
s_logger.error(basicErrMsg, e);
throw new CloudRuntimeException(basicErrMsg);
} finally {
- if (snapshot.getSwiftId() != null) {
- snapshotMgr.deleteSnapshotsDirForVolume(
- secondaryStoragePoolUrl, dcId, accountId, volumeId);
+ if (!(storTO instanceof NfsTO)) {
+ deleteSnapshotCacheChain((SnapshotInfo)srcData);
}
}
}
@@ -328,7 +269,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
answer = copyTemplate(srcData, destData);
} else if (srcData.getType() == DataObjectType.SNAPSHOT
&& destData.getType() == DataObjectType.VOLUME) {
- answer = copyFromSnapshot(srcData, destData);
+ answer = copyVolumeFromSnapshot(srcData, destData);
} else if (srcData.getType() == DataObjectType.SNAPSHOT
&& destData.getType() == DataObjectType.TEMPLATE) {
answer = createTemplateFromSnapshot(srcData, destData);
@@ -359,49 +300,7 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
@DB
protected Answer createTemplateFromSnapshot(DataObject srcData,
DataObject destData) {
- long snapshotId = srcData.getId();
- SnapshotVO snapshot = snapshotDao.findById(snapshotId);
- if (snapshot == null) {
- throw new CloudRuntimeException("Unable to find Snapshot for Id "
- + srcData.getId());
- }
- Long zoneId = snapshot.getDataCenterId();
- DataStore secStore = destData.getDataStore();
- /*
- HostVO secondaryStorageHost = this.templateMgr
- .getSecondaryStorageHost(zoneId);
- */
- String secondaryStorageURL = snapshotMgr
- .getSecondaryStorageURL(snapshot);
- VMTemplateVO template = this.templateDao.findById(destData.getId());
- String name = template.getName();
- String backupSnapshotUUID = snapshot.getBackupSnapshotId();
- if (backupSnapshotUUID == null) {
- throw new CloudRuntimeException(
- "Unable to create private template from snapshot "
- + snapshotId
- + " due to there is no backupSnapshotUUID for this snapshot");
- }
-
- Long dcId = snapshot.getDataCenterId();
- Long accountId = snapshot.getAccountId();
- Long volumeId = snapshot.getVolumeId();
-
- String origTemplateInstallPath = null;
- List<StoragePoolVO> pools = this.storageMgr
- .ListByDataCenterHypervisor(zoneId,
- snapshot.getHypervisorType());
- if (pools == null || pools.size() == 0) {
- throw new CloudRuntimeException(
- "Unable to find storage pools in zone " + zoneId);
- }
- StoragePoolVO poolvo = pools.get(0);
- StoragePool pool = (StoragePool) this.dataStoreMgr.getDataStore(
- poolvo.getId(), DataStoreRole.Primary);
-
- if (snapshot.getSwiftId() != null && snapshot.getSwiftId() != 0) {
- snapshotMgr.downloadSnapshotsFromSwift(snapshot);
- }
+
String value = configDao
.getValue(Config.CreatePrivateTemplateFromSnapshotWait
.toString());
@@ -410,172 +309,71 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
.parseInt(Config.CreatePrivateTemplateFromSnapshotWait
.getDefaultValue()));
- CreatePrivateTemplateFromSnapshotCommand cmd = new CreatePrivateTemplateFromSnapshotCommand(
- pool, secondaryStorageURL, dcId, accountId,
- snapshot.getVolumeId(), backupSnapshotUUID, snapshot.getName(),
- origTemplateInstallPath, template.getId(), name,
- _createprivatetemplatefromsnapshotwait);
-
- return sendCommand(cmd, pool, template.getId(), dcId, secStore);
- }
-
- @DB
- protected Answer sendCommand(Command cmd, StoragePool pool,
- long templateId, long zoneId, DataStore secStore) {
-
- CreatePrivateTemplateAnswer answer = null;
- try {
- answer = (CreatePrivateTemplateAnswer) this.storageMgr.sendToPool(
- pool, cmd);
- } catch (StorageUnavailableException e) {
- throw new CloudRuntimeException(
- "Failed to execute CreatePrivateTemplateFromSnapshotCommand",
- e);
- }
-
- if (answer == null || !answer.getResult()) {
- return answer;
- }
-
- VMTemplateVO privateTemplate = templateDao.findById(templateId);
- String answerUniqueName = answer.getUniqueName();
- if (answerUniqueName != null) {
- privateTemplate.setUniqueName(answerUniqueName);
- }
- ImageFormat format = answer.getImageFormat();
- if (format != null) {
- privateTemplate.setFormat(format);
- } else {
- // This never occurs.
- // Specify RAW format makes it unusable for snapshots.
- privateTemplate.setFormat(ImageFormat.RAW);
+ if (srcData.getDataStore().getRole() != DataStoreRole.ImageCache && destData.getDataStore().getRole() != DataStoreRole.ImageCache) {
+ SnapshotInfo snapshot = (SnapshotInfo)srcData;
+ srcData = cacheSnapshotChain(snapshot);
}
- String checkSum = this.templateMgr
- .getChecksum(secStore, answer.getPath());
-
- Transaction txn = Transaction.currentTxn();
-
- txn.start();
-
- privateTemplate.setChecksum(checkSum);
- templateDao.update(privateTemplate.getId(), privateTemplate);
-
- // add template zone ref for this template
- templateDao.addTemplateToZone(privateTemplate, zoneId);
- TemplateDataStoreVO templateHostVO = new TemplateDataStoreVO(secStore.getId(),
- privateTemplate.getId());
- templateHostVO.setDownloadPercent(100);
- templateHostVO.setDownloadState(Status.DOWNLOADED);
- templateHostVO.setInstallPath(answer.getPath());
- templateHostVO.setLastUpdated(new Date());
- templateHostVO.setSize(answer.getVirtualSize());
- templateHostVO.setPhysicalSize(answer.getphysicalSize());
- templateStoreDao.persist(templateHostVO);
- txn.close();
+ CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _createprivatetemplatefromsnapshotwait);
+ EndPoint ep = selector.select(srcData, destData);
+ Answer answer = ep.sendMessage(cmd);
return answer;
}
- private Answer createTemplateFromVolume(DataObject srcObj,
- DataObject destObj) {
- long volumeId = srcObj.getId();
- VolumeVO volume = this.volDao.findById(volumeId);
- if (volume == null) {
- throw new CloudRuntimeException("Unable to find volume for Id "
- + volumeId);
- }
- long accountId = volume.getAccountId();
- String vmName = this.volumeMgr.getVmNameOnVolume(volume);
- Long zoneId = volume.getDataCenterId();
- DataStore secStore = destObj.getDataStore();
- String secondaryStorageURL = secStore.getUri();
- VMTemplateVO template = this.templateDao.findById(destObj.getId());
- StoragePool pool = (StoragePool) this.dataStoreMgr.getDataStore(
- volume.getPoolId(), DataStoreRole.Primary);
+ private Answer createTemplateFromVolume(DataObject srcData,
+ DataObject destData) {
+
String value = configDao
.getValue(Config.CreatePrivateTemplateFromVolumeWait.toString());
int _createprivatetemplatefromvolumewait = NumbersUtil.parseInt(value,
Integer.parseInt(Config.CreatePrivateTemplateFromVolumeWait
.getDefaultValue()));
-
- CreatePrivateTemplateFromVolumeCommand cmd = new CreatePrivateTemplateFromVolumeCommand(
- pool, secondaryStorageURL, destObj.getId(), accountId,
- template.getName(), template.getUniqueName(), volume.getPath(),
- vmName, _createprivatetemplatefromvolumewait);
-
- return sendCommand(cmd, pool, template.getId(), zoneId, secStore);
- }
-
- private DataStore getSecHost(long volumeId, long dcId) {
- Long id = snapshotDao.getSecHostId(volumeId);
- if ( id != null) {
- return this.dataStoreMgr.getDataStore(id, DataStoreRole.Image);
+
+ if (srcData.getDataStore().getRole() != DataStoreRole.ImageCache && destData.getDataStore().getRole() != DataStoreRole.ImageCache) {
+ //need to copy it to image cache store
+ DataObject cacheData = cacheMgr.createCacheObject(srcData, destData.getDataStore().getScope());
+ CopyCommand cmd = new CopyCommand(cacheData.getTO(), destData.getTO(), _createprivatetemplatefromvolumewait);
+ EndPoint ep = selector.select(cacheData, destData);
+ Answer answer = ep.sendMessage(cmd);
+ return answer;
+ } else {
+ //handle copy it to/from cache store
+ CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _createprivatetemplatefromvolumewait);
+ EndPoint ep = selector.select(srcData, destData);
+ Answer answer = ep.sendMessage(cmd);
+ return answer;
}
- return this.dataStoreMgr.getImageStore(dcId);
}
- protected Answer copySnapshot(DataObject srcObject, DataObject destObject) {
- SnapshotInfo srcSnapshot = (SnapshotInfo)srcObject;
- VolumeInfo baseVolume = srcSnapshot.getBaseVolume();
- Long dcId = baseVolume.getDataCenterId();
- Long accountId = baseVolume.getAccountId();
-
- DataStore secStore = getSecHost(baseVolume.getId(), baseVolume.getDataCenterId());
- Long secHostId = secStore.getId();
- String secondaryStoragePoolUrl = secStore.getUri();
- String snapshotUuid = srcSnapshot.getPath();
- // In order to verify that the snapshot is not empty,
- // we check if the parent of the snapshot is not the same as the parent of the previous snapshot.
- // We pass the uuid of the previous snapshot to the plugin to verify this.
- SnapshotVO prevSnapshot = null;
- String prevSnapshotUuid = null;
- String prevBackupUuid = null;
-
-
- SwiftTO swift = _swiftMgr.getSwiftTO();
- S3TO s3 = _s3Mgr.getS3TO();
-
- long prevSnapshotId = srcSnapshot.getPrevSnapshotId();
- if (prevSnapshotId > 0) {
- prevSnapshot = snapshotDao.findByIdIncludingRemoved(prevSnapshotId);
- if ( prevSnapshot.getBackupSnapshotId() != null && swift == null) {
- if (prevSnapshot.getVersion() != null && prevSnapshot.getVersion().equals("2.2")) {
- prevBackupUuid = prevSnapshot.getBackupSnapshotId();
- prevSnapshotUuid = prevSnapshot.getPath();
- }
- } else if ((prevSnapshot.getSwiftId() != null && swift != null)
- || (prevSnapshot.getS3Id() != null && s3 != null)) {
- prevBackupUuid = prevSnapshot.getBackupSnapshotId();
- prevSnapshotUuid = prevSnapshot.getPath();
- }
- }
- boolean isVolumeInactive = this.volumeMgr.volumeInactive(baseVolume);
- String vmName = this.volumeMgr.getVmNameOnVolume(baseVolume);
- StoragePool srcPool = (StoragePool)dataStoreMgr.getPrimaryDataStore(baseVolume.getPoolId());
- String value = configDao.getValue(Config.BackupSnapshotWait.toString());
- int _backupsnapshotwait = NumbersUtil.parseInt(value, Integer.parseInt(Config.BackupSnapshotWait.getDefaultValue()));
- BackupSnapshotCommand backupSnapshotCommand = new BackupSnapshotCommand(secondaryStoragePoolUrl, dcId, accountId, baseVolume.getId(), srcSnapshot.getId(), secHostId, baseVolume.getPath(), srcPool, snapshotUuid,
- srcSnapshot.getName(), prevSnapshotUuid, prevBackupUuid, isVolumeInactive, vmName, _backupsnapshotwait);
+ protected Answer copySnapshot(DataObject srcData, DataObject destData) {
+ String value = configDao.getValue(Config.BackupSnapshotWait.toString());
+ int _backupsnapshotwait = NumbersUtil.parseInt(value, Integer.parseInt(Config.BackupSnapshotWait.getDefaultValue()));
- if ( swift != null ) {
- backupSnapshotCommand.setSwift(swift);
- } else if (s3 != null) {
- backupSnapshotCommand.setS3(s3);
- }
- BackupSnapshotAnswer answer = (BackupSnapshotAnswer) this.snapshotMgr.sendToPool(baseVolume, backupSnapshotCommand);
- if (answer != null && answer.getResult()) {
- SnapshotVO snapshotVO = this.snapshotDao.findById(srcSnapshot.getId());
- snapshotVO.setBackupSnapshotId(answer.getBackupSnapshotName());
- // persist an entry in snapshot_store_ref
- SnapshotDataStoreVO snapshotStore = new SnapshotDataStoreVO(secStore.getId(), snapshotVO.getId());
- this._snapshotStoreDao.persist(snapshotStore);
- if (answer.isFull()) {
- snapshotVO.setPrevSnapshotId(0L);
- }
- this.snapshotDao.update(srcSnapshot.getId(), snapshotVO);
- }
- return answer;
+ DataObject cacheData = null;
+ try {
+ if (destData.getDataStore().getRole() != DataStoreRole.ImageCache) {
+ cacheData = cacheMgr.getCacheObject(srcData, destData.getDataStore().getScope());
+
+ CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _backupsnapshotwait);
+ cmd.setCacheTO(cacheData.getTO());
+ EndPoint ep = selector.select(srcData, destData);
+ Answer answer = ep.sendMessage(cmd);
+ return answer;
+ } else {
+ CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _backupsnapshotwait);
+ EndPoint ep = selector.select(srcData, destData);
+ Answer answer = ep.sendMessage(cmd);
+ return answer;
+ }
+ } catch (Exception e) {
+ s_logger.debug("copy snasphot failed: " + e.toString());
+ if (cacheData != null) {
+ cacheMgr.deleteCacheObject(cacheData);
+ }
+ throw new CloudRuntimeException(e.toString());
+ }
+
}
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
index 50f3819..6fddcda 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
@@ -30,6 +30,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat;
+import org.apache.cloudstack.storage.command.CopyCmdAnswer;
import org.apache.cloudstack.storage.command.CreateObjectAnswer;
import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
@@ -234,6 +235,13 @@ public class SnapshotObject implements SnapshotInfo {
SnapshotObjectTO snapshotTO = (SnapshotObjectTO)((CreateObjectAnswer) answer).getData();
snapshotStore.setInstallPath(snapshotTO.getPath());
this.snapshotStore.update(snapshotStore.getId(), snapshotStore);
+ } else if (answer instanceof CopyCmdAnswer) {
+ SnapshotObjectTO snapshotTO = (SnapshotObjectTO)((CopyCmdAnswer) answer).getNewData();
+ snapshotStore.setInstallPath(snapshotTO.getPath());
+ if (snapshotTO.getParentSnapshotPath() == null) {
+ snapshotStore.setParentSnapshotId(0L);
+ }
+ this.snapshotStore.update(snapshotStore.getId(), snapshotStore);
} else {
throw new CloudRuntimeException("Unknown answer: " + answer.getClass());
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
index 2fb4609..615ed20 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
@@ -399,7 +399,7 @@ public class SnapshotServiceImpl implements SnapshotService {
@Override
public boolean deleteSnapshot(SnapshotInfo snapInfo) {
-
+ return true;
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManagerImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManagerImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManagerImpl.java
index aa1cf68..489ba28 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManagerImpl.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStateMachineManagerImpl.java
@@ -44,6 +44,12 @@ SnapshotStateMachineManager {
stateMachine.addTransition(Snapshot.State.CreatedOnPrimary, Event.BackupToSecondary, Snapshot.State.BackingUp);
stateMachine.addTransition(Snapshot.State.BackingUp, Event.OperationSucceeded, Snapshot.State.BackedUp);
stateMachine.addTransition(Snapshot.State.BackingUp, Event.OperationFailed, Snapshot.State.CreatedOnPrimary);
+ stateMachine.addTransition(Snapshot.State.BackedUp, Event.DestroyRequested, Snapshot.State.Destroying);
+ stateMachine.addTransition(Snapshot.State.BackedUp, Event.CopyingRequested, Snapshot.State.Copying);
+ stateMachine.addTransition(Snapshot.State.Copying, Event.OperationSucceeded, Snapshot.State.BackedUp);
+ stateMachine.addTransition(Snapshot.State.Copying, Event.OperationFailed, Snapshot.State.BackedUp);
+ stateMachine.addTransition(Snapshot.State.Destroying, Event.OperationSucceeded, Snapshot.State.Destroyed);
+ stateMachine.addTransition(Snapshot.State.Destroying, Event.OperationFailed, Snapshot.State.Error);
stateMachine.registerListener(new SnapshotStateListener());
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategyBase.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategyBase.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategyBase.java
index 70c30a0..fa0006a 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategyBase.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategyBase.java
@@ -9,9 +9,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotStrategy;
public abstract class SnapshotStrategyBase implements SnapshotStrategy {
@Inject
SnapshotService snapshotSvr;
- //the default strategy is:
- //create snapshot,
- //backup, then delete snapshot on primary storage
+
@Override
public SnapshotInfo takeSnapshot(SnapshotInfo snapshot) {
return snapshotSvr.takeSnapshot(snapshot).getSnashot();
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java
index 0fa044b..df2264a 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java
@@ -27,6 +27,7 @@ import com.cloud.storage.DataStoreRole;
import com.cloud.storage.Snapshot;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.VolumeVO;
+import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.snapshot.SnapshotManager;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.exception.CloudRuntimeException;
@@ -48,6 +49,8 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase {
@Inject
ConfigurationDao configDao;
@Inject
+ SnapshotDao snapshotDao;
+ @Inject
SnapshotDataFactory snapshotDataFactory;
@Override
@@ -114,82 +117,72 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase {
snapshot.addPayload(fullBackup);
return this.snapshotSvr.backupSnapshot(snapshot);
}
+
+ protected void deleteSnapshotChain(SnapshotInfo snapshot) {
+ while(snapshot != null) {
+ SnapshotInfo child = snapshot.getChild();
+ SnapshotInfo parent = snapshot.getParent();
+ if (child == null) {
+ if (!parent.getPath().equalsIgnoreCase(snapshot.getPath())) {
+ this.snapshotSvr.deleteSnapshot(snapshot);
+ snapshot = parent;
+ continue;
+ }
+ break;
+ } else {
+ break;
+ }
+ }
+ }
@Override
- public boolean deleteSnapshot(SnapshotInfo snapshot) {
- Long snapshotId = snapshot.getId();
- SnapshotObject snapObj = (SnapshotObject)snapshot;
-
- if (!Snapshot.State.BackedUp.equals(snapshot.getState()) || !Snapshot) {
+ public boolean deleteSnapshot(Long snapshotId) {
+ SnapshotVO snapshotVO = snapshotDao.findById(snapshotId);
+ if (snapshotVO.getState() == Snapshot.State.Destroyed) {
+ return true;
+ }
+
+ if (!Snapshot.State.BackedUp.equals(snapshotVO.getState())) {
throw new InvalidParameterValueException("Can't delete snapshotshot " + snapshotId + " due to it is not in BackedUp Status");
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Calling deleteSnapshot for snapshotId: " + snapshotId);
}
- SnapshotVO lastSnapshot = null;
- if (snapshot.getPrevSnapshotId() != null) {
- List<SnapshotVO> snaps = _snapshotDao.listByBackupUuid(snapshot.getVolumeId(), snapshot.getBackupSnapshotId());
- if (snaps != null && snaps.size() > 1) {
- snapshot.setBackupSnapshotId(null);
- SnapshotVO snapshotVO = this._snapshotDao.findById(snapshotId);
- _snapshotDao.update(snapshot.getId(), snapshotVO);
- }
- }
-
- _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);
- }
+
+
+ //firt mark the snapshot as destroyed, so that ui can't see it, but we may not destroy the snapshot on the storage, as other snaphosts may depend on it.
+ SnapshotInfo snapshotOnPrimary = this.snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Primary);
+ SnapshotObject obj = (SnapshotObject)snapshotOnPrimary;
+ try {
+ obj.processEvent(Snapshot.Event.DestroyRequested);
+ } catch (NoTransitionException e) {
+ s_logger.debug("Failed to destroy snapshot: " + e.toString());
+ return false;
+ }
+
+ try {
+ if (snapshotOnPrimary != null) {
+ deleteSnapshotChain(snapshotOnPrimary);
+ }
+
+ SnapshotInfo snapshotOnImage = this.snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Image);
+ if (snapshotOnImage != null) {
+ deleteSnapshotChain(snapshotOnImage);
+ }
+
+ obj.processEvent(Snapshot.Event.OperationSucceeded);
+ } catch (Exception e) {
+ s_logger.debug("Failed to delete snapshot: " + e.toString());
+ try {
+ obj.processEvent(Snapshot.Event.OperationFailed);
+ } catch (NoTransitionException e1) {
+ s_logger.debug("Failed to change snapshot state: " + e.toString());
+ }
}
+
return true;
}
-
- @Override
- public boolean canHandle(SnapshotInfo snapshot) {
- if (snapshot.getHypervisorType() == HypervisorType.XenServer) {
- return true;
- } else {
- return false;
- }
- }
@Override
public SnapshotInfo takeSnapshot(SnapshotInfo snapshot) {
@@ -197,4 +190,13 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase {
//TODO: add async
return this.backupSnapshot(snapshot);
}
+
+ @Override
+ public boolean canHandle(Snapshot snapshot) {
+ if (snapshot.getHypervisorType() == HypervisorType.XenServer) {
+ return true;
+ } else {
+ return false;
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java
index 7ff22c6..3b01475 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java
@@ -84,33 +84,17 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager {
public ObjectInDataStoreManagerImpl() {
stateMachines = new StateMachine2<State, Event, DataObjectInStore>();
- stateMachines.addTransition(State.Allocated, Event.CreateRequested,
+ stateMachines.addTransition(State.Allocated, Event.CreateOnlyRequested,
State.Creating);
- stateMachines.addTransition(State.Creating, Event.OperationSuccessed,
- State.Created);
stateMachines.addTransition(State.Creating, Event.OperationFailed,
- State.Failed);
- stateMachines.addTransition(State.Failed, Event.CreateRequested,
- State.Creating);
- stateMachines.addTransition(State.Ready, Event.DestroyRequested,
- State.Destroying);
- stateMachines.addTransition(State.Destroying, Event.OperationSuccessed,
- State.Destroyed);
- stateMachines.addTransition(State.Destroying, Event.OperationFailed,
- State.Destroying);
- stateMachines.addTransition(State.Destroying, Event.DestroyRequested,
- State.Destroying);
- stateMachines.addTransition(State.Created, Event.CopyingRequested,
+ State.Allocated);
+ stateMachines.addTransition(State.Creating, Event.OperationSuccessed,
+ State.Ready);
+ stateMachines.addTransition(State.Ready, Event.CopyingRequested,
State.Copying);
- stateMachines.addTransition(State.Copying, Event.OperationFailed,
- State.Created);
stateMachines.addTransition(State.Copying, Event.OperationSuccessed,
State.Ready);
- stateMachines.addTransition(State.Allocated, Event.CreateOnlyRequested,
- State.Creating2);
- stateMachines.addTransition(State.Creating2, Event.OperationFailed,
- State.Allocated);
- stateMachines.addTransition(State.Creating2, Event.OperationSuccessed,
+ stateMachines.addTransition(State.Copying, Event.OperationFailed,
State.Ready);
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java b/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java
index e95a1f3..11babcb 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java
@@ -149,4 +149,10 @@ public class SnapshotDataStoreDaoImpl extends GenericDaoBase<SnapshotDataStoreVO
sc.setParameters("store_role", role);
return findOneBy(sc);
}
+
+ @Override
+ public SnapshotDataStoreVO findByStoreSnapshot(long storeId, long snapshotId, boolean lock) {
+ // TODO Auto-generated method stub
+ return null;
+ }
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotEntityImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotEntityImpl.java b/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotEntityImpl.java
index 0a91186..a59e594 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotEntityImpl.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotEntityImpl.java
@@ -88,12 +88,6 @@ public class SnapshotEntityImpl implements SnapshotEntity {
}
@Override
- public String getPath() {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
public String getName() {
// TODO Auto-generated method stub
return null;
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
----------------------------------------------------------------------
diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
index 41e3560..567905d 100644
--- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
+++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
@@ -46,6 +46,8 @@ import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.utils.fsm.StateMachine2;
import com.cloud.utils.storage.encoding.EncodingType;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.dao.VMInstanceDao;
public class VolumeObject implements VolumeInfo {
private static final Logger s_logger = Logger.getLogger(VolumeObject.class);
@@ -58,6 +60,8 @@ public class VolumeObject implements VolumeInfo {
VolumeDataStoreDao volumeStoreDao;
@Inject
ObjectInDataStoreManager ojbectInStoreMgr;
+ @Inject
+ VMInstanceDao vmInstanceDao;
private Object payload;
public VolumeObject() {
@@ -74,6 +78,19 @@ public class VolumeObject implements VolumeInfo {
vo.configure(dataStore, volumeVO);
return vo;
}
+
+ public String getAttachedVmName() {
+ Long vmId = this.volumeVO.getInstanceId();
+ if (vmId != null) {
+ VMInstanceVO vm = vmInstanceDao.findById(vmId);
+
+ if (vm == null) {
+ return null;
+ }
+ return vm.getInstanceName();
+ }
+ return null;
+ }
@Override
public String getUuid() {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
index e5876b2..b57333e 100644
--- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
+++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
@@ -408,15 +408,17 @@ public class VolumeServiceImpl implements VolumeService {
private final AsyncCallFuture<VolumeApiResult> future;
private final DataStore primaryStore;
private final DataObject templateOnStore;
+ private final SnapshotInfo snapshot;
public CreateVolumeFromBaseImageContext(AsyncCompletionCallback<T> callback, VolumeObject vo,
DataStore primaryStore,
DataObject templateOnStore,
- AsyncCallFuture<VolumeApiResult> future) {
+ AsyncCallFuture<VolumeApiResult> future, SnapshotInfo snapshot) {
super(callback);
this.vo = vo;
this.future = future;
this.primaryStore = primaryStore;
this.templateOnStore = templateOnStore;
+ this.snapshot = snapshot;
}
@@ -428,7 +430,7 @@ public class VolumeServiceImpl implements VolumeService {
@DB
protected void createVolumeFromBaseImageAsync(VolumeInfo volume, DataObject templateOnPrimaryStore, PrimaryDataStore pd, AsyncCallFuture<VolumeApiResult> future) {
VolumeObject vo = (VolumeObject)volume;
- CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null, vo, pd, templateOnPrimaryStore, future);
+ CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null, vo, pd, templateOnPrimaryStore, future, null);
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
caller.setCallback(caller.getTarget().createVolumeFromBaseImageCallBack(null, null))
.setContext(context);
@@ -497,8 +499,9 @@ public class VolumeServiceImpl implements VolumeService {
try {
DataObject volumeOnStore = store.create(volume);
volume.processEvent(Event.CreateOnlyRequested);
+ snapshot.processEvent(Event.CopyingRequested);
CreateVolumeFromBaseImageContext<VolumeApiResult> context = new CreateVolumeFromBaseImageContext<VolumeApiResult>(null,
- (VolumeObject)volume, store, volumeOnStore, future);
+ (VolumeObject)volume, store, volumeOnStore, future, snapshot);
AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
caller.setCallback(caller.getTarget().createVolumeFromSnapshotCallback(null, null))
.setContext(context);
@@ -517,6 +520,7 @@ public class VolumeServiceImpl implements VolumeService {
CreateVolumeFromBaseImageContext<VolumeApiResult> context) {
CopyCommandResult result = callback.getResult();
VolumeInfo volume = context.vo;
+ SnapshotInfo snapshot = context.snapshot;
VolumeApiResult apiResult = new VolumeApiResult(volume);
Event event = null;
if (result.isFailed()) {
@@ -528,6 +532,7 @@ public class VolumeServiceImpl implements VolumeService {
try {
volume.processEvent(event);
+ snapshot.processEvent(event);
} catch (Exception e) {
s_logger.debug("create volume from snapshot failed", e);
apiResult.setResult(e.toString());
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
index 046827d..cdc8da9 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
@@ -3620,7 +3620,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
return false;
}
- private void swiftBackupSnapshot(Connection conn, SwiftTO swift, String srUuid, String snapshotUuid, String container, Boolean isISCSI, int wait) {
+ public void swiftBackupSnapshot(Connection conn, SwiftTO swift, String srUuid, String snapshotUuid, String container, Boolean isISCSI, int wait) {
String lfilename;
String ldir;
if ( isISCSI ) {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/2f689171/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java
index 98527a9..8d76241 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java
@@ -18,12 +18,20 @@
*/
package com.cloud.hypervisor.xen.resource;
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -43,6 +51,7 @@ import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol;
import org.apache.cloudstack.storage.to.ImageStoreTO;
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
+import org.apache.cloudstack.storage.to.SnapshotObjectTO;
import org.apache.cloudstack.storage.to.TemplateObjectTO;
import org.apache.cloudstack.storage.to.VolumeObjectTO;
import org.apache.http.HttpEntity;
@@ -54,18 +63,25 @@ import org.apache.log4j.Logger;
import org.apache.xmlrpc.XmlRpcException;
import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.BackupSnapshotAnswer;
import com.cloud.agent.api.Command;
+import com.cloud.agent.api.ManageSnapshotAnswer;
+import com.cloud.agent.api.ManageSnapshotCommand;
import com.cloud.agent.api.storage.CopyVolumeAnswer;
import com.cloud.agent.api.storage.CreateAnswer;
import com.cloud.agent.api.storage.DeleteVolumeCommand;
import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
import com.cloud.agent.api.to.DataStoreTO;
import com.cloud.agent.api.to.NfsTO;
+import com.cloud.agent.api.to.S3TO;
import com.cloud.agent.api.to.StorageFilerTO;
+import com.cloud.agent.api.to.SwiftTO;
import com.cloud.agent.api.to.VolumeTO;
import com.cloud.exception.InternalErrorException;
import com.cloud.hypervisor.xen.resource.CitrixResourceBase.SRType;
import com.cloud.storage.DataStoreRole;
+import com.cloud.utils.S3Utils;
+import com.cloud.utils.StringUtils;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.storage.encoding.DecodedDataObject;
import com.cloud.utils.storage.encoding.DecodedDataStore;
@@ -80,8 +96,6 @@ import com.xensource.xenapi.Types.BadServerResponse;
import com.xensource.xenapi.Types.XenAPIException;
import com.xensource.xenapi.VDI;
-import edu.emory.mathcs.backport.java.util.Arrays;
-
public class XenServerStorageResource {
private static final Logger s_logger = Logger.getLogger(XenServerStorageResource.class);
protected CitrixResourceBase hypervisorResource;
@@ -146,12 +160,62 @@ public class XenServerStorageResource {
return new CreateObjectAnswer(cmd, templateUrl, size);*/
return null;
}
+
+ protected CreateObjectAnswer createSnapshot(SnapshotObjectTO snapshotTO) {
+ Connection conn = hypervisorResource.getConnection();
+ long snapshotId = snapshotTO.getId();
+ String snapshotName = snapshotTO.getName();
+ String details = "create snapshot operation Failed for snapshotId: " + snapshotId;
+ String snapshotUUID = null;
+
+ try {
+ String volumeUUID = snapshotTO.getVolume().getPath();
+ VDI volume = VDI.getByUuid(conn, volumeUUID);
+
+ VDI snapshot = volume.snapshot(conn, new HashMap<String, String>());
+
+ if (snapshotName != null) {
+ snapshot.setNameLabel(conn, snapshotName);
+ }
+
+ snapshotUUID = snapshot.getUuid(conn);
+ String preSnapshotUUID = snapshotTO.getPath();
+ //check if it is a empty snapshot
+ if( preSnapshotUUID != null) {
+ SR sr = volume.getSR(conn);
+ String srUUID = sr.getUuid(conn);
+ String type = sr.getType(conn);
+ Boolean isISCSI = IsISCSI(type);
+ String snapshotParentUUID = getVhdParent(conn, srUUID, snapshotUUID, isISCSI);
+
+ String preSnapshotParentUUID = getVhdParent(conn, srUUID, preSnapshotUUID, isISCSI);
+ if( snapshotParentUUID != null && snapshotParentUUID.equals(preSnapshotParentUUID)) {
+ // this is empty snapshot, remove it
+ snapshot.destroy(conn);
+ snapshotUUID = preSnapshotUUID;
+ }
+ }
+ SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
+ newSnapshot.setPath(snapshotUUID);
+ return new CreateObjectAnswer(newSnapshot);
+ } catch (XenAPIException e) {
+ details += ", reason: " + e.toString();
+ s_logger.warn(details, e);
+ } catch (Exception e) {
+ details += ", reason: " + e.toString();
+ s_logger.warn(details, e);
+ }
+
+ return new CreateObjectAnswer(details);
+ }
protected CreateObjectAnswer execute(CreateObjectCommand cmd) {
DataTO data = cmd.getData();
try {
if (data.getObjectType() == DataObjectType.VOLUME) {
return createVolume(data);
- }
+ } else if (data.getObjectType() == DataObjectType.SNAPSHOT) {
+ return createSnapshot((SnapshotObjectTO)data);
+ }
return new CreateObjectAnswer("not supported type");
} catch (Exception e) {
s_logger.debug("Failed to create object: " + data.getObjectType() + ": " + e.toString());
@@ -821,6 +885,330 @@ public class XenServerStorageResource {
return new CopyCmdAnswer("unsupported protocol");
}
+ boolean swiftUpload(Connection conn, SwiftTO swift, String container, String ldir, String lfilename, Boolean isISCSI, int wait) {
+ String result = null;
+ try {
+ result = hypervisorResource.callHostPluginAsync(conn, "swiftxen", "swift", wait,
+ "op", "upload", "url", swift.getUrl(), "account", swift.getAccount(),
+ "username", swift.getUserName(), "key", swift.getKey(), "container", container,
+ "ldir", ldir, "lfilename", lfilename, "isISCSI", isISCSI.toString());
+ if( result != null && result.equals("true")) {
+ return true;
+ }
+ } catch (Exception e) {
+ s_logger.warn("swift upload failed due to " + e.toString(), e);
+ }
+ return false;
+ }
+
+ protected String deleteSnapshotBackup(Connection conn, String path, String secondaryStorageMountPath, String backupUUID) {
+
+ // If anybody modifies the formatting below again, I'll skin them
+ String result = hypervisorResource.callHostPlugin(conn, "vmopsSnapshot", "deleteSnapshotBackup", "backupUUID", backupUUID, "path", path, "secondaryStorageMountPath", secondaryStorageMountPath);
+
+ return result;
+ }
+
+ public void swiftBackupSnapshot(Connection conn, SwiftTO swift, String srUuid, String snapshotUuid, String container, Boolean isISCSI, int wait) {
+ String lfilename;
+ String ldir;
+ if ( isISCSI ) {
+ ldir = "/dev/VG_XenStorage-" + srUuid;
+ lfilename = "VHD-" + snapshotUuid;
+ } else {
+ ldir = "/var/run/sr-mount/" + srUuid;
+ lfilename = snapshotUuid + ".vhd";
+ }
+ swiftUpload(conn, swift, container, ldir, lfilename, isISCSI, wait);
+ }
+
+ private static List<String> serializeProperties(final Object object,
+ final Class<?> propertySet) {
+
+ assert object != null;
+ assert propertySet != null;
+ assert propertySet.isAssignableFrom(object.getClass());
+
+ try {
+
+ final BeanInfo beanInfo = Introspector.getBeanInfo(propertySet);
+ final PropertyDescriptor[] descriptors = beanInfo
+ .getPropertyDescriptors();
+
+ final List<String> serializedProperties = new ArrayList<String>();
+ for (final PropertyDescriptor descriptor : descriptors) {
+
+ serializedProperties.add(descriptor.getName());
+ final Object value = descriptor.getReadMethod().invoke(object);
+ serializedProperties.add(value != null ? value.toString()
+ : "null");
+
+ }
+
+ return Collections.unmodifiableList(serializedProperties);
+
+ } catch (IntrospectionException e) {
+ s_logger.warn(
+ "Ignored IntrospectionException when serializing class "
+ + object.getClass().getCanonicalName(), e);
+ } catch (IllegalArgumentException e) {
+ s_logger.warn(
+ "Ignored IllegalArgumentException when serializing class "
+ + object.getClass().getCanonicalName(), e);
+ } catch (IllegalAccessException e) {
+ s_logger.warn(
+ "Ignored IllegalAccessException when serializing class "
+ + object.getClass().getCanonicalName(), e);
+ } catch (InvocationTargetException e) {
+ s_logger.warn(
+ "Ignored InvocationTargetException when serializing class "
+ + object.getClass().getCanonicalName(), e);
+ }
+
+ return Collections.emptyList();
+
+ }
+
+ private boolean backupSnapshotToS3(final Connection connection,
+ final S3TO s3, final String srUuid, final String snapshotUuid,
+ final Boolean iSCSIFlag, final int wait) {
+
+ final String filename = iSCSIFlag ? "VHD-" + snapshotUuid
+ : snapshotUuid + ".vhd";
+ final String dir = (iSCSIFlag ? "/dev/VG_XenStorage-"
+ : "/var/run/sr-mount/") + srUuid;
+ final String key = StringUtils.join("/", "snapshots", snapshotUuid);
+
+ try {
+
+ final List<String> parameters = new ArrayList<String>(
+ serializeProperties(s3, S3Utils.ClientOptions.class));
+ parameters.addAll(Arrays.asList("operation", "put", "directory",
+ dir, "filename", filename, "iSCSIFlag",
+ iSCSIFlag.toString(), "key", key));
+ final String result = hypervisorResource.callHostPluginAsync(connection, "s3xen",
+ "s3", wait,
+ parameters.toArray(new String[parameters.size()]));
+
+ if (result != null && result.equals("true")) {
+ return true;
+ }
+
+ } catch (Exception e) {
+ s_logger.error(String.format(
+ "S3 upload failed of snapshot %1$s due to %2$s.",
+ snapshotUuid, e.toString()), e);
+ }
+
+ return false;
+
+ }
+
+ protected String backupSnapshot(Connection conn, String primaryStorageSRUuid, String path, String secondaryStorageMountPath, String snapshotUuid, String prevBackupUuid, Boolean isISCSI, int wait) {
+ String backupSnapshotUuid = null;
+
+ if (prevBackupUuid == null) {
+ prevBackupUuid = "";
+ }
+
+ // Each argument is put in a separate line for readability.
+ // Using more lines does not harm the environment.
+ String backupUuid = UUID.randomUUID().toString();
+ String results = hypervisorResource.callHostPluginAsync(conn, "vmopsSnapshot", "backupSnapshot", wait,
+ "primaryStorageSRUuid", primaryStorageSRUuid, "path", path, "secondaryStorageMountPath", secondaryStorageMountPath,
+ "snapshotUuid", snapshotUuid, "prevBackupUuid", prevBackupUuid, "backupUuid", backupUuid, "isISCSI", isISCSI.toString());
+ String errMsg = null;
+ if (results == null || results.isEmpty()) {
+ errMsg = "Could not copy backupUuid: " + backupSnapshotUuid
+ + " from primary storage " + primaryStorageSRUuid + " to secondary storage "
+ + secondaryStorageMountPath + " due to null";
+ } else {
+
+ String[] tmp = results.split("#");
+ String status = tmp[0];
+ backupSnapshotUuid = tmp[1];
+ // status == "1" if and only if backupSnapshotUuid != null
+ // So we don't rely on status value but return backupSnapshotUuid as an
+ // indicator of success.
+ if (status != null && status.equalsIgnoreCase("1") && backupSnapshotUuid != null) {
+ s_logger.debug("Successfully copied backupUuid: " + backupSnapshotUuid
+ + " to secondary storage");
+ return backupSnapshotUuid;
+ } else {
+ errMsg = "Could not copy backupUuid: " + backupSnapshotUuid
+ + " from primary storage " + primaryStorageSRUuid + " to secondary storage "
+ + secondaryStorageMountPath + " due to " + tmp[1];
+ }
+ }
+ String source = backupUuid + ".vhd";
+ hypervisorResource.killCopyProcess(conn, source);
+ s_logger.warn(errMsg);
+ return null;
+
+ }
+
+ private boolean destroySnapshotOnPrimaryStorageExceptThis(Connection conn, String volumeUuid, String avoidSnapshotUuid){
+ try {
+ VDI volume = getVDIbyUuid(conn, volumeUuid);
+ if (volume == null) {
+ throw new InternalErrorException("Could not destroy snapshot on volume " + volumeUuid + " due to can not find it");
+ }
+ Set<VDI> snapshots = volume.getSnapshots(conn);
+ for( VDI snapshot : snapshots ) {
+ try {
+ if(! snapshot.getUuid(conn).equals(avoidSnapshotUuid)) {
+ snapshot.destroy(conn);
+ }
+ } catch (Exception e) {
+ String msg = "Destroying snapshot: " + snapshot+ " on primary storage failed due to " + e.toString();
+ s_logger.warn(msg, e);
+ }
+ }
+ s_logger.debug("Successfully destroyed snapshot on volume: " + volumeUuid + " execept this current snapshot "+ avoidSnapshotUuid );
+ return true;
+ } catch (XenAPIException e) {
+ String msg = "Destroying snapshot on volume: " + volumeUuid + " execept this current snapshot "+ avoidSnapshotUuid + " failed due to " + e.toString();
+ s_logger.error(msg, e);
+ } catch (Exception e) {
+ String msg = "Destroying snapshot on volume: " + volumeUuid + " execept this current snapshot "+ avoidSnapshotUuid + " failed due to " + e.toString();
+ s_logger.warn(msg, e);
+ }
+
+ return false;
+ }
+
+ protected Answer backupSnasphot(DataTO srcData, DataTO destData, DataTO cacheData, int wait) {
+ Connection conn = hypervisorResource.getConnection();
+ PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)srcData.getDataStore();
+ String primaryStorageNameLabel = primaryStore.getUuid();
+ String secondaryStorageUrl = null;
+ NfsTO cacheStore = null;
+ String destPath = null;
+ if (cacheData != null) {
+ cacheStore = (NfsTO)cacheData.getDataStore();
+ secondaryStorageUrl = cacheStore.getUrl();
+ destPath = cacheData.getPath();
+ } else {
+ cacheStore = (NfsTO)destData.getDataStore();
+ secondaryStorageUrl = cacheStore.getUrl();
+ destPath = destData.getPath();
+ }
+
+ SnapshotObjectTO snapshotTO = (SnapshotObjectTO)srcData;
+ SnapshotObjectTO snapshotOnImage = (SnapshotObjectTO)destData;
+ String snapshotUuid = snapshotTO.getPath();
+
+ String prevBackupUuid = snapshotOnImage.getParentSnapshotPath();
+ String prevSnapshotUuid = snapshotTO.getParentSnapshotPath();
+
+ // By default assume failure
+ String details = null;
+ String snapshotBackupUuid = null;
+ boolean fullbackup = true;
+ try {
+ SR primaryStorageSR = hypervisorResource.getSRByNameLabelandHost(conn, primaryStorageNameLabel);
+ if (primaryStorageSR == null) {
+ throw new InternalErrorException("Could not backup snapshot because the primary Storage SR could not be created from the name label: " + primaryStorageNameLabel);
+ }
+ String psUuid = primaryStorageSR.getUuid(conn);
+ Boolean isISCSI = IsISCSI(primaryStorageSR.getType(conn));
+
+ VDI snapshotVdi = getVDIbyUuid(conn, snapshotUuid);
+ String snapshotPaUuid = null;
+ if ( prevBackupUuid != null ) {
+ try {
+ snapshotPaUuid = getVhdParent(conn, psUuid, snapshotUuid, isISCSI);
+ if( snapshotPaUuid != null ) {
+ String snashotPaPaPaUuid = getVhdParent(conn, psUuid, snapshotPaUuid, isISCSI);
+ String prevSnashotPaUuid = getVhdParent(conn, psUuid, prevSnapshotUuid, isISCSI);
+ if (snashotPaPaPaUuid != null && prevSnashotPaUuid!= null && prevSnashotPaUuid.equals(snashotPaPaPaUuid)) {
+ fullbackup = false;
+ }
+ }
+ } catch (Exception e) {
+ }
+ }
+
+ URI uri = new URI(secondaryStorageUrl);
+ String secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
+ DataStoreTO destStore = destData.getDataStore();
+ String folder = destPath;
+ if (fullbackup) {
+ // the first snapshot is always a full snapshot
+
+ if( !hypervisorResource.createSecondaryStorageFolder(conn, secondaryStorageMountPath, folder)) {
+ details = " Filed to create folder " + folder + " in secondary storage";
+ s_logger.warn(details);
+ return new CopyCmdAnswer(details);
+ }
+ String snapshotMountpoint = secondaryStorageUrl + "/" + folder;
+ SR snapshotSr = null;
+ try {
+ snapshotSr = hypervisorResource.createNfsSRbyURI(conn, new URI(snapshotMountpoint), false);
+ VDI backedVdi = hypervisorResource.cloudVDIcopy(conn, snapshotVdi, snapshotSr, wait);
+ snapshotBackupUuid = backedVdi.getUuid(conn);
+
+ if( destStore instanceof SwiftTO) {
+ try {
+ hypervisorResource.swiftBackupSnapshot(conn, (SwiftTO)destStore, snapshotSr.getUuid(conn), snapshotBackupUuid, "S-" + snapshotTO.getVolume().getVolumeId().toString(), false, wait);
+ snapshotBackupUuid = snapshotBackupUuid + ".vhd";
+ } finally {
+ deleteSnapshotBackup(conn, folder, secondaryStorageMountPath, snapshotBackupUuid);
+ }
+ } else if (destStore instanceof S3TO) {
+ try {
+ backupSnapshotToS3(conn, (S3TO)destStore, snapshotSr.getUuid(conn), snapshotBackupUuid, isISCSI, wait);
+ snapshotBackupUuid = snapshotBackupUuid + ".vhd";
+ } finally {
+ deleteSnapshotBackup(conn, folder, secondaryStorageMountPath, snapshotBackupUuid);
+ }
+ }
+
+ } finally {
+ if( snapshotSr != null) {
+ hypervisorResource.removeSR(conn, snapshotSr);
+ }
+ }
+ } else {
+ String primaryStorageSRUuid = primaryStorageSR.getUuid(conn);
+ if( destStore instanceof SwiftTO ) {
+ swiftBackupSnapshot(conn, (SwiftTO)destStore, primaryStorageSRUuid, snapshotPaUuid, "S-" + snapshotTO.getVolume().getVolumeId().toString(), isISCSI, wait);
+ if ( isISCSI ) {
+ snapshotBackupUuid = "VHD-" + snapshotPaUuid;
+ } else {
+ snapshotBackupUuid = snapshotPaUuid + ".vhd";
+ }
+
+ } else if (destStore instanceof S3TO ) {
+ backupSnapshotToS3(conn, (S3TO)destStore, primaryStorageSRUuid, snapshotPaUuid, isISCSI, wait);
+ } else {
+ snapshotBackupUuid = backupSnapshot(conn, primaryStorageSRUuid, folder + File.separator + UUID.nameUUIDFromBytes(secondaryStorageMountPath.getBytes())
+ , secondaryStorageMountPath, snapshotUuid, prevBackupUuid, isISCSI, wait);
+
+ }
+ }
+ String volumeUuid = snapshotTO.getVolume().getPath();
+ destroySnapshotOnPrimaryStorageExceptThis(conn, volumeUuid, snapshotUuid);
+
+ SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
+ newSnapshot.setPath(snapshotBackupUuid);
+ if (fullbackup) {
+ newSnapshot.setParentSnapshotPath(null);
+ } else {
+ newSnapshot.setParentSnapshotPath(prevBackupUuid);
+ }
+ return new CopyCmdAnswer(newSnapshot);
+ } catch (XenAPIException e) {
+ details = "BackupSnapshot Failed due to " + e.toString();
+ s_logger.warn(details, e);
+ } catch (Exception e) {
+ details = "BackupSnapshot Failed due to " + e.getMessage();
+ s_logger.warn(details, e);
+ }
+
+ return new CopyCmdAnswer(details);
+ }
+
protected Answer execute(CopyCommand cmd) {
DataTO srcData = cmd.getSrcTO();
DataTO destData = cmd.getDestTO();
@@ -838,6 +1226,9 @@ public class XenServerStorageResource {
return copyVolumeFromImageCacheToPrimary(srcData, destData, cmd.getWait());
} else if (srcData.getObjectType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
return copyVolumeFromPrimaryToSecondary(srcData, destData, cmd.getWait());
+ } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
+ DataTO cacheData = cmd.getCacheTO();
+ return backupSnasphot(srcData, destData, cacheData, cmd.getWait());
}
return new Answer(cmd, false, "not implemented yet");