1313# under the License.
1414
1515import abc
16+ import copy
17+ import uuid
1618
1719from oslo_utils import timeutils
20+ from ovs .db import idl as ovs_idl
1821from ovsdbapp .backend .ovs_idl import command
1922from ovsdbapp .backend .ovs_idl import idlutils
23+ from ovsdbapp .backend .ovs_idl import rowview
2024from ovsdbapp .schema .ovn_northbound import commands as ovn_nb_commands
2125from ovsdbapp import utils as ovsdbapp_utils
2226
@@ -100,6 +104,49 @@ def _add_gateway_chassis(api, txn, lrp_name, val):
100104 return 'gateway_chassis' , uuid_list
101105
102106
107+ def _sync_ha_chassis_group (txn , nb_api , name , chassis_priority ,
108+ may_exist = False , table_name = 'HA_Chassis_Group' ,
109+ ** columns ):
110+ result = None
111+ hcg = nb_api .lookup (table_name , name , default = None )
112+ if hcg :
113+ if not may_exist :
114+ raise RuntimeError (_ ('HA_Chassis_Group %s exists' % name ))
115+ else :
116+ hcg = txn .insert (nb_api ._tables [table_name ])
117+ hcg .name = name
118+ command .BaseCommand .set_columns (hcg , ** columns )
119+ result = hcg .uuid
120+
121+ # HA_Chassis registers handling.
122+ # Remove the non-existing chassis in ``self.chassis_priority``
123+ hc_to_remove = []
124+ for hc in getattr (hcg , 'ha_chassis' , []):
125+ if hc .chassis_name not in chassis_priority :
126+ hc_to_remove .append (hc )
127+
128+ for hc in hc_to_remove :
129+ hcg .delvalue ('ha_chassis' , hc )
130+ hc .delete ()
131+
132+ # Update the priority of the existing chassis.
133+ for hc in getattr (hcg , 'ha_chassis' , []):
134+ hc_priority = chassis_priority .pop (hc .chassis_name )
135+ hc .priority = hc_priority
136+
137+ # Add the non-existing HA_Chassis registers.
138+ for hc_name , priority in chassis_priority .items ():
139+ hc = txn .insert (nb_api .tables ['HA_Chassis' ])
140+ hc .chassis_name = hc_name
141+ hc .priority = priority
142+ hcg .addvalue ('ha_chassis' , hc )
143+
144+ if not result :
145+ result = rowview .RowView (hcg )
146+
147+ return result
148+
149+
103150class CheckLivenessCommand (command .BaseCommand ):
104151 def run_idl (self , txn ):
105152 # txn.pre_commit responsible for updating nb_global.nb_cfg, but
@@ -110,21 +157,64 @@ def run_idl(self, txn):
110157 self .result = self .api .nb_global .nb_cfg
111158
112159
160+ class AddNetworkCommand (command .AddCommand ):
161+ table_name = 'Logical_Switch'
162+
163+ def __init__ (self , api , network_id , may_exist = False , ** columns ):
164+ super ().__init__ (api )
165+ self .network_uuid = uuid .UUID (str (network_id ))
166+ self .may_exist = may_exist
167+ self .columns = columns
168+
169+ def run_idl (self , txn ):
170+ table = self .api .tables [self .table_name ]
171+ try :
172+ ls = table .rows [self .network_uuid ]
173+ if self .may_exist :
174+ self .result = rowview .RowView (ls )
175+ return
176+ msg = _ ("Switch %s already exists" ) % self .network_uuid
177+ raise RuntimeError (msg )
178+ except KeyError :
179+ # Adding a new LS
180+ if utils .ovs_persist_uuid_supported (txn .idl ):
181+ ls = txn .insert (table , new_uuid = self .network_uuid ,
182+ persist_uuid = True )
183+ else :
184+ ls = txn .insert (table )
185+ self .set_columns (ls , ** self .columns )
186+ ls .name = utils .ovn_name (self .network_uuid )
187+ self .result = ls .uuid
188+
189+
113190class AddLSwitchPortCommand (command .BaseCommand ):
114- def __init__ (self , api , lport , lswitch , may_exist , ** columns ):
191+ def __init__ (self , api , lport , lswitch , may_exist , network_id = None ,
192+ ** columns ):
115193 super ().__init__ (api )
116194 self .lport = lport
117195 self .lswitch = lswitch
118196 self .may_exist = may_exist
197+ self .network_uuid = uuid .UUID (str (network_id )) if network_id else None
119198 self .columns = columns
120199
121200 def run_idl (self , txn ):
122201 try :
202+ # We must look in the local cache first, because the LS may have
203+ # been created as part of the current transaction. or in the case
204+ # of adding an LSP to a LS that was created before persist_uuid
123205 lswitch = idlutils .row_by_value (self .api .idl , 'Logical_Switch' ,
124206 'name' , self .lswitch )
125207 except idlutils .RowNotFound :
126- msg = _ ("Logical Switch %s does not exist" ) % self .lswitch
127- raise RuntimeError (msg )
208+ if self .network_uuid and utils .ovs_persist_uuid_supported (txn .idl ):
209+ # Create a "fake" row with the right UUID so python-ovs creates
210+ # a transaction referencing the Row, even though we might not
211+ # have received the update for the row ourselves.
212+ lswitch = ovs_idl .Row (self .api .idl ,
213+ self .api .tables ['Logical_Switch' ],
214+ uuid = self .network_uuid , data = {})
215+ else :
216+ msg = _ ("Logical Switch %s does not exist" ) % self .lswitch
217+ raise RuntimeError (msg )
128218 if self .may_exist :
129219 port = idlutils .row_by_value (self .api .idl ,
130220 'Logical_Switch_Port' , 'name' ,
@@ -210,8 +300,8 @@ def run_idl(self, txn):
210300 else :
211301 new_port_dhcp_opts .add (dhcpv6_options .result )
212302 port .dhcpv6_options = [dhcpv6_options .result ]
213- for uuid in cur_port_dhcp_opts - new_port_dhcp_opts :
214- self .api ._tables ['DHCP_Options' ].rows [uuid ].delete ()
303+ for uuid_ in cur_port_dhcp_opts - new_port_dhcp_opts :
304+ self .api ._tables ['DHCP_Options' ].rows [uuid_ ].delete ()
215305
216306 external_ids_update = self .external_ids_update or {}
217307 external_ids = getattr (port , 'external_ids' , {})
@@ -293,8 +383,8 @@ def run_idl(self, txn):
293383 # Delete DHCP_Options records no longer referred by this port.
294384 cur_port_dhcp_opts = get_lsp_dhcp_options_uuids (
295385 lport , self .lport )
296- for uuid in cur_port_dhcp_opts :
297- self .api ._tables ['DHCP_Options' ].rows [uuid ].delete ()
386+ for uuid_ in cur_port_dhcp_opts :
387+ self .api ._tables ['DHCP_Options' ].rows [uuid_ ].delete ()
298388
299389 _delvalue_from_list (lswitch , 'ports' , lport )
300390 self .api ._tables ['Logical_Switch_Port' ].rows [lport .uuid ].delete ()
@@ -347,8 +437,7 @@ def run_idl(self, txn):
347437 az_hints = self .api .get_gateway_chassis_az_hints (self .g_name )
348438 filtered_existing_chassis = (
349439 self .scheduler .filter_existing_chassis (
350- nb_idl = self .api , gw_chassis = self .all_gw_chassis ,
351- physnet = physnet ,
440+ gw_chassis = self .all_gw_chassis , physnet = physnet ,
352441 chassis_physnets = self .chassis_with_physnets ,
353442 existing_chassis = existing_chassis , az_hints = az_hints ,
354443 chassis_with_azs = self .chassis_with_azs ))
@@ -388,9 +477,12 @@ def run_idl(self, txn):
388477 # the top.
389478 index = chassis .index (primary )
390479 chassis [0 ], chassis [index ] = chassis [index ], chassis [0 ]
391- setattr (
392- lrouter_port ,
393- * _add_gateway_chassis (self .api , txn , self .g_name , chassis ))
480+ chassis_priority = utils .get_chassis_priority (chassis )
481+ lrouter_name = lrouter_port .external_ids [
482+ ovn_const .OVN_ROUTER_NAME_EXT_ID_KEY ]
483+ hcg = _sync_ha_chassis_group (txn , self .api , lrouter_name ,
484+ chassis_priority , may_exist = True )
485+ setattr (lrouter_port , 'ha_chassis_group' , ovsdbapp_utils .get_uuid (hcg ))
394486
395487
396488class ScheduleNewGatewayCommand (command .BaseCommand ):
@@ -415,8 +507,11 @@ def run_idl(self, txn):
415507 self .api , self .sb_api , self .g_name , candidates = candidates ,
416508 target_lrouter = lrouter )
417509 if chassis :
418- setattr (lrouter_port ,
419- * _add_gateway_chassis (self .api , txn , self .g_name , chassis ))
510+ chassis_priority = utils .get_chassis_priority (chassis )
511+ hcg = _sync_ha_chassis_group (txn , self .api , self .lrouter_name ,
512+ chassis_priority , may_exist = True )
513+ setattr (lrouter_port , 'ha_chassis_group' ,
514+ ovsdbapp_utils .get_uuid (hcg ))
420515
421516
422517class LrDelCommand (ovn_nb_commands .LrDelCommand ):
@@ -465,8 +560,9 @@ def run_idl(self, txn):
465560 if col == 'gateway_chassis' :
466561 col , val = _add_gateway_chassis (self .api , txn , self .name ,
467562 val )
468- setattr (lrouter_port , col , val )
563+ self . set_column (lrouter_port , col , val )
469564 _addvalue_to_list (lrouter , 'ports' , lrouter_port )
565+ self .result = lrouter_port .uuid
470566
471567
472568class UpdateLRouterPortCommand (command .BaseCommand ):
@@ -491,7 +587,7 @@ def run_idl(self, txn):
491587 if col == 'gateway_chassis' :
492588 col , val = _add_gateway_chassis (self .api , txn , self .name ,
493589 val )
494- setattr (lrouter_port , col , val )
590+ self . set_column (lrouter_port , col , val )
495591
496592
497593class DelLRouterPortCommand (command .BaseCommand ):
@@ -1008,15 +1104,17 @@ def run_idl(self, txn):
10081104 # Remove the router pinning to a chassis (if any).
10091105 lrouter .delkey ('options' , 'chassis' )
10101106
1011- # Remove the HA_Chassis_Group of the router (if any).
1107+ for gw_port in self .api .get_lrouter_gw_ports (lrouter .name ):
1108+ gw_port .ha_chassis_group = []
1109+ lrouter .delvalue ('ports' , gw_port )
1110+
1111+ # Remove the HA_Chassis_Group of the router (if any), after
1112+ # removing it from the gateway Logical_Router_Ports.
10121113 hcg = self .api .lookup ('HA_Chassis_Group' ,
10131114 lrouter .name , default = None )
10141115 if hcg :
10151116 hcg .delete ()
10161117
1017- for gw_port in self .api .get_lrouter_gw_ports (lrouter .name ):
1018- lrouter .delvalue ('ports' , gw_port )
1019-
10201118
10211119class SetLSwitchPortToVirtualTypeCommand (command .BaseCommand ):
10221120 def __init__ (self , api , lport , vip , parent , if_exists ):
@@ -1089,3 +1187,22 @@ def run_idl(self, txn):
10891187 virtual_parents )
10901188
10911189 setattr (lsp , 'options' , options )
1190+
1191+
1192+ class HAChassisGroupWithHCAddCommand (command .AddCommand ):
1193+ table_name = 'HA_Chassis_Group'
1194+
1195+ def __init__ (self , api , name , chassis_priority , may_exist = False ,
1196+ ** columns ):
1197+ super ().__init__ (api )
1198+ self .name = name
1199+ self .chassis_priority = copy .deepcopy (chassis_priority )
1200+ self .may_exist = may_exist
1201+ self .columns = columns
1202+
1203+ def run_idl (self , txn ):
1204+ # HA_Chassis_Group register creation.
1205+ self .result = _sync_ha_chassis_group (
1206+ txn , self .api , self .name , self .chassis_priority ,
1207+ may_exist = self .may_exist , table_name = self .table_name ,
1208+ ** self .columns )
0 commit comments