Merge "Update related router when subnetpool change scope"

This commit is contained in:
Jenkins 2016-02-07 04:24:21 +00:00 committed by Gerrit Code Review
commit 8627fad607
7 changed files with 145 additions and 0 deletions

View File

@ -21,3 +21,4 @@ SECURITY_GROUP = 'security_group'
SECURITY_GROUP_RULE = 'security_group_rule'
SUBNET = 'subnet'
SUBNET_GATEWAY = 'subnet_gateway'
SUBNETPOOL_ADDRESS_SCOPE = 'subnetpool_address_scope'

View File

@ -59,6 +59,8 @@ ROUTER_INTERFACE_OWNERS = (DEVICE_OWNER_ROUTER_INTF,
ROUTER_INTERFACE_OWNERS_SNAT = (DEVICE_OWNER_ROUTER_INTF,
DEVICE_OWNER_DVR_INTERFACE,
DEVICE_OWNER_ROUTER_SNAT)
ROUTER_PORT_OWNERS = ROUTER_INTERFACE_OWNERS_SNAT + (DEVICE_OWNER_ROUTER_GW,)
L3_AGENT_MODE_DVR = 'dvr'
L3_AGENT_MODE_DVR_SNAT = 'dvr_snat'
L3_AGENT_MODE_LEGACY = 'legacy'

View File

@ -1034,12 +1034,24 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
self._validate_address_scope_id(context, reader.address_scope_id,
id, reader.prefixes,
reader.ip_version)
address_scope_changed = (orig_sp.address_scope_id !=
reader.address_scope_id)
orig_sp.update(self._filter_non_model_columns(
reader.subnetpool,
models_v2.SubnetPool))
self._update_subnetpool_prefixes(context,
reader.prefixes,
id)
if address_scope_changed:
# Notify about the update of subnetpool's address scope
kwargs = {'context': context, 'subnetpool_id': id}
registry.notify(resources.SUBNETPOOL_ADDRESS_SCOPE,
events.AFTER_UPDATE,
self.update_subnetpool,
**kwargs)
for key in ['min_prefixlen', 'max_prefixlen', 'default_prefixlen']:
updated['key'] = str(updated[key])

View File

@ -1654,6 +1654,27 @@ def _notify_subnet_gateway_ip_update(resource, event, trigger, **kwargs):
l3plugin.notify_router_updated(context, router_id)
def _notify_subnetpool_address_scope_update(resource, event,
trigger, **kwargs):
context = kwargs['context']
subnetpool_id = kwargs['subnetpool_id']
query = context.session.query(RouterPort.router_id)
query = query.join(models_v2.Port)
query = query.join(
models_v2.Subnet,
models_v2.Subnet.network_id == models_v2.Port.network_id)
query = query.filter(
models_v2.Subnet.subnetpool_id == subnetpool_id,
RouterPort.port_type.in_(l3_constants.ROUTER_PORT_OWNERS))
query = query.distinct()
router_ids = [r[0] for r in query]
l3plugin = manager.NeutronManager.get_service_plugins().get(
constants.L3_ROUTER_NAT)
l3plugin.notify_routers_updated(context, router_ids)
def subscribe():
registry.subscribe(
_prevent_l3_port_delete_callback, resources.PORT, events.BEFORE_DELETE)
@ -1662,6 +1683,10 @@ def subscribe():
registry.subscribe(
_notify_subnet_gateway_ip_update, resources.SUBNET_GATEWAY,
events.AFTER_UPDATE)
registry.subscribe(
_notify_subnetpool_address_scope_update,
resources.SUBNETPOOL_ADDRESS_SCOPE,
events.AFTER_UPDATE)
# NOTE(armax): multiple l3 service plugins (potentially out of tree) inherit
# from l3_db and may need the callbacks to be processed. Having an implicit

View File

@ -16,6 +16,9 @@
import mock
import testtools
from neutron.callbacks import events
from neutron.callbacks import registry
from neutron.callbacks import resources
from neutron.common import exceptions as n_exc
from neutron.db import l3_db
from neutron.extensions import l3
@ -185,3 +188,14 @@ class TestL3_NAT_dbonly_mixin(base.BaseTestCase):
self.db.get_floatingip = mock.Mock()
with testtools.ExpectedException(n_exc.ServicePortInUse):
self.db.prevent_l3_port_deletion(mock.Mock(), None)
@mock.patch.object(l3_db, '_notify_subnetpool_address_scope_update')
def test_subscribe_address_scope_of_subnetpool(self, notify):
l3_db.subscribe()
registry.notify(resources.SUBNETPOOL_ADDRESS_SCOPE,
events.AFTER_UPDATE, mock.ANY, context=mock.ANY,
subnetpool_id='fake_id')
notify.assert_called_once_with(resources.SUBNETPOOL_ADDRESS_SCOPE,
events.AFTER_UPDATE, mock.ANY,
context=mock.ANY,
subnetpool_id='fake_id')

View File

@ -14,10 +14,14 @@
import contextlib
import mock
import netaddr
import webob.exc
from neutron.api.v2 import attributes as attr
from neutron.callbacks import events
from neutron.callbacks import registry
from neutron.callbacks import resources
from neutron.common import constants
from neutron import context
from neutron.db import address_scope_db
@ -370,6 +374,62 @@ class TestSubnetPoolsWithAddressScopes(AddressScopeTestCase):
self._compare_resource(res, update_data['subnetpool'],
'subnetpool')
def _test_update_subnetpool_address_scope_notify(self, as_change=True):
with self.address_scope(name='foo-address-scope') as addr_scope:
foo_as_id = addr_scope['address_scope']['id']
subnet = netaddr.IPNetwork('10.10.10.0/24')
initial_subnetpool = self._test_create_subnetpool(
[subnet.cidr], name='foo-sp',
min_prefixlen='21', address_scope_id=foo_as_id)
subnetpool_id = initial_subnetpool['subnetpool']['id']
with self.address_scope(name='bar-address-scope') as other_as, \
self.network() as network:
data = {'subnet': {
'network_id': network['network']['id'],
'subnetpool_id': subnetpool_id,
'prefixlen': 24,
'ip_version': 4,
'tenant_id': network['network']['tenant_id']}}
req = self.new_create_request('subnets', data)
subnet = self.deserialize(self.fmt,
req.get_response(self.api))
with mock.patch.object(registry, 'notify') as notify:
plugin = db_base_plugin_v2.NeutronDbPluginV2()
plugin.is_address_scope_owned_by_tenant = mock.Mock(
return_value=True)
plugin._validate_address_scope_id = mock.Mock()
ctx = context.get_admin_context()
bar_as_id = other_as['address_scope']['id']
data = {'subnetpool': {
'name': 'bar-sp'}}
if as_change:
data['subnetpool']['address_scope_id'] = bar_as_id
updated_sp = plugin.update_subnetpool(
ctx, subnetpool_id, data)
self.assertEqual('bar-sp', updated_sp['name'])
if as_change:
self.assertEqual(bar_as_id,
updated_sp['address_scope_id'])
notify.assert_called_once_with(
resources.SUBNETPOOL_ADDRESS_SCOPE,
events.AFTER_UPDATE,
plugin.update_subnetpool, context=ctx,
subnetpool_id=subnetpool_id)
else:
self.assertEqual(foo_as_id,
updated_sp['address_scope_id'])
self.assertFalse(notify.called)
def test_update_subnetpool_address_scope_notify(self):
self._test_update_subnetpool_address_scope_notify()
def test_not_update_subnetpool_address_scope_not_notify(self):
self._test_update_subnetpool_address_scope_notify(False)
def test_delete_address_scope_in_use(self):
with self.address_scope(name='foo-address-scope') as addr_scope:
address_scope_id = addr_scope['address_scope']['id']

View File

@ -2692,6 +2692,37 @@ class L3NatTestCaseBase(L3NatTestCaseMixin):
chk_method.assert_called_with(mock.ANY,
['fake_device'], None)
def test__notify_subnetpool_address_scope_update(self):
plugin = manager.NeutronManager.get_service_plugins()[
service_constants.L3_ROUTER_NAT]
tenant_id = _uuid()
with mock.patch.object(
plugin, 'notify_routers_updated') as chk_method, \
self.subnetpool(prefixes=['10.0.0.0/24'],
admin=True, name='sp',
tenant_id=tenant_id) as subnetpool, \
self.router(tenant_id=tenant_id) as router, \
self.network(tenant_id=tenant_id) as network:
subnetpool_id = subnetpool['subnetpool']['id']
data = {'subnet': {
'network_id': network['network']['id'],
'subnetpool_id': subnetpool_id,
'prefixlen': 24,
'ip_version': 4,
'tenant_id': tenant_id}}
req = self.new_create_request('subnets', data)
subnet = self.deserialize(self.fmt, req.get_response(self.api))
admin_ctx = context.get_admin_context()
plugin.add_router_interface(
admin_ctx,
router['router']['id'], {'subnet_id': subnet['subnet']['id']})
l3_db._notify_subnetpool_address_scope_update(
mock.ANY, mock.ANY, mock.ANY,
context=admin_ctx, subnetpool_id=subnetpool_id)
chk_method.assert_called_with(admin_ctx, [router['router']['id']])
class L3AgentDbTestCaseBase(L3NatTestCaseMixin):