objects: make instance numa topology versioned in db
Makes data stored in the database for numa topology versioned by using object framework. Change-Id: I0e8ca96296fb88aa7a26fae1e476275a23e0c6bb
This commit is contained in:
@@ -376,8 +376,7 @@ class Instance(base.NovaPersistentObject, base.NovaObject):
|
||||
numa_topology = updates.pop('numa_topology', None)
|
||||
if numa_topology:
|
||||
expected_attrs.append('numa_topology')
|
||||
updates['extra']['numa_topology'] = (
|
||||
numa_topology.topology_from_obj().to_json())
|
||||
updates['extra']['numa_topology'] = numa_topology._to_json()
|
||||
pci_requests = updates.pop('pci_requests', None)
|
||||
if pci_requests:
|
||||
expected_attrs.append('pci_requests')
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo.serialization import jsonutils
|
||||
|
||||
from nova import db
|
||||
from nova import exception
|
||||
from nova.objects import base
|
||||
@@ -47,13 +49,19 @@ class InstanceNUMATopology(base.NovaObject):
|
||||
|
||||
@classmethod
|
||||
def obj_from_db_obj(cls, instance_uuid, db_obj):
|
||||
topo = hardware.VirtNUMAInstanceTopology.from_json(db_obj)
|
||||
obj_topology = cls.obj_from_topology(topo)
|
||||
obj_topology.instance_uuid = instance_uuid
|
||||
# NOTE (ndipanov) not really needed as we never save, but left for
|
||||
# consistency
|
||||
obj_topology.id = 0
|
||||
obj_topology.obj_reset_changes()
|
||||
if 'nova_object.name' in db_obj:
|
||||
obj_topology = cls.obj_from_primitive(
|
||||
jsonutils.loads(db_obj))
|
||||
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()
|
||||
return obj_topology
|
||||
|
||||
@classmethod
|
||||
@@ -81,22 +89,13 @@ class InstanceNUMATopology(base.NovaObject):
|
||||
# TODO(ndipanov) Remove this method on the major version bump to 2.0
|
||||
@base.remotable
|
||||
def create(self, context):
|
||||
topology = self.topology_from_obj()
|
||||
if not topology:
|
||||
return
|
||||
values = {'numa_topology': topology.to_json()}
|
||||
db.instance_extra_update_by_uuid(context, self.instance_uuid,
|
||||
values)
|
||||
self.obj_reset_changes()
|
||||
self._save(context)
|
||||
|
||||
# NOTE(ndipanov): We can't rename create and want to avoid version bump
|
||||
# as this needs to be backported to stable so this is not a @remotable
|
||||
# That's OK since we only call it from inside Instance.save() which is.
|
||||
def _save(self, context):
|
||||
topology = self.topology_from_obj()
|
||||
if not topology:
|
||||
return
|
||||
values = {'numa_topology': topology.to_json()}
|
||||
values = {'numa_topology': self._to_json()}
|
||||
db.instance_extra_update_by_uuid(context, self.instance_uuid,
|
||||
values)
|
||||
self.obj_reset_changes()
|
||||
@@ -121,3 +120,6 @@ class InstanceNUMATopology(base.NovaObject):
|
||||
return None
|
||||
|
||||
return cls.obj_from_db_obj(instance_uuid, db_extra['numa_topology'])
|
||||
|
||||
def _to_json(self):
|
||||
return jsonutils.dumps(self.obj_to_primitive())
|
||||
|
||||
@@ -30,7 +30,6 @@ from nova import notifications
|
||||
from nova import objects
|
||||
from nova.objects import instance
|
||||
from nova.objects import instance_info_cache
|
||||
from nova.objects import instance_numa_topology
|
||||
from nova.objects import pci_device
|
||||
from nova.objects import security_group
|
||||
from nova import test
|
||||
@@ -419,17 +418,19 @@ class _TestInstanceObject(object):
|
||||
@mock.patch('nova.objects.Instance._from_db_object')
|
||||
def test_save_updates_numa_topology(self, mock_fdo, mock_update,
|
||||
mock_extra_update):
|
||||
fake_obj_numa_topology = objects.InstanceNUMATopology(cells=[
|
||||
objects.InstanceNUMACell(id=0, cpuset=set([0]), memory=128),
|
||||
objects.InstanceNUMACell(id=1, cpuset=set([1]), memory=128)])
|
||||
fake_obj_numa_topology.instance_uuid = 'fake-uuid'
|
||||
jsonified = fake_obj_numa_topology._to_json()
|
||||
|
||||
mock_update.return_value = None, None
|
||||
inst = instance.Instance(
|
||||
context=self.context, id=123, uuid='fake-uuid')
|
||||
inst.numa_topology = (
|
||||
instance_numa_topology.InstanceNUMATopology.obj_from_topology(
|
||||
test_instance_numa_topology.fake_numa_topology))
|
||||
inst.numa_topology = fake_obj_numa_topology
|
||||
inst.save()
|
||||
mock_extra_update.assert_called_once_with(
|
||||
self.context, inst.uuid,
|
||||
{'numa_topology':
|
||||
test_instance_numa_topology.fake_numa_topology.to_json()})
|
||||
self.context, inst.uuid, {'numa_topology': jsonified})
|
||||
mock_extra_update.reset_mock()
|
||||
inst.numa_topology = None
|
||||
inst.save()
|
||||
@@ -707,19 +708,18 @@ class _TestInstanceObject(object):
|
||||
|
||||
def test_create_with_extras(self):
|
||||
inst = instance.Instance(uuid=self.fake_instance['uuid'],
|
||||
numa_topology=objects.InstanceNUMATopology.obj_from_topology(
|
||||
test_instance_numa_topology.fake_numa_topology),
|
||||
pci_requests=objects.InstancePCIRequests(
|
||||
requests=[
|
||||
objects.InstancePCIRequest(count=123,
|
||||
spec=[])]))
|
||||
|
||||
numa_topology=test_instance_numa_topology.fake_obj_numa_topology,
|
||||
pci_requests=objects.InstancePCIRequests(
|
||||
requests=[
|
||||
objects.InstancePCIRequest(count=123,
|
||||
spec=[])]))
|
||||
inst.create(self.context)
|
||||
self.assertIsNotNone(inst.numa_topology)
|
||||
self.assertIsNotNone(inst.pci_requests)
|
||||
got_numa_topo = objects.InstanceNUMATopology.get_by_instance_uuid(
|
||||
self.context, inst.uuid)
|
||||
self.assertEqual(inst.numa_topology.id, got_numa_topo.id)
|
||||
self.assertEqual(inst.numa_topology.instance_uuid,
|
||||
got_numa_topo.instance_uuid)
|
||||
got_pci_requests = objects.InstancePCIRequests.get_by_instance_uuid(
|
||||
self.context, inst.uuid)
|
||||
self.assertEqual(123, got_pci_requests.requests[0].count)
|
||||
|
||||
@@ -19,11 +19,16 @@ 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)])
|
||||
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_db_topology = {
|
||||
'created_at': None,
|
||||
@@ -31,10 +36,13 @@ fake_db_topology = {
|
||||
'deleted_at': None,
|
||||
'deleted': 0,
|
||||
'id': 1,
|
||||
'instance_uuid': str(uuid.uuid4()),
|
||||
'numa_topology': fake_numa_topology.to_json()
|
||||
'instance_uuid': fake_instance_uuid,
|
||||
'numa_topology': fake_obj_numa_topology._to_json()
|
||||
}
|
||||
|
||||
fake_old_db_topology = dict(fake_db_topology) # copy
|
||||
fake_old_db_topology['numa_topology'] = fake_numa_topology.to_json()
|
||||
|
||||
|
||||
class _TestInstanceNUMATopology(object):
|
||||
@mock.patch('nova.db.instance_extra_update_by_uuid')
|
||||
@@ -45,9 +53,15 @@ class _TestInstanceNUMATopology(object):
|
||||
topo_obj.create(self.context)
|
||||
self.assertEqual(1, len(mock_update.call_args_list))
|
||||
|
||||
@mock.patch('nova.db.instance_extra_get_by_instance_uuid')
|
||||
def test_get_by_instance_uuid(self, mock_get):
|
||||
mock_get.return_value = fake_db_topology
|
||||
@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.instance_uuid = fake_db_topology['instance_uuid']
|
||||
topo_obj._save(self.context)
|
||||
self.assertEqual(1, len(mock_update.call_args_list))
|
||||
|
||||
def _test_get_by_instance_uuid(self):
|
||||
numa_topology = objects.InstanceNUMATopology.get_by_instance_uuid(
|
||||
self.context, fake_db_topology['instance_uuid'])
|
||||
self.assertEqual(fake_db_topology['instance_uuid'],
|
||||
@@ -59,6 +73,16 @@ class _TestInstanceNUMATopology(object):
|
||||
self.assertEqual(topo_cell.memory, obj_cell.memory)
|
||||
self.assertEqual(topo_cell.pagesize, obj_cell.pagesize)
|
||||
|
||||
@mock.patch('nova.db.instance_extra_get_by_instance_uuid')
|
||||
def test_get_by_instance_uuid(self, mock_get):
|
||||
mock_get.return_value = fake_db_topology
|
||||
self._test_get_by_instance_uuid()
|
||||
|
||||
@mock.patch('nova.db.instance_extra_get_by_instance_uuid')
|
||||
def test_get_by_instance_uuid_old(self, mock_get):
|
||||
mock_get.return_value = fake_old_db_topology
|
||||
self._test_get_by_instance_uuid()
|
||||
|
||||
@mock.patch('nova.db.instance_extra_get_by_instance_uuid')
|
||||
def test_get_by_instance_uuid_missing(self, mock_get):
|
||||
mock_get.return_value = None
|
||||
|
||||
Reference in New Issue
Block a user