http://git-wip-us.apache.org/repos/asf/cloudstack/blob/70651571/test/integration/smoke/test_vm_ha.py ---------------------------------------------------------------------- diff --git a/test/integration/smoke/test_vm_ha.py b/test/integration/smoke/test_vm_ha.py new file mode 100644 index 0000000..ae5b51f --- /dev/null +++ b/test/integration/smoke/test_vm_ha.py @@ -0,0 +1,232 @@ +# 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. + +#Test from the Marvin - Testing in Python wiki + +import time + +#All tests inherit from cloudstackTestCase +from marvin.cloudstackTestCase import cloudstackTestCase + +#Import Integration Libraries + +#base - contains all resources as entities and defines create, delete, list operations on them +from marvin.integration.lib.base import Account, VirtualMachine, Cluster, Host, ServiceOffering, Configurations, SimulatorMock + +#utils - utility classes for common cleanup, external library wrappers etc +from marvin.integration.lib.utils import cleanup_resources + +#common - commonly used methods for all tests are listed here +from marvin.integration.lib.common import get_zone, get_domain, get_template + +from nose.plugins.attrib import attr + +class TestData(object): + """Test data object that is required to create resources + """ + def __init__(self): + self.testdata = { + #data to create an account + "account": { + "email": "[email protected]", + "firstname": "Test", + "lastname": "User", + "username": "test", + "password": "password", + }, + #data reqd for virtual machine creation + "virtual_machine" : { + "name" : "testvm", + "displayname" : "Test VM", + }, + #small service offering + "service_offering": { + "hasmall": { + "name": "HA Small Instance", + "displaytext": "HA Small Instance", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 256, + "hosttags": "ha", + "offerha": True, + }, + }, + "ostype": 'CentOS 5.3 (32-bit)', + } + + +class TestDeployVMHA(cloudstackTestCase): + """Test VM HA + """ + + def setUp(self): + self.testdata = TestData().testdata + self.apiclient = self.testClient.getApiClient() + + # Get Zone, Domain and Default Built-in template + self.domain = get_domain(self.apiclient, self.testdata) + self.zone = get_zone(self.apiclient, self.testdata) + self.testdata["mode"] = self.zone.networktype + self.template = get_template(self.apiclient, self.zone.id, self.testdata["ostype"]) + + self.hosts = [] + suitablecluster = None + clusters = Cluster.list(self.apiclient) + self.assertTrue(isinstance(clusters, list) and len(clusters) > 0, msg = "No clusters found") + for cluster in clusters: + self.hosts = Host.list(self.apiclient, clusterid=cluster.id, type='Routing') + if isinstance(self.hosts, list) and len(self.hosts) >= 2: + suitablecluster = cluster + break + self.assertTrue(isinstance(self.hosts, list) and len(self.hosts) >= 2, msg = "Atleast 2 hosts required in cluster for VM HA test") + #update host tags + for host in self.hosts: + Host.update(self.apiclient, id=host.id, hosttags=self.testdata["service_offering"]["hasmall"]["hosttags"]) + + #create a user account + self.account = Account.create( + self.apiclient, + self.testdata["account"], + domainid=self.domain.id + ) + #create a service offering + self.service_offering = ServiceOffering.create( + self.apiclient, + self.testdata["service_offering"]["hasmall"] + ) + #deploy ha vm + self.virtual_machine = VirtualMachine.create( + self.apiclient, + self.testdata["virtual_machine"], + accountid=self.account.name, + zoneid=self.zone.id, + domainid=self.account.domainid, + serviceofferingid=self.service_offering.id, + templateid=self.template.id + ) + list_vms = VirtualMachine.list(self.apiclient, id=self.virtual_machine.id) + self.debug( + "Verify listVirtualMachines response for virtual machine: %s"\ + % self.virtual_machine.id + ) + self.assertTrue(isinstance(list_vms, list) and len(list_vms) == 1, msg = "List VM response was empty") + self.virtual_machine = list_vms[0] + + self.mock_checkhealth = SimulatorMock.create( + apiclient=self.apiclient, + command="CheckHealthCommand", + zoneid=suitablecluster.zoneid, + podid=suitablecluster.podid, + clusterid=suitablecluster.id, + hostid=self.virtual_machine.hostid, + value="result:fail") + self.mock_ping = SimulatorMock.create( + apiclient=self.apiclient, + command="PingCommand", + zoneid=suitablecluster.zoneid, + podid=suitablecluster.podid, + clusterid=suitablecluster.id, + hostid=self.virtual_machine.hostid, + value="result:fail") + self.mock_checkvirtualmachine = SimulatorMock.create( + apiclient=self.apiclient, + command="CheckVirtualMachineCommand", + zoneid=suitablecluster.zoneid, + podid=suitablecluster.podid, + clusterid=suitablecluster.id, + hostid=self.virtual_machine.hostid, + value="result:fail") + self.mock_pingtest = SimulatorMock.create( + apiclient=self.apiclient, + command="PingTestCommand", + zoneid=suitablecluster.zoneid, + podid=suitablecluster.podid, + value="result:fail") + self.mock_checkonhost_list = [] + for host in self.hosts: + if host.id != self.virtual_machine.hostid: + self.mock_checkonhost_list.append(SimulatorMock.create( + apiclient=self.apiclient, + command="CheckOnHostCommand", + zoneid=suitablecluster.zoneid, + podid=suitablecluster.podid, + clusterid=suitablecluster.id, + hostid=host.id, + value="result:fail")) + #build cleanup list + self.cleanup = [ + self.service_offering, + self.account, + self.mock_checkhealth, + self.mock_ping, + self.mock_checkvirtualmachine, + self.mock_pingtest + ] + self.cleanup = self.cleanup + self.mock_checkonhost_list + + @attr(tags = ['selfservice']) + def test_vm_ha(self): + """Test VM HA + + # Validate the following: + # VM started on other host in cluster + """ + + #wait for VM to HA + ping_timeout = Configurations.list(self.apiclient, name="ping.timeout") + ping_interval = Configurations.list(self.apiclient, name="ping.interval") + total_duration = int(float(ping_timeout[0].value) * float(ping_interval[0].value)) + time.sleep(total_duration) + + duration = 0 + vm = None + while duration < total_duration: + list_vms = VirtualMachine.list(self.apiclient, id=self.virtual_machine.id) + self.assertTrue(isinstance(list_vms, list) and len(list_vms) == 1, msg = "List VM response was empty") + vm = list_vms[0] + if vm.hostid != self.virtual_machine.hostid: + break + else: + time.sleep(10) + duration = duration + 10 + + self.assertEqual( + vm.id, + self.virtual_machine.id, + "VM ids do not match") + self.assertEqual( + vm.name, + self.virtual_machine.name, + "VM names do not match") + self.assertEqual( + vm.state, + "Running", + msg="VM is not in Running state") + self.assertNotEqual( + vm.hostid, + self.virtual_machine.hostid, + msg="VM is not started on another host as part of HA") + + def tearDown(self): + try: + for host in self.hosts: + Host.update(self.apiclient, id=host.id, hosttags="") + + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + self.debug("Warning! Exception in tearDown: %s" % e) +
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/70651571/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 775b289..e055df8 100755 --- a/tools/marvin/marvin/integration/lib/base.py +++ b/tools/marvin/marvin/integration/lib/base.py @@ -1462,6 +1462,9 @@ class ServiceOffering: if "tags" in services: cmd.tags = services["tags"] + if "hosttags" in services: + cmd.hosttags = services["hosttags"] + if "deploymentplanner" in services: cmd.deploymentplanner = services["deploymentplanner"] @@ -1471,6 +1474,9 @@ class ServiceOffering: if "isvolatile" in services: cmd.isvolatile = services["isvolatile"] + if "offerha" in services: + cmd.offerha = services["offerha"] + # Service Offering private to that domain if domainid: cmd.domainid = domainid @@ -3834,4 +3840,50 @@ class IAMPolicy: cmd.id = self.id cmd.accounts = [str(acct.id) for acct in accts] apiclient.removeIAMPolicyFromAccount(cmd) - return + return + +class SimulatorMock: + """Manage simulator mock lifecycle""" + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, command, zoneid=None, podid=None, clusterid=None, hostid=None, value="result:fail", count=None, jsonresponse=None): + """Creates simulator mock""" + + cmd = configureSimulator.configureSimulatorCmd() + cmd.zoneid = zoneid + cmd.podid = podid + cmd.clusterid = clusterid + cmd.hostid = hostid + cmd.name = command + cmd.value = value + cmd.count = count + cmd.jsonresponse = jsonresponse + try: + simulatormock = apiclient.configureSimulator(cmd) + if simulatormock is not None: + return SimulatorMock(simulatormock.__dict__) + except Exception as e: + raise e + + def delete(self, apiclient): + """Removes simulator mock""" + + cmd = cleanupSimulatorMock.cleanupSimulatorMockCmd() + cmd.id = self.id + return apiclient.cleanupSimulatorMock(cmd) + + def query(self, apiclient): + """Queries simulator mock""" + + cmd = querySimulatorMock.querySimulatorMockCmd() + cmd.id = self.id + try: + simulatormock = apiclient.querySimulatorMock(cmd) + if simulatormock is not None: + return SimulatorMock(simulatormock.__dict__) + except Exception as e: + raise e + +
