Rework 'test_numa_topology'
This is a little cludgy and could make better use of existing test classes found in Tempest. The main changes are: - The test class is no longer unnecessarily split into a base class and test class - The test class now inherits from 'base.BaseV2ComputeAdminTest' rather than from 'manager.NetworkScenarioTest', allowing us to remove a lot of boilerplate - 'remote_client.RemoteClient' is subclassed to indicate how we're retrieving host NUMA topology - Some variables are renamed to clarify their purpose. This adds a dependency of the '[validation] run_validation' config option, which must now be set to 'True' to ensure networks are provisioned for guest instances that need them. Change-Id: Idfa521e81aba93c863b8996b6f42645711312759
This commit is contained in:
parent
a8807613ad
commit
ba71d6ed58
|
@ -14,17 +14,16 @@
|
|||
# under the License.
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_log import log as logging
|
||||
|
||||
from tempest.api.compute import base
|
||||
from tempest.common.utils.linux import remote_client
|
||||
from tempest import config
|
||||
from tempest.lib.common.utils import data_utils
|
||||
from tempest.scenario import manager
|
||||
from tempest import test
|
||||
|
||||
import testtools
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_host_numa_placement(instance, vcpus):
|
||||
"""Get placement of instance CPUs on host.
|
||||
|
@ -54,34 +53,49 @@ def get_host_numa_placement(instance, vcpus):
|
|||
return placement
|
||||
|
||||
|
||||
class TestServerNumaBase(manager.NetworkScenarioTest):
|
||||
credentials = ['admin']
|
||||
class NUMARemoteClient(remote_client.RemoteClient):
|
||||
|
||||
def get_numa_topology(self):
|
||||
nodes = []
|
||||
|
||||
node_count = self.exec_command(
|
||||
'ls /sys/devices/system/node | grep node | wc -l')
|
||||
for i in range(int(node_count)):
|
||||
node_cmd = 'cat /sys/devices/system/node/node%d/' % i
|
||||
|
||||
node = {}
|
||||
node['cpu'] = self.exec_command(node_cmd + 'cpulist')
|
||||
node['mem'] = self.exec_command(node_cmd + 'meminfo')
|
||||
nodes.append(node)
|
||||
|
||||
return nodes
|
||||
|
||||
|
||||
class NUMAServersTest(base.BaseV2ComputeAdminTest):
|
||||
disk_config = 'AUTO'
|
||||
|
||||
@classmethod
|
||||
def setup_credentials(cls):
|
||||
cls.prepare_instance_network()
|
||||
super(NUMAServersTest, cls).setup_credentials()
|
||||
|
||||
@classmethod
|
||||
def setup_clients(cls):
|
||||
cls.manager = cls.admin_manager
|
||||
super(manager.NetworkScenarioTest, cls).setup_clients()
|
||||
# Use admin client by default
|
||||
super(NUMAServersTest, cls).setup_clients()
|
||||
cls.flavors_client = cls.os_adm.flavors_client
|
||||
cls.client = cls.servers_client
|
||||
|
||||
def setUp(self):
|
||||
super(TestServerNumaBase, self).setUp()
|
||||
# Setup image and flavor the test instance
|
||||
# Support both configured and injected values
|
||||
self.image_ref = CONF.compute.image_ref
|
||||
self.flavor_ref = CONF.compute.flavor_ref
|
||||
self.run_ssh = CONF.validation.run_validation
|
||||
self.ssh_user = CONF.validation.image_ssh_user
|
||||
self.keypair = self.create_keypair()
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
# TODO(stephenfin): Do we need this?
|
||||
cls.set_validation_resources()
|
||||
super(NUMAServersTest, cls).resource_setup()
|
||||
|
||||
LOG.debug('Starting test for i:{image}, f:{flavor}. '
|
||||
'Run ssh: {ssh}, user: {ssh_user}'.format(
|
||||
image=self.image_ref, flavor=self.flavor_ref,
|
||||
ssh=self.run_ssh, ssh_user=self.ssh_user))
|
||||
|
||||
def create_flavor_with_numa(self):
|
||||
flavor_with_numa = data_utils.rand_name('numa_flavor')
|
||||
flavor_with_numa_id = data_utils.rand_int_id(start=1000)
|
||||
def create_flavor(self):
|
||||
flavor_name = data_utils.rand_name('numa_flavor')
|
||||
flavor_id = data_utils.rand_int_id(start=1000)
|
||||
|
||||
# TODO(stephenfin): Consider dropping this to 512 or similar
|
||||
ram = 2048
|
||||
vcpus = 4
|
||||
disk = 0
|
||||
|
@ -90,90 +104,53 @@ class TestServerNumaBase(manager.NetworkScenarioTest):
|
|||
}
|
||||
|
||||
# Create a flavor with extra specs
|
||||
resp = (self.flavors_client.create_flavor(name=flavor_with_numa,
|
||||
ram=ram, vcpus=vcpus,
|
||||
disk=disk,
|
||||
id=flavor_with_numa_id))
|
||||
self.flavors_client.set_flavor_extra_spec(flavor_with_numa_id,
|
||||
**extra_specs)
|
||||
self.addCleanup(self.flavor_clean_up, flavor_with_numa_id)
|
||||
self.assertEqual(200, resp.response.status)
|
||||
flavor = self.flavors_client.create_flavor(name=flavor_name, ram=ram,
|
||||
vcpus=vcpus, disk=disk,
|
||||
id=flavor_id)['flavor']
|
||||
self.flavors_client.set_flavor_extra_spec(flavor['id'], **extra_specs)
|
||||
self.addCleanup(self.flavor_clean_up, flavor['id'])
|
||||
|
||||
return flavor_with_numa_id
|
||||
return flavor['id']
|
||||
|
||||
def flavor_clean_up(self, flavor_id):
|
||||
resp = self.flavors_client.delete_flavor(flavor_id)
|
||||
self.assertEqual(resp.response.status, 202)
|
||||
self.flavors_client.delete_flavor(flavor_id)
|
||||
self.flavors_client.wait_for_resource_deletion(flavor_id)
|
||||
|
||||
def boot_instance(self):
|
||||
# Create server with image and flavor from input scenario
|
||||
security_groups = [{'name': self.security_group['name']}]
|
||||
create_kwargs = {
|
||||
'key_name': self.keypair['name'],
|
||||
'security_groups': security_groups
|
||||
}
|
||||
flavor = self.create_flavor_with_numa()
|
||||
self.instance = self.create_server(
|
||||
image_id=self.image_ref,
|
||||
flavor=flavor,
|
||||
@testtools.skipUnless(CONF.validation.run_validation,
|
||||
'Instance validation tests are disabled.')
|
||||
def test_verify_created_server_numa_topology(self):
|
||||
"""Smoke test NUMA support.
|
||||
|
||||
Validates NUMA support by launching an instance with a NUMA
|
||||
topology defined and validating the correctness of the topology
|
||||
on both host and guest.
|
||||
"""
|
||||
flavor_id = self.create_flavor()
|
||||
|
||||
admin_pass = self.image_ssh_password
|
||||
|
||||
server = self.create_test_server(
|
||||
validatable=True,
|
||||
wait_until='ACTIVE',
|
||||
**create_kwargs)
|
||||
adminPass=admin_pass,
|
||||
flavor=flavor_id)
|
||||
|
||||
def verify_ssh(self):
|
||||
# Obtain a floating IP
|
||||
floating_ip = self.compute_floating_ips_client.create_floating_ip()[
|
||||
'floating_ip']
|
||||
self.addCleanup(self.compute_floating_ips_client.delete_floating_ip,
|
||||
floating_ip['id'])
|
||||
# Attach a floating IP
|
||||
self.compute_floating_ips_client.associate_floating_ip_to_server(
|
||||
floating_ip['ip'], self.instance['id'])
|
||||
# Check ssh
|
||||
return self.get_remote_client(
|
||||
ip_address=floating_ip['ip'],
|
||||
username='cirros',
|
||||
private_key=self.keypair['private_key'])
|
||||
server = self.client.show_server(server['id'])['server']
|
||||
linux_client = NUMARemoteClient(
|
||||
self.get_server_ip(server),
|
||||
self.ssh_user,
|
||||
admin_pass,
|
||||
self.validation_resources['keypair']['private_key'],
|
||||
server=server,
|
||||
servers_client=self.client)
|
||||
|
||||
# Validate guest topology
|
||||
# TODO(stephenfin): Validate more of the NUMA topology than this
|
||||
numa_nodes = linux_client.get_numa_nodes()
|
||||
self.assertEqual(2, len(numa_nodes))
|
||||
|
||||
class TestServerNumaTopo(TestServerNumaBase):
|
||||
"""
|
||||
This smoke test case follows this basic set of operations:
|
||||
|
||||
* Create a keypair for use in launching an instance
|
||||
* Create a security group to control network access in instance
|
||||
* Add simple permissive rules to the security group
|
||||
* Launch an instance with numa topology defined
|
||||
* Perform ssh to instance
|
||||
* Get numa topology from VM, check correctness
|
||||
* Get numa placement info for VM from HOST
|
||||
* Check if placement is correct
|
||||
* Terminate the instance
|
||||
"""
|
||||
|
||||
def get_numa_topology(self, rmt):
|
||||
topo = {'nodes': []}
|
||||
nodes = int(rmt.exec_command("ls /sys/devices/system/node"
|
||||
" | grep node | wc -l"))
|
||||
for i in range(nodes):
|
||||
node = {}
|
||||
node['cpu'] = rmt.exec_command("cat /sys/devices/system/node/"
|
||||
"node%s/cpulist" % i)
|
||||
node['mem'] = rmt.exec_command("cat /sys/devices/system/node/"
|
||||
"node%s/meminfo" % i)
|
||||
topo["nodes"].append(node)
|
||||
return topo
|
||||
|
||||
@test.services('compute', 'network')
|
||||
def test_server_numa(self):
|
||||
self.security_group = self._create_security_group()
|
||||
self.boot_instance()
|
||||
rmt_client = self.verify_ssh()
|
||||
topo = self.get_numa_topology(rmt_client)
|
||||
self.assertEqual(2, len(topo['nodes']))
|
||||
self.assertNotEqual(None, rmt_client)
|
||||
placement = get_host_numa_placement(self.instance, 4)
|
||||
# Validate host topology
|
||||
placement = self.get_placement(server, 4)
|
||||
self.assertEqual(placement[0], placement[1])
|
||||
self.assertNotEqual(placement[1], placement[2])
|
||||
self.assertEqual(placement[2], placement[3])
|
||||
self.servers_client.delete_server(self.instance['id'])
|
||||
|
|
Loading…
Reference in New Issue