diff --git a/doc/source/admin/config-az.rst b/doc/source/admin/config-az.rst index 0d49fa2a9f9..45269378ad0 100644 --- a/doc/source/admin/config-az.rst +++ b/doc/source/admin/config-az.rst @@ -95,7 +95,6 @@ To confirm the agent's availability zone: | binary | neutron-l3-agent | | configurations | agent_mode='legacy', ex_gw_ports='2', | | | floating_ips='0', | - | | gateway_external_network_id='', | | | handle_internal_only_routers='True', | | | interface_driver='openvswitch', interfaces='4', | | | log_agent_heartbeats='False', routers='2' | diff --git a/neutron/agent/l3/agent.py b/neutron/agent/l3/agent.py index aaaf4476a2c..af0b5cfc3d3 100644 --- a/neutron/agent/l3/agent.py +++ b/neutron/agent/l3/agent.py @@ -404,9 +404,6 @@ class L3NATAgent(ha.AgentMixin, def _fetch_external_net_id(self, force=False): """Find UUID of single external network for this agent.""" - if self.conf.gateway_external_network_id: - return self.conf.gateway_external_network_id - if not force and self.target_ex_net_id: return self.target_ex_net_id @@ -417,8 +414,7 @@ class L3NATAgent(ha.AgentMixin, except oslo_messaging.RemoteError as e: with excutils.save_and_reraise_exception() as ctx: if e.exc_type == 'TooManyExternalNetworks': - # At this point we know gateway_external_network_id is not - # defined. Since there are more than one external network, + # Since there are more than one external network, # we will handle all of them ctx.reraise = False @@ -909,8 +905,6 @@ class L3NATAgentWithStateReport(L3NATAgent): 'agent_mode': self.conf.agent_mode, 'handle_internal_only_routers': self.conf.handle_internal_only_routers, - 'gateway_external_network_id': - self.conf.gateway_external_network_id, 'interface_driver': self.conf.interface_driver, 'log_agent_heartbeats': self.conf.AGENT.log_agent_heartbeats}, 'start_flag': True, diff --git a/neutron/cmd/upgrade_checks/checks.py b/neutron/cmd/upgrade_checks/checks.py index 3267b863635..07439a101d0 100644 --- a/neutron/cmd/upgrade_checks/checks.py +++ b/neutron/cmd/upgrade_checks/checks.py @@ -37,6 +37,8 @@ class CoreChecks(base.BaseChecks): def get_checks(self): return [ + (_("Gateway external network"), + self.gateway_external_network_check), (_("External network bridge"), self.external_network_bridge_check), (_("Worker counts configured"), self.worker_count_check) @@ -89,3 +91,35 @@ class CoreChecks(base.BaseChecks): upgradecheck.Code.SUCCESS, _("L3 agents are using integration bridge to connect external " "gateways")) + + @staticmethod + def gateway_external_network_check(checker): + if not cfg.CONF.database.connection: + return upgradecheck.Result( + upgradecheck.Code.WARNING, + _("Database connection string is not set. Check of usage of " + "'gateway_external_network_id' config option in L3 agents " + "can't be done")) + + agents_with_gateway_external_net = [] + for agent in get_l3_agents(): + config_string = agent.get('configurations') + if not config_string: + continue + config = jsonutils.loads(config_string) + if config.get("gateway_external_network_id"): + agents_with_gateway_external_net.append(agent.get("host")) + + if agents_with_gateway_external_net: + agents_list = ", ".join(agents_with_gateway_external_net) + return upgradecheck.Result( + upgradecheck.Code.WARNING, + _("L3 agents on hosts %s are still using " + "'gateway_external_network_id' config option to configure " + "external network used as gateway for routers. " + "This option is now removed and routers on those hosts can " + "use multiple external networks as gateways.") % agents_list) + else: + return upgradecheck.Result( + upgradecheck.Code.SUCCESS, + _("L3 agents can use multiple networks as external gateways.")) diff --git a/neutron/conf/agent/l3/config.py b/neutron/conf/agent/l3/config.py index e82d5903b14..8f52ff3a72e 100644 --- a/neutron/conf/agent/l3/config.py +++ b/neutron/conf/agent/l3/config.py @@ -56,12 +56,6 @@ OPTS = [ "single agent in a Neutron deployment, and may be " "False for all agents if all routers must have an " "external network gateway.")), - cfg.StrOpt('gateway_external_network_id', default='', - help=_("To allow the L3 agent to support multiple external " - "networks, gateway_external_network_id must be left " - "empty. Otherwise this value should be set to the UUID " - "of the single external network to be used."), - deprecated_for_removal=True), cfg.StrOpt('ipv6_gateway', default='', help=_("With IPv6, the network used for the external gateway " "does not need to have an associated subnet, since the " diff --git a/neutron/db/l3_agentschedulers_db.py b/neutron/db/l3_agentschedulers_db.py index a999433a365..8cdf89716a8 100644 --- a/neutron/db/l3_agentschedulers_db.py +++ b/neutron/db/l3_agentschedulers_db.py @@ -467,14 +467,10 @@ class L3AgentSchedulerDbMixin(l3agentscheduler.L3AgentSchedulerPluginBase, handle_internal_only_routers = agent_conf.get( 'handle_internal_only_routers', True) - gateway_external_network_id = agent_conf.get( - 'gateway_external_network_id', None) ex_net_id = (sync_router['external_gateway_info'] or {}).get( 'network_id') - if ((not ex_net_id and not handle_internal_only_routers) or - (ex_net_id and gateway_external_network_id and - ex_net_id != gateway_external_network_id)): + if not ex_net_id and not handle_internal_only_routers: continue candidates.append(l3_agent) diff --git a/neutron/db/l3_db.py b/neutron/db/l3_db.py index 41664f1ec5d..7b72bae860f 100644 --- a/neutron/db/l3_db.py +++ b/neutron/db/l3_db.py @@ -16,7 +16,6 @@ import functools import random import netaddr -from neutron_lib.api.definitions import external_net as extnet_apidef from neutron_lib.api.definitions import l3 as l3_apidef from neutron_lib.api import extensions from neutron_lib.api import validators @@ -277,85 +276,18 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, r = router['router'] gw_info = r.pop(EXTERNAL_GW_INFO, constants.ATTR_NOT_SPECIFIED) original = self.get_router(context, id) - # check whether router needs and can be rescheduled to the proper - # l3 agent (associated with given external network); - # do check before update in DB as an exception will be raised - # in case no proper l3 agent found if gw_info != constants.ATTR_NOT_SPECIFIED: - candidates = self._check_router_needs_rescheduling( - context, id, gw_info) # Update the gateway outside of the DB update since it involves L2 # calls that don't make sense to rollback and may cause deadlocks # in a transaction. self._update_router_gw_info(context, id, gw_info) - else: - candidates = None router_db = self._update_router_db(context, id, r) - if candidates: - l3_plugin = directory.get_plugin(plugin_constants.L3) - l3_plugin.reschedule_router(context, id, candidates) updated = self._make_router_dict(router_db) registry.notify(resources.ROUTER, events.AFTER_UPDATE, self, context=context, router_id=id, old_router=original, router=updated, request_attrs=r, router_db=router_db) return updated - def _check_router_needs_rescheduling(self, context, router_id, gw_info): - """Checks whether router's l3 agent can handle the given network - - :return: list of candidate agents if rescheduling needed, - None otherwise; raises exception if there is no eligible l3 agent - associated with target external network - """ - # TODO(obondarev): rethink placement of this func as l3 db manager is - # not really a proper place for agent scheduling stuff - network_id = gw_info.get('network_id') if gw_info else None - if not network_id: - return - - nets = self._core_plugin.get_networks( - context, {extnet_apidef.EXTERNAL: [True]}) - # nothing to do if there is only one external network - if len(nets) <= 1: - return - - # first get plugin supporting l3 agent scheduling - # (either l3 service plugin or core_plugin) - l3_plugin = directory.get_plugin(plugin_constants.L3) - if (not extensions.is_extension_supported( - l3_plugin, - constants.L3_AGENT_SCHEDULER_EXT_ALIAS) or - l3_plugin.router_scheduler is None): - # that might mean that we are dealing with non-agent-based - # implementation of l3 services - return - - if not l3_plugin.router_supports_scheduling(context, router_id): - return - cur_agents = l3_plugin.list_l3_agents_hosting_router( - context, router_id)['agents'] - for agent in cur_agents: - ext_net_id = agent['configurations'].get( - 'gateway_external_network_id') - if ext_net_id == network_id or not ext_net_id: - return - - # otherwise find l3 agent with matching gateway_external_network_id - active_agents = l3_plugin.get_l3_agents(context, active=True) - router = { - 'id': router_id, - 'external_gateway_info': {'network_id': network_id} - } - candidates = l3_plugin.get_l3_agent_candidates(context, - router, - active_agents) - if not candidates: - msg = (_('No eligible l3 agent associated with external network ' - '%s found') % network_id) - raise n_exc.BadRequest(resource='router', msg=msg) - - return candidates - def _create_router_gw_port(self, context, router, network_id, ext_ips): # Port has no 'tenant-id', as it is hidden from user port_data = {'tenant_id': '', # intentionally not set diff --git a/neutron/tests/common/helpers.py b/neutron/tests/common/helpers.py index 04e8a039ebb..0ee92cea981 100644 --- a/neutron/tests/common/helpers.py +++ b/neutron/tests/common/helpers.py @@ -56,7 +56,7 @@ class FakePlugin(agents_db.AgentDbMixin): def _get_l3_agent_dict(host, agent_mode, internal_only=True, - ext_net_id='', az=DEFAULT_AZ): + az=DEFAULT_AZ): return { 'agent_type': constants.AGENT_TYPE_L3, 'binary': 'neutron-l3-agent', @@ -64,8 +64,7 @@ def _get_l3_agent_dict(host, agent_mode, internal_only=True, 'topic': topics.L3_AGENT, 'availability_zone': az, 'configurations': {'agent_mode': agent_mode, - 'handle_internal_only_routers': internal_only, - 'gateway_external_network_id': ext_net_id}} + 'handle_internal_only_routers': internal_only}} def _register_agent(agent, plugin=None): @@ -78,8 +77,8 @@ def _register_agent(agent, plugin=None): def register_l3_agent(host=HOST, agent_mode=constants.L3_AGENT_MODE_LEGACY, - internal_only=True, ext_net_id='', az=DEFAULT_AZ): - agent = _get_l3_agent_dict(host, agent_mode, internal_only, ext_net_id, az) + internal_only=True, az=DEFAULT_AZ): + agent = _get_l3_agent_dict(host, agent_mode, internal_only, az) return _register_agent(agent) diff --git a/neutron/tests/functional/scheduler/test_l3_agent_scheduler.py b/neutron/tests/functional/scheduler/test_l3_agent_scheduler.py index bef9a18165e..c91a494462a 100644 --- a/neutron/tests/functional/scheduler/test_l3_agent_scheduler.py +++ b/neutron/tests/functional/scheduler/test_l3_agent_scheduler.py @@ -53,8 +53,7 @@ class L3SchedulerBaseTest(test_db_base_plugin_v2.NeutronDbPluginV2TestCase): def _create_l3_agent(self, host, context, agent_mode='legacy', state=True, ext_net_id=''): - agent = helpers.register_l3_agent(host, agent_mode, - ext_net_id=ext_net_id) + agent = helpers.register_l3_agent(host, agent_mode) helpers.set_agent_admin_state(agent.id, state) return agent diff --git a/neutron/tests/unit/agent/l3/test_agent.py b/neutron/tests/unit/agent/l3/test_agent.py index 77dcfd5ac5f..7921a64aaa6 100644 --- a/neutron/tests/unit/agent/l3/test_agent.py +++ b/neutron/tests/unit/agent/l3/test_agent.py @@ -2956,22 +2956,6 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework): agent._process_router_if_compatible(router) self.assertIn(router['id'], agent.router_info) - def test_process_router_if_compatible_with_ext_net_in_conf(self): - agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) - self.plugin_api.get_external_network_id.return_value = 'aaa' - - router = {'id': _uuid(), - 'routes': [], - 'admin_state_up': True, - 'external_gateway_info': {'network_id': 'bbb'}} - - agent.router_info = {} - self.conf.set_override('gateway_external_network_id', 'aaa') - self.assertRaises(l3_exc.RouterNotCompatibleWithAgent, - agent._process_router_if_compatible, - router) - self.assertNotIn(router['id'], agent.router_info) - def test_nonexistent_interface_driver(self): self.conf.set_override('interface_driver', None) self.assertRaises(SystemExit, l3_agent.L3NATAgent, diff --git a/neutron/tests/unit/cmd/upgrade_checks/test_checks.py b/neutron/tests/unit/cmd/upgrade_checks/test_checks.py index 9d7f17562bd..fd018bd4ba9 100644 --- a/neutron/tests/unit/cmd/upgrade_checks/test_checks.py +++ b/neutron/tests/unit/cmd/upgrade_checks/test_checks.py @@ -79,3 +79,30 @@ class TestChecks(base.BaseTestCase): self.assertIn('Host B', result.details) self.assertNotIn('Host A', result.details) self.assertNotIn('Host C', result.details) + + def test_gateway_external_network_check_good(self): + agents = [ + {'host': 'Host A', 'configurations': '{}'}, + {'host': 'Host B', + 'configurations': '{"gateway_external_network_id": ""}'} + ] + with mock.patch.object(checks, "get_l3_agents", return_value=agents): + result = checks.CoreChecks.gateway_external_network_check( + mock.Mock()) + self.assertEqual(Code.SUCCESS, result.code) + + def test_gateway_external_network_check_bad(self): + agents = [ + {'host': 'Host A', 'configurations': '{}'}, + {'host': 'Host B', + 'configurations': '{"gateway_external_network_id": "net-uuid"}'}, + {'host': 'Host C', + 'configurations': '{"gateway_external_network_id": ""}'} + ] + with mock.patch.object(checks, "get_l3_agents", return_value=agents): + result = checks.CoreChecks.gateway_external_network_check( + mock.Mock()) + self.assertEqual(Code.WARNING, result.code) + self.assertIn('Host B', result.details) + self.assertNotIn('Host A', result.details) + self.assertNotIn('Host C', result.details) diff --git a/neutron/tests/unit/extensions/test_l3.py b/neutron/tests/unit/extensions/test_l3.py index 5c6dbb7d2ee..fcf919cb878 100644 --- a/neutron/tests/unit/extensions/test_l3.py +++ b/neutron/tests/unit/extensions/test_l3.py @@ -58,7 +58,6 @@ from neutron.db import models_v2 from neutron.extensions import l3 from neutron.services.revisions import revision_plugin from neutron.tests import base -from neutron.tests.common import helpers from neutron.tests.unit.api import test_extensions from neutron.tests.unit.api.v2 import test_base from neutron.tests.unit.db import test_db_base_plugin_v2 @@ -4017,8 +4016,6 @@ class L3AgentDbTestCaseBase(L3NatTestCaseMixin): class L3BaseForIntTests(test_db_base_plugin_v2.NeutronDbPluginV2TestCase): - mock_rescheduling = True - def setUp(self, plugin=None, ext_mgr=None, service_plugins=None): if not plugin: plugin = 'neutron.tests.unit.extensions.test_l3.TestL3NatIntPlugin' @@ -4026,10 +4023,6 @@ class L3BaseForIntTests(test_db_base_plugin_v2.NeutronDbPluginV2TestCase): cfg.CONF.set_default('allow_overlapping_ips', True) ext_mgr = ext_mgr or L3TestExtensionManager() - if self.mock_rescheduling: - mock.patch('%s._check_router_needs_rescheduling' % plugin, - new=lambda *a: False).start() - super(L3BaseForIntTests, self).setUp(plugin=plugin, ext_mgr=ext_mgr, service_plugins=service_plugins) @@ -4067,7 +4060,6 @@ class L3NatDBIntAgentSchedulingTestCase(L3BaseForIntTests, def setUp(self, plugin='neutron.tests.unit.extensions.test_l3.' 'TestL3NatIntAgentSchedulingPlugin', ext_mgr=None, service_plugins=None): - self.mock_rescheduling = False super(L3NatDBIntAgentSchedulingTestCase, self).setUp( plugin, ext_mgr, service_plugins) self.adminContext = context.get_admin_context() @@ -4079,55 +4071,6 @@ class L3NatDBIntAgentSchedulingTestCase(L3BaseForIntTests, self.assertEqual(1, len(agents)) self.assertEqual(agents[0]['host'], agent_host) - def test_update_gateway_agent_exists_supporting_network(self): - with self.router() as r, self.subnet() as s1, self.subnet() as s2: - self._set_net_external(s1['subnet']['network_id']) - l3_rpc_cb = l3_rpc.L3RpcCallback() - helpers.register_l3_agent( - host='host1', - ext_net_id=s1['subnet']['network_id']) - helpers.register_l3_agent( - host='host2', internal_only=False, - ext_net_id=s2['subnet']['network_id']) - l3_rpc_cb.get_router_ids(self.adminContext, - host='host1') - self._assert_router_on_agent(r['router']['id'], 'host1') - - self._add_external_gateway_to_router( - r['router']['id'], - s1['subnet']['network_id']) - self._assert_router_on_agent(r['router']['id'], 'host1') - - self._set_net_external(s2['subnet']['network_id']) - self._add_external_gateway_to_router( - r['router']['id'], - s2['subnet']['network_id']) - self._assert_router_on_agent(r['router']['id'], 'host2') - - def test_update_gateway_agent_exists_supporting_multiple_network(self): - with self.router() as r, self.subnet() as s1, self.subnet() as s2: - self._set_net_external(s1['subnet']['network_id']) - l3_rpc_cb = l3_rpc.L3RpcCallback() - helpers.register_l3_agent( - host='host1', - ext_net_id=s1['subnet']['network_id']) - helpers.register_l3_agent( - host='host2', internal_only=False, ext_net_id='') - l3_rpc_cb.get_router_ids(self.adminContext, - host='host1') - self._assert_router_on_agent(r['router']['id'], 'host1') - - self._add_external_gateway_to_router( - r['router']['id'], - s1['subnet']['network_id']) - self._assert_router_on_agent(r['router']['id'], 'host1') - - self._set_net_external(s2['subnet']['network_id']) - self._add_external_gateway_to_router( - r['router']['id'], - s2['subnet']['network_id']) - self._assert_router_on_agent(r['router']['id'], 'host2') - def test_router_update_gateway_scheduling_not_supported(self): plugin = directory.get_plugin(plugin_constants.L3) mock.patch.object(plugin, 'router_supports_scheduling', @@ -4144,17 +4087,6 @@ class L3NatDBIntAgentSchedulingTestCase(L3BaseForIntTests, r['router']['id'], s1['subnet']['network_id']) - def test_router_update_gateway_no_eligible_l3_agent(self): - with self.router() as r: - with self.subnet() as s1: - with self.subnet() as s2: - self._set_net_external(s1['subnet']['network_id']) - self._set_net_external(s2['subnet']['network_id']) - self._add_external_gateway_to_router( - r['router']['id'], - s1['subnet']['network_id'], - expected_code=exc.HTTPBadRequest.code) - class L3RpcCallbackTestCase(base.BaseTestCase): diff --git a/releasenotes/notes/remove-gateway_external_network_id-config-option-c7aabf2f63004b41.yaml b/releasenotes/notes/remove-gateway_external_network_id-config-option-c7aabf2f63004b41.yaml new file mode 100644 index 00000000000..9d682781ede --- /dev/null +++ b/releasenotes/notes/remove-gateway_external_network_id-config-option-c7aabf2f63004b41.yaml @@ -0,0 +1,6 @@ +--- +upgrade: + - | + The ``gateway_external_network_id`` config option has been removed. + Systems where this option was set will now be able to support multiple + external networks for routers.