Skip to content

Commit 15f60be

Browse files
otherwiseguyslawqo
authored andcommitted
Add has_lock_periodic decorator for OVN Maintenance
Almost all of the periodic methods in ml2/OVN's maintenance code exit early if the IDL lock is not held. This adds a decorator that wraps the futurist periodic that exits if the lock isn't held. There are still a few methods that exit raising NeverAgain if certain features aren't available, and those have been left alone for now. Conflicts: neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/maintenance.py Partial-bug: #2074209 Change-Id: I9771bd4f76a9ec073afeeb80a787832102446cd6 (cherry picked from commit 1d7e99b) (cherry picked from commit 35d0535)
1 parent 82ece4f commit 15f60be

File tree

1 file changed

+32
-67
lines changed

1 file changed

+32
-67
lines changed

neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/maintenance.py

Lines changed: 32 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import abc
1717
import copy
18+
import functools
1819
import inspect
1920
import re
2021
import threading
@@ -53,6 +54,20 @@
5354
INCONSISTENCY_TYPE_DELETE = 'delete'
5455

5556

57+
def has_lock_periodic(*args, **kwargs):
58+
def wrapper(f):
59+
@functools.wraps(f)
60+
@periodics.periodic(*args, **kwargs)
61+
def decorator(self, *args, **kwargs):
62+
# This periodic task is included in DBInconsistenciesPeriodics
63+
# since it uses the lock to ensure only one worker is executing
64+
if not self.has_lock:
65+
return
66+
return f(self, *args, **kwargs)
67+
return decorator
68+
return wrapper
69+
70+
5671
class MaintenanceThread(object):
5772

