summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2023-03-16 18:06:09 +0000
committerGerrit Code Review <review@openstack.org>2023-03-16 18:06:09 +0000
commit6a69019fb5bed6ac490a64d4f5357e7a68c3975c (patch)
tree65a75c4a56a0a30d9eceea91434a1e1509e41df8
parent0091a25ea65e14bbc56c0b816617f61a74bb35aa (diff)
parent07855a68266484ae187c76708a727b8a4db1e2e2 (diff)
downloadneutron-6a69019fb5bed6ac490a64d4f5357e7a68c3975c.tar.gz
Merge "Delete the PB level registers when deleting the duplicated PB" into stable/zed
-rw-r--r--neutron/cmd/remove_duplicated_port_bindings.py15
-rw-r--r--neutron/objects/ports.py16
-rw-r--r--neutron/tests/unit/objects/test_ports.py10
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 6dafc1531a..7789dc73fe 100644
--- a/neutron/cmd/remove_duplicated_port_bindings.py
+++ b/neutron/cmd/remove_duplicated_port_bindings.py
@@ -35,7 +35,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
@@ -43,6 +43,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.
"""
@@ -54,12 +58,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 30367fb9db..cfad25d195 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(