Skip to content

Commit e9fa962

Browse files
authored
Merge pull request #82 from stackhpc/upstream/master-2025-11-24
Synchronise master with upstream
2 parents f100aec + 65a4e82 commit e9fa962

File tree

5 files changed

+531
-409
lines changed

5 files changed

+531
-409
lines changed

ovn_octavia_provider/driver.py

Lines changed: 138 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -203,10 +203,13 @@ def loadbalancer_create(self, loadbalancer):
203203
if not isinstance(loadbalancer.pools, o_datamodels.UnsetType):
204204
for pool in loadbalancer.pools:
205205
self.pool_create(pool)
206-
for member in pool.members:
207-
if not member.subnet_id:
208-
member.subnet_id = loadbalancer.vip_subnet_id
209-
self.member_create(member)
206+
members = [
207+
member if member.subnet_id else setattr(
208+
member, "subnet_id", loadbalancer.vip_subnet_id) or
209+
member
210+
for member in pool.members
211+
]
212+
self._members_create(members)
210213

211214
def loadbalancer_delete(self, loadbalancer, cascade=False):
212215
request_info = {'id': loadbalancer.loadbalancer_id,
@@ -259,8 +262,8 @@ def pool_delete(self, pool):
259262
if pool.healthmonitor:
260263
self.health_monitor_delete(pool.healthmonitor)
261264

262-
for member in pool.members:
263-
self.member_delete(member)
265+
if pool.members:
266+
self._members_delete(pool.members)
264267

265268
request_info = {'id': pool.pool_id,
266269
'protocol': pool.protocol,
@@ -373,88 +376,108 @@ def _ip_version_differs(self, member):
373376
return vip_version != (netaddr.IPNetwork(member.address).version)
374377

375378
def member_create(self, member):
376-
# Validate monitoring options if present
377-
self._check_member_monitor_options(member)
378-
if self._ip_version_differs(member):
379-
raise ovn_exc.IPVersionsMixingNotSupportedError()
380-
admin_state_up = member.admin_state_up
381-
subnet_id = member.subnet_id
382-
if (isinstance(subnet_id, o_datamodels.UnsetType) or not subnet_id):
383-
subnet_id, subnet_cidr = self._ovn_helper._get_subnet_from_pool(
384-
member.pool_id)
385-
if not (subnet_id and
386-
self._ovn_helper._check_ip_in_subnet(member.address,
387-
subnet_cidr)):
388-
msg = _('Subnet is required, or Loadbalancer associated with '
389-
'Pool must have a subnet, for Member creation '
390-
'with OVN Provider Driver if it is not the same as '
391-
'LB VIP subnet')
392-
raise driver_exceptions.UnsupportedOptionError(
393-
user_fault_string=msg,
394-
operator_fault_string=msg)
379+
self._members_create([member])
380+
381+
def _members_create(self, members):
382+
request_info = []
383+
request_info_dvr = []
384+
for member in members:
385+
# Validate monitoring options if present
386+
self._check_member_monitor_options(member)
387+
if self._ip_version_differs(member):
388+
raise ovn_exc.IPVersionsMixingNotSupportedError()
389+
admin_state_up = member.admin_state_up
390+
subnt_id = member.subnet_id
391+
if (isinstance(subnt_id, o_datamodels.UnsetType) or
392+
not subnt_id):
393+
subnt_id, subnt_cidr = self._ovn_helper._get_subnet_from_pool(
394+
member.pool_id)
395+
396+
if not (subnt_id and
397+
self._ovn_helper._check_ip_in_subnet(member.address,
398+
subnt_cidr)):
399+
msg = _('Subnet is required, or Loadbalancer associated '
400+
'with Pool must have a subnet, for Member '
401+
'creation with OVN Provider Driver if it is not '
402+
'the same as LB VIP subnet')
403+
raise driver_exceptions.UnsupportedOptionError(
404+
user_fault_string=msg,
405+
operator_fault_string=msg)
406+
407+
if isinstance(admin_state_up, o_datamodels.UnsetType):
408+
admin_state_up = True
409+
request_info.append({'id': member.member_id,
410+
'address': member.address,
411+
'protocol_port': member.protocol_port,
412+
'pool_id': member.pool_id,
413+
'subnet_id': subnt_id,
414+
'admin_state_up': admin_state_up})
415+
416+
# NOTE(mjozefcz): If LB has FIP on VIP
417+
# and member has FIP we need to centralize
418+
# traffic for member.
419+
request_info_dvr.append({'id': member.member_id,
420+
'address': member.address,
421+
'pool_id': member.pool_id,
422+
'subnet_id': subnt_id,
423+
'action': ovn_const.REQ_INFO_MEMBER_ADDED}
424+
)
395425

396-
if isinstance(admin_state_up, o_datamodels.UnsetType):
397-
admin_state_up = True
398-
request_info = {'id': member.member_id,
399-
'address': member.address,
400-
'protocol_port': member.protocol_port,
401-
'pool_id': member.pool_id,
402-
'subnet_id': subnet_id,
403-
'admin_state_up': admin_state_up}
404426
request = {'type': ovn_const.REQ_TYPE_MEMBER_CREATE,
405427
'info': request_info}
406428
self._ovn_helper.add_request(request)
407429

408-
# NOTE(mjozefcz): If LB has FIP on VIP
409-
# and member has FIP we need to centralize
410-
# traffic for member.
411-
request_info = {'id': member.member_id,
412-
'address': member.address,
413-
'pool_id': member.pool_id,
414-
'subnet_id': subnet_id,
415-
'action': ovn_const.REQ_INFO_MEMBER_ADDED}
416430
request = {'type': ovn_const.REQ_TYPE_HANDLE_MEMBER_DVR,
417-
'info': request_info}
431+
'info': request_info_dvr}
418432
self._ovn_helper.add_request(request)
419433

420434
def member_delete(self, member):
435+
self._members_delete([member])
436+
437+
def _members_delete(self, members):
421438
# NOTE(froyo): OVN provider allow to create member without param
422439
# subnet_id, in that case the driver search it according to the
423440
# pool_id, but it is not propagated to Octavia. In this case, if
424441
# the member is deleted, Octavia send the object without subnet_id.
425-
subnet_id = member.subnet_id
426-
if (isinstance(subnet_id, o_datamodels.UnsetType) or not subnet_id):
427-
subnet_id, subnet_cidr = self._ovn_helper._get_subnet_from_pool(
428-
member.pool_id)
429-
if not (subnet_id and
430-
self._ovn_helper._check_ip_in_subnet(member.address,
431-
subnet_cidr)):
432-
msg = _('Subnet is required, or Loadbalancer associated with '
433-
'Pool must have a subnet, for Member deletion if it is'
434-
'with OVN Provider Driver if it is not the same as '
435-
'LB VIP subnet')
436-
raise driver_exceptions.UnsupportedOptionError(
437-
user_fault_string=msg,
438-
operator_fault_string=msg)
442+
request_info = []
443+
request_info_dvr = []
444+
for member in members:
445+
subnt_id = member.subnet_id
446+
if (isinstance(subnt_id, o_datamodels.UnsetType) or not subnt_id):
447+
subnt_id, subnt_cidr = self._ovn_helper._get_subnet_from_pool(
448+
member.pool_id)
449+
if not (subnt_id and
450+
self._ovn_helper._check_ip_in_subnet(member.address,
451+
subnt_cidr)):
452+
msg = _('Subnet is required, or Loadbalancer associated '
453+
'with Pool must have a subnet, for Member '
454+
'deletion if it is with OVN Provider Driver if it '
455+
'is not the same as LB VIP subnet')
456+
raise driver_exceptions.UnsupportedOptionError(
457+
user_fault_string=msg,
458+
operator_fault_string=msg)
459+
460+
request_info.append({'id': member.member_id,
461+
'address': member.address,
462+
'protocol_port': member.protocol_port,
463+
'pool_id': member.pool_id,
464+
'subnet_id': subnt_id})
465+
# NOTE(mjozefcz): If LB has FIP on VIP
466+
# and member had FIP we can decentralize
467+
# the traffic now.
468+
request_info_dvr.append(
469+
{'id': member.member_id,
470+
'address': member.address,
471+
'pool_id': member.pool_id,
472+
'subnet_id': subnt_id,
473+
'action': ovn_const.REQ_INFO_MEMBER_DELETED})
439474

440-
request_info = {'id': member.member_id,
441-
'address': member.address,
442-
'protocol_port': member.protocol_port,
443-
'pool_id': member.pool_id,
444-
'subnet_id': subnet_id}
445475
request = {'type': ovn_const.REQ_TYPE_MEMBER_DELETE,
446476
'info': request_info}
447477
self._ovn_helper.add_request(request)
448-
# NOTE(mjozefcz): If LB has FIP on VIP
449-
# and member had FIP we can decentralize
450-
# the traffic now.
451-
request_info = {'id': member.member_id,
452-
'address': member.address,
453-
'pool_id': member.pool_id,
454-
'subnet_id': subnet_id,
455-
'action': ovn_const.REQ_INFO_MEMBER_DELETED}
478+
456479
request = {'type': ovn_const.REQ_TYPE_HANDLE_MEMBER_DVR,
457-
'info': request_info}
480+
'info': request_info_dvr}
458481
self._ovn_helper.add_request(request)
459482

