Convert to compute services name scheme
Hypervisor naming scheme was 'split' into two distinct address values. The first is compute host names which are derived from list-compute-services API [1]. The second address value is the compute control plane address that the tempest execution host will use to access compute hosts. From BaseWhiteboxComputeTest get_hypervisor_ip and get_all_hypervisors have been replaced with get_ctrlplane_address and list_compute_hosts respectively. Unlike get_hypervisor_ip, get_ctrlplane_address does not take a server id when finding a host ip, but instead takes a compute hostname. list_compute_hosts returns all service hostnames with binary name 'nova-compte' from the list-compute-services API. Several testcases from test_cpu_pinning.NUMALiveMigrationTest were updated to use the new methods accordingly. One key change is every test that calls list_compute_hosts, explicitly tries to convert returned hostname to it's controlplane address. This is done because TripleO does not have DNS entries for the compute hostnames and needs an IP address when utilizing the whitebox.services module. test_volume_negative.py was also updated to use the new methods when attempting to setup services. test_base.py had its tests updated as well to work with the new methods. [1] https://docs.openstack.org/api-ref/compute/?expanded=list-compute-services-detail#list-compute-services Change-Id: I4660043fcccec6721e197c4d77390744e356c59e
This commit is contained in:
parent
6a9c3bab8f
commit
2b6a050d92
@ -36,6 +36,7 @@ class BaseWhiteboxComputeTest(base.BaseV2ComputeAdminTest):
|
||||
# TODO(stephenfin): Rewrite tests to use 'admin_servers_client' etc.
|
||||
cls.servers_client = cls.os_admin.servers_client
|
||||
cls.flavors_client = cls.os_admin.flavors_client
|
||||
cls.service_client = cls.os_admin.services_client
|
||||
cls.hypervisor_client = cls.os_admin.hypervisor_client
|
||||
cls.image_client = cls.os_admin.image_client_v2
|
||||
cls.admin_migration_client = cls.os_admin.migrations_client
|
||||
@ -99,37 +100,44 @@ class BaseWhiteboxComputeTest(base.BaseV2ComputeAdminTest):
|
||||
|
||||
return new_image['id']
|
||||
|
||||
def get_hypervisor_ip(self, server_id):
|
||||
server = self.servers_client.show_server(server_id)
|
||||
host = server['server']['OS-EXT-SRV-ATTR:host']
|
||||
def get_ctrlplane_address(self, compute_hostname):
|
||||
"""Return the appropriate host address depending on a deployment.
|
||||
|
||||
if not CONF.whitebox.hypervisors:
|
||||
# NOTE(artom) [whitebox]/hypervisors not being set means we're
|
||||
# running against a devstack deployment and we can just use host
|
||||
# directly.
|
||||
return host
|
||||
In TripleO deployments the Undercloud does not have DNS entries for
|
||||
the compute hosts. This method checks if there are 'DNS' mappings of
|
||||
the provided hostname to it's control plane IP address and returns it.
|
||||
For Devstack deployments, no such parameters will exist and the method
|
||||
will just return compute_hostname
|
||||
|
||||
if host in CONF.whitebox.hypervisors:
|
||||
return CONF.whitebox.hypervisors[host]
|
||||
|
||||
raise exceptions.MissingHypervisorException(server=server_id,
|
||||
host=host)
|
||||
|
||||
def get_all_hypervisors(self):
|
||||
"""Returns a list of all hypervisor IPs in the deployment. Assumes all
|
||||
are up and running.
|
||||
:param compute_hostname: str the compute hostname
|
||||
:return str simply pass the provided compute_hostname back or
|
||||
return the associated control plane IP address
|
||||
"""
|
||||
if CONF.whitebox.hypervisors:
|
||||
return CONF.whitebox.hypervisors.values()
|
||||
hvs = self.hypervisor_client.list_hypervisors()['hypervisors']
|
||||
return [hv['hypervisor_hostname'] for hv in hvs]
|
||||
if not CONF.whitebox.ctrlplane_addresses:
|
||||
return compute_hostname
|
||||
|
||||
if compute_hostname in CONF.whitebox.ctrlplane_addresses:
|
||||
return CONF.whitebox.ctrlplane_addresses[compute_hostname]
|
||||
|
||||
raise exceptions.CtrlplaneAddressResolutionError(host=compute_hostname)
|
||||
|
||||
def list_compute_hosts(self):
|
||||
"""Returns a list of all nova-compute hostnames in the deployment.
|
||||
Assumes all are up and running.
|
||||
"""
|
||||
binary_name = 'nova-compute'
|
||||
services = \
|
||||
self.service_client.list_services(binary=binary_name)['services']
|
||||
return [service['host'] for service in services]
|
||||
|
||||
def get_server_xml(self, server_id):
|
||||
hv_ip = self.get_hypervisor_ip(server_id)
|
||||
server = self.servers_client.show_server(server_id)
|
||||
host = server['server']['OS-EXT-SRV-ATTR:host']
|
||||
cntrlplane_addr = self.get_ctrlplane_address(host)
|
||||
server_instance_name = self.servers_client.show_server(
|
||||
server_id)['server']['OS-EXT-SRV-ATTR:instance_name']
|
||||
|
||||
virshxml = clients.VirshXMLClient(hv_ip)
|
||||
virshxml = clients.VirshXMLClient(cntrlplane_addr)
|
||||
xml = virshxml.dumpxml(server_instance_name)
|
||||
return ET.fromstring(xml)
|
||||
|
||||
|
@ -338,8 +338,7 @@ class CPUThreadPolicyTest(BasePinningTest):
|
||||
try:
|
||||
host_address = CONF.whitebox.hypervisors[host]
|
||||
except KeyError:
|
||||
raise exceptions.MissingHypervisorException(server="",
|
||||
host=host)
|
||||
raise exceptions.CtrlplaneAddressResolutionError(host=host)
|
||||
else:
|
||||
host_address = host
|
||||
|
||||
@ -490,9 +489,11 @@ class NUMALiveMigrationTest(BasePinningTest):
|
||||
return set([len(cpu_list) for cpu_list in chain(*args)])
|
||||
|
||||
def test_cpu_pinning(self):
|
||||
hv1, hv2 = self.get_all_hypervisors()
|
||||
numaclient_1 = clients.NUMAClient(hv1)
|
||||
numaclient_2 = clients.NUMAClient(hv2)
|
||||
host1, host2 = [self.get_ctrlplane_address(host) for host in
|
||||
self.list_compute_hosts()]
|
||||
|
||||
numaclient_1 = clients.NUMAClient(host1)
|
||||
numaclient_2 = clients.NUMAClient(host2)
|
||||
|
||||
# Get hosts's topology
|
||||
topo_1 = numaclient_1.get_host_topology()
|
||||
@ -511,12 +512,12 @@ class NUMALiveMigrationTest(BasePinningTest):
|
||||
|
||||
# Set both hosts's vcpu_pin_set to the CPUs in the first NUMA node to
|
||||
# force instances to land there
|
||||
hv1_sm = clients.ServiceManager(hv1, 'nova-compute')
|
||||
hv2_sm = clients.ServiceManager(hv2, 'nova-compute')
|
||||
with hv1_sm.config_option('DEFAULT', 'vcpu_pin_set',
|
||||
self._get_cpu_spec(topo_1[0])), \
|
||||
hv2_sm.config_option('DEFAULT', 'vcpu_pin_set',
|
||||
self._get_cpu_spec(topo_2[0])):
|
||||
host1_sm = clients.ServiceManager(host1, 'nova-compute')
|
||||
host2_sm = clients.ServiceManager(host2, 'nova-compute')
|
||||
with host1_sm.config_option('DEFAULT', 'vcpu_pin_set',
|
||||
self._get_cpu_spec(topo_1[0])), \
|
||||
host2_sm.config_option('DEFAULT', 'vcpu_pin_set',
|
||||
self._get_cpu_spec(topo_2[0])):
|
||||
# Boot 2 servers such that their vCPUs "fill" a NUMA node.
|
||||
specs = {'hw:cpu_policy': 'dedicated'}
|
||||
flavor = self.create_flavor(vcpus=cpus_per_node.pop(),
|
||||
@ -554,13 +555,9 @@ class NUMALiveMigrationTest(BasePinningTest):
|
||||
# Live migrate server_b to server_a's compute, adding the second
|
||||
# NUMA node's CPUs to vcpu_pin_set
|
||||
host_a = self.get_host_other_than(server_b['id'])
|
||||
# NOTE (jparker) since certain deployment's execution hosts
|
||||
# may not have DNS mappings for their respective compute and
|
||||
# controllers nodes, attempt to determine and use the hv ip
|
||||
# when setting up the ServiceManager
|
||||
host_a_ip = self.get_hypervisor_ip(server_a['id'])
|
||||
host_a_sm = clients.ServiceManager(host_a_ip, 'nova-compute')
|
||||
numaclient_a = clients.NUMAClient(host_a_ip)
|
||||
host_a_addr = self.get_ctrlplane_address(host_a)
|
||||
host_a_sm = clients.ServiceManager(host_a_addr, 'nova-compute')
|
||||
numaclient_a = clients.NUMAClient(host_a_addr)
|
||||
topo_a = numaclient_a.get_host_topology()
|
||||
with host_a_sm.config_option(
|
||||
'DEFAULT', 'vcpu_pin_set',
|
||||
@ -597,20 +594,23 @@ class NUMALiveMigrationTest(BasePinningTest):
|
||||
|
||||
def test_emulator_threads(self):
|
||||
# Need 4 CPUs on each host
|
||||
for hv in self.get_all_hypervisors():
|
||||
numaclient = clients.NUMAClient(hv)
|
||||
host1, host2 = [self.get_ctrlplane_address(host) for host in
|
||||
self.list_compute_hosts()]
|
||||
|
||||
for host in [host1, host2]:
|
||||
numaclient = clients.NUMAClient(host)
|
||||
num_cpus = numaclient.get_num_cpus()
|
||||
if num_cpus < 4:
|
||||
raise self.skipException('%s has %d CPUs, need 4', hv,
|
||||
raise self.skipException('%s has %d CPUs, need 4',
|
||||
host,
|
||||
num_cpus)
|
||||
|
||||
hv1, hv2 = self.get_all_hypervisors()
|
||||
hv1_sm = clients.ServiceManager(hv1, 'nova-compute')
|
||||
hv2_sm = clients.ServiceManager(hv2, 'nova-compute')
|
||||
with hv1_sm.config_option('DEFAULT', 'vcpu_pin_set', '0,1'), \
|
||||
hv1_sm.config_option('compute', 'cpu_shared_set', '2'), \
|
||||
hv2_sm.config_option('DEFAULT', 'vcpu_pin_set', '0,1'), \
|
||||
hv2_sm.config_option('compute', 'cpu_shared_set', '3'):
|
||||
host1_sm = clients.ServiceManager(host1, 'nova-compute')
|
||||
host2_sm = clients.ServiceManager(host2, 'nova-compute')
|
||||
with host1_sm.config_option('DEFAULT', 'vcpu_pin_set', '0,1'), \
|
||||
host1_sm.config_option('compute', 'cpu_shared_set', '2'), \
|
||||
host2_sm.config_option('DEFAULT', 'vcpu_pin_set', '0,1'), \
|
||||
host2_sm.config_option('compute', 'cpu_shared_set', '3'):
|
||||
|
||||
# Boot two servers
|
||||
specs = {'hw:cpu_policy': 'dedicated',
|
||||
@ -656,9 +656,11 @@ class NUMALiveMigrationTest(BasePinningTest):
|
||||
self.delete_server(server_b['id'])
|
||||
|
||||
def test_hugepages(self):
|
||||
hv_a, hv_b = self.get_all_hypervisors()
|
||||
numaclient_a = clients.NUMAClient(hv_a)
|
||||
numaclient_b = clients.NUMAClient(hv_b)
|
||||
host_a, host_b = [self.get_ctrlplane_address(host) for host in
|
||||
self.list_compute_hosts()]
|
||||
|
||||
numaclient_a = clients.NUMAClient(host_a)
|
||||
numaclient_b = clients.NUMAClient(host_b)
|
||||
|
||||
# Get the first host's topology and hugepages config
|
||||
topo_a = numaclient_a.get_host_topology()
|
||||
|
@ -70,10 +70,10 @@ class VolumesAdminNegativeTest(base.BaseWhiteboxComputeTest,
|
||||
self.assertGreater(
|
||||
len(disks_after_attach),
|
||||
len(disks_before_attach))
|
||||
hypervisor = self.get_hypervisor_ip(server['id'])
|
||||
host = self.get_ctrlplane_address(server['OS-EXT-SRV-ATTR:host'])
|
||||
|
||||
# stop the nova_libvirt service
|
||||
clients.ServiceManager(hypervisor, 'nova-libvirt').stop()
|
||||
clients.ServiceManager(host, 'nova-libvirt').stop()
|
||||
|
||||
# While this call to n-api will return successfully the underlying call
|
||||
# to the virt driver will fail as the libvirt service is stopped.
|
||||
@ -85,7 +85,7 @@ class VolumesAdminNegativeTest(base.BaseWhiteboxComputeTest,
|
||||
len(disks_after_failed_detach), len(disks_after_attach))
|
||||
|
||||
# restart the nova_libvirt after failed detach
|
||||
clients.ServiceManager(hypervisor, 'nova-libvirt').restart()
|
||||
clients.ServiceManager(host, 'nova-libvirt').restart()
|
||||
|
||||
# This will be a successful detach as nova_libvirt is started again
|
||||
self.servers_client.detach_volume(server['id'], attachment['volumeId'])
|
||||
|
@ -40,18 +40,20 @@ general_opts = [
|
||||
default=False,
|
||||
help='Deployment is containerized.'),
|
||||
cfg.DictOpt(
|
||||
'hypervisors',
|
||||
help="Dictionary of hypervisor IP addresses. The keys are the "
|
||||
"hostnames as they appear in the OS-EXT-SRV-ATTR:host field of "
|
||||
"Nova's show server details API. The values are the ctlplane IP "
|
||||
"addresses. For example:"
|
||||
'ctrlplane_addresses',
|
||||
help="Dictionary of control plane addresses. The keys are the "
|
||||
"compute hostnames as they appear in the OS-EXT-SRV-ATTR:host "
|
||||
"field of Nova's show server details API. The values are the "
|
||||
"control plane addresses. For example:"
|
||||
""
|
||||
" hypervisors = compute-0.localdomain:172.16.42.11,"
|
||||
" controller-0.localdomain:172.16.42.10"
|
||||
" ctrlplane_addresses = compute-0.localdomain:172.16.42.11,"
|
||||
" compute-1.localdomain:172.16.42.10"
|
||||
""
|
||||
"While this looks like a poor man's DNS, this is needed "
|
||||
"because the environment running the test does not necessarily "
|
||||
"have the ctlplane DNS accessible."),
|
||||
"have the ctlplane DNS accessible.",
|
||||
deprecated_opts=[cfg.DeprecatedOpt('hypervisors',
|
||||
group='whitebox')]),
|
||||
cfg.IntOpt(
|
||||
'max_compute_nodes',
|
||||
default=31337,
|
||||
|
@ -16,8 +16,8 @@
|
||||
from tempest.lib import exceptions
|
||||
|
||||
|
||||
class MissingHypervisorException(exceptions.TempestException):
|
||||
message = "Unable to find IP in conf. Server: %(server)s, host: %(host)s."
|
||||
class CtrlplaneAddressResolutionError(exceptions.TempestException):
|
||||
message = "Unable to find IP in conf. for host: %(host)s."
|
||||
|
||||
|
||||
class MissingServiceSectionException(exceptions.TempestException):
|
||||
|
@ -26,6 +26,11 @@ def fake_show_server(server_id):
|
||||
return {'server': {'OS-EXT-SRV-ATTR:host': 'missing-host'}}
|
||||
|
||||
|
||||
def fake_list_services(binary):
|
||||
return {'services': [{'binary': 'nova-compute', 'host': 'fake-host'},
|
||||
{'binary': 'nova-compute', 'host': 'fake-host2'}]}
|
||||
|
||||
|
||||
class UtilsTestCase(base.WhiteboxPluginTestCase):
|
||||
|
||||
def setUp(self):
|
||||
@ -36,19 +41,21 @@ class UtilsTestCase(base.WhiteboxPluginTestCase):
|
||||
return_value=None)
|
||||
self.test_class = compute_base.BaseWhiteboxComputeTest()
|
||||
self.test_class.servers_client = mock.Mock()
|
||||
self.test_class.service_client = mock.Mock()
|
||||
self.test_class.servers_client.show_server = fake_show_server
|
||||
self.test_class.service_client.list_services = fake_list_services
|
||||
self.flags(hypervisors={'fake-host': 'fake-ip',
|
||||
'fake-host2': 'fake-ip2'}, group='whitebox')
|
||||
|
||||
def test_get_hypervisor_ip(self):
|
||||
def test_get_ctrlplane_address(self):
|
||||
self.assertEqual('fake-ip',
|
||||
self.test_class.get_hypervisor_ip('fake-id'))
|
||||
self.test_class.get_ctrlplane_address('fake-host'))
|
||||
|
||||
@mock.patch.object(compute_base.LOG, 'error')
|
||||
def test_get_hypervisor_ip_keyerror(self, mock_log):
|
||||
self.assertRaises(exceptions.MissingHypervisorException,
|
||||
self.test_class.get_hypervisor_ip, 'missing-id')
|
||||
def test_get_ctrlplane_address_keyerror(self, mock_log):
|
||||
self.assertRaises(exceptions.CtrlplaneAddressResolutionError,
|
||||
self.test_class.get_ctrlplane_address, 'missing-id')
|
||||
|
||||
def test_get_all_hypervisors(self):
|
||||
self.assertItemsEqual(['fake-ip', 'fake-ip2'],
|
||||
self.test_class.get_all_hypervisors())
|
||||
def test_list_compute_hosts(self):
|
||||
self.assertItemsEqual(['fake-host', 'fake-host2'],
|
||||
self.test_class.list_compute_hosts())
|
||||
|
Loading…
Reference in New Issue
Block a user