1) rename RevertToSnapshotCmd->RevertToVMSnapshotCmd 2) add marvin test for vm snapshot
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/d7cab21e Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/d7cab21e Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/d7cab21e Branch: refs/heads/ui-cisco-asa1000v-support Commit: d7cab21e9ae9df3f10dac502fd8f14f4deb3a348 Parents: 2510bf0 Author: Mice Xia <mice_...@tcloudcomputing.com> Authored: Fri May 3 12:18:47 2013 +0800 Committer: Mice Xia <mice_...@tcloudcomputing.com> Committed: Fri May 3 12:32:53 2013 +0800 ---------------------------------------------------------------------- .../user/vmsnapshot/RevertToSnapshotCmd.java | 92 ----- .../user/vmsnapshot/RevertToVMSnapshotCmd.java | 92 +++++ client/tomcatconf/commands.properties.in | 2 +- .../src/com/cloud/server/ManagementServerImpl.java | 4 +- test/integration/smoke/test_vm_snapshots.py | 308 +++++++++++++++ tools/marvin/marvin/integration/lib/base.py | 37 ++ ui/scripts/vm_snapshots.js | 2 +- 7 files changed, 441 insertions(+), 96 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d7cab21e/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/RevertToSnapshotCmd.java ---------------------------------------------------------------------- diff --git a/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/RevertToSnapshotCmd.java b/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/RevertToSnapshotCmd.java deleted file mode 100644 index ea7bf60..0000000 --- a/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/RevertToSnapshotCmd.java +++ /dev/null @@ -1,92 +0,0 @@ -// 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.api.command.user.vmsnapshot; - -import java.util.logging.Logger; - -import org.apache.cloudstack.api.APICommand; -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.ApiErrorCode; -import org.apache.cloudstack.api.BaseAsyncCmd; -import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.ServerApiException; -import org.apache.cloudstack.api.response.UserVmResponse; -import org.apache.cloudstack.api.response.VMSnapshotResponse; - -import com.cloud.event.EventTypes; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.user.Account; -import com.cloud.user.UserContext; -import com.cloud.uservm.UserVm; -import com.cloud.vm.snapshot.VMSnapshot; - -@APICommand(name = "revertToSnapshot",description = "Revert VM from a vmsnapshot.", responseObject = UserVmResponse.class, since="4.2.0") -public class RevertToSnapshotCmd extends BaseAsyncCmd { - public static final Logger s_logger = Logger - .getLogger(RevertToSnapshotCmd.class.getName()); - private static final String s_name = "reverttosnapshotresponse"; - - @Parameter(name = ApiConstants.VM_SNAPSHOT_ID, type = CommandType.UUID, required = true,entityType=VMSnapshotResponse.class,description = "The ID of the vm snapshot") - private Long vmSnapShotId; - - public Long getVmSnapShotId() { - return vmSnapShotId; - } - - @Override - public String getCommandName() { - return s_name; - } - - @Override - public long getEntityOwnerId() { - VMSnapshot vmSnapshot = _entityMgr.findById(VMSnapshot.class, getVmSnapShotId()); - if (vmSnapshot != null) { - return vmSnapshot.getAccountId(); - } - return Account.ACCOUNT_ID_SYSTEM; - } - - @Override - public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException, ConcurrentOperationException { - UserContext.current().setEventDetails( - "vmsnapshot id: " + getVmSnapShotId()); - UserVm result = _vmSnapshotService.revertToSnapshot(getVmSnapShotId()); - if (result != null) { - UserVmResponse response = _responseGenerator.createUserVmResponse( - "virtualmachine", result).get(0); - response.setResponseName(getCommandName()); - this.setResponseObject(response); - } else { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR,"Failed to revert VM snapshot"); - } - } - - @Override - public String getEventDescription() { - return "Revert from VM snapshot: " + getVmSnapShotId(); - } - - @Override - public String getEventType() { - return EventTypes.EVENT_VM_SNAPSHOT_REVERT; - } - -} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d7cab21e/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/RevertToVMSnapshotCmd.java ---------------------------------------------------------------------- diff --git a/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/RevertToVMSnapshotCmd.java b/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/RevertToVMSnapshotCmd.java new file mode 100644 index 0000000..f6d8b2c --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/RevertToVMSnapshotCmd.java @@ -0,0 +1,92 @@ +// 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.api.command.user.vmsnapshot; + +import java.util.logging.Logger; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.cloudstack.api.response.VMSnapshotResponse; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import com.cloud.user.UserContext; +import com.cloud.uservm.UserVm; +import com.cloud.vm.snapshot.VMSnapshot; + +@APICommand(name = "revertToVMSnapshot",description = "Revert VM from a vmsnapshot.", responseObject = UserVmResponse.class, since="4.2.0") +public class RevertToVMSnapshotCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger + .getLogger(RevertToVMSnapshotCmd.class.getName()); + private static final String s_name = "reverttovmsnapshotresponse"; + + @Parameter(name = ApiConstants.VM_SNAPSHOT_ID, type = CommandType.UUID, required = true,entityType=VMSnapshotResponse.class,description = "The ID of the vm snapshot") + private Long vmSnapShotId; + + public Long getVmSnapShotId() { + return vmSnapShotId; + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + VMSnapshot vmSnapshot = _entityMgr.findById(VMSnapshot.class, getVmSnapShotId()); + if (vmSnapshot != null) { + return vmSnapshot.getAccountId(); + } + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException, ConcurrentOperationException { + UserContext.current().setEventDetails( + "vmsnapshot id: " + getVmSnapShotId()); + UserVm result = _vmSnapshotService.revertToSnapshot(getVmSnapShotId()); + if (result != null) { + UserVmResponse response = _responseGenerator.createUserVmResponse( + "virtualmachine", result).get(0); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR,"Failed to revert VM snapshot"); + } + } + + @Override + public String getEventDescription() { + return "Revert from VM snapshot: " + getVmSnapShotId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_VM_SNAPSHOT_REVERT; + } + +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d7cab21e/client/tomcatconf/commands.properties.in ---------------------------------------------------------------------- diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index b49e1fb..7d950fe 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -569,7 +569,7 @@ removeFromGlobalLoadBalancerRule=15 listVMSnapshot=15 createVMSnapshot=15 deleteVMSnapshot=15 -revertToSnapshot=15 +revertToVMSnapshot=15 #### Baremetal commands addBaremetalHost=1 http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d7cab21e/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 da01b83..efd51e6 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -256,7 +256,7 @@ import org.apache.cloudstack.api.command.user.vmgroup.UpdateVMGroupCmd; import org.apache.cloudstack.api.command.user.vmsnapshot.CreateVMSnapshotCmd; import org.apache.cloudstack.api.command.user.vmsnapshot.DeleteVMSnapshotCmd; import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd; -import org.apache.cloudstack.api.command.user.vmsnapshot.RevertToSnapshotCmd; +import org.apache.cloudstack.api.command.user.vmsnapshot.RevertToVMSnapshotCmd; import org.apache.cloudstack.api.command.user.zone.ListZonesByCmd; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator; @@ -2524,7 +2524,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(ListZonesByCmd.class); cmdList.add(ListVMSnapshotCmd.class); cmdList.add(CreateVMSnapshotCmd.class); - cmdList.add(RevertToSnapshotCmd.class); + cmdList.add(RevertToVMSnapshotCmd.class); cmdList.add(DeleteVMSnapshotCmd.class); cmdList.add(AddIpToVmNicCmd.class); cmdList.add(RemoveIpFromVmNicCmd.class); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d7cab21e/test/integration/smoke/test_vm_snapshots.py ---------------------------------------------------------------------- diff --git a/test/integration/smoke/test_vm_snapshots.py b/test/integration/smoke/test_vm_snapshots.py new file mode 100644 index 0000000..353d499 --- /dev/null +++ b/test/integration/smoke/test_vm_snapshots.py @@ -0,0 +1,308 @@ +# 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. + +# Import Local Modules +import marvin +from nose.plugins.attrib import attr +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.integration.lib.utils import * +from marvin.integration.lib.base import * +from marvin.integration.lib.common import * +from marvin.remoteSSHClient import remoteSSHClient + +class Services: + """Test Snapshots Services + """ + + def __init__(self): + self.services = { + "account": { + "email": "t...@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + # Random characters are appended for unique + # username + "password": "password", + }, + "service_offering": { + "name": "Tiny Instance", + "displaytext": "Tiny Instance", + "cpunumber": 1, + "cpuspeed": 200, # in MHz + "memory": 256, # In MBs + }, + "server": { + "displayname": "TestVM", + "username": "root", + "password": "password", + "ssh_port": 22, + "hypervisor": 'XenServer', + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + }, + "mgmt_server": { + "ipaddress": '1.2.2.152', + "username": "root", + "password": "password", + "port": 22, + }, + "templates": { + "displaytext": 'Template', + "name": 'Template', + "ostype": "CentOS 5.3 (64-bit)", + "templatefilter": 'self', + }, + "test_dir": "/tmp", + "random_data": "random.data", + "snapshot_name":"TestSnapshot", + "snapshot_displaytext":"Test", + "ostype": "CentOS 5.3 (64-bit)", + "sleep": 60, + "timeout": 10, + "mode": 'advanced', # Networking mode: Advanced, Basic + } + +class TestVmSnapshot(cloudstackTestCase): + @classmethod + def setUpClass(cls): + cls.api_client = super(TestVmSnapshot, cls).getClsTestClient().getApiClient() + cls.services = Services().services + # Get Zone, Domain and templates + cls.domain = get_domain(cls.api_client, cls.services) + cls.zone = get_zone(cls.api_client, cls.services) + + template = get_template( + cls.api_client, + cls.zone.id, + cls.services["ostype"] + ) + cls.services["domainid"] = cls.domain.id + cls.services["server"]["zoneid"] = cls.zone.id + cls.services["templates"]["ostypeid"] = template.ostypeid + cls.services["zoneid"] = cls.zone.id + + # Create VMs, NAT Rules etc + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=cls.domain.id + ) + + cls.services["account"] = cls.account.name + + cls.service_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offering"] + ) + cls.virtual_machine = VirtualMachine.create( + cls.api_client, + cls.services["server"], + templateid=template.id, + accountid=cls.account.name, + domainid=cls.account.domainid, + serviceofferingid=cls.service_offering.id, + mode=cls.services["mode"] + ) + cls.random_data_0 = random_gen(100) + cls._cleanup = [ + cls.service_offering, + cls.account, + ] + return + + @classmethod + def tearDownClass(cls): + try: + # Cleanup resources used + cleanup_resources(cls.api_client, cls._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + return + + def tearDown(self): + try: + # Clean up, terminate the created instance, volumes and snapshots + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr(tags=["advanced", "advancedns", "smoke"]) + def test_01_create_vm_snapshots(self): + + try: + # Login to VM and write data to file system + ssh_client = self.virtual_machine.get_ssh_client() + + cmds = [ + "echo %s > %s/%s" % (self.random_data_0, self.services["test_dir"], self.services["random_data"]), + "cat %s/%s" % (self.services["test_dir"], self.services["random_data"]) + ] + + for c in cmds: + self.debug(c) + result = ssh_client.execute(c) + self.debug(result) + + except Exception: + self.fail("SSH failed for Virtual machine: %s" % + self.virtual_machine.ipaddress) + self.assertEqual( + self.random_data_0, + result[0], + "Check the random data has be write into temp file!" + ) + + time.sleep(self.services["sleep"]) + + vm_snapshot = VmSnapshot.create( + self.apiclient, + self.virtual_machine.id, + "false", + self.services["snapshot_name"], + self.services["snapshot_displaytext"] + ) + self.assertEqual( + vm_snapshot.state, + "Ready", + "Check the snapshot of vm is ready!" + ) + return + + @attr(tags=["advanced", "advancedns", "smoke"]) + def test_02_revert_vm_snapshots(self): + try: + ssh_client = self.virtual_machine.get_ssh_client() + + cmds = [ + "rm -rf %s/%s" % (self.services["test_dir"], self.services["random_data"]), + "ls %s/%s" % (self.services["test_dir"], self.services["random_data"]) + ] + + for c in cmds: + self.debug(c) + result = ssh_client.execute(c) + self.debug(result) + + except Exception: + self.fail("SSH failed for Virtual machine: %s" % + self.virtual_machine.ipaddress) + + if str(result[0]).index("No such file or directory") == -1: + self.fail("Check the random data has be delete from temp file!") + + time.sleep(self.services["sleep"]) + + list_snapshot_response = VmSnapshot.list(self.apiclient,vmid=self.virtual_machine.id,listall=True) + + self.assertEqual( + isinstance(list_snapshot_response, list), + True, + "Check list response returns a valid list" + ) + self.assertNotEqual( + list_snapshot_response, + None, + "Check if snapshot exists in ListSnapshot" + ) + + self.assertEqual( + list_snapshot_response[0].state, + "Ready", + "Check the snapshot of vm is ready!" + ) + + VmSnapshot.revertToSnapshot(self.apiclient,list_snapshot_response[0].id) + + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.virtual_machine.id + ) + + self.assertEqual( + list_vm_response[0].state, + "Stopped", + "Check the state of vm is Stopped!" + ) + + cmd = startVirtualMachine.startVirtualMachineCmd() + cmd.id = list_vm_response[0].id + self.apiclient.startVirtualMachine(cmd) + + time.sleep(self.services["sleep"]) + + try: + ssh_client = self.virtual_machine.get_ssh_client(reconnect=True) + + cmds = [ + "cat %s/%s" % (self.services["test_dir"], self.services["random_data"]) + ] + + for c in cmds: + self.debug(c) + result = ssh_client.execute(c) + self.debug(result) + + except Exception: + self.fail("SSH failed for Virtual machine: %s" % + self.virtual_machine.ipaddress) + + self.assertEqual( + self.random_data_0, + result[0], + "Check the random data is equal with the ramdom file!" + ) + @attr(tags=["advanced", "advancedns", "smoke"]) + def test_03_delete_vm_snapshots(self): + + list_snapshot_response = VmSnapshot.list(self.apiclient,vmid=self.virtual_machine.id,listall=True) + + self.assertEqual( + isinstance(list_snapshot_response, list), + True, + "Check list response returns a valid list" + ) + self.assertNotEqual( + list_snapshot_response, + None, + "Check if snapshot exists in ListSnapshot" + ) + """ + cmd = deleteVMSnapshot.deleteVMSnapshotCmd() + cmd.vmsnapshotid = list_snapshot_response[0].id + self.apiclient.deleteVMSnapshot(cmd) + """ + VmSnapshot.deleteVMSnapshot(self.apiclient,list_snapshot_response[0].id) + + time.sleep(self.services["sleep"]*3) + + list_snapshot_response = VmSnapshot.list(self.apiclient,vmid=self.virtual_machine.id,listall=True) + + self.assertEqual( + list_snapshot_response, + None, + "Check list vm snapshot has be deleted" + ) http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d7cab21e/tools/marvin/marvin/integration/lib/base.py ---------------------------------------------------------------------- diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py index 1d86c6c..bebf2b5 100755 --- a/tools/marvin/marvin/integration/lib/base.py +++ b/tools/marvin/marvin/integration/lib/base.py @@ -3045,3 +3045,40 @@ class ASA1000V: cmd = listCiscoAsa1000vResources.listCiscoAsa1000vResourcesCmd() [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listCiscoAsa1000vResources(cmd)) + +class VmSnapshot: + """Manage VM Snapshot life cycle""" + def __init__(self, items): + self.__dict__.update(items) + @classmethod + def create(cls,apiclient,vmid,snapshotmemory="false",name=None,description=None): + cmd = createVMSnapshot.createVMSnapshotCmd() + cmd.virtualmachineid = vmid + + if snapshotmemory: + cmd.snapshotmemory = snapshotmemory + if name: + cmd.name = name + if description: + cmd.description = description + return VmSnapshot(apiclient.createVMSnapshot(cmd).__dict__) + + @classmethod + def list(cls, apiclient, **kwargs): + cmd = listVMSnapshot.listVMSnapshotCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listVMSnapshot(cmd)) + + @classmethod + def revertToSnapshot(cls, apiclient,vmsnapshotid): + cmd = revertToVMSnapshot.revertToVMSnapshotCmd() + cmd.vmsnapshotid = vmsnapshotid + + return apiclient.revertToVMSnapshot(cmd) + + @classmethod + def deleteVMSnapshot(cls,apiclient,vmsnapshotid): + cmd = deleteVMSnapshot.deleteVMSnapshotCmd() + cmd.vmsnapshotid = vmsnapshotid + + return apiclient.deleteVMSnapshot(cmd) http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d7cab21e/ui/scripts/vm_snapshots.js ---------------------------------------------------------------------- diff --git a/ui/scripts/vm_snapshots.js b/ui/scripts/vm_snapshots.js index 0d6305b..190bf75 100644 --- a/ui/scripts/vm_snapshots.js +++ b/ui/scripts/vm_snapshots.js @@ -170,7 +170,7 @@ }, action: function(args) { $.ajax({ - url: createURL("revertToSnapshot&vmsnapshotid=" + args.context.vmsnapshots[0].id), + url: createURL("revertToVMSnapshot&vmsnapshotid=" + args.context.vmsnapshots[0].id), dataType: "json", async: true, success: function(json) {