Nuage Networks Plugin

Nuage networks’ openstack networking plugin enables integration
of openstack with Nuage Networks’ Virtual Service Platform (VSP)

Change-Id: If20b385b78a350cb9aae2c70b6a44888e74c23bc
Implements: blueprint nuage-networks-plugin
This commit is contained in:
ronak 2014-01-16 10:26:01 -08:00
parent 055bae5c08
commit e2bab25f54
18 changed files with 1710 additions and 0 deletions

View File

@ -0,0 +1,10 @@
# Please fill in the correct data for all the keys below and uncomment key-value pairs
[restproxy]
#default_net_partition_name = <default-net-partition-name>
#auth_resource = /auth
#server = ip:port
#organization = org
#serverauth = uname:pass
#serverssl = True
#base_uri = /base

View File

@ -0,0 +1,120 @@
# 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_initial
Revision ID: e766b19a3bb
Revises: 1b2580001654
Create Date: 2014-02-14 18:03:14.841064
"""
# revision identifiers, used by Alembic.
revision = 'e766b19a3bb'
down_revision = '1b2580001654'
migration_for_plugins = [
'neutron.plugins.nuage.plugin.NuagePlugin'
]
from alembic import op
import sqlalchemy as sa
from neutron.db import migration
from neutron.db.migration.alembic_migrations import common_ext_ops
def upgrade(active_plugins=None, options=None):
if not migration.should_run(active_plugins, migration_for_plugins):
return
common_ext_ops.upgrade_l3()
op.create_table(
'quotas',
sa.Column('id', sa.String(length=36), nullable=False),
sa.Column('tenant_id', sa.String(length=255), nullable=True),
sa.Column('resource', sa.String(length=255), nullable=True),
sa.Column('limit', sa.Integer(), nullable=True),
sa.PrimaryKeyConstraint('id'),
)
op.create_table(
'net_partitions',
sa.Column('id', sa.String(length=36), nullable=False),
sa.Column('name', sa.String(length=64), nullable=True),
sa.Column('l3dom_tmplt_id', sa.String(length=36), nullable=True),
sa.Column('l2dom_tmplt_id', sa.String(length=36), nullable=True),
sa.PrimaryKeyConstraint('id'),
)
op.create_table(
'port_mapping',
sa.Column('port_id', sa.String(length=36), nullable=False),
sa.Column('nuage_vport_id', sa.String(length=36), nullable=True),
sa.Column('nuage_vif_id', sa.String(length=36), nullable=True),
sa.Column('static_ip', sa.Boolean(), nullable=True),
sa.ForeignKeyConstraint(['port_id'], ['ports.id'],
ondelete='CASCADE'),
sa.PrimaryKeyConstraint('port_id'),
)
op.create_table(
'subnet_l2dom_mapping',
sa.Column('subnet_id', sa.String(length=36), nullable=False),
sa.Column('net_partition_id', sa.String(length=36), nullable=True),
sa.Column('nuage_subnet_id', sa.String(length=36), nullable=True),
sa.Column('nuage_l2dom_tmplt_id', sa.String(length=36),
nullable=True),
sa.Column('nuage_user_id', sa.String(length=36), nullable=True),
sa.Column('nuage_group_id', sa.String(length=36), nullable=True),
sa.ForeignKeyConstraint(['net_partition_id'], ['net_partitions.id'],
ondelete='CASCADE'),
sa.ForeignKeyConstraint(['subnet_id'], ['subnets.id'],
ondelete='CASCADE'),
sa.PrimaryKeyConstraint('subnet_id'),
)
op.create_table(
'net_partition_router_mapping',
sa.Column('net_partition_id', sa.String(length=36), nullable=False),
sa.Column('router_id', sa.String(length=36), nullable=False),
sa.Column('nuage_router_id', sa.String(length=36), nullable=True),
sa.ForeignKeyConstraint(['net_partition_id'], ['net_partitions.id'],
ondelete='CASCADE'),
sa.ForeignKeyConstraint(['router_id'], ['routers.id'],
ondelete='CASCADE'),
sa.PrimaryKeyConstraint('router_id'),
)
op.create_table(
'router_zone_mapping',
sa.Column('router_id', sa.String(length=36), nullable=False),
sa.Column('nuage_zone_id', sa.String(length=36), nullable=True),
sa.Column('nuage_user_id', sa.String(length=36), nullable=True),
sa.Column('nuage_group_id', sa.String(length=36), nullable=True),
sa.ForeignKeyConstraint(['router_id'], ['routers.id'],
ondelete='CASCADE'),
sa.PrimaryKeyConstraint('router_id'),
)
def downgrade(active_plugins=None, options=None):
if not migration.should_run(active_plugins, migration_for_plugins):
return
op.drop_table('router_zone_mapping')
op.drop_table('net_partition_router_mapping')
op.drop_table('subnet_l2dom_mapping')
op.drop_table('port_mapping')
op.drop_table('net_partitions')
op.drop_table('quotas')
common_ext_ops.downgrade_l3()

View File

View File

View File

@ -0,0 +1,47 @@
# Copyright 2014 Alcatel-Lucent USA Inc.
#
# 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.
#
# @author: Ronak Shah, Nuage Networks, Alcatel-Lucent USA Inc.
from oslo.config import cfg
restproxy_opts = [
cfg.StrOpt('server', default='localhost:8800',
help=_("IP Address and Port of Nuage's VSD server")),
cfg.StrOpt('serverauth', default='username:password',
secret=True,
help=_("Username and password for authentication")),
cfg.BoolOpt('serverssl', default=False,
help=_("Boolean for SSL connection with VSD server")),
cfg.StrOpt('base_uri', default='/',
help=_("Nuage provided base uri to reach out to VSD")),
cfg.StrOpt('organization', default='system',
help=_("Organization name in which VSD will orchestrate "
"network resources using openstack")),
cfg.StrOpt('auth_resource', default='',
help=_("Nuage provided uri for initial authorization to "
"access VSD")),
cfg.StrOpt('default_net_partition_name',
default='OpenStackDefaultNetPartition',
help=_("Default Network partition in which VSD will "
"orchestrate network resources using openstack")),
cfg.IntOpt('default_floatingip_quota',
default=254,
help=_("Per Net Partition quota of floating ips")),
]
def nuage_register_cfg_opts():
cfg.CONF.register_opts(restproxy_opts, "RESTPROXY")

View File

@ -0,0 +1,26 @@
# Copyright 2014 Alcatel-Lucent USA Inc.
#
# 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.
#
# @author: Ronak Shah, Nuage Networks, Alcatel-Lucent USA Inc.
from neutron.common import constants
AUTO_CREATE_PORT_OWNERS = [
constants.DEVICE_OWNER_DHCP,
constants.DEVICE_OWNER_ROUTER_INTF,
constants.DEVICE_OWNER_ROUTER_GW,
constants.DEVICE_OWNER_FLOATINGIP
]
NOVA_PORT_OWNER_PREF = 'compute:'

View File

@ -0,0 +1,24 @@
# Copyright 2014 Alcatel-Lucent USA Inc.
#
# 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.
#
# @author: Ronak Shah, Nuage Networks, Alcatel-Lucent USA Inc.
''' Nuage specific exceptions '''
from neutron.common import exceptions as n_exc
class OperationNotSupported(n_exc.InvalidConfigurationOption):
message = _("Nuage Plugin does not support this operation: %(msg)s")

View File

@ -0,0 +1,107 @@
# Copyright 2014 Alcatel-Lucent USA Inc.
#
# 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.
#
# @author: Ronak Shah, Nuage Networks, Alcatel-Lucent USA Inc.
from abc import abstractmethod
from neutron.api import extensions
from neutron.api.v2 import base
from neutron import manager
from neutron import quota
# Attribute Map
RESOURCE_ATTRIBUTE_MAP = {
'net_partitions': {
'id': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid': None},
'is_visible': True},
'name': {'allow_post': True, 'allow_put': False,
'is_visible': True, 'default': '',
'validate': {'type:name_not_default': None}},
'description': {'allow_post': True, 'allow_put': False,
'is_visible': True, 'default': '',
'validate': {'type:string_or_none': None}},
'tenant_id': {'allow_post': True, 'allow_put': False,
'required_by_policy': True,
'is_visible': True},
},
}
class Netpartition(object):
"""Extension class supporting net_partition.
"""
@classmethod
def get_name(cls):
return "NetPartition"
@classmethod
def get_alias(cls):
return "net-partition"
@classmethod
def get_description(cls):
return "NetPartition"
@classmethod
def get_namespace(cls):
return "http://nuagenetworks.net/ext/net_partition/api/v1.0"
@classmethod
def get_updated(cls):
return "2014-01-01T10:00:00-00:00"
@classmethod
def get_resources(cls):
"""Returns Ext Resources."""
exts = []
plugin = manager.NeutronManager.get_plugin()
resource_name = 'net_partition'
collection_name = resource_name.replace('_', '-') + "s"
params = RESOURCE_ATTRIBUTE_MAP.get(resource_name + "s", dict())
quota.QUOTAS.register_resource_by_name(resource_name)
controller = base.create_resource(collection_name,
resource_name,
plugin, params, allow_bulk=True)
ex = extensions.ResourceExtension(collection_name,
controller)
exts.append(ex)
return exts
class NetPartitionPluginBase(object):
@abstractmethod
def create_net_partition(self, context, router):
pass
@abstractmethod
def update_net_partition(self, context, id, router):
pass
@abstractmethod
def get_net_partition(self, context, id, fields=None):
pass
@abstractmethod
def delete_net_partition(self, context, id):
pass
@abstractmethod
def get_net_partitions(self, context, filters=None, fields=None):
pass

View File

@ -0,0 +1,73 @@
# Copyright 2014 Alcatel-Lucent USA Inc.
#
# 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.
#
# @author: Ronak Shah, Nuage Networks, Alcatel-Lucent USA Inc.
EXTENDED_ATTRIBUTES_2_0 = {
'routers': {
'net_partition': {
'allow_post': True,
'allow_put': True,
'is_visible': True,
'default': None,
'validate': {'type:string_or_none': None}
},
'rd': {
'allow_post': True,
'allow_put': True,
'is_visible': True,
'default': None,
'validate': {'type:string_or_none': None}
},
'rt': {
'allow_post': True,
'allow_put': True,
'is_visible': True,
'default': None,
'validate': {'type:string_or_none': None}
},
},
}
class Nuage_router(object):
"""Extension class supporting nuage router.
"""
@classmethod
def get_name(cls):
return "Nuage router"
@classmethod
def get_alias(cls):
return "nuage-router"
@classmethod
def get_description(cls):
return "Nuage Router"
@classmethod
def get_namespace(cls):
return "http://nuagenetworks.net/ext/routers/api/v1.0"
@classmethod
def get_updated(cls):
return "2014-01-01T10:00:00-00:00"
def get_extended_resources(self, version):
if version == "2.0":
return EXTENDED_ATTRIBUTES_2_0
else:
return {}

View File

@ -0,0 +1,59 @@
# Copyright 2014 Alcatel-Lucent USA Inc.
#
# 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.
#
# @author: Ronak Shah, Nuage Networks, Alcatel-Lucent USA Inc.
EXTENDED_ATTRIBUTES_2_0 = {
'subnets': {
'net_partition': {
'allow_post': True,
'allow_put': True,
'is_visible': True,
'default': None,
'validate': {'type:string_or_none': None}
},
},
}
class Nuage_subnet(object):
"""Extension class supporting Nuage subnet.
"""
@classmethod
def get_name(cls):
return "Nuage subnet"
@classmethod
def get_alias(cls):
return "nuage-subnet"
@classmethod
def get_description(cls):
return "Nuage subnet"
@classmethod
def get_namespace(cls):
return "http://nuagenetworks.net/ext/subnets/api/v1.0"
@classmethod
def get_updated(cls):
return "2014-01-01T10:00:00-00:00"
def get_extended_resources(self, version):
if version == "2.0":
return EXTENDED_ATTRIBUTES_2_0
else:
return {}

View File

@ -0,0 +1,74 @@
# Copyright 2014 Alcatel-Lucent USA Inc.
# All Rights Reserved.
#
# 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.
#
# @author: Ronak Shah, Nuage Networks, Alcatel-Lucent USA Inc.
from sqlalchemy import Boolean, Column, ForeignKey, String
from neutron.db import model_base
from neutron.db import models_v2
class NetPartition(model_base.BASEV2, models_v2.HasId):
__tablename__ = 'net_partitions'
name = Column(String(64))
l3dom_tmplt_id = Column(String(36))
l2dom_tmplt_id = Column(String(36))
class NetPartitionRouter(model_base.BASEV2):
__tablename__ = "net_partition_router_mapping"
net_partition_id = Column(String(36),
ForeignKey('net_partitions.id',
ondelete="CASCADE"),
primary_key=True)
router_id = Column(String(36),
ForeignKey('routers.id', ondelete="CASCADE"),
primary_key=True)
nuage_router_id = Column(String(36))
class RouterZone(model_base.BASEV2):
__tablename__ = "router_zone_mapping"
router_id = Column(String(36),
ForeignKey('routers.id', ondelete="CASCADE"),
primary_key=True)
nuage_zone_id = Column(String(36))
nuage_user_id = Column(String(36))
nuage_group_id = Column(String(36))
class SubnetL2Domain(model_base.BASEV2):
__tablename__ = 'subnet_l2dom_mapping'
subnet_id = Column(String(36),
ForeignKey('subnets.id', ondelete="CASCADE"),
primary_key=True)
net_partition_id = Column(String(36),
ForeignKey('net_partitions.id',
ondelete="CASCADE"))
nuage_subnet_id = Column(String(36))
nuage_l2dom_tmplt_id = Column(String(36))
nuage_user_id = Column(String(36))
nuage_group_id = Column(String(36))
class PortVPortMapping(model_base.BASEV2):
__tablename__ = 'port_mapping'
port_id = Column(String(36),
ForeignKey('ports.id', ondelete="CASCADE"),
primary_key=True)
nuage_vport_id = Column(String(36))
nuage_vif_id = Column(String(36))
static_ip = Column(Boolean())

View File

@ -0,0 +1,133 @@
# Copyright 2014 Alcatel-Lucent USA Inc.
#
# 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.
#
# @author: Ronak Shah, Nuage Networks, Alcatel-Lucent USA Inc.
from neutron.db import db_base_plugin_v2
from neutron.plugins.nuage import nuage_models
def add_entrouter_mapping(session, np_id,
router_id,
n_l3id):
ent_rtr_mapping = nuage_models.NetPartitionRouter(net_partition_id=np_id,
router_id=router_id,
nuage_router_id=n_l3id)
session.add(ent_rtr_mapping)
def add_rtrzone_mapping(session, neutron_router_id,
nuage_zone_id,
nuage_user_id=None,
nuage_group_id=None):
rtr_zone_mapping = nuage_models.RouterZone(router_id=neutron_router_id,
nuage_zone_id=nuage_zone_id,
nuage_user_id=nuage_user_id,
nuage_group_id=nuage_group_id)
session.add(rtr_zone_mapping)
def add_subnetl2dom_mapping(session, neutron_subnet_id,
nuage_sub_id,
np_id,
l2dom_id=None,
nuage_user_id=None,
nuage_group_id=None):
subnet_l2dom = nuage_models.SubnetL2Domain(subnet_id=neutron_subnet_id,
nuage_subnet_id=nuage_sub_id,
net_partition_id=np_id,
nuage_l2dom_tmplt_id=l2dom_id,
nuage_user_id=nuage_user_id,
nuage_group_id=nuage_group_id)
session.add(subnet_l2dom)
def update_subnetl2dom_mapping(subnet_l2dom,
new_dict):
subnet_l2dom.update(new_dict)
def add_port_vport_mapping(session, port_id, nuage_vport_id,
nuage_vif_id, static_ip):
port_mapping = nuage_models.PortVPortMapping(port_id=port_id,
nuage_vport_id=nuage_vport_id,
nuage_vif_id=nuage_vif_id,
static_ip=static_ip)
session.add(port_mapping)
return port_mapping
def update_port_vport_mapping(port_mapping,
new_dict):
port_mapping.update(new_dict)
def get_port_mapping_by_id(session, id):
query = session.query(nuage_models.PortVPortMapping)
return query.filter_by(port_id=id).first()
def get_ent_rtr_mapping_by_rtrid(session, rtrid):
query = session.query(nuage_models.NetPartitionRouter)
return query.filter_by(router_id=rtrid).first()
def get_rtr_zone_mapping(session, router_id):
query = session.query(nuage_models.RouterZone)
return query.filter_by(router_id=router_id).first()
def get_subnet_l2dom_by_id(session, id):
query = session.query(nuage_models.SubnetL2Domain)
return query.filter_by(subnet_id=id).first()
def add_net_partition(session, netpart_id,
l3dom_id, l2dom_id,
ent_name):
net_partitioninst = nuage_models.NetPartition(id=netpart_id,
name=ent_name,
l3dom_tmplt_id=l3dom_id,
l2dom_tmplt_id=l2dom_id)
session.add(net_partitioninst)
return net_partitioninst
def delete_net_partition(session, net_partition):
session.delete(net_partition)
def get_ent_rtr_mapping_by_entid(session,
entid):
query = session.query(nuage_models.NetPartitionRouter)
return query.filter_by(net_partition_id=entid).all()
def get_net_partition_by_name(session, name):
query = session.query(nuage_models.NetPartition)
return query.filter_by(name=name).first()
def get_net_partition_by_id(session, id):
query = session.query(nuage_models.NetPartition)
return query.filter_by(id=id).first()
def get_net_partitions(session, filters=None, fields=None):
query = session.query(nuage_models.NetPartition)
common_db = db_base_plugin_v2.CommonDbMixin()
query = common_db._apply_filters_to_query(query,
nuage_models.NetPartition,
filters)
return query

View File

@ -0,0 +1,697 @@
# Copyright 2014 Alcatel-Lucent USA Inc.
#
# 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.
#
# @author: Ronak Shah, Nuage Networks, Alcatel-Lucent USA Inc.
import re
import netaddr
from oslo.config import cfg
from sqlalchemy.orm import exc
from neutron.api import extensions as neutron_extensions
from neutron.api.v2 import attributes
from neutron.common import constants as os_constants
from neutron.common import exceptions as q_exc
from neutron.db import api as db
from neutron.db import db_base_plugin_v2
from neutron.db import external_net_db
from neutron.db import l3_db
from neutron.db import models_v2
from neutron.db import quota_db # noqa
from neutron.extensions import portbindings
from neutron.openstack.common import excutils
from neutron.openstack.common import importutils
from neutron.plugins.nuage.common import config
from neutron.plugins.nuage.common import constants
from neutron.plugins.nuage.common import exceptions as nuage_exc
from neutron.plugins.nuage import extensions
from neutron.plugins.nuage.extensions import netpartition
from neutron.plugins.nuage import nuagedb
from neutron import policy
class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
external_net_db.External_net_db_mixin,
l3_db.L3_NAT_db_mixin,
netpartition.NetPartitionPluginBase):
"""Class that implements Nuage Networks' plugin functionality."""
supported_extension_aliases = ["router", "binding", "external-net",
"net-partition", "nuage-router",
"nuage-subnet", "quotas"]
binding_view = "extension:port_binding:view"
def __init__(self):
super(NuagePlugin, self).__init__()
neutron_extensions.append_api_extensions_path(extensions.__path__)
config.nuage_register_cfg_opts()
self.nuageclient_init()
net_partition = cfg.CONF.RESTPROXY.default_net_partition_name
self._create_default_net_partition(net_partition)
def nuageclient_init(self):
server = cfg.CONF.RESTPROXY.server
serverauth = cfg.CONF.RESTPROXY.serverauth
serverssl = cfg.CONF.RESTPROXY.serverssl
base_uri = cfg.CONF.RESTPROXY.base_uri
auth_resource = cfg.CONF.RESTPROXY.auth_resource
organization = cfg.CONF.RESTPROXY.organization
nuageclient = importutils.import_module('nuagenetlib.nuageclient')
self.nuageclient = nuageclient.NuageClient(server, base_uri,
serverssl, serverauth,
auth_resource,
organization)
def _resource_finder(self, context, for_resource, resource, user_req):
match = re.match(attributes.UUID_PATTERN, user_req[resource])
if match:
obj_lister = getattr(self, "get_%s" % resource)
found_resource = obj_lister(context, user_req[resource])
if not found_resource:
msg = (_("%(resource)s with id %(resource_id)s does not "
"exist") % {'resource': resource,
'resource_id': user_req[resource]})
raise q_exc.BadRequest(resource=for_resource, msg=msg)
else:
filter = {'name': [user_req[resource]]}
obj_lister = getattr(self, "get_%ss" % resource)
found_resource = obj_lister(context, filters=filter)
if not found_resource:
msg = (_("Either %(resource)s %(req_resource)s not found "
"or you dont have credential to access it")
% {'resource': resource,
'req_resource': user_req[resource]})
raise q_exc.BadRequest(resource=for_resource, msg=msg)
if len(found_resource) > 1:
msg = (_("More than one entry found for %(resource)s "
"%(req_resource)s. Use id instead")
% {'resource': resource,
'req_resource': user_req[resource]})
raise q_exc.BadRequest(resource=for_resource, msg=msg)
found_resource = found_resource[0]
return found_resource
def _update_port_ip(self, context, port, new_ip):
subid = port['fixed_ips'][0]['subnet_id']
new_fixed_ips = {}
new_fixed_ips['subnet_id'] = subid
new_fixed_ips['ip_address'] = new_ip
ips, prev_ips = self._update_ips_for_port(context,
port["network_id"],
port['id'],
port["fixed_ips"],
[new_fixed_ips])
# Update ips if necessary
for ip in ips:
allocated = models_v2.IPAllocation(
network_id=port['network_id'], port_id=port['id'],
ip_address=ip['ip_address'], subnet_id=ip['subnet_id'])
context.session.add(allocated)
def _create_update_port(self, context, port,
port_mapping, subnet_mapping):
filters = {'device_id': [port['device_id']]}
ports = self.get_ports(context, filters)
netpart_id = subnet_mapping['net_partition_id']
net_partition = nuagedb.get_net_partition_by_id(context.session,
netpart_id)
params = {
'id': port['device_id'],
'mac': port['mac_address'],
'parent_id': subnet_mapping['nuage_subnet_id'],
'net_partition': net_partition,
'ip': None,
'no_of_ports': len(ports),
'tenant': port['tenant_id']
}
if port_mapping['static_ip']:
params['ip'] = port['fixed_ips'][0]['ip_address']
nuage_vm = self.nuageclient.create_vms(params)
if nuage_vm:
if port['fixed_ips'][0]['ip_address'] != str(nuage_vm['ip']):
self._update_port_ip(context, port, nuage_vm['ip'])
port_dict = {
'nuage_vport_id': nuage_vm['vport_id'],
'nuage_vif_id': nuage_vm['vif_id']
}
nuagedb.update_port_vport_mapping(port_mapping,
port_dict)
def create_port(self, context, port):
session = context.session
with session.begin(subtransactions=True):
p = port['port']
port = super(NuagePlugin, self).create_port(context, port)
device_owner = port.get('device_owner', None)
if (device_owner and
device_owner not in constants.AUTO_CREATE_PORT_OWNERS):
if 'fixed_ips' not in port or len(port['fixed_ips']) == 0:
return self._extend_port_dict_binding(context, port)
subnet_id = port['fixed_ips'][0]['subnet_id']
subnet_mapping = nuagedb.get_subnet_l2dom_by_id(session,
subnet_id)
if subnet_mapping:
static_ip = False
if (attributes.is_attr_set(p['fixed_ips']) and
'ip_address' in p['fixed_ips'][0]):
static_ip = True
nuage_vport_id = None
nuage_vif_id = None
port_mapping = nuagedb.add_port_vport_mapping(
session,
port['id'],
nuage_vport_id,
nuage_vif_id,
static_ip)
port_prefix = constants.NOVA_PORT_OWNER_PREF
if port['device_owner'].startswith(port_prefix):
#This request is coming from nova
try:
self._create_update_port(context, port,
port_mapping,
subnet_mapping)
except Exception:
with excutils.save_and_reraise_exception():
super(NuagePlugin, self).delete_port(
context,
port['id'])
return self._extend_port_dict_binding(context, port)
def update_port(self, context, id, port):
p = port['port']
if p.get('device_owner', '').startswith(
constants.NOVA_PORT_OWNER_PREF):
session = context.session
with session.begin(subtransactions=True):
port = self._get_port(context, id)
port.update(p)
if 'fixed_ips' not in port or len(port['fixed_ips']) == 0:
return self._make_port_dict(port)
subnet_id = port['fixed_ips'][0]['subnet_id']
subnet_mapping = nuagedb.get_subnet_l2dom_by_id(session,
subnet_id)
if not subnet_mapping:
msg = (_("Subnet %s not found on VSD") % subnet_id)
raise q_exc.BadRequest(resource='port', msg=msg)
port_mapping = nuagedb.get_port_mapping_by_id(session,
id)
if not port_mapping:
msg = (_("Port-Mapping for port %s not "
" found on VSD") % id)
raise q_exc.BadRequest(resource='port', msg=msg)
if not port_mapping['nuage_vport_id']:
self._create_update_port(context, port,
port_mapping, subnet_mapping)
updated_port = self._make_port_dict(port)
else:
updated_port = super(NuagePlugin, self).update_port(context, id,
port)
return updated_port
def delete_port(self, context, id, l3_port_check=True):
if l3_port_check:
self.prevent_l3_port_deletion(context, id)
port = self._get_port(context, id)
port_mapping = nuagedb.get_port_mapping_by_id(context.session,
id)
# This is required for to pass ut test_floatingip_port_delete
self.disassociate_floatingips(context, id)
if not port['fixed_ips']:
return super(NuagePlugin, self).delete_port(context, id)
sub_id = port['fixed_ips'][0]['subnet_id']
subnet_mapping = nuagedb.get_subnet_l2dom_by_id(context.session,
sub_id)
if not subnet_mapping:
return super(NuagePlugin, self).delete_port(context, id)
netpart_id = subnet_mapping['net_partition_id']
net_partition = nuagedb.get_net_partition_by_id(context.session,
netpart_id)
# Need to call this explicitly to delete vport_vporttag_mapping
if constants.NOVA_PORT_OWNER_PREF in port['device_owner']:
# This was a VM Port
filters = {'device_id': [port['device_id']]}
ports = self.get_ports(context, filters)
params = {
'no_of_ports': len(ports),
'net_partition': net_partition,
'tenant': port['tenant_id'],
'mac': port['mac_address'],
'nuage_vif_id': port_mapping['nuage_vif_id'],
'id': port['device_id']
}
self.nuageclient.delete_vms(params)
super(NuagePlugin, self).delete_port(context, id)
def _check_view_auth(self, context, resource, action):
return policy.check(context, action, resource)
def _extend_port_dict_binding(self, context, port):
if self._check_view_auth(context, port, self.binding_view):
port[portbindings.VIF_TYPE] = portbindings.VIF_TYPE_OVS
port[portbindings.VIF_DETAILS] = {
portbindings.CAP_PORT_FILTER: False
}
return port
def get_port(self, context, id, fields=None):
port = super(NuagePlugin, self).get_port(context, id, fields)
return self._fields(self._extend_port_dict_binding(context, port),
fields)
def get_ports(self, context, filters=None, fields=None):
ports = super(NuagePlugin, self).get_ports(context, filters, fields)
return [self._fields(self._extend_port_dict_binding(context, port),
fields) for port in ports]
def _check_router_subnet_for_tenant(self, context):
# Search router and subnet tables.
# If no entry left delete user and group from VSD
filters = {'tenant_id': [context.tenant]}
routers = self.get_routers(context, filters=filters)
subnets = self.get_subnets(context, filters=filters)
return bool(routers or subnets)
def create_network(self, context, network):
net = network['network']
with context.session.begin(subtransactions=True):
net = super(NuagePlugin, self).create_network(context,
network)
self._process_l3_create(context, net, network['network'])
return net
def update_network(self, context, id, network):
with context.session.begin(subtransactions=True):
net = super(NuagePlugin, self).update_network(context, id,
network)
self._process_l3_update(context, net, network['network'])
return net
def delete_network(self, context, id):
filter = {'network_id': [id]}
subnets = self.get_subnets(context, filters=filter)
for subnet in subnets:
self.delete_subnet(context, subnet['id'])
super(NuagePlugin, self).delete_network(context, id)
def _get_net_partition_for_subnet(self, context, subnet):
subn = subnet['subnet']
ent = subn.get('net_partition', None)
if not ent:
def_net_part = cfg.CONF.RESTPROXY.default_net_partition_name
net_partition = nuagedb.get_net_partition_by_name(context.session,
def_net_part)
else:
net_partition = self._resource_finder(context, 'subnet',
'net_partition', subn)
if not net_partition:
msg = _('Either net_partition is not provided with subnet OR '
'default net_partition is not created at the start')
raise q_exc.BadRequest(resource='subnet', msg=msg)
return net_partition
def _validate_create_subnet(self, subnet):
if ('host_routes' in subnet and
attributes.is_attr_set(subnet['host_routes'])):
msg = 'host_routes extensions not supported for subnets'
raise nuage_exc.OperationNotSupported(msg=msg)
if subnet['gateway_ip'] is None:
msg = "no-gateway option not supported with subnets"
raise nuage_exc.OperationNotSupported(msg=msg)
def create_subnet(self, context, subnet):
subn = subnet['subnet']
net_id = subn['network_id']
if self._network_is_external(context, net_id):
return super(NuagePlugin, self).create_subnet(context, subnet)
self._validate_create_subnet(subn)
net_partition = self._get_net_partition_for_subnet(context, subnet)
neutron_subnet = super(NuagePlugin, self).create_subnet(context,
subnet)
net = netaddr.IPNetwork(neutron_subnet['cidr'])
params = {
'net_partition': net_partition,
'tenant_id': neutron_subnet['tenant_id'],
'net': net
}
try:
nuage_subnet = self.nuageclient.create_subnet(neutron_subnet,
params)
except Exception:
with excutils.save_and_reraise_exception():
super(NuagePlugin, self).delete_subnet(context,
neutron_subnet['id'])
if nuage_subnet:
l2dom_id = str(nuage_subnet['nuage_l2template_id'])
user_id = nuage_subnet['nuage_userid']
group_id = nuage_subnet['nuage_groupid']
id = nuage_subnet['nuage_l2domain_id']
session = context.session
with session.begin(subtransactions=True):
nuagedb.add_subnetl2dom_mapping(session,
neutron_subnet['id'],
id,
net_partition['id'],
l2dom_id=l2dom_id,
nuage_user_id=user_id,
nuage_group_id=group_id)
return neutron_subnet
def delete_subnet(self, context, id):
subnet = self.get_subnet(context, id)
if self._network_is_external(context, subnet['network_id']):
return super(NuagePlugin, self).delete_subnet(context, id)
subnet_l2dom = nuagedb.get_subnet_l2dom_by_id(context.session, id)
if subnet_l2dom:
template_id = subnet_l2dom['nuage_l2dom_tmplt_id']
try:
self.nuageclient.delete_subnet(subnet_l2dom['nuage_subnet_id'],
template_id)
except Exception:
msg = (_('Unable to complete operation on subnet %s.'
'One or more ports have an IP allocation '
'from this subnet.') % id)
raise q_exc.BadRequest(resource='subnet', msg=msg)
super(NuagePlugin, self).delete_subnet(context, id)
if subnet_l2dom and not self._check_router_subnet_for_tenant(context):
self.nuageclient.delete_user(subnet_l2dom['nuage_user_id'])
self.nuageclient.delete_group(subnet_l2dom['nuage_group_id'])
def add_router_interface(self, context, router_id, interface_info):
session = context.session
with session.begin(subtransactions=True):
rtr_if_info = super(NuagePlugin,
self).add_router_interface(context,
router_id,
interface_info)
subnet_id = rtr_if_info['subnet_id']
subn = self.get_subnet(context, subnet_id)
rtr_zone_mapping = nuagedb.get_rtr_zone_mapping(session,
router_id)
ent_rtr_mapping = nuagedb.get_ent_rtr_mapping_by_rtrid(session,
router_id)
subnet_l2dom = nuagedb.get_subnet_l2dom_by_id(session,
subnet_id)
if not rtr_zone_mapping or not ent_rtr_mapping:
super(NuagePlugin,
self).remove_router_interface(context,
router_id,
interface_info)
msg = (_("Router %s does not hold default zone OR "
"net_partition mapping. Router-IF add failed")
% router_id)
raise q_exc.BadRequest(resource='router', msg=msg)
if not subnet_l2dom:
super(NuagePlugin,
self).remove_router_interface(context,
router_id,
interface_info)
msg = (_("Subnet %s does not hold Nuage VSD reference. "
"Router-IF add failed") % subnet_id)
raise q_exc.BadRequest(resource='subnet', msg=msg)
if (subnet_l2dom['net_partition_id'] !=
ent_rtr_mapping['net_partition_id']):
super(NuagePlugin,
self).remove_router_interface(context,
router_id,
interface_info)
msg = (_("Subnet %(subnet)s and Router %(router)s belong to "
"different net_partition Router-IF add "
"not permitted") % {'subnet': subnet_id,
'router': router_id})
raise q_exc.BadRequest(resource='subnet', msg=msg)
nuage_subnet_id = subnet_l2dom['nuage_subnet_id']
nuage_l2dom_tmplt_id = subnet_l2dom['nuage_l2dom_tmplt_id']
if self.nuageclient.vms_on_l2domain(nuage_subnet_id):
super(NuagePlugin,
self).remove_router_interface(context,
router_id,
interface_info)
msg = (_("Subnet %s has one or more active VMs "
"Router-IF add not permitted") % subnet_id)
raise q_exc.BadRequest(resource='subnet', msg=msg)
self.nuageclient.delete_subnet(nuage_subnet_id,
nuage_l2dom_tmplt_id)
net = netaddr.IPNetwork(subn['cidr'])
params = {
'net': net,
'zone_id': rtr_zone_mapping['nuage_zone_id']
}
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)
except Exception:
with excutils.save_and_reraise_exception():
super(NuagePlugin,
self).remove_router_interface(context,
router_id,
interface_info)
if nuage_subnet:
ns_dict = {}
ns_dict['nuage_subnet_id'] = nuage_subnet['nuage_subnetid']
ns_dict['nuage_l2dom_tmplt_id'] = None
nuagedb.update_subnetl2dom_mapping(subnet_l2dom,
ns_dict)
return rtr_if_info
def remove_router_interface(self, context, router_id, interface_info):
if 'subnet_id' in interface_info:
subnet_id = interface_info['subnet_id']
subnet = self.get_subnet(context, subnet_id)
found = False
try:
filters = {'device_id': [router_id],
'device_owner':
[os_constants.DEVICE_OWNER_ROUTER_INTF],
'network_id': [subnet['network_id']]}
ports = self.get_ports(context, filters)
for p in ports:
if p['fixed_ips'][0]['subnet_id'] == subnet_id:
found = True
break
except exc.NoResultFound:
msg = (_("No router interface found for Router %s. "
"Router-IF delete failed") % router_id)
raise q_exc.BadRequest(resource='router', msg=msg)
if not found:
msg = (_("No router interface found for Router %s. "
"Router-IF delete failed") % router_id)
raise q_exc.BadRequest(resource='router', msg=msg)
elif 'port_id' in interface_info:
port_db = self._get_port(context, interface_info['port_id'])
if not port_db:
msg = (_("No router interface found for Router %s. "
"Router-IF delete failed") % router_id)
raise q_exc.BadRequest(resource='router', msg=msg)
subnet_id = port_db['fixed_ips'][0]['subnet_id']
session = context.session
with session.begin(subtransactions=True):
subnet_l2dom = nuagedb.get_subnet_l2dom_by_id(session,
subnet_id)
nuage_subn_id = subnet_l2dom['nuage_subnet_id']
if self.nuageclient.vms_on_l2domain(nuage_subn_id):
msg = (_("Subnet %s has one or more active VMs "
"Router-IF delete not permitted") % subnet_id)
raise q_exc.BadRequest(resource='subnet', msg=msg)
neutron_subnet = self.get_subnet(context, subnet_id)
ent_rtr_mapping = nuagedb.get_ent_rtr_mapping_by_rtrid(
context.session,
router_id)
if not ent_rtr_mapping:
msg = (_("Router %s does not hold net_partition "
"assoc on Nuage VSD. Router-IF delete failed")
% router_id)
raise q_exc.BadRequest(resource='router', msg=msg)
net = netaddr.IPNetwork(neutron_subnet['cidr'])
net_part_id = ent_rtr_mapping['net_partition_id']
net_partition = self.get_net_partition(context,
net_part_id)
params = {
'net_partition': net_partition,
'tenant_id': neutron_subnet['tenant_id'],
'net': net
}
nuage_subnet = self.nuageclient.create_subnet(neutron_subnet,
params)
self.nuageclient.delete_domain_subnet(nuage_subn_id)
info = super(NuagePlugin,
self).remove_router_interface(context, router_id,
interface_info)
if nuage_subnet:
tmplt_id = str(nuage_subnet['nuage_l2template_id'])
ns_dict = {}
ns_dict['nuage_subnet_id'] = nuage_subnet['nuage_l2domain_id']
ns_dict['nuage_l2dom_tmplt_id'] = tmplt_id
nuagedb.update_subnetl2dom_mapping(subnet_l2dom,
ns_dict)
return info
def _get_net_partition_for_router(self, context, router):
rtr = router['router']
ent = rtr.get('net_partition', None)
if not ent:
def_net_part = cfg.CONF.RESTPROXY.default_net_partition_name
net_partition = nuagedb.get_net_partition_by_name(context.session,
def_net_part)
else:
net_partition = self._resource_finder(context, 'router',
'net_partition', rtr)
if not net_partition:
msg = _("Either net_partition is not provided with router OR "
"default net_partition is not created at the start")
raise q_exc.BadRequest(resource='router', msg=msg)
return net_partition
def create_router(self, context, router):
net_partition = self._get_net_partition_for_router(context, router)
neutron_router = super(NuagePlugin, self).create_router(context,
router)
params = {
'net_partition': net_partition,
'tenant_id': neutron_router['tenant_id']
}
try:
nuage_router = self.nuageclient.create_router(neutron_router,
router['router'],
params)
except Exception:
with excutils.save_and_reraise_exception():
super(NuagePlugin, self).delete_router(context,
neutron_router['id'])
if nuage_router:
user_id = nuage_router['nuage_userid']
group_id = nuage_router['nuage_groupid']
with context.session.begin(subtransactions=True):
nuagedb.add_entrouter_mapping(context.session,
net_partition['id'],
neutron_router['id'],
nuage_router['nuage_domain_id'])
nuagedb.add_rtrzone_mapping(context.session,
neutron_router['id'],
nuage_router['nuage_def_zone_id'],
nuage_user_id=user_id,
nuage_group_id=group_id)
return neutron_router
def delete_router(self, context, id):
session = context.session
ent_rtr_mapping = nuagedb.get_ent_rtr_mapping_by_rtrid(session,
id)
if ent_rtr_mapping:
nuage_router_id = ent_rtr_mapping['nuage_router_id']
self.nuageclient.delete_router(nuage_router_id)
router_zone = nuagedb.get_rtr_zone_mapping(session, id)
super(NuagePlugin, self).delete_router(context, id)
if router_zone and not self._check_router_subnet_for_tenant(context):
self.nuageclient.delete_user(router_zone['nuage_user_id'])
self.nuageclient.delete_group(router_zone['nuage_group_id'])
def _make_net_partition_dict(self, net_partition, fields=None):
res = {
'id': net_partition['id'],
'name': net_partition['name'],
'l3dom_tmplt_id': net_partition['l3dom_tmplt_id'],
'l2dom_tmplt_id': net_partition['l2dom_tmplt_id'],
}
return self._fields(res, fields)
def _create_net_partition(self, session, net_part_name):
fip_quota = cfg.CONF.RESTPROXY.default_floatingip_quota
params = {
"name": net_part_name,
"fp_quota": str(fip_quota)
}
nuage_net_partition = self.nuageclient.create_net_partition(params)
net_partitioninst = None
if nuage_net_partition:
nuage_entid = nuage_net_partition['nuage_entid']
l3dom_id = nuage_net_partition['l3dom_id']
l2dom_id = nuage_net_partition['l2dom_id']
with session.begin():
net_partitioninst = nuagedb.add_net_partition(session,
nuage_entid,
l3dom_id,
l2dom_id,
net_part_name)
if not net_partitioninst:
return {}
return self._make_net_partition_dict(net_partitioninst)
def _create_default_net_partition(self, default_net_part):
self.nuageclient.check_del_def_net_partition(default_net_part)
session = db.get_session()
net_partition = nuagedb.get_net_partition_by_name(session,
default_net_part)
if net_partition:
with session.begin(subtransactions=True):
nuagedb.delete_net_partition(session, net_partition)
self._create_net_partition(session, default_net_part)
def create_net_partition(self, context, net_partition):
ent = net_partition['net_partition']
session = context.session
return self._create_net_partition(session, ent["name"])
def delete_net_partition(self, context, id):
ent_rtr_mapping = nuagedb.get_ent_rtr_mapping_by_entid(
context.session,
id)
if ent_rtr_mapping:
msg = (_("One or more router still attached to "
"net_partition %s.") % id)
raise q_exc.BadRequest(resource='net_partition', msg=msg)
net_partition = nuagedb.get_net_partition_by_id(context.session, id)
if not net_partition:
msg = (_("NetPartition with %s does not exist") % id)
raise q_exc.BadRequest(resource='net_partition', msg=msg)
l3dom_tmplt_id = net_partition['l3dom_tmplt_id']
l2dom_tmplt_id = net_partition['l2dom_tmplt_id']
self.nuageclient.delete_net_partition(net_partition['id'],
l3dom_id=l3dom_tmplt_id,
l2dom_id=l2dom_tmplt_id)
with context.session.begin(subtransactions=True):
nuagedb.delete_net_partition(context.session,
net_partition)
def get_net_partition(self, context, id, fields=None):
net_partition = nuagedb.get_net_partition_by_id(context.session,
id)
return self._make_net_partition_dict(net_partition)
def get_net_partitions(self, context, filters=None, fields=None):
net_partitions = nuagedb.get_net_partitions(context.session,
filters=filters,
fields=fields)
return [self._make_net_partition_dict(net_partition, fields)
for net_partition in net_partitions]

