From 57f6db96d5e1995b7d3ff7df059c3c078d984f2b Mon Sep 17 00:00:00 2001 From: Sahid Orentino Ferdjaoui Date: Mon, 24 Nov 2014 12:04:19 -0500 Subject: [PATCH] objects: move numa host and cell to objects To continue objectification of numa, this commit move numa host/cell related to objects. Change-Id: I9fbc3ed6d9bd74840e42586faa9951d9672691c1 --- nova/compute/claims.py | 4 +- nova/compute/resource_tracker.py | 4 +- nova/db/sqlalchemy/models.py | 2 +- nova/objects/numa.py | 5 + .../scheduler/filters/numa_topology_filter.py | 3 +- nova/tests/unit/compute/test_claims.py | 10 +- .../unit/compute/test_resource_tracker.py | 40 +-- nova/tests/unit/objects/test_compute_node.py | 12 +- nova/tests/unit/scheduler/fakes.py | 16 +- .../tests/unit/scheduler/test_host_manager.py | 6 +- nova/tests/unit/virt/libvirt/test_driver.py | 14 +- nova/tests/unit/virt/test_hardware.py | 217 +++++++------- nova/virt/hardware.py | 264 +++++++----------- nova/virt/libvirt/driver.py | 14 +- 14 files changed, 291 insertions(+), 320 deletions(-) diff --git a/nova/compute/claims.py b/nova/compute/claims.py index b377d67198..1469d91ecf 100644 --- a/nova/compute/claims.py +++ b/nova/compute/claims.py @@ -204,10 +204,10 @@ class Claim(NopClaim): host_topology = resources.get('numa_topology') requested_topology = self.numa_topology if host_topology: - host_topology = hardware.VirtNUMAHostTopology.from_json( + host_topology = objects.NUMATopology.obj_from_db_obj( host_topology) instance_topology = ( - hardware.VirtNUMAHostTopology.fit_instance_to_host( + hardware.numa_fit_instance_to_host( host_topology, requested_topology, limits_topology=limit)) if requested_topology and not instance_topology: diff --git a/nova/compute/resource_tracker.py b/nova/compute/resource_tracker.py index bd8cb91477..0dbb91d8a5 100644 --- a/nova/compute/resource_tracker.py +++ b/nova/compute/resource_tracker.py @@ -600,11 +600,11 @@ class ResourceTracker(object): if itype: host_topology = resources.get('numa_topology') if host_topology: - host_topology = hardware.VirtNUMAHostTopology.from_json( + host_topology = objects.NUMATopology.obj_from_db_obj( host_topology) numa_topology = hardware.numa_get_constraints(itype, image_meta) numa_topology = ( - hardware.VirtNUMAHostTopology.fit_instance_to_host( + hardware.numa_fit_instance_to_host( host_topology, numa_topology)) usage = self._get_usage_dict( itype, numa_topology=numa_topology) diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index 7536863d03..45d0e4d08f 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -132,7 +132,7 @@ class ComputeNode(BASE, NovaBase): stats = Column(Text, default='{}') # json-encoded dict that contains NUMA topology as generated by - # nova.virt.hardware.VirtNUMAHostTopology.to_json() + # objects.NUMATopoloogy._to_json() numa_topology = Column(Text) diff --git a/nova/objects/numa.py b/nova/objects/numa.py index 9ecbee6246..e1a1646761 100644 --- a/nova/objects/numa.py +++ b/nova/objects/numa.py @@ -80,6 +80,11 @@ class NUMATopology(base.NovaObject): def _to_json(self): return jsonutils.dumps(self.obj_to_primitive()) + @classmethod + def obj_from_db_obj(cls, db_obj): + return cls.obj_from_primitive( + jsonutils.loads(db_obj)) + def __len__(self): """Defined so that boolean testing works the same as for lists.""" return len(self.cells) diff --git a/nova/scheduler/filters/numa_topology_filter.py b/nova/scheduler/filters/numa_topology_filter.py index 484f6470e2..1721f01a87 100644 --- a/nova/scheduler/filters/numa_topology_filter.py +++ b/nova/scheduler/filters/numa_topology_filter.py @@ -40,8 +40,7 @@ class NUMATopologyFilter(filters.BaseHostFilter): cell.id, cell.cpuset, cell.memory, max_cell_cpu, max_cell_memory)) limits = hardware.VirtNUMALimitTopology(cells=limit_cells) - instance_topology = ( - hardware.VirtNUMAHostTopology.fit_instance_to_host( + instance_topology = (hardware.numa_fit_instance_to_host( host_topology, requested_topology, limits_topology=limits)) if not instance_topology: diff --git a/nova/tests/unit/compute/test_claims.py b/nova/tests/unit/compute/test_claims.py index 94563b2fad..6dbb318914 100644 --- a/nova/tests/unit/compute/test_claims.py +++ b/nova/tests/unit/compute/test_claims.py @@ -121,10 +121,12 @@ class ClaimTestCase(test.NoDBTestCase): 'free_disk_gb': 20, 'vcpus': 2, 'vcpus_used': 0, - 'numa_topology': hardware.VirtNUMAHostTopology( - cells=[hardware.VirtNUMATopologyCellUsage(1, [1, 2], 512), - hardware.VirtNUMATopologyCellUsage(2, [3, 4], 512)] - ).to_json() + 'numa_topology': objects.NUMATopology( + cells=[objects.NUMACell(id=1, cpuset=set([1, 2]), memory=512, + memory_usage=0, cpu_usage=0), + objects.NUMACell(id=2, cpuset=set([3, 4]), memory=512, + memory_usage=0, cpu_usage=0)] + )._to_json() } if values: resources.update(values) diff --git a/nova/tests/unit/compute/test_resource_tracker.py b/nova/tests/unit/compute/test_resource_tracker.py index 65ee9cfef1..ce16e4b141 100644 --- a/nova/tests/unit/compute/test_resource_tracker.py +++ b/nova/tests/unit/compute/test_resource_tracker.py @@ -44,9 +44,11 @@ FAKE_VIRT_MEMORY_MB = 5 FAKE_VIRT_MEMORY_OVERHEAD = 1 FAKE_VIRT_MEMORY_WITH_OVERHEAD = ( FAKE_VIRT_MEMORY_MB + FAKE_VIRT_MEMORY_OVERHEAD) -FAKE_VIRT_NUMA_TOPOLOGY = hardware.VirtNUMAHostTopology( - cells=[hardware.VirtNUMATopologyCellUsage(0, set([1, 2]), 3072), - hardware.VirtNUMATopologyCellUsage(1, set([3, 4]), 3072)]) +FAKE_VIRT_NUMA_TOPOLOGY = objects.NUMATopology( + cells=[objects.NUMACell(id=0, cpuset=set([1, 2]), memory=3072, + cpu_usage=0, memory_usage=0), + objects.NUMACell(id=1, cpuset=set([3, 4]), memory=3072, + cpu_usage=0, memory_usage=0)]) FAKE_VIRT_NUMA_TOPOLOGY_OVERHEAD = hardware.VirtNUMALimitTopology( cells=[hardware.VirtNUMATopologyCellLimit( 0, set([1, 2]), 3072, 4, 10240), @@ -121,7 +123,7 @@ class FakeVirtDriver(driver.ComputeDriver): 'hypervisor_hostname': 'fakehost', 'cpu_info': '', 'numa_topology': ( - self.numa_topology.to_json() if self.numa_topology else None), + self.numa_topology._to_json() if self.numa_topology else None), } if self.pci_support: d['pci_passthrough_devices'] = jsonutils.dumps(self.pci_devices) @@ -585,7 +587,7 @@ class BaseTrackerTestCase(BaseTestCase): if field == 'numa_topology': self.assertEqualNUMAHostTopology( - value, hardware.VirtNUMAHostTopology.from_json(x)) + value, objects.NUMATopology.obj_from_db_obj(x)) else: self.assertEqual(value, x) @@ -729,12 +731,12 @@ class InstanceClaimTestCase(BaseTrackerTestCase): if self.tracker.driver.numa_topology is None: return None mem = mem * 1024 - return hardware.VirtNUMAHostTopology( - cells=[hardware.VirtNUMATopologyCellUsage( - 0, set([1, 2]), 3072, cpu_usage=cpus, + return objects.NUMATopology( + cells=[objects.NUMACell( + id=0, cpuset=set([1, 2]), memory=3072, cpu_usage=cpus, memory_usage=mem), - hardware.VirtNUMATopologyCellUsage( - 1, set([3, 4]), 3072, cpu_usage=cpus, + objects.NUMACell( + id=1, cpuset=set([3, 4]), memory=3072, cpu_usage=cpus, memory_usage=mem)]) @mock.patch('nova.objects.InstancePCIRequests.get_by_instance_uuid', @@ -792,7 +794,7 @@ class InstanceClaimTestCase(BaseTrackerTestCase): self.assertEqual(FAKE_VIRT_MEMORY_MB - claim_mem_total, self.compute["free_ram_mb"]) self.assertEqualNUMAHostTopology( - claim_topology, hardware.VirtNUMAHostTopology.from_json( + claim_topology, objects.NUMATopology.obj_from_db_obj( self.compute['numa_topology'])) self.assertEqual(FAKE_VIRT_LOCAL_GB, self.compute["local_gb"]) @@ -817,7 +819,7 @@ class InstanceClaimTestCase(BaseTrackerTestCase): self.assertEqual(FAKE_VIRT_MEMORY_MB - claim_mem_total, self.compute['free_ram_mb']) self.assertEqualNUMAHostTopology( - claim_topology, hardware.VirtNUMAHostTopology.from_json( + claim_topology, objects.NUMATopology.obj_from_db_obj( self.compute['numa_topology'])) self.assertEqual(claim_disk, self.compute['local_gb_used']) @@ -845,7 +847,7 @@ class InstanceClaimTestCase(BaseTrackerTestCase): self.assertEqual(FAKE_VIRT_MEMORY_MB - claim_mem_total, self.compute["free_ram_mb"]) self.assertEqualNUMAHostTopology( - claim_topology, hardware.VirtNUMAHostTopology.from_json( + claim_topology, objects.NUMATopology.obj_from_db_obj( self.compute['numa_topology'])) self.assertEqual(claim_disk, self.compute["local_gb_used"]) @@ -858,7 +860,7 @@ class InstanceClaimTestCase(BaseTrackerTestCase): self.assertEqual(FAKE_VIRT_MEMORY_MB, self.compute["free_ram_mb"]) self.assertEqualNUMAHostTopology( FAKE_VIRT_NUMA_TOPOLOGY, - hardware.VirtNUMAHostTopology.from_json( + objects.NUMATopology.obj_from_db_obj( self.compute['numa_topology'])) self.assertEqual(0, self.compute["local_gb_used"]) @@ -887,7 +889,7 @@ class InstanceClaimTestCase(BaseTrackerTestCase): self.tracker.compute_node['memory_mb_used']) self.assertEqualNUMAHostTopology( claim_topology, - hardware.VirtNUMAHostTopology.from_json( + objects.NUMATopology.obj_from_db_obj( self.compute['numa_topology'])) self.assertEqual(root_gb * 2, self.tracker.compute_node['local_gb_used']) @@ -919,7 +921,7 @@ class InstanceClaimTestCase(BaseTrackerTestCase): self.assertEqualNUMAHostTopology( claim_topology, - hardware.VirtNUMAHostTopology.from_json( + objects.NUMATopology.obj_from_db_obj( self.compute['numa_topology'])) @mock.patch('nova.objects.InstancePCIRequests.get_by_instance_uuid', @@ -939,7 +941,7 @@ class InstanceClaimTestCase(BaseTrackerTestCase): self.assertEqual(0, self.compute['local_gb_used']) self.assertEqualNUMAHostTopology( FAKE_VIRT_NUMA_TOPOLOGY, - hardware.VirtNUMAHostTopology.from_json( + objects.NUMATopology.obj_from_db_obj( self.compute['numa_topology'])) @mock.patch('nova.objects.InstancePCIRequests.get_by_instance_uuid', @@ -962,7 +964,7 @@ class InstanceClaimTestCase(BaseTrackerTestCase): self.compute['memory_mb_used']) self.assertEqualNUMAHostTopology( claim_topology, - hardware.VirtNUMAHostTopology.from_json( + objects.NUMATopology.obj_from_db_obj( self.compute['numa_topology'])) self.assertEqual(flavor['root_gb'] + flavor['ephemeral_gb'], self.compute['local_gb_used']) @@ -978,7 +980,7 @@ class InstanceClaimTestCase(BaseTrackerTestCase): self.compute['memory_mb_used']) self.assertEqualNUMAHostTopology( claim_topology, - hardware.VirtNUMAHostTopology.from_json( + objects.NUMATopology.obj_from_db_obj( self.compute['numa_topology'])) self.assertEqual(flavor['root_gb'] + flavor['ephemeral_gb'], self.compute['local_gb_used']) diff --git a/nova/tests/unit/objects/test_compute_node.py b/nova/tests/unit/objects/test_compute_node.py index 0bbf8050c8..be717af0b8 100644 --- a/nova/tests/unit/objects/test_compute_node.py +++ b/nova/tests/unit/objects/test_compute_node.py @@ -18,11 +18,11 @@ from oslo.utils import timeutils from nova import db from nova import exception +from nova import objects from nova.objects import compute_node from nova.objects import hv_spec from nova.objects import service from nova.tests.unit.objects import test_objects -from nova.virt import hardware NOW = timeutils.utcnow().replace(microsecond=0) fake_stats = {'num_foo': '10'} @@ -30,10 +30,12 @@ fake_stats_db_format = jsonutils.dumps(fake_stats) # host_ip is coerced from a string to an IPAddress # but needs to be converted to a string for the database format fake_host_ip = '127.0.0.1' -fake_numa_topology = hardware.VirtNUMAHostTopology( - cells=[hardware.VirtNUMATopologyCellUsage(0, set([1, 2]), 512), - hardware.VirtNUMATopologyCellUsage(1, set([3, 4]), 512)]) -fake_numa_topology_db_format = fake_numa_topology.to_json() +fake_numa_topology = objects.NUMATopology( + cells=[objects.NUMACell(id=0, cpuset=set([1, 2]), memory=512, + cpu_usage=0, memory_usage=0), + objects.NUMACell(id=1, cpuset=set([3, 4]), memory=512, + cpu_usage=0, memory_usage=0)]) +fake_numa_topology_db_format = fake_numa_topology._to_json() fake_hv_spec = hv_spec.HVSpec(arch='foo', hv_type='bar', vm_mode='foobar') fake_supported_hv_specs = [fake_hv_spec] # for backward compatibility, each supported instance object diff --git a/nova/tests/unit/scheduler/fakes.py b/nova/tests/unit/scheduler/fakes.py index d1b2918d33..487616e55f 100644 --- a/nova/tests/unit/scheduler/fakes.py +++ b/nova/tests/unit/scheduler/fakes.py @@ -21,15 +21,17 @@ from oslo.serialization import jsonutils from nova.compute import vm_states from nova import db +from nova import objects from nova.scheduler import filter_scheduler from nova.scheduler import host_manager -from nova.virt import hardware -NUMA_TOPOLOGY = hardware.VirtNUMAHostTopology( - cells=[hardware.VirtNUMATopologyCellUsage( - 0, set([1, 2]), 512), - hardware.VirtNUMATopologyCellUsage( - 1, set([3, 4]), 512)]) +NUMA_TOPOLOGY = objects.NUMATopology( + cells=[objects.NUMACell( + id=0, cpuset=set([1, 2]), memory=512, + cpu_usage=0, memory_usage=0), + objects.NUMACell( + id=1, cpuset=set([3, 4]), memory=512, + cpu_usage=0, memory_usage=0)]) COMPUTE_NODES = [ dict(id=1, local_gb=1024, memory_mb=1024, vcpus=1, @@ -49,7 +51,7 @@ COMPUTE_NODES = [ free_disk_gb=3072, local_gb_used=0, updated_at=None, service=dict(host='host3', disabled=False), hypervisor_hostname='node3', host_ip='127.0.0.1', - hypervisor_version=0, numa_topology=NUMA_TOPOLOGY.to_json()), + hypervisor_version=0, numa_topology=NUMA_TOPOLOGY._to_json()), dict(id=4, local_gb=8192, memory_mb=8192, vcpus=8, disk_available_least=8192, free_ram_mb=8192, vcpus_used=0, free_disk_gb=8888, local_gb_used=0, updated_at=None, diff --git a/nova/tests/unit/scheduler/test_host_manager.py b/nova/tests/unit/scheduler/test_host_manager.py index c45483388e..58485b8c6d 100644 --- a/nova/tests/unit/scheduler/test_host_manager.py +++ b/nova/tests/unit/scheduler/test_host_manager.py @@ -26,13 +26,13 @@ from nova.compute import vm_states from nova import db from nova import exception from nova.i18n import _LW +from nova import objects from nova.scheduler import filters from nova.scheduler import host_manager from nova import test from nova.tests.unit import matchers from nova.tests.unit.scheduler import fakes from nova import utils -from nova.virt import hardware class FakeFilterClass1(filters.BaseHostFilter): @@ -319,7 +319,7 @@ class HostManagerTestCase(test.NoDBTestCase): self.assertEqual(host_states_map[('host3', 'node3')].free_disk_mb, 3145728) self.assertThat( - hardware.VirtNUMAHostTopology.from_json( + objects.NUMATopology.obj_from_db_obj( host_states_map[('host3', 'node3')].numa_topology )._to_dict(), matchers.DictMatches(fakes.NUMA_TOPOLOGY._to_dict())) @@ -532,7 +532,7 @@ class HostStateTestCase(test.NoDBTestCase): local_gb_used=0, free_ram_mb=0, vcpus=0, vcpus_used=0, updated_at=None, host_ip='127.0.0.1', hypervisor_version=hyper_ver_int, - numa_topology=fakes.NUMA_TOPOLOGY.to_json()) + numa_topology=fakes.NUMA_TOPOLOGY._to_json()) host = host_manager.HostState("fakehost", "fakenode") host.update_from_compute_node(compute) diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index 0929950d28..bd3ef2e3e4 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -10594,11 +10594,13 @@ class HostStateTestCase(test.NoDBTestCase): "vendor_id": '8086', "dev_type": 'type-PF', "phys_function": None}] - numa_topology = hardware.VirtNUMAHostTopology( - cells=[hardware.VirtNUMATopologyCellUsage( - 1, set([1, 2]), 1024), - hardware.VirtNUMATopologyCellUsage( - 2, set([3, 4]), 1024)]) + numa_topology = objects.NUMATopology( + cells=[objects.NUMACell( + id=1, cpuset=set([1, 2]), memory=1024, + cpu_usage=0, memory_usage=0), + objects.NUMACell( + id=2, cpuset=set([3, 4]), memory=1024, + cpu_usage=0, memory_usage=0)]) class FakeConnection(libvirt_driver.LibvirtDriver): """Fake connection object.""" @@ -10676,7 +10678,7 @@ class HostStateTestCase(test.NoDBTestCase): self.assertEqual(stats["disk_available_least"], 80) self.assertEqual(jsonutils.loads(stats["pci_passthrough_devices"]), HostStateTestCase.pci_devices) - self.assertThat(hardware.VirtNUMAHostTopology.from_json( + self.assertThat(objects.NUMATopology.obj_from_db_obj( stats['numa_topology'])._to_dict(), matchers.DictMatches( HostStateTestCase.numa_topology._to_dict())) diff --git a/nova/tests/unit/virt/test_hardware.py b/nova/tests/unit/virt/test_hardware.py index a8c906a388..0a6dfbc3a3 100644 --- a/nova/tests/unit/virt/test_hardware.py +++ b/nova/tests/unit/virt/test_hardware.py @@ -893,10 +893,13 @@ class NUMATopologyTest(test.NoDBTestCase): topology.cells[i].memory) def test_host_usage_contiguous(self): - hosttopo = hw.VirtNUMAHostTopology([ - hw.VirtNUMATopologyCellUsage(0, set([0, 1, 2, 3]), 1024), - hw.VirtNUMATopologyCellUsage(1, set([4, 6]), 512), - hw.VirtNUMATopologyCellUsage(2, set([5, 7]), 512), + hosttopo = objects.NUMATopology(cells=[ + objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=1024, + cpu_usage=0, memory_usage=0), + objects.NUMACell(id=1, cpuset=set([4, 6]), memory=512, + cpu_usage=0, memory_usage=0), + objects.NUMACell(id=2, cpuset=set([5, 7]), memory=512, + cpu_usage=0, memory_usage=0), ]) instance1 = objects.InstanceNUMATopology(cells=[ objects.InstanceNUMACell(id=0, cpuset=set([0, 1, 2]), memory=256), @@ -907,13 +910,12 @@ class NUMATopologyTest(test.NoDBTestCase): objects.InstanceNUMACell(id=1, cpuset=set([5, 7]), memory=256), ]) - hostusage = hw.VirtNUMAHostTopology.usage_from_instances( + hostusage = hw.numa_usage_from_instances( hosttopo, [instance1, instance2]) self.assertEqual(len(hosttopo), len(hostusage)) - self.assertIsInstance(hostusage.cells[0], - hw.VirtNUMATopologyCellUsage) + self.assertIsInstance(hostusage.cells[0], objects.NUMACell) self.assertEqual(hosttopo.cells[0].cpuset, hostusage.cells[0].cpuset) self.assertEqual(hosttopo.cells[0].memory, @@ -921,8 +923,7 @@ class NUMATopologyTest(test.NoDBTestCase): self.assertEqual(hostusage.cells[0].cpu_usage, 5) self.assertEqual(hostusage.cells[0].memory_usage, 512) - self.assertIsInstance(hostusage.cells[1], - hw.VirtNUMATopologyCellUsage) + self.assertIsInstance(hostusage.cells[1], objects.NUMACell) self.assertEqual(hosttopo.cells[1].cpuset, hostusage.cells[1].cpuset) self.assertEqual(hosttopo.cells[1].memory, @@ -930,8 +931,7 @@ class NUMATopologyTest(test.NoDBTestCase): self.assertEqual(hostusage.cells[1].cpu_usage, 3) self.assertEqual(hostusage.cells[1].memory_usage, 512) - self.assertIsInstance(hostusage.cells[2], - hw.VirtNUMATopologyCellUsage) + self.assertIsInstance(hostusage.cells[2], objects.NUMACell) self.assertEqual(hosttopo.cells[2].cpuset, hostusage.cells[2].cpuset) self.assertEqual(hosttopo.cells[2].memory, @@ -940,27 +940,31 @@ class NUMATopologyTest(test.NoDBTestCase): self.assertEqual(hostusage.cells[2].memory_usage, 0) def test_host_usage_sparse(self): - hosttopo = hw.VirtNUMAHostTopology([ - hw.VirtNUMATopologyCellUsage(0, set([0, 1, 2, 3]), 1024), - hw.VirtNUMATopologyCellUsage(5, set([4, 6]), 512), - hw.VirtNUMATopologyCellUsage(6, set([5, 7]), 512), + hosttopo = objects.NUMATopology(cells=[ + objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=1024, + cpu_usage=0, memory_usage=0), + objects.NUMACell(id=5, cpuset=set([4, 6]), memory=512, + cpu_usage=0, memory_usage=0), + objects.NUMACell(id=6, cpuset=set([5, 7]), memory=512, + cpu_usage=0, memory_usage=0), ]) instance1 = objects.InstanceNUMATopology(cells=[ objects.InstanceNUMACell(id=0, cpuset=set([0, 1, 2]), memory=256), objects.InstanceNUMACell(id=6, cpuset=set([4]), memory=256), ]) instance2 = objects.InstanceNUMATopology(cells=[ - objects.InstanceNUMACell(id=0, cpuset=set([0, 1]), memory=256), - objects.InstanceNUMACell(id=5, cpuset=set([5, 7]), memory=256), + objects.InstanceNUMACell(id=0, cpuset=set([0, 1]), memory=256, + cpu_usage=0, memory_usage=0), + objects.InstanceNUMACell(id=5, cpuset=set([5, 7]), memory=256, + cpu_usage=0, memory_usage=0), ]) - hostusage = hw.VirtNUMAHostTopology.usage_from_instances( + hostusage = hw.numa_usage_from_instances( hosttopo, [instance1, instance2]) self.assertEqual(len(hosttopo), len(hostusage)) - self.assertIsInstance(hostusage.cells[0], - hw.VirtNUMATopologyCellUsage) + self.assertIsInstance(hostusage.cells[0], objects.NUMACell) self.assertEqual(hosttopo.cells[0].id, hostusage.cells[0].id) self.assertEqual(hosttopo.cells[0].cpuset, @@ -970,8 +974,7 @@ class NUMATopologyTest(test.NoDBTestCase): self.assertEqual(hostusage.cells[0].cpu_usage, 5) self.assertEqual(hostusage.cells[0].memory_usage, 512) - self.assertIsInstance(hostusage.cells[1], - hw.VirtNUMATopologyCellUsage) + self.assertIsInstance(hostusage.cells[1], objects.NUMACell) self.assertEqual(hosttopo.cells[1].id, hostusage.cells[1].id) self.assertEqual(hosttopo.cells[1].cpuset, @@ -981,8 +984,7 @@ class NUMATopologyTest(test.NoDBTestCase): self.assertEqual(hostusage.cells[1].cpu_usage, 2) self.assertEqual(hostusage.cells[1].memory_usage, 256) - self.assertIsInstance(hostusage.cells[2], - hw.VirtNUMATopologyCellUsage) + self.assertIsInstance(hostusage.cells[2], objects.NUMACell) self.assertEqual(hosttopo.cells[2].cpuset, hostusage.cells[2].cpuset) self.assertEqual(hosttopo.cells[2].memory, @@ -991,37 +993,35 @@ class NUMATopologyTest(test.NoDBTestCase): self.assertEqual(hostusage.cells[2].memory_usage, 256) def test_host_usage_culmulative_with_free(self): - hosttopo = hw.VirtNUMAHostTopology([ - hw.VirtNUMATopologyCellUsage( - 0, set([0, 1, 2, 3]), 1024, cpu_usage=2, memory_usage=512), - hw.VirtNUMATopologyCellUsage( - 1, set([4, 6]), 512, cpu_usage=1, memory_usage=512), - hw.VirtNUMATopologyCellUsage(2, set([5, 7]), 256), + hosttopo = objects.NUMATopology(cells=[ + objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=1024, + cpu_usage=2, memory_usage=512), + objects.NUMACell(id=1, cpuset=set([4, 6]), memory=512, + cpu_usage=1, memory_usage=512), + objects.NUMACell(id=2, cpuset=set([5, 7]), memory=256, + cpu_usage=0, memory_usage=0), ]) instance1 = objects.InstanceNUMATopology(cells=[ objects.InstanceNUMACell(id=0, cpuset=set([0, 1, 2]), memory=512), objects.InstanceNUMACell(id=1, cpuset=set([3]), memory=256), objects.InstanceNUMACell(id=2, cpuset=set([4]), memory=256)]) - hostusage = hw.VirtNUMAHostTopology.usage_from_instances( + hostusage = hw.numa_usage_from_instances( hosttopo, [instance1]) - self.assertIsInstance(hostusage.cells[0], - hw.VirtNUMATopologyCellUsage) + self.assertIsInstance(hostusage.cells[0], objects.NUMACell) self.assertEqual(hostusage.cells[0].cpu_usage, 5) self.assertEqual(hostusage.cells[0].memory_usage, 1024) - self.assertIsInstance(hostusage.cells[1], - hw.VirtNUMATopologyCellUsage) + self.assertIsInstance(hostusage.cells[1], objects.NUMACell) self.assertEqual(hostusage.cells[1].cpu_usage, 2) self.assertEqual(hostusage.cells[1].memory_usage, 768) - self.assertIsInstance(hostusage.cells[2], - hw.VirtNUMATopologyCellUsage) + self.assertIsInstance(hostusage.cells[2], objects.NUMACell) self.assertEqual(hostusage.cells[2].cpu_usage, 1) self.assertEqual(hostusage.cells[2].memory_usage, 256) # Test freeing of resources - hostusage = hw.VirtNUMAHostTopology.usage_from_instances( + hostusage = hw.numa_usage_from_instances( hostusage, [instance1], free=True) self.assertEqual(hostusage.cells[0].cpu_usage, 2) self.assertEqual(hostusage.cells[0].memory_usage, 512) @@ -1033,27 +1033,29 @@ class NUMATopologyTest(test.NoDBTestCase): self.assertEqual(hostusage.cells[2].memory_usage, 0) def test_topo_usage_none(self): - hosttopo = hw.VirtNUMAHostTopology([ - hw.VirtNUMATopologyCellUsage(0, set([0, 1]), 512), - hw.VirtNUMATopologyCellUsage(1, set([2, 3]), 512), + hosttopo = objects.NUMATopology(cells=[ + objects.NUMACell(id=0, cpuset=set([0, 1]), memory=512, + cpu_usage=0, memory_usage=0), + objects.NUMACell(id=1, cpuset=set([2, 3]), memory=512, + cpu_usage=0, memory_usage=0), ]) instance1 = objects.InstanceNUMATopology(cells=[ objects.InstanceNUMACell(id=0, cpuset=set([0, 1]), memory=256), objects.InstanceNUMACell(id=2, cpuset=set([2]), memory=256), ]) - hostusage = hw.VirtNUMAHostTopology.usage_from_instances( + hostusage = hw.numa_usage_from_instances( None, [instance1]) self.assertIsNone(hostusage) - hostusage = hw.VirtNUMAHostTopology.usage_from_instances( + hostusage = hw.numa_usage_from_instances( hosttopo, []) self.assertEqual(hostusage.cells[0].cpu_usage, 0) self.assertEqual(hostusage.cells[0].memory_usage, 0) self.assertEqual(hostusage.cells[1].cpu_usage, 0) self.assertEqual(hostusage.cells[1].memory_usage, 0) - hostusage = hw.VirtNUMAHostTopology.usage_from_instances( + hostusage = hw.numa_usage_from_instances( hosttopo, None) self.assertEqual(hostusage.cells[0].cpu_usage, 0) self.assertEqual(hostusage.cells[0].memory_usage, 0) @@ -1062,7 +1064,7 @@ class NUMATopologyTest(test.NoDBTestCase): def assertNUMACellMatches(self, expected_cell, got_cell): attrs = ('cpuset', 'memory', 'id') - if isinstance(expected_cell, hw.VirtNUMAHostTopology): + if isinstance(expected_cell, objects.NUMATopology): attrs += ('cpu_usage', 'memory_usage') for attr in attrs: @@ -1070,13 +1072,13 @@ class NUMATopologyTest(test.NoDBTestCase): getattr(got_cell, attr)) def test_json(self): - expected = hw.VirtNUMAHostTopology( + expected = objects.NUMATopology( cells=[ - hw.VirtNUMATopologyCellUsage( - 1, set([1, 2]), 1024), - hw.VirtNUMATopologyCellUsage( - 2, set([3, 4]), 1024)]) - got = hw.VirtNUMAHostTopology.from_json(expected.to_json()) + objects.NUMACell(id=1, cpuset=set([1, 2]), memory=1024, + cpu_usage=0, memory_usage=0), + objects.NUMACell(id=2, cpuset=set([3, 4]), memory=1024, + cpu_usage=0, memory_usage=0)]) + got = objects.NUMATopology.obj_from_db_obj(expected._to_json()) for exp_cell, got_cell in zip(expected.cells, got.cells): self.assertNUMACellMatches(exp_cell, got_cell) @@ -1084,54 +1086,56 @@ class NUMATopologyTest(test.NoDBTestCase): class VirtNUMATopologyCellUsageTestCase(test.NoDBTestCase): def test_fit_instance_cell_success_no_limit(self): - host_cell = hw.VirtNUMATopologyCellUsage(4, set([1, 2]), 1024) + host_cell = objects.NUMACell(id=4, cpuset=set([1, 2]), memory=1024, + cpu_usage=0, memory_usage=0) instance_cell = objects.InstanceNUMACell( id=0, cpuset=set([1, 2]), memory=1024) - fitted_cell = host_cell.fit_instance_cell(host_cell, instance_cell) + fitted_cell = hw._numa_fit_instance_cell(host_cell, instance_cell) self.assertIsInstance(fitted_cell, objects.InstanceNUMACell) self.assertEqual(host_cell.id, fitted_cell.id) def test_fit_instance_cell_success_w_limit(self): - host_cell = hw.VirtNUMATopologyCellUsage(4, set([1, 2]), 1024, + host_cell = objects.NUMACell(id=4, cpuset=set([1, 2]), memory=1024, cpu_usage=2, memory_usage=1024) limit_cell = hw.VirtNUMATopologyCellLimit( - 4, set([1, 2]), 1024, + 4, cpuset=set([1, 2]), memory=1024, cpu_limit=4, memory_limit=2048) instance_cell = objects.InstanceNUMACell( id=0, cpuset=set([1, 2]), memory=1024) - fitted_cell = host_cell.fit_instance_cell( + fitted_cell = hw._numa_fit_instance_cell( host_cell, instance_cell, limit_cell=limit_cell) self.assertIsInstance(fitted_cell, objects.InstanceNUMACell) self.assertEqual(host_cell.id, fitted_cell.id) def test_fit_instance_cell_self_overcommit(self): - host_cell = hw.VirtNUMATopologyCellUsage(4, set([1, 2]), 1024) + host_cell = objects.NUMACell(id=4, cpuset=set([1, 2]), memory=1024, + cpu_usage=0, memory_usage=0) limit_cell = hw.VirtNUMATopologyCellLimit( - 4, set([1, 2]), 1024, + 4, cpuset=set([1, 2]), memory=1024, cpu_limit=4, memory_limit=2048) instance_cell = objects.InstanceNUMACell( id=0, cpuset=set([1, 2, 3]), memory=4096) - fitted_cell = host_cell.fit_instance_cell( + fitted_cell = hw._numa_fit_instance_cell( host_cell, instance_cell, limit_cell=limit_cell) self.assertIsNone(fitted_cell) def test_fit_instance_cell_fail_w_limit(self): - host_cell = hw.VirtNUMATopologyCellUsage(4, set([1, 2]), 1024, + host_cell = objects.NUMACell(id=4, cpuset=set([1, 2]), memory=1024, cpu_usage=2, memory_usage=1024) limit_cell = hw.VirtNUMATopologyCellLimit( - 4, set([1, 2]), 1024, + 4, cpuset=set([1, 2]), memory=1024, cpu_limit=4, memory_limit=2048) instance_cell = objects.InstanceNUMACell( id=0, cpuset=set([1, 2]), memory=4096) - fitted_cell = host_cell.fit_instance_cell( + fitted_cell = hw._numa_fit_instance_cell( host_cell, instance_cell, limit_cell=limit_cell) self.assertIsNone(fitted_cell) instance_cell = objects.InstanceNUMACell( id=0, cpuset=set([1, 2, 3, 4, 5]), memory=1024) - fitted_cell = host_cell.fit_instance_cell( + fitted_cell = hw._numa_fit_instance_cell( host_cell, instance_cell, limit_cell=limit_cell) self.assertIsNone(fitted_cell) @@ -1140,22 +1144,20 @@ class VirtNUMAHostTopologyTestCase(test.NoDBTestCase): def setUp(self): super(VirtNUMAHostTopologyTestCase, self).setUp() - self.host = hw.VirtNUMAHostTopology( + self.host = objects.NUMATopology( cells=[ - hw.VirtNUMATopologyCellUsage( - 1, set([1, 2]), 2048, + objects.NUMACell(id=1, cpuset=set([1, 2]), memory=2048, cpu_usage=2, memory_usage=2048), - hw.VirtNUMATopologyCellUsage( - 2, set([3, 4]), 2048, + objects.NUMACell(id=2, cpuset=set([3, 4]), memory=2048, cpu_usage=2, memory_usage=2048)]) self.limits = hw.VirtNUMALimitTopology( cells=[ hw.VirtNUMATopologyCellLimit( - 1, set([1, 2]), 2048, + 1, cpuset=set([1, 2]), memory=2048, cpu_limit=4, memory_limit=4096), hw.VirtNUMATopologyCellLimit( - 2, set([3, 4]), 2048, + 2, cpuset=set([3, 4]), memory=2048, cpu_limit=4, memory_limit=3072)]) self.instance1 = objects.InstanceNUMATopology( @@ -1172,45 +1174,45 @@ class VirtNUMAHostTopologyTestCase(test.NoDBTestCase): id=0, cpuset=set([1, 2]), memory=1024)]) def test_get_fitting_success_no_limits(self): - fitted_instance1 = hw.VirtNUMAHostTopology.fit_instance_to_host( + fitted_instance1 = hw.numa_fit_instance_to_host( self.host, self.instance1) self.assertIsInstance(fitted_instance1, objects.InstanceNUMATopology) - self.host = hw.VirtNUMAHostTopology.usage_from_instances(self.host, + self.host = hw.numa_usage_from_instances(self.host, [fitted_instance1]) - fitted_instance2 = hw.VirtNUMAHostTopology.fit_instance_to_host( + fitted_instance2 = hw.numa_fit_instance_to_host( self.host, self.instance3) self.assertIsInstance(fitted_instance2, objects.InstanceNUMATopology) def test_get_fitting_success_limits(self): - fitted_instance = hw.VirtNUMAHostTopology.fit_instance_to_host( + fitted_instance = hw.numa_fit_instance_to_host( self.host, self.instance3, self.limits) self.assertIsInstance(fitted_instance, objects.InstanceNUMATopology) self.assertEqual(1, fitted_instance.cells[0].id) def test_get_fitting_fails_no_limits(self): - fitted_instance = hw.VirtNUMAHostTopology.fit_instance_to_host( + fitted_instance = hw.numa_fit_instance_to_host( self.host, self.instance2, self.limits) self.assertIsNone(fitted_instance) def test_get_fitting_culmulative_fails_limits(self): - fitted_instance1 = hw.VirtNUMAHostTopology.fit_instance_to_host( + fitted_instance1 = hw.numa_fit_instance_to_host( self.host, self.instance1, self.limits) self.assertIsInstance(fitted_instance1, objects.InstanceNUMATopology) self.assertEqual(1, fitted_instance1.cells[0].id) - self.host = hw.VirtNUMAHostTopology.usage_from_instances(self.host, + self.host = hw.numa_usage_from_instances(self.host, [fitted_instance1]) - fitted_instance2 = hw.VirtNUMAHostTopology.fit_instance_to_host( + fitted_instance2 = hw.numa_fit_instance_to_host( self.host, self.instance1, self.limits) self.assertIsNone(fitted_instance2) def test_get_fitting_culmulative_success_limits(self): - fitted_instance1 = hw.VirtNUMAHostTopology.fit_instance_to_host( + fitted_instance1 = hw.numa_fit_instance_to_host( self.host, self.instance1, self.limits) self.assertIsInstance(fitted_instance1, objects.InstanceNUMATopology) self.assertEqual(1, fitted_instance1.cells[0].id) - self.host = hw.VirtNUMAHostTopology.usage_from_instances(self.host, + self.host = hw.numa_usage_from_instances(self.host, [fitted_instance1]) - fitted_instance2 = hw.VirtNUMAHostTopology.fit_instance_to_host( + fitted_instance2 = hw.numa_fit_instance_to_host( self.host, self.instance3, self.limits) self.assertIsInstance(fitted_instance2, objects.InstanceNUMATopology) self.assertEqual(2, fitted_instance2.cells[0].id) @@ -1263,9 +1265,11 @@ class NumberOfSerialPortsTest(test.NoDBTestCase): class HelperMethodsTestCase(test.NoDBTestCase): def setUp(self): super(HelperMethodsTestCase, self).setUp() - self.hosttopo = hw.VirtNUMAHostTopology([ - hw.VirtNUMATopologyCellUsage(0, set([0, 1]), 512), - hw.VirtNUMATopologyCellUsage(1, set([2, 3]), 512), + self.hosttopo = objects.NUMATopology(cells=[ + objects.NUMACell(id=0, cpuset=set([0, 1]), memory=512, + memory_usage=0, cpu_usage=0), + objects.NUMACell(id=1, cpuset=set([2, 3]), memory=512, + memory_usage=0, cpu_usage=0), ]) self.instancetopo = objects.InstanceNUMATopology( instance_uuid='fake-uuid', @@ -1285,19 +1289,19 @@ class HelperMethodsTestCase(test.NoDBTestCase): self.assertEqual(256, host_usage.cells[1].memory_usage) def test_dicts_json(self): - host = {'numa_topology': self.hosttopo.to_json()} + host = {'numa_topology': self.hosttopo._to_json()} instance = {'numa_topology': self.instancetopo._to_json()} res = hw.get_host_numa_usage_from_instance(host, instance) self.assertIsInstance(res, six.string_types) - self._check_usage(hw.VirtNUMAHostTopology.from_json(res)) + self._check_usage(objects.NUMATopology.obj_from_db_obj(res)) def test_dicts_instance_json(self): host = {'numa_topology': self.hosttopo} instance = {'numa_topology': self.instancetopo._to_json()} res = hw.get_host_numa_usage_from_instance(host, instance) - self.assertIsInstance(res, hw.VirtNUMAHostTopology) + self.assertIsInstance(res, objects.NUMATopology) self._check_usage(res) def test_dicts_instance_json_old(self): @@ -1306,35 +1310,44 @@ class HelperMethodsTestCase(test.NoDBTestCase): jsonutils.dumps(self.instancetopo._to_dict())} res = hw.get_host_numa_usage_from_instance(host, instance) - self.assertIsInstance(res, hw.VirtNUMAHostTopology) + self.assertIsInstance(res, objects.NUMATopology) self._check_usage(res) def test_dicts_host_json(self): - host = {'numa_topology': self.hosttopo.to_json()} + host = {'numa_topology': self.hosttopo._to_json()} instance = {'numa_topology': self.instancetopo} res = hw.get_host_numa_usage_from_instance(host, instance) self.assertIsInstance(res, six.string_types) - self._check_usage(hw.VirtNUMAHostTopology.from_json(res)) + self._check_usage(objects.NUMATopology.obj_from_db_obj(res)) + + def test_dicts_host_json_old(self): + host = {'numa_topology': jsonutils.dumps( + self.hosttopo._to_dict())} + instance = {'numa_topology': self.instancetopo} + + res = hw.get_host_numa_usage_from_instance(host, instance) + self.assertIsInstance(res, six.string_types) + self._check_usage(objects.NUMATopology.obj_from_db_obj(res)) def test_object_host_instance_json(self): - host = objects.ComputeNode(numa_topology=self.hosttopo.to_json()) + host = objects.ComputeNode(numa_topology=self.hosttopo._to_json()) instance = {'numa_topology': self.instancetopo._to_json()} res = hw.get_host_numa_usage_from_instance(host, instance) self.assertIsInstance(res, six.string_types) - self._check_usage(hw.VirtNUMAHostTopology.from_json(res)) + self._check_usage(objects.NUMATopology.obj_from_db_obj(res)) def test_object_host_instance(self): - host = objects.ComputeNode(numa_topology=self.hosttopo.to_json()) + host = objects.ComputeNode(numa_topology=self.hosttopo._to_json()) instance = {'numa_topology': self.instancetopo} res = hw.get_host_numa_usage_from_instance(host, instance) self.assertIsInstance(res, six.string_types) - self._check_usage(hw.VirtNUMAHostTopology.from_json(res)) + self._check_usage(objects.NUMATopology.obj_from_db_obj(res)) def test_instance_with_fetch(self): - host = objects.ComputeNode(numa_topology=self.hosttopo.to_json()) + host = objects.ComputeNode(numa_topology=self.hosttopo._to_json()) fake_uuid = str(uuid.uuid4()) instance = {'uuid': fake_uuid} @@ -1345,7 +1358,7 @@ class HelperMethodsTestCase(test.NoDBTestCase): self.assertTrue(get_mock.called) def test_object_instance_with_load(self): - host = objects.ComputeNode(numa_topology=self.hosttopo.to_json()) + host = objects.ComputeNode(numa_topology=self.hosttopo._to_json()) fake_uuid = str(uuid.uuid4()) instance = objects.Instance(context=self.context, uuid=fake_uuid) @@ -1356,7 +1369,7 @@ class HelperMethodsTestCase(test.NoDBTestCase): self.assertTrue(get_mock.called) def test_instance_serialized_by_build_request_spec(self): - host = objects.ComputeNode(numa_topology=self.hosttopo.to_json()) + host = objects.ComputeNode(numa_topology=self.hosttopo._to_json()) fake_uuid = str(uuid.uuid4()) instance = objects.Instance(context=self.context, id=1, uuid=fake_uuid, numa_topology=self.instancetopo) @@ -1366,27 +1379,27 @@ class HelperMethodsTestCase(test.NoDBTestCase): base_obj.obj_to_primitive(instance)) res = hw.get_host_numa_usage_from_instance(host, instance_raw) self.assertIsInstance(res, six.string_types) - self._check_usage(hw.VirtNUMAHostTopology.from_json(res)) + self._check_usage(objects.NUMATopology.obj_from_db_obj(res)) def test_attr_host(self): class Host(object): def __init__(obj): - obj.numa_topology = self.hosttopo.to_json() + obj.numa_topology = self.hosttopo._to_json() host = Host() instance = {'numa_topology': self.instancetopo._to_json()} res = hw.get_host_numa_usage_from_instance(host, instance) self.assertIsInstance(res, six.string_types) - self._check_usage(hw.VirtNUMAHostTopology.from_json(res)) + self._check_usage(objects.NUMATopology.obj_from_db_obj(res)) def test_never_serialize_result(self): - host = {'numa_topology': self.hosttopo.to_json()} + host = {'numa_topology': self.hosttopo._to_json()} instance = {'numa_topology': self.instancetopo} res = hw.get_host_numa_usage_from_instance(host, instance, never_serialize_result=True) - self.assertIsInstance(res, hw.VirtNUMAHostTopology) + self.assertIsInstance(res, objects.NUMATopology) self._check_usage(res) diff --git a/nova/virt/hardware.py b/nova/virt/hardware.py index 4707a1a613..b85075173f 100644 --- a/nova/virt/hardware.py +++ b/nova/virt/hardware.py @@ -652,84 +652,34 @@ class VirtNUMATopologyCellLimit(VirtNUMATopologyCell): return cls(cell_id, cpuset, memory, cpu_limit, memory_limit) -class VirtNUMATopologyCellUsage(VirtNUMATopologyCell): - """Class for reporting NUMA resources and usage in a cell +def _numa_fit_instance_cell(host_cell, instance_cell, limit_cell=None): + """Check if a instance cell can fit and set it's cell id - The VirtNUMATopologyCellUsage class specializes - VirtNUMATopologyCell to include information about the - utilization of hardware resources in a NUMA cell. + :param host_cell: host cell to fit the instance cell onto + :param instance_cell: instance cell we want to fit + :param limit_cell: cell with limits of the host_cell if any + + Make sure we can fit the instance cell onto a host cell and if so, + return a new objects.InstanceNUMACell with the id set to that of + the host, or None if the cell exceeds the limits of the host + + :returns: a new instance cell or None """ + # NOTE (ndipanov): do not allow an instance to overcommit against + # itself on any NUMA cell + if (instance_cell.memory > host_cell.memory or + len(instance_cell.cpuset) > len(host_cell.cpuset)): + return None - def __init__(self, id, cpuset, memory, cpu_usage=0, memory_usage=0): - """Create a new NUMA Cell with usage - - :param id: integer identifier of cell - :param cpuset: set containing list of CPU indexes - :param memory: RAM measured in MiB - :param cpu_usage: number of CPUs allocated - :param memory_usage: RAM allocated in MiB - - Creates a new NUMA cell object to record the hardware - resources and utilization. The number of CPUs specified - by the @cpu_usage parameter may be larger than the number - of bits set in @cpuset if CPU overcommit is used. Likewise - the amount of RAM specified by the @memory_usage parameter - may be larger than the available RAM in @memory if RAM - overcommit is used. - - :returns: a new NUMA cell object - """ - - super(VirtNUMATopologyCellUsage, self).__init__( - id, cpuset, memory) - - self.cpu_usage = cpu_usage - self.memory_usage = memory_usage - - @classmethod - def fit_instance_cell(cls, host_cell, instance_cell, limit_cell=None): - """Check if a instance cell can fit and set it's cell id - - :param host_cell: host cell to fit the instance cell onto - :param instance_cell: instance cell we want to fit - :param limit_cell: cell with limits of the host_cell if any - - Make sure we can fit the instance cell onto a host cell and if so, - return a new objects.InstanceNUMACell with the id set to that of - the host, or None if the cell exceeds the limits of the host - - :returns: a new instance cell or None - """ - # NOTE (ndipanov): do not allow an instance to overcommit against - # itself on any NUMA cell - if (instance_cell.memory > host_cell.memory or - len(instance_cell.cpuset) > len(host_cell.cpuset)): + if limit_cell: + memory_usage = host_cell.memory_usage + instance_cell.memory + cpu_usage = host_cell.cpu_usage + len(instance_cell.cpuset) + if (memory_usage > limit_cell.memory_limit or + cpu_usage > limit_cell.cpu_limit): return None - - if limit_cell: - memory_usage = host_cell.memory_usage + instance_cell.memory - cpu_usage = host_cell.cpu_usage + len(instance_cell.cpuset) - if (memory_usage > limit_cell.memory_limit or - cpu_usage > limit_cell.cpu_limit): - return None - return objects.InstanceNUMACell( - id=host_cell.id, cpuset=instance_cell.cpuset, - memory=instance_cell.memory) - - def _to_dict(self): - data_dict = super(VirtNUMATopologyCellUsage, self)._to_dict() - data_dict['mem']['used'] = self.memory_usage - data_dict['cpu_usage'] = self.cpu_usage - return data_dict - - @classmethod - def _from_dict(cls, data_dict): - cpuset = parse_cpu_spec(data_dict.get('cpus', '')) - cpu_usage = data_dict.get('cpu_usage', 0) - memory = data_dict.get('mem', {}).get('total', 0) - memory_usage = data_dict.get('mem', {}).get('used', 0) - cell_id = data_dict.get('id') - return cls(cell_id, cpuset, memory, cpu_usage, memory_usage) + return objects.InstanceNUMACell( + id=host_cell.id, cpuset=instance_cell.cpuset, + memory=instance_cell.memory) class VirtNUMATopology(object): @@ -903,93 +853,83 @@ class VirtNUMALimitTopology(VirtNUMATopology): cell_class = VirtNUMATopologyCellLimit -class VirtNUMAHostTopology(VirtNUMATopology): +def numa_fit_instance_to_host( + host_topology, instance_topology, limits_topology=None): + """Fit the instance topology onto the host topology given the limits - """Class represents the NUMA configuration and utilization - of a compute node. As well as exposing the overall topology - it tracks the utilization of the resources by guest instances + :param host_topology: objects.NUMATopology object to fit an instance on + :param instance_topology: objects.InstanceNUMATopology to be fitted + :param limits_topology: VirtNUMALimitTopology that defines limits + + Given a host and instance topology and optionally limits - this method + will attempt to fit instance cells onto all permutations of host cells + by calling the _numa_fit_instance_cell method, and return a new + InstanceNUMATopology with it's cell ids set to host cell id's of + the first successful permutation, or None. + """ + if (not (host_topology and instance_topology) or + len(host_topology) < len(instance_topology)): + return + else: + if limits_topology is None: + limits_topology_cells = itertools.repeat( + None, len(host_topology)) + else: + limits_topology_cells = limits_topology.cells + # TODO(ndipanov): We may want to sort permutations differently + # depending on whether we want packing/spreading over NUMA nodes + for host_cell_perm in itertools.permutations( + zip(host_topology.cells, limits_topology_cells), + len(instance_topology) + ): + cells = [] + for (host_cell, limit_cell), instance_cell in zip( + host_cell_perm, instance_topology.cells): + got_cell = _numa_fit_instance_cell( + host_cell, instance_cell, limit_cell) + if got_cell is None: + break + cells.append(got_cell) + if len(cells) == len(host_cell_perm): + return objects.InstanceNUMATopology(cells=cells) + + +def numa_usage_from_instances(host, instances, free=False): + """Get host topology usage + + :param host: objects.NUMATopology with usage information + :param instances: list of objects.InstanceNUMATopology + :param free: If True usage of the host will be decreased + + Sum the usage from all @instances to report the overall + host topology usage + + :returns: objects.NUMATopology including usage information """ - cell_class = VirtNUMATopologyCellUsage + if host is None: + return - @classmethod - def fit_instance_to_host(cls, host_topology, instance_topology, - limits_topology=None): - """Fit the instance topology onto the host topology given the limits + instances = instances or [] + cells = [] + sign = -1 if free else 1 + for hostcell in host.cells: + memory_usage = hostcell.memory_usage + cpu_usage = hostcell.cpu_usage + for instance in instances: + for instancecell in instance.cells: + if instancecell.id == hostcell.id: + memory_usage = ( + memory_usage + sign * instancecell.memory) + cpu_usage = cpu_usage + sign * len(instancecell.cpuset) - :param host_topology: VirtNUMAHostTopology object to fit an instance on - :param instance_topology: objects.InstanceNUMATopology to be fitted - :param limits_topology: VirtNUMALimitTopology that defines limits + cell = objects.NUMACell( + id=hostcell.id, cpuset=hostcell.cpuset, memory=hostcell.memory, + cpu_usage=max(0, cpu_usage), memory_usage=max(0, memory_usage)) - Given a host and instance topology and optionally limits - this method - will attempt to fit instance cells onto all permutations of host cells - by calling the fit_instance_cell method, and return a new - InstanceNUMATopology with it's cell ids set to host cell id's of - the first successful permutation, or None. - """ - if (not (host_topology and instance_topology) or - len(host_topology) < len(instance_topology)): - return - else: - if limits_topology is None: - limits_topology_cells = itertools.repeat( - None, len(host_topology)) - else: - limits_topology_cells = limits_topology.cells - # TODO(ndipanov): We may want to sort permutations differently - # depending on whether we want packing/spreading over NUMA nodes - for host_cell_perm in itertools.permutations( - zip(host_topology.cells, limits_topology_cells), - len(instance_topology) - ): - cells = [] - for (host_cell, limit_cell), instance_cell in zip( - host_cell_perm, instance_topology.cells): - got_cell = cls.cell_class.fit_instance_cell( - host_cell, instance_cell, limit_cell) - if got_cell is None: - break - cells.append(got_cell) - if len(cells) == len(host_cell_perm): - return objects.InstanceNUMATopology(cells=cells) + cells.append(cell) - @classmethod - def usage_from_instances(cls, host, instances, free=False): - """Get host topology usage - - :param host: VirtNUMAHostTopology with usage information - :param instances: list of objects.InstanceNUMATopology - :param free: If True usage of the host will be decreased - - Sum the usage from all @instances to report the overall - host topology usage - - :returns: VirtNUMAHostTopology including usage information - """ - - if host is None: - return - - instances = instances or [] - cells = [] - sign = -1 if free else 1 - for hostcell in host.cells: - memory_usage = hostcell.memory_usage - cpu_usage = hostcell.cpu_usage - for instance in instances: - for instancecell in instance.cells: - if instancecell.id == hostcell.id: - memory_usage = ( - memory_usage + sign * instancecell.memory) - cpu_usage = cpu_usage + sign * len(instancecell.cpuset) - - cell = cls.cell_class( - hostcell.id, hostcell.cpuset, hostcell.memory, - max(0, cpu_usage), max(0, memory_usage)) - - cells.append(cell) - - return cls(cells) + return objects.NUMATopology(cells=cells) # TODO(ndipanov): Remove when all code paths are using objects @@ -1055,7 +995,7 @@ def host_topology_and_format_from_host(host): Since we may get a host as either a dict, a db object, or an actual ComputeNode object, or an instance of HostState class, this makes sure we - get beck either None, or an instance of VirtNUMAHostTopology class. + get beck either None, or an instance of objects.NUMATopology class. :returns: A two-tuple, first element is the topology itself or None, second is a boolean set to True if topology was in json format. @@ -1069,7 +1009,9 @@ def host_topology_and_format_from_host(host): if host_numa_topology is not None and isinstance( host_numa_topology, six.string_types): was_json = True - host_numa_topology = VirtNUMAHostTopology.from_json(host_numa_topology) + + host_numa_topology = (objects.NUMATopology.obj_from_db_obj( + host_numa_topology)) return host_numa_topology, was_json @@ -1091,10 +1033,10 @@ def get_host_numa_usage_from_instance(host, instance, free=False, :param free: if True the the returned topology will have it's usage decreased instead. :param never_serialize_result: if True result will always be an instance of - VirtNUMAHostTopology class. + objects.NUMATopology class. :returns: numa_usage in the format it was on the host or - VirtNUMAHostTopology instance if never_serialize_result was True + objects.NUMATopology instance if never_serialize_result was True """ instance_numa_topology = instance_topology_from_instance(instance) if instance_numa_topology: @@ -1104,11 +1046,11 @@ def get_host_numa_usage_from_instance(host, instance, free=False, host) updated_numa_topology = ( - VirtNUMAHostTopology.usage_from_instances( - host_numa_topology, instance_numa_topology, free=free)) + numa_usage_from_instances( + host_numa_topology, instance_numa_topology, free=free)) if updated_numa_topology is not None: if jsonify_result and not never_serialize_result: - updated_numa_topology = updated_numa_topology.to_json() + updated_numa_topology = updated_numa_topology._to_json() return updated_numa_topology diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index fa7bb8e0fd..965fc54d9d 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -4912,11 +4912,13 @@ class LibvirtDriver(driver.ComputeDriver): if topology is None or not topology.cells: return - topology = hardware.VirtNUMAHostTopology( - cells=[hardware.VirtNUMATopologyCellUsage( - cell.id, set(cpu.id for cpu in cell.cpus), - cell.memory / units.Ki) - for cell in topology.cells]) + topology = objects.NUMATopology( + cells=[objects.NUMACell( + id=cell.id, + cpuset=set(cpu.id for cpu in cell.cpus), + memory=cell.memory / units.Ki, + cpu_usage=0, memory_usage=0) + for cell in topology.cells]) allowed_cpus = hardware.get_vcpu_pin_set() if allowed_cpus: @@ -5046,7 +5048,7 @@ class LibvirtDriver(driver.ComputeDriver): numa_topology = self._get_host_numa_topology() if numa_topology: - data['numa_topology'] = numa_topology.to_json() + data['numa_topology'] = numa_topology._to_json() else: data['numa_topology'] = None