OVO obj_make_compatible does not handle if parent object reduced a lenght of a list field

Bug #1961482 reported by Balazs Gibizer
10
This bug affects 2 people
Affects Status Importance Assigned to Milestone
oslo.versionedobjects
New
Undecided
Unassigned

Bug Description

In Nova we have the following relationship (reduced the size of the objects for clarity):

class Architecture(BaseNovaEnum):
    X86_64 = arch.X86_64
    RISCV32 = arch.RISCV32

class ArchitectureField(BaseEnumField):
    AUTO_TYPE = Architecture()

class HVSpec(VersionedObject):
    # bumped to 1.3 when RISCV32 introduced
    VERSION = '1.3'
    fields = {
        'arch': fields.ArchitectureField(),
        }

class ComputeNode(VersionedObject):
    # bumped to 1.20 when RISCV32 introduced
    VERSION = '1.20'

    fields = {
        'supported_hv_specs': fields.ListOfObjectsField('HVSpec'),
    }

Now assume having a ComputeNode object with version 1.20 using RISCV32 in one of the HVSpecs in the supported_hv_specs list and you want to backport that object to ComputeNode 1.19 (HVSpec 1.2).

The HVSpec object cannot backport itself as there is no valid old version of the object. So only the parent object, ComputeNode, can do a meaningful backport. It can remove the supported_hv_specs list those HVSpec objects that has too new arch value.

So the impl for that is something like:

    def obj_make_compatible(self, primitive, target_version):
        str_target_version = target_version
        target_version = versionutils.convert_version_to_tuple(target_version)
        if target_version < (1, 20) and 'supported_hv_specs' in primitive:
            primitive['supported_hv_specs'] = [
                hvspec for hvspec in primitive['supported_hv_specs']
                if hvspec['nova_object.data']['arch'] not in
                ('riscv32', 'riscv64')
                ]
        # [removed the older backports]

        super(ComputeNode, self).obj_make_compatible(
            primitive, str_target_version)

However this fail on the OVO side when doing the HVSpec backport at [1]:

      File "/home/gibizer/upstream/git/nova/nova/tests/unit/objects/test_compute_node.py", line 517, in test_obj_make_compatible_new_archs
    primitive = compute.obj_to_primitive(

      File "/home/gibizer/upstream/git/nova/.tox/py39/lib/python3.9/site-packages/fixtures/_fixtures/monkeypatch.py", line 89, in avoid_get
    return captured_method(*args, **kwargs)

      File "/home/gibizer/upstream/git/nova/.tox/py39/lib/python3.9/site-packages/oslo_versionedobjects/fixture.py", line 464, in _doit
    result = self._original_otp(obj, *args, **kwargs)

      File "/home/gibizer/upstream/git/nova/.tox/py39/lib/python3.9/site-packages/oslo_versionedobjects/base.py", line 562, in obj_to_primitive
    self.obj_make_compatible_from_manifest(primitive,

      File "/home/gibizer/upstream/git/nova/.tox/py39/lib/python3.9/site-packages/oslo_versionedobjects/base.py", line 536, in obj_make_compatible_from_manifest
    return self.obj_make_compatible(primitive, target_version)

      File "/home/gibizer/upstream/git/nova/nova/objects/compute_node.py", line 158, in obj_make_compatible
    super(ComputeNode, self).obj_make_compatible(

      File "/home/gibizer/upstream/git/nova/.tox/py39/lib/python3.9/site-packages/oslo_versionedobjects/base.py", line 523, in obj_make_compatible
    self._obj_make_obj_compatible(primitive, target_version, key)

      File "/home/gibizer/upstream/git/nova/.tox/py39/lib/python3.9/site-packages/oslo_versionedobjects/base.py", line 483, in _obj_make_obj_compatible
    _get_subobject_version(target_version,

      File "/home/gibizer/upstream/git/nova/.tox/py39/lib/python3.9/site-packages/oslo_versionedobjects/base.py", line 1192, in _get_subobject_version
    backport_func(child)

      File "/home/gibizer/upstream/git/nova/.tox/py39/lib/python3.9/site-packages/oslo_versionedobjects/base.py", line 485, in <lambda>
    lambda ver: _do_subobject_backport(

      File "/home/gibizer/upstream/git/nova/.tox/py39/lib/python3.9/site-packages/oslo_versionedobjects/base.py", line 1209, in _do_subobject_backport
    element._obj_primitive_field(primitive[field][i], 'data'),

    IndexError: list index out of range

What happens is that in [1] the primitive is the reduced list but the supported_hv_specs field on the parent obj still having all the original HVSpec OVOs. Basically the implementation assumes that a list in primitives has the same lenght as a list field value.

[1] https://github.com/openstack/oslo.versionedobjects/blob/25d34d68dafd12fcc4fc843975b8b97994f2bd58/oslo_versionedobjects/base.py#L1207-L1212

description: updated
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.