460483
def member_update(self, old_member, new_member):
@@ -470,7 +493,7 @@ def member_update(self, old_member, new_member):
470493
if not isinstance(new_member.admin_state_up, o_datamodels.UnsetType):
471494
request_info['admin_state_up'] = new_member.admin_state_up
472495
request = {'type': ovn_const.REQ_TYPE_MEMBER_UPDATE,
473-
'info': request_info}
496+
'info': [request_info]}
474497
self._ovn_helper.add_request(request)
475498

476499
def member_batch_update(self, pool_id, members):
@@ -482,6 +505,10 @@ def member_batch_update(self, pool_id, members):
482505
members_to_delete = copy.copy(existing_members)
483506
pool_subnet_id = None
484507
pool_subnet_cidr = None
508+
request_info_create = []
509+
request_info_update = []
510+
request_info_delete = []
511+
request_info_dvr_delete = []
485512
for member in members:
486513
# NOTE(froyo): in order to keep sync with Octavia DB, we raise
487514
# not supporting exceptions as soon as posible, considering the
@@ -520,49 +547,65 @@ def member_batch_update(self, pool_id, members):
520547
admin_state_up = True
521548

522549
member_info = self._ovn_helper._get_member_info(member)
550+
request_info = {
551+
'id': member.member_id,
552+
'address': member.address,
553+
'protocol_port': member.protocol_port,
554+
'pool_id': member.pool_id,
555+
'subnet_id': member.subnet_id,
556+
'admin_state_up': admin_state_up}
557+
523558
if member_info not in existing_members:
524-
req_type = ovn_const.REQ_TYPE_MEMBER_CREATE
559+
request_info_create.append(request_info)
525560
else:
526561
# If member exists in pool, then Update
527-
req_type = ovn_const.REQ_TYPE_MEMBER_UPDATE
562+
request_info_update.append(request_info)
528563
# Remove all updating members so only deleted ones are left
529564
members_to_delete.remove(member_info)
530565

