diff --git a/etc/l3_agent.ini b/etc/l3_agent.ini index 46cafa3952c..7ad23531b96 100644 --- a/etc/l3_agent.ini +++ b/etc/l3_agent.ini @@ -29,3 +29,15 @@ root_helper = sudo # If use_namespaces is set as False then the agent can only configure one router. # This is done by setting the specific router_id. # router_id = + +# Each L3 agent can be associated with at most one external network. This +# value should be set to the UUID of that external network. If empty, +# the agent will enforce that only a single external networks exists and +# use that external network id +# gateway_external_net_id = + +# Indicates that this L3 agent should also handle routers that do not have +# an external network gateway configured. This option should be True only +# for a single agent in a Quantum deployment, and may be False for all agents +# if all routers must have an external network gateway +# handle_internal_only_routers = True diff --git a/quantum/agent/l3_agent.py b/quantum/agent/l3_agent.py index 9c5a0447bd7..902d60c62f6 100644 --- a/quantum/agent/l3_agent.py +++ b/quantum/agent/l3_agent.py @@ -90,7 +90,13 @@ class L3NATAgent(object): help="Allow overlapping IP."), cfg.StrOpt('router_id', default='', help="If namespaces is disabled, the l3 agent can only" - " confgure a router that has the matching router ID.") + " confgure a router that has the matching router ID."), + cfg.BoolOpt('handle_internal_only_routers', + default=True, + help="Agent should implement routers with no gateway"), + cfg.StrOpt('gateway_external_network_id', default='', + help="UUID of external network for routers implemented " + "by the agents."), ] def __init__(self, conf): @@ -171,13 +177,37 @@ class L3NATAgent(object): time.sleep(self.polling_interval) + def _fetch_external_net_id(self): + """Find UUID of single external network for this agent""" + if self.conf.gateway_external_network_id: + return self.conf.gateway_external_network_id + + params = {'router:external': True} + ex_nets = self.qclient.list_networks(**params)['networks'] + if len(ex_nets) > 1: + raise Exception("must configure 'external_network_id' if " + "Quantum has more than one external network.") + if len(ex_nets) == 0: + return None + return ex_nets[0]['id'] + def do_single_loop(self): prev_router_ids = set(self.router_info) cur_router_ids = set() + target_ex_net_id = self._fetch_external_net_id() + # identify and update new or modified routers for r in self.qclient.list_routers()['routers']: - #FIXME(danwent): handle admin state + if not r['admin_state_up']: + continue + + ex_net_id = r['external_gateway_info'].get('network_id', None) + if not ex_net_id and not self.conf.handle_internal_only_routers: + continue + + if ex_net_id and ex_net_id != target_ex_net_id: + continue # If namespaces are disabled, only process the router associated # with the configured agent id. diff --git a/quantum/tests/unit/test_l3_agent.py b/quantum/tests/unit/test_l3_agent.py index 587f611fe9e..810b6edf066 100644 --- a/quantum/tests/unit/test_l3_agent.py +++ b/quantum/tests/unit/test_l3_agent.py @@ -237,8 +237,12 @@ class TestBasicRouterOperations(unittest.TestCase): self.client_inst.list_ports.return_value = {'ports': []} + self.client_inst.list_networks.return_value = {'networks': []} + self.client_inst.list_routers.return_value = {'routers': [ - {'id': _uuid()}]} + {'id': _uuid(), + 'admin_state_up': True, + 'external_gateway_info': {}}]} agent.do_single_loop() self.client_inst.list_routers.return_value = {'routers': []}