2022-02-19 16:05:22 |
Balazs Gibizer |
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.
I think the code should iterate the primitive value instead of iterating the obj.field value.
[1] https://github.com/openstack/oslo.versionedobjects/blob/25d34d68dafd12fcc4fc843975b8b97994f2bd58/oslo_versionedobjects/base.py#L1207-L1212 |
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 |
|