Skip to content

Commit ab524c1

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Add sync floating IP support"
2 parents 6834289 + c16e20e commit ab524c1

File tree

5 files changed

+549
-61
lines changed

5 files changed

+549
-61
lines changed

ovn_octavia_provider/common/constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,9 @@
8888

8989
# Request information constants
9090
REQ_INFO_ACTION_ASSOCIATE = 'associate'
91+
REQ_INFO_ACTION_SYNC = 'sync'
9192
REQ_INFO_ACTION_DISASSOCIATE = 'disassociate'
93+
9294
REQ_INFO_MEMBER_ADDED = 'member_added'
9395
REQ_INFO_MEMBER_DELETED = 'member_deleted'
9496

ovn_octavia_provider/driver.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,59 @@ def _ensure_loadbalancer(self, loadbalancer):
798798
ovn_lb)
799799
self._ovn_helper._update_status_to_octavia(status)
800800

801+
def _fip_sync(self, loadbalancer):
802+
LOG.info("Starting sync floating IP for loadbalancer "
803+
f"{loadbalancer.loadbalancer_id}")
804+
if not loadbalancer.vip_port_id or not loadbalancer.vip_network_id:
805+
LOG.debug("VIP Port or Network not set for loadbalancer "
806+
f"{loadbalancer.loadbalancer_id}, skip FIP sync.")
807+
return
808+
809+
# Try to get FIP from neutron
810+
fips = self._ovn_helper.get_fip_from_vip(loadbalancer)
811+
812+
# get FIP from LSP
813+
vip_lsp = self._ovn_helper.get_lsp(
814+
port_id=loadbalancer.vip_port_id,
815+
network_id=loadbalancer.vip_network_id)
816+
lsp_fip = vip_lsp.external_ids.get(
817+
ovn_const.OVN_PORT_FIP_EXT_ID_KEY) if vip_lsp else None
818+
819+
if fips:
820+
neutron_fip = fips[0].floating_ip_address
821+
if not vip_lsp:
822+
LOG.warn(
823+
"Logic Switch Port not found for port "
824+
f"{loadbalancer.vip_port_id}. "
825+
"Skip sync FIP for loadbalancer "
826+
f"{loadbalancer.loadbalancer_id}. Please "
827+
"run command `neutron-ovn-db-sync-util` "
828+
"first to sync OVN DB with Neutron DB.")
829+
return
830+
if lsp_fip != neutron_fip:
831+
LOG.warn(
832+
"Floating IP not consistent between Logic Switch "
833+
f"Port and Neutron. Found FIP {lsp_fip} "
834+
f"in LSP {vip_lsp.name}, but we have {neutron_fip} from "
835+
"Neutron. Skip sync FIP for "
836+
f"loadbalancer {loadbalancer.loadbalancer_id}. "
837+
"Please run command `neutron-ovn-db-sync-util` "
838+
"first to sync OVN DB with Neutron DB.")
839+
return
840+
self._ovn_helper.vip_port_update_handler(
841+
vip_lp=vip_lsp, fip=lsp_fip,
842+
action=ovn_const.REQ_INFO_ACTION_SYNC)
843+
else:
844+
LOG.warn("Floating IP not found for loadbalancer "
845+
f"{loadbalancer.loadbalancer_id}")
846+
if lsp_fip:
847+
LOG.warn(
848+
"Floating IP not consistent between Logic Switch "
849+
f"Port and Neutron. Found FIP {lsp_fip} configured "
850+
f"in LSP {vip_lsp.name}, but no FIP configured from "
851+
"Neutron. Please run command `neutron-ovn-db-sync-util` "
852+
"first to sync OVN DB with Neutron DB.")
853+
801854
def do_sync(self, **lb_filters):
802855
LOG.info(f"Starting sync OVN DB with Loadbalancer filter {lb_filters}")
803856
octavia_client = clients.get_octavia_client()
@@ -841,3 +894,4 @@ def do_sync(self, **lb_filters):
841894
provider_pools if provider_pools else o_datamodels.Unset
842895
)
843896
self._ensure_loadbalancer(provider_lb)
897+
self._fip_sync(provider_lb)

ovn_octavia_provider/helper.py

Lines changed: 97 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -355,8 +355,11 @@ def vip_port_update_handler(self, vip_lp, fip, action):
355355
if port:
356356
request_info['vip_related'] = [
357357
ip['ip_address'] for ip in port.fixed_ips]
358-
self.add_request({'type': ovn_const.REQ_TYPE_HANDLE_VIP_FIP,
359-
'info': request_info})
358+
if action != ovn_const.REQ_INFO_ACTION_SYNC:
359+
self.add_request({'type': ovn_const.REQ_TYPE_HANDLE_VIP_FIP,
360+
'info': request_info})
361+
else:
362+
self.handle_vip_fip(request_info)
360363

