Add support at NB BGP Driver for exposing OVN LBs
Change-Id: I4b1992d938e157a693c9db33882e5bc27ef8f604
This commit is contained in:
parent
aaa0ae0c1a
commit
bb663ad778
@ -140,7 +140,7 @@ The folloging events are watched and handled by the BGP watcher:
|
||||
|
||||
The BGP watcher detects OVN Southbound Database events at the ``Port_Binding``
|
||||
and ``Load_Balancer`` tables. It creates new event classes named
|
||||
``PortBindingChassisEvent`` and ``OVNLBMemberEvent``, that all the events
|
||||
``PortBindingChassisEvent`` and ``OVNLBEvent``, that all the events
|
||||
watched for BGP use as the base (inherit from).
|
||||
|
||||
The specific defined events to react to are:
|
||||
|
@ -79,7 +79,7 @@ networking accordingly.
|
||||
|
||||
The BGP watcher detects OVN Southbound Database events at the ``Port_Binding``
|
||||
and ``Load_Balancer`` tables. It creates new event classes named
|
||||
``PortBindingChassisEvent`` and ``OVNLBMemberEvent``, that all the events
|
||||
``PortBindingChassisEvent`` and ``OVNLBEvent``, that all the events
|
||||
watched for BGP use as the base (inherit from).
|
||||
|
||||
The driver react specifically to the following events:
|
||||
|
@ -33,6 +33,10 @@ OVN_DEVICE_OWNER_EXT_ID_KEY = 'neutron:device_owner'
|
||||
OVN_FIP_EXT_ID_KEY = 'neutron:port_fip'
|
||||
OVN_FIP_NET_EXT_ID_KEY = 'neutron:fip_network_id'
|
||||
LB_VIP_PORT_PREFIX = "ovn-lb-vip-"
|
||||
OVN_LB_VIP_IP_EXT_ID_KEY = 'neutron:vip'
|
||||
OVN_LB_VIP_FIP_EXT_ID_KEY = 'neutron:vip_fip'
|
||||
OVN_LB_VIP_PORT_EXT_ID_KEY = 'neutron:vip_port_id'
|
||||
OVN_LB_LR_REF_EXT_ID_KEY = 'lr_ref'
|
||||
|
||||
OVS_RULE_COOKIE = "999"
|
||||
OVS_VRF_RULE_COOKIE = "998"
|
||||
|
@ -36,7 +36,7 @@ LOG = logging.getLogger(__name__)
|
||||
# logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
OVN_TABLES = ['Logical_Switch_Port', 'NAT', 'Logical_Switch',
|
||||
'Logical_Router_Port']
|
||||
'Logical_Router_Port', 'Load_Balancer']
|
||||
LOCAL_CLUSTER_OVN_TABLES = ['Logical_Switch', 'Logical_Switch_Port',
|
||||
'Logical_Router', 'Logical_Router_Port',
|
||||
'Logical_Router_Policy',
|
||||
@ -146,7 +146,9 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
||||
"LogicalSwitchPortProviderDeleteEvent",
|
||||
"LogicalSwitchPortFIPCreateEvent",
|
||||
"LogicalSwitchPortFIPDeleteEvent",
|
||||
"LocalnetCreateDeleteEvent"])
|
||||
"LocalnetCreateDeleteEvent",
|
||||
"OVNLBCreateEvent",
|
||||
"OVNLBDeleteEvent"])
|
||||
if self._expose_tenant_networks:
|
||||
events.update(["ChassisRedirectCreateEvent",
|
||||
"ChassisRedirectDeleteEvent",
|
||||
@ -202,6 +204,9 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
||||
continue
|
||||
self._ensure_lsp_exposed(port)
|
||||
|
||||
# add missing routes/ips for OVN loadbalancers
|
||||
self._expose_lbs(self.ovn_local_cr_lrps.keys())
|
||||
|
||||
# remove extra wiring leftovers
|
||||
wire_utils.cleanup_wiring(self.nb_idl,
|
||||
self.ovn_bridge_mappings,
|
||||
@ -323,6 +328,22 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
||||
bridge_vlan = localnet.tag[0]
|
||||
return bridge_device, bridge_vlan
|
||||
|
||||
def _expose_lbs(self, router_list):
|
||||
lbs = self.nb_idl.get_active_local_lbs(router_list)
|
||||
for lb in lbs:
|
||||
self._expose_ovn_lb_vip(lb)
|
||||
# if vip-fip expose fip too
|
||||
if lb.external_ids.get(constants.OVN_LB_VIP_FIP_EXT_ID_KEY):
|
||||
self._expose_ovn_lb_fip(lb)
|
||||
|
||||
def _withdraw_lbs(self, router_list):
|
||||
lbs = self.nb_idl.get_active_local_lbs(router_list)
|
||||
for lb in lbs:
|
||||
self._withdraw_ovn_lb_vip(lb)
|
||||
# if vip-fip withdraw fip too
|
||||
if lb.external_ids.get(constants.OVN_LB_VIP_FIP_EXT_ID_KEY):
|
||||
self._withdraw_ovn_lb_fip(lb)
|
||||
|
||||
@lockutils.synchronized('nbbgp')
|
||||
def expose_ip(self, ips, ips_info):
|
||||
'''Advertice BGP route by adding IP to device.
|
||||
@ -339,20 +360,28 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
||||
logical_switch = ips_info.get('logical_switch')
|
||||
if not logical_switch:
|
||||
return False
|
||||
localnet, bridge_device, bridge_vlan = self._get_ls_localnet_info(
|
||||
logical_switch)
|
||||
if not bridge_device:
|
||||
# This means it is not a provider network
|
||||
self.ovn_tenant_ls[logical_switch] = True
|
||||
return False
|
||||
if bridge_device not in self.ovn_bridge_mappings.values():
|
||||
# This node is not properly configured, no need to expose it
|
||||
return False
|
||||
if not self.ovn_provider_ls.get(logical_switch):
|
||||
self.ovn_provider_ls[logical_switch] = {
|
||||
'bridge_device': bridge_device,
|
||||
'bridge_vlan': bridge_vlan,
|
||||
'localnet': localnet}
|
||||
|
||||
bridge_info = self.ovn_provider_ls.get(logical_switch)
|
||||
if bridge_info:
|
||||
# already known provider ls
|
||||
bridge_device = bridge_info['bridge_device']
|
||||
bridge_vlan = bridge_info['bridge_vlan']
|
||||
localnet = bridge_info['localnet']
|
||||
else:
|
||||
localnet, bridge_device, bridge_vlan = self._get_ls_localnet_info(
|
||||
logical_switch)
|
||||
if not bridge_device:
|
||||
# This means it is not a provider network
|
||||
self.ovn_tenant_ls[logical_switch] = True
|
||||
return False
|
||||
if bridge_device not in self.ovn_bridge_mappings.values():
|
||||
# This node is not properly configured, no need to expose it
|
||||
return False
|
||||
if not self.ovn_provider_ls.get(logical_switch):
|
||||
self.ovn_provider_ls[logical_switch] = {
|
||||
'bridge_device': bridge_device,
|
||||
'bridge_vlan': bridge_vlan,
|
||||
'localnet': localnet}
|
||||
mac = ips_info.get('mac')
|
||||
return self._expose_ip(ips, mac, logical_switch, bridge_device,
|
||||
bridge_vlan, port_type=ips_info['type'],
|
||||
@ -379,6 +408,7 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
||||
self.ovn_local_cr_lrps[router] = {
|
||||
'bridge_device': bridge_device,
|
||||
'bridge_vlan': bridge_vlan,
|
||||
'provider_switch': logical_switch,
|
||||
'ips': ips,
|
||||
}
|
||||
# Expose associated subnets
|
||||
@ -393,6 +423,9 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY),
|
||||
'address_scopes': driver_utils.get_addr_scopes(port)}
|
||||
self._expose_subnet(ips, subnet_info)
|
||||
|
||||
# add missing routes/ips for OVN loadbalancers
|
||||
self._expose_lbs([router])
|
||||
else:
|
||||
if not self._expose_provider_port(ips, mac, logical_switch,
|
||||
bridge_device, bridge_vlan,
|
||||
@ -452,6 +485,10 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY),
|
||||
'address_scopes': driver_utils.get_addr_scopes(port)}
|
||||
self._withdraw_subnet(ips, subnet_info)
|
||||
|
||||
# withdraw routes/ips for OVN loadbalancers
|
||||
self._withdraw_lbs([ips_info['router']])
|
||||
|
||||
try:
|
||||
del self.ovn_local_cr_lrps[ips_info['router']]
|
||||
except KeyError:
|
||||
@ -497,19 +534,26 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
||||
return self._expose_fip(ip, mac, logical_switch, row)
|
||||
|
||||
def _expose_fip(self, ip, mac, logical_switch, row):
|
||||
localnet, bridge_device, bridge_vlan = self._get_ls_localnet_info(
|
||||
logical_switch)
|
||||
if not bridge_device:
|
||||
# This means it is not a provider network
|
||||
return False
|
||||
if bridge_device not in self.ovn_bridge_mappings.values():
|
||||
# This node is not properly configured, no need to expose it
|
||||
return False
|
||||
if not self.ovn_provider_ls.get(logical_switch):
|
||||
self.ovn_provider_ls[logical_switch] = {
|
||||
'bridge_device': bridge_device,
|
||||
'bridge_vlan': bridge_vlan,
|
||||
'localnet': localnet}
|
||||
bridge_info = self.ovn_provider_ls.get(logical_switch)
|
||||
if bridge_info:
|
||||
# already known provider ls
|
||||
bridge_device = bridge_info['bridge_device']
|
||||
bridge_vlan = bridge_info['bridge_vlan']
|
||||
localnet = bridge_info['localnet']
|
||||
else:
|
||||
localnet, bridge_device, bridge_vlan = self._get_ls_localnet_info(
|
||||
logical_switch)
|
||||
if not bridge_device:
|
||||
# This means it is not a provider network
|
||||
return False
|
||||
if bridge_device not in self.ovn_bridge_mappings.values():
|
||||
# This node is not properly configured, no need to expose it
|
||||
return False
|
||||
if not self.ovn_provider_ls.get(logical_switch):
|
||||
self.ovn_provider_ls[logical_switch] = {
|
||||
'bridge_device': bridge_device,
|
||||
'bridge_vlan': bridge_vlan,
|
||||
'localnet': localnet}
|
||||
tenant_logical_switch = row.external_ids.get(
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY)
|
||||
if not tenant_logical_switch:
|
||||
@ -556,6 +600,10 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
||||
def expose_remote_ip(self, ips, ips_info):
|
||||
self._expose_remote_ip(ips, ips_info)
|
||||
|
||||
@lockutils.synchronized('nbbgp')
|
||||
def withdraw_remote_ip(self, ips, ips_info):
|
||||
self._withdraw_remote_ip(ips, ips_info)
|
||||
|
||||
def _expose_remote_ip(self, ips, ips_info):
|
||||
ips_to_expose = ips
|
||||
if not CONF.expose_tenant_networks:
|
||||
@ -574,10 +622,6 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
||||
LOG.debug("Added BGP route for tenant IP(s) %s on chassis %s",
|
||||
ips_to_expose, self.chassis)
|
||||
|
||||
@lockutils.synchronized('nbbgp')
|
||||
def withdraw_remote_ip(self, ips, ips_info):
|
||||
self._withdraw_remote_ip(ips, ips_info)
|
||||
|
||||
def _withdraw_remote_ip(self, ips, ips_info):
|
||||
ips_to_withdraw = ips
|
||||
if not CONF.expose_tenant_networks:
|
||||
@ -737,6 +781,95 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
||||
pass
|
||||
return True
|
||||
|
||||
@lockutils.synchronized('nbbgp')
|
||||
def expose_ovn_lb_vip(self, lb):
|
||||
self._expose_ovn_lb_vip(lb)
|
||||
|
||||
def _expose_ovn_lb_vip(self, lb):
|
||||
vip_port = lb.external_ids.get(constants.OVN_LB_VIP_PORT_EXT_ID_KEY)
|
||||
vip_ip = lb.external_ids.get(constants.OVN_LB_VIP_IP_EXT_ID_KEY)
|
||||
vip_router = lb.external_ids[
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY].replace('neutron-', "", 1)
|
||||
vip_lsp = self.nb_idl.lsp_get(vip_port).execute(check_error=True)
|
||||
if not vip_lsp:
|
||||
LOG.debug("Something went wrong, VIP port %s not found", vip_port)
|
||||
return
|
||||
vip_net = vip_lsp.external_ids.get(constants.OVN_LS_NAME_EXT_ID_KEY)
|
||||
if vip_net in self.ovn_local_lrps.keys():
|
||||
# It is a VIP on a tenant network
|
||||
# NOTE: the LB is exposed through the cr-lrp, so we add the
|
||||
# vip_router instead of the logical switch
|
||||
ips_info = {'logical_switch': vip_router}
|
||||
self._expose_remote_ip([vip_ip], ips_info)
|
||||
else:
|
||||
# It is a VIP on a provider network
|
||||
localnet, bridge_device, bridge_vlan = self._get_ls_localnet_info(
|
||||
vip_net)
|
||||
self._expose_provider_port([vip_ip], None, vip_net, bridge_device,
|
||||
bridge_vlan, localnet)
|
||||
|
||||
@lockutils.synchronized('nbbgp')
|
||||
def withdraw_ovn_lb_vip(self, lb):
|
||||
self._withdraw_ovn_lb_vip(lb)
|
||||
|
||||
def _withdraw_ovn_lb_vip(self, lb):
|
||||
vip_ip = lb.external_ids.get(constants.OVN_LB_VIP_IP_EXT_ID_KEY)
|
||||
vip_router = lb.external_ids[
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY].replace('neutron-', "", 1)
|
||||
|
||||
cr_lrp_info = self.ovn_local_cr_lrps.get(vip_router)
|
||||
if not cr_lrp_info:
|
||||
return
|
||||
provider_ls = cr_lrp_info['provider_switch']
|
||||
if self._exposed_ips.get(provider_ls, {}).get(vip_ip):
|
||||
# VIP is on provider network
|
||||
self._withdraw_provider_port([vip_ip],
|
||||
cr_lrp_info['provider_switch'],
|
||||
cr_lrp_info['bridge_device'],
|
||||
cr_lrp_info['bridge_vlan'])
|
||||
else:
|
||||
# VIP is on tenant network
|
||||
ips_info = {'logical_switch': vip_router}
|
||||
self._withdraw_remote_ip([vip_ip], ips_info)
|
||||
|
||||
@lockutils.synchronized('nbbgp')
|
||||
def expose_ovn_lb_fip(self, lb):
|
||||
self._expose_ovn_lb_fip(lb)
|
||||
|
||||
def _expose_ovn_lb_fip(self, lb):
|
||||
vip_port = lb.external_ids.get(constants.OVN_LB_VIP_PORT_EXT_ID_KEY)
|
||||
vip_lsp = self.nb_idl.lsp_get(vip_port).execute(check_error=True)
|
||||
if not vip_lsp:
|
||||
LOG.debug("Something went wrong, VIP port %s not found", vip_port)
|
||||
return
|
||||
|
||||
external_ip, external_mac, ls_name = (
|
||||
self.get_port_external_ip_and_ls(vip_lsp.name))
|
||||
if not external_ip or not ls_name:
|
||||
LOG.debug("Something went wrong, no NAT entry for the VIP %s",
|
||||
vip_port)
|
||||
return
|
||||
self._expose_fip(external_ip, external_mac, ls_name, vip_lsp)
|
||||
|
||||
@lockutils.synchronized('nbbgp')
|
||||
def withdraw_ovn_lb_fip(self, lb):
|
||||
self._withdraw_ovn_lb_fip(lb)
|
||||
|
||||
def _withdraw_ovn_lb_fip(self, lb):
|
||||
vip_fip = lb.external_ids.get(constants.OVN_LB_VIP_FIP_EXT_ID_KEY)
|
||||
# OVN loadbalancers ARPs are replied by router port
|
||||
vip_router = lb.external_ids.get(
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY, "").replace('neutron-', "", 1)
|
||||
if not vip_router:
|
||||
return
|
||||
cr_lrp_info = self.ovn_local_cr_lrps.get(vip_router)
|
||||
if not cr_lrp_info:
|
||||
return
|
||||
self._withdraw_provider_port([vip_fip],
|
||||
cr_lrp_info['provider_switch'],
|
||||
cr_lrp_info['bridge_device'],
|
||||
cr_lrp_info['bridge_vlan'])
|
||||
|
||||
def _address_scope_allowed(self, ip, address_scopes):
|
||||
if not self.allowed_address_scopes:
|
||||
# No address scopes to filter on => announce everything
|
||||
|
@ -467,6 +467,16 @@ class OvsdbNbOvnIdl(nb_impl_idl.OvnNbApiIdlImpl, Backend):
|
||||
ports.extend(cmd.execute(check_error=True))
|
||||
return ports
|
||||
|
||||
def get_active_local_lbs(self, local_gateway_ports):
|
||||
lbs = []
|
||||
cmd = self.db_find_rows('Load_Balancer', ('vips', '!=', {}))
|
||||
for row in cmd.execute(check_error=True):
|
||||
if (row.vips and row.external_ids[
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY].replace(
|
||||
'neutron-', "", 1) in local_gateway_ports):
|
||||
lbs.append(row)
|
||||
return lbs
|
||||
|
||||
# FIXME(ltomasbo): This can be removed once ovsdbapp version is >=2.3.0
|
||||
def ls_get_localnet_ports(self, logical_switch, if_exists=True):
|
||||
return LSGetLocalnetPortsCommand(self, logical_switch,
|
||||
|
@ -42,14 +42,27 @@ class PortBindingChassisEvent(Event):
|
||||
return len(mac.strip().split(' ')) > 1
|
||||
|
||||
|
||||
class OVNLBMemberEvent(Event):
|
||||
class OVNLBEvent(Event):
|
||||
def __init__(self, bgp_agent, events):
|
||||
self.agent = bgp_agent
|
||||
table = 'Load_Balancer'
|
||||
super(OVNLBMemberEvent, self).__init__(
|
||||
super(OVNLBEvent, self).__init__(
|
||||
events, table, None)
|
||||
self.event_name = self.__class__.__name__
|
||||
|
||||
def _get_router(self, row):
|
||||
try:
|
||||
return row.external_ids[
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY].replace('neutron-', "", 1)
|
||||
except (AttributeError, KeyError):
|
||||
return
|
||||
|
||||
def _get_vip_fip(self, row):
|
||||
try:
|
||||
return row.external_ids[constants.OVN_LB_VIP_FIP_EXT_ID_KEY]
|
||||
except (AttributeError, KeyError):
|
||||
return
|
||||
|
||||
|
||||
class LSPChassisEvent(Event):
|
||||
def __init__(self, bgp_agent, events):
|
||||
@ -74,10 +87,10 @@ class LSPChassisEvent(Event):
|
||||
return None, None
|
||||
|
||||
def _get_network(self, row):
|
||||
if (hasattr(row, 'external_ids') and
|
||||
row.external_ids.get(constants.OVN_LS_NAME_EXT_ID_KEY)):
|
||||
try:
|
||||
return row.external_ids[constants.OVN_LS_NAME_EXT_ID_KEY]
|
||||
return None
|
||||
except (AttributeError, KeyError):
|
||||
return
|
||||
|
||||
|
||||
class LRPChassisEvent(Event):
|
||||
@ -89,7 +102,7 @@ class LRPChassisEvent(Event):
|
||||
self.event_name = self.__class__.__name__
|
||||
|
||||
def _get_network(self, row):
|
||||
if (hasattr(row, 'external_ids') and
|
||||
row.external_ids.get(constants.OVN_LS_NAME_EXT_ID_KEY)):
|
||||
try:
|
||||
return row.external_ids[constants.OVN_LS_NAME_EXT_ID_KEY]
|
||||
return None
|
||||
except (AttributeError, KeyError):
|
||||
return
|
||||
|
@ -372,7 +372,7 @@ class OVNLBVIPPortEvent(base_watcher.PortBindingChassisEvent):
|
||||
self.agent.expose_ovn_lb(ovn_lb_ip, row)
|
||||
|
||||
|
||||
class OVNLBMemberCreateEvent(base_watcher.OVNLBMemberEvent):
|
||||
class OVNLBMemberCreateEvent(base_watcher.OVNLBEvent):
|
||||
def __init__(self, bgp_agent):
|
||||
events = (self.ROW_CREATE,)
|
||||
super(OVNLBMemberCreateEvent, self).__init__(
|
||||
@ -445,7 +445,7 @@ class OVNLBMemberCreateEvent(base_watcher.OVNLBMemberEvent):
|
||||
vip_ip, row.name, associated_cr_lrp_port)
|
||||
|
||||
|
||||
class OVNLBMemberDeleteEvent(base_watcher.OVNLBMemberEvent):
|
||||
class OVNLBMemberDeleteEvent(base_watcher.OVNLBEvent):
|
||||
def __init__(self, bgp_agent):
|
||||
events = (self.ROW_DELETE,)
|
||||
super(OVNLBMemberDeleteEvent, self).__init__(
|
||||
|
@ -616,3 +616,122 @@ class LogicalSwitchPortTenantDeleteEvent(base_watcher.LSPChassisEvent):
|
||||
'logical_switch': self._get_network(row)
|
||||
}
|
||||
self.agent.withdraw_remote_ip(ips, ips_info)
|
||||
|
||||
|
||||
class OVNLBCreateEvent(base_watcher.OVNLBEvent):
|
||||
def __init__(self, bgp_agent):
|
||||
events = (self.ROW_UPDATE,)
|
||||
super(OVNLBCreateEvent, self).__init__(
|
||||
bgp_agent, events)
|
||||
|
||||
def match_fn(self, event, row, old):
|
||||
# The ovn lb balancers are exposed through the cr-lrp, so if the
|
||||
# local agent does not have the matching router there is no need
|
||||
# to process the event
|
||||
try:
|
||||
if not row.vips:
|
||||
return False
|
||||
lb_router = self._get_router(row)
|
||||
if lb_router not in self.agent.ovn_local_cr_lrps.keys():
|
||||
return False
|
||||
|
||||
# Only expose if there is a modification in the VIPS
|
||||
# And only expose if it is the first item on VIPs
|
||||
if hasattr(old, 'vips'):
|
||||
if not old.vips and row.vips:
|
||||
return True
|
||||
|
||||
if hasattr(old, 'external_ids'):
|
||||
# Check if the lb_router was added
|
||||
old_lb_router = self._get_router(old)
|
||||
if lb_router != old_lb_router:
|
||||
return True
|
||||
# Also check if there is a vip_fip addition to expose the FIP
|
||||
vip_fip = self._get_vip_fip(row)
|
||||
if not vip_fip:
|
||||
return False
|
||||
old_vip_fip = self._get_vip_fip(old)
|
||||
if vip_fip != old_vip_fip:
|
||||
return True
|
||||
except (IndexError, AttributeError):
|
||||
return False
|
||||
return False
|
||||
|
||||
def _run(self, event, row, old):
|
||||
vip_fip = self._get_vip_fip(row)
|
||||
old_vip_fip = self._get_vip_fip(old)
|
||||
with _SYNC_STATE_LOCK.read_lock():
|
||||
if hasattr(old, 'external_ids'):
|
||||
if vip_fip and vip_fip != old_vip_fip:
|
||||
self.agent.expose_ovn_lb_fip(row)
|
||||
else:
|
||||
self.agent.expose_ovn_lb_vip(row)
|
||||
|
||||
|
||||
class OVNLBDeleteEvent(base_watcher.OVNLBEvent):
|
||||
def __init__(self, bgp_agent):
|
||||
events = (self.ROW_DELETE, self.ROW_UPDATE)
|
||||
super(OVNLBDeleteEvent, self).__init__(
|
||||
bgp_agent, events)
|
||||
|
||||
def match_fn(self, event, row, old):
|
||||
# The ovn lb balancers are exposed through the cr-lrp, so if the
|
||||
# local agent does not have the matching router there is no need
|
||||
# to process the event
|
||||
try:
|
||||
if event == self.ROW_DELETE:
|
||||
if not row.vips:
|
||||
return False
|
||||
lb_router = self._get_router(row)
|
||||
if lb_router in self.agent.ovn_local_cr_lrps.keys():
|
||||
return True
|
||||
return False
|
||||
|
||||
# ROW UPDATE EVENT
|
||||
lb_router = self._get_router(row)
|
||||
old_external_ids = False
|
||||
if hasattr(old, 'external_ids'):
|
||||
old_external_ids = True
|
||||
old_lb_router = self._get_router(old)
|
||||
if not old_lb_router:
|
||||
return False
|
||||
if old_lb_router not in self.agent.ovn_local_cr_lrps.keys():
|
||||
return False
|
||||
if old_lb_router != lb_router:
|
||||
# Router should not be removed, but if that is the case we
|
||||
# should remove the loadbalancer
|
||||
return True
|
||||
# Also check if the vip_fip is removed to withdraw the FIP
|
||||
vip_fip = self._get_vip_fip(row)
|
||||
old_vip_fip = self._get_vip_fip(old)
|
||||
if old_vip_fip and old_vip_fip != vip_fip:
|
||||
return True
|
||||
|
||||
# Withdraw IP if VIPs is removed
|
||||
if hasattr(old, 'vips'):
|
||||
if old.vips and not row.vips:
|
||||
if old_external_ids:
|
||||
old_lb_router = self._get_router(old)
|
||||
return (old_lb_router in
|
||||
self.agent.ovn_local_cr_lrps.keys())
|
||||
else:
|
||||
return (lb_router in
|
||||
self.agent.ovn_local_cr_lrps.keys())
|
||||
except (IndexError, AttributeError):
|
||||
return False
|
||||
return False
|
||||
|
||||
def _run(self, event, row, old):
|
||||
vip_fip = self._get_vip_fip(row)
|
||||
old_vip_fip = self._get_vip_fip(old)
|
||||
with _SYNC_STATE_LOCK.read_lock():
|
||||
if event == self.ROW_DELETE:
|
||||
self.agent.withdraw_ovn_lb_vip(row)
|
||||
if vip_fip:
|
||||
self.agent.withdraw_ovn_lb_fip(row)
|
||||
else:
|
||||
if not vip_fip and vip_fip != old_vip_fip:
|
||||
self.agent.withdraw_ovn_lb_fip(old)
|
||||
|
||||
if hasattr(old, 'vips'):
|
||||
self.agent.withdraw_ovn_lb_vip(row)
|
||||
|
@ -59,7 +59,8 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
|
||||
self.router1_info = {'bridge_device': self.bridge,
|
||||
'bridge_vlan': 100,
|
||||
'ips': ['172.24.4.11']}
|
||||
'ips': ['172.24.4.11'],
|
||||
'provider_switch': 'provider-ls'}
|
||||
self.nb_bgp_driver.ovn_local_cr_lrps = {
|
||||
'router1': self.router1_info}
|
||||
self.ovn_routing_tables = {
|
||||
@ -165,16 +166,25 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
port1 = fakes.create_object({
|
||||
'name': 'port-1',
|
||||
'type': constants.OVN_CHASSISREDIRECT_VIF_PORT_TYPE})
|
||||
lb1 = fakes.create_object({
|
||||
'name': 'lb1',
|
||||
'external_ids': {constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fake-fip'}
|
||||
})
|
||||
self.nb_idl.get_active_cr_lrp_on_chassis.return_value = [crlrp_port]
|
||||
self.nb_idl.get_active_local_lrps.return_value = [lrp0]
|
||||
self.nb_idl.get_active_lsp_on_chassis.return_value = [
|
||||
port0, port1]
|
||||
self.nb_idl.get_active_local_lbs.return_value = [lb1]
|
||||
mock_ensure_crlrp_exposed = mock.patch.object(
|
||||
self.nb_bgp_driver, '_ensure_crlrp_exposed').start()
|
||||
mock_expose_subnet = mock.patch.object(
|
||||
self.nb_bgp_driver, '_expose_subnet').start()
|
||||
mock_ensure_lsp_exposed = mock.patch.object(
|
||||
self.nb_bgp_driver, '_ensure_lsp_exposed').start()
|
||||
mock_expose_ovn_lb_vip = mock.patch.object(
|
||||
self.nb_bgp_driver, '_expose_ovn_lb_vip').start()
|
||||
mock_expose_ovn_lb_fip = mock.patch.object(
|
||||
self.nb_bgp_driver, '_expose_ovn_lb_fip').start()
|
||||
mock_routing_bridge.return_value = ['fake-route']
|
||||
mock_nic_address.return_value = self.mac
|
||||
mock_get_patch_ports.return_value = [1, 2]
|
||||
@ -211,6 +221,8 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
'network': 'network1',
|
||||
'address_scopes': {4: None, 6: None}})
|
||||
mock_ensure_lsp_exposed.assert_called_once_with(port0)
|
||||
mock_expose_ovn_lb_vip.assert_called_once_with(lb1)
|
||||
mock_expose_ovn_lb_fip.assert_called_once_with(lb1)
|
||||
mock_del_exposed_ips.assert_called_once_with(
|
||||
ips, CONF.bgp_nic)
|
||||
mock_del_ip_rules.assert_called_once_with(fake_ip_rules)
|
||||
@ -443,13 +455,24 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
self.nb_bgp_driver.ovn_bridge_mappings = {'fake-localnet': 'br-ex'}
|
||||
mock_expose_subnet = mock.patch.object(
|
||||
self.nb_bgp_driver, '_expose_subnet').start()
|
||||
lrp0 = fakes.create_object({
|
||||
'name': 'lrp_port',
|
||||
'external_ids': {
|
||||
constants.OVN_CIDRS_EXT_ID_KEY: "10.0.0.1/24",
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'network1',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'}})
|
||||
self.nb_idl.get_active_local_lrps.return_value = [lrp0]
|
||||
|
||||
if (ips_info.get('router') and
|
||||
ips_info['type'] == constants.OVN_CR_LRP_PORT_TYPE):
|
||||
lrp0 = fakes.create_object({
|
||||
'name': 'lrp_port',
|
||||
'external_ids': {
|
||||
constants.OVN_CIDRS_EXT_ID_KEY: "10.0.0.1/24",
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'network1',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'}})
|
||||
self.nb_idl.get_active_local_lrps.return_value = [lrp0]
|
||||
lb1 = fakes.create_object({
|
||||
'name': 'lb1', 'external_ids': {
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fake-fip'}})
|
||||
self.nb_idl.get_active_local_lbs.return_value = [lb1]
|
||||
mock_expose_ovn_lb_vip = mock.patch.object(
|
||||
self.nb_bgp_driver, '_expose_ovn_lb_vip').start()
|
||||
mock_expose_ovn_lb_fip = mock.patch.object(
|
||||
self.nb_bgp_driver, '_expose_ovn_lb_fip').start()
|
||||
|
||||
self.nb_bgp_driver.expose_ip(ips, ips_info)
|
||||
|
||||
@ -480,6 +503,8 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
["10.0.0.1/24"], {'associated_router': 'router1',
|
||||
'network': 'network1',
|
||||
'address_scopes': {4: None, 6: None}})
|
||||
mock_expose_ovn_lb_vip.assert_called_once_with(lb1)
|
||||
mock_expose_ovn_lb_fip.assert_called_once_with(lb1)
|
||||
|
||||
def test_expose_ip(self):
|
||||
ips = [self.ipv4, self.ipv6]
|
||||
@ -542,13 +567,23 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
|
||||
mock_withdraw_subnet = mock.patch.object(
|
||||
self.nb_bgp_driver, '_withdraw_subnet').start()
|
||||
lrp0 = fakes.create_object({
|
||||
'name': 'lrp_port',
|
||||
'external_ids': {
|
||||
constants.OVN_CIDRS_EXT_ID_KEY: "10.0.0.1/24",
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'network1',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'}})
|
||||
self.nb_idl.get_active_local_lrps.return_value = [lrp0]
|
||||
if (ips_info.get('router') and
|
||||
ips_info['type'] == constants.OVN_CR_LRP_PORT_TYPE):
|
||||
lrp0 = fakes.create_object({
|
||||
'name': 'lrp_port',
|
||||
'external_ids': {
|
||||
constants.OVN_CIDRS_EXT_ID_KEY: "10.0.0.1/24",
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'network1',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'}})
|
||||
self.nb_idl.get_active_local_lrps.return_value = [lrp0]
|
||||
lb1 = fakes.create_object({
|
||||
'name': 'lb1', 'external_ids': {
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fake-fip'}})
|
||||
self.nb_idl.get_active_local_lbs.return_value = [lb1]
|
||||
mock_withdraw_ovn_lb_vip = mock.patch.object(
|
||||
self.nb_bgp_driver, '_withdraw_ovn_lb_vip').start()
|
||||
mock_withdraw_ovn_lb_fip = mock.patch.object(
|
||||
self.nb_bgp_driver, '_withdraw_ovn_lb_fip').start()
|
||||
|
||||
self.nb_bgp_driver.withdraw_ip(ips, ips_info)
|
||||
|
||||
@ -578,6 +613,8 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
["10.0.0.1/24"], {'associated_router': 'router1',
|
||||
'network': 'network1',
|
||||
'address_scopes': {4: None, 6: None}})
|
||||
mock_withdraw_ovn_lb_vip.assert_called_once_with(lb1)
|
||||
mock_withdraw_ovn_lb_fip.assert_called_once_with(lb1)
|
||||
|
||||
def test_withdraw_ip(self):
|
||||
ips = [self.ipv4, self.ipv6]
|
||||
@ -1113,3 +1150,243 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
mock.ANY, ips[1], self.router1_info['bridge_device'],
|
||||
self.router1_info['bridge_vlan'], mock.ANY,
|
||||
self.router1_info['ips'])
|
||||
|
||||
def test_expose_ovn_lb_vip_tenant(self):
|
||||
self.nb_bgp_driver.ovn_local_lrps = {'net1': ['ip1']}
|
||||
lb = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_PORT_EXT_ID_KEY: 'vip_port',
|
||||
constants.OVN_LB_VIP_IP_EXT_ID_KEY: 'vip'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
|
||||
vip_lsp = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'
|
||||
})
|
||||
self.nb_idl.lsp_get.return_value.execute.return_value = vip_lsp
|
||||
mock_expose_remote_ip = mock.patch.object(
|
||||
self.nb_bgp_driver, '_expose_remote_ip').start()
|
||||
mock_expose_provider_port = mock.patch.object(
|
||||
self.nb_bgp_driver, '_expose_provider_port').start()
|
||||
|
||||
self.nb_bgp_driver.expose_ovn_lb_vip(lb)
|
||||
|
||||
mock_expose_remote_ip.assert_called_once_with(
|
||||
['vip'], {'logical_switch': 'router1'}
|
||||
)
|
||||
mock_expose_provider_port.assert_not_called()
|
||||
|
||||
def test_expose_ovn_lb_vip_provider(self):
|
||||
self.nb_bgp_driver.ovn_local_lrps = {'net1': ['ip1']}
|
||||
lb = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_PORT_EXT_ID_KEY: 'vip_port',
|
||||
constants.OVN_LB_VIP_IP_EXT_ID_KEY: 'vip'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
|
||||
vip_lsp = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net2'
|
||||
})
|
||||
self.nb_idl.lsp_get.return_value.execute.return_value = vip_lsp
|
||||
mock_expose_remote_ip = mock.patch.object(
|
||||
self.nb_bgp_driver, '_expose_remote_ip').start()
|
||||
mock_expose_provider_port = mock.patch.object(
|
||||
self.nb_bgp_driver, '_expose_provider_port').start()
|
||||
mock_get_ls_localnet_info = mock.patch.object(
|
||||
self.nb_bgp_driver, '_get_ls_localnet_info').start()
|
||||
mock_get_ls_localnet_info.return_value = (None, None, None)
|
||||
|
||||
self.nb_bgp_driver.expose_ovn_lb_vip(lb)
|
||||
|
||||
mock_expose_remote_ip.assert_not_called()
|
||||
mock_get_ls_localnet_info.assert_called_once_with('net2')
|
||||
mock_expose_provider_port.assert_called_once_with(
|
||||
['vip'], None, 'net2', mock.ANY, mock.ANY, mock.ANY)
|
||||
|
||||
def test_expose_ovn_lb_vip_no_vip(self):
|
||||
self.nb_bgp_driver.ovn_local_lrps = {'net1': ['ip1']}
|
||||
lb = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_PORT_EXT_ID_KEY: 'vip_port',
|
||||
constants.OVN_LB_VIP_IP_EXT_ID_KEY: 'vip'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
|
||||
self.nb_idl.lsp_get.return_value.execute.return_value = None
|
||||
mock_expose_remote_ip = mock.patch.object(
|
||||
self.nb_bgp_driver, '_expose_remote_ip').start()
|
||||
mock_expose_provider_port = mock.patch.object(
|
||||
self.nb_bgp_driver, '_expose_provider_port').start()
|
||||
|
||||
self.nb_bgp_driver.expose_ovn_lb_vip(lb)
|
||||
|
||||
mock_expose_remote_ip.assert_not_called()
|
||||
mock_expose_provider_port.assert_not_called()
|
||||
|
||||
def test_withdraw_ovn_lb_vip_tenant(self):
|
||||
lb = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_PORT_EXT_ID_KEY: 'vip_port',
|
||||
constants.OVN_LB_VIP_IP_EXT_ID_KEY: 'vip'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
mock_withdraw_remote_ip = mock.patch.object(
|
||||
self.nb_bgp_driver, '_withdraw_remote_ip').start()
|
||||
mock_withdraw_provider_port = mock.patch.object(
|
||||
self.nb_bgp_driver, '_withdraw_provider_port').start()
|
||||
|
||||
self.nb_bgp_driver.withdraw_ovn_lb_vip(lb)
|
||||
|
||||
mock_withdraw_provider_port.assert_not_called()
|
||||
mock_withdraw_remote_ip.assert_called_once_with(
|
||||
['vip'], {'logical_switch': 'router1'})
|
||||
|
||||
def test_withdraw_ovn_lb_vip_provider(self):
|
||||
self.nb_bgp_driver._exposed_ips = {
|
||||
'provider-ls': {'vip': {'bridge_device': self.bridge,
|
||||
'bridge_vlan': None}}}
|
||||
lb = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_PORT_EXT_ID_KEY: 'vip_port',
|
||||
constants.OVN_LB_VIP_IP_EXT_ID_KEY: 'vip'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
mock_withdraw_remote_ip = mock.patch.object(
|
||||
self.nb_bgp_driver, '_withdraw_remote_ip').start()
|
||||
mock_withdraw_provider_port = mock.patch.object(
|
||||
self.nb_bgp_driver, '_withdraw_provider_port').start()
|
||||
|
||||
self.nb_bgp_driver.withdraw_ovn_lb_vip(lb)
|
||||
|
||||
mock_withdraw_provider_port.assert_called_once_with(
|
||||
['vip'],
|
||||
self.router1_info['provider_switch'],
|
||||
self.router1_info['bridge_device'],
|
||||
self.router1_info['bridge_vlan'])
|
||||
mock_withdraw_remote_ip.assert_not_called()
|
||||
|
||||
def test_withdraw_ovn_lb_vip_no_router(self):
|
||||
lb = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router2',
|
||||
constants.OVN_LB_VIP_PORT_EXT_ID_KEY: 'vip_port',
|
||||
constants.OVN_LB_VIP_IP_EXT_ID_KEY: 'vip'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
mock_withdraw_remote_ip = mock.patch.object(
|
||||
self.nb_bgp_driver, '_withdraw_remote_ip').start()
|
||||
mock_withdraw_provider_port = mock.patch.object(
|
||||
self.nb_bgp_driver, '_withdraw_provider_port').start()
|
||||
|
||||
self.nb_bgp_driver.withdraw_ovn_lb_vip(lb)
|
||||
|
||||
mock_withdraw_remote_ip.assert_not_called()
|
||||
mock_withdraw_provider_port.assert_not_called()
|
||||
|
||||
def test_expose_ovn_lb_fip(self):
|
||||
lb = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_PORT_EXT_ID_KEY: 'vip_port',
|
||||
constants.OVN_LB_VIP_IP_EXT_ID_KEY: 'vip'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
vip_lsp = utils.create_row(
|
||||
name='vip-port-name',
|
||||
external_ids={
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net2'
|
||||
})
|
||||
self.nb_idl.lsp_get.return_value.execute.return_value = vip_lsp
|
||||
mock_get_port_external_ip_and_ls = mock.patch.object(
|
||||
self.nb_bgp_driver, 'get_port_external_ip_and_ls').start()
|
||||
mock_get_port_external_ip_and_ls.return_value = ('fip',
|
||||
'fip-mac',
|
||||
'provider-ls')
|
||||
mock_expose_fip = mock.patch.object(
|
||||
self.nb_bgp_driver, '_expose_fip').start()
|
||||
|
||||
self.nb_bgp_driver.expose_ovn_lb_fip(lb)
|
||||
mock_expose_fip.assert_called_once_with(
|
||||
'fip', 'fip-mac', 'provider-ls', vip_lsp)
|
||||
|
||||
def test_expose_ovn_lb_fip_no_vip_port(self):
|
||||
lb = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_PORT_EXT_ID_KEY: 'vip_port',
|
||||
constants.OVN_LB_VIP_IP_EXT_ID_KEY: 'vip'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
self.nb_idl.lsp_get.return_value.execute.return_value = None
|
||||
mock_expose_fip = mock.patch.object(
|
||||
self.nb_bgp_driver, '_expose_fip').start()
|
||||
|
||||
self.nb_bgp_driver.expose_ovn_lb_fip(lb)
|
||||
mock_expose_fip.assert_not_called()
|
||||
|
||||
def test_expose_ovn_lb_fip_no_external_ip(self):
|
||||
lb = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_PORT_EXT_ID_KEY: 'vip_port',
|
||||
constants.OVN_LB_VIP_IP_EXT_ID_KEY: 'vip'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
vip_lsp = utils.create_row(
|
||||
name='vip-port-name',
|
||||
external_ids={
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net2'
|
||||
})
|
||||
self.nb_idl.lsp_get.return_value.execute.return_value = vip_lsp
|
||||
mock_get_port_external_ip_and_ls = mock.patch.object(
|
||||
self.nb_bgp_driver, 'get_port_external_ip_and_ls').start()
|
||||
mock_get_port_external_ip_and_ls.return_value = (None, None, None)
|
||||
mock_expose_fip = mock.patch.object(
|
||||
self.nb_bgp_driver, '_expose_fip').start()
|
||||
|
||||
self.nb_bgp_driver.expose_ovn_lb_fip(lb)
|
||||
mock_expose_fip.assert_not_called()
|
||||
|
||||
def test_withdraw_ovn_lb_fip(self):
|
||||
lb = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_PORT_EXT_ID_KEY: 'vip_port',
|
||||
constants.OVN_LB_VIP_IP_EXT_ID_KEY: 'vip',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'vip-fip'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
mock_withdraw_provider_port = mock.patch.object(
|
||||
self.nb_bgp_driver, '_withdraw_provider_port').start()
|
||||
|
||||
self.nb_bgp_driver.withdraw_ovn_lb_fip(lb)
|
||||
mock_withdraw_provider_port.assert_called_once_with(
|
||||
['vip-fip'],
|
||||
self.router1_info['provider_switch'],
|
||||
self.router1_info['bridge_device'],
|
||||
self.router1_info['bridge_vlan'])
|
||||
|
||||
def test_withdraw_ovn_lb_fip_no_vip_router(self):
|
||||
lb = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_VIP_PORT_EXT_ID_KEY: 'vip_port',
|
||||
constants.OVN_LB_VIP_IP_EXT_ID_KEY: 'vip',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'vip-fip'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
mock_withdraw_provider_port = mock.patch.object(
|
||||
self.nb_bgp_driver, '_withdraw_provider_port').start()
|
||||
|
||||
self.nb_bgp_driver.withdraw_ovn_lb_fip(lb)
|
||||
mock_withdraw_provider_port.assert_not_called()
|
||||
|
||||
def test_withdraw_ovn_lb_fip_no_cr_lrp(self):
|
||||
lb = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router2',
|
||||
constants.OVN_LB_VIP_PORT_EXT_ID_KEY: 'vip_port',
|
||||
constants.OVN_LB_VIP_IP_EXT_ID_KEY: 'vip',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'vip-fip'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
mock_withdraw_provider_port = mock.patch.object(
|
||||
self.nb_bgp_driver, '_withdraw_provider_port').start()
|
||||
|
||||
self.nb_bgp_driver.withdraw_ovn_lb_fip(lb)
|
||||
mock_withdraw_provider_port.assert_not_called()
|
||||
|
@ -203,6 +203,24 @@ class TestOvsdbNbOvnIdl(test_base.TestCase):
|
||||
|
||||
self.nb_idl.db_find_rows.assert_has_calls(expected_calls)
|
||||
|
||||
def test_get_active_local_lbs(self):
|
||||
local_gateway_ports = ['router1']
|
||||
lb1 = fakes.create_object({
|
||||
'vips': {'vip': 'member1,member2'},
|
||||
'external_ids': {
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: "neutron-router1"}})
|
||||
lb2 = fakes.create_object({
|
||||
'vips': {'vip': 'member1,member2'},
|
||||
'external_ids': {
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: "neutron-router2"}})
|
||||
self.nb_idl.db_find_rows.return_value.execute.return_value = [lb1, lb2]
|
||||
|
||||
ret = self.nb_idl.get_active_local_lbs(local_gateway_ports)
|
||||
|
||||
self.assertEqual([lb1], ret)
|
||||
self.nb_idl.db_find_rows.assert_called_once_with(
|
||||
'Load_Balancer', ('vips', '!=', {}))
|
||||
|
||||
|
||||
class TestOvsdbSbOvnIdl(test_base.TestCase):
|
||||
|
||||
|
@ -44,6 +44,33 @@ class TestPortBindingChassisEvent(test_base.TestCase):
|
||||
'aa:bb:cc:dd:ee:ff 10.10.1.16 10.10.1.17 10.10.1.18'))
|
||||
|
||||
|
||||
class FakeOVNLBEvent(base_watcher.OVNLBEvent):
|
||||
def run(self):
|
||||
pass
|
||||
|
||||
|
||||
class TestOVNLBEvent(test_base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestOVNLBEvent, self).setUp()
|
||||
self.ovnlb_event = FakeOVNLBEvent(
|
||||
mock.Mock(), [mock.Mock()])
|
||||
|
||||
def test__get_router(self):
|
||||
row = utils.create_row(
|
||||
external_ids={constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-net'})
|
||||
self.assertEqual('net', self.ovnlb_event._get_router(row))
|
||||
row = utils.create_row(external_ids={})
|
||||
self.assertEqual(None, self.ovnlb_event._get_router(row))
|
||||
|
||||
def test__get_vip_fip(self):
|
||||
row = utils.create_row(
|
||||
external_ids={constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip'})
|
||||
self.assertEqual('fip', self.ovnlb_event._get_vip_fip(row))
|
||||
row = utils.create_row(external_ids={})
|
||||
self.assertEqual(None, self.ovnlb_event._get_vip_fip(row))
|
||||
|
||||
|
||||
class FakeLSPChassisEvent(base_watcher.LSPChassisEvent):
|
||||
def run(self):
|
||||
pass
|
||||
|
@ -1098,3 +1098,291 @@ class TestLogicalSwitchPortTenantDeleteEvent(test_base.TestCase):
|
||||
up=[True])
|
||||
self.event.run(None, row, mock.Mock())
|
||||
self.agent.withdraw_remote_ip.assert_not_called()
|
||||
|
||||
|
||||
class TestOVNLBCreateEvent(test_base.TestCase):
|
||||
def setUp(self):
|
||||
super(TestOVNLBCreateEvent, self).setUp()
|
||||
self.chassis = 'fake-chassis'
|
||||
self.chassis_id = 'fake-chassis-id'
|
||||
self.agent = mock.Mock(chassis=self.chassis,
|
||||
chassis_id=self.chassis_id)
|
||||
self.agent.ovn_local_cr_lrps = {
|
||||
'router1': {'bridge_device': 'br-ex',
|
||||
'bridge_vlan': None,
|
||||
'ips': ['172.24.16.2']}}
|
||||
self.event = nb_bgp_watcher.OVNLBCreateEvent(
|
||||
self.agent)
|
||||
|
||||
def test_match_fn(self):
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
old = utils.create_row(vips={})
|
||||
self.assertTrue(self.event.match_fn(mock.Mock(), row, old))
|
||||
|
||||
def test_match_fn_router_added(self):
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
old = utils.create_row(external_ids={})
|
||||
self.assertTrue(self.event.match_fn(mock.Mock(), row, old))
|
||||
|
||||
def test_match_fn_fip_added(self):
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
old = utils.create_row(external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1'})
|
||||
self.assertTrue(self.event.match_fn(mock.Mock(), row, old))
|
||||
|
||||
def test_match_fn_no_vips(self):
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
|
||||
vips={})
|
||||
self.assertFalse(self.event.match_fn(mock.Mock(), row, mock.Mock()))
|
||||
|
||||
def test_match_fn_no_local_crlrp(self):
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router2',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
self.assertFalse(self.event.match_fn(mock.Mock(), row, mock.Mock()))
|
||||
|
||||
def test_run_vip(self):
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
old = utils.create_row(vips={})
|
||||
|
||||
self.event.run(None, row, old)
|
||||
|
||||
self.agent.expose_ovn_lb_vip.assert_called_once_with(row)
|
||||
self.agent.expose_ovn_lb_fip.assert_not_called()
|
||||
|
||||
def test_run_vip_added_extra_ext_id_info(self):
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1',
|
||||
'other': 'info'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
old = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'})
|
||||
|
||||
self.event.run(None, row, old)
|
||||
|
||||
self.agent.expose_ovn_lb_vip.assert_not_called()
|
||||
self.agent.expose_ovn_lb_fip.assert_not_called()
|
||||
|
||||
def test_run_fip(self):
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
old = utils.create_row(external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1'})
|
||||
|
||||
self.event.run(None, row, old)
|
||||
|
||||
self.agent.expose_ovn_lb_vip.assert_not_called()
|
||||
self.agent.expose_ovn_lb_fip.assert_called_once_with(row)
|
||||
|
||||
|
||||
class TestOVNLBDeleteEvent(test_base.TestCase):
|
||||
def setUp(self):
|
||||
super(TestOVNLBDeleteEvent, self).setUp()
|
||||
self.chassis = 'fake-chassis'
|
||||
self.chassis_id = 'fake-chassis-id'
|
||||
self.agent = mock.Mock(chassis=self.chassis,
|
||||
chassis_id=self.chassis_id)
|
||||
self.agent.ovn_local_cr_lrps = {
|
||||
'router1': {'bridge_device': 'br-ex',
|
||||
'bridge_vlan': None,
|
||||
'ips': ['172.24.16.2']}}
|
||||
self.event = nb_bgp_watcher.OVNLBDeleteEvent(
|
||||
self.agent)
|
||||
|
||||
def test_match_fn(self):
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
|
||||
vips={})
|
||||
old = utils.create_row(vips={'vip': 'member', 'fip': 'member'})
|
||||
self.assertTrue(self.event.match_fn(mock.Mock(), row, old))
|
||||
|
||||
def test_match_fn_delete(self):
|
||||
event = self.event.ROW_DELETE
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
self.assertTrue(self.event.match_fn(event, row, mock.Mock()))
|
||||
|
||||
def test_match_fn_delete_no_vips(self):
|
||||
event = self.event.ROW_DELETE
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
|
||||
vips={})
|
||||
self.assertFalse(self.event.match_fn(event, row, mock.Mock()))
|
||||
|
||||
def test_match_fn_delete_no_local_router(self):
|
||||
event = self.event.ROW_DELETE
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router2',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
self.assertFalse(self.event.match_fn(event, row, mock.Mock()))
|
||||
|
||||
def test_match_fn_router_deleted(self):
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
old = utils.create_row(external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1'
|
||||
})
|
||||
self.assertTrue(self.event.match_fn(mock.Mock(), row, old))
|
||||
|
||||
def test_match_fn_no_old_router(self):
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
old = utils.create_row(external_ids={})
|
||||
self.assertFalse(self.event.match_fn(mock.Mock(), row, old))
|
||||
|
||||
def test_match_fn_old_router_non_local(self):
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
old = utils.create_row(external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router2',
|
||||
})
|
||||
self.assertFalse(self.event.match_fn(mock.Mock(), row, old))
|
||||
|
||||
def test_match_fn_fip_deleted(self):
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
old = utils.create_row(external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip'})
|
||||
self.assertTrue(self.event.match_fn(mock.Mock(), row, old))
|
||||
|
||||
def test_match_fn_vip_deleted_with_ext_id_update(self):
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
|
||||
vips={})
|
||||
old = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1',
|
||||
'other': 'info'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
self.assertTrue(self.event.match_fn(mock.Mock(), row, old))
|
||||
|
||||
def test_run_vip(self):
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
|
||||
vips={})
|
||||
old = utils.create_row(vips={'vip': 'member'})
|
||||
|
||||
self.event.run(None, row, old)
|
||||
|
||||
self.agent.withdraw_ovn_lb_vip.assert_called_once_with(row)
|
||||
self.agent.withdraw_ovn_lb_fip.assert_not_called()
|
||||
|
||||
def test_run_vip_delete(self):
|
||||
event = self.event.ROW_DELETE
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
|
||||
vips={})
|
||||
|
||||
self.event.run(event, row, None)
|
||||
|
||||
self.agent.withdraw_ovn_lb_vip.assert_called_once_with(row)
|
||||
self.agent.withdraw_ovn_lb_fip.assert_called_once_with(row)
|
||||
|
||||
def test_run_vip_deleted_extra_ext_id_info(self):
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
old = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1',
|
||||
'other': 'info'})
|
||||
|
||||
self.event.run(None, row, old)
|
||||
|
||||
self.agent.withdraw_ovn_lb_vip.assert_not_called()
|
||||
self.agent.withdraw_ovn_lb_fip.assert_not_called()
|
||||
|
||||
def test_run_fip(self):
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
|
||||
vips={'vip': 'member', 'fip': 'member'})
|
||||
old = utils.create_row(external_ids={
|
||||
constants.OVN_LB_LR_REF_EXT_ID_KEY: 'neutron-router1',
|
||||
constants.OVN_LB_VIP_FIP_EXT_ID_KEY: 'fip'})
|
||||
|
||||
self.event.run(None, row, old)
|
||||
|
||||
self.agent.withdraw_ovn_lb_vip.assert_not_called()
|
||||
self.agent.withdraw_ovn_lb_fip.assert_called_once_with(old)
|
||||
|
Loading…
x
Reference in New Issue
Block a user