| # 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. | |
| """ P1 tests for dedicated Host high availability | |
| """ | |
| #Import Local Modules | |
| from nose.plugins.attrib import attr | |
| from marvin.cloudstackTestCase import cloudstackTestCase | |
| import unittest | |
| from marvin.cloudstackAPI import (migrateVirtualMachine, | |
| prepareHostForMaintenance, | |
| cancelHostMaintenance) | |
| from marvin.lib.utils import cleanup_resources | |
| from marvin.lib.base import (Account, | |
| VirtualMachine, | |
| ServiceOffering, | |
| Cluster, | |
| Host, | |
| Configurations) | |
| from marvin.lib.common import (get_zone, | |
| get_domain, | |
| get_template, | |
| list_hosts, | |
| list_virtual_machines, | |
| list_service_offering) | |
| import time | |
| class Services: | |
| """ Dedicated host HA test cases """ | |
| def __init__(self): | |
| self.services = { | |
| "account": { | |
| "email": "test@test.com", | |
| "firstname": "HA", | |
| "lastname": "HA", | |
| "username": "HA", | |
| # Random characters are appended for unique | |
| # username | |
| "password": "password", | |
| }, | |
| "service_offering_with_ha": { | |
| "name": "Tiny Instance With HA Enabled", | |
| "displaytext": "Tiny Instance", | |
| "cpunumber": 1, | |
| "cpuspeed": 100, # in MHz | |
| "memory": 128, # In MBs | |
| }, | |
| "service_offering_without_ha": { | |
| "name": "Tiny Instance Without HA", | |
| "displaytext": "Tiny Instance", | |
| "cpunumber": 1, | |
| "cpuspeed": 100, # in MHz | |
| "memory": 128, # In MBs | |
| }, | |
| "virtual_machine": { | |
| "displayname": "VM", | |
| "username": "root", | |
| "password": "password", | |
| "ssh_port": 22, | |
| "hypervisor": 'XenServer', | |
| # Hypervisor type should be same as | |
| # hypervisor type of cluster | |
| "privateport": 22, | |
| "publicport": 22, | |
| "protocol": 'TCP', | |
| }, | |
| "ostype": 'CentOS 5.3 (64-bit)', | |
| "timeout": 100, | |
| } | |
| class TestHostHighAvailability(cloudstackTestCase): | |
| """ Dedicated host HA test cases """ | |
| @classmethod | |
| def setUpClass(cls): | |
| cls.testClient = super(TestHostHighAvailability, cls).getClsTestClient() | |
| cls.api_client = cls.testClient.getApiClient() | |
| cls.services = Services().services | |
| # Get Zone, Domain and templates | |
| cls.domain = get_domain(cls.api_client) | |
| cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests()) | |
| cls.template = get_template( | |
| cls.api_client, | |
| cls.zone.id, | |
| cls.services["ostype"] | |
| ) | |
| cls.hypervisor = cls.testClient.getHypervisorInfo() | |
| if cls.hypervisor.lower() in ['lxc']: | |
| raise unittest.SkipTest("Template creation from root volume is not supported in LXC") | |
| clusterWithSufficientHosts = None | |
| clusters = Cluster.list(cls.api_client, zoneid=cls.zone.id) | |
| for cluster in clusters: | |
| cls.hosts = Host.list(cls.api_client, clusterid=cluster.id, type="Routing") | |
| if len(cls.hosts) >= 3: | |
| clusterWithSufficientHosts = cluster | |
| break | |
| if clusterWithSufficientHosts is None: | |
| raise unittest.SkipTest("No Cluster with 3 hosts found") | |
| configs = Configurations.list( | |
| cls.api_client, | |
| name='ha.tag' | |
| ) | |
| assert isinstance(configs, list), "Config list not\ | |
| retrieved for ha.tag" | |
| if configs[0].value != "ha": | |
| raise unittest.SkipTest("Please set the global config\ | |
| value for ha.tag as 'ha'") | |
| Host.update(cls.api_client, id=cls.hosts[2].id, hosttags="ha") | |
| cls.services["virtual_machine"]["zoneid"] = cls.zone.id | |
| cls.services["virtual_machine"]["template"] = cls.template.id | |
| cls.service_offering_with_ha = ServiceOffering.create( | |
| cls.api_client, | |
| cls.services["service_offering_with_ha"], | |
| offerha=True | |
| ) | |
| cls.service_offering_without_ha = ServiceOffering.create( | |
| cls.api_client, | |
| cls.services["service_offering_without_ha"], | |
| offerha=False | |
| ) | |
| cls._cleanup = [ | |
| cls.service_offering_with_ha, | |
| cls.service_offering_without_ha, | |
| ] | |
| return | |
| @classmethod | |
| def tearDownClass(cls): | |
| try: | |
| # Remove the host from HA | |
| Host.update(cls.api_client, id=cls.hosts[2].id, hosttags="") | |
| #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.account = Account.create( | |
| self.apiclient, | |
| self.services["account"], | |
| admin=True, | |
| domainid=self.domain.id | |
| ) | |
| self.cleanup = [self.account] | |
| return | |
| def tearDown(self): | |
| try: | |
| #Clean up, terminate the created accounts, domains etc | |
| cleanup_resources(self.apiclient, self.cleanup) | |
| except Exception as e: | |
| raise Exception("Warning: Exception during cleanup : %s" % e) | |
| return | |
| @attr(configuration="ha.tag") | |
| @attr(tags=["advanced", "advancedns", "sg", "basic", "eip", "simulator"]) | |
| def test_01_vm_deployment_with_compute_offering_with_ha_enabled(self): | |
| """ Test VM deployments (Create HA enabled Compute Service Offering and VM) """ | |
| # Steps, | |
| #1. Create a Compute service offering with the 'Offer HA' option selected. | |
| #2. Create a Guest VM with the compute service offering created above. | |
| # Validations, | |
| #1. Ensure that the offering is created and that in the UI the 'Offer HA' field is enabled (Yes) | |
| #The listServiceOffering API should list 'offerha' as true. | |
| #2. Select the newly created VM and ensure that the Compute offering field value lists the compute service offering that was selected. | |
| # Also, check that the HA Enabled field is enabled 'Yes'. | |
| #list and validate above created service offering with Ha enabled | |
| list_service_response = list_service_offering( | |
| self.apiclient, | |
| id=self.service_offering_with_ha.id | |
| ) | |
| self.assertEqual( | |
| isinstance(list_service_response, list), | |
| True, | |
| "listServiceOfferings returned invalid object in response." | |
| ) | |
| self.assertNotEqual( | |
| len(list_service_response), | |
| 0, | |
| "listServiceOfferings returned empty list." | |
| ) | |
| self.assertEqual( | |
| list_service_response[0].offerha, | |
| True, | |
| "The service offering is not HA enabled" | |
| ) | |
| #create virtual machine with the service offering with Ha enabled | |
| virtual_machine = VirtualMachine.create( | |
| self.apiclient, | |
| self.services["virtual_machine"], | |
| accountid=self.account.name, | |
| domainid=self.account.domainid, | |
| serviceofferingid=self.service_offering_with_ha.id | |
| ) | |
| vms = VirtualMachine.list( | |
| self.apiclient, | |
| id=virtual_machine.id, | |
| listall=True | |
| ) | |
| self.assertEqual( | |
| isinstance(vms, list), | |
| True, | |
| "listVirtualMachines returned invalid object in response." | |
| ) | |
| self.assertNotEqual( | |
| len(vms), | |
| 0, | |
| "listVirtualMachines returned empty list." | |
| ) | |
| self.debug("Deployed VM on host: %s" % vms[0].hostid) | |
| self.assertEqual( | |
| vms[0].haenable, | |
| True, | |
| "VM not created with HA enable tag" | |
| ) | |
| @attr(configuration="ha.tag") | |
| @attr(tags=["advanced", "advancedns", "sg", "basic", "eip", "simulator", "multihost"]) | |
| def test_02_no_vm_creation_on_host_with_haenabled(self): | |
| """ Verify you can not create new VMs on hosts with an ha.tag """ | |
| # Steps, | |
| #1. Fresh install CS (Bonita) that supports this feature | |
| #2. Create Basic zone, pod, cluster, add 3 hosts to cluster (host1, host2, host3), secondary & primary Storage | |
| #3. When adding host3, assign the HA host tag. | |
| #4. You should already have a compute service offering with HA already create from above. If not, create one for HA. | |
| #5. Create VMs with the service offering with and without the HA tag | |
| # Validations, | |
| #Check to make sure the newly created VM is not on any HA enabled hosts | |
| #The VM should be created only on host1 or host2 and never host3 (HA enabled) | |
| #create and verify virtual machine with HA enabled service offering | |
| virtual_machine_with_ha = VirtualMachine.create( | |
| self.apiclient, | |
| self.services["virtual_machine"], | |
| accountid=self.account.name, | |
| domainid=self.account.domainid, | |
| serviceofferingid=self.service_offering_with_ha.id | |
| ) | |
| vms = VirtualMachine.list( | |
| self.apiclient, | |
| id=virtual_machine_with_ha.id, | |
| listall=True | |
| ) | |
| self.assertEqual( | |
| isinstance(vms, list), | |
| True, | |
| "listVirtualMachines returned invalid object in response." | |
| ) | |
| self.assertNotEqual( | |
| len(vms), | |
| 0, | |
| "listVirtualMachines returned empty list." | |
| ) | |
| vm = vms[0] | |
| self.debug("Deployed VM on host: %s" % vm.hostid) | |
| #validate the virtual machine created is host Ha enabled | |
| list_hosts_response = list_hosts( | |
| self.apiclient, | |
| id=vm.hostid | |
| ) | |
| self.assertEqual( | |
| isinstance(list_hosts_response, list), | |
| True, | |
| "listHosts returned invalid object in response." | |
| ) | |
| self.assertNotEqual( | |
| len(list_hosts_response), | |
| 0, | |
| "listHosts retuned empty list in response." | |
| ) | |
| self.assertEqual( | |
| list_hosts_response[0].hahost, | |
| False, | |
| "VM created on HA enabled host." | |
| ) | |
| #create and verify virtual machine with Ha disabled service offering | |
| virtual_machine_without_ha = VirtualMachine.create( | |
| self.apiclient, | |
| self.services["virtual_machine"], | |
| accountid=self.account.name, | |
| domainid=self.account.domainid, | |
| serviceofferingid=self.service_offering_without_ha.id | |
| ) | |
| vms = VirtualMachine.list( | |
| self.apiclient, | |
| id=virtual_machine_without_ha.id, | |
| listall=True | |
| ) | |
| self.assertEqual( | |
| isinstance(vms, list), | |
| True, | |
| "listVirtualMachines returned invalid object in response." | |
| ) | |
| self.assertNotEqual( | |
| len(vms), | |
| 0, | |
| "listVirtualMachines returned empty list." | |
| ) | |
| vm = vms[0] | |
| self.debug("Deployed VM on host: %s" % vm.hostid) | |
| #verify that the virtual machine created on the host is Ha disabled | |
| list_hosts_response = list_hosts( | |
| self.apiclient, | |
| id=vm.hostid | |
| ) | |
| self.assertEqual( | |
| isinstance(list_hosts_response, list), | |
| True, | |
| "listHosts returned invalid object in response." | |
| ) | |
| self.assertNotEqual( | |
| len(list_hosts_response), | |
| 0, | |
| "listHosts returned empty list." | |
| ) | |
| host = list_hosts_response[0] | |
| self.assertEqual( | |
| host.hahost, | |
| False, | |
| "VM migrated to HA enabled host." | |
| ) | |
| @attr(configuration="ha.tag") | |
| @attr(tags=["advanced", "advancedns", "sg", "basic", "eip", "simulator", "multihost"]) | |
| def test_03_cant_migrate_vm_to_host_with_ha_positive(self): | |
| """ Verify you can not migrate VMs to hosts with an ha.tag (positive) """ | |
| # Steps, | |
| # 1. Create a Compute service offering with the 'Offer HA' option selected. | |
| # 2. Create a Guest VM with the compute service offering created above. | |
| # 3. Select the VM and migrate VM to another host. Choose a 'Suitable' host (i.e. host2) | |
| # Validations | |
| # The option from the 'Migrate instance to another host' dialog box' should list host3 as 'Not Suitable' for migration. | |
| # Confirm that the VM is migrated to the 'Suitable' host you selected | |
| # (i.e. host2) | |
| # create and verify the virtual machine with HA enabled service | |
| # offering | |
| self.hypervisor = self.testClient.getHypervisorInfo() | |
| if self.hypervisor.lower() in ['lxc']: | |
| self.skipTest("vm migrate is not supported in %s" % self.hypervisor) | |
| virtual_machine_with_ha = VirtualMachine.create( | |
| self.apiclient, | |
| self.services["virtual_machine"], | |
| accountid=self.account.name, | |
| domainid=self.account.domainid, | |
| serviceofferingid=self.service_offering_with_ha.id | |
| ) | |
| vms = VirtualMachine.list( | |
| self.apiclient, | |
| id=virtual_machine_with_ha.id, | |
| listall=True, | |
| ) | |
| self.assertEqual( | |
| isinstance(vms, list), | |
| True, | |
| "List VMs should return valid response for deployed VM" | |
| ) | |
| self.assertNotEqual( | |
| len(vms), | |
| 0, | |
| "List VMs should return valid response for deployed VM" | |
| ) | |
| vm = vms[0] | |
| self.debug("Deployed VM on host: %s" % vm.hostid) | |
| # Find out a Suitable host for VM migration | |
| list_hosts_response = list_hosts( | |
| self.apiclient, | |
| virtualmachineid = vm.id | |
| ) | |
| self.assertEqual( | |
| isinstance(list_hosts_response, list), | |
| True, | |
| "The listHosts API returned the invalid list" | |
| ) | |
| self.assertNotEqual( | |
| len(list_hosts_response), | |
| 0, | |
| "The listHosts returned nothing." | |
| ) | |
| suitableHost = None | |
| for host in list_hosts_response: | |
| if host.suitableformigration and host.hostid != vm.hostid: | |
| suitableHost = host | |
| break | |
| self.assertTrue( | |
| suitableHost is not None, | |
| "suitablehost should not be None") | |
| # Migration of the VM to a suitable host | |
| self.debug( | |
| "Migrating VM-ID: %s to Host: %s" % | |
| (vm.id, suitableHost.id)) | |
| cmd = migrateVirtualMachine.migrateVirtualMachineCmd() | |
| cmd.hostid = suitableHost.id | |
| cmd.virtualmachineid = vm.id | |
| self.apiclient.migrateVirtualMachine(cmd) | |
| # Verify that the VM migrated to a targeted Suitable host | |
| list_vm_response = list_virtual_machines( | |
| self.apiclient, | |
| id=vm.id | |
| ) | |
| self.assertEqual( | |
| isinstance(list_vm_response, list), | |
| True, | |
| "The listVirtualMachines returned the invalid list." | |
| ) | |
| self.assertNotEqual( | |
| list_vm_response, | |
| None, | |
| "The listVirtualMachines API returned nothing." | |
| ) | |
| vm_response = list_vm_response[0] | |
| self.assertEqual( | |
| vm_response.id, | |
| vm.id, | |
| "The virtual machine id and the virtual machine from listVirtualMachines is not matching." | |
| ) | |
| self.assertEqual( | |
| vm_response.hostid, | |
| suitableHost.id, | |
| "The VM is not migrated to targeted suitable host." | |
| ) | |
| @attr(configuration="ha.tag") | |
| @attr(tags=["advanced", "advancedns", "sg", "basic", "eip", "simulator", "multihost"]) | |
| def test_04_cant_migrate_vm_to_host_with_ha_negative(self): | |
| """ Verify you can not migrate VMs to hosts with an ha.tag (negative) """ | |
| # Steps, | |
| #1. Create a Compute service offering with the 'Offer HA' option selected. | |
| #2. Create a Guest VM with the compute service offering created above. | |
| #3. Select the VM and migrate VM to another host. Choose a 'Not Suitable' host. | |
| # Validations, | |
| #The option from the 'Migrate instance to another host' dialog box should list host3 as 'Not Suitable' for migration. | |
| #By design, The Guest VM can STILL can be migrated to host3 if the admin chooses to do so. | |
| #create and verify virtual machine with HA enabled service offering | |
| self.hypervisor = self.testClient.getHypervisorInfo() | |
| if self.hypervisor.lower() in ['lxc']: | |
| self.skipTest("vm migrate is not supported in %s" % self.hypervisor) | |
| virtual_machine_with_ha = VirtualMachine.create( | |
| self.apiclient, | |
| self.services["virtual_machine"], | |
| accountid=self.account.name, | |
| domainid=self.account.domainid, | |
| serviceofferingid=self.service_offering_with_ha.id | |
| ) | |
| vms = VirtualMachine.list( | |
| self.apiclient, | |
| id=virtual_machine_with_ha.id, | |
| listall=True | |
| ) | |
| self.assertEqual( | |
| isinstance(vms, list), | |
| True, | |
| "The listVirtualMachines returned invalid object in response." | |
| ) | |
| self.assertNotEqual( | |
| len(vms), | |
| 0, | |
| "The listVirtualMachines returned empty response." | |
| ) | |
| vm = vms[0] | |
| self.debug("Deployed VM on host: %s" % vm.hostid) | |
| #Find out Non-Suitable host for VM migration | |
| list_hosts_response = list_hosts( | |
| self.apiclient, | |
| type="Routing" | |
| ) | |
| self.assertEqual( | |
| isinstance(list_hosts_response, list), | |
| True, | |
| "listHosts returned invalid object in response." | |
| ) | |
| self.assertNotEqual( | |
| len(list_hosts_response), | |
| 0, | |
| "listHosts returned empty response." | |
| ) | |
| notSuitableHost = None | |
| for host in list_hosts_response: | |
| if not host.suitableformigration and host.id != vm.hostid: | |
| notSuitableHost = host | |
| break | |
| self.assertTrue(notSuitableHost is not None, "notsuitablehost should not be None") | |
| #Migrate VM to Non-Suitable host | |
| self.debug("Migrating VM-ID: %s to Host: %s" % (vm.id, notSuitableHost.id)) | |
| cmd = migrateVirtualMachine.migrateVirtualMachineCmd() | |
| cmd.hostid = notSuitableHost.id | |
| cmd.virtualmachineid = vm.id | |
| self.apiclient.migrateVirtualMachine(cmd) | |
| #Verify that the virtual machine got migrated to targeted Non-Suitable host | |
| list_vm_response = list_virtual_machines( | |
| self.apiclient, | |
| id=vm.id | |
| ) | |
| self.assertEqual( | |
| isinstance(list_vm_response, list), | |
| True, | |
| "listVirtualMachine returned invalid object in response." | |
| ) | |
| self.assertNotEqual( | |
| len(list_vm_response), | |
| 0, | |
| "listVirtualMachines returned empty response." | |
| ) | |
| self.assertEqual( | |
| list_vm_response[0].id, | |
| vm.id, | |
| "Virtual machine id with the virtual machine from listVirtualMachine is not matching." | |
| ) | |
| self.assertEqual( | |
| list_vm_response[0].hostid, | |
| notSuitableHost.id, | |
| "The detination host id of migrated VM is not matching." | |
| ) | |
| @attr(configuration="ha.tag") | |
| @attr(speed="slow") | |
| @attr(tags=["advanced", "advancedns", "sg", "basic", "eip", "simulator", "multihost"]) | |
| def test_05_no_vm_with_ha_gets_migrated_to_ha_host_in_live_migration(self): | |
| """ Verify that none of the VMs with HA enabled migrate to an ha tagged host during live migration """ | |
| # Steps, | |
| #1. Fresh install CS that supports this feature | |
| #2. Create Basic zone, pod, cluster, add 3 hosts to cluster (host1, host2, host3), secondary & primary Storage | |
| #3. When adding host3, assign the HA host tag. | |
| #4. Create VMs with and without the Compute Service Offering with the HA tag. | |
| #5. Note the VMs on host1 and whether any of the VMs have their 'HA enabled' flags enabled. | |
| #6. Put host1 into maintenance mode. | |
| # Validations, | |
| #1. Make sure the VMs are created on either host1 or host2 and not on host3 | |
| #2. Putting host1 into maintenance mode should trigger a live migration. Make sure the VMs are not migrated to HA enabled host3. | |
| # create and verify virtual machine with HA disabled service offering | |
| self.hypervisor = self.testClient.getHypervisorInfo() | |
| if self.hypervisor.lower() in ['lxc']: | |
| self.skipTest("vm migrate is not supported in %s" % self.hypervisor) | |
| virtual_machine_with_ha = VirtualMachine.create( | |
| self.apiclient, | |
| self.services["virtual_machine"], | |
| accountid=self.account.name, | |
| domainid=self.account.domainid, | |
| serviceofferingid=self.service_offering_with_ha.id | |
| ) | |
| vms = VirtualMachine.list( | |
| self.apiclient, | |
| id=virtual_machine_with_ha.id, | |
| listall=True | |
| ) | |
| self.assertEqual( | |
| isinstance(vms, list), | |
| True, | |
| "List VMs should return valid response for deployed VM" | |
| ) | |
| self.assertNotEqual( | |
| len(vms), | |
| 0, | |
| "List VMs should return valid response for deployed VM" | |
| ) | |
| vm_with_ha_enabled = vms[0] | |
| #Verify the virtual machine got created on non HA host | |
| list_hosts_response = list_hosts( | |
| self.apiclient, | |
| id=vm_with_ha_enabled.hostid | |
| ) | |
| self.assertEqual( | |
| isinstance(list_hosts_response, list), | |
| True, | |
| "Check list response returns a valid list" | |
| ) | |
| self.assertNotEqual( | |
| len(list_hosts_response), | |
| 0, | |
| "Check Host is available" | |
| ) | |
| self.assertEqual( | |
| list_hosts_response[0].hahost, | |
| False, | |
| "The virtual machine is not ha enabled so check if VM is created on host which is also not ha enabled" | |
| ) | |
| #put the Host in maintenance mode | |
| self.debug("Enabling maintenance mode for host %s" % vm_with_ha_enabled.hostid) | |
| cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd() | |
| cmd.id = vm_with_ha_enabled.hostid | |
| self.apiclient.prepareHostForMaintenance(cmd) | |
| timeout = self.services["timeout"] | |
| #verify the VM live migration happened to another running host | |
| self.debug("Waiting for VM to come up") | |
| time.sleep(timeout) | |
| vms = VirtualMachine.list( | |
| self.apiclient, | |
| id=vm_with_ha_enabled.id, | |
| listall=True, | |
| ) | |
| self.assertEqual( | |
| isinstance(vms, list), | |
| True, | |
| "List VMs should return valid response for deployed VM" | |
| ) | |
| self.assertNotEqual( | |
| len(vms), | |
| 0, | |
| "List VMs should return valid response for deployed VM" | |
| ) | |
| vm_with_ha_enabled1 = vms[0] | |
| list_hosts_response = list_hosts( | |
| self.apiclient, | |
| id=vm_with_ha_enabled1.hostid | |
| ) | |
| self.assertEqual( | |
| isinstance(list_hosts_response, list), | |
| True, | |
| "Check list response returns a valid list" | |
| ) | |
| self.assertNotEqual( | |
| len(list_hosts_response), | |
| 0, | |
| "Check Host is available" | |
| ) | |
| self.assertEqual( | |
| list_hosts_response[0].hahost, | |
| False, | |
| "The virtual machine is not ha enabled so check if VM is created on host which is also not ha enabled" | |
| ) | |
| self.debug("Disabling the maintenance mode for host %s" % vm_with_ha_enabled.hostid) | |
| cmd = cancelHostMaintenance.cancelHostMaintenanceCmd() | |
| cmd.id = vm_with_ha_enabled.hostid | |
| self.apiclient.cancelHostMaintenance(cmd) | |
| @attr(configuration="ha.tag") | |
| @attr(speed="slow") | |
| @attr(tags=["advanced", "advancedns", "sg", "basic", "eip", "simulator", "multihost"]) | |
| def test_06_no_vm_without_ha_gets_migrated_to_ha_host_in_live_migration(self): | |
| """ Verify that none of the VMs without HA enabled migrate to an ha tagged host during live migration """ | |
| # Steps, | |
| #1. Fresh install CS that supports this feature | |
| #2. Create Basic zone, pod, cluster, add 3 hosts to cluster (host1, host2, host3), secondary & primary Storage | |
| #3. When adding host3, assign the HA host tag. | |
| #4. Create VMs with and without the Compute Service Offering with the HA tag. | |
| #5. Note the VMs on host1 and whether any of the VMs have their 'HA enabled' flags enabled. | |
| #6. Put host1 into maintenance mode. | |
| # Validations, | |
| #1. Make sure the VMs are created on either host1 or host2 and not on host3 | |
| #2. Putting host1 into maintenance mode should trigger a live migration. Make sure the VMs are not migrated to HA enabled host3. | |
| # create and verify virtual machine with HA disabled service offering | |
| self.hypervisor = self.testClient.getHypervisorInfo() | |
| if self.hypervisor.lower() in ['lxc']: | |
| self.skipTest("vm migrate is not supported in %s" % self.hypervisor) | |
| virtual_machine_without_ha = VirtualMachine.create( | |
| self.apiclient, | |
| self.services["virtual_machine"], | |
| accountid=self.account.name, | |
| domainid=self.account.domainid, | |
| serviceofferingid=self.service_offering_without_ha.id | |
| ) | |
| vms = VirtualMachine.list( | |
| self.apiclient, | |
| id=virtual_machine_without_ha.id, | |
| listall=True | |
| ) | |
| self.assertEqual( | |
| isinstance(vms, list), | |
| True, | |
| "List VMs should return valid response for deployed VM" | |
| ) | |
| self.assertNotEqual( | |
| len(vms), | |
| 0, | |
| "List VMs should return valid response for deployed VM" | |
| ) | |
| vm_with_ha_disabled = vms[0] | |
| #Verify the virtual machine got created on non HA host | |
| list_hosts_response = list_hosts( | |
| self.apiclient, | |
| id=vm_with_ha_disabled.hostid | |
| ) | |
| self.assertEqual( | |
| isinstance(list_hosts_response, list), | |
| True, | |
| "Check list response returns a valid list" | |
| ) | |
| self.assertNotEqual( | |
| len(list_hosts_response), | |
| 0, | |
| "Check Host is available" | |
| ) | |
| self.assertEqual( | |
| list_hosts_response[0].hahost, | |
| False, | |
| "The virtual machine is not ha enabled so check if VM is created on host which is also not ha enabled" | |
| ) | |
| #put the Host in maintenance mode | |
| self.debug("Enabling maintenance mode for host %s" % vm_with_ha_disabled.hostid) | |
| cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd() | |
| cmd.id = vm_with_ha_disabled.hostid | |
| self.apiclient.prepareHostForMaintenance(cmd) | |
| timeout = self.services["timeout"] | |
| #verify the VM live migration happened to another running host | |
| self.debug("Waiting for VM to come up") | |
| time.sleep(timeout) | |
| vms = VirtualMachine.list( | |
| self.apiclient, | |
| id=vm_with_ha_disabled.id, | |
| listall=True | |
| ) | |
| self.assertEqual( | |
| isinstance(vms, list), | |
| True, | |
| "List VMs should return valid response for deployed VM" | |
| ) | |
| self.assertNotEqual( | |
| len(vms), | |
| 0, | |
| "List VMs should return valid response for deployed VM" | |
| ) | |
| list_hosts_response = list_hosts( | |
| self.apiclient, | |
| id=vms[0].hostid | |
| ) | |
| self.assertEqual( | |
| isinstance(list_hosts_response, list), | |
| True, | |
| "Check list response returns a valid list" | |
| ) | |
| self.assertNotEqual( | |
| len(list_hosts_response), | |
| 0, | |
| "Check Host is available" | |
| ) | |
| self.assertEqual( | |
| list_hosts_response[0].hahost, | |
| False, | |
| "The virtual machine is not ha enabled so check if VM is created on host which is also not ha enabled" | |
| ) | |
| self.debug("Disabling the maintenance mode for host %s" % vm_with_ha_disabled.hostid) | |
| cmd = cancelHostMaintenance.cancelHostMaintenanceCmd() | |
| cmd.id = vm_with_ha_disabled.hostid | |
| self.apiclient.cancelHostMaintenance(cmd) |