cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mtutkow...@apache.org
Subject git commit: updated refs/heads/master to e70dde0
Date Wed, 15 Oct 2014 04:05:09 GMT
Repository: cloudstack
Updated Branches:
  refs/heads/master 340bcc60c -> e70dde09c


Implementing snapshot-strategy support for reverting a volume to a snapshot


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/e70dde09
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/e70dde09
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/e70dde09

Branch: refs/heads/master
Commit: e70dde09c919b4c64566dd84484b67208b2fd321
Parents: 340bcc6
Author: Mike Tutkowski <mike.tutkowski@solidfire.com>
Authored: Tue Oct 14 17:04:35 2014 -0600
Committer: Mike Tutkowski <mike.tutkowski@solidfire.com>
Committed: Tue Oct 14 22:04:18 2014 -0600

----------------------------------------------------------------------
 api/src/com/cloud/storage/Volume.java           |  5 ++
 .../snapshot/StorageSystemSnapshotStrategy.java | 85 +++++++++++++++++++-
 .../driver/SolidFirePrimaryDataStoreDriver.java | 27 ++++++-
 .../storage/datastore/util/SolidFireUtil.java   | 43 ++++++++++
 server/src/com/cloud/api/ApiResponseHelper.java | 38 ++++++++-
 5 files changed, 190 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e70dde09/api/src/com/cloud/storage/Volume.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/storage/Volume.java b/api/src/com/cloud/storage/Volume.java
