Skip to content

Commit 833260b

Browse files
ralonsohfrittentheke
authored andcommitted
Delete the PB level registers when deleting the duplicated PB
The ``neutron-remove-duplicated-port-bindings`` script removes the duplicated port binding registers ("ml2_port_bindings" table) that have status=INACTIVE. This patch also removes the corresponding port binding levels ("ml2_port_binding_levels" table) associated to those inactive port bindings. Closes-Bug: #2000078 Change-Id: I12fa0764cd0ff509f1859b61060d64cc5a54a7b9 (cherry picked from commit 572185e) (cherry picked from commit 07855a6)
1 parent f83a97d commit 833260b

File tree

3 files changed

+32
-9
lines changed

3 files changed

+32
-9
lines changed

neutron/cmd/remove_duplicated_port_bindings.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,18 @@ def setup_conf(conf):
3434

3535

3636
def main():
37-
"""Main method for removing the duplicated port binding registers.
37+
"""Main method for removing duplicated port binding and pb level registers.
3838
3939
This script finds all ``PortBinding`` registers with the same ``port_id``.
4040
That happens during the live-migration process. Once finished, the inactive
4141
port binding register is deleted. However, it could happen that during the
4242
live-migration, an error occurs and this deletion is not executed. The
4343
related port cannot be migrated anymore.
4444
45+
This script removes the inactive ``PortBinding`` referred to a port ID and
46+
the corresponding ``PortBindingLevel`` registers associated to this port
47+
ID and ``PortBinding.host``.
48+
4549
This script should not be executed during a live migration process. It will
4650
remove the inactive port binding and will break the migration.
4751
"""
@@ -53,12 +57,15 @@ def main():
5357
dup_pbindings = ports_obj.PortBinding.get_duplicated_port_bindings(
5458
admin_ctx)
5559

56-
# Clean duplicated port bindings that are INACTIVE (if not in dry-run).
60+
# Clean duplicated port bindings that are INACTIVE and the
61+
# corresponding port binding level registers (if not in dry-run).
5762
if not _dry_run:
5863
for pbinding in dup_pbindings:
64+
port_id, host = pbinding.port_id, pbinding.host
5965
ports_obj.PortBinding.delete_objects(
60-
admin_ctx, status=constants.INACTIVE,
61-
port_id=pbinding.port_id)
66+
admin_ctx, status=constants.INACTIVE, port_id=port_id)
67+
ports_obj.PortBindingLevel.delete_objects(
68+
admin_ctx, port_id=port_id, host=host)
6269

6370
if dup_pbindings:
6471
port_ids = [pbinding.port_id for pbinding in dup_pbindings]

neutron/objects/ports.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,19 @@ def get_port_id_and_host(cls, context, vif_type, vnic_type, status):
106106
@classmethod
107107
@db_api.CONTEXT_READER
108108
def get_duplicated_port_bindings(cls, context):
109-
return context.session.query(
110-
cls.db_model).group_by(
111-
cls.db_model.port_id).having(sqlalchemy.func.count() > 1).all()
109+
# This query will return the port_id of all "ml2_port_bindings"
110+
# registers that appears more than once (duplicated
111+
# "ml2_port_bindings" registers).
112+
# At the same time, this query returns only the "ml2_port_bindings"
113+
# that have status=INACTIVE.
114+
select = (
115+
sqlalchemy.select(cls.db_model.port_id).
116+
select_from(cls.db_model).
117+
group_by(cls.db_model.port_id).
118+
having(sqlalchemy.func.count(cls.db_model.port_id) > 1))
119+
_filter = and_(cls.db_model.port_id.in_(select),
120+
cls.db_model.status == constants.INACTIVE)
121+
return context.session.query(cls.db_model).filter(_filter).all()
112122

113123

114124
@base.NeutronObjectRegistry.register

neutron/tests/unit/objects/test_ports.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,20 @@ class PortBindingDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
5656

5757
def test_get_duplicated_port_bindings(self):
5858
port_id = self._create_test_port_id()
59-
self.update_obj_fields({'port_id': port_id},
60-
objs=[self.objs[0], self.objs[1]])
59+
self.update_obj_fields(
60+
{'port_id': port_id, 'status': constants.ACTIVE},
61+
obj_fields=[self.obj_fields[0]])
62+
self.update_obj_fields(
63+
{'port_id': port_id, 'status': constants.INACTIVE},
64+
obj_fields=[self.obj_fields[1]])
6165
for i in range(3):
6266
_obj = self._make_object(self.obj_fields[i])
6367
_obj.create()
6468
dup_pb = ports.PortBinding.get_duplicated_port_bindings(self.context)
6569
self.assertEqual(1, len(dup_pb))
6670
self.assertEqual(port_id, dup_pb[0].port_id)
71+
# The PB register returned is the INACTIVE one.
72+
self.assertEqual(self.obj_fields[1]['host'], dup_pb[0].host)
6773

6874

6975
class DistributedPortBindingIfaceObjTestCase(

0 commit comments

Comments
 (0)