diff --git a/nova/pci/manager.py b/nova/pci/manager.py index acf712f3d5..9ce50f5d9f 100644 --- a/nova/pci/manager.py +++ b/nova/pci/manager.py @@ -63,7 +63,13 @@ class PciDevTracker(object): self.stale = {} self.node_id = compute_node.id self.dev_filter = whitelist.Whitelist(CONF.pci.passthrough_whitelist) - self.stats = stats.PciDeviceStats(dev_filter=self.dev_filter) + numa_topology = compute_node.numa_topology + if numa_topology: + # For legacy reasons, the NUMATopology is stored as a JSON blob. + # Deserialize it into a real object. + numa_topology = objects.NUMATopology.obj_from_db_obj(numa_topology) + self.stats = stats.PciDeviceStats( + numa_topology, dev_filter=self.dev_filter) self._context = context self.pci_devs = objects.PciDeviceList.get_by_compute_node( context, self.node_id) diff --git a/nova/pci/stats.py b/nova/pci/stats.py index 5dd0ddfdee..cb36cbadc1 100644 --- a/nova/pci/stats.py +++ b/nova/pci/stats.py @@ -54,8 +54,9 @@ class PciDeviceStats(object): pool_keys = ['product_id', 'vendor_id', 'numa_node', 'dev_type'] - def __init__(self, stats=None, dev_filter=None): + def __init__(self, numa_topology, stats=None, dev_filter=None): super(PciDeviceStats, self).__init__() + self.numa_topology = numa_topology # NOTE(sbauza): Stats are a PCIDevicePoolList object self.pools = [pci_pool.to_dict() for pci_pool in stats] if stats else [] @@ -234,8 +235,7 @@ class PciDeviceStats(object): except exception.PciDeviceNotFound: return - @staticmethod - def _filter_pools_for_spec(pools, request): + def _filter_pools_for_spec(self, pools, request): """Filter out pools that don't match the request's device spec. Exclude pools that do not match the specified ``vendor_id``, @@ -254,8 +254,7 @@ class PciDeviceStats(object): if utils.pci_device_prop_match(pool, request_specs) ] - @classmethod - def _filter_pools_for_numa_cells(cls, pools, request, numa_cells): + def _filter_pools_for_numa_cells(self, pools, request, numa_cells): """Filter out pools with the wrong NUMA affinity, if required. Exclude pools that do not have *suitable* PCI NUMA affinity. @@ -324,8 +323,7 @@ class PciDeviceStats(object): return sorted( pools, key=lambda pool: pool.get('numa_node') not in numa_cell_ids) - @classmethod - def _filter_pools_for_unrequested_pfs(cls, pools, request): + def _filter_pools_for_unrequested_pfs(self, pools, request): """Filter out pools with PFs, unless these are required. This is necessary in cases where PFs and VFs have the same product_id @@ -347,8 +345,7 @@ class PciDeviceStats(object): ] return pools - @classmethod - def _filter_pools(cls, pools, request, numa_cells): + def _filter_pools(self, pools, request, numa_cells): """Determine if an individual PCI request can be met. Filter pools, which are collections of devices with similar traits, to @@ -372,7 +369,7 @@ class PciDeviceStats(object): # Firstly, let's exclude all devices that don't match our spec (e.g. # they've got different PCI IDs or something) before_count = sum([pool['count'] for pool in pools]) - pools = cls._filter_pools_for_spec(pools, request) + pools = self._filter_pools_for_spec(pools, request) after_count = sum([pool['count'] for pool in pools]) if after_count < before_count: @@ -389,7 +386,7 @@ class PciDeviceStats(object): # *assuming* we have devices and care about that, as determined by # policy before_count = after_count - pools = cls._filter_pools_for_numa_cells(pools, request, numa_cells) + pools = self._filter_pools_for_numa_cells(pools, request, numa_cells) after_count = sum([pool['count'] for pool in pools]) if after_count < before_count: @@ -405,7 +402,7 @@ class PciDeviceStats(object): # Finally, if we're not requesting PFs then we should not use these. # Exclude them. before_count = after_count - pools = cls._filter_pools_for_unrequested_pfs(pools, request) + pools = self._filter_pools_for_unrequested_pfs(pools, request) after_count = sum([pool['count'] for pool in pools]) if after_count < before_count: diff --git a/nova/scheduler/host_manager.py b/nova/scheduler/host_manager.py index ea2b0d2949..1118678bde 100644 --- a/nova/scheduler/host_manager.py +++ b/nova/scheduler/host_manager.py @@ -227,6 +227,7 @@ class HostState(object): self.numa_topology = objects.NUMATopology.obj_from_db_obj( compute.numa_topology) if compute.numa_topology else None self.pci_stats = pci_stats.PciDeviceStats( + self.numa_topology, stats=compute.pci_device_pools) # All virt drivers report host_ip diff --git a/nova/tests/unit/compute/test_claims.py b/nova/tests/unit/compute/test_claims.py index a13bd4355e..85e5ed40d1 100644 --- a/nova/tests/unit/compute/test_claims.py +++ b/nova/tests/unit/compute/test_claims.py @@ -61,7 +61,7 @@ class DummyTracker(object): return_value=objects.PciDeviceList() ): self.pci_tracker = pci_manager.PciDevTracker( - ctxt, objects.ComputeNode(id=1)) + ctxt, objects.ComputeNode(id=1, numa_topology=None)) class ClaimTestCase(test.NoDBTestCase): diff --git a/nova/tests/unit/pci/test_manager.py b/nova/tests/unit/pci/test_manager.py index eb8e1c054e..3bc5ae65ea 100644 --- a/nova/tests/unit/pci/test_manager.py +++ b/nova/tests/unit/pci/test_manager.py @@ -144,7 +144,7 @@ class PciDevTrackerTestCase(test.NoDBTestCase): def _create_tracker(self, fake_devs): self.fake_devs = fake_devs self.tracker = manager.PciDevTracker( - self.fake_context, objects.ComputeNode(id=1)) + self.fake_context, objects.ComputeNode(id=1, numa_topology=None)) def setUp(self): super(PciDevTrackerTestCase, self).setUp() @@ -222,7 +222,7 @@ class PciDevTrackerTestCase(test.NoDBTestCase): fake_pci_devs = [copy.deepcopy(fake_pci_4), copy.deepcopy(fake_pci_5)] fake_pci_devs_json = jsonutils.dumps(fake_pci_devs) tracker = manager.PciDevTracker( - self.fake_context, objects.ComputeNode(id=1)) + self.fake_context, objects.ComputeNode(id=1, numa_topology=None)) tracker.update_devices_from_hypervisor_resources(fake_pci_devs_json) self.assertEqual(5, len(tracker.pci_devs)) @@ -251,7 +251,7 @@ class PciDevTrackerTestCase(test.NoDBTestCase): fake_pci_devs = [fake_pci] fake_pci_devs_json = jsonutils.dumps(fake_pci_devs) tracker = manager.PciDevTracker( - self.fake_context, objects.ComputeNode(id=1)) + self.fake_context, objects.ComputeNode(id=1, numa_topology=None)) # We expect that the device with 32bit PCI domain is ignored, so we'll # have only the 3 original fake devs tracker.update_devices_from_hypervisor_resources(fake_pci_devs_json) @@ -426,7 +426,8 @@ class PciDevTrackerTestCase(test.NoDBTestCase): fake_devs_numa = copy.deepcopy(fake_db_devs) fake_devs_numa.append(fake_db_dev_3) self.tracker = manager.PciDevTracker( - mock.sentinel.context, objects.ComputeNode(id=1)) + mock.sentinel.context, + objects.ComputeNode(id=1, numa_topology=None)) self.tracker._set_hvdevs(fake_devs_numa) pci_requests = copy.deepcopy(fake_pci_requests)[:1] pci_requests[0]['count'] = 2 diff --git a/nova/tests/unit/pci/test_stats.py b/nova/tests/unit/pci/test_stats.py index 3e73dedaac..4dae4f0ce1 100644 --- a/nova/tests/unit/pci/test_stats.py +++ b/nova/tests/unit/pci/test_stats.py @@ -97,7 +97,7 @@ class PciDeviceStatsTestCase(test.NoDBTestCase): def setUp(self): super(PciDeviceStatsTestCase, self).setUp() - self.pci_stats = stats.PciDeviceStats() + self.pci_stats = stats.PciDeviceStats(objects.NUMATopology()) # The following two calls need to be made before adding the devices. patcher = fakes.fake_pci_whitelist() self.addCleanup(patcher.stop) @@ -123,7 +123,7 @@ class PciDeviceStatsTestCase(test.NoDBTestCase): self.fake_dev_2) def test_pci_stats_equivalent(self): - pci_stats2 = stats.PciDeviceStats() + pci_stats2 = stats.PciDeviceStats(objects.NUMATopology()) for dev in [self.fake_dev_1, self.fake_dev_2, self.fake_dev_3, @@ -132,7 +132,7 @@ class PciDeviceStatsTestCase(test.NoDBTestCase): self.assertEqual(self.pci_stats, pci_stats2) def test_pci_stats_not_equivalent(self): - pci_stats2 = stats.PciDeviceStats() + pci_stats2 = stats.PciDeviceStats(objects.NUMATopology()) for dev in [self.fake_dev_1, self.fake_dev_2, self.fake_dev_3]: @@ -141,7 +141,7 @@ class PciDeviceStatsTestCase(test.NoDBTestCase): def test_object_create(self): m = self.pci_stats.to_device_pools_obj() - new_stats = stats.PciDeviceStats(m) + new_stats = stats.PciDeviceStats(objects.NUMATopology(), m) self.assertEqual(len(new_stats.pools), 3) self.assertEqual(set([d['count'] for d in new_stats]), @@ -426,7 +426,7 @@ class PciDeviceStatsTestCase(test.NoDBTestCase): def test_white_list_parsing(self, mock_whitelist_parse): white_list = '{"product_id":"0001", "vendor_id":"8086"}' CONF.set_override('passthrough_whitelist', white_list, 'pci') - pci_stats = stats.PciDeviceStats() + pci_stats = stats.PciDeviceStats(objects.NUMATopology()) pci_stats.add_device(self.fake_dev_2) pci_stats.remove_device(self.fake_dev_2) self.assertEqual(1, mock_whitelist_parse.call_count) @@ -441,7 +441,9 @@ class PciDeviceStatsWithTagsTestCase(test.NoDBTestCase): '{"vendor_id":"1137","product_id":"0072"}'] self.flags(passthrough_whitelist=white_list, group='pci') dev_filter = whitelist.Whitelist(white_list) - self.pci_stats = stats.PciDeviceStats(dev_filter=dev_filter) + self.pci_stats = stats.PciDeviceStats( + objects.NUMATopology(), + dev_filter=dev_filter) def _create_pci_devices(self): self.pci_tagged_devices = [] @@ -594,7 +596,7 @@ class PciDeviceVFPFStatsTestCase(test.NoDBTestCase): white_list = ['{"vendor_id":"8086","product_id":"1528"}', '{"vendor_id":"8086","product_id":"1515"}'] self.flags(passthrough_whitelist=white_list, group='pci') - self.pci_stats = stats.PciDeviceStats() + self.pci_stats = stats.PciDeviceStats(objects.NUMATopology()) def _create_pci_devices(self, vf_product_id=1515, pf_product_id=1528): self.sriov_pf_devices = [] diff --git a/nova/tests/unit/scheduler/filters/test_pci_passthrough_filters.py b/nova/tests/unit/scheduler/filters/test_pci_passthrough_filters.py index f99f8e8bb0..c500b4a887 100644 --- a/nova/tests/unit/scheduler/filters/test_pci_passthrough_filters.py +++ b/nova/tests/unit/scheduler/filters/test_pci_passthrough_filters.py @@ -70,7 +70,8 @@ class TestPCIPassthroughFilter(test.NoDBTestCase): requests = objects.InstancePCIRequests(requests=[request]) spec_obj = objects.RequestSpec(pci_requests=requests) host = fakes.FakeHostState('host1', 'node1', - attribute_dict={'pci_stats': stats.PciDeviceStats()}) + attribute_dict={ + 'pci_stats': stats.PciDeviceStats(objects.NUMATopology())}) self.assertFalse(self.filt_cls.host_passes(host, spec_obj)) def test_pci_passthrough_with_pci_stats_none(self): diff --git a/nova/tests/unit/scheduler/test_host_manager.py b/nova/tests/unit/scheduler/test_host_manager.py index 5e08bb3554..e101b19777 100644 --- a/nova/tests/unit/scheduler/test_host_manager.py +++ b/nova/tests/unit/scheduler/test_host_manager.py @@ -1568,10 +1568,9 @@ class HostStateTestCase(test.NoDBTestCase): host = host_manager.HostState("fakehost", "fakenode", uuids.cell) self.assertIsNone(host.updated) host.pci_stats = pci_stats.PciDeviceStats( - [objects.PciDevicePool(vendor_id='8086', - product_id='15ed', - numa_node=1, - count=1)]) + objects.NUMATopology(), + [objects.PciDevicePool(vendor_id='8086', product_id='15ed', + numa_node=1, count=1)]) host.numa_topology = fakes.NUMA_TOPOLOGY host.consume_from_request(req_spec) self.assertIsInstance(req_spec.numa_topology, @@ -1602,7 +1601,7 @@ class HostStateTestCase(test.NoDBTestCase): self.assertIsNone(host.updated) fake_updated = mock.sentinel.fake_updated host.updated = fake_updated - host.pci_stats = pci_stats.PciDeviceStats() + host.pci_stats = pci_stats.PciDeviceStats(objects.NUMATopology()) with mock.patch.object(host.pci_stats, 'apply_requests', side_effect=exception.PciDeviceRequestFailed): host.consume_from_request(req_spec) diff --git a/nova/tests/unit/scheduler/weights/test_weights_pci.py b/nova/tests/unit/scheduler/weights/test_weights_pci.py index 1186f4e6bc..d257c67c1f 100644 --- a/nova/tests/unit/scheduler/weights/test_weights_pci.py +++ b/nova/tests/unit/scheduler/weights/test_weights_pci.py @@ -37,7 +37,7 @@ def _create_pci_stats(counts): return None pools = [_create_pci_pool(count) for count in counts] - return stats.PciDeviceStats(pools) + return stats.PciDeviceStats(objects.NUMATopology(), pools) class PCIWeigherTestCase(test.NoDBTestCase): diff --git a/nova/tests/unit/virt/test_hardware.py b/nova/tests/unit/virt/test_hardware.py index f1b47548cd..611410269f 100644 --- a/nova/tests/unit/virt/test_hardware.py +++ b/nova/tests/unit/virt/test_hardware.py @@ -2831,7 +2831,7 @@ class VirtNUMAHostTopologyTestCase(test.NoDBTestCase): pci_request = objects.InstancePCIRequest(count=1, spec=[{'vendor_id': '8086'}]) pci_reqs = [pci_request] - pci_stats = stats.PciDeviceStats() + pci_stats = stats.PciDeviceStats(objects.NUMATopology()) with mock.patch.object(stats.PciDeviceStats, 'support_requests', return_value= True): fitted_instance1 = hw.numa_fit_instance_to_host(self.host, @@ -2845,7 +2845,7 @@ class VirtNUMAHostTopologyTestCase(test.NoDBTestCase): pci_request = objects.InstancePCIRequest(count=1, spec=[{'vendor_id': '8086'}]) pci_reqs = [pci_request] - pci_stats = stats.PciDeviceStats() + pci_stats = stats.PciDeviceStats(objects.NUMATopology()) with mock.patch.object(stats.PciDeviceStats, 'support_requests', return_value= False): fitted_instance1 = hw.numa_fit_instance_to_host( @@ -2861,6 +2861,7 @@ class VirtNUMAHostTopologyTestCase(test.NoDBTestCase): test_dict = copy.copy(fake_pci.fake_pool_dict) test_dict['numa_node'] = node return stats.PciDeviceStats( + objects.NUMATopology(), [objects.PciDevicePool.from_dict(test_dict)]) # the PCI device is found on host cell 1