diff options
author | Zuul <zuul@review.opendev.org> | 2023-03-20 10:49:29 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2023-03-20 10:49:29 +0000 |
commit | 257bf0dc6055419fd34581793cdfb3d552437efc (patch) | |
tree | a789568b99c98228f7ac26b198b13d4ad93dbe94 | |
parent | 7ca09bfc2e7b489bd541895a6d35164022905284 (diff) | |
parent | 2fb9ddb01ed44fae19c0184baa8620e95e51e344 (diff) | |
download | neutron-257bf0dc6055419fd34581793cdfb3d552437efc.tar.gz |
Merge "Delete the PB level registers when deleting the duplicated PB" into stable/xena
-rw-r--r-- | neutron/cmd/remove_duplicated_port_bindings.py | 15 | ||||
-rw-r--r-- | neutron/objects/ports.py | 16 | ||||
-rw-r--r-- | neutron/tests/unit/objects/test_ports.py | 10 |
3 files changed, 32 insertions, 9 deletions
diff --git a/neutron/cmd/remove_duplicated_port_bindings.py b/neutron/cmd/remove_duplicated_port_bindings.py index be630e5b0f..8d7ceef962 100644 --- a/neutron/cmd/remove_duplicated_port_bindings.py +++ b/neutron/cmd/remove_duplicated_port_bindings.py @@ -34,7 +34,7 @@ def setup_conf(conf): def main(): - """Main method for removing the duplicated port binding registers. + """Main method for removing duplicated port binding and pb level registers. This script finds all ``PortBinding`` registers with the same ``port_id``. That happens during the live-migration process. Once finished, the inactive @@ -42,6 +42,10 @@ def main(): live-migration, an error occurs and this deletion is not executed. The related port cannot be migrated anymore. + This script removes the inactive ``PortBinding`` referred to a port ID and + the corresponding ``PortBindingLevel`` registers associated to this port + ID and ``PortBinding.host``. + This script should not be executed during a live migration process. It will remove the inactive port binding and will break the migration. """ @@ -53,12 +57,15 @@ def main(): dup_pbindings = ports_obj.PortBinding.get_duplicated_port_bindings( admin_ctx) - # Clean duplicated port bindings that are INACTIVE (if not in dry-run). + # Clean duplicated port bindings that are INACTIVE and the + # corresponding port binding level registers (if not in dry-run). if not _dry_run: for pbinding in dup_pbindings: + port_id, host = pbinding.port_id, pbinding.host ports_obj.PortBinding.delete_objects( - admin_ctx, status=constants.INACTIVE, - port_id=pbinding.port_id) + admin_ctx, status=constants.INACTIVE, port_id=port_id) + ports_obj.PortBindingLevel.delete_objects( + admin_ctx, port_id=port_id, host=host) if dup_pbindings: port_ids = [pbinding.port_id for pbinding in dup_pbindings] diff --git a/neutron/objects/ports.py b/neutron/objects/ports.py index 6df24f1717..ad621e879e 100644 --- a/neutron/objects/ports.py +++ b/neutron/objects/ports.py @@ -106,9 +106,19 @@ class PortBinding(PortBindingBase): @classmethod @db_api.CONTEXT_READER def get_duplicated_port_bindings(cls, context): - return context.session.query( - cls.db_model).group_by( - cls.db_model.port_id).having(sqlalchemy.func.count() > 1).all() + # This query will return the port_id of all "ml2_port_bindings" + # registers that appears more than once (duplicated + # "ml2_port_bindings" registers). + # At the same time, this query returns only the "ml2_port_bindings" + # that have status=INACTIVE. + select = ( + sqlalchemy.select(cls.db_model.port_id). + select_from(cls.db_model). + group_by(cls.db_model.port_id). + having(sqlalchemy.func.count(cls.db_model.port_id) > 1)) + _filter = and_(cls.db_model.port_id.in_(select), + cls.db_model.status == constants.INACTIVE) + return context.session.query(cls.db_model).filter(_filter).all() @base.NeutronObjectRegistry.register diff --git a/neutron/tests/unit/objects/test_ports.py b/neutron/tests/unit/objects/test_ports.py index 6ca0c4b9ab..c8ac2671c4 100644 --- a/neutron/tests/unit/objects/test_ports.py +++ b/neutron/tests/unit/objects/test_ports.py @@ -56,14 +56,20 @@ class PortBindingDbObjectTestCase(obj_test_base.BaseDbObjectTestCase, def test_get_duplicated_port_bindings(self): port_id = self._create_test_port_id() - self.update_obj_fields({'port_id': port_id}, - objs=[self.objs[0], self.objs[1]]) + self.update_obj_fields( + {'port_id': port_id, 'status': constants.ACTIVE}, + obj_fields=[self.obj_fields[0]]) + self.update_obj_fields( + {'port_id': port_id, 'status': constants.INACTIVE}, + obj_fields=[self.obj_fields[1]]) for i in range(3): _obj = self._make_object(self.obj_fields[i]) _obj.create() dup_pb = ports.PortBinding.get_duplicated_port_bindings(self.context) self.assertEqual(1, len(dup_pb)) self.assertEqual(port_id, dup_pb[0].port_id) + # The PB register returned is the INACTIVE one. + self.assertEqual(self.obj_fields[1]['host'], dup_pb[0].host) class DistributedPortBindingIfaceObjTestCase( |