From 4c9cb83d6b46a6425e603194649a61f51a07a307 Mon Sep 17 00:00:00 2001 From: Slawek Kaplonski Date: Mon, 1 Aug 2022 13:00:28 +0200 Subject: [PATCH] Bump revision number of objects when description is changed "Description" attribute belongs to the StandardAttribute class from which many other classes inherits (like e.g. Network, Port or Subnet). In case when only description of object is updated, revision number of the object should be bumped but it wasn't the case for all of the objects. For example updated description of the Network or Router didn't bumped its revision_number. It was like that because StandardAttribute object was the only one which was dirty in the session, and as it is not member of the HasStandardAttibutes class, it was filtered out. Now, to fix that problem revision_plugin looks in the session.dirty list for objects which inherits from HasStandardAttibutes class (as it was before) but also for StandardAttribute objects to bump revision numbers. Closes-Bug: #1981817 Closes-Bug: #1865173 Change-Id: I79b40a8ae5d594ed6fc875572663469c8b701202 --- neutron/services/revisions/revision_plugin.py | 33 ++++++++++++++++--- .../revisions/test_revision_plugin.py | 16 +++++++++ 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/neutron/services/revisions/revision_plugin.py b/neutron/services/revisions/revision_plugin.py index cedf5298a6a..5cc2cac1fbe 100644 --- a/neutron/services/revisions/revision_plugin.py +++ b/neutron/services/revisions/revision_plugin.py @@ -49,15 +49,38 @@ class RevisionPlugin(service_base.ServicePluginBase): db_api.sqla_listen(se.Session, 'after_rollback', self._clear_rev_bumped_flags) + def _get_objects_to_bump_revision(self, dirty_objects): + all_std_attr_objects = [] + objects_to_bump_revision = [] + for dirty_object in dirty_objects: + if isinstance(dirty_object, standard_attr.HasStandardAttributes): + objects_to_bump_revision.append(dirty_object) + elif isinstance(dirty_object, standard_attr.StandardAttribute): + all_std_attr_objects.append(dirty_object) + + # Now as we have all objects divided into 2 groups, we need to ensure + # that we don't have revision number for the same one in both groups. + # It may happen e.g. for the Subnet object, as during update of Subnet, + # both Subnet and StandardAttribute objects of that subnet are dirty. + # But for example for Network, when only description is changed, only + # StandardAttribute object is in the dirty objects set. + std_attr_ids = [o.standard_attr_id for o in objects_to_bump_revision] + + # NOTE(slaweq): StandardAttribute objects which have "description" + # field modified, should have revision bumped too + objects_to_bump_revision += [ + o for o in all_std_attr_objects + if ('description' not in o._sa_instance_state.unmodified and + o.id not in std_attr_ids)] + + return objects_to_bump_revision + def bump_revisions(self, session, context, instances): self._enforce_if_match_constraints(session) - # bump revision number for any updated objects in the session + # bump revision number for updated objects in the session self._bump_obj_revisions( session, - [ - obj for obj in session.dirty - if isinstance(obj, standard_attr.HasStandardAttributes)] - ) + self._get_objects_to_bump_revision(session.dirty)) # see if any created/updated/deleted objects bump the revision # of another object diff --git a/neutron/tests/unit/services/revisions/test_revision_plugin.py b/neutron/tests/unit/services/revisions/test_revision_plugin.py index 2594f4f7499..6937eea5192 100644 --- a/neutron/tests/unit/services/revisions/test_revision_plugin.py +++ b/neutron/tests/unit/services/revisions/test_revision_plugin.py @@ -191,6 +191,22 @@ class TestRevisionPlugin(test_plugin.Ml2PluginV2TestCase): new_rev = response['port']['revision_number'] self.assertGreater(new_rev, rev) + def test_network_description_bumps_revision(self): + with self.network() as net: + rev = net['network']['revision_number'] + data = {'network': {'description': 'Test Description'}} + response = self._update('networks', net['network']['id'], data) + new_rev = response['network']['revision_number'] + self.assertEqual(rev + 1, new_rev) + + def test_subnet_description_bumps_revision(self): + with self.subnet() as subnet: + rev = subnet['subnet']['revision_number'] + data = {'subnet': {'description': 'Test Description'}} + response = self._update('subnets', subnet['subnet']['id'], data) + new_rev = response['subnet']['revision_number'] + self.assertEqual(rev + 1, new_rev) + def test_security_group_rule_ops_bump_security_group(self): s = {'security_group': {'tenant_id': 'some_tenant', 'name': '', 'description': 's'}}