Merge "Add router_factory to l3-agent and L3 extension API"
This commit is contained in:
commit
554b7cd228
@ -194,6 +194,40 @@ class L3PluginApi(object):
|
||||
return cctxt.call(context, 'get_host_ha_router_count', host=self.host)
|
||||
|
||||
|
||||
class RouterFactory(object):
|
||||
|
||||
def __init__(self):
|
||||
self._routers = {}
|
||||
|
||||
def register(self, features, router_cls):
|
||||
"""Register router class which implements BaseRouterInfo
|
||||
|
||||
Features which is a list of strings converted to frozenset internally
|
||||
for key uniqueness.
|
||||
|
||||
:param features: a list of strings of router's features
|
||||
:param router_cls: a router class which implements BaseRouterInfo
|
||||
"""
|
||||
self._routers[frozenset(features)] = router_cls
|
||||
|
||||
def create(self, features, **kwargs):
|
||||
"""Create router instance with registered router class
|
||||
|
||||
:param features: a list of strings of router's features
|
||||
:param kwargs: arguments for router class
|
||||
:returns: a router instance which implements BaseRouterInfo
|
||||
:raises: n_exc.RouterNotFoundInRouterFactory
|
||||
"""
|
||||
try:
|
||||
router = self._routers[frozenset(features)]
|
||||
return router(**kwargs)
|
||||
except KeyError:
|
||||
exc = l3_exc.RouterNotFoundInRouterFactory(
|
||||
router_id=kwargs['router_id'], features=features)
|
||||
LOG.exception(exc.msg)
|
||||
raise exc
|
||||
|
||||
|
||||
@profiler.trace_cls("l3-agent")
|
||||
class L3NATAgent(ha.AgentMixin,
|
||||
dvr.AgentMixin,
|
||||
@ -223,6 +257,8 @@ class L3NATAgent(ha.AgentMixin,
|
||||
else:
|
||||
self.conf = cfg.CONF
|
||||
self.router_info = {}
|
||||
self.router_factory = RouterFactory()
|
||||
self._register_router_cls(self.router_factory)
|
||||
|
||||
self._check_config_params()
|
||||
|
||||
@ -328,6 +364,21 @@ class L3NATAgent(ha.AgentMixin,
|
||||
except Exception:
|
||||
LOG.exception('update_all_ha_network_port_statuses failed')
|
||||
|
||||
def _register_router_cls(self, factory):
|
||||
factory.register([], legacy_router.LegacyRouter)
|
||||
factory.register(['ha'], ha_router.HaRouter)
|
||||
|
||||
if self.conf.agent_mode == lib_const.L3_AGENT_MODE_DVR_SNAT:
|
||||
factory.register(['distributed'],
|
||||
dvr_router.DvrEdgeRouter)
|
||||
factory.register(['ha', 'distributed'],
|
||||
dvr_edge_ha_router.DvrEdgeHaRouter)
|
||||
else:
|
||||
factory.register(['distributed'],
|
||||
dvr_local_router.DvrLocalRouter)
|
||||
factory.register(['ha', 'distributed'],
|
||||
dvr_local_router.DvrLocalRouter)
|
||||
|
||||
def _check_config_params(self):
|
||||
"""Check items in configuration files.
|
||||
|
||||
@ -375,7 +426,6 @@ class L3NATAgent(ha.AgentMixin,
|
||||
raise Exception(msg)
|
||||
|
||||
def _create_router(self, router_id, router):
|
||||
args = []
|
||||
kwargs = {
|
||||
'agent': self,
|
||||
'router_id': router_id,
|
||||
@ -385,9 +435,15 @@ class L3NATAgent(ha.AgentMixin,
|
||||
'interface_driver': self.driver,
|
||||
}
|
||||
|
||||
features = []
|
||||
if router.get('distributed'):
|
||||
features.append('distributed')
|
||||
kwargs['host'] = self.host
|
||||
|
||||
if router.get('ha'):
|
||||
features.append('ha')
|
||||
kwargs['state_change_callback'] = self.enqueue_state_change
|
||||
|
||||
if router.get('distributed') and router.get('ha'):
|
||||
# Case 1: If the router contains information about the HA interface
|
||||
# and if the requesting agent is a DVR_SNAT agent then go ahead
|
||||
@ -398,22 +454,12 @@ class L3NATAgent(ha.AgentMixin,
|
||||
# that needs to provision a router namespace because of a DVR
|
||||
# service port (e.g. DHCP). So go ahead and create a regular DVR
|
||||
# edge router.
|
||||
if (self.conf.agent_mode == lib_const.L3_AGENT_MODE_DVR_SNAT and
|
||||
router.get(lib_const.HA_INTERFACE_KEY) is not None):
|
||||
kwargs['state_change_callback'] = self.enqueue_state_change
|
||||
return dvr_edge_ha_router.DvrEdgeHaRouter(*args, **kwargs)
|
||||
if (not router.get(lib_const.HA_INTERFACE_KEY) or
|
||||
self.conf.agent_mode != lib_const.L3_AGENT_MODE_DVR_SNAT):
|
||||
features.remove('ha')
|
||||
kwargs.pop('state_change_callback')
|
||||
|
||||
if router.get('distributed'):
|
||||
if self.conf.agent_mode == lib_const.L3_AGENT_MODE_DVR_SNAT:
|
||||
return dvr_router.DvrEdgeRouter(*args, **kwargs)
|
||||
else:
|
||||
return dvr_local_router.DvrLocalRouter(*args, **kwargs)
|
||||
|
||||
if router.get('ha'):
|
||||
kwargs['state_change_callback'] = self.enqueue_state_change
|
||||
return ha_router.HaRouter(*args, **kwargs)
|
||||
|
||||
return legacy_router.LegacyRouter(*args, **kwargs)
|
||||
return self.router_factory.create(features, **kwargs)
|
||||
|
||||
@lockutils.synchronized('resize_greenpool')
|
||||
def _resize_process_pool(self):
|
||||
@ -486,7 +532,8 @@ class L3NATAgent(ha.AgentMixin,
|
||||
|
||||
def init_extension_manager(self, connection):
|
||||
l3_ext_manager.register_opts(self.conf)
|
||||
self.agent_api = l3_ext_api.L3AgentExtensionAPI(self.router_info)
|
||||
self.agent_api = l3_ext_api.L3AgentExtensionAPI(self.router_info,
|
||||
self.router_factory)
|
||||
self.l3_ext_manager = (
|
||||
l3_ext_manager.L3AgentExtensionsManager(self.conf))
|
||||
self.l3_ext_manager.initialize(
|
||||
|
@ -26,8 +26,9 @@ class L3AgentExtensionAPI(object):
|
||||
agent's RouterInfo object.
|
||||
'''
|
||||
|
||||
def __init__(self, router_info):
|
||||
def __init__(self, router_info, router_factory):
|
||||
self._router_info = router_info
|
||||
self._router_factory = router_factory
|
||||
|
||||
def _local_namespaces(self):
|
||||
local_ns_list = ip_lib.list_network_namespaces()
|
||||
@ -68,3 +69,9 @@ class L3AgentExtensionAPI(object):
|
||||
def get_router_info(self, router_id):
|
||||
"""Return RouterInfo for the given router id."""
|
||||
return self._router_info.get(router_id)
|
||||
|
||||
def register_router(self, features, router_cls):
|
||||
"""Register router class with the given features. This is for the
|
||||
plugin to ovrride with their own ``router_info`` class.
|
||||
"""
|
||||
self._router_factory.register(features, router_cls)
|
||||
|
@ -12,6 +12,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import abc
|
||||
import collections
|
||||
|
||||
import netaddr
|
||||
@ -19,6 +20,7 @@ from neutron_lib import constants as lib_constants
|
||||
from neutron_lib.exceptions import l3 as l3_exc
|
||||
from neutron_lib.utils import helpers
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
|
||||
from neutron._i18n import _
|
||||
from neutron.agent.l3 import namespaces
|
||||
@ -40,7 +42,8 @@ ADDRESS_SCOPE_MARK_ID_MAX = 2048
|
||||
DEFAULT_ADDRESS_SCOPE = "noscope"
|
||||
|
||||
|
||||
class RouterInfo(object):
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class BaseRouterInfo(object):
|
||||
|
||||
def __init__(self,
|
||||
agent,
|
||||
@ -51,16 +54,88 @@ class RouterInfo(object):
|
||||
use_ipv6=False):
|
||||
self.agent = agent
|
||||
self.router_id = router_id
|
||||
self.agent_conf = agent_conf
|
||||
self.ex_gw_port = None
|
||||
# Invoke the setter for establishing initial SNAT action
|
||||
self._snat_enabled = None
|
||||
self.fip_map = {}
|
||||
self.router = router
|
||||
self.agent_conf = agent_conf
|
||||
self.driver = interface_driver
|
||||
self.use_ipv6 = use_ipv6
|
||||
|
||||
self.internal_ports = []
|
||||
self.ns_name = None
|
||||
self.process_monitor = None
|
||||
|
||||
def initialize(self, process_monitor):
|
||||
"""Initialize the router on the system.
|
||||
|
||||
This differs from __init__ in that this method actually affects the
|
||||
system creating namespaces, starting processes, etc. The other merely
|
||||
initializes the python object. This separates in-memory object
|
||||
initialization from methods that actually go do stuff to the system.
|
||||
|
||||
:param process_monitor: The agent's process monitor instance.
|
||||
"""
|
||||
self.process_monitor = process_monitor
|
||||
|
||||
@property
|
||||
def router(self):
|
||||
return self._router
|
||||
|
||||
@router.setter
|
||||
def router(self, value):
|
||||
self._router = value
|
||||
if not self._router:
|
||||
return
|
||||
# enable_snat by default if it wasn't specified by plugin
|
||||
self._snat_enabled = self._router.get('enable_snat', True)
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete(self, agent):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def process(self, agent):
|
||||
"""Process updates to this router
|
||||
|
||||
This method is the point where the agent requests that updates be
|
||||
applied to this router.
|
||||
|
||||
:param agent: Passes the agent in order to send RPC messages.
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_ex_gw_port(self):
|
||||
return self.router.get('gw_port')
|
||||
|
||||
def get_gw_ns_name(self):
|
||||
return self.ns_name
|
||||
|
||||
def get_internal_device_name(self, port_id):
|
||||
return (INTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN]
|
||||
|
||||
def get_external_device_name(self, port_id):
|
||||
return (EXTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN]
|
||||
|
||||
def get_external_device_interface_name(self, ex_gw_port):
|
||||
return self.get_external_device_name(ex_gw_port['id'])
|
||||
|
||||
|
||||
class RouterInfo(BaseRouterInfo):
|
||||
|
||||
def __init__(self,
|
||||
agent,
|
||||
router_id,
|
||||
router,
|
||||
agent_conf,
|
||||
interface_driver,
|
||||
use_ipv6=False):
|
||||
super(RouterInfo, self).__init__(agent, router_id, router, agent_conf,
|
||||
interface_driver, use_ipv6)
|
||||
|
||||
self.ex_gw_port = None
|
||||
self.fip_map = {}
|
||||
self.pd_subnets = {}
|
||||
self.floating_ips = set()
|
||||
# Invoke the setter for establishing initial SNAT action
|
||||
self.router = router
|
||||
self.use_ipv6 = use_ipv6
|
||||
ns = self.create_router_namespace_object(
|
||||
router_id, agent_conf, interface_driver, use_ipv6)
|
||||
self.router_namespace = ns
|
||||
@ -75,8 +150,6 @@ class RouterInfo(object):
|
||||
self.initialize_address_scope_iptables()
|
||||
self.initialize_metadata_iptables()
|
||||
self.routes = []
|
||||
self.driver = interface_driver
|
||||
self.process_monitor = None
|
||||
# radvd is a neutron.agent.linux.ra.DaemonMonitor
|
||||
self.radvd = None
|
||||
self.centralized_port_forwarding_fip_set = set()
|
||||
@ -84,16 +157,7 @@ class RouterInfo(object):
|
||||
self.qos_gateway_ips = set()
|
||||
|
||||
def initialize(self, process_monitor):
|
||||
"""Initialize the router on the system.
|
||||
|
||||
This differs from __init__ in that this method actually affects the
|
||||
system creating namespaces, starting processes, etc. The other merely
|
||||
initializes the python object. This separates in-memory object
|
||||
initialization from methods that actually go do stuff to the system.
|
||||
|
||||
:param process_monitor: The agent's process monitor instance.
|
||||
"""
|
||||
self.process_monitor = process_monitor
|
||||
super(RouterInfo, self).initialize(process_monitor)
|
||||
self.radvd = ra.DaemonMonitor(self.router_id,
|
||||
self.ns_name,
|
||||
process_monitor,
|
||||
@ -107,33 +171,9 @@ class RouterInfo(object):
|
||||
return namespaces.RouterNamespace(
|
||||
router_id, agent_conf, iface_driver, use_ipv6)
|
||||
|
||||
@property
|
||||
def router(self):
|
||||
return self._router
|
||||
|
||||
@router.setter
|
||||
def router(self, value):
|
||||
self._router = value
|
||||
if not self._router:
|
||||
return
|
||||
# enable_snat by default if it wasn't specified by plugin
|
||||
self._snat_enabled = self._router.get('enable_snat', True)
|
||||
|
||||
def is_router_master(self):
|
||||
return True
|
||||
|
||||
def get_internal_device_name(self, port_id):
|
||||
return (INTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN]
|
||||
|
||||
def get_external_device_name(self, port_id):
|
||||
return (EXTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN]
|
||||
|
||||
def get_external_device_interface_name(self, ex_gw_port):
|
||||
return self.get_external_device_name(ex_gw_port['id'])
|
||||
|
||||
def get_gw_ns_name(self):
|
||||
return self.ns_name
|
||||
|
||||
def _update_routing_table(self, operation, route, namespace):
|
||||
cmd = ['ip', 'route', operation, 'to', route['destination'],
|
||||
'via', route['nexthop']]
|
||||
@ -158,9 +198,6 @@ class RouterInfo(object):
|
||||
LOG.debug("Removed route entry is '%s'", route)
|
||||
self.update_routing_table('delete', route)
|
||||
|
||||
def get_ex_gw_port(self):
|
||||
return self.router.get('gw_port')
|
||||
|
||||
def get_floating_ips(self):
|
||||
"""Filter Floating IPs to be hosted on this agent."""
|
||||
return self.router.get(lib_constants.FLOATINGIP_KEY, [])
|
||||
@ -1174,13 +1211,6 @@ class RouterInfo(object):
|
||||
|
||||
@common_utils.exception_logger()
|
||||
def process(self):
|
||||
"""Process updates to this router
|
||||
|
||||
This method is the point where the agent requests that updates be
|
||||
applied to this router.
|
||||
|
||||
:param agent: Passes the agent in order to send RPC messages.
|
||||
"""
|
||||
LOG.debug("Process updates, router %s", self.router['id'])
|
||||
self.centralized_port_forwarding_fip_set = set(self.router.get(
|
||||
'port_forwardings_fip_set', set()))
|
||||
|
@ -579,6 +579,10 @@ class TestDvrRouter(framework.L3AgentTestFramework):
|
||||
|
||||
self._add_fip_agent_gw_port_info_to_router(router,
|
||||
external_gw_port)
|
||||
# Router creation is delegated to router_factory. We have to
|
||||
# re-register here so that factory can find override agent mode
|
||||
# normally.
|
||||
self.agent._register_router_cls(self.agent.router_factory)
|
||||
return router
|
||||
|
||||
def _get_fip_agent_gw_port_for_router(
|
||||
|
@ -128,7 +128,7 @@ class QosExtensionBaseTestCase(test_agent.BasicRouterOperationsFramework):
|
||||
'L3AgentExtensionAPI.get_router_info').start()
|
||||
self.get_router_info.side_effect = _mock_get_router_info
|
||||
|
||||
self.agent_api = l3_ext_api.L3AgentExtensionAPI(None)
|
||||
self.agent_api = l3_ext_api.L3AgentExtensionAPI(None, None)
|
||||
self.fip_qos_ext.consume_api(self.agent_api)
|
||||
|
||||
|
||||
|
@ -129,7 +129,7 @@ class QosExtensionBaseTestCase(test_agent.BasicRouterOperationsFramework):
|
||||
'L3AgentExtensionAPI.get_router_info').start()
|
||||
self.get_router_info.side_effect = _mock_get_router_info
|
||||
|
||||
self.agent_api = l3_ext_api.L3AgentExtensionAPI(None)
|
||||
self.agent_api = l3_ext_api.L3AgentExtensionAPI(None, None)
|
||||
self.gw_ip_qos_ext.consume_api(self.agent_api)
|
||||
|
||||
|
||||
|
@ -90,7 +90,7 @@ class PortForwardingExtensionBaseTestCase(
|
||||
'L3AgentExtensionAPI.get_router_info').start()
|
||||
self.get_router_info.return_value = self.router_info
|
||||
|
||||
self.agent_api = l3_ext_api.L3AgentExtensionAPI(None)
|
||||
self.agent_api = l3_ext_api.L3AgentExtensionAPI(None, None)
|
||||
self.fip_pf_ext.consume_api(self.agent_api)
|
||||
|
||||
self.port_forwardings = [self.portforwarding1]
|
||||
|
@ -35,7 +35,9 @@ from testtools import matchers
|
||||
|
||||
from neutron.agent.common import resource_processing_queue
|
||||
from neutron.agent.l3 import agent as l3_agent
|
||||
from neutron.agent.l3 import dvr_edge_ha_router
|
||||
from neutron.agent.l3 import dvr_edge_router as dvr_router
|
||||
from neutron.agent.l3 import dvr_local_router
|
||||
from neutron.agent.l3 import dvr_router_base
|
||||
from neutron.agent.l3 import dvr_snat_ns
|
||||
from neutron.agent.l3 import ha_router
|
||||
@ -450,6 +452,67 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
||||
self.assertEqual(len(stale_router_ids), destroy_proxy.call_count)
|
||||
destroy_proxy.assert_has_calls(expected_calls, any_order=True)
|
||||
|
||||
def test__create_router_legacy_agent(self):
|
||||
router = {'distributed': False, 'ha': False}
|
||||
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
router_info = agent._create_router(_uuid(), router)
|
||||
|
||||
self.assertEqual(legacy_router.LegacyRouter, type(router_info))
|
||||
|
||||
def test__create_router_ha_agent(self):
|
||||
router = {'distributed': False, 'ha': True}
|
||||
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
router_info = agent._create_router(_uuid(), router)
|
||||
|
||||
self.assertEqual(ha_router.HaRouter, type(router_info))
|
||||
|
||||
def test__create_router_dvr_agent(self):
|
||||
router = {'distributed': True, 'ha': False}
|
||||
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
router_info = agent._create_router(_uuid(), router)
|
||||
|
||||
self.assertEqual(dvr_local_router.DvrLocalRouter, type(router_info))
|
||||
|
||||
def test__create_router_dvr_agent_with_dvr_snat_mode(self):
|
||||
router = {'distributed': True, 'ha': False}
|
||||
|
||||
self.conf.set_override('agent_mode',
|
||||
lib_constants.L3_AGENT_MODE_DVR_SNAT)
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
router_info = agent._create_router(_uuid(), router)
|
||||
|
||||
self.assertEqual(dvr_router.DvrEdgeRouter, type(router_info))
|
||||
|
||||
def test__create_router_dvr_ha_agent(self):
|
||||
router = {'distributed': True, 'ha': True}
|
||||
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
router_info = agent._create_router(_uuid(), router)
|
||||
|
||||
self.assertEqual(dvr_local_router.DvrLocalRouter, type(router_info))
|
||||
|
||||
def test__create_router_dvr_ha_agent_with_dvr_snat_mode(self):
|
||||
router = {'distributed': True, 'ha': True,
|
||||
lib_constants.HA_INTERFACE_KEY: None}
|
||||
|
||||
self.conf.set_override('agent_mode',
|
||||
lib_constants.L3_AGENT_MODE_DVR_SNAT)
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
router_info = agent._create_router(_uuid(), router)
|
||||
|
||||
self.assertEqual(dvr_router.DvrEdgeRouter, type(router_info))
|
||||
|
||||
router = {'distributed': True, 'ha': True,
|
||||
lib_constants.HA_INTERFACE_KEY: True}
|
||||
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
router_info = agent._create_router(_uuid(), router)
|
||||
|
||||
self.assertEqual(dvr_edge_ha_router.DvrEdgeHaRouter, type(router_info))
|
||||
|
||||
def test_router_info_create(self):
|
||||
id = _uuid()
|
||||
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
|
||||
|
@ -18,8 +18,9 @@ import mock
|
||||
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from neutron.agent.l3 import agent
|
||||
from neutron.agent.l3 import l3_agent_extension_api as l3_agent_api
|
||||
from neutron.agent.l3 import router_info
|
||||
from neutron.agent.l3 import router_info as l3router
|
||||
from neutron.agent.linux import ip_lib
|
||||
from neutron.conf.agent import common as config
|
||||
from neutron.conf.agent.l3 import config as l3_config
|
||||
@ -38,7 +39,7 @@ class TestL3AgentExtensionApi(base.BaseTestCase):
|
||||
'agent_conf': self.conf,
|
||||
'interface_driver': mock.ANY,
|
||||
'use_ipv6': mock.ANY}
|
||||
ri = router_info.RouterInfo(mock.Mock(), self.router_id, **ri_kwargs)
|
||||
ri = l3router.RouterInfo(mock.Mock(), self.router_id, **ri_kwargs)
|
||||
ri.internal_ports = ports
|
||||
return {ri.router_id: ri}, ri
|
||||
|
||||
@ -51,7 +52,7 @@ class TestL3AgentExtensionApi(base.BaseTestCase):
|
||||
'list_network_namespaces') as mock_list_netns:
|
||||
|
||||
mock_list_netns.return_value = []
|
||||
api_object = l3_agent_api.L3AgentExtensionAPI(router_info)
|
||||
api_object = l3_agent_api.L3AgentExtensionAPI(router_info, None)
|
||||
router = api_object.get_router_hosting_port(port_ids[0])
|
||||
|
||||
mock_list_netns.assert_called_once_with()
|
||||
@ -65,7 +66,7 @@ class TestL3AgentExtensionApi(base.BaseTestCase):
|
||||
with mock.patch.object(ip_lib,
|
||||
'list_network_namespaces') as mock_list_netns:
|
||||
mock_list_netns.return_value = [ri.ns_name]
|
||||
api_object = l3_agent_api.L3AgentExtensionAPI(router_info)
|
||||
api_object = l3_agent_api.L3AgentExtensionAPI(router_info, None)
|
||||
router = api_object.get_router_hosting_port(port_ids[0])
|
||||
self.assertEqual(ri, router)
|
||||
|
||||
@ -75,7 +76,7 @@ class TestL3AgentExtensionApi(base.BaseTestCase):
|
||||
with mock.patch.object(ip_lib,
|
||||
'list_network_namespaces') as mock_list_netns:
|
||||
mock_list_netns.return_value = [ri.ns_name]
|
||||
api_object = l3_agent_api.L3AgentExtensionAPI(router_info)
|
||||
api_object = l3_agent_api.L3AgentExtensionAPI(router_info, None)
|
||||
routers = api_object.get_routers_in_project(self.project_id)
|
||||
self.assertEqual([ri], routers)
|
||||
|
||||
@ -85,7 +86,7 @@ class TestL3AgentExtensionApi(base.BaseTestCase):
|
||||
with mock.patch.object(ip_lib,
|
||||
'list_network_namespaces') as mock_list_netns:
|
||||
mock_list_netns.return_value = [ri.ns_name]
|
||||
api_object = l3_agent_api.L3AgentExtensionAPI(router_info)
|
||||
api_object = l3_agent_api.L3AgentExtensionAPI(router_info, None)
|
||||
router_in_ns = api_object.is_router_in_namespace(ri.router_id)
|
||||
self.assertTrue(router_in_ns)
|
||||
|
||||
@ -95,17 +96,32 @@ class TestL3AgentExtensionApi(base.BaseTestCase):
|
||||
with mock.patch.object(ip_lib,
|
||||
'list_network_namespaces') as mock_list_netns:
|
||||
mock_list_netns.return_value = [uuidutils.generate_uuid()]
|
||||
api_object = l3_agent_api.L3AgentExtensionAPI(router_info)
|
||||
api_object = l3_agent_api.L3AgentExtensionAPI(router_info, None)
|
||||
router_in_ns = api_object.is_router_in_namespace(ri.router_id)
|
||||
self.assertFalse(router_in_ns)
|
||||
|
||||
def test_get_router_info(self):
|
||||
router_info, ri = self._prepare_router_data()
|
||||
api_object = l3_agent_api.L3AgentExtensionAPI(router_info)
|
||||
api_object = l3_agent_api.L3AgentExtensionAPI(router_info, None)
|
||||
self.assertEqual(ri, api_object.get_router_info(self.router_id))
|
||||
|
||||
def test_get_router_info_nonexistent(self):
|
||||
router_info, ri = self._prepare_router_data()
|
||||
api_object = l3_agent_api.L3AgentExtensionAPI(router_info)
|
||||
api_object = l3_agent_api.L3AgentExtensionAPI(router_info, None)
|
||||
self.assertIsNone(
|
||||
api_object.get_router_info(uuidutils.generate_uuid()))
|
||||
|
||||
def test_register_router(self):
|
||||
router_info, ri = self._prepare_router_data()
|
||||
router_info_cls = l3router.BaseRouterInfo
|
||||
router_factory = agent.RouterFactory()
|
||||
api_object = l3_agent_api.L3AgentExtensionAPI(router_info,
|
||||
router_factory)
|
||||
self.assertIsNone(
|
||||
api_object.register_router([], router_info_cls))
|
||||
self.assertIsNone(
|
||||
api_object.register_router(['ha'], router_info_cls))
|
||||
self.assertIsNone(
|
||||
api_object.register_router(['distributed'], router_info_cls))
|
||||
self.assertIsNone(
|
||||
api_object.register_router(['ha', 'distributed'], router_info_cls))
|
||||
|
@ -75,7 +75,7 @@ class L3LoggingExtBaseTestCase(test_agent.BasicRouterOperationsFramework):
|
||||
'neutron.agent.l3.l3_agent_extension_api.'
|
||||
'L3AgentExtensionAPI.get_router_info').start()
|
||||
self.get_router_info.side_effect = _mock_get_router_info
|
||||
self.agent_api = l3_ext_api.L3AgentExtensionAPI(None)
|
||||
self.agent_api = l3_ext_api.L3AgentExtensionAPI(None, None)
|
||||
mock.patch(
|
||||
'neutron.manager.NeutronManager.load_class_for_provider').start()
|
||||
|
||||
|
@ -0,0 +1,10 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
A new parameter ``router_factory`` has been added to
|
||||
``neutron.agent.l3.L3AgentExtensionAPI``. Developers can register
|
||||
``neutron.agent.l3.agent.RouterInfo`` class and delegate it for
|
||||
``RouterInfo`` creation.
|
||||
|
||||
Extensions can extend ``RouterInfo`` itself which correspond to each
|
||||
features (ha, distribtued, ha + distributed).
|
Loading…
Reference in New Issue
Block a user