Updated Branches: refs/heads/master 4747b2abf -> aad1cda7e
Updates to revertSnapshot API Added revertSnapshot API action to UI Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/350c9447 Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/350c9447 Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/350c9447 Branch: refs/heads/master Commit: 350c94474b6abe4ce097e7616798d45952ed9253 Parents: 4747b2a Author: Chris Suich <chris.su...@netapp.com> Authored: Mon Oct 7 16:04:48 2013 -0400 Committer: Edison Su <sudi...@gmail.com> Committed: Mon Oct 14 15:19:51 2013 -0700 ---------------------------------------------------------------------- .../user/snapshot/RevertSnapshotCmd.java | 11 ++-- .../classes/resources/messages.properties | 3 + client/tomcatconf/commands.properties.in | 2 +- .../storage/snapshot/SnapshotServiceImpl.java | 59 ++++++++++++++++++++ .../com/cloud/server/ManagementServerImpl.java | 11 ++-- .../storage/snapshot/SnapshotManagerImpl.java | 12 ++++ ui/dictionary.jsp | 3 + ui/scripts/storage.js | 34 +++++++++++ 8 files changed, 125 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/350c9447/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 946eebd..6e790e1 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 @@ -18,9 +18,6 @@ */ package org.apache.cloudstack.api.command.user.snapshot; -import com.cloud.event.EventTypes; -import com.cloud.storage.Snapshot; -import com.cloud.user.Account; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiCommandJobType; import org.apache.cloudstack.api.ApiConstants; @@ -33,7 +30,11 @@ import org.apache.cloudstack.api.response.SnapshotResponse; import org.apache.cloudstack.api.response.SuccessResponse; import org.apache.cloudstack.context.CallContext; -@APICommand(name = "RevertSnapshot", description = "revert a volume snapshot.", responseObject = SnapshotResponse.class) +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) public class RevertSnapshotCmd extends BaseAsyncCmd { private static final String s_name = "revertsnapshotresponse"; @Parameter(name= ApiConstants.ID, type= BaseCmd.CommandType.UUID, entityType = SnapshotResponse.class, @@ -70,10 +71,12 @@ public class RevertSnapshotCmd extends BaseAsyncCmd { return "revert snapshot: " + getId(); } + @Override public ApiCommandJobType getInstanceType() { return ApiCommandJobType.Snapshot; } + @Override public Long getInstanceId() { return getId(); } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/350c9447/client/WEB-INF/classes/resources/messages.properties ---------------------------------------------------------------------- diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties index 7970369..c075bf8 100644 --- a/client/WEB-INF/classes/resources/messages.properties +++ b/client/WEB-INF/classes/resources/messages.properties @@ -251,6 +251,8 @@ label.action.stop.systemvm.processing=Stopping System VM.... label.action.stop.systemvm=Stop System VM label.action.take.snapshot.processing=Taking Snapshot.... label.action.take.snapshot=Take Snapshot +label.action.revert.snapshot.processing=Reverting to Snapshot... +label.action.revert.snapshot=Revert to Snapshot label.action.unmanage.cluster.processing=Unmanaging Cluster.... label.action.unmanage.cluster=Unmanage Cluster label.action.update.OS.preference.processing=Updating OS Preference.... @@ -1297,6 +1299,7 @@ message.action.stop.instance=Please confirm that you want to stop this instance. message.action.stop.router=All services provided by this virtual router will be interrupted. Please confirm that you want to stop this router. message.action.stop.systemvm=Please confirm that you want to stop this system VM. message.action.take.snapshot=Please confirm that you want to take a snapshot of this volume. +message.action.revert.snapshot=Please confirm that you want to revert the owning volume to this snapshot. message.action.unmanage.cluster=Please confirm that you want to unmanage the cluster. message.action.vmsnapshot.delete=Please confirm that you want to delete this VM snapshot. message.action.vmsnapshot.revert=Revert VM snapshot http://git-wip-us.apache.org/repos/asf/cloudstack/blob/350c9447/client/tomcatconf/commands.properties.in ---------------------------------------------------------------------- diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index 58c770d..96e841a 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -79,7 +79,7 @@ deleteSnapshot=15 createSnapshotPolicy=15 deleteSnapshotPolicies=15 listSnapshotPolicies=15 - +revertSnapshot=15 #### template commands createTemplate=15 http://git-wip-us.apache.org/repos/asf/cloudstack/blob/350c9447/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 c09adca..a4014b0 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 @@ -42,6 +42,7 @@ import org.apache.cloudstack.framework.async.AsyncRpcContext; import org.apache.cloudstack.storage.command.CommandResult; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; +import org.apache.cloudstack.storage.datastore.PrimaryDataStore; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; @@ -132,6 +133,19 @@ public class SnapshotServiceImpl implements SnapshotService { } + static private class RevertSnapshotContext<T> extends AsyncRpcContext<T> { + final SnapshotInfo snapshot; + final AsyncCallFuture<SnapshotResult> future; + + public RevertSnapshotContext(AsyncCompletionCallback<T> callback, SnapshotInfo snapshot, + AsyncCallFuture<SnapshotResult> future) { + super(callback); + this.snapshot = snapshot; + this.future = future; + } + + } + protected Void createSnapshotAsyncCallback(AsyncCallbackDispatcher<SnapshotServiceImpl, CreateCmdResult> callback, CreateSnapshotContext<CreateCmdResult> context) { CreateCmdResult result = callback.getResult(); @@ -364,6 +378,28 @@ public class SnapshotServiceImpl implements SnapshotService { return null; } + protected Void revertSnapshotCallback(AsyncCallbackDispatcher<SnapshotServiceImpl, CommandResult> callback, + RevertSnapshotContext<CommandResult> context) { + + CommandResult result = callback.getResult(); + AsyncCallFuture<SnapshotResult> future = context.future; + SnapshotResult res = null; + try { + if (result.isFailed()) { + s_logger.debug("revert snapshot failed" + result.getResult()); + res = new SnapshotResult(context.snapshot, null); + res.setResult(result.getResult()); + } else { + res = new SnapshotResult(context.snapshot, null); + } + } catch (Exception e) { + s_logger.debug("Failed to in revertSnapshotCallback", e); + res.setResult(e.toString()); + } + future.complete(res); + return null; + } + @Override public boolean deleteSnapshot(SnapshotInfo snapInfo) { snapInfo.processEvent(ObjectInDataStoreStateMachine.Event.DestroyRequested); @@ -394,6 +430,29 @@ public class SnapshotServiceImpl implements SnapshotService { @Override public boolean revertSnapshot(Long snapshotId) { + SnapshotInfo snapshot = snapshotfactory.getSnapshot(snapshotId, DataStoreRole.Primary); + PrimaryDataStore store = (PrimaryDataStore)snapshot.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); + + SnapshotResult result = null; + try { + result = future.get(); + if (result.isFailed()) { + throw new CloudRuntimeException(result.getResult()); + } + return true; + } catch (InterruptedException e) { + s_logger.debug("revert snapshot is failed: " + e.toString()); + } catch (ExecutionException e) { + s_logger.debug("revert snapshot is failed: " + e.toString()); + } + return false; } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/350c9447/server/src/com/cloud/server/ManagementServerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 0a0fcdc..7173044 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -42,9 +42,6 @@ import javax.crypto.spec.SecretKeySpec; import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.commons.codec.binary.Base64; -import org.apache.log4j.Logger; - import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.affinity.AffinityGroupProcessor; @@ -339,6 +336,7 @@ import org.apache.cloudstack.api.command.user.snapshot.DeleteSnapshotCmd; import org.apache.cloudstack.api.command.user.snapshot.DeleteSnapshotPoliciesCmd; import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotPoliciesCmd; import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotsCmd; +import org.apache.cloudstack.api.command.user.snapshot.RevertSnapshotCmd; import org.apache.cloudstack.api.command.user.ssh.CreateSSHKeyPairCmd; import org.apache.cloudstack.api.command.user.ssh.DeleteSSHKeyPairCmd; import org.apache.cloudstack.api.command.user.ssh.ListSSHKeyPairsCmd; @@ -438,6 +436,8 @@ import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.utils.identity.ManagementServerNode; +import org.apache.commons.codec.binary.Base64; +import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.api.GetVncPortAnswer; @@ -2731,6 +2731,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(DeleteSnapshotPoliciesCmd.class); cmdList.add(ListSnapshotPoliciesCmd.class); cmdList.add(ListSnapshotsCmd.class); + cmdList.add(RevertSnapshotCmd.class); cmdList.add(CreateSSHKeyPairCmd.class); cmdList.add(DeleteSSHKeyPairCmd.class); cmdList.add(ListSSHKeyPairsCmd.class); @@ -3164,7 +3165,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe } @Override - @ActionEvent(eventType = "", eventDescription = "", async = true) + @ActionEvent(eventType = "", eventDescription = "", async = true) public VMInstanceVO destroySystemVM(DestroySystemVmCmd cmd) { VMInstanceVO systemVm = _vmInstanceDao.findByIdTypes(cmd.getId(), VirtualMachine.Type.ConsoleProxy, VirtualMachine.Type.SecondaryStorageVm); @@ -3640,7 +3641,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe String password = vm.getDetail("Encrypted.Password"); if (password == null || password.equals("")) { InvalidParameterValueException ex = new InvalidParameterValueException("No password for VM with specified id found. " + - "If VM is created from password enabled template and SSH keypair is assigned to VM then only password can be retrieved."); + "If VM is created from password enabled template and SSH keypair is assigned to VM then only password can be retrieved."); ex.addProxyObject(vm.getUuid(), "vmId"); throw ex; } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/350c9447/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 0b53cfd..a50d89c 100755 --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -264,6 +264,18 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, throw new InvalidParameterValueException("No such snapshot"); } + Volume volume = _volsDao.findById(snapshot.getVolumeId()); + Long instanceId = volume.getInstanceId(); + + // If this volume is attached to an VM, then the VM needs to be in the stopped state + // in order to revert the volume + if (instanceId != null) { + UserVmVO vm = _vmDao.findById(instanceId); + if (vm.getState() != State.Stopped && vm.getState() != State.Shutdowned) { + throw new InvalidParameterValueException("The VM the specified disk is attached to is not in the shutdown state."); + } + } + SnapshotStrategy snapshotStrategy = null; for (SnapshotStrategy strategy : snapshotStrategies) { if (strategy.canHandle(snapshot)) { http://git-wip-us.apache.org/repos/asf/cloudstack/blob/350c9447/ui/dictionary.jsp ---------------------------------------------------------------------- diff --git a/ui/dictionary.jsp b/ui/dictionary.jsp index 3563376..80aab6f 100644 --- a/ui/dictionary.jsp +++ b/ui/dictionary.jsp @@ -260,6 +260,8 @@ dictionary = { 'label.action.stop.systemvm.processing': '<fmt:message key="label.action.stop.systemvm.processing" />', 'label.action.take.snapshot': '<fmt:message key="label.action.take.snapshot" />', 'label.action.take.snapshot.processing': '<fmt:message key="label.action.take.snapshot.processing" />', +'label.action.revert.snapshot': '<fmt:message key="label.action.revert.snapshot" />', +'label.action.revert.snapshot.processing': '<fmt:message key="label.action.revert.snapshot.processing" />', 'label.action.unmanage.cluster': '<fmt:message key="label.action.unmanage.cluster" />', 'label.action.unmanage.cluster.processing': '<fmt:message key="label.action.unmanage.cluster.processing" />', 'label.action.update.OS.preference': '<fmt:message key="label.action.update.OS.preference" />', @@ -1264,6 +1266,7 @@ dictionary = { 'message.action.stop.router': '<fmt:message key="message.action.stop.router" />', 'message.action.stop.systemvm': '<fmt:message key="message.action.stop.systemvm" />', 'message.action.take.snapshot': '<fmt:message key="message.action.take.snapshot" />', +'message.action.revert.snapshot': '<fmt:message key="message.action.revert.snapshot" />', 'message.action.unmanage.cluster': '<fmt:message key="message.action.unmanage.cluster" />', 'message.action.vmsnapshot.delete': '<fmt:message key="message.action.vmsnapshot.delete" />', 'message.action.vmsnapshot.revert': '<fmt:message key="message.action.vmsnapshot.revert" />', http://git-wip-us.apache.org/repos/asf/cloudstack/blob/350c9447/ui/scripts/storage.js ---------------------------------------------------------------------- diff --git a/ui/scripts/storage.js b/ui/scripts/storage.js index 88fb9f2..b16f4d4 100644 --- a/ui/scripts/storage.js +++ b/ui/scripts/storage.js @@ -1760,6 +1760,36 @@ } }, + revertSnapshot: { + label: 'label.action.revert.snapshot', + messages: { + confirm: function(args) { + return 'message.action.revert.snapshot'; + }, + notification: function(args) { + return 'label.action.revert.snapshot'; + } + }, + action: function(args) { + $.ajax({ + url: createURL("revertSnapshot&id="+args.context.snapshots[0].id), + dataType: "json", + async: true, + success: function(json) { + var jid = json.revertsnapshotresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + remove: { label: 'label.action.delete.snapshot', messages: { @@ -1929,6 +1959,10 @@ if (jsonObj.state == "BackedUp") { allowedActions.push("createTemplate"); allowedActions.push("createVolume"); + + if (args.context.volumes[0].vmstate == "Stopped") { + allowedActions.push("revertSnapshot"); + } } allowedActions.push("remove");