5873
def __init__(self):
@@ -289,15 +304,10 @@ def _fix_create_update_subnet(self, context, row):
289304
# is held by some other neutron-server instance in the cloud, we'll attempt
290305
# to perform the migration every 10 seconds until completed.
291306
# TODO(ihrachys): Remove the migration to stateful fips in Z+1.
292-
@periodics.periodic(spacing=10, run_immediately=True)
307+
@has_lock_periodic(spacing=10, run_immediately=True)
293308
@rerun_on_schema_updates
294309
def migrate_to_stateful_fips(self):
295310
"""Perform the migration from stateless to stateful Floating IPs. """
296-
# Only the worker holding a valid lock within OVSDB will perform the
297-
# migration.
298-
if not self.has_lock:
299-
return
300-
301311
admin_context = n_context.get_admin_context()
302312
nb_sync = ovn_db_sync.OvnNbSynchronizer(
303313
self._ovn_client._plugin, self._nb_idl, self._ovn_client._sb_idl,
@@ -358,14 +368,9 @@ def _log(inconsistencies, type_):
358368
_log(create_update_inconsistencies, INCONSISTENCY_TYPE_CREATE_UPDATE)
359369
_log(delete_inconsistencies, INCONSISTENCY_TYPE_DELETE)
360370

361-
@periodics.periodic(spacing=ovn_const.DB_CONSISTENCY_CHECK_INTERVAL,
362-
run_immediately=True)
371+
@has_lock_periodic(spacing=ovn_const.DB_CONSISTENCY_CHECK_INTERVAL,
372+
run_immediately=True)
363373
def check_for_inconsistencies(self):
364-
# Only the worker holding a valid lock within OVSDB will run
365-
# this periodic
366-
if not self.has_lock:
367-
return
368-
369374
admin_context = n_context.get_admin_context()
370375
create_update_inconsistencies = (
371376
revision_numbers_db.get_inconsistent_resources(admin_context))
@@ -481,13 +486,8 @@ def _delete_floatingip_and_pf(self, context, fip_id):
481486

482487
# A static spacing value is used here, but this method will only run
483488
# once per lock due to the use of periodics.NeverAgain().
484-
@periodics.periodic(spacing=600,
485-
run_immediately=True)
489+
@has_lock_periodic(spacing=600, run_immediately=True)
486490
def check_global_dhcp_opts(self):
487-
# This periodic task is included in DBInconsistenciesPeriodics since
488-
# it uses the lock to ensure only one worker is executing
489-
if not self.has_lock:
490-
return
491491
if (not ovn_conf.get_global_dhcpv4_opts() and
492492
not ovn_conf.get_global_dhcpv6_opts()):
493493
# No need to scan the subnets if the settings are unset.
@@ -516,11 +516,8 @@ def check_global_dhcp_opts(self):
516516

517517
# A static spacing value is used here, but this method will only run
518518
# once per lock due to the use of periodics.NeverAgain().
519-
@periodics.periodic(spacing=600, run_immediately=True)
519+
@has_lock_periodic(spacing=600, run_immediately=True)
520520
def check_for_igmp_snoop_support(self):
521-
if not self.has_lock:
522-
return
523-
524521
with self._nb_idl.transaction(check_error=True) as txn:
525522
value = ('true' if ovn_conf.is_igmp_snooping_enabled()
526523
else 'false')
@@ -539,11 +536,8 @@ def check_for_igmp_snoop_support(self):
539536
# TODO(czesla): Remove this in the A+4 cycle
540537
# A static spacing value is used here, but this method will only run
541538
# once per lock due to the use of periodics.NeverAgain().
542-
@periodics.periodic(spacing=600, run_immediately=True)
539+
@has_lock_periodic(spacing=600, run_immediately=True)
543540
def check_port_has_address_scope(self):
544-
if not self.has_lock:
545-
return
546-
547541
ports = self._nb_idl.db_find_rows(
548542
"Logical_Switch_Port", ("type", "!=", ovn_const.LSP_TYPE_LOCALNET)
549543
).execute(check_error=True)
@@ -618,11 +612,8 @@ def check_for_ha_chassis_group(self):
618612
# TODO(lucasagomes): Remove this in the B+3 cycle
619613
# A static spacing value is used here, but this method will only run
620614
# once per lock due to the use of periodics.NeverAgain().
621-
@periodics.periodic(spacing=600, run_immediately=True)
615+
@has_lock_periodic(spacing=600, run_immediately=True)
622616
def check_for_mcast_flood_reports(self):
623-
if not self.has_lock:
624-
return
625-
626617
cmds = []
627618
for port in self._nb_idl.lsp_list().execute(check_error=True):
628619
port_type = port.type.strip()
@@ -667,11 +658,8 @@ def check_for_mcast_flood_reports(self):
667658
# TODO(lucasagomes): Remove this in the Z cycle
668659
# A static spacing value is used here, but this method will only run
669660
# once per lock due to the use of periodics.NeverAgain().
670-
@periodics.periodic(spacing=600, run_immediately=True)
661+
@has_lock_periodic(spacing=600, run_immediately=True)
671662
def check_router_mac_binding_options(self):
672-
if not self.has_lock:
673-
return
674-
675663
cmds = []
676664
for router in self._nb_idl.lr_list().execute(check_error=True):
677665
if (router.options.get('always_learn_from_arp_request') and
@@ -726,14 +714,12 @@ def update_port_qos_with_external_ids_reference(self):
726714

727715
# A static spacing value is used here, but this method will only run
728716
# once per lock due to the use of periodics.NeverAgain().
729-
@periodics.periodic(spacing=600, run_immediately=True)
717+
@has_lock_periodic(spacing=600, run_immediately=True)
730718
def check_redirect_type_router_gateway_ports(self):
731719
"""Check OVN router gateway ports
732720
Check for the option "redirect-type=bridged" value for
733721
router gateway ports.
734722
"""
735-
if not self.has_lock:
736-
return
737723
context = n_context.get_admin_context()
738724
cmds = []
739725
gw_ports = self._ovn_client._plugin.get_ports(
@@ -786,14 +772,12 @@ def check_redirect_type_router_gateway_ports(self):
786772

787773
# A static spacing value is used here, but this method will only run
788774
# once per lock due to the use of periodics.NeverAgain().
789-
@periodics.periodic(spacing=600, run_immediately=True)
775+
@has_lock_periodic(spacing=600, run_immediately=True)
790776
def check_vlan_distributed_ports(self):
791777
"""Check VLAN distributed ports
792778
Check for the option "reside-on-redirect-chassis" value for
793779
distributed VLAN ports.
794780
"""
795-
if not self.has_lock:
796-
return
797781
context = n_context.get_admin_context()
798782
cmds = []
799783
# Get router ports belonging to VLAN networks
@@ -829,12 +813,9 @@ def check_vlan_distributed_ports(self):
829813
# a gateway (that means, that has "external_ids:OVN_GW_PORT_EXT_ID_KEY").
830814
# A static spacing value is used here, but this method will only run
831815
# once per lock due to the use of periodics.NeverAgain().
832-
@periodics.periodic(spacing=600, run_immediately=True)
816+
@has_lock_periodic(spacing=600, run_immediately=True)
833817
def update_logical_router_with_gateway_network_id(self):
834818
"""Update all OVN logical router registers with the GW network ID"""
835-
if not self.has_lock:
836-
return
837-
838819
cmds = []
839820
context = n_context.get_admin_context()
840821
for lr in self._nb_idl.lr_list().execute(check_error=True):
@@ -911,16 +892,13 @@ def check_baremetal_ports_dhcp_options(self):
911892
raise periodics.NeverAgain()
912893

913894
# TODO(ralonsoh): Remove this in the Z+4 cycle
914-
@periodics.periodic(spacing=600, run_immediately=True)
895+
@has_lock_periodic(spacing=600, run_immediately=True)
915896
def update_port_virtual_type(self):
916897
"""Set type=virtual to those ports with parents
917898
Before LP#1973276, any virtual port with "device_owner" defined, lost
918899
its type=virtual. This task restores the type for those ports updated
919900
before the fix https://review.opendev.org/c/openstack/neutron/+/841711.
920901
"""
921-
if not self.has_lock:
922-
return
923-
924902
context = n_context.get_admin_context()
925903
cmds = []
926904
for lsp in self._nb_idl.lsp_list().execute(check_error=True):
@@ -948,7 +926,7 @@ def update_port_virtual_type(self):
948926
raise periodics.NeverAgain()
949927

950928
# TODO(ralonsoh): Remove this in the Antelope+4 cycle
951-
@periodics.periodic(spacing=600, run_immediately=True)
929+
@has_lock_periodic(spacing=600, run_immediately=True)
952930
def create_router_extra_attributes_registers(self):
953931
"""Create missing ``RouterExtraAttributes`` registers.
954932
@@ -958,9 +936,6 @@ def create_router_extra_attributes_registers(self):
958936
only execution method finds those ``Routers`` registers without the
959937
child one and creates one with the default values.
960938
"""
961-
if not self.has_lock:
962-
return
963-
964939
context = n_context.get_admin_context()
965940
for router_id in router_obj.Router.\
966941
get_router_ids_without_router_std_attrs(context):
@@ -1008,13 +983,10 @@ def add_gw_port_info_to_logical_router_port(self):
1008983
txn.add(cmd)
1009984
raise periodics.NeverAgain()
1010985

1011-
@periodics.periodic(spacing=600, run_immediately=True)
986+
@has_lock_periodic(spacing=600, run_immediately=True)
1012987
def check_router_default_route_empty_dst_ip(self):
1013988
"""Check routers with default route with empty dst-ip (LP: #2002993).
1014989
"""
1015-
if not self.has_lock:
1016-
return
1017-
1018990
cmds = []
1019991
for router in self._nb_idl.lr_list().execute(check_error=True):
1020992
if not router.external_ids.get(ovn_const.OVN_REV_NUM_EXT_ID_KEY):
@@ -1036,7 +1008,7 @@ def check_router_default_route_empty_dst_ip(self):
10361008
raise periodics.NeverAgain()
10371009

10381010
# TODO(ralonsoh): Remove this in the Antelope+4 cycle
1039-
@periodics.periodic(spacing=600, run_immediately=True)
1011+
@has_lock_periodic(spacing=600, run_immediately=True)
10401012
def add_vnic_type_and_pb_capabilities_to_lsp(self):
10411013
"""Add the port VNIC type and port binding capabilities to the LSP.
10421014
@@ -1047,9 +1019,6 @@ def add_vnic_type_and_pb_capabilities_to_lsp(self):
10471019
been added to the LSP the VNIC type and the port binding capabilities.
10481020
To implement LP#1998608, only direct ports are needed.
10491021
"""
1050-
if not self.has_lock:
1051-
return
1052-
10531022
port_bindings = ports_obj.PortBinding.get_port_binding_by_vnic_type(
10541023
n_context.get_admin_context(), portbindings.VNIC_DIRECT)
10551024
with self._nb_idl.transaction(check_error=True) as txn:
@@ -1071,7 +1040,7 @@ def add_vnic_type_and_pb_capabilities_to_lsp(self):
10711040

10721041
raise periodics.NeverAgain()
10731042

1074-
@periodics.periodic(spacing=600, run_immediately=True)
1043+
@has_lock_periodic(spacing=600, run_immediately=True)
10751044
def check_fair_meter_consistency(self):
10761045
"""Update the logging meter after neutron-server reload
10771046
@@ -1080,8 +1049,6 @@ def check_fair_meter_consistency(self):
10801049
driver after the OVN NB idl is loaded
10811050
10821051
"""
1083-
if not self.has_lock:
1084-
return
10851052
if log_driver.OVNDriver.network_logging_supported(self._nb_idl):
10861053
meter_name = (
10871054
cfg.CONF.network_log.local_output_log_base or "acl_log_meter")
@@ -1146,7 +1113,7 @@ def remove_duplicated_chassis_registers(self):
11461113
for table in ('Chassis_Private', 'Chassis'):
11471114
txn.add(self._sb_idl.db_destroy(table, ch.name))
11481115

1149-
@periodics.periodic(spacing=86400, run_immediately=True)
1116+
@has_lock_periodic(spacing=86400, run_immediately=True)
11501117
def cleanup_old_hash_ring_nodes(self):
11511118
"""Daily task to cleanup old stable Hash Ring node entries.
11521119
@@ -1155,8 +1122,6 @@ def cleanup_old_hash_ring_nodes(self):
11551122
information.
11561123
11571124
"""
1158-
if not self.has_lock:
1159-
return
11601125
context = n_context.get_admin_context()
11611126
hash_ring_db.cleanup_old_nodes(context, days=5)
11621127

0 commit comments

Comments
 (0)