Repository: cloudstack
Updated Branches:
  refs/heads/master f732c7d1e -> c0a0aec0f


CLOUDSTACK-5863: revert volume snapshot for KVM/QCOW2


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

Branch: refs/heads/master
Commit: 92344c006dfa8abf4ce81e2a25839cbb762d1b17
Parents: e7ddbd4
Author: Wei Zhou <[email protected]>
Authored: Mon Aug 24 11:01:50 2015 +0200
Committer: Wei Zhou <[email protected]>
Committed: Mon Aug 24 11:01:50 2015 +0200

----------------------------------------------------------------------
 api/src/com/cloud/storage/Volume.java           |  5 ++
 .../user/snapshot/RevertSnapshotCmd.java        | 14 ++-
 .../storage/command/RevertSnapshotCommand.java  | 49 ++++++++++
 .../api/storage/PrimaryDataStoreDriver.java     |  2 +-
 .../subsystem/api/storage/SnapshotService.java  |  2 +-
 .../subsystem/api/storage/SnapshotStrategy.java |  2 +-
 .../datastore/db/SnapshotDataStoreDao.java      |  3 +
 .../snapshot/SnapshotDataFactoryImpl.java       |  5 +-
 .../storage/snapshot/SnapshotServiceImpl.java   |  8 +-
 .../storage/snapshot/SnapshotStrategyBase.java  |  4 +-
 .../snapshot/StorageSystemSnapshotStrategy.java | 54 +++++++++--
 .../snapshot/XenserverSnapshotStrategy.java     |  2 +-
 .../image/db/SnapshotDataStoreDaoImpl.java      | 14 +++
 .../LibvirtRevertSnapshotCommandWrapper.java    | 95 ++++++++++++++++++++
 .../ElastistorPrimaryDataStoreDriver.java       |  2 +-
 .../CloudStackPrimaryDataStoreDriverImpl.java   | 24 ++++-
 .../driver/NexentaPrimaryDataStoreDriver.java   |  2 +-
 .../SamplePrimaryDataStoreDriverImpl.java       |  2 +-
 .../driver/SolidFirePrimaryDataStoreDriver.java |  2 +-
 scripts/storage/qcow2/managesnapshot.sh         | 18 +++-
 .../storage/snapshot/SnapshotManagerImpl.java   | 23 ++++-
 ui/css/cloudstack3.css                          |  2 +
 ui/scripts/storage.js                           |  3 +
 23 files changed, 309 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/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 9f5f502..f70ead9 100644
