1515
1616import abc
1717import copy
18+ import functools
1819import inspect
1920import re
2021import threading
5354INCONSISTENCY_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+
5671class 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 ,
@@ -310,7 +320,7 @@ def migrate_to_stateful_fips(self):
310320 # to perform the migration every 10 seconds until completed.
311321 # TODO(jlibosva): Remove the migration to port groups at some point. It's
312322 # been around since Queens release so it is good to drop this soon.
313- @periodics . periodic (spacing = 10 , run_immediately = True )
323+ @has_lock_periodic (spacing = 10 , run_immediately = True )
314324 @rerun_on_schema_updates
315325 def migrate_to_port_groups (self ):
316326 """Perform the migration from Address Sets to Port Groups. """
@@ -322,11 +332,6 @@ def migrate_to_port_groups(self):
322332 if not self ._nb_idl .get_address_sets ():
323333 raise periodics .NeverAgain ()
324334
325- # Only the worker holding a valid lock within OVSDB will perform the
326- # migration.
327- if not self .has_lock :
328- return
329-
330335 admin_context = n_context .get_admin_context ()
331336 nb_sync = ovn_db_sync .OvnNbSynchronizer (
332337 self ._ovn_client ._plugin , self ._nb_idl , self ._ovn_client ._sb_idl ,
@@ -358,14 +363,9 @@ def _log(inconsistencies, type_):
358363 _log (create_update_inconsistencies , INCONSISTENCY_TYPE_CREATE_UPDATE )
359364 _log (delete_inconsistencies , INCONSISTENCY_TYPE_DELETE )
360365
361- @periodics . periodic (spacing = ovn_const .DB_CONSISTENCY_CHECK_INTERVAL ,
362- run_immediately = True )
366+ @has_lock_periodic (spacing = ovn_const .DB_CONSISTENCY_CHECK_INTERVAL ,
367+ run_immediately = True )
363368 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-
369369 admin_context = n_context .get_admin_context ()
370370 create_update_inconsistencies = (
371371 revision_numbers_db .get_inconsistent_resources (admin_context ))
@@ -481,13 +481,8 @@ def _delete_floatingip_and_pf(self, context, fip_id):
481481
482482 # A static spacing value is used here, but this method will only run
483483 # once per lock due to the use of periodics.NeverAgain().
484- @periodics .periodic (spacing = 600 ,
485- run_immediately = True )
484+ @has_lock_periodic (spacing = 600 , run_immediately = True )
486485 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
491486 if (not ovn_conf .get_global_dhcpv4_opts () and
492487 not ovn_conf .get_global_dhcpv6_opts ()):
493488 # No need to scan the subnets if the settings are unset.
@@ -516,11 +511,8 @@ def check_global_dhcp_opts(self):
516511
517512 # A static spacing value is used here, but this method will only run
518513 # once per lock due to the use of periodics.NeverAgain().
519- @periodics . periodic (spacing = 600 , run_immediately = True )
514+ @has_lock_periodic (spacing = 600 , run_immediately = True )
520515 def check_for_igmp_snoop_support (self ):
521- if not self .has_lock :
522- return
523-
524516 with self ._nb_idl .transaction (check_error = True ) as txn :
525517 value = ('true' if ovn_conf .is_igmp_snooping_enabled ()
526518 else 'false' )
@@ -539,11 +531,8 @@ def check_for_igmp_snoop_support(self):
539531 # TODO(czesla): Remove this in the A+4 cycle
540532 # A static spacing value is used here, but this method will only run
541533 # once per lock due to the use of periodics.NeverAgain().
542- @periodics . periodic (spacing = 600 , run_immediately = True )
534+ @has_lock_periodic (spacing = 600 , run_immediately = True )
543535 def check_port_has_address_scope (self ):
544- if not self .has_lock :
545- return
546-
547536 ports = self ._nb_idl .db_find_rows (
548537 "Logical_Switch_Port" , ("type" , "!=" , ovn_const .LSP_TYPE_LOCALNET )
549538 ).execute (check_error = True )
@@ -585,16 +574,13 @@ def _delete_default_ha_chassis_group(self, txn):
585574
586575 # A static spacing value is used here, but this method will only run
587576 # once per lock due to the use of periodics.NeverAgain().
588- @periodics . periodic (spacing = 600 , run_immediately = True )
577+ @has_lock_periodic (spacing = 600 , run_immediately = True )
589578 def check_for_ha_chassis_group (self ):
590579 # If external ports is not supported stop running
591580 # this periodic task
592581 if not self ._ovn_client .is_external_ports_supported ():
593582 raise periodics .NeverAgain ()
594583
595- if not self .has_lock :
596- return
597-
598584 external_ports = self ._nb_idl .db_find_rows (
599585 'Logical_Switch_Port' , ('type' , '=' , ovn_const .LSP_TYPE_EXTERNAL )
600586 ).execute (check_error = True )
@@ -618,11 +604,8 @@ def check_for_ha_chassis_group(self):
618604 # TODO(lucasagomes): Remove this in the B+3 cycle
619605 # A static spacing value is used here, but this method will only run
620606 # once per lock due to the use of periodics.NeverAgain().
621- @periodics . periodic (spacing = 600 , run_immediately = True )
607+ @has_lock_periodic (spacing = 600 , run_immediately = True )
622608 def check_for_mcast_flood_reports (self ):
623- if not self .has_lock :
624- return
625-
626609 cmds = []
627610 for port in self ._nb_idl .lsp_list ().execute (check_error = True ):
628611 port_type = port .type .strip ()
@@ -667,11 +650,8 @@ def check_for_mcast_flood_reports(self):
667650 # TODO(lucasagomes): Remove this in the Z cycle
668651 # A static spacing value is used here, but this method will only run
669652 # once per lock due to the use of periodics.NeverAgain().
670- @periodics . periodic (spacing = 600 , run_immediately = True )
653+ @has_lock_periodic (spacing = 600 , run_immediately = True )
671654 def check_router_mac_binding_options (self ):
672- if not self .has_lock :
673- return
674-
675655 cmds = []
676656 for router in self ._nb_idl .lr_list ().execute (check_error = True ):
677657 if (router .options .get ('always_learn_from_arp_request' ) and
@@ -692,16 +672,13 @@ def check_router_mac_binding_options(self):
692672 # TODO(ralonsoh): Remove this in the Z+2 cycle
693673 # A static spacing value is used here, but this method will only run
694674 # once per lock due to the use of periodics.NeverAgain().
695- @periodics . periodic (spacing = 600 , run_immediately = True )
675+ @has_lock_periodic (spacing = 600 , run_immediately = True )
696676 def update_port_qos_with_external_ids_reference (self ):
697677 """Update all OVN QoS registers with the port ID
698678
699679 This method will only update the OVN QoS registers related to port QoS,
700680 not FIP QoS. FIP QoS have the corresponding "external_ids" reference.
701681 """
702- if not self .has_lock :
703- return
704-
705682 regex = re .compile (
706683 r'(inport|outport) == \"(?P<port_id>[a-z0-9\-]{36})\"' )
707684 cmds = []
@@ -726,14 +703,12 @@ def update_port_qos_with_external_ids_reference(self):
726703
727704 # A static spacing value is used here, but this method will only run
728705 # once per lock due to the use of periodics.NeverAgain().
729- @periodics . periodic (spacing = 600 , run_immediately = True )
706+ @has_lock_periodic (spacing = 600 , run_immediately = True )
730707 def check_redirect_type_router_gateway_ports (self ):
731708 """Check OVN router gateway ports
732709 Check for the option "redirect-type=bridged" value for
733710 router gateway ports.
734711 """
735- if not self .has_lock :
736- return
737712 context = n_context .get_admin_context ()
738713 cmds = []
739714 gw_ports = self ._ovn_client ._plugin .get_ports (
@@ -786,14 +761,12 @@ def check_redirect_type_router_gateway_ports(self):
786761
787762 # A static spacing value is used here, but this method will only run
788763 # once per lock due to the use of periodics.NeverAgain().
789- @periodics . periodic (spacing = 600 , run_immediately = True )
764+ @has_lock_periodic (spacing = 600 , run_immediately = True )
790765 def check_vlan_distributed_ports (self ):
791766 """Check VLAN distributed ports
792767 Check for the option "reside-on-redirect-chassis" value for
793768 distributed VLAN ports.
794769 """
795- if not self .has_lock :
796- return
797770 context = n_context .get_admin_context ()
798771 cmds = []
799772 # Get router ports belonging to VLAN networks
@@ -829,12 +802,9 @@ def check_vlan_distributed_ports(self):
829802 # a gateway (that means, that has "external_ids:OVN_GW_PORT_EXT_ID_KEY").
830803 # A static spacing value is used here, but this method will only run
831804 # once per lock due to the use of periodics.NeverAgain().
832- @periodics . periodic (spacing = 600 , run_immediately = True )
805+ @has_lock_periodic (spacing = 600 , run_immediately = True )
833806 def update_logical_router_with_gateway_network_id (self ):
834807 """Update all OVN logical router registers with the GW network ID"""
835- if not self .has_lock :
836- return
837-
838808 cmds = []
839809 context = n_context .get_admin_context ()
840810 for lr in self ._nb_idl .lr_list ().execute (check_error = True ):
@@ -859,7 +829,7 @@ def update_logical_router_with_gateway_network_id(self):
859829
860830 # A static spacing value is used here, but this method will only run
861831 # once per lock due to the use of periodics.NeverAgain().
862- @periodics . periodic (spacing = 600 , run_immediately = True )
832+ @has_lock_periodic (spacing = 600 , run_immediately = True )
863833 def check_baremetal_ports_dhcp_options (self ):
864834 """Update baremetal ports DHCP options
865835
@@ -871,9 +841,6 @@ def check_baremetal_ports_dhcp_options(self):
871841 if not self ._ovn_client .is_external_ports_supported ():
872842 raise periodics .NeverAgain ()
873843
874- if not self .has_lock :
875- return
876-
877844 context = n_context .get_admin_context ()
878845 ports = ports_obj .Port .get_ports_by_vnic_type_and_host (
879846 context , portbindings .VNIC_BAREMETAL )
@@ -911,16 +878,13 @@ def check_baremetal_ports_dhcp_options(self):
911878 raise periodics .NeverAgain ()
912879
913880 # TODO(ralonsoh): Remove this in the Z+4 cycle
914- @periodics . periodic (spacing = 600 , run_immediately = True )
881+ @has_lock_periodic (spacing = 600 , run_immediately = True )
915882 def update_port_virtual_type (self ):
916883 """Set type=virtual to those ports with parents
917884 Before LP#1973276, any virtual port with "device_owner" defined, lost
918885 its type=virtual. This task restores the type for those ports updated
919886 before the fix https://review.opendev.org/c/openstack/neutron/+/841711.
920887 """
921- if not self .has_lock :
922- return
923-
924888 context = n_context .get_admin_context ()
925889 cmds = []
926890 for lsp in self ._nb_idl .lsp_list ().execute (check_error = True ):
@@ -948,7 +912,7 @@ def update_port_virtual_type(self):
948912 raise periodics .NeverAgain ()
949913
950914 # TODO(ralonsoh): Remove this in the Antelope+4 cycle
951- @periodics . periodic (spacing = 600 , run_immediately = True )
915+ @has_lock_periodic (spacing = 600 , run_immediately = True )
952916 def create_router_extra_attributes_registers (self ):
953917 """Create missing ``RouterExtraAttributes`` registers.
954918
@@ -958,9 +922,6 @@ def create_router_extra_attributes_registers(self):
958922 only execution method finds those ``Routers`` registers without the
959923 child one and creates one with the default values.
960924 """
961- if not self .has_lock :
962- return
963-
964925 context = n_context .get_admin_context ()
965926 for router_id in router_obj .Router .\
966927 get_router_ids_without_router_std_attrs (context ):
@@ -1008,13 +969,10 @@ def add_gw_port_info_to_logical_router_port(self):
1008969 txn .add (cmd )
1009970 raise periodics .NeverAgain ()
1010971
1011- @periodics . periodic (spacing = 600 , run_immediately = True )
972+ @has_lock_periodic (spacing = 600 , run_immediately = True )
1012973 def check_router_default_route_empty_dst_ip (self ):
1013974 """Check routers with default route with empty dst-ip (LP: #2002993).
1014975 """
1015- if not self .has_lock :
1016- return
1017-
1018976 cmds = []
1019977 for router in self ._nb_idl .lr_list ().execute (check_error = True ):
1020978 if not router .external_ids .get (ovn_const .OVN_REV_NUM_EXT_ID_KEY ):
@@ -1036,7 +994,7 @@ def check_router_default_route_empty_dst_ip(self):
1036994 raise periodics .NeverAgain ()
1037995
1038996 # TODO(ralonsoh): Remove this in the Antelope+4 cycle
1039- @periodics . periodic (spacing = 600 , run_immediately = True )
997+ @has_lock_periodic (spacing = 600 , run_immediately = True )
1040998 def add_vnic_type_and_pb_capabilities_to_lsp (self ):
1041999 """Add the port VNIC type and port binding capabilities to the LSP.
10421000
@@ -1047,9 +1005,6 @@ def add_vnic_type_and_pb_capabilities_to_lsp(self):
10471005 been added to the LSP the VNIC type and the port binding capabilities.
10481006 To implement LP#1998608, only direct ports are needed.
10491007 """
1050- if not self .has_lock :
1051- return
1052-
10531008 port_bindings = ports_obj .PortBinding .get_port_binding_by_vnic_type (
10541009 n_context .get_admin_context (), portbindings .VNIC_DIRECT )
10551010 with self ._nb_idl .transaction (check_error = True ) as txn :
@@ -1071,7 +1026,7 @@ def add_vnic_type_and_pb_capabilities_to_lsp(self):
10711026
10721027 raise periodics .NeverAgain ()
10731028
1074- @periodics . periodic (spacing = 600 , run_immediately = True )
1029+ @has_lock_periodic (spacing = 600 , run_immediately = True )
10751030 def check_fair_meter_consistency (self ):
10761031 """Update the logging meter after neutron-server reload
10771032
@@ -1080,16 +1035,14 @@ def check_fair_meter_consistency(self):
10801035 driver after the OVN NB idl is loaded
10811036
10821037 """
1083- if not self .has_lock :
1084- return
10851038 if log_driver .OVNDriver .network_logging_supported (self ._nb_idl ):
10861039 meter_name = (
10871040 cfg .CONF .network_log .local_output_log_base or "acl_log_meter" )
10881041 self ._ovn_client .create_ovn_fair_meter (meter_name ,
10891042 from_reload = True )
10901043 raise periodics .NeverAgain ()
10911044
1092- @periodics . periodic (spacing = 300 , run_immediately = True )
1045+ @has_lock_periodic (spacing = 300 , run_immediately = True )
10931046 def remove_duplicated_chassis_registers (self ):
10941047 """Remove the "Chassis" and "Chassis_Private" duplicated registers.
10951048
@@ -1108,9 +1061,6 @@ def remove_duplicated_chassis_registers(self):
11081061 if not self ._sb_idl .is_table_present ('Chassis_Private' ):
11091062 raise periodics .NeverAgain ()
11101063
1111- if not self .has_lock :
1112- return
1113-
11141064 # dup_chassis_port_host = {host_name: [(ch1, ch_private1),
11151065 # (ch2, ch_private2), ... ]}
11161066 dup_chassis_port_host = {}
@@ -1146,7 +1096,7 @@ def remove_duplicated_chassis_registers(self):
11461096 for table in ('Chassis_Private' , 'Chassis' ):
11471097 txn .add (self ._sb_idl .db_destroy (table , ch .name ))
11481098
1149- @periodics . periodic (spacing = 86400 , run_immediately = True )
1099+ @has_lock_periodic (spacing = 86400 , run_immediately = True )
11501100 def cleanup_old_hash_ring_nodes (self ):
11511101 """Daily task to cleanup old stable Hash Ring node entries.
11521102
@@ -1155,8 +1105,6 @@ def cleanup_old_hash_ring_nodes(self):
11551105 information.
11561106
11571107 """
1158- if not self .has_lock :
1159- return
11601108 context = n_context .get_admin_context ()
11611109 hash_ring_db .cleanup_old_nodes (context , days = 5 )
11621110
0 commit comments