531-
request_info = {'id': member.member_id,
532-
'address': member.address,
533-
'protocol_port': member.protocol_port,
534-
'pool_id': member.pool_id,
535-
'subnet_id': member.subnet_id,
536-
'admin_state_up': admin_state_up}
537-
request = {'type': req_type,
538-
'info': request_info}
539-
request_list.append(request)
540-
541566
for member in members_to_delete:
542567
member_info = member.split('_')
543568
member_ip, member_port, subnet_id, member_id = (
544569
self._ovn_helper._extract_member_info(member)[0])
545-
request_info = {'id': member_info[1],
546-
'address': member_ip,
547-
'protocol_port': member_port,
548-
'pool_id': pool_id}
570+
request_info = {
571+
'id': member_info[1],
572+
'address': member_ip,
573+
'protocol_port': member_port,
574+
'pool_id': pool_id}
549575
if len(member_info) == 4:
550576
request_info['subnet_id'] = subnet_id
551-
request = {'type': ovn_const.REQ_TYPE_MEMBER_DELETE,
552-
'info': request_info}
553-
request_list.append(request)
577+
request_info_delete.append(request_info)
554578

555579
# NOTE(mjozefcz): If LB has FIP on VIP
556580
# and member had FIP we can decentralize
557581
# the traffic now.
558-
request_info = {'id': member_id,
559-
'address': member_ip,
560-
'pool_id': pool_id,
561-
'action': ovn_const.REQ_INFO_MEMBER_DELETED}
582+
request_info = {
583+
'id': member_id,
584+
'address': member_ip,
585+
'pool_id': pool_id,
586+
'action': ovn_const.REQ_INFO_MEMBER_DELETED}
562587
if len(member_info) == 4:
563588
request_info['subnet_id'] = subnet_id
589+
request_info_dvr_delete.append(request_info)
590+
591+
if request_info_create:
592+
request = {'type': ovn_const.REQ_TYPE_MEMBER_CREATE,
593+
'info': request_info_create}
594+
request_list.append(request)
595+
596+
if request_info_update:
597+
request = {'type': ovn_const.REQ_TYPE_MEMBER_UPDATE,
598+
'info': request_info_update}
599+
request_list.append(request)
600+
601+
if request_info_delete:
602+
request = {'type': ovn_const.REQ_TYPE_MEMBER_DELETE,
603+
'info': request_info_delete}
604+
request_list.append(request)
605+
606+
if request_info_dvr_delete:
564607
request = {'type': ovn_const.REQ_TYPE_HANDLE_MEMBER_DVR,
565-
'info': request_info}
608+
'info': request_info_dvr_delete}
566609
request_list.append(request)
567610

568611
for request in request_list:

0 commit comments

Comments
 (0)