Skip to content

Commit dad5666

Browse files
author
Balazs Gibizer
committed
Migrate RequestSpec.numa_topology to use pcpuset
When the InstanceNUMATopology OVO has changed in I901fbd7df00e45196395ff4c69e7b8aa3359edf6 to separately track pcpus from vcpus a data migration was added. This data migration is triggered when the InstanceNUMATopology object is loaded from the instance_extra table. However that patch is missed the fact that the InstanceNUMATopology object can be loaded from the request_spec table as well. So InstanceNUMATopology object in RequestSpec are not migrated. This could lead to errors in the scheduler when such RequestSpec object is used for scheduling (e.g. during a migration of a pre Victoria instance with cpu pinning) This patch adds the missing data migration. Change-Id: I812d720555bdf008c83cae3d81541a37bd99e594 Closes-Bug: #1952941 (cherry picked from commit e853bb5) (cherry picked from commit 7f6ec8c)
1 parent b190c30 commit dad5666

File tree

4 files changed

+47
-42
lines changed

4 files changed

+47
-42
lines changed

nova/objects/instance_numa.py

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,10 @@ def obj_from_db_obj(cls, context, instance_uuid, db_obj):
166166

167167
if 'nova_object.name' in primitive:
168168
obj = cls.obj_from_primitive(primitive)
169-
cls._migrate_legacy_dedicated_instance_cpuset(
170-
context, instance_uuid, obj)
169+
updated = cls._migrate_legacy_dedicated_instance_cpuset(obj)
170+
if updated:
171+
cls._save_migrated_cpuset_to_instance_extra(
172+
context, obj, instance_uuid)
171173
else:
172174
obj = cls._migrate_legacy_object(context, instance_uuid, primitive)
173175

