L2gateway db implementation for RESTful API

This is initial db related files required
for implementing l2gateway RESTful API

Implements: blueprint l2-gateway-api
Change-Id: Ie6bd6b506bd704e0a86273ec7240b7eebb3b18b1
changes/97/144097/30
Selvakumar 9 years ago committed by Selvakumar S
parent 522c44a3e1
commit 47de11fc2e

@ -0,0 +1,91 @@
# Copyright 2015 OpenStack Foundation
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
#
# 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.
from neutron.common import exceptions
import sqlalchemy as sa
class L2GatewayCommonDbMixin(object):
def _apply_filters_to_query(self, query, model, filters):
"""Apply filters to query for the models."""
if filters:
for key, value in filters.iteritems():
column = getattr(model, key, None)
if column:
query = query.filter(column.in_(value))
return query
def _model_query(self, context, model):
"""Query model based on filter."""
query = context.session.query(model)
query_filter = None
if not context.is_admin and hasattr(model, 'tenant_id'):
if hasattr(model, 'shared'):
query_filter = ((model.tenant_id == context.tenant_id) |
(model.shared == sa.true()))
else:
query_filter = (model.tenant_id == context.tenant_id)
if query_filter is not None:
query = query.filter(query_filter)
return query
def _get_collection_query(self, context, model, filters=None,
sorts=None, limit=None, marker_obj=None,
page_reverse=False):
"""Get collection query for the models."""
collection = self._model_query(context, model)
collection = self._apply_filters_to_query(collection, model, filters)
return collection
def _get_marker_obj(self, context, resource, limit, marker):
"""Get marker object for the resource."""
if limit and marker:
return getattr(self, '_get_%s' % resource)(context, marker)
return None
def _fields(self, resource, fields):
"""Get fields for the resource for get query."""
if fields:
return dict(((key, item) for key, item in resource.items()
if key in fields))
return resource
def _get_tenant_id_for_create(self, context, resource):
"""Get tenant id for creation of resources."""
if context.is_admin and 'tenant_id' in resource:
tenant_id = resource['tenant_id']
elif ('tenant_id' in resource and
resource['tenant_id'] != context.tenant_id):
reason = _('Cannot create resource for another tenant')
raise exceptions.AdminRequired(reason=reason)
else:
tenant_id = context.tenant_id
return tenant_id
def _get_collection(self, context, model, dict_func, filters=None,
fields=None, sorts=None, limit=None, marker_obj=None,
page_reverse=False):
"""Get collection object based on query for resources."""
query = self._get_collection_query(context, model, filters=filters,
sorts=sorts,
limit=limit,
marker_obj=marker_obj,
page_reverse=page_reverse)
items = [dict_func(c, fields) for c in query]
if limit and page_reverse:
items.reverse()
return items

