Merge "Extraroute extension support for nuage plugin"
This commit is contained in:
commit
dd6f865818
@ -0,0 +1,68 @@
|
|||||||
|
# Copyright 2014 OpenStack Foundation
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""nuage_extraroute
|
||||||
|
|
||||||
|
Revision ID: 10cd28e692e9
|
||||||
|
Revises: 1b837a7125a9
|
||||||
|
Create Date: 2014-05-14 14:47:53.148132
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '10cd28e692e9'
|
||||||
|
down_revision = '1b837a7125a9'
|
||||||
|
|
||||||
|
# Change to ['*'] if this migration applies to all plugins
|
||||||
|
|
||||||
|
migration_for_plugins = [
|
||||||
|
'neutron.plugins.nuage.plugin.NuagePlugin'
|
||||||
|
]
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
from neutron.db import migration
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade(active_plugins=None, options=None):
|
||||||
|
if not migration.should_run(active_plugins, migration_for_plugins):
|
||||||
|
return
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
'routerroutes_mapping',
|
||||||
|
sa.Column('router_id', sa.String(length=36), nullable=False),
|
||||||
|
sa.Column('nuage_route_id', sa.String(length=36), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(['router_id'], ['routers.id'],
|
||||||
|
ondelete='CASCADE'),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
'routerroutes',
|
||||||
|
sa.Column('destination', sa.String(length=64), nullable=False),
|
||||||
|
sa.Column('nexthop', sa.String(length=64), nullable=False),
|
||||||
|
sa.Column('router_id', sa.String(length=36), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(['router_id'], ['routers.id'],
|
||||||
|
ondelete='CASCADE'),
|
||||||
|
sa.PrimaryKeyConstraint('destination', 'nexthop',
|
||||||
|
'router_id'),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade(active_plugins=None, options=None):
|
||||||
|
if not migration.should_run(active_plugins, migration_for_plugins):
|
||||||
|
return
|
||||||
|
|
||||||
|
op.drop_table('routerroutes')
|
||||||
|
op.drop_table('routerroutes_mapping')
|
@ -1 +1 @@
|
|||||||
1b837a7125a9
|
10cd28e692e9
|
@ -72,3 +72,13 @@ class PortVPortMapping(model_base.BASEV2):
|
|||||||
nuage_vport_id = Column(String(36))
|
nuage_vport_id = Column(String(36))
|
||||||
nuage_vif_id = Column(String(36))
|
nuage_vif_id = Column(String(36))
|
||||||
static_ip = Column(Boolean())
|
static_ip = Column(Boolean())
|
||||||
|
|
||||||
|
|
||||||
|
class RouterRoutesMapping(model_base.BASEV2, models_v2.Route):
|
||||||
|
__tablename__ = 'routerroutes_mapping'
|
||||||
|
router_id = Column(String(36),
|
||||||
|
ForeignKey('routers.id',
|
||||||
|
ondelete="CASCADE"),
|
||||||
|
primary_key=True,
|
||||||
|
nullable=False)
|
||||||
|
nuage_route_id = Column(String(36))
|
||||||
|
@ -131,3 +131,24 @@ def get_net_partitions(session, filters=None, fields=None):
|
|||||||
nuage_models.NetPartition,
|
nuage_models.NetPartition,
|
||||||
filters)
|
filters)
|
||||||
return query
|
return query
|
||||||
|
|
||||||
|
|
||||||
|
def delete_static_route(session, static_route):
|
||||||
|
session.delete(static_route)
|
||||||
|
|
||||||
|
|
||||||
|
def get_router_route_mapping(session, id, route):
|
||||||
|
qry = session.query(nuage_models.RouterRoutesMapping)
|
||||||
|
return qry.filter_by(router_id=id,
|
||||||
|
destination=route['destination'],
|
||||||
|
nexthop=route['nexthop']).one()
|
||||||
|
|
||||||
|
|
||||||
|
def add_static_route(session, router_id, nuage_rtr_id,
|
||||||
|
destination, nexthop):
|
||||||
|
staticrt = nuage_models.RouterRoutesMapping(router_id=router_id,
|
||||||
|
nuage_route_id=nuage_rtr_id,
|
||||||
|
destination=destination,
|
||||||
|
nexthop=nexthop)
|
||||||
|
session.add(staticrt)
|
||||||
|
return staticrt
|
||||||
|
@ -25,9 +25,11 @@ from neutron.api import extensions as neutron_extensions
|
|||||||
from neutron.api.v2 import attributes
|
from neutron.api.v2 import attributes
|
||||||
from neutron.common import constants as os_constants
|
from neutron.common import constants as os_constants
|
||||||
from neutron.common import exceptions as n_exc
|
from neutron.common import exceptions as n_exc
|
||||||
|
from neutron.common import utils
|
||||||
from neutron.db import api as db
|
from neutron.db import api as db
|
||||||
from neutron.db import db_base_plugin_v2
|
from neutron.db import db_base_plugin_v2
|
||||||
from neutron.db import external_net_db
|
from neutron.db import external_net_db
|
||||||
|
from neutron.db import extraroute_db
|
||||||
from neutron.db import l3_db
|
from neutron.db import l3_db
|
||||||
from neutron.db import models_v2
|
from neutron.db import models_v2
|
||||||
from neutron.db import quota_db # noqa
|
from neutron.db import quota_db # noqa
|
||||||
@ -46,12 +48,13 @@ from neutron import policy
|
|||||||
|
|
||||||
class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||||
external_net_db.External_net_db_mixin,
|
external_net_db.External_net_db_mixin,
|
||||||
|
extraroute_db.ExtraRoute_db_mixin,
|
||||||
l3_db.L3_NAT_db_mixin,
|
l3_db.L3_NAT_db_mixin,
|
||||||
netpartition.NetPartitionPluginBase):
|
netpartition.NetPartitionPluginBase):
|
||||||
"""Class that implements Nuage Networks' plugin functionality."""
|
"""Class that implements Nuage Networks' plugin functionality."""
|
||||||
supported_extension_aliases = ["router", "binding", "external-net",
|
supported_extension_aliases = ["router", "binding", "external-net",
|
||||||
"net-partition", "nuage-router",
|
"net-partition", "nuage-router",
|
||||||
"nuage-subnet", "quotas"]
|
"nuage-subnet", "quotas", "extraroute"]
|
||||||
|
|
||||||
binding_view = "extension:port_binding:view"
|
binding_view = "extension:port_binding:view"
|
||||||
|
|
||||||
@ -606,6 +609,65 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
nuage_group_id=group_id)
|
nuage_group_id=group_id)
|
||||||
return neutron_router
|
return neutron_router
|
||||||
|
|
||||||
|
def _validate_nuage_staticroutes(self, old_routes, added, removed):
|
||||||
|
cidrs = []
|
||||||
|
for old in old_routes:
|
||||||
|
if old not in removed:
|
||||||
|
ip = netaddr.IPNetwork(old['destination'])
|
||||||
|
cidrs.append(ip)
|
||||||
|
for route in added:
|
||||||
|
ip = netaddr.IPNetwork(route['destination'])
|
||||||
|
matching = netaddr.all_matching_cidrs(ip.ip, cidrs)
|
||||||
|
if matching:
|
||||||
|
msg = _('for same subnet, multiple static routes not allowed')
|
||||||
|
raise n_exc.BadRequest(resource='router', msg=msg)
|
||||||
|
cidrs.append(ip)
|
||||||
|
|
||||||
|
def update_router(self, context, id, router):
|
||||||
|
r = router['router']
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
if 'routes' in r:
|
||||||
|
old_routes = self._get_extra_routes_by_router_id(context,
|
||||||
|
id)
|
||||||
|
added, removed = utils.diff_list_of_dict(old_routes,
|
||||||
|
r['routes'])
|
||||||
|
self._validate_nuage_staticroutes(old_routes, added, removed)
|
||||||
|
ent_rtr_mapping = nuagedb.get_ent_rtr_mapping_by_rtrid(
|
||||||
|
context.session, id)
|
||||||
|
if not ent_rtr_mapping:
|
||||||
|
msg = (_("Router %s does not hold net-partition "
|
||||||
|
"assoc on VSD. extra-route failed") % id)
|
||||||
|
raise n_exc.BadRequest(resource='router', msg=msg)
|
||||||
|
# Let it do internal checks first and verify it.
|
||||||
|
router_updated = super(NuagePlugin,
|
||||||
|
self).update_router(context,
|
||||||
|
id,
|
||||||
|
router)
|
||||||
|
for route in removed:
|
||||||
|
rtr_rt_mapping = nuagedb.get_router_route_mapping(
|
||||||
|
context.session, id, route)
|
||||||
|
if rtr_rt_mapping:
|
||||||
|
self.nuageclient.delete_nuage_staticroute(
|
||||||
|
rtr_rt_mapping['nuage_route_id'])
|
||||||
|
nuagedb.delete_static_route(context.session,
|
||||||
|
rtr_rt_mapping)
|
||||||
|
for route in added:
|
||||||
|
params = {
|
||||||
|
'parent_id': ent_rtr_mapping['nuage_router_id'],
|
||||||
|
'net': netaddr.IPNetwork(route['destination']),
|
||||||
|
'nexthop': route['nexthop']
|
||||||
|
}
|
||||||
|
nuage_rt_id = self.nuageclient.create_nuage_staticroute(
|
||||||
|
params)
|
||||||
|
nuagedb.add_static_route(context.session,
|
||||||
|
id, nuage_rt_id,
|
||||||
|
route['destination'],
|
||||||
|
route['nexthop'])
|
||||||
|
else:
|
||||||
|
router_updated = super(NuagePlugin, self).update_router(
|
||||||
|
context, id, router)
|
||||||
|
return router_updated
|
||||||
|
|
||||||
def delete_router(self, context, id):
|
def delete_router(self, context, id):
|
||||||
session = context.session
|
session = context.session
|
||||||
ent_rtr_mapping = nuagedb.get_ent_rtr_mapping_by_rtrid(session,
|
ent_rtr_mapping = nuagedb.get_ent_rtr_mapping_by_rtrid(session,
|
||||||
|
@ -83,3 +83,9 @@ class FakeNuageClient(object):
|
|||||||
|
|
||||||
def delete_vms(self, params):
|
def delete_vms(self, params):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def create_nuage_staticroute(self, params):
|
||||||
|
return str(uuid.uuid4())
|
||||||
|
|
||||||
|
def delete_nuage_staticroute(self, id):
|
||||||
|
pass
|
||||||
|
@ -18,6 +18,7 @@ import os
|
|||||||
|
|
||||||
import mock
|
import mock
|
||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
|
from webob import exc
|
||||||
|
|
||||||
from neutron.extensions import portbindings
|
from neutron.extensions import portbindings
|
||||||
from neutron.plugins.nuage import extensions
|
from neutron.plugins.nuage import extensions
|
||||||
@ -25,6 +26,7 @@ from neutron.plugins.nuage import plugin as nuage_plugin
|
|||||||
from neutron.tests.unit import _test_extension_portbindings as test_bindings
|
from neutron.tests.unit import _test_extension_portbindings as test_bindings
|
||||||
from neutron.tests.unit.nuage import fake_nuageclient
|
from neutron.tests.unit.nuage import fake_nuageclient
|
||||||
from neutron.tests.unit import test_db_plugin
|
from neutron.tests.unit import test_db_plugin
|
||||||
|
from neutron.tests.unit import test_extension_extraroute as extraroute_test
|
||||||
from neutron.tests.unit import test_l3_plugin
|
from neutron.tests.unit import test_l3_plugin
|
||||||
|
|
||||||
API_EXT_PATH = os.path.dirname(extensions.__file__)
|
API_EXT_PATH = os.path.dirname(extensions.__file__)
|
||||||
@ -160,3 +162,32 @@ class TestNuagePortsV2(NuagePluginV2TestCase,
|
|||||||
class TestNuageL3NatTestCase(NuagePluginV2TestCase,
|
class TestNuageL3NatTestCase(NuagePluginV2TestCase,
|
||||||
test_l3_plugin.L3NatDBIntTestCase):
|
test_l3_plugin.L3NatDBIntTestCase):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TestNuageExtrarouteTestCase(NuagePluginV2TestCase,
|
||||||
|
extraroute_test.ExtraRouteDBIntTestCase):
|
||||||
|
|
||||||
|
def test_router_update_with_dup_destination_address(self):
|
||||||
|
with self.router() as r:
|
||||||
|
with self.subnet(cidr='10.0.1.0/24') as s:
|
||||||
|
with self.port(subnet=s, no_delete=True) as p:
|
||||||
|
self._router_interface_action('add',
|
||||||
|
r['router']['id'],
|
||||||
|
None,
|
||||||
|
p['port']['id'])
|
||||||
|
|
||||||
|
routes = [{'destination': '135.207.0.0/16',
|
||||||
|
'nexthop': '10.0.1.3'},
|
||||||
|
{'destination': '135.207.0.0/16',
|
||||||
|
'nexthop': '10.0.1.5'}]
|
||||||
|
|
||||||
|
self._update('routers', r['router']['id'],
|
||||||
|
{'router': {'routes':
|
||||||
|
routes}},
|
||||||
|
expected_code=exc.HTTPBadRequest.code)
|
||||||
|
|
||||||
|
# clean-up
|
||||||
|
self._router_interface_action('remove',
|
||||||
|
r['router']['id'],
|
||||||
|
None,
|
||||||
|
p['port']['id'])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user