objects: move virt numa instance to objects

Moves VirtNUMAInstance in InstanceNUMATopology provides by
objects.

Change-Id: I1a93f00a390312590963a9ed50722a946d772d3b
This commit is contained in:
Sahid Orentino Ferdjaoui
2014-11-21 06:24:16 -05:00
parent 74415918b9
commit bb3202f859
14 changed files with 377 additions and 500 deletions
+1 -4
View File
@@ -785,11 +785,8 @@ class API(base.Base):
block_device.properties_root_device_name(
boot_meta.get('properties', {})))
numa_topology = hardware.VirtNUMAInstanceTopology.get_constraints(
numa_topology = hardware.numa_get_constraints(
instance_type, boot_meta.get('properties', {}))
if numa_topology is not None:
numa_topology = objects.InstanceNUMATopology.obj_from_topology(
numa_topology)
system_metadata = flavors.save_flavor_info(
dict(), instance_type)
+4 -10
View File
@@ -202,8 +202,7 @@ class Claim(NopClaim):
def _test_numa_topology(self, resources, limit):
host_topology = resources.get('numa_topology')
requested_topology = (self.numa_topology and
self.numa_topology.topology_from_obj())
requested_topology = self.numa_topology
if host_topology:
host_topology = hardware.VirtNUMAHostTopology.from_json(
host_topology)
@@ -215,9 +214,7 @@ class Claim(NopClaim):
return (_("Requested instance NUMA topology cannot fit "
"the given host NUMA topology"))
elif instance_topology:
self.claimed_numa_topology = (
objects.InstanceNUMATopology.obj_from_topology(
instance_topology))
self.claimed_numa_topology = instance_topology
def _test(self, type_, unit, total, used, requested, limit):
"""Test if the given type of resource needed for a claim can be safely
@@ -274,11 +271,8 @@ class ResizeClaim(Claim):
@property
def numa_topology(self):
instance_topology = hardware.VirtNUMAInstanceTopology.get_constraints(
self.instance_type, self.image_meta)
if instance_topology:
return objects.InstanceNUMATopology.obj_from_topology(
instance_topology)
return hardware.numa_get_constraints(
self.instance_type, self.image_meta)
def _test_pci(self):
pci_requests = objects.InstancePCIRequests.\
+3 -6
View File
@@ -247,9 +247,8 @@ class ResourceTracker(object):
instance['system_metadata'])
if instance_type['id'] == itype['id']:
numa_topology = (
hardware.VirtNUMAInstanceTopology.get_constraints(
itype, image_meta))
numa_topology = hardware.numa_get_constraints(
itype, image_meta)
usage = self._get_usage_dict(
itype, numa_topology=numa_topology)
if self.pci_tracker:
@@ -603,9 +602,7 @@ class ResourceTracker(object):
if host_topology:
host_topology = hardware.VirtNUMAHostTopology.from_json(
host_topology)
numa_topology = (
hardware.VirtNUMAInstanceTopology.get_constraints(
itype, image_meta))
numa_topology = hardware.numa_get_constraints(itype, image_meta)
numa_topology = (
hardware.VirtNUMAHostTopology.fit_instance_to_host(
host_topology, numa_topology))
+52 -29
View File
@@ -33,6 +33,26 @@ class InstanceNUMACell(base.NovaObject):
'pagesize': fields.IntegerField(nullable=True),
}
def _to_dict(self):
# NOTE(sahid): Used as legacy, could be renamed in
# _legacy_to_dict_ to the future to avoid confusing.
return {'cpus': hardware.format_cpu_spec(self.cpuset,
allow_ranges=False),
'mem': {'total': self.memory},
'id': self.id,
'pagesize': self.pagesize}
@classmethod
def _from_dict(cls, data_dict):
# NOTE(sahid): Used as legacy, could be renamed in
# _legacy_from_dict_ to the future to avoid confusing.
cpuset = hardware.parse_cpu_spec(data_dict.get('cpus', ''))
memory = data_dict.get('mem', {}).get('total', 0)
cell_id = data_dict.get('id')
pagesize = data_dict.get('pagesize')
return cls(id=cell_id, cpuset=cpuset,
memory=memory, pagesize=pagesize)
class InstanceNUMATopology(base.NovaObject):
# Version 1.0: Initial version
@@ -48,43 +68,29 @@ class InstanceNUMATopology(base.NovaObject):
}
@classmethod
def obj_from_db_obj(cls, instance_uuid, db_obj):
if 'nova_object.name' in db_obj:
obj_topology = cls.obj_from_primitive(
jsonutils.loads(db_obj))
def obj_from_primitive(cls, primitive):
if 'nova_object.name' in primitive:
obj_topology = super(InstanceNUMATopology, cls).obj_from_primitive(
primitive)
else:
# NOTE(sahid): This compatibility code needs to stay until we can
# guarantee that there are no cases of the old format stored in
# the database (or forever, if we can never guarantee that).
topo = hardware.VirtNUMAInstanceTopology.from_json(db_obj)
obj_topology = cls.obj_from_topology(topo)
obj_topology.instance_uuid = instance_uuid
# No benefit to store a list of changed fields
obj_topology.obj_reset_changes()
obj_topology = InstanceNUMATopology._from_dict(primitive)
obj_topology.id = 0
return obj_topology
@classmethod
def obj_from_topology(cls, topology):
if not isinstance(topology, hardware.VirtNUMAInstanceTopology):
raise exception.ObjectActionError(action='obj_from_topology',
reason='invalid topology class')
if topology:
cells = []
for topocell in topology.cells:
cell = InstanceNUMACell(id=topocell.id, cpuset=topocell.cpuset,
memory=topocell.memory,
pagesize=topocell.pagesize)
cells.append(cell)
return cls(cells=cells)
def obj_from_db_obj(cls, instance_uuid, db_obj):
primitive = jsonutils.loads(db_obj)
obj_topology = cls.obj_from_primitive(primitive)
def topology_from_obj(self):
cells = []
for objcell in self.cells:
cell = hardware.VirtNUMATopologyCellInstance(
objcell.id, objcell.cpuset, objcell.memory, objcell.pagesize)
cells.append(cell)
return hardware.VirtNUMAInstanceTopology(cells=cells)
if 'nova_object.name' not in db_obj:
obj_topology.instance_uuid = instance_uuid
# No benefit to store a list of changed fields
obj_topology.obj_reset_changes()
return obj_topology
# TODO(ndipanov) Remove this method on the major version bump to 2.0
@base.remotable
@@ -123,3 +129,20 @@ class InstanceNUMATopology(base.NovaObject):
def _to_json(self):
return jsonutils.dumps(self.obj_to_primitive())
def __len__(self):
"""Defined so that boolean testing works the same as for lists."""
return len(self.cells)
def _to_dict(self):
# NOTE(sahid): Used as legacy, could be renamed in _legacy_to_dict_
# in the future to avoid confusing.
return {'cells': [cell._to_dict() for cell in self.cells]}
@classmethod
def _from_dict(cls, data_dict):
# NOTE(sahid): Used as legacy, could be renamed in _legacy_from_dict_
# in the future to avoid confusing.
return cls(cells=[
InstanceNUMACell._from_dict(cell_dict)
for cell_dict in data_dict.get('cells', [])])
@@ -47,7 +47,7 @@ class NUMATopologyFilter(filters.BaseHostFilter):
if not instance_topology:
return False
host_state.limits['numa_topology'] = limits.to_json()
instance['numa_topology'] = instance_topology.to_json()
instance['numa_topology'] = instance_topology
return True
elif requested_topology:
return False
@@ -2357,7 +2357,7 @@ class ServersControllerCreateTest(test.TestCase):
self._check_admin_pass_missing(server)
self.assertEqual(FAKE_UUID, server['id'])
@mock.patch('nova.virt.hardware.VirtNUMAInstanceTopology.get_constraints')
@mock.patch('nova.virt.hardware.numa_get_constraints')
def test_create_instance_numa_topology_wrong(self, numa_constraints_mock):
numa_constraints_mock.side_effect = (
exception.ImageNUMATopologyIncomplete)
+12 -12
View File
@@ -73,7 +73,7 @@ class ClaimTestCase(test.NoDBTestCase):
'id': 1, 'created_at': None, 'updated_at': None,
'deleted_at': None, 'deleted': None,
'instance_uuid': instance['uuid'],
'numa_topology': numa_topology.to_json()
'numa_topology': numa_topology._to_json()
}
else:
db_numa_topology = None
@@ -234,15 +234,15 @@ class ClaimTestCase(test.NoDBTestCase):
self.assertFalse(self.tracker.ext_resources_handler.usage_is_itype)
def test_numa_topology_no_limit(self, mock_get):
huge_instance = hardware.VirtNUMAInstanceTopology(
cells=[hardware.VirtNUMATopologyCellInstance(
1, set([1, 2]), 512)])
huge_instance = objects.InstanceNUMATopology(
cells=[objects.InstanceNUMACell(
id=1, cpuset=set([1, 2]), memory=512)])
self._claim(numa_topology=huge_instance)
def test_numa_topology_fails(self, mock_get):
huge_instance = hardware.VirtNUMAInstanceTopology(
cells=[hardware.VirtNUMATopologyCellInstance(
1, set([1, 2, 3, 4, 5]), 2048)])
huge_instance = objects.InstanceNUMATopology(
cells=[objects.InstanceNUMACell(
id=1, cpuset=set([1, 2, 3, 4, 5]), memory=2048)])
limit_topo = hardware.VirtNUMALimitTopology(
cells=[hardware.VirtNUMATopologyCellLimit(
1, [1, 2], 512, cpu_limit=2, memory_limit=512),
@@ -254,9 +254,9 @@ class ClaimTestCase(test.NoDBTestCase):
numa_topology=huge_instance)
def test_numa_topology_passes(self, mock_get):
huge_instance = hardware.VirtNUMAInstanceTopology(
cells=[hardware.VirtNUMATopologyCellInstance(
1, set([1, 2]), 512)])
huge_instance = objects.InstanceNUMATopology(
cells=[objects.InstanceNUMACell(
id=1, cpuset=set([1, 2]), memory=512)])
limit_topo = hardware.VirtNUMALimitTopology(
cells=[hardware.VirtNUMATopologyCellLimit(
1, [1, 2], 512, cpu_limit=5, memory_limit=4096),
@@ -292,8 +292,8 @@ class ResizeClaimTestCase(ClaimTestCase):
numa_constraint = kwargs.pop('numa_topology', None)
if overhead is None:
overhead = {'memory_mb': 0}
with mock.patch.object(
hardware.VirtNUMAInstanceTopology, 'get_constraints',
with mock.patch(
'nova.virt.hardware.numa_get_constraints',
return_value=numa_constraint):
return claims.ResizeClaim('context', self.instance, instance_type,
{}, self.tracker, self.resources,
+14 -9
View File
@@ -7312,7 +7312,7 @@ class ComputeAPITestCase(BaseTestCase):
self.compute_api.create(self.context, inst_type,
self.fake_image['id'])
@mock.patch('nova.virt.hardware.VirtNUMAInstanceTopology.get_constraints')
@mock.patch('nova.virt.hardware.numa_get_constraints')
def test_create_with_numa_topology(self, numa_constraints_mock):
inst_type = flavors.get_default_flavor()
# This is what the stubbed out method will return
@@ -7320,19 +7320,24 @@ class ComputeAPITestCase(BaseTestCase):
'ramdisk_id': 'fake_ramdisk_id',
'something_else': 'meow'}
numa_topology = hardware.VirtNUMAInstanceTopology(
cells=[hardware.VirtNUMATopologyCellInstance(0, set([1, 2]), 512),
hardware.VirtNUMATopologyCellInstance(1, set([3, 4]), 512)])
numa_topology = objects.InstanceNUMATopology(
cells=[objects.InstanceNUMACell(
id=0, cpuset=set([1, 2]), memory=512),
objects.InstanceNUMACell(
id=1, cpuset=set([3, 4]), memory=512)])
numa_constraints_mock.return_value = numa_topology
instances, resv_id = self.compute_api.create(self.context, inst_type,
self.fake_image['id'])
numa_constraints_mock.assert_called_once_with(
inst_type, fake_image_props)
self.assertThat(numa_topology._to_dict(),
matchers.DictMatches(
instances[0].numa_topology
.topology_from_obj()._to_dict()))
inst_type, fake_image_props)
self.assertEqual(
numa_topology.cells[0].obj_to_primitive(),
instances[0].numa_topology.cells[0].obj_to_primitive())
self.assertEqual(
numa_topology.cells[1].obj_to_primitive(),
instances[0].numa_topology.cells[1].obj_to_primitive())
def test_create_instance_defaults_display_name(self):
# Verify that an instance cannot be created without a display_name.
@@ -292,7 +292,7 @@ class BaseTestCase(test.TestCase):
numa_topology = kwargs.pop('numa_topology', None)
if numa_topology:
extra['numa_topology'] = numa_topology.to_json()
extra['numa_topology'] = numa_topology._to_json()
instance.update(kwargs)
instance['extra'] = extra
@@ -719,9 +719,11 @@ class TrackerExtraResourcesTestCase(BaseTrackerTestCase):
class InstanceClaimTestCase(BaseTrackerTestCase):
def _instance_topology(self, mem):
mem = mem * 1024
return hardware.VirtNUMAInstanceTopology(
cells=[hardware.VirtNUMATopologyCellInstance(0, set([1]), mem),
hardware.VirtNUMATopologyCellInstance(1, set([3]), mem)])
return objects.InstanceNUMATopology(
cells=[objects.InstanceNUMACell(
id=0, cpuset=set([1]), memory=mem),
objects.InstanceNUMACell(
id=1, cpuset=set([3]), memory=mem)])
def _claim_topology(self, mem, cpus=1):
if self.tracker.driver.numa_topology is None:
@@ -13,22 +13,24 @@
import uuid
import mock
from oslo.serialization import jsonutils
from nova import exception
from nova import objects
from nova.tests.unit.objects import test_objects
from nova.virt import hardware
fake_instance_uuid = str(uuid.uuid4())
fake_numa_topology = hardware.VirtNUMAInstanceTopology(
cells=[hardware.VirtNUMATopologyCellInstance(
0, set([1, 2]), 512, 2048),
hardware.VirtNUMATopologyCellInstance(
1, set([3, 4]), 512, 2048)])
fake_obj_numa_topology = objects.InstanceNUMATopology.obj_from_topology(
fake_numa_topology)
fake_obj_numa_topology.instance_uuid = fake_instance_uuid
fake_obj_numa_topology = objects.InstanceNUMATopology(
instance_uuid = fake_instance_uuid,
cells=[
objects.InstanceNUMACell(
id=0, cpuset=set([1, 2]), memory=512, pagesize=2048),
objects.InstanceNUMACell(
id=1, cpuset=set([3, 4]), memory=512, pagesize=2048)
])
fake_numa_topology = fake_obj_numa_topology._to_dict()
fake_db_topology = {
'created_at': None,
@@ -41,22 +43,20 @@ fake_db_topology = {
}
fake_old_db_topology = dict(fake_db_topology) # copy
fake_old_db_topology['numa_topology'] = fake_numa_topology.to_json()
fake_old_db_topology['numa_topology'] = jsonutils.dumps(fake_numa_topology)
class _TestInstanceNUMATopology(object):
@mock.patch('nova.db.instance_extra_update_by_uuid')
def test_create(self, mock_update):
topo_obj = objects.InstanceNUMATopology.obj_from_topology(
fake_numa_topology)
topo_obj = fake_obj_numa_topology
topo_obj.instance_uuid = fake_db_topology['instance_uuid']
topo_obj.create(self.context)
self.assertEqual(1, len(mock_update.call_args_list))
@mock.patch('nova.db.instance_extra_update_by_uuid')
def test_save(self, mock_update):
topo_obj = objects.InstanceNUMATopology.obj_from_topology(
fake_numa_topology)
topo_obj = fake_obj_numa_topology
topo_obj.instance_uuid = fake_db_topology['instance_uuid']
topo_obj._save(self.context)
self.assertEqual(1, len(mock_update.call_args_list))
@@ -67,8 +67,9 @@ class _TestInstanceNUMATopology(object):
self.assertEqual(fake_db_topology['instance_uuid'],
numa_topology.instance_uuid)
for obj_cell, topo_cell in zip(
numa_topology.cells, fake_numa_topology.cells):
numa_topology.cells, fake_obj_numa_topology['cells']):
self.assertIsInstance(obj_cell, objects.InstanceNUMACell)
self.assertEqual(topo_cell.id, obj_cell.id)
self.assertEqual(topo_cell.cpuset, obj_cell.cpuset)
self.assertEqual(topo_cell.memory, obj_cell.memory)
self.assertEqual(topo_cell.pagesize, obj_cell.pagesize)
@@ -29,13 +29,12 @@ class TestNUMATopologyFilter(test.NoDBTestCase):
self.filt_cls = numa_topology_filter.NUMATopologyFilter()
def test_numa_topology_filter_pass(self):
instance_topology = hardware.VirtNUMAInstanceTopology(
cells=[hardware.VirtNUMATopologyCellInstance(0, set([1]), 512),
hardware.VirtNUMATopologyCellInstance(1, set([3]), 512)])
instance_topology = objects.InstanceNUMATopology(
cells=[objects.InstanceNUMACell(id=0, cpuset=set([1]), memory=512),
objects.InstanceNUMACell(id=1, cpuset=set([3]), memory=512)
])
instance = fake_instance.fake_instance_obj(mock.sentinel.ctx)
instance.numa_topology = (
objects.InstanceNUMATopology.obj_from_topology(
instance_topology))
instance.numa_topology = instance_topology
filter_properties = {
'request_spec': {
'instance_properties': jsonutils.to_primitive(
@@ -45,13 +44,12 @@ class TestNUMATopologyFilter(test.NoDBTestCase):
self.assertTrue(self.filt_cls.host_passes(host, filter_properties))
def test_numa_topology_filter_numa_instance_no_numa_host_fail(self):
instance_topology = hardware.VirtNUMAInstanceTopology(
cells=[hardware.VirtNUMATopologyCellInstance(0, set([1]), 512),
hardware.VirtNUMATopologyCellInstance(1, set([3]), 512)])
instance_topology = objects.InstanceNUMATopology(
cells=[objects.InstanceNUMACell(id=0, cpuset=set([1]), memory=512),
objects.InstanceNUMACell(id=1, cpuset=set([3]), memory=512)
])
instance = fake_instance.fake_instance_obj(mock.sentinel.ctx)
instance.numa_topology = (
objects.InstanceNUMATopology.obj_from_topology(
instance_topology))
instance.numa_topology = instance_topology
filter_properties = {
'request_spec': {
@@ -72,14 +70,13 @@ class TestNUMATopologyFilter(test.NoDBTestCase):
self.assertTrue(self.filt_cls.host_passes(host, filter_properties))
def test_numa_topology_filter_fail_fit(self):
instance_topology = hardware.VirtNUMAInstanceTopology(
cells=[hardware.VirtNUMATopologyCellInstance(0, set([1]), 512),
hardware.VirtNUMATopologyCellInstance(1, set([2]), 512),
hardware.VirtNUMATopologyCellInstance(2, set([3]), 512)])
instance_topology = objects.InstanceNUMATopology(
cells=[objects.InstanceNUMACell(id=0, cpuset=set([1]), memory=512),
objects.InstanceNUMACell(id=1, cpuset=set([2]), memory=512),
objects.InstanceNUMACell(id=2, cpuset=set([3]), memory=512)
])
instance = fake_instance.fake_instance_obj(mock.sentinel.ctx)
instance.numa_topology = (
objects.InstanceNUMATopology.obj_from_topology(
instance_topology))
instance.numa_topology = instance_topology
filter_properties = {
'request_spec': {
'instance_properties': jsonutils.to_primitive(
@@ -91,13 +88,13 @@ class TestNUMATopologyFilter(test.NoDBTestCase):
def test_numa_topology_filter_fail_memory(self):
self.flags(ram_allocation_ratio=1)
instance_topology = hardware.VirtNUMAInstanceTopology(
cells=[hardware.VirtNUMATopologyCellInstance(0, set([1]), 1024),
hardware.VirtNUMATopologyCellInstance(1, set([3]), 512)])
instance_topology = objects.InstanceNUMATopology(
cells=[objects.InstanceNUMACell(id=0, cpuset=set([1]),
memory=1024),
objects.InstanceNUMACell(id=1, cpuset=set([3]), memory=512)
])
instance = fake_instance.fake_instance_obj(mock.sentinel.ctx)
instance.numa_topology = (
objects.InstanceNUMATopology.obj_from_topology(
instance_topology))
instance.numa_topology = instance_topology
filter_properties = {
'request_spec': {
'instance_properties': jsonutils.to_primitive(
@@ -109,14 +106,12 @@ class TestNUMATopologyFilter(test.NoDBTestCase):
def test_numa_topology_filter_fail_cpu(self):
self.flags(cpu_allocation_ratio=1)
instance_topology = hardware.VirtNUMAInstanceTopology(
cells=[hardware.VirtNUMATopologyCellInstance(0, set([1]), 512),
hardware.VirtNUMATopologyCellInstance(
1, set([3, 4, 5]), 512)])
instance_topology = objects.InstanceNUMATopology(
cells=[objects.InstanceNUMACell(id=0, cpuset=set([1]), memory=512),
objects.InstanceNUMACell(id=1, cpuset=set([3, 4, 5]),
memory=512)])
instance = fake_instance.fake_instance_obj(mock.sentinel.ctx)
instance.numa_topology = (
objects.InstanceNUMATopology.obj_from_topology(
instance_topology))
instance.numa_topology = instance_topology
filter_properties = {
'request_spec': {
'instance_properties': jsonutils.to_primitive(
@@ -129,13 +124,12 @@ class TestNUMATopologyFilter(test.NoDBTestCase):
self.flags(cpu_allocation_ratio=21)
self.flags(ram_allocation_ratio=1.3)
instance_topology = hardware.VirtNUMAInstanceTopology(
cells=[hardware.VirtNUMATopologyCellInstance(0, set([1]), 512),
hardware.VirtNUMATopologyCellInstance(1, set([3]), 512)])
instance_topology = objects.InstanceNUMATopology(
cells=[objects.InstanceNUMACell(id=0, cpuset=set([1]), memory=512),
objects.InstanceNUMACell(id=1, cpuset=set([3]), memory=512)
])
instance = fake_instance.fake_instance_obj(mock.sentinel.ctx)
instance.numa_topology = (
objects.InstanceNUMATopology.obj_from_topology(
instance_topology))
instance.numa_topology = instance_topology
filter_properties = {
'request_spec': {
'instance_properties': jsonutils.to_primitive(
+10 -13
View File
@@ -1334,12 +1334,11 @@ class LibvirtConnTestCase(test.NoDBTestCase):
@mock.patch.object(objects.Flavor, 'get_by_id')
def test_get_guest_config_non_numa_host_instance_topo(self, mock_flavor):
instance_topology = objects.InstanceNUMATopology.obj_from_topology(
hardware.VirtNUMAInstanceTopology(
cells=[hardware.VirtNUMATopologyCellInstance(
0, set([0]), 1024),
hardware.VirtNUMATopologyCellInstance(
1, set([2]), 1024)]))
instance_topology = objects.InstanceNUMATopology(
cells=[objects.InstanceNUMACell(
id=0, cpuset=set([0]), memory=1024),
objects.InstanceNUMACell(
id=1, cpuset=set([2]), memory=1024)])
instance_ref = objects.Instance(**self.test_instance)
instance_ref.numa_topology = instance_topology
flavor = objects.Flavor(memory_mb=2048, vcpus=2, root_gb=496,
@@ -1378,13 +1377,11 @@ class LibvirtConnTestCase(test.NoDBTestCase):
@mock.patch.object(objects.Flavor, 'get_by_id')
def test_get_guest_config_numa_host_instance_topo(self, mock_flavor):
instance_topology = objects.InstanceNUMATopology.obj_from_topology(
hardware.VirtNUMAInstanceTopology(
cells=[hardware.VirtNUMATopologyCellInstance(
0, set([0, 1]), 1024),
hardware.VirtNUMATopologyCellInstance(
1, set([2, 3]),
1024)]))
instance_topology = objects.InstanceNUMATopology(
cells=[objects.InstanceNUMACell(
id=0, cpuset=set([0, 1]), memory=1024),
objects.InstanceNUMACell(
id=1, cpuset=set([2, 3]), memory=1024)])
instance_ref = objects.Instance(**self.test_instance)
instance_ref.numa_topology = instance_topology
flavor = objects.Flavor(memory_mb=2048, vcpus=2, root_gb=496,
+84 -189
View File
@@ -23,7 +23,6 @@ from nova import exception
from nova import objects
from nova.objects import base as base_obj
from nova import test
from nova.tests.unit import matchers
from nova.virt import hardware as hw
@@ -726,12 +725,12 @@ class NUMATopologyTest(test.NoDBTestCase):
}),
"image": {
},
"expect": hw.VirtNUMAInstanceTopology(
"expect": objects.InstanceNUMATopology(cells=
[
hw.VirtNUMATopologyCellInstance(
0, set([0, 1, 2, 3]), 1024),
hw.VirtNUMATopologyCellInstance(
1, set([4, 5, 6, 7]), 1024),
objects.InstanceNUMACell(
id=0, cpuset=set([0, 1, 2, 3]), memory=1024),
objects.InstanceNUMACell(
id=1, cpuset=set([4, 5, 6, 7]), memory=1024),
]),
},
{
@@ -756,14 +755,14 @@ class NUMATopologyTest(test.NoDBTestCase):
}),
"image": {
},
"expect": hw.VirtNUMAInstanceTopology(
"expect": objects.InstanceNUMATopology(cells=
[
hw.VirtNUMATopologyCellInstance(
0, set([0, 1, 2, 3]), 1024),
hw.VirtNUMATopologyCellInstance(
1, set([4, 6]), 512),
hw.VirtNUMATopologyCellInstance(
2, set([5, 7]), 512),
objects.InstanceNUMACell(
id=0, cpuset=set([0, 1, 2, 3]), memory=1024),
objects.InstanceNUMACell(
id=1, cpuset=set([4, 6]), memory=512),
objects.InstanceNUMACell(
id=2, cpuset=set([5, 7]), memory=512),
]),
},
{
@@ -874,16 +873,16 @@ class NUMATopologyTest(test.NoDBTestCase):
for testitem in testdata:
if testitem["expect"] is None:
topology = hw.VirtNUMAInstanceTopology.get_constraints(
topology = hw.numa_get_constraints(
testitem["flavor"], testitem["image"])
self.assertIsNone(topology)
elif type(testitem["expect"]) == type:
self.assertRaises(testitem["expect"],
hw.VirtNUMAInstanceTopology.get_constraints,
hw.numa_get_constraints,
testitem["flavor"],
testitem["image"])
else:
topology = hw.VirtNUMAInstanceTopology.get_constraints(
topology = hw.numa_get_constraints(
testitem["flavor"], testitem["image"])
self.assertEqual(len(testitem["expect"].cells),
len(topology.cells))
@@ -899,13 +898,13 @@ class NUMATopologyTest(test.NoDBTestCase):
hw.VirtNUMATopologyCellUsage(1, set([4, 6]), 512),
hw.VirtNUMATopologyCellUsage(2, set([5, 7]), 512),
])
instance1 = hw.VirtNUMAInstanceTopology([
hw.VirtNUMATopologyCellInstance(0, set([0, 1, 2]), 256),
hw.VirtNUMATopologyCellInstance(1, set([4]), 256),
instance1 = objects.InstanceNUMATopology(cells=[
objects.InstanceNUMACell(id=0, cpuset=set([0, 1, 2]), memory=256),
objects.InstanceNUMACell(id=1, cpuset=set([4]), memory=256),
])
instance2 = hw.VirtNUMAInstanceTopology([
hw.VirtNUMATopologyCellInstance(0, set([0, 1]), 256),
hw.VirtNUMATopologyCellInstance(1, set([5, 7]), 256),
instance2 = objects.InstanceNUMATopology(cells=[
objects.InstanceNUMACell(id=0, cpuset=set([0, 1]), memory=256),
objects.InstanceNUMACell(id=1, cpuset=set([5, 7]), memory=256),
])
hostusage = hw.VirtNUMAHostTopology.usage_from_instances(
@@ -946,13 +945,13 @@ class NUMATopologyTest(test.NoDBTestCase):
hw.VirtNUMATopologyCellUsage(5, set([4, 6]), 512),
hw.VirtNUMATopologyCellUsage(6, set([5, 7]), 512),
])
instance1 = hw.VirtNUMAInstanceTopology([
hw.VirtNUMATopologyCellInstance(0, set([0, 1, 2]), 256),
hw.VirtNUMATopologyCellInstance(6, set([4]), 256),
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 = hw.VirtNUMAInstanceTopology([
hw.VirtNUMATopologyCellInstance(0, set([0, 1]), 256),
hw.VirtNUMATopologyCellInstance(5, set([5, 7]), 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),
])
hostusage = hw.VirtNUMAHostTopology.usage_from_instances(
@@ -999,10 +998,10 @@ class NUMATopologyTest(test.NoDBTestCase):
1, set([4, 6]), 512, cpu_usage=1, memory_usage=512),
hw.VirtNUMATopologyCellUsage(2, set([5, 7]), 256),
])
instance1 = hw.VirtNUMAInstanceTopology([
hw.VirtNUMATopologyCellInstance(0, set([0, 1, 2]), 512),
hw.VirtNUMATopologyCellInstance(1, set([3]), 256),
hw.VirtNUMATopologyCellInstance(2, set([4]), 256)])
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(
hosttopo, [instance1])
@@ -1038,9 +1037,9 @@ class NUMATopologyTest(test.NoDBTestCase):
hw.VirtNUMATopologyCellUsage(0, set([0, 1]), 512),
hw.VirtNUMATopologyCellUsage(1, set([2, 3]), 512),
])
instance1 = hw.VirtNUMAInstanceTopology([
hw.VirtNUMATopologyCellInstance(0, set([0, 1]), 256),
hw.VirtNUMATopologyCellInstance(2, set([2]), 256),
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(
@@ -1061,10 +1060,6 @@ class NUMATopologyTest(test.NoDBTestCase):
self.assertEqual(hostusage.cells[1].cpu_usage, 0)
self.assertEqual(hostusage.cells[1].memory_usage, 0)
def _test_to_dict(self, cell_or_topo, expected):
got = cell_or_topo._to_dict()
self.assertThat(expected, matchers.DictMatches(got))
def assertNUMACellMatches(self, expected_cell, got_cell):
attrs = ('cpuset', 'memory', 'id')
if isinstance(expected_cell, hw.VirtNUMAHostTopology):
@@ -1074,104 +1069,6 @@ class NUMATopologyTest(test.NoDBTestCase):
self.assertEqual(getattr(expected_cell, attr),
getattr(got_cell, attr))
def _test_cell_from_dict(self, data_dict, expected_cell):
cell_class = expected_cell.__class__
got_cell = cell_class._from_dict(data_dict)
self.assertNUMACellMatches(expected_cell, got_cell)
def _test_topo_from_dict(self, data_dict, expected_topo):
got_topo = expected_topo.__class__._from_dict(
data_dict)
for got_cell, expected_cell in zip(
got_topo.cells, expected_topo.cells):
self.assertNUMACellMatches(expected_cell, got_cell)
def test_numa_cell_dict(self):
cell = hw.VirtNUMATopologyCellInstance(1, set([1, 2]), 512)
cell_dict = {'cpus': '1,2',
'mem': {'total': 512},
'id': 1,
'pagesize': None}
self._test_to_dict(cell, cell_dict)
self._test_cell_from_dict(cell_dict, cell)
def test_numa_cell_pagesize_dict(self):
cell = hw.VirtNUMATopologyCellInstance(
1, set([1, 2]), 512, 2048)
cell_dict = {'cpus': '1,2',
'mem': {'total': 512},
'id': 1,
'pagesize': 2048}
self._test_to_dict(cell, cell_dict)
self._test_cell_from_dict(cell_dict, cell)
def test_numa_limit_cell_dict(self):
cell = hw.VirtNUMATopologyCellLimit(1, set([1, 2]), 512, 4, 2048)
cell_dict = {'cpus': '1,2', 'cpu_limit': 4,
'mem': {'total': 512, 'limit': 2048},
'id': 1}
self._test_to_dict(cell, cell_dict)
self._test_cell_from_dict(cell_dict, cell)
def test_numa_cell_usage_dict(self):
cell = hw.VirtNUMATopologyCellUsage(1, set([1, 2]), 512)
cell_dict = {'cpus': '1,2', 'cpu_usage': 0,
'mem': {'total': 512, 'used': 0},
'id': 1}
self._test_to_dict(cell, cell_dict)
self._test_cell_from_dict(cell_dict, cell)
def test_numa_instance_topo_dict(self):
topo = hw.VirtNUMAInstanceTopology(
cells=[
hw.VirtNUMATopologyCellInstance(1, set([1, 2]), 1024),
hw.VirtNUMATopologyCellInstance(2, set([3, 4]), 1024)])
topo_dict = {'cells': [
{'cpus': '1,2',
'mem': {'total': 1024},
'id': 1,
'pagesize': None},
{'cpus': '3,4',
'mem': {'total': 1024},
'id': 2,
'pagesize': None}]}
self._test_to_dict(topo, topo_dict)
self._test_topo_from_dict(topo_dict, topo)
def test_numa_limits_topo_dict(self):
topo = hw.VirtNUMALimitTopology(
cells=[
hw.VirtNUMATopologyCellLimit(
1, set([1, 2]), 1024, 4, 2048),
hw.VirtNUMATopologyCellLimit(
2, set([3, 4]), 1024, 4, 2048)])
topo_dict = {'cells': [
{'cpus': '1,2', 'cpu_limit': 4,
'mem': {'total': 1024, 'limit': 2048},
'id': 1},
{'cpus': '3,4', 'cpu_limit': 4,
'mem': {'total': 1024, 'limit': 2048},
'id': 2}]}
self._test_to_dict(topo, topo_dict)
self._test_topo_from_dict(topo_dict, topo)
def test_numa_topo_dict_with_usage(self):
topo = hw.VirtNUMAHostTopology(
cells=[
hw.VirtNUMATopologyCellUsage(
1, set([1, 2]), 1024),
hw.VirtNUMATopologyCellUsage(
2, set([3, 4]), 1024)])
topo_dict = {'cells': [
{'cpus': '1,2', 'cpu_usage': 0,
'mem': {'total': 1024, 'used': 0},
'id': 1},
{'cpus': '3,4', 'cpu_usage': 0,
'mem': {'total': 1024, 'used': 0},
'id': 2}]}
self._test_to_dict(topo, topo_dict)
self._test_topo_from_dict(topo_dict, topo)
def test_json(self):
expected = hw.VirtNUMAHostTopology(
cells=[
@@ -1188,10 +1085,10 @@ 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)
instance_cell = hw.VirtNUMATopologyCellInstance(
None, set([1, 2]), 1024)
instance_cell = objects.InstanceNUMACell(
id=0, cpuset=set([1, 2]), memory=1024)
fitted_cell = host_cell.fit_instance_cell(host_cell, instance_cell)
self.assertIsInstance(fitted_cell, hw.VirtNUMATopologyCellInstance)
self.assertIsInstance(fitted_cell, objects.InstanceNUMACell)
self.assertEqual(host_cell.id, fitted_cell.id)
def test_fit_instance_cell_success_w_limit(self):
@@ -1201,11 +1098,11 @@ class VirtNUMATopologyCellUsageTestCase(test.NoDBTestCase):
limit_cell = hw.VirtNUMATopologyCellLimit(
4, set([1, 2]), 1024,
cpu_limit=4, memory_limit=2048)
instance_cell = hw.VirtNUMATopologyCellInstance(
None, set([1, 2]), 1024)
instance_cell = objects.InstanceNUMACell(
id=0, cpuset=set([1, 2]), memory=1024)
fitted_cell = host_cell.fit_instance_cell(
host_cell, instance_cell, limit_cell=limit_cell)
self.assertIsInstance(fitted_cell, hw.VirtNUMATopologyCellInstance)
self.assertIsInstance(fitted_cell, objects.InstanceNUMACell)
self.assertEqual(host_cell.id, fitted_cell.id)
def test_fit_instance_cell_self_overcommit(self):
@@ -1213,8 +1110,8 @@ class VirtNUMATopologyCellUsageTestCase(test.NoDBTestCase):
limit_cell = hw.VirtNUMATopologyCellLimit(
4, set([1, 2]), 1024,
cpu_limit=4, memory_limit=2048)
instance_cell = hw.VirtNUMATopologyCellInstance(
None, set([1, 2, 3]), 4096)
instance_cell = objects.InstanceNUMACell(
id=0, cpuset=set([1, 2, 3]), memory=4096)
fitted_cell = host_cell.fit_instance_cell(
host_cell, instance_cell, limit_cell=limit_cell)
self.assertIsNone(fitted_cell)
@@ -1226,14 +1123,14 @@ class VirtNUMATopologyCellUsageTestCase(test.NoDBTestCase):
limit_cell = hw.VirtNUMATopologyCellLimit(
4, set([1, 2]), 1024,
cpu_limit=4, memory_limit=2048)
instance_cell = hw.VirtNUMATopologyCellInstance(
None, set([1, 2]), 4096)
instance_cell = objects.InstanceNUMACell(
id=0, cpuset=set([1, 2]), memory=4096)
fitted_cell = host_cell.fit_instance_cell(
host_cell, instance_cell, limit_cell=limit_cell)
self.assertIsNone(fitted_cell)
instance_cell = hw.VirtNUMATopologyCellInstance(
None, set([1, 2, 3, 4, 5]), 1024)
instance_cell = objects.InstanceNUMACell(
id=0, cpuset=set([1, 2, 3, 4, 5]), memory=1024)
fitted_cell = host_cell.fit_instance_cell(
host_cell, instance_cell, limit_cell=limit_cell)
self.assertIsNone(fitted_cell)
@@ -1261,33 +1158,33 @@ class VirtNUMAHostTopologyTestCase(test.NoDBTestCase):
2, set([3, 4]), 2048,
cpu_limit=4, memory_limit=3072)])
self.instance1 = hw.VirtNUMAInstanceTopology(
self.instance1 = objects.InstanceNUMATopology(
cells=[
hw.VirtNUMATopologyCellInstance(
None, set([1, 2]), 2048)])
self.instance2 = hw.VirtNUMAInstanceTopology(
objects.InstanceNUMACell(
id=0, cpuset=set([1, 2]), memory=2048)])
self.instance2 = objects.InstanceNUMATopology(
cells=[
hw.VirtNUMATopologyCellInstance(
None, set([1, 2, 3, 4]), 1024)])
self.instance3 = hw.VirtNUMAInstanceTopology(
objects.InstanceNUMACell(
id=0, cpuset=set([1, 2, 3, 4]), memory=1024)])
self.instance3 = objects.InstanceNUMATopology(
cells=[
hw.VirtNUMATopologyCellInstance(
None, set([1, 2]), 1024)])
objects.InstanceNUMACell(
id=0, cpuset=set([1, 2]), memory=1024)])
def test_get_fitting_success_no_limits(self):
fitted_instance1 = hw.VirtNUMAHostTopology.fit_instance_to_host(
self.host, self.instance1)
self.assertIsInstance(fitted_instance1, hw.VirtNUMAInstanceTopology)
self.assertIsInstance(fitted_instance1, objects.InstanceNUMATopology)
self.host = hw.VirtNUMAHostTopology.usage_from_instances(self.host,
[fitted_instance1])
fitted_instance2 = hw.VirtNUMAHostTopology.fit_instance_to_host(
self.host, self.instance3)
self.assertIsInstance(fitted_instance2, hw.VirtNUMAInstanceTopology)
self.assertIsInstance(fitted_instance2, objects.InstanceNUMATopology)
def test_get_fitting_success_limits(self):
fitted_instance = hw.VirtNUMAHostTopology.fit_instance_to_host(
self.host, self.instance3, self.limits)
self.assertIsInstance(fitted_instance, hw.VirtNUMAInstanceTopology)
self.assertIsInstance(fitted_instance, objects.InstanceNUMATopology)
self.assertEqual(1, fitted_instance.cells[0].id)
def test_get_fitting_fails_no_limits(self):
@@ -1298,7 +1195,7 @@ class VirtNUMAHostTopologyTestCase(test.NoDBTestCase):
def test_get_fitting_culmulative_fails_limits(self):
fitted_instance1 = hw.VirtNUMAHostTopology.fit_instance_to_host(
self.host, self.instance1, self.limits)
self.assertIsInstance(fitted_instance1, hw.VirtNUMAInstanceTopology)
self.assertIsInstance(fitted_instance1, objects.InstanceNUMATopology)
self.assertEqual(1, fitted_instance1.cells[0].id)
self.host = hw.VirtNUMAHostTopology.usage_from_instances(self.host,
[fitted_instance1])
@@ -1309,13 +1206,13 @@ class VirtNUMAHostTopologyTestCase(test.NoDBTestCase):
def test_get_fitting_culmulative_success_limits(self):
fitted_instance1 = hw.VirtNUMAHostTopology.fit_instance_to_host(
self.host, self.instance1, self.limits)
self.assertIsInstance(fitted_instance1, hw.VirtNUMAInstanceTopology)
self.assertIsInstance(fitted_instance1, objects.InstanceNUMATopology)
self.assertEqual(1, fitted_instance1.cells[0].id)
self.host = hw.VirtNUMAHostTopology.usage_from_instances(self.host,
[fitted_instance1])
fitted_instance2 = hw.VirtNUMAHostTopology.fit_instance_to_host(
self.host, self.instance3, self.limits)
self.assertIsInstance(fitted_instance2, hw.VirtNUMAInstanceTopology)
self.assertIsInstance(fitted_instance2, objects.InstanceNUMATopology)
self.assertEqual(2, fitted_instance2.cells[0].id)
@@ -1370,9 +1267,13 @@ class HelperMethodsTestCase(test.NoDBTestCase):
hw.VirtNUMATopologyCellUsage(0, set([0, 1]), 512),
hw.VirtNUMATopologyCellUsage(1, set([2, 3]), 512),
])
self.instancetopo = hw.VirtNUMAInstanceTopology([
hw.VirtNUMATopologyCellInstance(0, set([0, 1]), 256),
hw.VirtNUMATopologyCellInstance(1, set([2]), 256),
self.instancetopo = objects.InstanceNUMATopology(
instance_uuid='fake-uuid',
cells=[
objects.InstanceNUMACell(
id=0, cpuset=set([0, 1]), memory=256, pagesize=2048),
objects.InstanceNUMACell(
id=1, cpuset=set([2]), memory=256, pagesize=2048),
])
self.context = context.RequestContext('fake-user',
'fake-project')
@@ -1385,7 +1286,7 @@ class HelperMethodsTestCase(test.NoDBTestCase):
def test_dicts_json(self):
host = {'numa_topology': self.hosttopo.to_json()}
instance = {'numa_topology': self.instancetopo.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)
@@ -1393,7 +1294,16 @@ class HelperMethodsTestCase(test.NoDBTestCase):
def test_dicts_instance_json(self):
host = {'numa_topology': self.hosttopo}
instance = {'numa_topology': self.instancetopo.to_json()}
instance = {'numa_topology': self.instancetopo._to_json()}
res = hw.get_host_numa_usage_from_instance(host, instance)
self.assertIsInstance(res, hw.VirtNUMAHostTopology)
self._check_usage(res)
def test_dicts_instance_json_old(self):
host = {'numa_topology': self.hosttopo}
instance = {'numa_topology':
jsonutils.dumps(self.instancetopo._to_dict())}
res = hw.get_host_numa_usage_from_instance(host, instance)
self.assertIsInstance(res, hw.VirtNUMAHostTopology)
@@ -1409,7 +1319,7 @@ class HelperMethodsTestCase(test.NoDBTestCase):
def test_object_host_instance_json(self):
host = objects.ComputeNode(numa_topology=self.hosttopo.to_json())
instance = {'numa_topology': self.instancetopo.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)
@@ -1449,8 +1359,7 @@ class HelperMethodsTestCase(test.NoDBTestCase):
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=objects.InstanceNUMATopology.obj_from_topology(
self.instancetopo))
numa_topology=self.instancetopo)
# NOTE (ndipanov): This emulates scheduler.utils.build_request_spec
# We can remove this test once we no longer use that method.
instance_raw = jsonutils.to_primitive(
@@ -1465,7 +1374,7 @@ class HelperMethodsTestCase(test.NoDBTestCase):
obj.numa_topology = self.hosttopo.to_json()
host = Host()
instance = {'numa_topology': self.instancetopo.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)
@@ -1488,23 +1397,9 @@ class VirtMemoryPagesTestCase(test.NoDBTestCase):
self.assertEqual(1024, pages.total)
self.assertEqual(512, pages.used)
def test_virt_pages_topology_to_dict(self):
pages = hw.VirtPagesTopology(4, 1024, 512)
self.assertEqual({'size_kb': 4,
'total': 1024,
'used': 512}, pages.to_dict())
def test_virt_pages_topology_from_dict(self):
pages = hw.VirtPagesTopology.from_dict({'size_kb': 4,
'total': 1024,
'used': 512})
self.assertEqual(4, pages.size_kb)
self.assertEqual(1024, pages.total)
self.assertEqual(512, pages.used)
def test_cell_instance_pagesize(self):
cell = hw.VirtNUMATopologyCellInstance(
0, set([0]), 1024, 2048)
cell = objects.InstanceNUMACell(
id=0, cpuset=set([0]), memory=1024, pagesize=2048)
self.assertEqual(0, cell.id)
self.assertEqual(set([0]), cell.cpuset)
+141 -169
View File
@@ -609,40 +609,6 @@ class VirtNUMATopologyCell(object):
return cls(cell_id, cpuset, memory)
class VirtNUMATopologyCellInstance(VirtNUMATopologyCell):
"""Class for reporting NUMA resources in an iinstance cell."""
def __init__(self, id, cpuset, memory, pagesize=None):
"""Create a new NUMA Cell Instance
:param id: integer identifier of cell
:param cpuset: set containing list of CPU indexes
:param memory: RAM measured in Mib
:param pagesize: measured in Kib
:returns: a new NUMA cell instance object
"""
super(VirtNUMATopologyCellInstance, self).__init__(
id, cpuset, memory)
self.pagesize = pagesize
def _to_dict(self):
return {'cpus': format_cpu_spec(self.cpuset, allow_ranges=False),
'mem': {'total': self.memory},
'id': self.id,
'pagesize': self.pagesize}
@classmethod
def _from_dict(cls, data_dict):
cpuset = parse_cpu_spec(data_dict.get('cpus', ''))
memory = data_dict.get('mem', {}).get('total', 0)
cell_id = data_dict.get('id')
pagesize = data_dict.get('pagesize')
return cls(cell_id, cpuset, memory, pagesize)
class VirtNUMATopologyCellLimit(VirtNUMATopologyCell):
def __init__(self, id, cpuset, memory, cpu_limit, memory_limit):
"""Create a new NUMA Cell with usage
@@ -729,7 +695,7 @@ class VirtNUMATopologyCellUsage(VirtNUMATopologyCell):
: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 VirtNUMATopologyCellInstance with the id set to that of
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
@@ -746,9 +712,9 @@ class VirtNUMATopologyCellUsage(VirtNUMATopologyCell):
if (memory_usage > limit_cell.memory_limit or
cpu_usage > limit_cell.cpu_limit):
return None
return VirtNUMATopologyCellInstance(
host_cell.id, instance_cell.cpuset, instance_cell.memory,
pagesize=instance_cell.pagesize)
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()
@@ -809,124 +775,124 @@ class VirtNUMATopology(object):
return cls._from_dict(jsonutils.loads(json_string))
class VirtNUMAInstanceTopology(VirtNUMATopology):
"""Class to represent the topology configured for a guest
instance. It provides helper APIs to determine configuration
from the metadata specified against the flavour and or
disk image
def _numa_get_flavor_or_image_prop(flavor, image_meta, propname):
flavor_val = flavor.get('extra_specs', {}).get("hw:" + propname)
image_val = image_meta.get("hw_" + propname)
if flavor_val is not None:
if image_val is not None:
raise exception.ImageNUMATopologyForbidden(
name='hw_' + propname)
return flavor_val
else:
return image_val
def _numa_get_constraints_manual(nodes, flavor, image_meta):
cells = []
totalmem = 0
availcpus = set(range(flavor['vcpus']))
for node in range(nodes):
cpus = _numa_get_flavor_or_image_prop(
flavor, image_meta, "numa_cpus.%d" % node)
mem = _numa_get_flavor_or_image_prop(
flavor, image_meta, "numa_mem.%d" % node)
# We're expecting both properties set, so
# raise an error if either is missing
if cpus is None or mem is None:
raise exception.ImageNUMATopologyIncomplete()
mem = int(mem)
cpuset = parse_cpu_spec(cpus)
for cpu in cpuset:
if cpu > (flavor['vcpus'] - 1):
raise exception.ImageNUMATopologyCPUOutOfRange(
cpunum=cpu, cpumax=(flavor['vcpus'] - 1))
if cpu not in availcpus:
raise exception.ImageNUMATopologyCPUDuplicates(
cpunum=cpu)
availcpus.remove(cpu)
cells.append(objects.InstanceNUMACell(
id=node, cpuset=cpuset, memory=mem))
totalmem = totalmem + mem
if availcpus:
raise exception.ImageNUMATopologyCPUsUnassigned(
cpuset=str(availcpus))
if totalmem != flavor['memory_mb']:
raise exception.ImageNUMATopologyMemoryOutOfRange(
memsize=totalmem,
memtotal=flavor['memory_mb'])
return objects.InstanceNUMATopology(cells=cells)
def _numa_get_constraints_auto(nodes, flavor, image_meta):
if ((flavor['vcpus'] % nodes) > 0 or
(flavor['memory_mb'] % nodes) > 0):
raise exception.ImageNUMATopologyAsymmetric()
cells = []
for node in range(nodes):
cpus = _numa_get_flavor_or_image_prop(
flavor, image_meta, "numa_cpus.%d" % node)
mem = _numa_get_flavor_or_image_prop(
flavor, image_meta, "numa_mem.%d" % node)
# We're not expecting any properties set, so
# raise an error if there are any
if cpus is not None or mem is not None:
raise exception.ImageNUMATopologyIncomplete()
ncpus = int(flavor['vcpus'] / nodes)
mem = int(flavor['memory_mb'] / nodes)
start = node * ncpus
cpuset = set(range(start, start + ncpus))
cells.append(objects.InstanceNUMACell(
id=node, cpuset=cpuset, memory=mem))
return objects.InstanceNUMATopology(cells=cells)
# TODO(sahid): Move numa related to hardward/numa.py
def numa_get_constraints(flavor, image_meta):
"""Return topology related to input request
:param flavor: Flavor object to read extra specs from
:param image_meta: Image object to read image metadata from
:returns: InstanceNUMATopology or None
"""
nodes = _numa_get_flavor_or_image_prop(
flavor, image_meta, "numa_nodes")
cell_class = VirtNUMATopologyCellInstance
if nodes is None:
return None
@staticmethod
def _get_flavor_or_image_prop(flavor, image_meta, propname):
flavor_val = flavor.get('extra_specs', {}).get("hw:" + propname)
image_val = image_meta.get("hw_" + propname)
nodes = int(nodes)
if flavor_val is not None:
if image_val is not None:
raise exception.ImageNUMATopologyForbidden(
name='hw_' + propname)
# We'll pick what path to go down based on whether
# anything is set for the first node. Both paths
# have logic to cope with inconsistent property usage
auto = _numa_get_flavor_or_image_prop(
flavor, image_meta, "numa_cpus.0") is None
return flavor_val
else:
return image_val
@classmethod
def _get_constraints_manual(cls, nodes, flavor, image_meta):
cells = []
totalmem = 0
availcpus = set(range(flavor['vcpus']))
for node in range(nodes):
cpus = cls._get_flavor_or_image_prop(
flavor, image_meta, "numa_cpus.%d" % node)
mem = cls._get_flavor_or_image_prop(
flavor, image_meta, "numa_mem.%d" % node)
# We're expecting both properties set, so
# raise an error if either is missing
if cpus is None or mem is None:
raise exception.ImageNUMATopologyIncomplete()
mem = int(mem)
cpuset = parse_cpu_spec(cpus)
for cpu in cpuset:
if cpu > (flavor['vcpus'] - 1):
raise exception.ImageNUMATopologyCPUOutOfRange(
cpunum=cpu, cpumax=(flavor['vcpus'] - 1))
if cpu not in availcpus:
raise exception.ImageNUMATopologyCPUDuplicates(
cpunum=cpu)
availcpus.remove(cpu)
cells.append(cls.cell_class(node, cpuset, mem))
totalmem = totalmem + mem
if availcpus:
raise exception.ImageNUMATopologyCPUsUnassigned(
cpuset=str(availcpus))
if totalmem != flavor['memory_mb']:
raise exception.ImageNUMATopologyMemoryOutOfRange(
memsize=totalmem,
memtotal=flavor['memory_mb'])
return cls(cells)
@classmethod
def _get_constraints_auto(cls, nodes, flavor, image_meta):
if ((flavor['vcpus'] % nodes) > 0 or
(flavor['memory_mb'] % nodes) > 0):
raise exception.ImageNUMATopologyAsymmetric()
cells = []
for node in range(nodes):
cpus = cls._get_flavor_or_image_prop(
flavor, image_meta, "numa_cpus.%d" % node)
mem = cls._get_flavor_or_image_prop(
flavor, image_meta, "numa_mem.%d" % node)
# We're not expecting any properties set, so
# raise an error if there are any
if cpus is not None or mem is not None:
raise exception.ImageNUMATopologyIncomplete()
ncpus = int(flavor['vcpus'] / nodes)
mem = int(flavor['memory_mb'] / nodes)
start = node * ncpus
cpuset = set(range(start, start + ncpus))
cells.append(cls.cell_class(node, cpuset, mem))
return cls(cells)
@classmethod
def get_constraints(cls, flavor, image_meta):
nodes = cls._get_flavor_or_image_prop(
flavor, image_meta, "numa_nodes")
if nodes is None:
return None
nodes = int(nodes)
# We'll pick what path to go down based on whether
# anything is set for the first node. Both paths
# have logic to cope with inconsistent property usage
auto = cls._get_flavor_or_image_prop(
flavor, image_meta, "numa_cpus.0") is None
if auto:
return cls._get_constraints_auto(
nodes, flavor, image_meta)
else:
return cls._get_constraints_manual(
nodes, flavor, image_meta)
if auto:
return _numa_get_constraints_auto(
nodes, flavor, image_meta)
else:
return _numa_get_constraints_manual(
nodes, flavor, image_meta)
class VirtNUMALimitTopology(VirtNUMATopology):
@@ -952,13 +918,13 @@ class VirtNUMAHostTopology(VirtNUMATopology):
"""Fit the instance topology onto the host topology given the limits
:param host_topology: VirtNUMAHostTopology object to fit an instance on
:param instance_topology: VirtNUMAInstanceTopology object to be fitted
: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 fit_instance_cell method, and return a new
VirtNUMAInstanceTopology with it's cell ids set to host cell id's of
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
@@ -985,14 +951,14 @@ class VirtNUMAHostTopology(VirtNUMATopology):
break
cells.append(got_cell)
if len(cells) == len(host_cell_perm):
return VirtNUMAInstanceTopology(cells=cells)
return objects.InstanceNUMATopology(cells=cells)
@classmethod
def usage_from_instances(cls, host, instances, free=False):
"""Get host topology usage
:param host: VirtNUMAHostTopology with usage information
:param instances: list of VirtNUMAInstanceTopology
: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
@@ -1053,26 +1019,32 @@ def instance_topology_from_instance(instance):
if instance_numa_topology:
if isinstance(instance_numa_topology, six.string_types):
instance_numa_topology = VirtNUMAInstanceTopology.from_json(
instance_numa_topology)
instance_numa_topology = (
objects.InstanceNUMATopology.obj_from_primitive(
jsonutils.loads(instance_numa_topology)))
elif isinstance(instance_numa_topology, dict):
# NOTE (ndipanov): A horrible hack so that we can use this in the
# scheduler, since the InstanceNUMATopology object is serialized
# raw using the obj_base.obj_to_primitive, (which is buggy and will
# give us a dict with a list of InstanceNUMACell objects), and then
# passed to jsonutils.to_primitive, which will make a dict out of
# those objects. All of this is done by
# scheduler.utils.build_request_spec called in the conductor.
# NOTE (ndipanov): A horrible hack so that we can use
# this in the scheduler, since the
# InstanceNUMATopology object is serialized raw using
# the obj_base.obj_to_primitive, (which is buggy and
# will give us a dict with a list of InstanceNUMACell
# objects), and then passed to jsonutils.to_primitive,
# which will make a dict out of those objects. All of
# this is done by scheduler.utils.build_request_spec
# called in the conductor.
#
# Remove when request_spec is a proper object itself!
dict_cells = instance_numa_topology.get('cells')
if dict_cells:
cells = [VirtNUMATopologyCellInstance(cell['id'],
set(cell['cpuset']),
cell['memory'],
cell.get('pagesize'))
cells = [objects.InstanceNUMACell(
id=cell['id'],
cpuset=set(cell['cpuset']),
memory=cell['memory'],
pagesize=cell.get('pagesize'))
for cell in dict_cells]
instance_numa_topology = VirtNUMAInstanceTopology(cells=cells)
instance_numa_topology = objects.InstanceNUMATopology(
cells=cells)
return instance_numa_topology