@@ -176,13 +178,14 @@ def obj_from_db_obj(cls, context, instance_uuid, db_obj):
176178
# TODO(huaqiang): Remove after Wallaby once we are sure these objects have
177179
# been loaded at least once.
178180
@classmethod
179-
def _migrate_legacy_dedicated_instance_cpuset(cls, context, instance_uuid,
180-
obj):
181+
def _migrate_legacy_dedicated_instance_cpuset(cls, obj):
181182
# NOTE(huaqiang): We may meet some topology object with the old version
182183
# 'InstanceNUMACell' cells, in that case, the 'dedicated' CPU is kept
183184
# in 'InstanceNUMACell.cpuset' field, but it should be kept in
184185
# 'InstanceNUMACell.pcpuset' field since Victoria. Making an upgrade
185-
# and persisting to database.
186+
# here but letting the caller persist the result if needed as we
187+
# don't know which table the InstanceNUMACell is coming from. It can
188+
# come from instance_extra or request_spec too.
186189
update_db = False
187190
for cell in obj.cells:
188191
if len(cell.cpuset) == 0:
@@ -194,14 +197,20 @@ def _migrate_legacy_dedicated_instance_cpuset(cls, context, instance_uuid,
194197
cell.pcpuset = cell.cpuset
195198
cell.cpuset = set()
196199
update_db = True
200+
return update_db
197201

198-
if update_db:
199-
db_obj = jsonutils.dumps(obj.obj_to_primitive())
200-
values = {
201-
'numa_topology': db_obj,
202-
}
203-
db.instance_extra_update_by_uuid(context, instance_uuid,
204-
values)
202+
# TODO(huaqiang): Remove after Yoga once we are sure these objects have
203+
# been loaded at least once.
204+
@classmethod
205+
def _save_migrated_cpuset_to_instance_extra(
206+
cls, context, obj, instance_uuid
207+
):
208+
db_obj = jsonutils.dumps(obj.obj_to_primitive())
209+
values = {
210+
'numa_topology': db_obj,
211+
}
212+
db.instance_extra_update_by_uuid(
213+
context, instance_uuid, values)
205214

206215
# TODO(stephenfin): Remove in X or later, once this has bedded in
207216
@classmethod

nova/objects/request_spec.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,8 @@ def ensure_network_information(self, instance):
585585
@staticmethod
586586
def _from_db_object(context, spec, db_spec):
587587
spec_obj = spec.obj_from_primitive(jsonutils.loads(db_spec['spec']))
588+
data_migrated = False
589+
588590
for key in spec.fields:
589591
# Load these from the db model not the serialized object within,
590592
# though they should match.
@@ -605,6 +607,13 @@ def _from_db_object(context, spec, db_spec):
605607
# fields. If they are not set, set None.
606608
if not spec.obj_attr_is_set(key):
607609
setattr(spec, key, None)
610+
elif key == "numa_topology":
611+
if key in spec_obj:
612+
spec.numa_topology = spec_obj.numa_topology
613+
if spec.numa_topology:
614+
data_migrated = objects.InstanceNUMATopology.\
615+
_migrate_legacy_dedicated_instance_cpuset(
616+
spec.numa_topology)
608617
elif key in spec_obj:
609618
setattr(spec, key, getattr(spec_obj, key))
610619
spec._context = context
@@ -626,6 +635,9 @@ def _from_db_object(context, spec, db_spec):
626635
# NOTE(danms): Instance group may have been deleted
627636
spec.instance_group = None
628637

638+
if data_migrated:
639+
spec.save()
640+
629641
spec.obj_reset_changes()
630642
return spec
631643

nova/tests/unit/objects/test_request_spec.py

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -611,29 +611,12 @@ def test_get_by_instance_uuid(self, mock_get_ig, get_by_uuid):
611611
self.assertIsInstance(req_obj.instance_group, objects.InstanceGroup)
612612
self.assertEqual('fresh', req_obj.instance_group.name)
613613

614-
# FIXME(gibi): This is bug 1952941. When the cpuset -> pcpuset data
615-
# migration was added to InstanceNUMATopology it was missed that such
616-
# object is not only hydrated via
617-
# InstanceNUMATopology.get_by_instance_uuid() but also hydrated by
618-
# RequestSpec.get_by_instance_uuid() indirectly. However the
619-
# latter code patch does not call InstanceNUMATopology.obj_from_db_obj()
620-
# that triggers the data migration via
621-
# InstanceNUMATopology._migrate_legacy_dedicated_instance_cpuset.
622-
# This causes that when the new nova code loads an old RequestSpec object
623-
# from the DB (e.g. during migration of an instance) the
624-
# InstanceNUMATopology in the RequestSpec will not be migrated to the new
625-
# object version and it will lead to errors when the pcpuset field is read
626-
# during scheduling.
627-
@mock.patch(
628-
'nova.objects.instance_numa.InstanceNUMATopology.'
629-
'_migrate_legacy_dedicated_instance_cpuset',
630-
new=mock.NonCallableMock()
631-
)
614+
@mock.patch('nova.objects.request_spec.RequestSpec.save')
632615
@mock.patch.object(
633616
request_spec.RequestSpec, '_get_by_instance_uuid_from_db')
634617
@mock.patch('nova.objects.InstanceGroup.get_by_uuid')
635618
def test_get_by_instance_uuid_numa_topology_migration(
636-
self, mock_get_ig, get_by_uuid
619+
self, mock_get_ig, get_by_uuid, mock_save
637620
):
638621
# Simulate a pre-Victoria RequestSpec where the pcpuset field is not
639622
# defined for the embedded InstanceNUMACell objects but the cpu_policy
@@ -661,18 +644,10 @@ def test_get_by_instance_uuid_numa_topology_migration(
661644
self.context, fake_spec['instance_uuid'])
662645

663646
self.assertEqual(2, len(req_obj.numa_topology.cells))
647+
self.assertEqual({1, 2}, req_obj.numa_topology.cells[0].pcpuset)
648+
self.assertEqual({3, 4}, req_obj.numa_topology.cells[1].pcpuset)
664649

665-
# This is bug 1952941 as the pcpuset is not defined in object as the
666-
# object is not migrated
667-
ex = self.assertRaises(
668-
NotImplementedError,
669-
lambda: req_obj.numa_topology.cells[0].pcpuset
670-
)
671-
self.assertIn("Cannot load 'pcpuset' in the base class", str(ex))
672-
673-
# This is the expected behavior
674-
# self.assertEqual({1, 2}, req_obj.numa_topology.cells[0].pcpuset)
675-
# self.assertEqual({3, 4}, req_obj.numa_topology.cells[1].pcpuset)
650+
mock_save.assert_called_once()
676651

677652
def _check_update_primitive(self, req_obj, changes):
678653
self.assertEqual(req_obj.instance_uuid, changes['instance_uuid'])
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
fixes:
3+
- |
4+
The `bug 1952941`_ is fixed where a pre-Victoria server with pinned
5+
CPUs cannot be migrated or evacuated after the cloud is upgraded to
6+
Victoria or newer as the scheduling fails with
7+
``NotImplementedError: Cannot load 'pcpuset'`` error.
8+
9+
.. _bug 1952941: https://bugs.launchpad.net/nova/+bug/1952941

0 commit comments

Comments
 (0)