@ -0,0 +1,358 @@
# Copyright 2015 OpenStack Foundation
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
#
# 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.
from neutron.common import exceptions
from neutron.openstack.common import log as logging
from neutron.openstack.common import uuidutils
from networking_l2gw.db.l2gateway import db_query
from networking_l2gw.db.l2gateway import l2gateway_models as models
from networking_l2gw.extensions import l2gateway
from networking_l2gw.extensions import l2gatewayconnection
from networking_l2gw.services.l2gateway.common import config
from networking_l2gw.services.l2gateway.common import constants
from networking_l2gw.services.l2gateway.common import l2gw_validators
from networking_l2gw.services.l2gateway import exceptions as l2gw_exc
from sqlalchemy.orm import exc as sa_orm_exc
LOG = logging.getLogger(__name__)
class L2GatewayMixin(l2gateway.L2GatewayPluginBase,
db_query.L2GatewayCommonDbMixin,
l2gatewayconnection.L2GatewayConnectionPluginBase):
"""Class L2GatewayMixin for handling l2_gateway resource."""
gateway_resource = constants.GATEWAY_RESOURCE_NAME
connection_resource = constants.CONNECTION_RESOURCE_NAME
config.register_l2gw_opts_helper()
def _get_l2_gateway(self, context, gw_id):
try:
gw = context.session.query(models.L2Gateway).get(gw_id)
except sa_orm_exc.NoResultFound:
raise l2gw_exc.L2GatewayNotFound(gateway_id=gw_id)
return gw
def _get_l2_gateways(self, context):
try:
gw = context.session.query(models.L2Gateway).all()
except sa_orm_exc.NoResultFound:
raise l2gw_exc.L2GatewayNotFound(gateway_id="")
return gw
def _get_l2_gateway_interface(self, context, id):
try:
gw = context.session.query(models.L2GatewayInterface).filter_by(
device_id=id).all()
except sa_orm_exc.NoResultFound:
raise l2gw_exc.L2GatewayInterfaceNotFound(interface_id=id)
return gw
def _check_vlan_on_interface(self, context, l2gw_id):
device_db = self._get_l2_gateway_device(context, l2gw_id)
for device_model in device_db:
interface_db = self._get_l2_gateway_interface(context,
device_model.id)
for int_model in interface_db:
query = context.session.query(models.L2GatewayInterface)
int_db = query.filter_by(id=int_model.id).first()
seg_id = int_db[constants.SEG_ID]
if seg_id > 0:
return True
return False
def _get_l2_gateway_device(self, context, l2gw_id):
try:
gw = context.session.query(models.L2GatewayDevice).filter_by(
l2_gateway_id=l2gw_id).all()
except sa_orm_exc.NoResultFound:
raise l2gw_exc.L2GatewayDeviceNotFound(device_id=l2gw_id)
return gw
def _get_l2_gateway_connection(self, context, cn_id):
try:
con = context.session.query(models.L2GatewayConnection).get(cn_id)
except sa_orm_exc.NoResultFound:
raise l2gw_exc.L2GatewayConnectionNotFound(id=cn_id)
return con
def _make_l2gw_connections_dict(self, gw_conn, fields=None):
if gw_conn is None:
raise l2gw_exc.L2GatewayConnectionNotFound(id="")
res = {'id': gw_conn['id'],
'network_id': gw_conn['network_id'],
'l2_gateway_id': gw_conn['l2_gateway_id']
}
return self._fields(res, fields)
def _make_l2_gateway_dict(self, l2_gateway, interface_db, fields=None):
device_list = []
interface_list = []
for d in l2_gateway['devices']:
if not interface_list:
for interfaces_db in d['interfaces']:
interface_list.append({'name':
interfaces_db['interface_name'],
constants.SEG_ID:
interfaces_db[constants.SEG_ID]})
device_list.append({'device_name': d['device_name'],
'id': d['id'],
'interfaces': interface_list})
res = {'id': l2_gateway['id'],
'name': l2_gateway['name'],
'devices': device_list,
'tenant_id': l2_gateway['tenant_id']}
return self._fields(res, fields)
def _set_mapping_info_defaults(self, mapping_info):
if not mapping_info.get(constants.SEG_ID):
mapping_info[constants.SEG_ID] = 0
def _retrieve_gateway_connections(self, context, gateway_id,
mapping_info={}, only_one=False):
filters = {'l2_gateway_id': [gateway_id]}
for k, v in mapping_info.iteritems():
if v:
filters[k] = [v]
query = self._get_collection_query(context,
models.L2GatewayConnection,
filters)
return query.one() if only_one else query.all()
def create_l2_gateway(self, context, l2_gateway):
"""Create a logical gateway."""
self._admin_check(context, 'CREATE')
gw = l2_gateway[self.gateway_resource]
tenant_id = self._get_tenant_id_for_create(context, gw)
devices = gw['devices']
with context.session.begin(subtransactions=True):
gw_db = models.L2Gateway(
id=gw.get('id', uuidutils.generate_uuid()),
tenant_id=tenant_id,
name=gw.get('name'))
context.session.add(gw_db)
l2gw_device_dict = {}
interface_db_list = []
for device in devices:
l2gw_device_dict['l2_gateway_id'] = id
device_name = device['device_name']
l2gw_device_dict['device_name'] = device_name
l2gw_device_dict['id'] = uuidutils.generate_uuid()
uuid = self._generate_uuid()
d_db = models.L2GatewayDevice(id=uuid,
l2_gateway_id=gw_db.id,
device_name=device_name)
context.session.add(d_db)
for interface_list in device['interfaces']:
name = interface_list.get('name')
seg_list = interface_list.get(constants.SEG_ID, None)
if seg_list:
for segs in seg_list:
uuid = self._generate_uuid()
interface_db = self._get_int_model(uuid,
name,
d_db.id,
segs)
context.session.add(interface_db)
interface_db_list.append(interface_db)
else:
uuid = self._generate_uuid()
default_seg_id = constants.SEG_ID
interface_db = self._get_int_model(uuid,
name,
d_db.id,
default_seg_id)
context.session.add(interface_db)
interface_db_list.append(interface_db)
context.session.query(models.L2GatewayDevice).all()
return self._make_l2_gateway_dict(gw_db, interface_db_list)
def update_l2_gateway(self, context, id, l2_gateway):
"""Update l2 gateway."""
self._admin_check(context, 'UPDATE')
gw = l2_gateway[self.gateway_resource]
devices = gw['devices']
with context.session.begin(subtransactions=True):
l2gw_db = self._get_l2_gateway(context, id)
if l2gw_db.network_connections:
raise l2gw_exc.L2GatewayInUse(gateway_id=id)
l2gw_db.name = gw.get('name')
interface_db_list = []
device_db = self._get_l2_gateway_device(context, id)
interface_dict_list = []
for device in devices:
for interfaces in device['interfaces']:
interface_dict_list.append(interfaces)
for d_val in device_db:
interface_db = self._get_l2_gateway_interface(context,
d_val.id)
self._delete_l2_gateway_interfaces(context, interface_db)
for interfaces in interface_dict_list:
int_name = interfaces.get('name')
seg_id_list = interfaces.get(constants.SEG_ID, None)
uuid = self._generate_uuid()
for seg_ids in seg_id_list:
interface_db = self._get_int_model(uuid,
int_name,
d_val.id,
seg_ids)
context.session.add(interface_db)
interface_db_list.append(interface_db)
return self._make_l2_gateway_dict(l2gw_db, interface_db_list)
def get_l2_gateway(self, context, id, fields=None):
"""get the l2 gateway by id."""
self._admin_check(context, 'GET')
gw_db = self._get_l2_gateway(context, id)
if gw_db:
device_db = self._get_l2_gateway_device(context, gw_db.id)
for devices in device_db:
interface_db = self._get_l2_gateway_interface(context,
devices.id)
return self._make_l2_gateway_dict(gw_db, interface_db, fields)
else:
return []
def delete_l2_gateway(self, context, id):
"""delete the l2 gateway by id."""
self._admin_check(context, 'DELETE')
with context.session.begin(subtransactions=True):
gw_db = self._get_l2_gateway(context, id)
if gw_db is None:
raise l2gw_exc.L2GatewayNotFound(gateway_id=id)
if gw_db.network_connections:
raise l2gw_exc.L2GatewayInUse(gateway_id=id)
context.session.delete(gw_db)
LOG.debug("l2 gateway '%s' was deleted.", id)
def get_l2_gateways(self, context, filters=None, fields=None,
sorts=None,
limit=None,
marker=None,
page_reverse=False):
"""list the l2 gateways available in the neutron DB."""
self._admin_check(context, 'GET')
marker_obj = self._get_marker_obj(
context, 'l2_gateway', limit, marker)
return self._get_collection(context, models.L2Gateway,
self._make_l2_gateway_dict,
filters=filters, fields=fields,
sorts=sorts, limit=limit,
marker_obj=marker_obj,
page_reverse=page_reverse)
def _update_segmentation_id(self, context, l2gw_id, segmentation_id):
"""Update segmentation id for interfaces."""
device_db = self._get_l2_gateway_device(context, l2gw_id)
for device_model in device_db:
interface_db = self._get_l2_gateway_interface(context,
device_model.id)
for interface_model in interface_db:
interface_model.segmentation_id = segmentation_id
def _delete_l2_gateway_interfaces(self, context, int_db_list):
"""delete the l2 interfaces by id."""
with context.session.begin(subtransactions=True):
for interfaces in int_db_list:
context.session.delete(interfaces)
LOG.debug("l2 gateway interfaces was deleted.")
def create_l2_gateway_connection(self, context, l2_gateway_connection):
"""Create l2 gateway connection."""
self._admin_check(context, 'CREATE')
gw_connection = l2_gateway_connection[self.connection_resource]
l2_gw_id = gw_connection.get('l2_gateway_id')
network_id = gw_connection.get('network_id')
segmentation_id = gw_connection.get(constants.SEG_ID)
nw_map = {}
nw_map['network_id'] = network_id
nw_map['l2_gateway_id'] = l2_gw_id
if segmentation_id in gw_connection:
nw_map[constants.SEG_ID] = segmentation_id
check_vlan = self._check_vlan_on_interface(context, l2_gw_id)
network_id = l2gw_validators.validate_network_mapping_list(nw_map,
check_vlan)
if segmentation_id:
self._update_segmentation_id(context, l2_gw_id, segmentation_id)
with context.session.begin(subtransactions=True):
gw_db = self._get_l2_gateway(context, l2_gw_id)
tenant_id = self._get_tenant_id_for_create(context, gw_db)
if self._retrieve_gateway_connections(context,
l2_gw_id,
nw_map):
raise l2gw_exc.L2GatewayConnectionExists(mapping=nw_map,
gateway_id=l2_gw_id)
nw_map['tenant_id'] = tenant_id
connection_id = uuidutils.generate_uuid()
nw_map['id'] = connection_id
nw_map.pop(constants.SEG_ID, None)
gw_db.network_connections.append(
models.L2GatewayConnection(**nw_map))
gw_db = models.L2GatewayConnection(id=connection_id,
tenant_id=tenant_id,
network_id=network_id,
l2_gateway_id=l2_gw_id)
return self._make_l2gw_connections_dict(gw_db)
def get_l2_gateway_connections(self, context, filters=None,
fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
"""List l2 gateway connections."""
self._admin_check(context, 'GET')
marker_obj = self._get_marker_obj(
context, 'l2_gateway_connection', limit, marker)
return self._get_collection(context, models.L2GatewayConnection,
self._make_l2gw_connections_dict,
filters=filters, fields=fields,
sorts=sorts, limit=limit,
marker_obj=marker_obj,
page_reverse=page_reverse)
def get_l2_gateway_connection(self, context, id, fields=None):
"""Get l2 gateway connection."""
self._admin_check(context, 'GET')
"""Get the l2 gateway connection by id."""
gw_db = self._get_l2_gateway_connection(context, id)
return self._make_l2gw_connections_dict(gw_db, fields)
def delete_l2_gateway_connection(self, context, id):
"""Delete the l2 gateway connection by id."""
self._admin_check(context, 'DELETE')
with context.session.begin(subtransactions=True):
gw_db = self._get_l2_gateway_connection(context, id)
context.session.delete(gw_db)
LOG.debug("l2 gateway '%s' was destroyed.", id)
def _admin_check(self, context, action):
"""Admin role check helper."""
# TODO(selva): his check should be required if the tenant_id is
# specified inthe request, otherwise the policy.json do a trick
# this need further revision.
if not context.is_admin:
reason = _('Cannot %(action)s resource for non admin tenant')
raise exceptions.AdminRequired(reason=reason)
def _generate_uuid(self):
"""Generate uuid helper."""
uuid = uuidutils.generate_uuid()
return uuid
def _get_int_model(self, uuid, interface_name, dev_id, seg_id):
return models.L2GatewayInterface(id=uuid,
interface_name=interface_name,
device_id=dev_id,
segmentation_id=seg_id)

@ -0,0 +1,63 @@
# Copyright 2015 OpenStack Foundation
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
#
# 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.
from neutron.db import model_base
from neutron.db import models_v2
import sqlalchemy as sa
from sqlalchemy import orm
class L2GatewayConnection(model_base.BASEV2, models_v2.HasTenant,
models_v2.HasId):
"""Define an l2 gateway connection between a l2 gateway and a network."""
l2_gateway_id = sa.Column(sa.String(36),
sa.ForeignKey('l2gateways.id',
ondelete='CASCADE'))
network_id = sa.Column(sa.String(36),
sa.ForeignKey('networks.id', ondelete='CASCADE'))
__table_args__ = (sa.UniqueConstraint(l2_gateway_id,
network_id),)
class L2GatewayInterface(model_base.BASEV2, models_v2.HasId):
"""Define an l2 gateway interface."""
interface_name = sa.Column(sa.String(255))
device_id = sa.Column(sa.String(36),
sa.ForeignKey('l2gatewaydevices.id',
ondelete='CASCADE'))
segmentation_id = sa.Column(sa.Integer)
class L2GatewayDevice(model_base.BASEV2, models_v2.HasId):
"""Define an l2 gateway device."""
device_name = sa.Column(sa.String(255))
interfaces = orm.relationship(L2GatewayInterface,
backref='l2gatewaydevices',
cascade='all,delete')
l2_gateway_id = sa.Column(sa.String(36),
sa.ForeignKey('l2gateways.id',
ondelete='CASCADE'))
class L2Gateway(model_base.BASEV2, models_v2.HasId,
models_v2.HasTenant):
"""Define an l2 gateway."""
name = sa.Column(sa.String(255))
devices = orm.relationship(L2GatewayDevice,
backref='l2gateways',
cascade='all,delete')
network_connections = orm.relationship(L2GatewayConnection,
lazy='joined')

@ -0,0 +1,88 @@
# Copyright 2015 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.
#
"""l2gateway_models
Revision ID: 42438454c556
Revises: 54c9c8fe22bf
Create Date: 2014-11-27 01:57:56.997665
"""
# revision identifiers, used by Alembic.
revision = '42438454c556'
down_revision = '54c9c8fe22bf'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.create_table('l2gateways',
sa.Column('id', sa.String(length=36), nullable=False),
sa.Column('name', sa.String(length=255), nullable=True),
sa.Column('tenant_id', sa.String(length=255),
nullable=True),
sa.PrimaryKeyConstraint('id'))
op.create_table('l2gatewaydevices',
sa.Column('id', sa.String(length=36), nullable=False),
sa.Column('device_name', sa.String(length=255),
nullable=False),
sa.Column('l2_gateway_id', sa.String(length=36),
nullable=False),
sa.ForeignKeyConstraint(['l2_gateway_id'],
['l2gateways.id'],
ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id'))
op.create_table('l2gatewayinterfaces',
sa.Column('id', sa.String(length=36), nullable=False),
sa.Column('interface_name', sa.String(length=255),
nullable=True),
sa.Column('segmentation_id', sa.Integer(),
nullable=True),
sa.Column('device_id', sa.String(length=36),
nullable=False),
sa.ForeignKeyConstraint(['device_id'],
['l2gatewaydevices.id'],
ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id'))
op.create_table('l2gatewayconnections',
sa.Column('id', sa.String(length=36), nullable=False),
sa.Column('tenant_id', sa.String(length=255),
nullable=True),
sa.Column('l2_gateway_id', sa.String(length=36),
nullable=True),
sa.Column('network_id', sa.String(length=36),
nullable=True),
sa.Column('segmentation_id', sa.Integer(),
nullable=True),
sa.ForeignKeyConstraint(['l2_gateway_id'],
['l2gateways.id'],
ondelete='CASCADE'),
sa.ForeignKeyConstraint(['network_id'], ['networks.id'],
ondelete='CASCADE'),
sa.UniqueConstraint('l2_gateway_id',
'network_id'),
sa.PrimaryKeyConstraint('id'))
def downgrade():
op.drop_table('l2gatewayconnections')
op.drop_table('l2gatewayinterfaces')
op.drop_table('l2gatewaydevices')
op.drop_table('l2gateways')

@ -0,0 +1,115 @@
# Copyright 2015 OpenStack Foundation
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
#
# 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.
import abc
from neutron.api import extensions
from neutron.api.v2 import attributes
from neutron.api.v2 import resource_helper
from networking_l2gw.services.l2gateway.common import constants
from networking_l2gw.services.l2gateway.common import l2gw_validators
RESOURCE_ATTRIBUTE_MAP = {
constants.L2_GATEWAYS: {
'id': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'name': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'devices': {'allow_post': True, 'allow_put': True,
'validate': {'type:l2gwdevice_list': None},
'is_visible': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True,
'is_visible': True}
},
}
validator_func = l2gw_validators.validate_gwdevice_list
attributes.validators['type:l2gwdevice_list'] = validator_func
class L2gateway(extensions.ExtensionDescriptor):
"""API extension for Layer-2 Gateway support."""
@classmethod
def get_name(cls):
return "L2 Gateway"
@classmethod
def get_alias(cls):
return "l2-gateway"
@classmethod
def get_description(cls):
return "Connects Neutron networks with external networks at layer 2."
@classmethod
def get_namespace(cls):
return "https://review.openstack.org/#/c/144173/3/specs/kilo/"
"l2-gateway-api.rst"
@classmethod
def get_updated(cls):
return "2015-01-01T00:00:00-00:00"
@classmethod
def get_resources(cls):
"""Returns Ext Resources."""
mem_actions = {}
plural_mappings = resource_helper.build_plural_mappings(
{}, RESOURCE_ATTRIBUTE_MAP)
attributes.PLURALS.update(plural_mappings)
resources = resource_helper.build_resource_info(plural_mappings,
RESOURCE_ATTRIBUTE_MAP,
constants.L2GW,
action_map=mem_actions,
register_quota=True,
translate_name=True)
return resources
def get_extended_resources(self, version):
if version == "2.0":
return RESOURCE_ATTRIBUTE_MAP
else:
return {}
class L2GatewayPluginBase(object):
@abc.abstractmethod
def create_l2_gateway(self, context, l2_gateway):
pass
@abc.abstractmethod
def get_l2_gateway(self, context, id, fields=None):
pass
@abc.abstractmethod
def delete_l2_gateway(self, context, id):
pass
@abc.abstractmethod
def get_l2_gateways(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
pass
@abc.abstractmethod
def update_l2_gateway(self, context, id, l2_gateway):
pass

@ -0,0 +1,115 @@
# Copyright 2015 OpenStack Foundation
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
#
# 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.
import abc
from neutron.api import extensions
from neutron.api.v2 import attributes
from neutron.api.v2 import resource_helper
from networking_l2gw.services.l2gateway.common import constants
RESOURCE_ATTRIBUTE_MAP = {
constants.L2_GATEWAYS_CONNECTION: {
'id': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'l2_gateway_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'network_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'is_visible': True},
'segmentation_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True,
'is_visible': True}
},
}
class L2gatewayconnection(extensions.ExtensionDescriptor):
"""API extension for Layer-2 Gateway connection support."""
@classmethod
def get_name(cls):
return "L2 Gateway connection"
@classmethod
def get_alias(cls):
return "l2-gateway-connection"
@classmethod
def get_description(cls):
return "Connects Neutron networks with external networks at layer 2."
@classmethod
def get_namespace(cls):
return "https://review.openstack.org/#/c/144173/3/specs/kilo/"
"l2-gateway-api.rst"
@classmethod
def get_updated(cls):
return "2014-01-01T00:00:00-00:00"
@classmethod
def get_resources(cls):
"""Returns Ext Resources."""
mem_actions = {}
plural_mappings = resource_helper.build_plural_mappings(
{}, RESOURCE_ATTRIBUTE_MAP)
attributes.PLURALS.update(plural_mappings)
resources = resource_helper.build_resource_info(plural_mappings,
RESOURCE_ATTRIBUTE_MAP,
constants.L2GW,
action_map=mem_actions,
register_quota=True,
translate_name=True)
return resources
def get_extended_resources(self, version):
if version == "2.0":
return RESOURCE_ATTRIBUTE_MAP
else:
return {}
class L2GatewayConnectionPluginBase(object):
@abc.abstractmethod
def delete_l2_gateway_connection(self, context, l2_gateway_id,
network_mapping_list):
pass
@abc.abstractmethod
def create_l2_gateway_connection(self, context, l2_gateway_id,
network_mapping_list):
pass
@abc.abstractmethod
def get_l2_gateway_connections(self, context, filters=None,
fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
pass
@abc.abstractmethod
def get_l2_gateway_connection(self, context, id, fields=None):
pass

@ -39,3 +39,14 @@ TRANSACT = 'transact'
OVSDB_SCHEMA_NAME = 'hardware_vtep'
OVSDB_IDENTIFIER = 'ovsdb_identifier'
L2GW_AGENT_TYPE = 'l2gw_agent_type'
IFACE_NAME_ATTR = 'interface_name'
NETWORK_ID = 'network_id'
SEG_ID = 'segmentation_id'
L2GATEWAY_ID = 'l2_gateway_id'
GATEWAY_RESOURCE_NAME = 'l2_gateway'
L2_GATEWAYS = 'l2-gateways'
DEVICE_ID_ATTR = 'device_name'
IFACE_NAME_ATTR = 'interfaces'
CONNECTION_RESOURCE_NAME = 'l2_gateway_connection'
EXT_ALIAS = 'l2-gateway-connection'
L2_GATEWAYS_CONNECTION = "%ss" % EXT_ALIAS

@ -0,0 +1,87 @@
# Copyright 2015 OpenStack Foundation
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
#
# 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.
from neutron.api.v2 import attributes
from neutron.common import exceptions
from networking_l2gw.services.l2gateway.common import constants
ALLOWED_CONNECTION_ATTRIBUTES = set((constants.NETWORK_ID,
constants.SEG_ID,
constants.L2GATEWAY_ID
))
def validate_gwdevice_list(data, valid_values=None):
"""Validate the list of devices."""
if not data:
# Devices must be provided
msg = _("Cannot create a gateway with an empty device list")
return msg
try:
for device in data:
interface_data = device.get(constants.IFACE_NAME_ATTR)
device_name = device.get(constants.DEVICE_ID_ATTR)
if not interface_data:
msg = _("Cannot create a gateway with an empty interfaces")
return msg
if not device_name:
msg = _("Cannot create a gateway with an empty device_name")
return msg
for int_dict in interface_data:
err_msg = attributes._validate_dict(int_dict, None)
if not int_dict.get('name'):
msg = _("Cannot create a gateway with an empty"
"interface name")
return msg
segmentation_id_list = int_dict.get(constants.SEG_ID)
if type(segmentation_id_list) is not list:
msg = _("segmentation_id type should be of list type ")
return msg
if not segmentation_id_list:
msg = _("segmentation_id_list should not be empty")
return msg
if err_msg:
return err_msg
except TypeError:
return (_("%s: provided data are not iterable") %
validate_gwdevice_list.__name__)
def validate_network_mapping_list(network_mapping, check_vlan):
"""Validate network mapping list in connection."""
if not network_mapping.get('segmentation_id'):
if check_vlan is False:
raise exceptions.InvalidInput(
error_message=_("Segmentation id must be specified in create"
"l2gateway connections"))
network_id = network_mapping.get(constants.NETWORK_ID)
if not network_id:
raise exceptions.InvalidInput(
error_message=_("A valid network identifier must be specified "
"when connecting a network to a network "
"gateway. Unable to complete operation"))
connection_attrs = set(network_mapping.keys())
if not connection_attrs.issubset(ALLOWED_CONNECTION_ATTRIBUTES):
raise exceptions.InvalidInput(
error_message=(_("Invalid keys found among the ones provided "
"in request : %(connection_attrs)s."),
connection_attrs))
seg_id = network_mapping.get(constants.SEG_ID)
if seg_id:
if int(seg_id) < 0 or int(seg_id) > 4095:
msg = _("Segmentation id is invalid")
raise exceptions.InvalidInput(error_message=msg)
return network_id

@ -42,9 +42,9 @@ class L2GatewayPortInUse(exceptions.InUse):
"therefore cannot be deleted directly via the port API.")
class L2GatewayConnectionInUse(exceptions.InUse):
message = _("The specified mapping '%(mapping)s' is already in use on "
"l2 gateway '%(gateway_id)s'.")
class L2GatewayConnectionExists(exceptions.InUse):
message = _("The specified mapping '%(mapping)s' exists on "
"network gateway '%(gateway_id)s'.")
class L2MultipleGatewayConnections(exceptions.NeutronException):
@ -52,13 +52,16 @@ class L2MultipleGatewayConnections(exceptions.NeutronException):
"with provided criteria.")
class L2GatewayInterfaceNotFound(exceptions.NeutronException):
message = _("L2 Gateway interface not found on '%(interface_id)s'")
class L2GatewayConnectionNotFound(exceptions.NotFound):
message = _("The connection %(network_mapping_info)s was not found on the "
"l2 gateway '%(network_gateway_id)s'")
message = _("The connection %(id)s was not found on the l2 gateway")
base.FAULT_MAP.update({L2GatewayInUse: web_exc.HTTPConflict,
L2GatewayPortInUse: web_exc.HTTPConflict,
L2GatewayConnectionInUse: web_exc.HTTPConflict,
L2GatewayConnectionExists: web_exc.HTTPConflict,
L2GatewayConnectionNotFound: web_exc.HTTPNotFound,
L2MultipleGatewayConnections: web_exc.HTTPConflict})

@ -0,0 +1,178 @@
# Copyright 2015 OpenStack Foundation
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
#
# 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.
from neutron import context
from neutron.openstack.common import log as logging
from neutron.tests.unit import testlib_api
from networking_l2gw.db.l2gateway import l2gateway_db
from networking_l2gw.services.l2gateway.common import constants
from networking_l2gw.services.l2gateway import exceptions
from oslo.utils import importutils
DB_PLUGIN_KLASS = 'neutron.db.db_base_plugin_v2.NeutronDbPluginV2'
LOG = logging.getLogger(__name__)
class L2GWTestCase(testlib_api.SqlTestCase):
"""Unit test for l2 Gateway DB support."""
def setUp(self):
super(L2GWTestCase, self).setUp()
self.ctx = context.get_admin_context()
self.mixin = l2gateway_db.L2GatewayMixin()
self.gw_resource = constants.L2_GATEWAYS
self.con_resource = constants.CONNECTION_RESOURCE_NAME
self.plugin = importutils.import_object(DB_PLUGIN_KLASS)
def _create_l2gateway(self, l2gateway):
"""Create l2gateway helper method."""
with self.ctx.session.begin(subtransactions=True):
return self.mixin.create_l2_gateway(self.ctx, l2gateway)
def _get_l2_gateway_data(self, name, device_name):
"""Get l2 gateway data helper method."""
data = {"l2_gateway": {"name": name,
"devices":
[{"interfaces": [{"name": "port1",
"segmentation_id": ["111"]}],
"device_name": device_name}]}}
return data
def _get_nw_data(self):
return {'network': {'id': 'fake-id',
'name': 'net1',
'admin_state_up': True,
'tenant_id': 'test-tenant',
'shared': False}}
def _get_l2_gateway_data_without_seg_id(self, name, device_name):
"""Get l2 gateway data helper method."""
data = {"l2_gateway": {"name": name,
"devices":
[{"interfaces": [{"name": "port1"}],
"device_name": device_name}]}}
return data
def test_l2_gateway_create(self):
"""Test l2 gateway create."""
name = "l2gw_1"
device_name = "device1"
data = self._get_l2_gateway_data(name, device_name)
result = self._create_l2gateway(data)
self.assertEqual(result['name'], name)
def _get_l2_gateways(self):
"""Update l2gateway helper."""
with self.ctx.session.begin(subtransactions=True):
return self.mixin.get_l2_gateways(self.ctx)
def test_l2gateway_list(self):
"""Test l2 gateway list."""
name = "l2gw_1"
device_name = "device1"
data = self._get_l2_gateway_data(name, device_name)
self._create_l2gateway(data)
result2 = self._get_l2_gateways()
self.assertIn('id', result2[0])
def _update_l2_gateway(self, id, l2gateway):
"""Update l2gateway helper."""
with self.ctx.session.begin(subtransactions=True):
return self.mixin.update_l2_gateway(self.ctx, id, l2gateway)
def test_l2_gateway_update(self):
"""Test l2 gateway update."""
name_create = "l2gw_1"
name_update = "l2gw_2"
device_name = "device1"
data_l2gw_create = self._get_l2_gateway_data(name_create,
device_name)
gw_org = self._create_l2gateway(data_l2gw_create)
l2gw_id = gw_org['id']
l2_gw_update_dict = self._get_l2_gateway_data(name_update,
device_name)
result = self._update_l2_gateway(l2gw_id, l2_gw_update_dict)
self.assertNotEqual(result['name'], name_create)
def _create_l2gateway_connection(self, l2gateway_con):
"""Create L2 gateway connection resource helper method."""
with self.ctx.session.begin(subtransactions=True):
return self.mixin.create_l2_gateway_connection(self.ctx,
l2gateway_con)
def _list_l2gateway_connection(self):
"""Create L2 gateway connection resource helper method."""
with self.ctx.session.begin(subtransactions=True):
return self.mixin.get_l2_gateway_connections(self.ctx)
def test_l2gateway_connection_create_delete_list(self):
"""Test l2 gateway connection create and delete."""
name = "l2gw_con1"
device_name = "device_name1"
data_l2gw = self._get_l2_gateway_data(name, device_name)
gw = self._create_l2gateway(data_l2gw)
net_data = self._get_nw_data()
net = self.plugin.create_network(self.ctx, net_data)
l2gw_id = gw['id']
data_con = {self.con_resource: {'l2_gateway_id': l2gw_id,
'network_id': net['id'],
'segmentation_id': "199"}}
gw_con = self._create_l2gateway_connection(data_con)
exp_net_id = gw_con['network_id']
self.assertEqual(net['id'], exp_net_id)
cn_id = gw_con['id']
list_con = self._list_l2gateway_connection()
self.assertIn('id', list_con[0])
result = self._delete_l2gw_connection(cn_id)
self.assertIsNone(result)
def test_l2gateway_con_create_and_delete_in_use_without_seg_id(self):
"""Test l2 gateway connection create without seg id when use."""
name = "l2gw_con2"
device_name = "device_name2"
data_l2gw = self._get_l2_gateway_data(name,
device_name)
gw = self._create_l2gateway(data_l2gw)
net_data = self._get_nw_data()
net = self.plugin.create_network(self.ctx, net_data)
l2gw_id = gw['id']
data_con = {self.con_resource: {'l2_gateway_id': l2gw_id,
'network_id': net['id']}}
self._create_l2gateway_connection(data_con)
self.assertRaises(exceptions.L2GatewayInUse,
self._delete_l2gateway, l2gw_id)
def _delete_l2gateway(self, l2gw_id):
"""Delete l2 gateway helper method."""
with self.ctx.session.begin(subtransactions=True):
return self.mixin.delete_l2_gateway(self.ctx,
l2gw_id)
def test_l2gateway_delete(self):
"""Test l2 gateway delete."""
data_l2gw = self._get_l2_gateway_data("gateway_delete",
"device_name")
gw_actual = self._create_l2gateway(data_l2gw)
l2gw_id = gw_actual['id']
result = self._delete_l2gateway(l2gw_id)
self.assertIsNone(result)
def _delete_l2gw_connection(self, con_id):
"""Delete l2 gateway connection."""
with self.ctx.session.begin(subtransactions=True):
return self.mixin.delete_l2_gateway_connection(self.ctx, con_id)
Loading…
Cancel
Save