Merge "Add support for provider-network extension in nuage Plugin"
This commit is contained in:
commit
deb3579e6e
@ -1 +1 @@
|
||||
3b85b693a95f
|
||||
aae5706a396
|
||||
|
@ -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')
|
@ -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")
|
||||
|
@ -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))
|
||||
|
@ -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())
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user