View File

View File

@ -0,0 +1,85 @@
# Copyright 2014 Alcatel-Lucent USA Inc.
#
# 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.
#
# @author: Ronak Shah, Aniket Dandekar, Nuage Networks, Alcatel-Lucent USA Inc.
import uuid
class FakeNuageClient(object):
def __init__(self, server, base_uri, serverssl,
serverauth, auth_resource, organization):
pass
def rest_call(self, action, resource, data, extra_headers=None):
pass
def vms_on_l2domain(self, l2dom_id):
pass
def create_subnet(self, neutron_subnet, params):
nuage_subnet = {
'nuage_l2template_id': str(uuid.uuid4()),
'nuage_userid': str(uuid.uuid4()),
'nuage_groupid': str(uuid.uuid4()),
'nuage_l2domain_id': str(uuid.uuid4())
}
return nuage_subnet
def delete_subnet(self, id, template_id):
pass
def create_router(self, neutron_router, router, params):
nuage_router = {
'nuage_userid': str(uuid.uuid4()),
'nuage_groupid': str(uuid.uuid4()),
'nuage_domain_id': str(uuid.uuid4()),
'nuage_def_zone_id': str(uuid.uuid4()),
}
return nuage_router
def delete_router(self, id):
pass
def delete_user(self, id):
pass
def delete_group(self, id):
pass
def create_domain_subnet(self, neutron_subnet, params):
pass
def delete_domain_subnet(self, id):
pass
def create_net_partition(self, params):
fake_net_partition = {
'nuage_entid': str(uuid.uuid4()),
'l3dom_id': str(uuid.uuid4()),
'l2dom_id': str(uuid.uuid4()),
}
return fake_net_partition
def delete_net_partition(self, id, l3dom_id=None, l2dom_id=None):
pass
def check_del_def_net_partition(self, ent_name):
pass
def create_vms(self, params):
pass
def delete_vms(self, params):
pass

