diff --git a/.zuul.yaml b/.zuul.yaml index c5e90f5c..5f032680 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -86,7 +86,7 @@ vars: # NOTE(artom) We can't have this on the parent job, otherwise the two # -cpupinnig jobs will inherit it as well. - tempest_exclude_regex: test_live_migrate_and_reboot + tempest_exclude_regex: test_live_migrate_and_reboot|test_shared_pinned_and_unpinned_guest - job: name: whitebox-devstack-multinode-cpupinning @@ -95,7 +95,7 @@ Runs the CPU pinning tests on single-NUMA, non-SMT, nested virt VMs. Uses [compute]cpu_dedicated_set to configure host CPUs for pinning. vars: - tempest_test_regex: 'test_live_migrate_and_reboot' + tempest_test_regex: test_live_migrate_and_reboot|test_shared_pinned_and_unpinned_guest devstack_local_conf: post-config: $NOVA_CONF: diff --git a/whitebox_tempest_plugin/api/compute/numa_helper.py b/whitebox_tempest_plugin/api/compute/numa_helper.py index 6eacfe64..1163cb97 100644 --- a/whitebox_tempest_plugin/api/compute/numa_helper.py +++ b/whitebox_tempest_plugin/api/compute/numa_helper.py @@ -28,3 +28,14 @@ class NUMAHelperMixin(object): for pin in vcpupins: pinset |= hardware.parse_cpu_spec(pin.get('cpuset')) return pinset + + def get_host_pcpus_for_guest_vcpu(self, server_id, instance_cpu_id): + """Search the xml vcpu element of the provided instance for its cpuset. + Convert cpuset found into a set of integers. + """ + + xml_cpu_search = "./cputune/vcpupin[@vcpu='%s']" % instance_cpu_id + root = self.get_server_xml(server_id) + cpus = root.find(xml_cpu_search) + cpuset = cpus.attrib.get('cpuset') + return hardware.parse_cpu_spec(cpuset) diff --git a/whitebox_tempest_plugin/api/compute/test_cpu_pinning.py b/whitebox_tempest_plugin/api/compute/test_cpu_pinning.py index 9cd772f4..0ce74b8e 100644 --- a/whitebox_tempest_plugin/api/compute/test_cpu_pinning.py +++ b/whitebox_tempest_plugin/api/compute/test_cpu_pinning.py @@ -1335,3 +1335,50 @@ class NUMARebuildTest(BasePinningTest): db_topo_rebuilt = self._get_db_numa_topology(server['id']) self.assertEqual(db_topo_orig, db_topo_rebuilt, "NUMA topology doesn't match") + + +class MixedCPUPolicyTest(BasePinningTest, numa_helper.NUMAHelperMixin): + vcpus = 2 + mixed_cpu_policy = {'hw:cpu_policy': 'mixed', + 'hw:cpu_dedicated_mask': '^0'} + + def test_shared_pinned_and_unpinned_guest(self): + flavor = self.create_flavor(vcpus=self.vcpus, + extra_specs=self.mixed_cpu_policy) + + server = self.create_test_server(flavor=flavor['id']) + host = self.get_host_for_server(server['id']) + host_sm = clients.NovaServiceManager(host, 'nova-compute', + self.os_admin.services_client) + + # Gather the current hosts cpu dedicated and shared set values + host_dedicated_cpus = host_sm.get_cpu_dedicated_set() + host_shared_cpus = host_sm.get_cpu_shared_set() + + # Find the PCPU's currently mapped to core 0 of the guest + guest_shared_cpus = self.get_host_pcpus_for_guest_vcpu(server['id'], 0) + + # Validate the PCPUs mapped to core 0 are a subset of the cpu shared + # set of the host + self.assertItemsEqual(guest_shared_cpus, host_shared_cpus, + 'Shared CPU Set %s of shared server %s is ' + 'not equal to shared set of host %s' % + (guest_shared_cpus, server['id'], + host_shared_cpus)) + + # Find the PCPU pinned to core 1 of the guest + guest_dedicated_cpus = \ + self.get_host_pcpus_for_guest_vcpu(server['id'], 1) + + # Confirm only one PCPU is mapped to core 1 of the guest + self.assertEqual(1, len(guest_dedicated_cpus), 'Only one PCPU should ' + 'be pinned to the guest CPU ID 1, but instead ' + 'found %s' % guest_dedicated_cpus) + + # Validate PCPU pinned to core 1 is a subset of the cpu dedicated set + # of the host + self.assertTrue(guest_dedicated_cpus.issubset(host_dedicated_cpus), + 'PCPU %s pinned to CPU id 1 of instance %s located on ' + 'host %s is not a subset of the dedicated set %s' % + (guest_dedicated_cpus, server['id'], host, + host_dedicated_cpus)) diff --git a/whitebox_tempest_plugin/services/clients.py b/whitebox_tempest_plugin/services/clients.py index da53a4ff..693dc4f3 100644 --- a/whitebox_tempest_plugin/services/clients.py +++ b/whitebox_tempest_plugin/services/clients.py @@ -26,6 +26,7 @@ from tempest.lib import exceptions as tempest_libexc from whitebox_tempest_plugin.common import waiters from whitebox_tempest_plugin import exceptions +from whitebox_tempest_plugin import hardware from whitebox_tempest_plugin import utils as whitebox_utils CONF = config.CONF @@ -233,6 +234,16 @@ class NovaServiceManager(ServiceManager): 'down') return result + def get_cpu_shared_set(self): + shared_set = self.get_conf_opt('compute', 'cpu_shared_set') + return hardware.parse_cpu_spec(shared_set) + + def get_cpu_dedicated_set(self): + dedicated_set = self.get_conf_opt('compute', 'cpu_dedicated_set') + dedicated_set = (dedicated_set if dedicated_set is not None else + self.get_conf_opt('DEFAULT', 'vcpu_pin_set')) + return hardware.parse_cpu_spec(dedicated_set) + class NUMAClient(SSHClient): """A client to get host NUMA information. `numactl` needs to be installed