@@ -3269,6 +3269,184 @@ def _add_lbhc(self, ovn_lb, pool_key, info):
3269
3269
LOG .exception (ovn_const .EXCEPTION_MSG , "set of health check" )
3270
3270
return status
3271
3271
3272
+ def _sync_lbhc (self , ovn_lb , pool_key , hm ):
3273
+ hm_id = hm [constants .ID ]
3274
+ # Example
3275
+ # MONITOR_PRT = 80
3276
+ # ID=$(ovn-nbctl --bare --column _uuid find
3277
+ # Load_Balancer_Health_Check vip="${LB_VIP_ADDR}\:${MONITOR_PRT}")
3278
+ # In our case the monitor port will be the members protocol port
3279
+ vips = []
3280
+ if ovn_const .LB_EXT_IDS_VIP_KEY in ovn_lb .external_ids :
3281
+ vips .append (ovn_lb .external_ids .get (ovn_const .LB_EXT_IDS_VIP_KEY ))
3282
+ if ovn_const .LB_EXT_IDS_ADDIT_VIP_KEY in ovn_lb .external_ids :
3283
+ vips .extend (ovn_lb .external_ids .get (
3284
+ ovn_const .LB_EXT_IDS_ADDIT_VIP_KEY ).split (',' ))
3285
+ fips = []
3286
+ if ovn_const .LB_EXT_IDS_VIP_FIP_KEY in ovn_lb .external_ids :
3287
+ fips .append (ovn_lb .external_ids .get (
3288
+ ovn_const .LB_EXT_IDS_VIP_FIP_KEY ))
3289
+ if ovn_const .LB_EXT_IDS_ADDIT_VIP_FIP_KEY in ovn_lb .external_ids :
3290
+ fips .extend (ovn_lb .external_ids .get (
3291
+ ovn_const .LB_EXT_IDS_ADDIT_VIP_FIP_KEY ).split (',' ))
3292
+ if not vips :
3293
+ msg = (f"Could not find VIP for HM { hm_id } , LB external_ids: "
3294
+ f"{ ovn_lb .external_ids } " )
3295
+ raise driver_exceptions .DriverError (msg )
3296
+
3297
+ vip_port = self ._get_pool_listener_port (ovn_lb , pool_key )
3298
+
3299
+ # This is to enable lookups by Octavia DB ID value
3300
+ external_ids = {
3301
+ ovn_const .LB_EXT_IDS_HM_KEY : hm_id ,
3302
+ ovn_const .LB_EXT_IDS_HM_POOL_KEY : pool_key [
3303
+ len (ovn_const .LB_EXT_IDS_POOL_PREFIX ):],
3304
+ }
3305
+
3306
+ options = {
3307
+ 'interval' : str (hm ['interval' ]),
3308
+ 'timeout' : str (hm ['timeout' ]),
3309
+ 'success_count' : str (hm ['success_count' ]),
3310
+ 'failure_count' : str (hm ['failure_count' ])}
3311
+
3312
+ try :
3313
+ with self .ovn_nbdb_api .transaction (check_error = True ) as txn :
3314
+ for vip in vips :
3315
+ recreate = False
3316
+ # Just seems like this needs ovsdbapp support, see:
3317
+ # ovsdbapp/schema/ovn_northbound/impl_idl.py
3318
+ # - lb_add()
3319
+ # ovsdbapp/schema/ovn_northbound/commands.py
3320
+ # - LbAddCommand()
3321
+ # then this could just be self.ovn_nbdb_api.lb_hm_add()
3322
+ external_ids_vip = copy .deepcopy (external_ids )
3323
+ external_ids_vip [ovn_const .LB_EXT_IDS_HM_VIP ] = vip
3324
+ if netaddr .IPNetwork (vip ).version == n_const .IP_VERSION_6 :
3325
+ vip = f'[{ vip } ]'
3326
+ kwargs = {
3327
+ 'vip' : vip + ':' + str (vip_port ) if vip_port else '' ,
3328
+ 'options' : options ,
3329
+ 'external_ids' : external_ids_vip }
3330
+
3331
+ hms_key = ovn_lb .external_ids .get (
3332
+ ovn_const .LB_EXT_IDS_HMS_KEY , [])
3333
+ if hms_key :
3334
+ hms_key = jsonutils .loads (hms_key )
3335
+ lbhcs , _ = self ._find_ovn_lb_from_hm_id (hm_id )
3336
+ if not lbhcs :
3337
+ recreate = True
3338
+ for lbhc in lbhcs :
3339
+ commands = []
3340
+ if lbhc .vip != kwargs .get ('vip' ):
3341
+ commands .append (
3342
+ self .ovn_nbdb_api .db_set (
3343
+ 'Load_Balancer_Health_Check' ,
3344
+ lbhc .uuid ,
3345
+ ('vip' , kwargs .get ('vip' ))))
3346
+ if lbhc .options != options :
3347
+ commands .append (
3348
+ self .ovn_nbdb_api .db_set (
3349
+ 'Load_Balancer_Health_Check' ,
3350
+ lbhc .uuid ,
3351
+ ('options' , options )))
3352
+ if lbhc .external_ids != external_ids_vip :
3353
+ commands .append (
3354
+ self .ovn_nbdb_api .db_set (
3355
+ 'Load_Balancer_Health_Check' ,
3356
+ lbhc .uuid ,
3357
+ ('external_ids' , external_ids_vip )))
3358
+
3359
+ found_in_exist = False
3360
+ for hc in ovn_lb .health_check :
3361
+ if str (hc .uuid ) == str (lbhc .uuid ):
3362
+ found_in_exist = True
3363
+ break
3364
+ if not found_in_exist :
3365
+ commands .append (
3366
+ self .ovn_nbdb_api .db_add (
3367
+ 'Load_Balancer' , ovn_lb .uuid ,
3368
+ ('health_check' , lbhc .uuid )))
3369
+ if hm_id not in hms_key :
3370
+ hms_key .append (hm_id )
3371
+ commands .append (self .ovn_nbdb_api .db_set (
3372
+ 'Load_Balancer' , ovn_lb .uuid ,
3373
+ ('external_ids' ,
3374
+ {ovn_const .LB_EXT_IDS_HMS_KEY :
3375
+ jsonutils .dumps (hms_key )})))
3376
+ self ._execute_commands (commands )
3377
+ if recreate :
3378
+ health_check = txn .add (
3379
+ self .ovn_nbdb_api .db_create (
3380
+ 'Load_Balancer_Health_Check' ,
3381
+ ** kwargs ))
3382
+ txn .add (self .ovn_nbdb_api .db_set (
3383
+ 'Load_Balancer_Health_Check' ,
3384
+ health_check ,
3385
+ ('vip' , kwargs .get ('vip' ))))
3386
+ txn .add (self .ovn_nbdb_api .db_add (
3387
+ 'Load_Balancer' , ovn_lb .uuid ,
3388
+ 'health_check' , health_check ))
3389
+ if hm_id not in hms_key :
3390
+ hms_key .append (hm_id )
3391
+ txn .add (self .ovn_nbdb_api .db_set (
3392
+ 'Load_Balancer' , ovn_lb .uuid ,
3393
+ ('external_ids' , {ovn_const .LB_EXT_IDS_HMS_KEY :
3394
+ jsonutils .dumps (hms_key )})))
3395
+ if fips :
3396
+ external_ids_fip = copy .deepcopy (external_ids )
3397
+ for fip in fips :
3398
+ recreate = False
3399
+ external_ids_fip [ovn_const .LB_EXT_IDS_HM_VIP ] = fip
3400
+ if netaddr .IPNetwork (
3401
+ fip ).version == n_const .IP_VERSION_6 :
3402
+ fip = f'[{ fip } ]'
3403
+ fip_kwargs = {
3404
+ 'vip' : fip + ':' + str (vip_port )
3405
+ if vip_port
3406
+ else '' ,
3407
+ 'options' : options ,
3408
+ 'external_ids' : external_ids_fip }
3409
+
3410
+ lbhcs , _ = self ._find_ovn_lb_from_hm_id (hm_id )
3411
+ if not lbhcs :
3412
+ recreate = True
3413
+ for lbhc in lbhcs :
3414
+ commands = []
3415
+ if lbhc .vip != fip_kwargs ['vip' ]:
3416
+ commands .append (
3417
+ self .ovn_nbdb_api .db_set (
3418
+ 'Load_Balancer_Health_Check' ,
3419
+ lbhc .uuid ,
3420
+ ('vip' , fip_kwargs ['vip' ])))
3421
+ if lbhc .options != options :
3422
+ commands .append (
3423
+ self .ovn_nbdb_api .db_set (
3424
+ 'Load_Balancer_Health_Check' ,
3425
+ lbhc .uuid ,
3426
+ ('options' , options )))
3427
+ if lbhc .external_ids != external_ids_vip :
3428
+ commands .append (
3429
+ self .ovn_nbdb_api .db_set (
3430
+ 'Load_Balancer_Health_Check' ,
3431
+ lbhc .uuid ,
3432
+ ('external_ids' , external_ids_fip )))
3433
+ self ._execute_commands (commands )
3434
+ if recreate :
3435
+ fip_health_check = txn .add (
3436
+ self .ovn_nbdb_api .db_create (
3437
+ 'Load_Balancer_Health_Check' ,
3438
+ ** fip_kwargs ))
3439
+ txn .add (self .ovn_nbdb_api .db_set (
3440
+ 'Load_Balancer_Health_Check' ,
3441
+ fip_health_check ,
3442
+ ('vip' , fip_kwargs ['vip' ])))
3443
+ txn .add (self .ovn_nbdb_api .db_add (
3444
+ 'Load_Balancer' , ovn_lb .uuid ,
3445
+ 'health_check' , fip_health_check ))
3446
+ except Exception as e :
3447
+ msg = (f"Error syncing Load Balancer Health Check: { e } " )
3448
+ raise driver_exceptions .DriverError (msg )
3449
+
3272
3450
def _update_lbhc_vip_port (self , lbhc , vip_port ):
3273
3451
if lbhc .vip :
3274
3452
vip = lbhc .vip .rsplit (":" )[0 ] + ':' + str (vip_port )
@@ -3495,6 +3673,46 @@ def hm_create(self, info):
3495
3673
status [constants .HEALTHMONITORS ] = [hm_status ]
3496
3674
return status
3497
3675
3676
+ def hm_sync (self , hm , ovn_lb , pool_key ):
3677
+ """Sync Health Monitor object with an OVN LoadBalancer
3678
+
3679
+ The method performs the following steps:
3680
+ 1. Create Health Monitor in OVN NB in case we don't find
3681
+ load_balancer_health_checks entries associated
3682
+ 2. If we found load_balancer_health_checks entries associated
3683
+ 2.1. Update member status affected on OVN loadbalancer external_ids
3684
+ 2.2. Sync OVN load_balancer_health_checks entries
3685
+ 2.3. Update OVN Loadbalancer ip_port_mappings
3686
+ 2.4. Update OVN Loadbalancer member_status info on external_ids
3687
+
3688
+ :param hm: The source health monitor object from Octavia DB
3689
+ :param ovn_lb: The OVN LoadBalancer object that needs to be sync
3690
+ :param pool_key: The pool_key where health monitor is associated
3691
+ """
3692
+ lbhcs , ovn_lb = self ._find_ovn_lb_from_hm_id (hm [constants .ID ])
3693
+ if not lbhcs :
3694
+ LOG .debug ("Loadbalancer health check %s not found!" ,
3695
+ hm [constants .ID ])
3696
+ # Create in case we don't found it
3697
+ self .hm_create (hm )
3698
+ return
3699
+
3700
+ pool_id = hm [constants .POOL_ID ]
3701
+ self ._update_member_statuses (ovn_lb , pool_id , constants .ACTIVE ,
3702
+ constants .ONLINE )
3703
+ try :
3704
+ self ._sync_lbhc (ovn_lb , pool_key , hm )
3705
+ except Exception as e :
3706
+ LOG .exception (f"Failed syncing Load Balancer Health Monitor: { e } " )
3707
+
3708
+ for mb_ip , mb_port , mb_subnet , mb_id in self ._extract_member_info (
3709
+ ovn_lb .external_ids [pool_key ]):
3710
+ mb_status = self ._update_hm_member (ovn_lb , pool_key , mb_ip )
3711
+ if not mb_status :
3712
+ self ._clean_ip_port_mappings (ovn_lb , pool_key )
3713
+ break
3714
+ self ._update_external_ids_member_status (ovn_lb , mb_id , mb_status )
3715
+
3498
3716
def hm_update (self , info ):
3499
3717
status = {
3500
3718
constants .HEALTHMONITORS : [
@@ -3871,3 +4089,42 @@ def hm_update_event(self, info):
3871
4089
status [k ].extend (status_lb [k ])
3872
4090
3873
4091
return status
4092
+
4093
+ def hm_purge (self , lb_id ):
4094
+ # remove redundant hm if any, if no
4095
+ # ovn_const.LB_EXT_IDS_HMS_KEY from lb matches,
4096
+ # this hm has no used and should already got replaced.
4097
+ ovn_lbs = []
4098
+ try :
4099
+ ovn_lbs = self ._find_ovn_lbs_with_retry (lb_id )
4100
+ except idlutils .RowNotFound :
4101
+ LOG .debug (f"OVN loadbalancer { lb_id } not found." )
4102
+ fetch_hc_ids = []
4103
+ for ovn_lb in ovn_lbs :
4104
+ hm_ids = ovn_lb .external_ids .get (
4105
+ ovn_const .LB_EXT_IDS_HMS_KEY , [])
4106
+ if hm_ids :
4107
+ hm_ids = jsonutils .loads (hm_ids )
4108
+ for hm_id in hm_ids :
4109
+ lbhcs = []
4110
+ try :
4111
+ lbhcs = self ._lookup_lbhcs_by_hm_id (hm_id )
4112
+ except idlutils .RowNotFound :
4113
+ continue
4114
+ fetch_hc_ids .extend ([str (lbhc .uuid ) for lbhc in lbhcs ])
4115
+
4116
+ for hc_id in ovn_lb .health_check :
4117
+ if str (hc_id .uuid ) not in fetch_hc_ids :
4118
+ commands = []
4119
+ commands .append (
4120
+ self .ovn_nbdb_api .db_remove (
4121
+ 'Load_Balancer' , ovn_lb .uuid ,
4122
+ 'health_check' , hc_id .uuid ))
4123
+ commands .append (
4124
+ self .ovn_nbdb_api .db_destroy (
4125
+ 'Load_Balancer_Health_Check' ,
4126
+ hc_id .uuid ))
4127
+ try :
4128
+ self ._execute_commands (commands )
4129
+ except idlutils .RowNotFound :
4130
+ LOG .debug ("health check not found for purge." )
0 commit comments