View File

@ -0,0 +1,93 @@
# Copyright 2014 Alcatel-Lucent USA Inc.
#
# 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.
#
# @author: Ronak Shah, Nuage Networks, Alcatel-Lucent USA Inc.
import contextlib
import uuid
import webob.exc
from neutron.plugins.nuage.extensions import netpartition as netpart_ext
from neutron.tests.unit.nuage import test_nuage_plugin
from neutron.tests.unit import test_extensions
class NetPartitionTestExtensionManager(object):
def get_resources(self):
return netpart_ext.Netpartition.get_resources()
def get_actions(self):
return []
def get_request_extensions(self):
return []
class NetPartitionTestCase(test_nuage_plugin.NuagePluginV2TestCase):
def setUp(self):
ext_mgr = NetPartitionTestExtensionManager()
super(NetPartitionTestCase, self).setUp()
self.ext_api = test_extensions.setup_extensions_middleware(ext_mgr)
def _make_netpartition(self, fmt, name):
data = {
'net_partition': {
'name': name,
'tenant_id': uuid.uuid4()
}
}
netpart_req = self.new_create_request('net-partitions', data, fmt)
resp = netpart_req.get_response(self.ext_api)
if resp.status_int >= webob.exc.HTTPClientError.code:
raise webob.exc.HTTPClientError(code=resp.status_int)
return self.deserialize(fmt, resp)
def _del_netpartition(self, id):
self._delete('net-partitions', id)
@contextlib.contextmanager
def netpartition(self, name='netpartition1',
do_delete=True,
fmt=None,
**kwargs):
netpart = self._make_netpartition(fmt or self.fmt, name)
try:
yield netpart
finally:
if do_delete:
self._del_netpartition(netpart['net_partition']['id'])
def test_create_netpartition(self):
name = 'netpart1'
keys = [('name', name)]
with self.netpartition(name=name) as netpart:
for k, v in keys:
self.assertEqual(netpart['net_partition'][k], v)
def test_delete_netpartition(self):
name = 'netpart1'
netpart = self._make_netpartition(self.fmt, name)
req = self.new_delete_request('net-partitions',
netpart['net_partition']['id'])
res = req.get_response(self.ext_api)
self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code)
def test_show_netpartition(self):
with self.netpartition(name='netpart1') as npart:
req = self.new_show_request('net-partitions',
npart['net_partition']['id'])
res = self.deserialize(self.fmt, req.get_response(self.ext_api))
self.assertEqual(res['net_partition']['name'],
npart['net_partition']['name'])

