Simplify keepalived.virtual_routes
keepalived.virtual_routes previously held one list of virtual routes of different kinds, and the HA router class manipulated that list directly. The list held both the default gateway virtual route, and any extra routes. This means that when adding extra routes for example, the HA router would first have to remove all routes that are not default gateway routes, then add the extra routes received via RPC. This is messy because: a) It's needlessly complicated b) It's fragile c) There's zero separation of concerns (HA router should not know how keepalived maintains its list of virtual routes) d) It requires changes to the management of the default gateway and virtual routes just to add another type of extra routes This patch solves these issues by separating the persistency of virtual routes according to their role. Co-Authored-By: gong yong sheng <gong.yongsheng@99cloud.net> Related-Bug: 1414640 Change-Id: I1406b1876c3a47b110818686b42e5f2f688154fa
This commit is contained in:
parent
949f6e23b3
commit
e214b56da9
|
@ -179,20 +179,15 @@ class HaRouter(router.RouterInfo):
|
|||
new_routes = self.router['routes']
|
||||
|
||||
instance = self._get_keepalived_instance()
|
||||
|
||||
# Filter out all of the old routes while keeping only the default route
|
||||
default_gw = (n_consts.IPv6_ANY, n_consts.IPv4_ANY)
|
||||
instance.virtual_routes = [route for route in instance.virtual_routes
|
||||
if route.destination in default_gw]
|
||||
for route in new_routes:
|
||||
instance.virtual_routes.append(keepalived.KeepalivedVirtualRoute(
|
||||
route['destination'],
|
||||
route['nexthop']))
|
||||
|
||||
instance.virtual_routes.extra_routes = [
|
||||
keepalived.KeepalivedVirtualRoute(
|
||||
route['destination'], route['nexthop'])
|
||||
for route in new_routes]
|
||||
self.routes = new_routes
|
||||
|
||||
def _add_default_gw_virtual_route(self, ex_gw_port, interface_name):
|
||||
subnets = ex_gw_port.get('subnets', [])
|
||||
default_gw_rts = []
|
||||
for subnet in subnets:
|
||||
gw_ip = subnet['gateway_ip']
|
||||
if gw_ip:
|
||||
|
@ -202,12 +197,9 @@ class HaRouter(router.RouterInfo):
|
|||
netaddr.IPAddress(gw_ip).version == 4 else
|
||||
n_consts.IPv6_ANY)
|
||||
instance = self._get_keepalived_instance()
|
||||
instance.virtual_routes = (
|
||||
[route for route in instance.virtual_routes
|
||||
if route.destination != default_gw])
|
||||
instance.virtual_routes.append(
|
||||
keepalived.KeepalivedVirtualRoute(
|
||||
default_gw, gw_ip, interface_name))
|
||||
default_gw_rts.append(keepalived.KeepalivedVirtualRoute(
|
||||
default_gw, gw_ip, interface_name))
|
||||
instance.virtual_routes.gateway_routes = default_gw_rts
|
||||
|
||||
def _should_delete_ipv6_lladdr(self, ipv6_lladdr):
|
||||
"""Only the master should have any IP addresses configured.
|
||||
|
|
|
@ -107,6 +107,32 @@ class KeepalivedVirtualRoute(object):
|
|||
return output
|
||||
|
||||
|
||||
class KeepalivedInstanceRoutes(object):
|
||||
def __init__(self):
|
||||
self.gateway_routes = []
|
||||
self.extra_routes = []
|
||||
|
||||
def remove_routes_on_interface(self, interface_name):
|
||||
self.gateway_routes = [gw_rt for gw_rt in self.gateway_routes
|
||||
if gw_rt.interface_name != interface_name]
|
||||
# NOTE(amuller): extra_routes are initialized from the router's
|
||||
# 'routes' attribute. These routes do not have an interface
|
||||
# parameter and so cannot be removed via an interface_name lookup.
|
||||
|
||||
@property
|
||||
def routes(self):
|
||||
return self.gateway_routes + self.extra_routes
|
||||
|
||||
def __len__(self):
|
||||
return len(self.routes)
|
||||
|
||||
def build_config(self):
|
||||
return itertools.chain([' virtual_routes {'],
|
||||
(' %s' % route.build_config()
|
||||
for route in self.routes),
|
||||
[' }'])
|
||||
|
||||
|
||||
class KeepalivedInstance(object):
|
||||
"""Instance section of a keepalived configuration."""
|
||||
|
||||
|
@ -127,7 +153,7 @@ class KeepalivedInstance(object):
|
|||
self.mcast_src_ip = mcast_src_ip
|
||||
self.track_interfaces = []
|
||||
self.vips = []
|
||||
self.virtual_routes = []
|
||||
self.virtual_routes = KeepalivedInstanceRoutes()
|
||||
self.authentication = None
|
||||
metadata_cidr = '169.254.169.254/32'
|
||||
self.primary_vip_range = get_free_range(
|
||||
|
@ -148,8 +174,7 @@ class KeepalivedInstance(object):
|
|||
self.vips = [vip for vip in self.vips
|
||||
if vip.interface_name != interface_name]
|
||||
|
||||
self.virtual_routes = [vroute for vroute in self.virtual_routes
|
||||
if vroute.interface_name != interface_name]
|
||||
self.virtual_routes.remove_routes_on_interface(interface_name)
|
||||
|
||||
def remove_vip_by_ip_address(self, ip_address):
|
||||
self.vips = [vip for vip in self.vips
|
||||
|
@ -243,8 +268,8 @@ class KeepalivedInstance(object):
|
|||
|
||||
config.extend(self._build_vips_config())
|
||||
|
||||
if self.virtual_routes:
|
||||
config.extend(self._build_virtual_routes_config())
|
||||
if len(self.virtual_routes):
|
||||
config.extend(self.virtual_routes.build_config())
|
||||
|
||||
config.append('}')
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ class KeepalivedConfBaseMixin(object):
|
|||
virtual_route = keepalived.KeepalivedVirtualRoute(n_consts.IPv4_ANY,
|
||||
"192.168.1.1",
|
||||
"eth1")
|
||||
instance1.virtual_routes.append(virtual_route)
|
||||
instance1.virtual_routes.gateway_routes = [virtual_route]
|
||||
|
||||
instance2 = keepalived.KeepalivedInstance('MASTER', 'eth4', 2,
|
||||
['169.254.192.0/18'],
|
||||
|
@ -189,6 +189,43 @@ class KeepalivedStateExceptionTestCase(base.BaseTestCase):
|
|||
invalid_auth_type, 'some_password')
|
||||
|
||||
|
||||
class KeepalivedInstanceRoutesTestCase(base.BaseTestCase):
|
||||
@classmethod
|
||||
def _get_instance_routes(cls):
|
||||
routes = keepalived.KeepalivedInstanceRoutes()
|
||||
default_gw_eth0 = keepalived.KeepalivedVirtualRoute(
|
||||
'0.0.0.0/0', '1.0.0.254', 'eth0')
|
||||
default_gw_eth1 = keepalived.KeepalivedVirtualRoute(
|
||||
'::/0', 'fe80::3e97:eff:fe26:3bfa/64', 'eth1')
|
||||
routes.gateway_routes = [default_gw_eth0, default_gw_eth1]
|
||||
extra_routes = [
|
||||
keepalived.KeepalivedVirtualRoute('10.0.0.0/8', '1.0.0.1'),
|
||||
keepalived.KeepalivedVirtualRoute('20.0.0.0/8', '2.0.0.2')]
|
||||
routes.extra_routes = extra_routes
|
||||
return routes
|
||||
|
||||
def test_routes(self):
|
||||
routes = self._get_instance_routes()
|
||||
self.assertEqual(len(routes.routes), 4)
|
||||
|
||||
def test_remove_routes_on_interface(self):
|
||||
routes = self._get_instance_routes()
|
||||
routes.remove_routes_on_interface('eth0')
|
||||
self.assertEqual(len(routes.routes), 3)
|
||||
routes.remove_routes_on_interface('eth1')
|
||||
self.assertEqual(len(routes.routes), 2)
|
||||
|
||||
def test_build_config(self):
|
||||
expected = """ virtual_routes {
|
||||
0.0.0.0/0 via 1.0.0.254 dev eth0
|
||||
::/0 via fe80::3e97:eff:fe26:3bfa/64 dev eth1
|
||||
10.0.0.0/8 via 1.0.0.1
|
||||
20.0.0.0/8 via 2.0.0.2
|
||||
}"""
|
||||
routes = self._get_instance_routes()
|
||||
self.assertEqual(expected, '\n'.join(routes.build_config()))
|
||||
|
||||
|
||||
class KeepalivedInstanceTestCase(base.BaseTestCase,
|
||||
KeepalivedConfBaseMixin):
|
||||
def test_get_primary_vip(self):
|
||||
|
|
Loading…
Reference in New Issue