blob: 1b9b0c02c709cbedad0f2f8e20ccb506faa609bc [file] [log] [blame]
# 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.
"""
Tests of Non-Strict (host anti-affinity and host affinity) affinity groups
"""
import logging
from marvin.codes import FAILED
from nose.plugins.attrib import attr
from marvin.cloudstackTestCase import cloudstackTestCase
from marvin.cloudstackAPI import startVirtualMachine, stopVirtualMachine, destroyVirtualMachine
from marvin.lib.base import (Account,
AffinityGroup,
Domain,
Host,
ServiceOffering,
VirtualMachine,
Zone,
Network,
NetworkOffering)
from marvin.lib.common import (get_domain,
get_zone,
get_template,
get_test_template)
class TestNonStrictAffinityGroups(cloudstackTestCase):
"""
Test Non-Strict (host anti-affinity and host affinity) affinity groups
"""
@classmethod
def setUpClass(cls):
cls.testClient = super(
TestNonStrictAffinityGroups,
cls).getClsTestClient()
cls.apiclient = cls.testClient.getApiClient()
cls.services = cls.testClient.getParsedTestDataConfig()
zone = get_zone(cls.apiclient, cls.testClient.getZoneForTests())
cls.zone = Zone(zone.__dict__)
cls.hypervisor = cls.testClient.getHypervisorInfo()
cls.template = get_test_template(cls.apiclient, cls.zone.id, cls.hypervisor)
if cls.template == FAILED:
assert False, "get_test_template() failed to return template\
with hypervisor %s" % cls.hypervisor
cls._cleanup = []
cls.logger = logging.getLogger("TestNonStrictAffinityGroups")
cls.stream_handler = logging.StreamHandler()
cls.logger.setLevel(logging.DEBUG)
cls.logger.addHandler(cls.stream_handler)
cls.skipTests = False
hosts = Host.list(
cls.apiclient,
zoneid=cls.zone.id,
state='Up',
resourcestate='Enabled'
)
if not hosts or not isinstance(hosts, list) or len(hosts) < 2:
cls.logger.debug("This test requires at least two (Up and Enabled) hosts in the zone")
cls.skipTests = True
return
cls.domain = get_domain(cls.apiclient)
# 1. Create small service offering
cls.service_offering = ServiceOffering.create(
cls.apiclient,
cls.services["service_offerings"]["small"]
)
cls._cleanup.append(cls.service_offering)
# 3. Create network offering for isolated networks
cls.network_offering_isolated = NetworkOffering.create(
cls.apiclient,
cls.services["isolated_network_offering"]
)
cls.network_offering_isolated.update(cls.apiclient, state='Enabled')
cls._cleanup.append(cls.network_offering_isolated)
# 4. Create sub-domain
cls.sub_domain = Domain.create(
cls.apiclient,
cls.services["acl"]["domain1"]
)
cls._cleanup.append(cls.sub_domain)
# 5. Create regular user
cls.regular_user = Account.create(
cls.apiclient,
cls.services["acl"]["accountD11A"],
domainid=cls.sub_domain.id
)
cls._cleanup.append(cls.regular_user)
# 5. Create api clients for regular user
cls.regular_user_user = cls.regular_user.user[0]
cls.regular_user_apiclient = cls.testClient.getUserApiClient(
cls.regular_user_user.username, cls.sub_domain.name
)
# 7. Create network for regular user
cls.services["network"]["name"] = "Test Network Isolated - Regular user"
cls.user_network = Network.create(
cls.regular_user_apiclient,
cls.services["network"],
networkofferingid=cls.network_offering_isolated.id,
zoneid=cls.zone.id
)
@classmethod
def tearDownClass(cls):
super(TestNonStrictAffinityGroups, cls).tearDownClass()
def setUp(self):
if self.skipTests:
self.skipTest("This test requires at least two (Up and Enabled) hosts in the zone")
self.apiclient = self.testClient.getApiClient()
self.cleanup = []
def tearDown(self):
super(TestNonStrictAffinityGroups, self).tearDown()
@classmethod
def get_vm_host_id(cls, vm_id):
list_vms = VirtualMachine.list(
cls.apiclient,
id=vm_id
)
vm = list_vms[0]
return vm.hostid
@attr(tags=["advanced"], required_hardware="false")
def test_01_non_strict_host_anti_affinity(self):
""" Verify Non-Strict host anti-affinity """
# 1. Create Non-Strict host anti-affinity
# 2. Deploy vm-1 with the group
# 3. Deploy vm-2 with the group. It will be started on different host if there are multiple hosts.
# 4. Migrate vm-2 to same host as vm-1
# 5. Stop vm-2, start vm-2. It will be started on same host as vm-1
# 6. Stop vm-2, start vm-2 with considerlasthost=false. It will be started on different host as vm-1
# 7. Deploy vm-3 with same host, vm-3 should be started on specified host.
# 8. Deploy vm-4 with startvm=false, then start the VM.
# vm-4 should be started on different host if there are multiple hosts.
self.logger.debug("=== Running test_01_non_strict_host_anti_affinity ===")
# 1. Create Non-Strict host anti-affinity
affinity_group_params = {
"name": "Test affinity group",
"type": "non-strict host anti-affinity",
}
self.affinity_group = AffinityGroup.create(
self.regular_user_apiclient,
affinity_group_params
)
self.cleanup.append(self.affinity_group)
# 2. Deploy vm-1 with the group
self.services["virtual_machine"]["name"] = "virtual-machine-1"
self.services["virtual_machine"]["displayname"] = "virtual-machine-1"
self.virtual_machine_1 = VirtualMachine.create(
self.regular_user_apiclient,
self.services["virtual_machine"],
serviceofferingid=self.service_offering.id,
templateid=self.template.id,
zoneid=self.zone.id,
networkids=self.user_network.id,
affinitygroupids=self.affinity_group.id
)
self.cleanup.append(self.virtual_machine_1)
vm_1_host_id = self.get_vm_host_id(self.virtual_machine_1.id)
# 3. Deploy vm-2 with the group. It will be started on different host if there are multiple hosts.
self.services["virtual_machine"]["name"] = "virtual-machine-2"
self.services["virtual_machine"]["displayname"] = "virtual-machine-2"
self.virtual_machine_2 = VirtualMachine.create(
self.regular_user_apiclient,
self.services["virtual_machine"],
serviceofferingid=self.service_offering.id,
templateid=self.template.id,
zoneid=self.zone.id,
networkids=self.user_network.id,
affinitygroupids=self.affinity_group.id
)
vm_2_host_id = self.get_vm_host_id(self.virtual_machine_2.id)
self.assertNotEqual(vm_1_host_id,
vm_2_host_id,
msg="Both VMs of affinity group %s are on the same host" % self.affinity_group.name)
# 4. Migrate vm-2 to same host as vm-1
self.virtual_machine_2.migrate(
self.apiclient,
hostid=vm_1_host_id
)
# 5. Stop vm-2, start vm-2. It will be started on same host as vm-1
stopCmd = stopVirtualMachine.stopVirtualMachineCmd()
stopCmd.id = self.virtual_machine_2.id
stopCmd.forced = True
self.apiclient.stopVirtualMachine(stopCmd)
startCmd = startVirtualMachine.startVirtualMachineCmd()
startCmd.id = self.virtual_machine_2.id
self.apiclient.startVirtualMachine(startCmd)
vm_2_host_id = self.get_vm_host_id(self.virtual_machine_2.id)
self.assertEqual(vm_1_host_id,
vm_2_host_id,
msg="Both VMs of affinity group %s are on the different host" % self.affinity_group.name)
# 6. Stop vm-2, start vm-2 with considerlasthost=false. It will be started on different host as vm-1
stopCmd.id = self.virtual_machine_2.id
stopCmd.forced = True
self.apiclient.stopVirtualMachine(stopCmd)
startCmd = startVirtualMachine.startVirtualMachineCmd()
startCmd.id = self.virtual_machine_2.id
startCmd.considerlasthost = False
self.apiclient.startVirtualMachine(startCmd)
vm_2_host_id = self.get_vm_host_id(self.virtual_machine_2.id)
self.assertNotEqual(vm_1_host_id,
vm_2_host_id,
msg="Both VMs of affinity group %s are on the same host" % self.affinity_group.name)
destroyCmd = destroyVirtualMachine.destroyVirtualMachineCmd()
destroyCmd.id = self.virtual_machine_2.id
destroyCmd.expunge = True
self.apiclient.destroyVirtualMachine(destroyCmd)
# 7. Deploy vm-3 with same host, vm-3 should be started on specified host.
self.services["virtual_machine"]["name"] = "virtual-machine-3"
self.services["virtual_machine"]["displayname"] = "virtual-machine-3"
self.virtual_machine_3 = VirtualMachine.create(
self.apiclient,
self.services["virtual_machine"],
serviceofferingid=self.service_offering.id,
templateid=self.template.id,
zoneid=self.zone.id,
networkids=self.user_network.id,
affinitygroupids=self.affinity_group.id,
domainid=self.sub_domain.id,
accountid=self.regular_user.name,
hostid=vm_1_host_id
)
vm_3_host_id = self.get_vm_host_id(self.virtual_machine_3.id)
self.assertEqual(vm_1_host_id,
vm_3_host_id,
msg="virtual-machine-3 should be started on %s" % vm_1_host_id)
destroyCmd.id = self.virtual_machine_3.id
destroyCmd.expunge = True
self.apiclient.destroyVirtualMachine(destroyCmd)
# 8. Deploy vm-4 with startvm=false, then start the VM.
# vm-4 should be started on different host if there are multiple hosts.
self.services["virtual_machine"]["name"] = "virtual-machine-4"
self.services["virtual_machine"]["displayname"] = "virtual-machine-4"
self.virtual_machine_4 = VirtualMachine.create(
self.regular_user_apiclient,
self.services["virtual_machine"],
serviceofferingid=self.service_offering.id,
templateid=self.template.id,
zoneid=self.zone.id,
networkids=self.user_network.id,
affinitygroupids=self.affinity_group.id,
startvm=False
)
self.cleanup.append(self.virtual_machine_4)
startCmd.id = self.virtual_machine_4.id
startCmd.considerlasthost = None
self.apiclient.startVirtualMachine(startCmd)
vm_4_host_id = self.get_vm_host_id(self.virtual_machine_4.id)
self.assertNotEqual(vm_1_host_id,
vm_4_host_id,
msg="virtual-machine-4 should be not started on %s" % vm_1_host_id)
@attr(tags=["advanced"], required_hardware="false")
def test_02_non_strict_host_affinity(self):
""" Verify Non-Strict host affinity """
# 1. Create Non-Strict host affinity
# 2. Deploy vm-11 with the group
# 3. Deploy vm-12 with the group. It will be started on same host.
# 4. Migrate vm-12 to different host as vm-11
# 5. Stop vm-12, start vm-12. It will be started on different host as vm-11
# 6. Stop vm-12, start vm-12 with considerlasthost=false. It will be started on same host as vm-11
# 7. Deploy vm-13 with different host, vm-13 should be started on specified host.
# 8. Deploy vm-14 with startvm=false, then start the VM. vm-14 should be started on same host.
self.logger.debug("=== Running test_02_non_strict_host_affinity ===")
# 1. Create Non-Strict host affinity
affinity_group_params = {
"name": "Test affinity group",
"type": "non-strict host affinity",
}
self.affinity_group = AffinityGroup.create(
self.regular_user_apiclient,
affinity_group_params
)
self.cleanup.append(self.affinity_group)
# 2. Deploy vm-11 with the group
self.services["virtual_machine"]["name"] = "virtual-machine-11"
self.services["virtual_machine"]["displayname"] = "virtual-machine-11"
self.virtual_machine_11 = VirtualMachine.create(
self.regular_user_apiclient,
self.services["virtual_machine"],
serviceofferingid=self.service_offering.id,
templateid=self.template.id,
zoneid=self.zone.id,
networkids=self.user_network.id,
affinitygroupids=self.affinity_group.id
)
self.cleanup.append(self.virtual_machine_11)
vm_11_host_id = self.get_vm_host_id(self.virtual_machine_11.id)
# 3. Deploy vm-12 with the group. It will be started on same host.
self.services["virtual_machine"]["name"] = "virtual-machine-12"
self.services["virtual_machine"]["displayname"] = "virtual-machine-12"
self.virtual_machine_12 = VirtualMachine.create(
self.regular_user_apiclient,
self.services["virtual_machine"],
serviceofferingid=self.service_offering.id,
templateid=self.template.id,
zoneid=self.zone.id,
networkids=self.user_network.id,
affinitygroupids=self.affinity_group.id
)
vm_12_host_id = self.get_vm_host_id(self.virtual_machine_12.id)
self.assertEqual(vm_11_host_id,
vm_12_host_id,
msg="Both VMs of affinity group %s are on the different host" % self.affinity_group.name)
# 4. Migrate vm-12 to different host as vm-11
self.virtual_machine_12.migrate(
self.apiclient
)
# 5. Stop vm-12, start vm-12. It will be started on different host as vm-11
stopCmd = stopVirtualMachine.stopVirtualMachineCmd()
stopCmd.id = self.virtual_machine_12.id
stopCmd.forced = True
self.apiclient.stopVirtualMachine(stopCmd)
startCmd = startVirtualMachine.startVirtualMachineCmd()
startCmd.id = self.virtual_machine_12.id
self.apiclient.startVirtualMachine(startCmd)
vm_12_host_id = self.get_vm_host_id(self.virtual_machine_12.id)
self.assertNotEqual(vm_11_host_id,
vm_12_host_id,
msg="Both VMs of affinity group %s are on the same host" % self.affinity_group.name)
# 6. Stop vm-12, start vm-12 with considerlasthost=false. It will be started on same host as vm-11
stopCmd.id = self.virtual_machine_12.id
stopCmd.forced = True
self.apiclient.stopVirtualMachine(stopCmd)
startCmd.id = self.virtual_machine_12.id
startCmd.considerlasthost = False
self.apiclient.startVirtualMachine(startCmd)
vm_12_host_id = self.get_vm_host_id(self.virtual_machine_12.id)
self.assertEqual(vm_11_host_id,
vm_12_host_id,
msg="Both VMs of affinity group %s are on the different host" % self.affinity_group.name)
destroyCmd = destroyVirtualMachine.destroyVirtualMachineCmd()
destroyCmd.id = self.virtual_machine_12.id
destroyCmd.expunge = True
self.apiclient.destroyVirtualMachine(destroyCmd)
# 7. Deploy vm-13 with different host, vm-13 should be started on specified host.
self.services["virtual_machine"]["name"] = "virtual-machine-13"
self.services["virtual_machine"]["displayname"] = "virtual-machine-13"
self.virtual_machine_13 = VirtualMachine.create(
self.apiclient,
self.services["virtual_machine"],
serviceofferingid=self.service_offering.id,
templateid=self.template.id,
zoneid=self.zone.id,
networkids=self.user_network.id,
affinitygroupids=self.affinity_group.id,
domainid=self.sub_domain.id,
accountid=self.regular_user.name,
hostid=vm_12_host_id
)
vm_13_host_id = self.get_vm_host_id(self.virtual_machine_13.id)
self.assertEqual(vm_12_host_id,
vm_13_host_id,
msg="virtual-machine-13 should be started on %s" % vm_12_host_id)
destroyCmd.id = self.virtual_machine_13.id
destroyCmd.expunge = True
self.apiclient.destroyVirtualMachine(destroyCmd)
# 8. Deploy vm-14 with startvm=false, then start the VM. vm-14 should be started on same host.
self.services["virtual_machine"]["name"] = "virtual-machine-14"
self.services["virtual_machine"]["displayname"] = "virtual-machine-14"
self.virtual_machine_14 = VirtualMachine.create(
self.regular_user_apiclient,
self.services["virtual_machine"],
serviceofferingid=self.service_offering.id,
templateid=self.template.id,
zoneid=self.zone.id,
networkids=self.user_network.id,
affinitygroupids=self.affinity_group.id,
startvm=False
)
self.cleanup.append(self.virtual_machine_14)
startCmd.id = self.virtual_machine_14.id
startCmd.considerlasthost = None
self.apiclient.startVirtualMachine(startCmd)
vm_14_host_id = self.get_vm_host_id(self.virtual_machine_14.id)
self.assertEqual(vm_11_host_id,
vm_14_host_id,
msg="virtual-machine-4 should be started on %s" % vm_11_host_id)