--- a/api/src/com/cloud/storage/Volume.java
+++ b/api/src/com/cloud/storage/Volume.java
@@ -39,6 +39,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"),
+        RevertSnapshotting("There is a snapshot created on this volume, the 
volume is being reverting from snapshot"),
         Resizing("The volume is being resized"),
         Expunging("The volume is being expunging"),
         Expunged("The volume has been expunged"),
@@ -91,6 +92,9 @@ public interface Volume extends ControlledEntity, Identity, 
InternalIdentity, Ba
             s_fsm.addTransition(new StateMachine2.Transition<State, 
Event>(Ready, Event.SnapshotRequested, Snapshotting, null));
             s_fsm.addTransition(new StateMachine2.Transition<State, 
Event>(Snapshotting, Event.OperationSucceeded, Ready, null));
             s_fsm.addTransition(new StateMachine2.Transition<State, 
Event>(Snapshotting, Event.OperationFailed, Ready,null));
+            s_fsm.addTransition(new StateMachine2.Transition<State, 
Event>(Ready, Event.RevertSnapshotRequested, RevertSnapshotting, null));
+            s_fsm.addTransition(new StateMachine2.Transition<State, 
Event>(RevertSnapshotting, Event.OperationSucceeded, Ready, null));
+            s_fsm.addTransition(new StateMachine2.Transition<State, 
Event>(RevertSnapshotting, Event.OperationFailed, Ready,null));
             s_fsm.addTransition(new StateMachine2.Transition<State, 
Event>(Allocated, Event.MigrationCopyRequested, Creating, null));
             s_fsm.addTransition(new StateMachine2.Transition<State, 
Event>(Creating, Event.MigrationCopyFailed, Allocated, null));
             s_fsm.addTransition(new StateMachine2.Transition<State, 
Event>(Creating, Event.MigrationCopySucceeded, Ready, Arrays.asList(new 
StateMachine2.Transition.Impact[]{StateMachine2.Transition.Impact.USAGE})));
@@ -131,6 +135,7 @@ public interface Volume extends ControlledEntity, Identity, 
InternalIdentity, Ba
         MigrationCopySucceeded,
         MigrationCopyFailed,
         SnapshotRequested,
+        RevertSnapshotRequested,
         DestroyRequested,
         ExpungingRequested,
         ResizeRequested,

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/api/src/org/apache/cloudstack/api/command/user/snapshot/RevertSnapshotCmd.java
----------------------------------------------------------------------
diff --git 
a/api/src/org/apache/cloudstack/api/command/user/snapshot/RevertSnapshotCmd.java
 
b/api/src/org/apache/cloudstack/api/command/user/snapshot/RevertSnapshotCmd.java
index 0c79f81..d2ccf6a 100644
--- 
a/api/src/org/apache/cloudstack/api/command/user/snapshot/RevertSnapshotCmd.java
+++ 
b/api/src/org/apache/cloudstack/api/command/user/snapshot/RevertSnapshotCmd.java
@@ -31,25 +31,36 @@ import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.api.response.SnapshotResponse;
 import org.apache.cloudstack.api.response.SuccessResponse;
 import org.apache.cloudstack.context.CallContext;
+import org.apache.log4j.Logger;
 
 import com.cloud.event.EventTypes;
 import com.cloud.storage.Snapshot;
 import com.cloud.user.Account;
 
-@APICommand(name = "revertSnapshot", description = "revert a volume 
snapshot.", responseObject = SnapshotResponse.class, entityType = 
{Snapshot.class},
+@APICommand(name = "revertSnapshot", description = "revert a volume 
snapshot.", responseObject = SuccessResponse.class, entityType = 
{Snapshot.class},
         requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
 public class RevertSnapshotCmd extends BaseAsyncCmd {
+    public static final Logger s_logger = 
Logger.getLogger(RevertSnapshotCmd.class.getName());
     private static final String s_name = "revertsnapshotresponse";
 
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
     @ACL(accessType = AccessType.OperateEntry)
     @Parameter(name= ApiConstants.ID, type= BaseCmd.CommandType.UUID, 
entityType = SnapshotResponse.class,
             required=true, description="The ID of the snapshot")
     private Long id;
 
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
     public Long getId() {
         return id;
     }
 
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
     @Override
     public String getCommandName() {
         return s_name;
@@ -91,7 +102,6 @@ public class RevertSnapshotCmd extends BaseAsyncCmd {
         boolean result = _snapshotService.revertSnapshot(getId());
         if (result) {
             SuccessResponse response = new SuccessResponse(getCommandName());
-            response.setResponseName(getCommandName());
             setResponseObject(response);
         } else {
             throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed 
to revert snapshot");

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/core/src/org/apache/cloudstack/storage/command/RevertSnapshotCommand.java
----------------------------------------------------------------------
diff --git 
a/core/src/org/apache/cloudstack/storage/command/RevertSnapshotCommand.java 
b/core/src/org/apache/cloudstack/storage/command/RevertSnapshotCommand.java
new file mode 100644
index 0000000..1a4403b
--- /dev/null
+++ b/core/src/org/apache/cloudstack/storage/command/RevertSnapshotCommand.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cloudstack.storage.command;
+
+import org.apache.cloudstack.storage.to.SnapshotObjectTO;
+
+public final class RevertSnapshotCommand extends StorageSubSystemCommand {
+    private SnapshotObjectTO data;
+    private boolean _executeInSequence = false;
+
+    public RevertSnapshotCommand(SnapshotObjectTO data) {
+        super();
+        this.data = data;
+    }
+
+    protected RevertSnapshotCommand() {
+        super();
+    }
+
+    public SnapshotObjectTO getData() {
+        return this.data;
+    }
+
+    @Override
+    public void setExecuteInSequence(final boolean executeInSequence) {
+        _executeInSequence = executeInSequence;
+    }
+
+    @Override
+    public boolean executeInSequence() {
+        return _executeInSequence;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java
----------------------------------------------------------------------
diff --git 
a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java
 
b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java
index 5e7090d..0c6bd93 100644
--- 
a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java
+++ 
b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java
@@ -48,5 +48,5 @@ public interface PrimaryDataStoreDriver extends 
DataStoreDriver {
 
     public void takeSnapshot(SnapshotInfo snapshot, 
AsyncCompletionCallback<CreateCmdResult> callback);
 
-    public void revertSnapshot(SnapshotInfo snapshot, 
AsyncCompletionCallback<CommandResult> callback);
+    public void revertSnapshot(SnapshotInfo snapshotOnImageStore, SnapshotInfo 
snapshotOnPrimaryStore, AsyncCompletionCallback<CommandResult> callback);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotService.java
----------------------------------------------------------------------
diff --git 
a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotService.java
 
b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotService.java
index 4edeb55..322de77 100644
--- 
a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotService.java
+++ 
b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotService.java
@@ -24,7 +24,7 @@ public interface SnapshotService {
 
     boolean deleteSnapshot(SnapshotInfo snapshot);
 
-    boolean revertSnapshot(Long snapshotId);
+    boolean revertSnapshot(SnapshotInfo snapshot);
 
     void syncVolumeSnapshotsToRegionStore(long volumeId, DataStore store);
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/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 0af9b09..fbf6004 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
@@ -29,7 +29,7 @@ public interface SnapshotStrategy {
 
     boolean deleteSnapshot(Long snapshotId);
 
-    boolean revertSnapshot(Long snapshotId);
+    boolean revertSnapshot(SnapshotInfo snapshot);
 
     StrategyPriority canHandle(Snapshot snapshot, SnapshotOperation op);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/engine/schema/src/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java
----------------------------------------------------------------------
diff --git 
a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java
 
b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java
index 231b241..4b83e31 100644
--- 
a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java
+++ 
b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java
@@ -60,4 +60,7 @@ public interface SnapshotDataStoreDao extends 
GenericDao<SnapshotDataStoreVO, Lo
     SnapshotDataStoreVO findOldestSnapshotForVolume(Long volumeId, 
DataStoreRole role);
 
     void updateVolumeIds(long oldVolId, long newVolId);
+
+    SnapshotDataStoreVO findByVolume(long volumeId, DataStoreRole role);
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java
----------------------------------------------------------------------
diff --git 
a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java
 
b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java
index 16c14f3..171885e 100644
--- 
a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java
+++ 
b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java
@@ -72,7 +72,10 @@ public class SnapshotDataFactoryImpl implements 
SnapshotDataFactory {
         SnapshotVO snapshot = snapshotDao.findById(snapshotId);
         SnapshotDataStoreVO snapshotStore = 
snapshotStoreDao.findBySnapshot(snapshotId, role);
         if (snapshotStore == null) {
-            return null;
+            snapshotStore = 
snapshotStoreDao.findByVolume(snapshot.getVolumeId(), role);
+            if (snapshotStore == null) {
+                return null;
+            }
         }
         DataStore store = 
storeMgr.getDataStore(snapshotStore.getDataStoreId(), role);
         SnapshotObject so = SnapshotObject.getSnapshotObject(snapshot, store);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/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 4c76cda..a9aad0a 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
@@ -407,16 +407,16 @@ public class SnapshotServiceImpl implements 
SnapshotService {
     }
 
     @Override
-    public boolean revertSnapshot(Long snapshotId) {
-        SnapshotInfo snapshot = _snapshotFactory.getSnapshot(snapshotId, 
DataStoreRole.Primary);
-        PrimaryDataStore store = (PrimaryDataStore)snapshot.getDataStore();
+    public boolean revertSnapshot(SnapshotInfo snapshot) {
+        SnapshotInfo snapshotOnPrimaryStore = 
_snapshotFactory.getSnapshot(snapshot.getId(), DataStoreRole.Primary);
+        PrimaryDataStore store = 
(PrimaryDataStore)snapshotOnPrimaryStore.getDataStore();
 
         AsyncCallFuture<SnapshotResult> future = new 
AsyncCallFuture<SnapshotResult>();
         RevertSnapshotContext<CommandResult> context = new 
RevertSnapshotContext<CommandResult>(null, snapshot, future);
         AsyncCallbackDispatcher<SnapshotServiceImpl, CommandResult> caller = 
AsyncCallbackDispatcher.create(this);
         caller.setCallback(caller.getTarget().revertSnapshotCallback(null, 
null)).setContext(context);
 
-        ((PrimaryDataStoreDriver)store.getDriver()).revertSnapshot(snapshot, 
caller);
+        ((PrimaryDataStoreDriver)store.getDriver()).revertSnapshot(snapshot, 
snapshotOnPrimaryStore, caller);
 
         SnapshotResult result = null;
         try {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/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 6db8343..b08a837 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
@@ -37,7 +37,7 @@ public abstract class SnapshotStrategyBase implements 
SnapshotStrategy {
     }
 
     @Override
-    public boolean revertSnapshot(Long snapshotId) {
-        return snapshotSvr.revertSnapshot(snapshotId);
+    public boolean revertSnapshot(SnapshotInfo snapshot) {
+        return snapshotSvr.revertSnapshot(snapshot);
     }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/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 deec7fe..2c71525 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
@@ -35,6 +35,7 @@ import 
org.apache.cloudstack.engine.subsystem.api.storage.SnapshotResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService;
+import 
org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
 import org.apache.cloudstack.storage.command.SnapshotAndCopyAnswer;
 import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
@@ -56,6 +57,8 @@ import com.cloud.storage.DataStoreRole;
 import com.cloud.storage.Snapshot;
 import com.cloud.storage.SnapshotVO;
 import com.cloud.storage.Storage.ImageFormat;
+import com.cloud.storage.StoragePool;
+import com.cloud.storage.StoragePoolStatus;
 import com.cloud.storage.Volume;
 import com.cloud.storage.VolumeVO;
 import com.cloud.storage.dao.SnapshotDao;
@@ -153,8 +156,44 @@ public class StorageSystemSnapshotStrategy extends 
SnapshotStrategyBase {
     }
 
     @Override
-    public boolean revertSnapshot(Long snapshotId) {
-        throw new UnsupportedOperationException("Reverting not supported. 
Create a template or volume based on the snapshot instead.");
+    public boolean revertSnapshot(SnapshotInfo snapshot) {
+        if (canHandle(snapshot,SnapshotOperation.REVERT) == 
StrategyPriority.CANT_HANDLE) {
+            throw new UnsupportedOperationException("Reverting not supported. 
Create a template or volume based on the snapshot instead.");
+        }
+
+        SnapshotVO snapshotVO = 
_snapshotDao.acquireInLockTable(snapshot.getId());
+        if (snapshotVO == null) {
+            throw new CloudRuntimeException("Failed to get lock on snapshot:" 
+ snapshot.getId());
+        }
+
+        try {
+            VolumeInfo volumeInfo = snapshot.getBaseVolume();
+            StoragePool store = (StoragePool)volumeInfo.getDataStore();
+            if (store != null && store.getStatus() != StoragePoolStatus.Up) {
+                snapshot.processEvent(Event.OperationFailed);
+                throw new CloudRuntimeException("store is not in up state");
+            }
+            volumeInfo.stateTransit(Volume.Event.RevertSnapshotRequested);
+            boolean result = false;
+            try {
+                result =  snapshotSvr.revertSnapshot(snapshot);
+                if (! result) {
+                    s_logger.debug("Failed to revert snapshot: " + 
snapshot.getId());
+                    throw new CloudRuntimeException("Failed to revert 
snapshot: " + snapshot.getId());
+                }
+            } finally {
+                if (result) {
+                    volumeInfo.stateTransit(Volume.Event.OperationSucceeded);
+                } else {
+                    volumeInfo.stateTransit(Volume.Event.OperationFailed);
+                }
+            }
+            return result;
+        } finally {
+            if (snapshotVO != null) {
+                _snapshotDao.releaseFromLockTable(snapshot.getId());
+            }
+        }
     }
 
     @Override
@@ -401,10 +440,6 @@ public class StorageSystemSnapshotStrategy extends 
SnapshotStrategyBase {
 
     @Override
     public StrategyPriority canHandle(Snapshot snapshot, SnapshotOperation op) 
{
-        if (SnapshotOperation.REVERT.equals(op)) {
-            return StrategyPriority.CANT_HANDLE;
-        }
-
         long volumeId = snapshot.getVolumeId();
         VolumeVO volumeVO = _volumeDao.findById(volumeId);
 
@@ -424,6 +459,13 @@ public class StorageSystemSnapshotStrategy extends 
SnapshotStrategyBase {
             storagePoolId = volumeVO.getPoolId();
         }
 
+        if (SnapshotOperation.REVERT.equals(op)) {
+            if (volumeVO != null && 
ImageFormat.QCOW2.equals(volumeVO.getFormat()))
+                return StrategyPriority.DEFAULT;
+            else
+                return StrategyPriority.CANT_HANDLE;
+        }
+
         DataStore dataStore = _dataStoreMgr.getDataStore(storagePoolId, 
DataStoreRole.Primary);
 
         Map<String, String> mapCapabilities = 
dataStore.getDriver().getCapabilities();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/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 8ed77df..96ea7bb 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
@@ -278,7 +278,7 @@ public class XenserverSnapshotStrategy extends 
SnapshotStrategyBase {
     }
 
     @Override
-    public boolean revertSnapshot(Long snapshotId) {
+    public boolean revertSnapshot(SnapshotInfo snapshot) {
         throw new CloudRuntimeException("revert Snapshot is not supported");
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/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 142cd66..fea0b77 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
@@ -55,6 +55,7 @@ public class SnapshotDataStoreDaoImpl extends 
GenericDaoBase<SnapshotDataStoreVO
     private SearchBuilder<SnapshotDataStoreVO> storeSnapshotSearch;
     private SearchBuilder<SnapshotDataStoreVO> snapshotIdSearch;
     private SearchBuilder<SnapshotDataStoreVO> volumeIdSearch;
+    private SearchBuilder<SnapshotDataStoreVO> volumeSearch;
 
     private final String parentSearch = "select store_id, store_role, 
snapshot_id from cloud.snapshot_store_ref where store_id = ? "
         + " and store_role = ? and volume_id = ? and state = 'Ready'" + " 
order by created DESC " + " limit 1";
@@ -119,6 +120,11 @@ public class SnapshotDataStoreDaoImpl extends 
GenericDaoBase<SnapshotDataStoreVO
         volumeIdSearch.and("volume_id", volumeIdSearch.entity().getVolumeId(), 
SearchCriteria.Op.EQ);
         volumeIdSearch.done();
 
+        volumeSearch = createSearchBuilder();
+        volumeSearch.and("volume_id", volumeSearch.entity().getVolumeId(), 
SearchCriteria.Op.EQ);
+        volumeSearch.and("store_role", volumeSearch.entity().getRole(), 
SearchCriteria.Op.EQ);
+        volumeSearch.done();
+
         return true;
     }
 
@@ -292,6 +298,14 @@ public class SnapshotDataStoreDaoImpl extends 
GenericDaoBase<SnapshotDataStoreVO
     }
 
     @Override
+    public SnapshotDataStoreVO findByVolume(long volumeId, DataStoreRole role) 
{
+        SearchCriteria<SnapshotDataStoreVO> sc = volumeSearch.create();
+        sc.setParameters("volume_id", volumeId);
+        sc.setParameters("store_role", role);
+        return findOneBy(sc);
+    }
+
+    @Override
     public List<SnapshotDataStoreVO> findBySnapshotId(long snapshotId) {
         SearchCriteria<SnapshotDataStoreVO> sc = snapshotIdSearch.create();
         sc.setParameters("snapshot_id", snapshotId);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRevertSnapshotCommandWrapper.java
----------------------------------------------------------------------
diff --git 
a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRevertSnapshotCommandWrapper.java
 
b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRevertSnapshotCommandWrapper.java
new file mode 100644
index 0000000..22edf81
--- /dev/null
+++ 
b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRevertSnapshotCommandWrapper.java
@@ -0,0 +1,95 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+package com.cloud.hypervisor.kvm.resource.wrapper;
+
+import java.io.File;
+
+import org.apache.cloudstack.storage.command.RevertSnapshotCommand;
+import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
+import org.apache.cloudstack.storage.to.SnapshotObjectTO;
+import org.apache.cloudstack.storage.to.VolumeObjectTO;
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.NfsTO;
+import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
+import com.cloud.hypervisor.kvm.storage.KVMPhysicalDisk;
+import com.cloud.hypervisor.kvm.storage.KVMStoragePool;
+import com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager;
+import com.cloud.resource.CommandWrapper;
+import com.cloud.resource.ResourceWrapper;
+import com.cloud.storage.Storage.StoragePoolType;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.script.Script;
+
+@ResourceWrapper(handles =  RevertSnapshotCommand.class)
+public final class LibvirtRevertSnapshotCommandWrapper extends 
CommandWrapper<RevertSnapshotCommand, Answer, LibvirtComputingResource> {
+
+    private static final Logger s_logger = 
Logger.getLogger(LibvirtRevertSnapshotCommandWrapper.class);
+
+    @Override
+    public Answer execute(final RevertSnapshotCommand command, final 
LibvirtComputingResource libvirtComputingResource) {
+        SnapshotObjectTO snapshot = command.getData();
+        VolumeObjectTO volume = snapshot.getVolume();
+        PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO) 
volume.getDataStore();
+        DataStoreTO snapshotImageStore = snapshot.getDataStore();
+        if (!(snapshotImageStore instanceof NfsTO)) {
+            return new Answer(command, false, "revert snapshot on object 
storage is not implemented yet");
+        }
+        NfsTO nfsImageStore = (NfsTO) snapshotImageStore;
+
+        String secondaryStoragePoolUrl = nfsImageStore.getUrl();
+
+        String volumePath = volume.getPath();
+        String snapshotPath = null;
+        String snapshotRelPath = null;
+        KVMStoragePool secondaryStoragePool = null;
+        try {
+            final KVMStoragePoolManager storagePoolMgr = 
libvirtComputingResource.getStoragePoolMgr();
+            secondaryStoragePool = 
storagePoolMgr.getStoragePoolByURI(secondaryStoragePoolUrl);
+            String ssPmountPath = secondaryStoragePool.getLocalPath();
+            snapshotRelPath = snapshot.getPath();
+            snapshotPath = ssPmountPath + File.separator + snapshotRelPath;
+
+            KVMPhysicalDisk snapshotDisk = 
storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(),
+                    primaryStore.getUuid(), volumePath);
+            KVMStoragePool primaryPool = snapshotDisk.getPool();
+
+            if (primaryPool.getType() == StoragePoolType.RBD) {
+                return new Answer(command, false, "revert snapshot to RBD is 
not implemented yet");
+            } else {
+                Script cmd = new 
Script(libvirtComputingResource.manageSnapshotPath(), 
libvirtComputingResource.getCmdsTimeout(), s_logger);
+                cmd.add("-v", snapshotPath);
+                cmd.add("-n", snapshotDisk.getName());
+                cmd.add("-p", snapshotDisk.getPath());
+                String result = cmd.execute();
+                if (result != null) {
+                    s_logger.debug("Failed to revert snaptshot: " + result);
+                    return new Answer(command, false, result);
+                }
+            }
+
+            return new Answer(command, true, "RevertSnapshotCommand executes 
successfully");
+        } catch (CloudRuntimeException e) {
+            return new Answer(command, false, e.toString());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/driver/ElastistorPrimaryDataStoreDriver.java
----------------------------------------------------------------------
diff --git 
a/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/driver/ElastistorPrimaryDataStoreDriver.java
 
b/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/driver/ElastistorPrimaryDataStoreDriver.java
index cc7c8ef..b7ae4d4 100644
--- 
a/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/driver/ElastistorPrimaryDataStoreDriver.java
+++ 
b/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/driver/ElastistorPrimaryDataStoreDriver.java
@@ -393,7 +393,7 @@ public class ElastistorPrimaryDataStoreDriver extends 
CloudStackPrimaryDataStore
     }
 
     @Override
-    public void revertSnapshot(SnapshotInfo snapshot, 
AsyncCompletionCallback<CommandResult> callback) {
+    public void revertSnapshot(SnapshotInfo snapshot, SnapshotInfo 
snapshotOnPrimaryStore, AsyncCompletionCallback<CommandResult> callback) {
         throw new UnsupportedOperationException();
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
----------------------------------------------------------------------
diff --git 
a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
 
b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
index e416bf8..e92e8f6 100644
--- 
a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
+++ 
b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
@@ -46,6 +46,7 @@ import org.apache.cloudstack.storage.command.CopyCmdAnswer;
 import org.apache.cloudstack.storage.command.CopyCommand;
 import org.apache.cloudstack.storage.command.CreateObjectCommand;
 import org.apache.cloudstack.storage.command.DeleteCommand;
+import org.apache.cloudstack.storage.command.RevertSnapshotCommand;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.cloudstack.storage.to.SnapshotObjectTO;
@@ -323,7 +324,28 @@ public class CloudStackPrimaryDataStoreDriverImpl 
implements PrimaryDataStoreDri
     }
 
     @Override
-    public void revertSnapshot(SnapshotInfo snapshot, 
AsyncCompletionCallback<CommandResult> callback) {
+    public void revertSnapshot(SnapshotInfo snapshot, SnapshotInfo 
snapshotOnPrimaryStore, AsyncCompletionCallback<CommandResult> callback) {
+        SnapshotObjectTO snapshotTO = (SnapshotObjectTO)snapshot.getTO();
+        RevertSnapshotCommand cmd = new RevertSnapshotCommand(snapshotTO);
+
+        CommandResult result = new CommandResult();
+        try {
+            EndPoint ep = epSelector.select(snapshotOnPrimaryStore);
+            if ( ep == null ){
+                String errMsg = "No remote endpoint to send 
RevertSnapshotCommand, check if host or ssvm is down?";
+                s_logger.error(errMsg);
+                result.setResult(errMsg);
+            } else {
+                Answer answer = ep.sendMessage(cmd);
+                if (answer != null && !answer.getResult()) {
+                    result.setResult(answer.getDetails());
+                }
+            }
+        } catch (Exception ex) {
+            s_logger.debug("Unable to revert snapshot " + snapshot.getId(), 
ex);
+            result.setResult(ex.toString());
+        }
+        callback.complete(result);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/driver/NexentaPrimaryDataStoreDriver.java
----------------------------------------------------------------------
diff --git 
a/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/driver/NexentaPrimaryDataStoreDriver.java
 
b/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/driver/NexentaPrimaryDataStoreDriver.java
index 7ce46a2..7524703 100644
--- 
a/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/driver/NexentaPrimaryDataStoreDriver.java
+++ 
b/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/driver/NexentaPrimaryDataStoreDriver.java
@@ -130,7 +130,7 @@ public class NexentaPrimaryDataStoreDriver implements 
PrimaryDataStoreDriver {
     public void takeSnapshot(SnapshotInfo snapshot, 
AsyncCompletionCallback<CreateCmdResult> callback) {}
 
     @Override
-    public void revertSnapshot(SnapshotInfo snapshot, 
AsyncCompletionCallback<CommandResult> callback) {}
+    public void revertSnapshot(SnapshotInfo snapshot, SnapshotInfo 
snapshotOnPrimaryStore, AsyncCompletionCallback<CommandResult> callback) {}
 
     @Override
     public void createAsync(DataStore dataStore, DataObject dataObject, 
AsyncCompletionCallback<CreateCmdResult> callback) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
----------------------------------------------------------------------
diff --git 
a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
 
b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
index 7c989d2..0a4cfd6 100644
--- 
a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
+++ 
b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
@@ -210,7 +210,7 @@ public class SamplePrimaryDataStoreDriverImpl implements 
PrimaryDataStoreDriver
     }
 
     @Override
-    public void revertSnapshot(SnapshotInfo snapshot, 
AsyncCompletionCallback<CommandResult> callback) {
+    public void revertSnapshot(SnapshotInfo snapshot, SnapshotInfo 
snapshotOnPrimaryStore, AsyncCompletionCallback<CommandResult> callback) {
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/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 a19aa6b..e934426 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
@@ -688,7 +688,7 @@ public class SolidFirePrimaryDataStoreDriver implements 
PrimaryDataStoreDriver {
     }
 
     @Override
-    public void revertSnapshot(SnapshotInfo snapshotInfo, 
AsyncCompletionCallback<CommandResult> callback) {
+    public void revertSnapshot(SnapshotInfo snapshot, SnapshotInfo 
snapshotOnPrimaryStore, AsyncCompletionCallback<CommandResult> callback) {
         throw new UnsupportedOperationException("Reverting not supported. 
Create a template or volume based on the snapshot instead.");
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/scripts/storage/qcow2/managesnapshot.sh
----------------------------------------------------------------------
diff --git a/scripts/storage/qcow2/managesnapshot.sh 
b/scripts/storage/qcow2/managesnapshot.sh
index 4225407..b8caa2e 100755
--- a/scripts/storage/qcow2/managesnapshot.sh
+++ b/scripts/storage/qcow2/managesnapshot.sh
@@ -235,12 +235,21 @@ backup_snapshot() {
   fi
   return 0
 }
+
+revert_snapshot() {
+  local snapshotPath=$1
+  local destPath=$2
+  ${qemu_img} convert -f qcow2 -O qcow2 "$snapshotPath" "$destPath" || \
+   ( printf "${qemu_img} failed to revert snapshot ${snapshotPath} to disk 
${destPath}.\n" >&2; return 2 )
+  return 0
+}
 #set -x
 
 cflag=
 dflag=
 rflag=
 bflag=
+vflag=
 nflag=
 pathval=
 snapshot=
@@ -249,7 +258,7 @@ deleteDir=
 dmsnapshot=no
 dmrollback=no
 
-while getopts 'c:d:r:n:b:p:t:f' OPTION
+while getopts 'c:d:r:n:b:v:p:t:f' OPTION
 do
   case $OPTION in
   c)   cflag=1
@@ -264,6 +273,9 @@ do
   b)    bflag=1
         pathval="$OPTARG"
         ;;
+  v)    vflag=1
+        pathval="$OPTARG"
+        ;;
   n)   nflag=1
        snapshot="$OPTARG"
        ;;
@@ -304,6 +316,10 @@ elif [ "$rflag" == "1" ]
 then
   rollback_snapshot $pathval "$snapshot" $destPath
   exit $?
+elif [ "$vflag" == "1" ]
+then
+  revert_snapshot $pathval $destPath
+  exit $?
 fi
 
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java 
b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
index bc66130..d6fafb1 100644
--- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
+++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
@@ -247,12 +247,16 @@ public class SnapshotManagerImpl extends ManagerBase 
implements SnapshotManager,
 
     @Override
     public boolean revertSnapshot(Long snapshotId) {
-        Snapshot snapshot = _snapshotDao.findById(snapshotId);
+        SnapshotVO snapshot = _snapshotDao.findById(snapshotId);
         if (snapshot == null) {
             throw new InvalidParameterValueException("No such snapshot");
         }
 
-        Volume volume = _volsDao.findById(snapshot.getVolumeId());
+        VolumeVO volume = _volsDao.findById(snapshot.getVolumeId());
+        if (volume.getState() != Volume.State.Ready) {
+            throw new InvalidParameterValueException("The volume is not in 
Ready state.");
+        }
+
         Long instanceId = volume.getInstanceId();
 
         // If this volume is attached to an VM, then the VM needs to be in the 
stopped state
@@ -264,6 +268,11 @@ public class SnapshotManagerImpl extends ManagerBase 
implements SnapshotManager,
             }
         }
 
+        SnapshotInfo snapshotInfo = snapshotFactory.getSnapshot(snapshotId, 
DataStoreRole.Image);
+        if (snapshotInfo == null) {
+            throw new CloudRuntimeException("snapshot:" + snapshotId + " not 
exist in data store");
+        }
+
         SnapshotStrategy snapshotStrategy = 
_storageStrategyFactory.getSnapshotStrategy(snapshot, SnapshotOperation.REVERT);
 
         if (snapshotStrategy == null) {
@@ -271,7 +280,15 @@ public class SnapshotManagerImpl extends ManagerBase 
implements SnapshotManager,
             return false;
         }
 
-        return snapshotStrategy.revertSnapshot(snapshotId);
+        boolean result = snapshotStrategy.revertSnapshot(snapshotInfo);
+        if (result) {
+            // update volume size and primary storage count
+            _resourceLimitMgr.decrementResourceCount(snapshot.getAccountId(), 
ResourceType.primary_storage,
+                    new Long(volume.getSize() - snapshot.getSize()));
+            volume.setSize(snapshot.getSize());
+            _volsDao.update(volume.getId(), volume);
+        }
+        return result;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/ui/css/cloudstack3.css
----------------------------------------------------------------------
diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css
index 60ac9ca..c170bde 100644
--- a/ui/css/cloudstack3.css
+++ b/ui/css/cloudstack3.css
@@ -12675,6 +12675,7 @@ div.ui-dialog div.autoscaler div.field-group 
div.form-container form div.form-it
   background-position: -167px -677px;
 }
 
+.revertSnapshot .icon,
 .restoreVM .icon,
 .restore .icon,
 .recover .icon {
@@ -12690,6 +12691,7 @@ div.ui-dialog div.autoscaler div.field-group 
div.form-container form div.form-it
   background-position: -167px -66px;
 }
 
+.revertSnapshot:hover .icon,
 .restoreVM:hover .icon,
 .restore:hover .icon {
   background-position: -168px -613px;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/92344c00/ui/scripts/storage.js
----------------------------------------------------------------------
diff --git a/ui/scripts/storage.js b/ui/scripts/storage.js
index ce4f077..77bd002 100644
--- a/ui/scripts/storage.js
+++ b/ui/scripts/storage.js
@@ -1862,6 +1862,9 @@
                         volumename: {
                             label: 'label.volume'
                         },
+                        name: {
+                            label: 'label.name'
+                        },
                         intervaltype: {
                             label: 'label.interval.type'
                         },

Reply via email to