Merge "Add support for provider-network extension in nuage Plugin"

This commit is contained in:
Jenkins 2014-08-28 11:09:12 +00:00 committed by Gerrit Code Review
commit deb3579e6e
8 changed files with 213 additions and 14 deletions

View File

@ -1 +1 @@
3b85b693a95f
aae5706a396

View File

@ -0,0 +1,45 @@
# 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_provider_networks
Revision ID: aae5706a396
Revises: 3b85b693a95f
Create Date: 2014-08-18 16:00:21.898795
"""
revision = 'aae5706a396'
down_revision = '3b85b693a95f'
from alembic import op
import sqlalchemy as sa
def upgrade(active_plugins=None, options=None):
op.create_table(
'nuage_provider_net_bindings',
sa.Column('network_id', sa.String(length=36), nullable=False),
sa.Column('network_type', sa.String(length=32), nullable=False),
sa.Column('physical_network', sa.String(length=64), nullable=False),
sa.Column('vlan_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(
['network_id'], ['networks.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('network_id')
)
def downgrade(active_plugins=None, options=None):
op.drop_table('nuage_provider_net_bindings')

View File

@ -22,3 +22,7 @@ from neutron.common import exceptions as n_exc
class OperationNotSupported(n_exc.InvalidConfigurationOption):
message = _("Nuage Plugin does not support this operation: %(msg)s")
class NuageBadRequest(n_exc.BadRequest):
message = _("Bad request: %(msg)s")

View File

@ -40,6 +40,18 @@ class NetPartitionRouter(model_base.BASEV2):
nuage_router_id = sa.Column(sa.String(36))
class ProviderNetBinding(model_base.BASEV2):
"""Represents binding of virtual network to physical_network and vlan."""
__tablename__ = 'nuage_provider_net_bindings'
network_id = sa.Column(sa.String(36),
sa.ForeignKey('networks.id', ondelete="CASCADE"),
primary_key=True)
network_type = sa.Column(sa.String(32), nullable=False)
physical_network = sa.Column(sa.String(64), nullable=False)
vlan_id = sa.Column(sa.Integer, nullable=False)
class SubnetL2Domain(model_base.BASEV2):
__tablename__ = 'nuage_subnet_l2dom_mapping'
subnet_id = sa.Column(sa.String(36),
@ -51,4 +63,4 @@ class SubnetL2Domain(model_base.BASEV2):
nuage_subnet_id = sa.Column(sa.String(36))
nuage_l2dom_tmplt_id = sa.Column(sa.String(36))
nuage_user_id = sa.Column(sa.String(36))
nuage_group_id = sa.Column(sa.String(36))
nuage_group_id = sa.Column(sa.String(36))

View File

@ -98,4 +98,20 @@ def get_ent_rtr_mapping_by_entid(session,
def get_ent_rtr_mapping_by_rtrid(session, rtrid):
query = session.query(nuage_models.NetPartitionRouter)
return query.filter_by(router_id=rtrid).first()
return query.filter_by(router_id=rtrid).first()
def add_network_binding(session, network_id, network_type, physical_network,
vlan_id):
binding = nuage_models.ProviderNetBinding(
network_id=network_id,
network_type=network_type,
physical_network=physical_network,
vlan_id=vlan_id)
session.add(binding)
def get_network_binding(session, network_id):
return (session.query(nuage_models.ProviderNetBinding).
filter_by(network_id=network_id).
first())

View File

@ -36,6 +36,7 @@ from neutron.db import securitygroups_db as sg_db
from neutron.extensions import external_net
from neutron.extensions import l3
from neutron.extensions import portbindings
from neutron.extensions import providernet as pnet
from neutron.extensions import securitygroup as ext_sg
from neutron.openstack.common import excutils
from neutron.openstack.common import importutils
@ -58,7 +59,7 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
"""Class that implements Nuage Networks' plugin functionality."""
supported_extension_aliases = ["router", "binding", "external-net",
"net-partition", "nuage-router",
"nuage-subnet", "quotas",
"nuage-subnet", "quotas", "provider",
"extraroute", "security-group"]
binding_view = "extension:port_binding:view"
@ -378,8 +379,49 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
subnets = self.get_subnets(context, filters=filters)
return bool(routers or subnets)
def _extend_network_dict_provider(self, context, network):
binding = nuagedb.get_network_binding(context.session, network['id'])
if binding:
network[pnet.NETWORK_TYPE] = binding.network_type
network[pnet.PHYSICAL_NETWORK] = binding.physical_network
network[pnet.SEGMENTATION_ID] = binding.vlan_id
def _process_provider_create(self, context, attrs):
network_type = attrs.get(pnet.NETWORK_TYPE)
physical_network = attrs.get(pnet.PHYSICAL_NETWORK)
segmentation_id = attrs.get(pnet.SEGMENTATION_ID)
network_type_set = attributes.is_attr_set(network_type)
physical_network_set = attributes.is_attr_set(physical_network)
segmentation_id_set = attributes.is_attr_set(segmentation_id)
if not (network_type_set or physical_network_set or
segmentation_id_set):
return None, None, None
if not network_type_set:
msg = _("provider:network_type required")
raise n_exc.InvalidInput(error_message=msg)
elif network_type != 'vlan':
msg = (_("provider:network_type %s not supported in VSP")
% network_type)
raise nuage_exc.NuageBadRequest(msg=msg)
if not physical_network_set:
msg = _("provider:physical_network required")
raise nuage_exc.NuageBadRequest(msg=msg)
if not segmentation_id_set:
msg = _("provider:segmentation_id required")
raise nuage_exc.NuageBadRequest(msg=msg)
self.nuageclient.validate_provider_network(network_type,
physical_network,
segmentation_id)
return network_type, physical_network, segmentation_id
def create_network(self, context, network):
net = network['network']
(network_type, physical_network,
vlan_id) = self._process_provider_create(context,
network['network'])
with context.session.begin(subtransactions=True):
self._ensure_default_security_group(
context,
@ -388,6 +430,11 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
net = super(NuagePlugin, self).create_network(context,
network)
self._process_l3_create(context, net, network['network'])
if network_type == 'vlan':
nuagedb.add_network_binding(context.session, net['id'],
network_type,
physical_network, vlan_id)
self._extend_network_dict_provider(context, net)
return net
def _validate_update_network(self, context, id, network):
@ -413,7 +460,25 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
raise n_exc.NetworkInUse(net_id=id)
return (is_external_set, subnet)
def get_network(self, context, net_id, fields=None):
net = super(NuagePlugin, self).get_network(context,
net_id,
None)
self._extend_network_dict_provider(context, net)
return self._fields(net, fields)
def get_networks(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None, page_reverse=False):
nets = super(NuagePlugin,
self).get_networks(context, filters, None, sorts,
limit, marker, page_reverse)
for net in nets:
self._extend_network_dict_provider(context, net)
return [self._fields(net, fields) for net in nets]
def update_network(self, context, id, network):
pnet._raise_if_updates_provider_attributes(network['network'])
with context.session.begin(subtransactions=True):
is_external_set, subnet = self._validate_update_network(context,
id,
@ -477,6 +542,14 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
msg = "no-gateway option not supported with subnets"
raise nuage_exc.OperationNotSupported(msg=msg)
def _validate_create_provider_subnet(self, context, net_id):
net_filter = {'network_id': [net_id]}
existing_subn = self.get_subnets(context, filters=net_filter)
if len(existing_subn) > 0:
msg = _('Only one subnet is allowed per '
'Provider network %s') % net_id
raise nuage_exc.OperationNotSupported(msg=msg)
def _delete_nuage_sharedresource(self, net_id):
self.nuageclient.delete_nuage_sharedresource(net_id)
@ -508,14 +581,15 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
self._add_nuage_sharedresource(subn, net_id, type)
return subn
def _create_nuage_subnet(self, context, neutron_subnet,
netpart_id, l2dom_template_id):
def _create_nuage_subnet(self, context, neutron_subnet, netpart_id,
l2dom_template_id, pnet_binding):
net = netaddr.IPNetwork(neutron_subnet['cidr'])
params = {
'netpart_id': netpart_id,
'tenant_id': neutron_subnet['tenant_id'],
'net': net,
'l2dom_tmplt_id': l2dom_template_id
'l2dom_tmplt_id': l2dom_template_id,
'pnet_binding': pnet_binding
}
try:
nuage_subnet = self.nuageclient.create_subnet(neutron_subnet,
@ -547,6 +621,9 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
if self._network_is_external(context, net_id):
return self._create_nuage_sharedresource(
context, subnet, constants.SR_TYPE_FLOATING)
pnet_binding = nuagedb.get_network_binding(context.session, net_id)
if pnet_binding:
self._validate_create_provider_subnet(context, net_id)
self._validate_create_subnet(subn)
@ -554,7 +631,8 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
neutron_subnet = super(NuagePlugin, self).create_subnet(context,
subnet)
self._create_nuage_subnet(context, neutron_subnet, net_partition['id'],
subn['nuage_subnet_template'])
subn['nuage_subnet_template'],
pnet_binding)
return neutron_subnet
def delete_subnet(self, context, id):
@ -637,13 +715,17 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
self.nuageclient.delete_subnet(nuage_subnet_id,
nuage_l2dom_tmplt_id)
net = netaddr.IPNetwork(subn['cidr'])
pnet_binding = nuagedb.get_network_binding(context.session,
subn['network_id'])
params = {
'net': net,
'zone_id': nuage_zone['nuage_zone_id'],
'neutron_subnet_id': subnet_id
'neutron_subnet_id': subnet_id,
'pnet_binding': pnet_binding
}
if not attributes.is_attr_set(subn['gateway_ip']):
subn['gateway_ip'] = str(netaddr.IPAddress(net.first + 1))
try:
nuage_subnet = self.nuageclient.create_domain_subnet(subn,
params)
@ -723,14 +805,17 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
net = netaddr.IPNetwork(neutron_subnet['cidr'])
netpart_id = ent_rtr_mapping['net_partition_id']
pnet_binding = nuagedb.get_network_binding(
context.session, neutron_subnet['network_id'])
params = {
'tenant_id': neutron_subnet['tenant_id'],
'net': net,
'netpart_id': netpart_id
'netpart_id': netpart_id,
'nuage_subn_id': nuage_subn_id,
'neutron_subnet': neutron_subnet,
'pnet_binding': pnet_binding
}
nuage_subnet = self.nuageclient.create_subnet(neutron_subnet,
params)
self.nuageclient.delete_domain_subnet(nuage_subn_id)
nuage_subnet = self.nuageclient.remove_router_interface(params)
info = super(NuagePlugin,
self).remove_router_interface(context, router_id,
interface_info)

View File

@ -185,3 +185,9 @@ class FakeNuageClient(object):
def delete_port_security_group_bindings(self, params):
pass
def validate_provider_network(self, net_type, phy_net, vlan_id):
pass
def remove_router_interface(self, params):
pass

View File

@ -22,9 +22,11 @@ import mock
from oslo.config import cfg
from webob import exc
from neutron import context
from neutron.extensions import external_net
from neutron.extensions import l3
from neutron.extensions import portbindings
from neutron.extensions import providernet as pnet
from neutron.openstack.common import uuidutils
from neutron.plugins.nuage import extensions
from neutron.plugins.nuage.extensions import nuage_router
@ -348,3 +350,32 @@ class TestNuageExtrarouteTestCase(NuagePluginV2TestCase,
class TestNuageSecurityGroupTestCase(NuagePluginV2TestCase,
test_sg.TestSecurityGroups):
pass
class TestNuageProviderNetTestCase(NuagePluginV2TestCase):
def test_create_provider_network(self):
phy_net = uuidutils.generate_uuid()
data = {'network': {'name': 'pnet1',
'tenant_id': 'admin',
pnet.NETWORK_TYPE: 'vlan',
pnet.PHYSICAL_NETWORK: phy_net,
pnet.SEGMENTATION_ID: 123}}
network_req = self.new_create_request('networks', data, self.fmt)
net = self.deserialize(self.fmt, network_req.get_response(self.api))
self.assertEqual('vlan', net['network'][pnet.NETWORK_TYPE])
self.assertEqual(phy_net, net['network'][pnet.PHYSICAL_NETWORK])
self.assertEqual(123, net['network'][pnet.SEGMENTATION_ID])
def test_create_provider_network_no_admin(self):
phy_net = uuidutils.generate_uuid()
data = {'network': {'name': 'pnet1',
'tenant_id': 'no_admin',
pnet.NETWORK_TYPE: 'vlan',
pnet.PHYSICAL_NETWORK: phy_net,
pnet.SEGMENTATION_ID: 123}}
network_req = self.new_create_request('networks', data, self.fmt)
network_req.environ['neutron.context'] = context.Context(
'', 'no_admin', is_admin=False)
res = network_req.get_response(self.api)
self.assertEqual(exc.HTTPForbidden.code, res.status_int)