index b67a395..48145a7 100755
--- a/api/src/com/cloud/storage/Volume.java
+++ b/api/src/com/cloud/storage/Volume.java
@@ -38,6 +38,7 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity,
Ba
         Ready("The volume is ready to be used."),
         Migrating("The volume is migrating to other storage pool"),
         Snapshotting("There is a snapshot created on this volume, not backed up to secondary
storage yet"),
+        Reverting("Replace the existing volume on a storage system with a snapshot of it"),
         Resizing("The volume is being resized"),
         Expunging("The volume is being expunging"),
         Expunged("The volume is being expunging"),
@@ -85,8 +86,11 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity,
Ba
             s_fsm.addTransition(Expunging, Event.OperationSucceeded, Expunged);
             s_fsm.addTransition(Expunging, Event.OperationFailed, Destroy);
             s_fsm.addTransition(Ready, Event.SnapshotRequested, Snapshotting);
+            s_fsm.addTransition(Ready, Event.RevertRequested, Reverting);
             s_fsm.addTransition(Snapshotting, Event.OperationSucceeded, Ready);
             s_fsm.addTransition(Snapshotting, Event.OperationFailed, Ready);
+            s_fsm.addTransition(Reverting, Event.OperationSucceeded, Ready);
+            s_fsm.addTransition(Reverting, Event.OperationFailed, Ready);
             s_fsm.addTransition(Ready, Event.MigrationRequested, Migrating);
             s_fsm.addTransition(Migrating, Event.OperationSucceeded, Ready);
             s_fsm.addTransition(Migrating, Event.OperationFailed, Ready);
@@ -111,6 +115,7 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity,
Ba
         UploadRequested,
         MigrationRequested,
         SnapshotRequested,
+        RevertRequested,
         DestroyRequested,
         ExpungingRequested,
         ResizeRequested;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e70dde09/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java
b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java
index 894aa5a..dc43d7d 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java
@@ -33,23 +33,35 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
 
+import com.cloud.dc.ClusterVO;
+import com.cloud.dc.dao.ClusterDao;
 import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.storage.DataStoreRole;
 import com.cloud.storage.Snapshot;
 import com.cloud.storage.SnapshotVO;
 import com.cloud.storage.Volume;
+import com.cloud.storage.Volume.Type;
 import com.cloud.storage.VolumeVO;
 import com.cloud.storage.dao.SnapshotDao;
 import com.cloud.storage.dao.VolumeDao;
+import com.cloud.uservm.UserVm;
 import com.cloud.utils.db.DB;
+import com.cloud.utils.db.EntityManager;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.fsm.NoTransitionException;
+import com.cloud.vm.VirtualMachine.State;
 
 @Component
 public class StorageSystemSnapshotStrategy extends SnapshotStrategyBase {
     private static final Logger s_logger = Logger.getLogger(StorageSystemSnapshotStrategy.class);
 
+    @Inject private ClusterDao _clusterDao;
     @Inject private DataStoreManager _dataStoreMgr;
+    @Inject private EntityManager _entityMgr;
+    @Inject private HostDao _hostDao;
     @Inject private SnapshotDao _snapshotDao;
     @Inject private SnapshotDataFactory _snapshotDataFactory;
     @Inject private SnapshotDataStoreDao _snapshotStoreDao;
@@ -121,6 +133,75 @@ public class StorageSystemSnapshotStrategy extends SnapshotStrategyBase
{
 
     @Override
     public boolean revertSnapshot(Long snapshotId) {
+        // verify the following:
+        //  if root disk, the VM cannot be running (don't allow this at all for ESX)
+        //  if data disk, the disk cannot be in the attached state
+
+        SnapshotInfo snapshotInfo = _snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Primary);
+        VolumeInfo volumeInfo = snapshotInfo.getBaseVolume();
+        VolumeVO volume = _volumeDao.findById(volumeInfo.getId());
+
+        if (volume.getVolumeType() == Type.DATADISK) {
+            if (volume.getAttached() != null) {
+                throw new CloudRuntimeException("A data disk must be in the detached state
in order to perform a revert.");
+            }
+        }
+        else if (volume.getVolumeType() == Type.ROOT) {
+            Long instanceId = volume.getInstanceId();
+            UserVm vm = _entityMgr.findById(UserVm.class, instanceId);
+
+            Long hostId = vm.getHostId();
+            HostVO hostVO = _hostDao.findById(hostId);
+            Long clusterId = hostVO.getClusterId();
+            ClusterVO clusterVO = _clusterDao.findById(clusterId);
+
+            if (clusterVO.getHypervisorType() != HypervisorType.XenServer && clusterVO.getHypervisorType()
!=  HypervisorType.KVM) {
+                throw new CloudRuntimeException("Unsupported hypervisor type for root disk
revert. Create a template from this disk and use it instead.");
+            }
+
+            if (vm.getState() != State.Stopped) {
+                throw new CloudRuntimeException("A root disk cannot be reverted unless the
VM it's attached to is in the stopped state.");
+            }
+        }
+        else {
+            throw new CloudRuntimeException("Unsupported volume type");
+        }
+
+        SnapshotVO snapshotVO = _snapshotDao.acquireInLockTable(snapshotId);
+
+        if (snapshotVO == null) {
+            throw new CloudRuntimeException("Failed to acquire lock on the following snapshot:
" + snapshotId);
+        }
+
+        try {
+            volumeInfo.stateTransit(Volume.Event.RevertRequested);
+
+            boolean result = false;
+
+            try {
+                result = snapshotSvr.revertSnapshot(snapshotId);
+            }
+            finally {
+                if (result) {
+                    volumeInfo.stateTransit(Volume.Event.OperationSucceeded);
+                }
+                else {
+                    String msg = "Failed to revert the volume to a snapshot";
+
+                    s_logger.debug(msg);
+
+                    volumeInfo.stateTransit(Volume.Event.OperationFailed);
+
+                    throw new CloudRuntimeException("Failed to revert the volume to a snapshot");
+                }
+            }
+        }
+        finally {
+            if (snapshotVO != null) {
+                _snapshotDao.releaseFromLockTable(snapshotId);
+            }
+        }
+
         return true;
     }
 
@@ -189,9 +270,9 @@ public class StorageSystemSnapshotStrategy extends SnapshotStrategyBase
{
     @Override
     public StrategyPriority canHandle(Snapshot snapshot, SnapshotOperation op) {
         long volumeId = snapshot.getVolumeId();
-        VolumeVO volume = _volumeDao.findById(volumeId);
+        VolumeVO volumeVO = _volumeDao.findById(volumeId);
 
-        long storagePoolId = volume.getPoolId();
+        long storagePoolId = volumeVO.getPoolId();
         DataStore dataStore = _dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary);
 
         Map<String, String> mapCapabilities = dataStore.getDriver().getCapabilities();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e70dde09/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java
b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java
index 946dd18..04970b7 100644
--- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java
@@ -609,8 +609,31 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver
{
     }
 
     @Override
-    public void revertSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CommandResult>
callback) {
-        throw new UnsupportedOperationException();
+    public void revertSnapshot(SnapshotInfo snapshotInfo, AsyncCompletionCallback<CommandResult>
callback) {
+        String errMsg = null;
+
+        try {
+            VolumeInfo volumeInfo = snapshotInfo.getBaseVolume();
+
+            long storagePoolId = volumeInfo.getPoolId();
+            long sfVolumeId = Long.parseLong(volumeInfo.getFolder());
+            long sfSnapshotId = getSolidFireSnapshotId(snapshotInfo.getId());
+
+            SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId,
_storagePoolDetailsDao);
+
+            SolidFireUtil.rollBackVolumeToSnapshot(sfConnection, sfVolumeId, sfSnapshotId);
+        }
+        catch (Exception ex) {
+            s_logger.debug(SolidFireUtil.LOG_PREFIX + "Failed to take CloudStack snapshot:
" + snapshotInfo.getId(), ex);
+
+            errMsg = ex.getMessage();
+        }
+
+        CommandResult result = new CommandResult();
+
+        result.setResult(errMsg);
+
+        callback.complete(result);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e70dde09/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java
b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java
index 65f3554..786f227 100644
--- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java
@@ -689,6 +689,20 @@ public class SolidFireUtil {
         executeJsonRpc(sfConnection, strSnapshotToDeleteJson);
     }
 
+    public static void rollBackVolumeToSnapshot(SolidFireConnection sfConnection, long volumeId,
long snapshotId) {
+        final Gson gson = new GsonBuilder().create();
+
+        RollbackToInitiate rollbackToInitiate = new RollbackToInitiate(volumeId, snapshotId);
+
+        String strRollbackToInitiateJson = gson.toJson(rollbackToInitiate);
+
+        String strRollbackInitiatedResultJson = executeJsonRpc(sfConnection, strRollbackToInitiateJson);
+
+        RollbackInitiatedResult rollbackInitiatedResult = gson.fromJson(strRollbackInitiatedResultJson,
RollbackInitiatedResult.class);
+
+        verifyResult(rollbackInitiatedResult.result, strRollbackInitiatedResultJson, gson);
+    }
+
     public static long createSolidFireClone(SolidFireConnection sfConnection, long lVolumeId,
String cloneName) {
         final Gson gson = new GsonBuilder().create();
 
@@ -1294,6 +1308,26 @@ public class SolidFireUtil {
     }
 
     @SuppressWarnings("unused")
+    private static final class RollbackToInitiate {
+        private final String method = "RollbackToSnapshot";
+        private final RollbackToInitiateParams params;
+
+        private RollbackToInitiate(final long lVolumeId, final long lSnapshotId) {
+            params = new RollbackToInitiateParams(lVolumeId, lSnapshotId);
+        }
+
+        private static final class RollbackToInitiateParams {
+            private long volumeID;
+            private long snapshotID;
+
+            private RollbackToInitiateParams(final long lVolumeId, final long lSnapshotId)
{
+                volumeID = lVolumeId;
+                snapshotID = lSnapshotId;
+            }
+        }
+    }
+
+    @SuppressWarnings("unused")
     private static final class CloneToCreate {
         private final String method = "CloneVolume";
         private final CloneToCreateParams params;
@@ -1539,6 +1573,15 @@ public class SolidFireUtil {
         }
     }
 
+    @SuppressWarnings("unused")
+    private static final class RollbackInitiatedResult {
+        private Result result;
+
+        private static final class Result {
+            private long snapshotID;
+        }
+    }
+
     private static final class CloneCreateResult {
         private Result result;
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e70dde09/server/src/com/cloud/api/ApiResponseHelper.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java
index f4d0293..50376d2 100755
--- a/server/src/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/com/cloud/api/ApiResponseHelper.java
@@ -138,6 +138,9 @@ import org.apache.cloudstack.api.response.VpnUsersResponse;
 import org.apache.cloudstack.api.response.ZoneResponse;
 import org.apache.cloudstack.config.Configuration;
 import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
 import org.apache.cloudstack.framework.jobs.AsyncJob;
@@ -278,6 +281,7 @@ import com.cloud.storage.UploadVO;
 import com.cloud.storage.VMTemplateVO;
 import com.cloud.storage.Volume;
 import com.cloud.storage.VolumeVO;
+import com.cloud.storage.dao.VolumeDao;
 import com.cloud.storage.snapshot.SnapshotPolicy;
 import com.cloud.storage.snapshot.SnapshotSchedule;
 import com.cloud.template.VirtualMachineTemplate;
@@ -307,13 +311,13 @@ public class ApiResponseHelper implements ResponseGenerator {
 
     private static final Logger s_logger = Logger.getLogger(ApiResponseHelper.class);
     private static final DecimalFormat s_percentFormat = new DecimalFormat("##.##");
+
     @Inject
     private EntityManager _entityMgr;
     @Inject
     private UsageService _usageSvc;
     @Inject
     NetworkModel _ntwkModel;
-
     @Inject
     protected AccountManager _accountMgr;
     @Inject
@@ -322,6 +326,10 @@ public class ApiResponseHelper implements ResponseGenerator {
     ConfigurationManager _configMgr;
     @Inject
     SnapshotDataFactory snapshotfactory;
+    @Inject
+    private VolumeDao _volumeDao;
+    @Inject
+    private DataStoreManager _dataStoreMgr;
 
     @Override
     public UserResponse createUserResponse(User user) {
@@ -459,10 +467,13 @@ public class ApiResponseHelper implements ResponseGenerator {
         snapshotResponse.setState(snapshot.getState());
 
         SnapshotInfo snapshotInfo = null;
-        if (!(snapshot instanceof SnapshotInfo)) {
-            snapshotInfo = snapshotfactory.getSnapshot(snapshot.getId(), DataStoreRole.Image);
-        } else {
+
+        if (snapshot instanceof SnapshotInfo) {
             snapshotInfo = (SnapshotInfo)snapshot;
+        } else {
+            DataStoreRole dataStoreRole = getDataStoreRole(snapshot);
+
+            snapshotInfo = snapshotfactory.getSnapshot(snapshot.getId(), dataStoreRole);
         }
 
         if (snapshotInfo == null) {
@@ -485,6 +496,25 @@ public class ApiResponseHelper implements ResponseGenerator {
         return snapshotResponse;
     }
 
+    private DataStoreRole getDataStoreRole(Snapshot snapshot) {
+        long volumeId = snapshot.getVolumeId();
+        VolumeVO volumeVO = _volumeDao.findById(volumeId);
+
+        long storagePoolId = volumeVO.getPoolId();
+        DataStore dataStore = _dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary);
+
+        Map<String, String> mapCapabilities = dataStore.getDriver().getCapabilities();
+
+        String value = mapCapabilities.get(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT.toString());
+        Boolean supportsStorageSystemSnapshots = new Boolean(value);
+
+        if (supportsStorageSystemSnapshots) {
+            return DataStoreRole.Primary;
+        }
+
+        return DataStoreRole.Image;
+    }
+
     @Override
     public VMSnapshotResponse createVMSnapshotResponse(VMSnapshot vmSnapshot) {
         VMSnapshotResponse vmSnapshotResponse = new VMSnapshotResponse();


Mime
View raw message