View File

@ -0,0 +1,162 @@
# Copyright 2014 Alcatel-Lucent USA Inc.
#
# 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.
#
# @author: Ronak Shah, Aniket Dandekar, Nuage Networks, Alcatel-Lucent USA Inc.
import os
import mock
from oslo.config import cfg
from neutron.extensions import portbindings
from neutron.plugins.nuage import extensions
from neutron.plugins.nuage import plugin as nuage_plugin
from neutron.tests.unit import _test_extension_portbindings as test_bindings
from neutron.tests.unit.nuage import fake_nuageclient
from neutron.tests.unit import test_db_plugin
from neutron.tests.unit import test_l3_plugin
API_EXT_PATH = os.path.dirname(extensions.__file__)
FAKE_DEFAULT_ENT = 'default'
NUAGE_PLUGIN_PATH = 'neutron.plugins.nuage.plugin'
FAKE_SERVER = '1.1.1.1'
FAKE_SERVER_AUTH = 'user:pass'
FAKE_SERVER_SSL = False
FAKE_BASE_URI = '/base/'
FAKE_AUTH_RESOURCE = '/auth'
FAKE_ORGANIZATION = 'fake_org'
_plugin_name = ('%s.NuagePlugin' % NUAGE_PLUGIN_PATH)
class NuagePluginV2TestCase(test_db_plugin.NeutronDbPluginV2TestCase):
def setUp(self, plugin=_plugin_name,
ext_mgr=None, service_plugins=None):
def mock_nuageClient_init(self):
server = FAKE_SERVER
serverauth = FAKE_SERVER_AUTH
serverssl = FAKE_SERVER_SSL
base_uri = FAKE_BASE_URI
auth_resource = FAKE_AUTH_RESOURCE
organization = FAKE_ORGANIZATION
self.nuageclient = None
self.nuageclient = fake_nuageclient.FakeNuageClient(server,
base_uri,
serverssl,
serverauth,
auth_resource,
organization)
with mock.patch.object(nuage_plugin.NuagePlugin,
'nuageclient_init', new=mock_nuageClient_init):
cfg.CONF.set_override('api_extensions_path',
API_EXT_PATH)
super(NuagePluginV2TestCase, self).setUp(plugin=plugin,
ext_mgr=ext_mgr)
class TestNuageBasicGet(NuagePluginV2TestCase,
test_db_plugin.TestBasicGet):
pass
class TestNuageV2HTTPResponse(NuagePluginV2TestCase,
test_db_plugin.TestV2HTTPResponse):
pass
class TestNuageNetworksV2(NuagePluginV2TestCase,
test_db_plugin.TestNetworksV2):
pass
class TestNuageSubnetsV2(NuagePluginV2TestCase,
test_db_plugin.TestSubnetsV2):
def test_create_subnet_bad_hostroutes(self):
self.skipTest("Plugin does not support Neutron Subnet host-routes")
def test_create_subnet_inconsistent_ipv4_hostroute_dst_v6(self):
self.skipTest("Plugin does not support Neutron Subnet host-routes")
def test_create_subnet_inconsistent_ipv4_hostroute_np_v6(self):
self.skipTest("Plugin does not support Neutron Subnet host-routes")
def test_update_subnet_adding_additional_host_routes_and_dns(self):
self.skipTest("Plugin does not support Neutron Subnet host-routes")
def test_update_subnet_inconsistent_ipv6_hostroute_dst_v4(self):
self.skipTest("Plugin does not support Neutron Subnet host-routes")
def test_update_subnet_inconsistent_ipv6_hostroute_np_v4(self):
self.skipTest("Plugin does not support Neutron Subnet host-routes")
def test_create_subnet_with_one_host_route(self):
self.skipTest("Plugin does not support Neutron Subnet host-routes")
def test_create_subnet_with_two_host_routes(self):
self.skipTest("Plugin does not support Neutron Subnet host-routes")
def test_create_subnet_with_too_many_routes(self):
self.skipTest("Plugin does not support Neutron Subnet host-routes")
def test_update_subnet_route(self):
self.skipTest("Plugin does not support Neutron Subnet host-routes")
def test_update_subnet_route_to_None(self):
self.skipTest("Plugin does not support Neutron Subnet host-routes")
def test_update_subnet_route_with_too_many_entries(self):
self.skipTest("Plugin does not support Neutron Subnet host-routes")
def test_delete_subnet_with_route(self):
self.skipTest("Plugin does not support Neutron Subnet host-routes")
def test_delete_subnet_with_dns_and_route(self):
self.skipTest("Plugin does not support Neutron Subnet host-routes")
def test_validate_subnet_host_routes_exhausted(self):
self.skipTest("Plugin does not support Neutron Subnet host-routes")
def test_validate_subnet_dns_nameservers_exhausted(self):
self.skipTest("Plugin does not support Neutron Subnet host-routes")
def test_create_subnet_with_none_gateway(self):
self.skipTest("Plugin does not support "
"Neutron Subnet no-gateway option")
def test_create_subnet_with_none_gateway_fully_allocated(self):
self.skipTest("Plugin does not support Neutron "
"Subnet no-gateway option")
def test_create_subnet_with_none_gateway_allocation_pool(self):
self.skipTest("Plugin does not support Neutron "
"Subnet no-gateway option")
class TestNuagePluginPortBinding(NuagePluginV2TestCase,
test_bindings.PortBindingsTestCase):
VIF_TYPE = portbindings.VIF_TYPE_OVS
def setUp(self):
super(TestNuagePluginPortBinding, self).setUp()
class TestNuagePortsV2(NuagePluginV2TestCase,
test_db_plugin.TestPortsV2):
pass
class TestNuageL3NatTestCase(NuagePluginV2TestCase,
test_l3_plugin.L3NatDBIntTestCase):
pass