diff --git a/neutron/db/l3_db.py b/neutron/db/l3_db.py index a9afb76ef53..7405917c163 100644 --- a/neutron/db/l3_db.py +++ b/neutron/db/l3_db.py @@ -163,6 +163,8 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, def _create_router_db(self, context, router, tenant_id): """Create the DB object.""" + registry.notify(resources.ROUTER, events.BEFORE_CREATE, + self, context=context, router=router) with context.session.begin(subtransactions=True): # pre-generate id so it will be available when # configuring external gw port diff --git a/neutron/db/l3_dvr_db.py b/neutron/db/l3_dvr_db.py index c7cf7472a72..0aca1c02379 100644 --- a/neutron/db/l3_dvr_db.py +++ b/neutron/db/l3_dvr_db.py @@ -79,17 +79,17 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin, resources.ROUTER, events.AFTER_CREATE) registry.subscribe(n._delete_dvr_internal_ports, resources.ROUTER_GATEWAY, events.AFTER_DELETE) + registry.subscribe(n._set_distributed_flag, + resources.ROUTER, events.PRECOMMIT_CREATE) + registry.subscribe(n._handle_distributed_migration, + resources.ROUTER, events.PRECOMMIT_UPDATE) return n - def _create_router_db(self, context, router, tenant_id): - """Create a router db object with dvr additions.""" - with context.session.begin(subtransactions=True): - router_db = super( - L3_NAT_with_dvr_db_mixin, self)._create_router_db( - context, router, tenant_id) - router['distributed'] = is_distributed_router(router) - self._process_extra_attr_router_create(context, router_db, router) - return router_db + def _set_distributed_flag(self, resource, event, trigger, context, + router, router_db, **kwargs): + """Event handler to set distributed flag on creation.""" + router['distributed'] = is_distributed_router(router) + self._process_extra_attr_router_create(context, router_db, router) def _validate_router_migration(self, context, router_db, router_res): """Allow centralized -> distributed state transition only.""" @@ -123,28 +123,25 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin, raise l3.RouterInUse(router_id=router_db['id'], reason=e) - def _update_router_db(self, context, router_id, data): - with context.session.begin(subtransactions=True): - router_db = super( - L3_NAT_with_dvr_db_mixin, self)._update_router_db( - context, router_id, data) - migrating_to_distributed = ( - not router_db.extra_attributes.distributed and - data.get('distributed') is True) - self._validate_router_migration(context, router_db, data) - router_db.extra_attributes.update(data) - if data.get('distributed'): - self._migrate_router_ports( - context, router_db, - old_owner=const.DEVICE_OWNER_ROUTER_INTF, - new_owner=const.DEVICE_OWNER_DVR_INTERFACE) - if migrating_to_distributed: - cur_agents = self.list_l3_agents_hosting_router( - context, router_db['id'])['agents'] - for agent in cur_agents: - self._unbind_router(context, router_db['id'], - agent['id']) - return router_db + def _handle_distributed_migration(self, resource, event, trigger, context, + router_id, router, router_db, **kwargs): + """Event handler for router update migration to distributed.""" + migrating_to_distributed = ( + not router_db.extra_attributes.distributed and + router.get('distributed') is True) + self._validate_router_migration(context, router_db, router) + router_db.extra_attributes.update(router) + if router.get('distributed'): + self._migrate_router_ports( + context, router_db, + old_owner=const.DEVICE_OWNER_ROUTER_INTF, + new_owner=const.DEVICE_OWNER_DVR_INTERFACE) + if migrating_to_distributed: + cur_agents = self.list_l3_agents_hosting_router( + context, router_db['id'])['agents'] + for agent in cur_agents: + self._unbind_router(context, router_db['id'], + agent['id']) def _create_snat_interfaces_after_change(self, resource, event, trigger, context, router_id, router, diff --git a/neutron/services/l3_router/service_providers/driver_controller.py b/neutron/services/l3_router/service_providers/driver_controller.py index 83e0828205f..9dcb14d9c73 100644 --- a/neutron/services/l3_router/service_providers/driver_controller.py +++ b/neutron/services/l3_router/service_providers/driver_controller.py @@ -47,6 +47,8 @@ class DriverController(object): self._stm.add_provider_configuration( constants.L3_ROUTER_NAT, _LegacyPlusProviderConfiguration()) self._load_drivers() + registry.subscribe(self._check_router_request, + resources.ROUTER, events.BEFORE_CREATE) registry.subscribe(self._set_router_provider, resources.ROUTER, events.PRECOMMIT_CREATE) registry.subscribe(self._update_router_provider, @@ -67,6 +69,12 @@ class DriverController(object): self._flavor_plugin_ref = directory.get_plugin(constants.FLAVORS) return self._flavor_plugin_ref + def _check_router_request(self, resource, event, trigger, context, + router, **kwargs): + """Validates that API request is sane (flags compat with flavor).""" + drv = self._get_provider_for_create(context, router) + _ensure_driver_supports_request(drv, router) + def _set_router_provider(self, resource, event, trigger, context, router, router_db, **kwargs): """Associates a router with a service provider. @@ -78,7 +86,6 @@ class DriverController(object): if _flavor_specified(router): router_db.flavor_id = router['flavor_id'] drv = self._get_provider_for_create(context, router) - _ensure_driver_supports_request(drv, router) self._stm.add_resource_association(context, 'L3_ROUTER_NAT', drv.name, router['id']) diff --git a/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py b/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py index b0777e475a9..9d9f58f9166 100644 --- a/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py +++ b/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py @@ -43,6 +43,7 @@ from neutron.extensions import l3_ext_ha_mode as l3_ha from neutron.extensions import l3agentscheduler as l3agent from neutron.extensions import portbindings from neutron import manager +from neutron.plugins.common import constants as service_constants from neutron.scheduler import l3_agent_scheduler from neutron.tests import base from neutron.tests.common import helpers @@ -1412,6 +1413,13 @@ class L3HAPlugin(db_v2.NeutronDbPluginV2, l3_hascheduler_db.L3_HA_scheduler_db_mixin): supported_extension_aliases = ["l3-ha", "router_availability_zone"] + @classmethod + def get_plugin_type(cls): + return service_constants.L3_ROUTER_NAT + + def get_plugin_description(self): + return "L3 Routing Service Plugin for testing" + class L3HATestCaseMixin(testlib_api.SqlTestCase, L3SchedulerBaseMixin): @@ -1421,19 +1429,19 @@ class L3HATestCaseMixin(testlib_api.SqlTestCase, self.adminContext = n_context.get_admin_context() mock.patch('neutron.common.rpc.get_client').start() - self.plugin = L3HAPlugin() self.setup_coreplugin('ml2', load_plugins=False) cfg.CONF.set_override('service_plugins', - ['neutron.services.l3_router.' - 'l3_router_plugin.L3RouterPlugin']) + ['neutron.tests.unit.scheduler.' + 'test_l3_agent_scheduler.L3HAPlugin']) cfg.CONF.set_override('max_l3_agents_per_router', 0) + + manager.init() + self.plugin = directory.get_plugin(constants.L3) self.plugin.router_scheduler = importutils.import_object( 'neutron.scheduler.l3_agent_scheduler.ChanceScheduler' ) - - manager.init() self._register_l3_agents() @staticmethod