361364
def _find_lb_in_ls(self, network):
362365
"""Find LB associated to a Network using Network information
@@ -2966,8 +2969,13 @@ def handle_vip_fip(self, fip_info):
29662969
additional_vip_fip = fip_info.get('additional_vip_fip', False)
29672970
external_ids = copy.deepcopy(ovn_lb.external_ids)
29682971
commands = []
2972+
need_ext_set = True
2973+
need_hc_set = True
29692974

2970-
if fip_info['action'] == ovn_const.REQ_INFO_ACTION_ASSOCIATE:
2975+
if fip_info['action'] in (
2976+
ovn_const.REQ_INFO_ACTION_ASSOCIATE,
2977+
ovn_const.REQ_INFO_ACTION_SYNC
2978+
):
29712979
if additional_vip_fip:
29722980
existing_addi_vip_fip = external_ids.get(
29732981
ovn_const.LB_EXT_IDS_ADDIT_VIP_FIP_KEY, [])
@@ -2984,31 +2992,51 @@ def handle_vip_fip(self, fip_info):
29842992
fip_info['vip_fip'])
29852993
vip_fip_info = {
29862994
ovn_const.LB_EXT_IDS_VIP_FIP_KEY: fip_info['vip_fip']}
2987-
commands.append(
2988-
self.ovn_nbdb_api.db_set('Load_Balancer', ovn_lb.uuid,
2989-
('external_ids', vip_fip_info)))
2990-
for lb_hc in ovn_lb.health_check:
2991-
if self._get_vip_lbhc(lb_hc) in fip_info['vip_related']:
2992-
vip = fip_info['vip_fip']
2993-
lb_hc_external_ids = copy.deepcopy(lb_hc.external_ids)
2994-
lb_hc_external_ids[ovn_const.LB_EXT_IDS_HM_VIP] = vip
2995-
if self._check_lbhc_vip_format(lb_hc.vip):
2996-
port = lb_hc.vip.rsplit(':')[-1]
2997-
vip += ':' + port
2998-
else:
2999-
vip = ''
3000-
kwargs = {
3001-
'vip': vip,
3002-
'options': lb_hc.options,
3003-
'external_ids': lb_hc_external_ids}
3004-
with self.ovn_nbdb_api.transaction(
3005-
check_error=True) as txn:
3006-
fip_lbhc = txn.add(self.ovn_nbdb_api.db_create(
3007-
'Load_Balancer_Health_Check', **kwargs))
3008-
txn.add(self.ovn_nbdb_api.db_add(
3009-
'Load_Balancer', ovn_lb.uuid,
3010-
'health_check', fip_lbhc))
2995+
if fip_info['action'] == ovn_const.REQ_INFO_ACTION_SYNC:
2996+
# Don't need to trigger OVN DB set if external_ids not changed
2997+
need_ext_set = not all(
2998+
ovn_lb.external_ids.get(k) ==
2999+
v for k, v in vip_fip_info.items()
3000+
)
3001+
# For sync scenario, check if FIP VIP already in health_check
3002+
for lb_hc in ovn_lb.health_check:
3003+
# All lbhc in health_check are already checked
3004+
# at this stage of sync workflow in hm_purge.
3005+
# So we should be able to just check health_check.
3006+
if self._get_vip_lbhc(lb_hc) == fip_info['vip_fip']:
3007+
need_hc_set = False
3008+
break
3009+
3010+
if need_ext_set:
3011+
commands.append(
3012+
self.ovn_nbdb_api.db_set(
3013+
'Load_Balancer', ovn_lb.uuid, (
3014+
'external_ids', vip_fip_info)))
3015+
3016+
if need_hc_set:
3017+
for lb_hc in ovn_lb.health_check:
3018+
if self._get_vip_lbhc(lb_hc) in fip_info['vip_related']:
3019+
vip = fip_info['vip_fip']
3020+
lb_hc_external_ids = copy.deepcopy(lb_hc.external_ids)
3021+
lb_hc_external_ids[ovn_const.LB_EXT_IDS_HM_VIP] = vip
3022+
if self._check_lbhc_vip_format(lb_hc.vip):
3023+
port = lb_hc.vip.rsplit(':')[-1]
3024+
vip += ':' + port
3025+
else:
3026+
vip = ''
3027+
kwargs = {
3028+
'vip': vip,
3029+
'options': lb_hc.options,
3030+
'external_ids': lb_hc_external_ids}
3031+
with self.ovn_nbdb_api.transaction(
3032+
check_error=True) as txn:
3033+
fip_lbhc = txn.add(self.ovn_nbdb_api.db_create(
3034+
'Load_Balancer_Health_Check', **kwargs))
3035+
txn.add(self.ovn_nbdb_api.db_add(
3036+
'Load_Balancer', ovn_lb.uuid,
3037+
'health_check', fip_lbhc))
30113038
else:
3039+
# For disassociate case
30123040
existing_addi_vip_fip_need_updated = False
30133041
existing_addi_vip_fip = external_ids.get(
30143042
ovn_const.LB_EXT_IDS_ADDIT_VIP_FIP_KEY, [])
@@ -3052,8 +3080,14 @@ def handle_vip_fip(self, fip_info):
30523080
commands.append(self.ovn_nbdb_api.db_destroy(
30533081
'Load_Balancer_Health_Check', lb_hc.uuid))
30543082
break
3055-
3056-
commands.extend(self._refresh_lb_vips(ovn_lb, external_ids))
3083+
commands.extend(
3084+
self._refresh_lb_vips(
3085+
ovn_lb,
3086+
external_ids,
3087+
is_sync=(
3088+
fip_info['action'] == ovn_const.REQ_INFO_ACTION_SYNC)
3089+
)
3090+
)
30573091
self._execute_commands(commands)
30583092

30593093
def handle_member_dvr(self, info):
@@ -3140,6 +3174,18 @@ def handle_member_dvr(self, info):
31403174
{'member': info['id'],
31413175
'fip': fip.external_ip})
31423176

3177+
def get_lsp(self, port_id, network_id):
3178+
ls_name = utils.ovn_name(network_id)
3179+
try:
3180+
ls = self.ovn_nbdb_api.lookup('Logical_Switch', ls_name)
3181+
except idlutils.RowNotFound:
3182+
LOG.warn(f"Logical Switch {ls_name} not found.")
3183+
return
3184+
for port in ls.ports:
3185+
if port_id in port.name:
3186+
# We found particular port
3187+
return port
3188+
31433189
def _get_member_lsp(self, member_ip, member_subnet_id):
31443190
neutron_client = clients.get_neutron_client()
31453191
try:
@@ -3160,6 +3206,15 @@ def _get_member_lsp(self, member_ip, member_subnet_id):
31603206
# We found particular port
31613207
return port
31623208

3209+
def get_fip_from_vip(self, lb):
3210+
neutron_client = clients.get_neutron_client()
3211+
try:
3212+
return list(neutron_client.ips(port_id=lb.vip_port_id))
3213+
except openstack.exceptions.HttpException as e:
3214+
LOG.warn("Error on fetch fip for "
3215+
f"{lb.loadbalancer_id} "
3216+
f"Error: {str(e)}")
3217+
31633218
def _add_lbhc(self, ovn_lb, pool_key, info):
31643219
hm_id = info[constants.ID]
31653220
status = {constants.ID: hm_id,
@@ -3586,7 +3641,7 @@ def _lookup_lbhcs_by_hm_id(self, hm_id):
35863641
raise idlutils.RowNotFound(table='Load_Balancer_Health_Check',
35873642
col='external_ids', match=hm_id)
35883643

3589-
def _find_ovn_lb_from_hm_id(self, hm_id):
3644+
def _find_ovn_lb_from_hm_id(self, hm_id, lbhc_vip=None):
35903645
lbs = self.ovn_nbdb_api.db_list_rows(
35913646
'Load_Balancer').execute(check_error=True)
35923647
ovn_lb = None
@@ -3597,7 +3652,14 @@ def _find_ovn_lb_from_hm_id(self, hm_id):
35973652
break
35983653

35993654
try:
3600-
lbhcs = self._lookup_lbhcs_by_hm_id(hm_id)
3655+
lbhcs_by_hm_id = self._lookup_lbhcs_by_hm_id(hm_id)
3656+
if lbhc_vip:
3657+
lbhcs = []
3658+
for lbhc in lbhcs_by_hm_id:
3659+
if lbhc.vip == lbhc_vip:
3660+
lbhcs.append(lbhc)
3661+
else:
3662+
lbhcs = lbhcs_by_hm_id
36013663
except idlutils.RowNotFound:
36023664
LOG.debug("Loadbalancer health check %s not found!", hm_id)
36033665
return [], ovn_lb
@@ -4112,17 +4174,17 @@ def hm_purge(self, lb_id):
41124174
continue
41134175
fetch_hc_ids.extend([str(lbhc.uuid) for lbhc in lbhcs])
41144176

4115-
for hc_id in ovn_lb.health_check:
4116-
if str(hc_id.uuid) not in fetch_hc_ids:
4177+
for lbhc in ovn_lb.health_check:
4178+
if str(lbhc.uuid) not in fetch_hc_ids:
41174179
commands = []
41184180
commands.append(
41194181
self.ovn_nbdb_api.db_remove(
41204182
'Load_Balancer', ovn_lb.uuid,
4121-
'health_check', hc_id.uuid))
4183+
'health_check', lbhc.uuid))
41224184
commands.append(
41234185
self.ovn_nbdb_api.db_destroy(
41244186
'Load_Balancer_Health_Check',
4125-
hc_id.uuid))
4187+
lbhc.uuid))
41264188
try:
41274189
self._execute_commands(commands)
41284190
except idlutils.RowNotFound:

0 commit comments

Comments
 (0)