VPN as a Service (VPNaaS) API and DataModel
implements:blueprint VPNaaS-Python-API It provides the basic API and DataModel for the "VPN As A Service" feature that includes: * VPNService * IPsecSiteConnection * IKEPolicy * IPsecPolicy Change-Id: I059d4db05118a4eecd388b8e8db0d714a8f9cb8f
This commit is contained in:
parent
331b1d4ee2
commit
7856f68ec3
@ -261,6 +261,23 @@ def _validate_subnet(data, valid_values=None):
|
||||
return msg
|
||||
|
||||
|
||||
def _validate_subnet_list(data, valid_values=None):
|
||||
if not isinstance(data, list):
|
||||
msg = _("'%s' is not a list") % data
|
||||
LOG.debug(msg)
|
||||
return msg
|
||||
|
||||
if len(set(data)) != len(data):
|
||||
msg = _("Duplicate items in the list: '%s'") % ', '.join(data)
|
||||
LOG.debug(msg)
|
||||
return msg
|
||||
|
||||
for item in data:
|
||||
msg = _validate_subnet(item)
|
||||
if msg:
|
||||
return msg
|
||||
|
||||
|
||||
def _validate_regex(data, valid_values=None):
|
||||
try:
|
||||
if re.match(valid_values, data):
|
||||
@ -474,6 +491,7 @@ validators = {'type:dict': _validate_dict,
|
||||
'type:regex': _validate_regex,
|
||||
'type:string': _validate_string,
|
||||
'type:subnet': _validate_subnet,
|
||||
'type:subnet_list': _validate_subnet_list,
|
||||
'type:uuid': _validate_uuid,
|
||||
'type:uuid_or_none': _validate_uuid_or_none,
|
||||
'type:uuid_list': _validate_uuid_list,
|
||||
|
@ -0,0 +1,183 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2013 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.
|
||||
#
|
||||
|
||||
"""Support for VPNaaS
|
||||
|
||||
Revision ID: 52ff27f7567a
|
||||
Revises: 39cf3f799352
|
||||
Create Date: 2013-07-14 23:04:13.395955
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '52ff27f7567a'
|
||||
down_revision = '39cf3f799352'
|
||||
|
||||
# Change to ['*'] if this migration applies to all plugins
|
||||
|
||||
migration_for_plugins = [
|
||||
'*'
|
||||
]
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
from neutron.db import migration
|
||||
|
||||
|
||||
def upgrade(active_plugin=None, options=None):
|
||||
if not migration.should_run(active_plugin, migration_for_plugins):
|
||||
return
|
||||
|
||||
op.create_table(
|
||||
'ikepolicies',
|
||||
sa.Column('tenant_id', sa.String(length=255), nullable=True),
|
||||
sa.Column('id', sa.String(length=36), nullable=False),
|
||||
sa.Column('name', sa.String(length=255), nullable=True),
|
||||
sa.Column('description', sa.String(length=255), nullable=True),
|
||||
sa.Column(
|
||||
'auth_algorithm',
|
||||
sa.Enum('sha1', name='vpn_auth_algorithms'), nullable=False),
|
||||
sa.Column(
|
||||
'encryption_algorithm',
|
||||
sa.Enum('3des', 'aes-128', 'aes-256', 'aes-192',
|
||||
name='vpn_encrypt_algorithms'), nullable=False),
|
||||
sa.Column(
|
||||
'phase1_negotiation_mode',
|
||||
sa.Enum('main', name='ike_phase1_mode'), nullable=False),
|
||||
sa.Column(
|
||||
'lifetime_units',
|
||||
sa.Enum('seconds', 'kilobytes', name='vpn_lifetime_units'),
|
||||
nullable=False),
|
||||
sa.Column('lifetime_value', sa.Integer(), nullable=False),
|
||||
sa.Column(
|
||||
'ike_version',
|
||||
sa.Enum('v1', 'v2', name='ike_versions'), nullable=False),
|
||||
sa.Column(
|
||||
'pfs',
|
||||
sa.Enum('group2', 'group5', 'group14', name='vpn_pfs'),
|
||||
nullable=False),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table(
|
||||
'ipsecpolicies',
|
||||
sa.Column('tenant_id', sa.String(length=255), nullable=True),
|
||||
sa.Column('id', sa.String(length=36), nullable=False),
|
||||
sa.Column('name', sa.String(length=255), nullable=True),
|
||||
sa.Column('description', sa.String(length=255), nullable=True),
|
||||
sa.Column(
|
||||
'transform_protocol',
|
||||
sa.Enum('esp', 'ah', 'ah-esp', name='ipsec_transform_protocols'),
|
||||
nullable=False),
|
||||
sa.Column(
|
||||
'auth_algorithm',
|
||||
sa.Enum('sha1', name='vpn_auth_algorithms'), nullable=False),
|
||||
sa.Column(
|
||||
'encryption_algorithm',
|
||||
sa.Enum(
|
||||
'3des', 'aes-128',
|
||||
'aes-256', 'aes-192', name='vpn_encrypt_algorithms'),
|
||||
nullable=False),
|
||||
sa.Column(
|
||||
'encapsulation_mode',
|
||||
sa.Enum('tunnel', 'transport', name='ipsec_encapsulations'),
|
||||
nullable=False),
|
||||
sa.Column(
|
||||
'lifetime_units',
|
||||
sa.Enum(
|
||||
'seconds', 'kilobytes',
|
||||
name='vpn_lifetime_units'), nullable=False),
|
||||
sa.Column(
|
||||
'lifetime_value', sa.Integer(), nullable=False),
|
||||
sa.Column(
|
||||
'pfs',
|
||||
sa.Enum(
|
||||
'group2', 'group5', 'group14', name='vpn_pfs'),
|
||||
nullable=False),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table(
|
||||
'vpnservices',
|
||||
sa.Column('tenant_id', sa.String(length=255), nullable=True),
|
||||
sa.Column('id', sa.String(length=36), nullable=False),
|
||||
sa.Column('name', sa.String(length=255), nullable=True),
|
||||
sa.Column('description', sa.String(length=255), nullable=True),
|
||||
sa.Column('status', sa.String(length=16), nullable=False),
|
||||
sa.Column('admin_state_up', sa.Boolean(), nullable=False),
|
||||
sa.Column('subnet_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('router_id', sa.String(length=36), nullable=False),
|
||||
sa.ForeignKeyConstraint(['router_id'], ['routers.id'], ),
|
||||
sa.ForeignKeyConstraint(['subnet_id'], ['subnets.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table(
|
||||
'ipsec_site_connections',
|
||||
sa.Column('tenant_id', sa.String(length=255), nullable=True),
|
||||
sa.Column('id', sa.String(length=36), nullable=False),
|
||||
sa.Column('name', sa.String(length=255), nullable=True),
|
||||
sa.Column('description', sa.String(length=255), nullable=True),
|
||||
sa.Column('peer_address', sa.String(length=64), nullable=False),
|
||||
sa.Column('peer_id', sa.String(length=255), nullable=False),
|
||||
sa.Column('route_mode', sa.String(length=8), nullable=False),
|
||||
sa.Column('mtu', sa.Integer(), nullable=False),
|
||||
sa.Column(
|
||||
'initiator',
|
||||
sa.Enum(
|
||||
'bi-directional', 'response-only', name='vpn_initiators'),
|
||||
nullable=False),
|
||||
sa.Column('auth_mode', sa.String(length=16), nullable=False),
|
||||
sa.Column('psk', sa.String(length=255), nullable=False),
|
||||
sa.Column(
|
||||
'dpd_action',
|
||||
sa.Enum(
|
||||
'hold', 'clear', 'restart',
|
||||
'disabled', 'restart-by-peer', name='vpn_dpd_actions'),
|
||||
nullable=False),
|
||||
sa.Column('dpd_interval', sa.Integer(), nullable=False),
|
||||
sa.Column('dpd_timeout', sa.Integer(), nullable=False),
|
||||
sa.Column('status', sa.String(length=16), nullable=False),
|
||||
sa.Column('admin_state_up', sa.Boolean(), nullable=False),
|
||||
sa.Column('vpnservice_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('ipsecpolicy_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('ikepolicy_id', sa.String(length=36), nullable=False),
|
||||
sa.ForeignKeyConstraint(['ikepolicy_id'], ['ikepolicies.id']),
|
||||
sa.ForeignKeyConstraint(['ipsecpolicy_id'], ['ipsecpolicies.id']),
|
||||
sa.ForeignKeyConstraint(['vpnservice_id'], ['vpnservices.id']),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table(
|
||||
'ipsecpeercidrs',
|
||||
sa.Column('cidr', sa.String(length=32), nullable=False),
|
||||
sa.Column('ipsec_site_connection_id',
|
||||
sa.String(length=36),
|
||||
nullable=False),
|
||||
sa.ForeignKeyConstraint(['ipsec_site_connection_id'],
|
||||
['ipsecsiteonnections.id'],
|
||||
ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('cidr', 'ipsec_site_connection_id')
|
||||
)
|
||||
|
||||
|
||||
def downgrade(active_plugin=None, options=None):
|
||||
if not migration.should_run(active_plugin, migration_for_plugins):
|
||||
return
|
||||
|
||||
op.drop_table('ipsecpeercidrs')
|
||||
op.drop_table('ipsec_site_connections')
|
||||
op.drop_table('vpnservices')
|
||||
op.drop_table('ipsecpolicies')
|
||||
op.drop_table('ikepolicies')
|
18
neutron/db/vpn/__init__.py
Normal file
18
neutron/db/vpn/__init__.py
Normal file
@ -0,0 +1,18 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||
# 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: Swaminathan Vasudevan, Hewlett-Packard.
|
591
neutron/db/vpn/vpn_db.py
Normal file
591
neutron/db/vpn/vpn_db.py
Normal file
@ -0,0 +1,591 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||
# 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: Swaminathan Vasudevan, Hewlett-Packard.
|
||||
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import orm
|
||||
from sqlalchemy.orm import exc
|
||||
|
||||
from neutron.common import constants as q_constants
|
||||
from neutron.db import agentschedulers_db as agent_db
|
||||
from neutron.db import api as qdbapi
|
||||
from neutron.db import db_base_plugin_v2 as base_db
|
||||
from neutron.db import l3_db
|
||||
from neutron.db import model_base
|
||||
from neutron.db import models_v2
|
||||
from neutron.extensions import vpnaas
|
||||
from neutron.extensions.vpnaas import VPNPluginBase
|
||||
from neutron import manager
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.openstack.common import uuidutils
|
||||
from neutron.plugins.common import constants
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IPsecPeerCidr(model_base.BASEV2):
|
||||
"""Internal representation of a IPsec Peer Cidrs."""
|
||||
|
||||
cidr = sa.Column(sa.String(32), nullable=False, primary_key=True)
|
||||
ipsec_site_connection_id = sa.Column(
|
||||
sa.String(36),
|
||||
sa.ForeignKey('ipsec_site_connections.id',
|
||||
ondelete="CASCADE"),
|
||||
primary_key=True)
|
||||
|
||||
|
||||
class IPsecPolicy(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
|
||||
"""Represents a v2 IPsecPolicy Object."""
|
||||
__tablename__ = 'ipsecpolicies'
|
||||
name = sa.Column(sa.String(255))
|
||||
description = sa.Column(sa.String(255))
|
||||
transform_protocol = sa.Column(sa.Enum("esp", "ah", "ah-esp",
|
||||
name="ipsec_transform_protocols"),
|
||||
nullable=False)
|
||||
auth_algorithm = sa.Column(sa.Enum("sha1",
|
||||
name="vpn_auth_algorithms"),
|
||||
nullable=False)
|
||||
encryption_algorithm = sa.Column(sa.Enum("3des", "aes-128",
|
||||
"aes-256", "aes-192",
|
||||
name="vpn_encrypt_algorithms"),
|
||||
nullable=False)
|
||||
encapsulation_mode = sa.Column(sa.Enum("tunnel", "transport",
|
||||
name="ipsec_encapsulations"),
|
||||
nullable=False)
|
||||
lifetime_units = sa.Column(sa.Enum("seconds", "kilobytes",
|
||||
name="vpn_lifetime_units"),
|
||||
nullable=False)
|
||||
lifetime_value = sa.Column(sa.Integer, nullable=False)
|
||||
pfs = sa.Column(sa.Enum("group2", "group5", "group14",
|
||||
name="vpn_pfs"), nullable=False)
|
||||
|
||||
|
||||
class IKEPolicy(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
|
||||
"""Represents a v2 IKEPolicy Object."""
|
||||
__tablename__ = 'ikepolicies'
|
||||
name = sa.Column(sa.String(255))
|
||||
description = sa.Column(sa.String(255))
|
||||
auth_algorithm = sa.Column(sa.Enum("sha1",
|
||||
name="vpn_auth_algorithms"),
|
||||
nullable=False)
|
||||
encryption_algorithm = sa.Column(sa.Enum("3des", "aes-128",
|
||||
"aes-256", "aes-192",
|
||||
name="vpn_encrypt_algorithms"),
|
||||
nullable=False)
|
||||
phase1_negotiation_mode = sa.Column(sa.Enum("main",
|
||||
name="ike_phase1_mode"),
|
||||
nullable=False)
|
||||
lifetime_units = sa.Column(sa.Enum("seconds", "kilobytes",
|
||||
name="vpn_lifetime_units"),
|
||||
nullable=False)
|
||||
lifetime_value = sa.Column(sa.Integer, nullable=False)
|
||||
ike_version = sa.Column(sa.Enum("v1", "v2", name="ike_versions"),
|
||||
nullable=False)
|
||||
pfs = sa.Column(sa.Enum("group2", "group5", "group14",
|
||||
name="vpn_pfs"), nullable=False)
|
||||
|
||||
|
||||
class IPsecSiteConnection(model_base.BASEV2,
|
||||
models_v2.HasId, models_v2.HasTenant):
|
||||
"""Represents a IPsecSiteConnection Object."""
|
||||
__tablename__ = 'ipsec_site_connections'
|
||||
name = sa.Column(sa.String(255))
|
||||
description = sa.Column(sa.String(255))
|
||||
peer_address = sa.Column(sa.String(64), nullable=False)
|
||||
peer_id = sa.Column(sa.String(255), nullable=False)
|
||||
route_mode = sa.Column(sa.String(8), nullable=False)
|
||||
mtu = sa.Column(sa.Integer, nullable=False)
|
||||
initiator = sa.Column(sa.Enum("bi-directional", "response-only",
|
||||
name="vpn_initiators"), nullable=False)
|
||||
auth_mode = sa.Column(sa.String(16), nullable=False)
|
||||
psk = sa.Column(sa.String(255), nullable=False)
|
||||
dpd_action = sa.Column(sa.Enum("hold", "clear",
|
||||
"restart", "disabled",
|
||||
"restart-by-peer", name="vpn_dpd_actions"),
|
||||
nullable=False)
|
||||
dpd_interval = sa.Column(sa.Integer, nullable=False)
|
||||
dpd_timeout = sa.Column(sa.Integer, nullable=False)
|
||||
status = sa.Column(sa.String(16), nullable=False)
|
||||
admin_state_up = sa.Column(sa.Boolean(), nullable=False)
|
||||
vpnservice_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('vpnservices.id'),
|
||||
nullable=False)
|
||||
ipsecpolicy_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('ipsecpolicies.id'),
|
||||
nullable=False)
|
||||
ikepolicy_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('ikepolicies.id'),
|
||||
nullable=False)
|
||||
ipsecpolicy = orm.relationship(
|
||||
IPsecPolicy, backref='ipsec_site_connection')
|
||||
ikepolicy = orm.relationship(IKEPolicy, backref='ipsec_site_connection')
|
||||
peer_cidrs = orm.relationship(IPsecPeerCidr,
|
||||
backref='ipsec_site_connection',
|
||||
lazy='joined',
|
||||
cascade='all, delete, delete-orphan')
|
||||
|
||||
|
||||
class VPNService(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
|
||||
"""Represents a v2 VPNService Object."""
|
||||
name = sa.Column(sa.String(255))
|
||||
description = sa.Column(sa.String(255))
|
||||
status = sa.Column(sa.String(16), nullable=False)
|
||||
admin_state_up = sa.Column(sa.Boolean(), nullable=False)
|
||||
subnet_id = sa.Column(sa.String(36), sa.ForeignKey('subnets.id'),
|
||||
nullable=False)
|
||||
router_id = sa.Column(sa.String(36), sa.ForeignKey('routers.id'),
|
||||
nullable=False)
|
||||
subnet = orm.relationship(models_v2.Subnet)
|
||||
router = orm.relationship(l3_db.Router)
|
||||
ipsec_site_connections = orm.relationship(
|
||||
IPsecSiteConnection,
|
||||
backref='vpnservice',
|
||||
cascade="all, delete-orphan")
|
||||
|
||||
|
||||
class VPNPluginDb(VPNPluginBase, base_db.CommonDbMixin):
|
||||
"""VPN plugin database class using SQLAlchemy models."""
|
||||
|
||||
def __init__(self):
|
||||
"""Do the initialization for the vpn service plugin here."""
|
||||
qdbapi.register_models()
|
||||
|
||||
def update_status(self, context, model, v_id, status):
|
||||
with context.session.begin(subtransactions=True):
|
||||
v_db = self._get_resource(context, model, v_id)
|
||||
v_db.update({'status': status})
|
||||
|
||||
def _get_resource(self, context, model, v_id):
|
||||
try:
|
||||
r = self._get_by_id(context, model, v_id)
|
||||
except exc.NoResultFound:
|
||||
if issubclass(model, IPsecSiteConnection):
|
||||
raise vpnaas.IPsecSiteConnectionNotFound(
|
||||
ipsec_site_conn_id=v_id
|
||||
)
|
||||
elif issubclass(model, IKEPolicy):
|
||||
raise vpnaas.IKEPolicyNotFound(ikepolicy_id=v_id)
|
||||
elif issubclass(model, IPsecPolicy):
|
||||
raise vpnaas.IPsecPolicyNotFound(ipsecpolicy_id=v_id)
|
||||
elif issubclass(model, VPNService):
|
||||
raise vpnaas.VPNServiceNotFound(vpnservice_id=v_id)
|
||||
else:
|
||||
raise
|
||||
return r
|
||||
|
||||
def assert_update_allowed(self, obj):
|
||||
status = getattr(obj, 'status', None)
|
||||
if status != constants.ACTIVE:
|
||||
raise vpnaas.VPNStateInvalid(id=id, state=status)
|
||||
|
||||
def _make_ipsec_site_connection_dict(self, ipsec_site_conn, fields=None):
|
||||
|
||||
res = {'id': ipsec_site_conn['id'],
|
||||
'tenant_id': ipsec_site_conn['tenant_id'],
|
||||
'name': ipsec_site_conn['name'],
|
||||
'description': ipsec_site_conn['description'],
|
||||
'peer_address': ipsec_site_conn['peer_address'],
|
||||
'peer_id': ipsec_site_conn['peer_id'],
|
||||
'route_mode': ipsec_site_conn['route_mode'],
|
||||
'mtu': ipsec_site_conn['mtu'],
|
||||
'auth_mode': ipsec_site_conn['auth_mode'],
|
||||
'psk': ipsec_site_conn['psk'],
|
||||
'initiator': ipsec_site_conn['initiator'],
|
||||
'dpd': {
|
||||
'action': ipsec_site_conn['dpd_action'],
|
||||
'interval': ipsec_site_conn['dpd_interval'],
|
||||
'timeout': ipsec_site_conn['dpd_timeout']
|
||||
},
|
||||
'admin_state_up': ipsec_site_conn['admin_state_up'],
|
||||
'status': ipsec_site_conn['status'],
|
||||
'vpnservice_id': ipsec_site_conn['vpnservice_id'],
|
||||
'ikepolicy_id': ipsec_site_conn['ikepolicy_id'],
|
||||
'ipsecpolicy_id': ipsec_site_conn['ipsecpolicy_id'],
|
||||
'peer_cidrs': [pcidr['cidr']
|
||||
for pcidr in ipsec_site_conn['peer_cidrs']]
|
||||
}
|
||||
|
||||
return self._fields(res, fields)
|
||||
|
||||
def create_ipsec_site_connection(self, context, ipsec_site_connection):
|
||||
ipsec_sitecon = ipsec_site_connection['ipsec_site_connection']
|
||||
dpd = ipsec_sitecon['dpd']
|
||||
ipsec_sitecon['dpd_action'] = dpd.get('action', 'hold')
|
||||
ipsec_sitecon['dpd_interval'] = dpd.get('interval', 30)
|
||||
ipsec_sitecon['dpd_timeout'] = dpd.get('timeout', 120)
|
||||
tenant_id = self._get_tenant_id_for_create(context, ipsec_sitecon)
|
||||
if ipsec_sitecon['dpd_timeout'] < ipsec_sitecon['dpd_interval']:
|
||||
raise vpnaas.IPsecSiteConnectionDpdIntervalValueError(
|
||||
attribute_a='dpd_timeout')
|
||||
with context.session.begin(subtransactions=True):
|
||||
#Check permissions
|
||||
self._get_resource(context,
|
||||
VPNService,
|
||||
ipsec_sitecon['vpnservice_id'])
|
||||
self._get_resource(context,
|
||||
IKEPolicy,
|
||||
ipsec_sitecon['ikepolicy_id'])
|
||||
self._get_resource(context,
|
||||
IPsecPolicy,
|
||||
ipsec_sitecon['ipsecpolicy_id'])
|
||||
ipsec_site_conn_db = IPsecSiteConnection(
|
||||
id=uuidutils.generate_uuid(),
|
||||
tenant_id=tenant_id,
|
||||
name=ipsec_sitecon['name'],
|
||||
description=ipsec_sitecon['description'],
|
||||
peer_address=ipsec_sitecon['peer_address'],
|
||||
peer_id=ipsec_sitecon['peer_id'],
|
||||
route_mode='static',
|
||||
mtu=ipsec_sitecon['mtu'],
|
||||
auth_mode='psk',
|
||||
psk=ipsec_sitecon['psk'],
|
||||
initiator=ipsec_sitecon['initiator'],
|
||||
dpd_action=ipsec_sitecon['dpd_action'],
|
||||
dpd_interval=ipsec_sitecon['dpd_interval'],
|
||||
dpd_timeout=ipsec_sitecon['dpd_timeout'],
|
||||
admin_state_up=ipsec_sitecon['admin_state_up'],
|
||||
status=constants.PENDING_CREATE,
|
||||
vpnservice_id=ipsec_sitecon['vpnservice_id'],
|
||||
ikepolicy_id=ipsec_sitecon['ikepolicy_id'],
|
||||
ipsecpolicy_id=ipsec_sitecon['ipsecpolicy_id']
|
||||
)
|
||||
context.session.add(ipsec_site_conn_db)
|
||||
for cidr in ipsec_sitecon['peer_cidrs']:
|
||||
peer_cidr_db = IPsecPeerCidr(
|
||||
cidr=cidr,
|
||||
ipsec_site_connection_id=ipsec_site_conn_db['id']
|
||||
)
|
||||
context.session.add(peer_cidr_db)
|
||||
return self._make_ipsec_site_connection_dict(ipsec_site_conn_db)
|
||||
|
||||
def update_ipsec_site_connection(
|
||||
self, context,
|
||||
ipsec_site_conn_id, ipsec_site_connection):
|
||||
ipsec_sitecon = ipsec_site_connection['ipsec_site_connection']
|
||||
dpd = ipsec_sitecon.get('dpd', {})
|
||||
if dpd.get('action'):
|
||||
ipsec_sitecon['dpd_action'] = dpd.get('action')
|
||||
if dpd.get('interval'):
|
||||
ipsec_sitecon['dpd_interval'] = dpd.get('interval')
|
||||
if dpd.get('timeout'):
|
||||
ipsec_sitecon['dpd_timeout'] = dpd.get('timeout')
|
||||
changed_peer_cidrs = False
|
||||
with context.session.begin(subtransactions=True):
|
||||
ipsec_site_conn_db = self._get_resource(
|
||||
context,
|
||||
IPsecSiteConnection,
|
||||
ipsec_site_conn_id)
|
||||
self.assert_update_allowed(ipsec_site_conn_db)
|
||||
if "peer_cidrs" in ipsec_sitecon:
|
||||
changed_peer_cidrs = True
|
||||
old_peer_cidr_list = ipsec_site_conn_db['peer_cidrs']
|
||||
old_peer_cidr_dict = dict(
|
||||
(peer_cidr['cidr'], peer_cidr)
|
||||
for peer_cidr in old_peer_cidr_list)
|
||||
new_peer_cidr_set = set(ipsec_sitecon["peer_cidrs"])
|
||||
old_peer_cidr_set = set(old_peer_cidr_dict)
|
||||
|
||||
new_peer_cidrs = list(new_peer_cidr_set)
|
||||
for peer_cidr in old_peer_cidr_set - new_peer_cidr_set:
|
||||
context.session.delete(old_peer_cidr_dict[peer_cidr])
|
||||
for peer_cidr in new_peer_cidr_set - old_peer_cidr_set:
|
||||
pcidr = IPsecPeerCidr(
|
||||
cidr=peer_cidr,
|
||||
ipsec_site_connection_id=ipsec_site_conn_id)
|
||||
context.session.add(pcidr)
|
||||
del ipsec_sitecon["peer_cidrs"]
|
||||
if ipsec_sitecon:
|
||||
ipsec_site_conn_db.update(ipsec_sitecon)
|
||||
result = self._make_ipsec_site_connection_dict(ipsec_site_conn_db)
|
||||
if changed_peer_cidrs:
|
||||
result['peer_cidrs'] = new_peer_cidrs
|
||||
return result
|
||||
|
||||
def delete_ipsec_site_connection(self, context, ipsec_site_conn_id):
|
||||
with context.session.begin(subtransactions=True):
|
||||
ipsec_site_conn_db = self._get_resource(
|
||||
context, IPsecSiteConnection, ipsec_site_conn_id
|
||||
)
|
||||
context.session.delete(ipsec_site_conn_db)
|
||||
|
||||
def get_ipsec_site_connection(self, context,
|
||||
ipsec_site_conn_id, fields=None):
|
||||
ipsec_site_conn_db = self._get_resource(
|
||||
context, IPsecSiteConnection, ipsec_site_conn_id
|
||||
)
|
||||
return self._make_ipsec_site_connection_dict(
|
||||
ipsec_site_conn_db, fields)
|
||||
|
||||
def get_ipsec_site_connections(self, context, filters=None, fields=None):
|
||||
return self._get_collection(context, IPsecSiteConnection,
|
||||
self._make_ipsec_site_connection_dict,
|
||||
filters=filters, fields=fields)
|
||||
|
||||
def _make_ikepolicy_dict(self, ikepolicy, fields=None):
|
||||
res = {'id': ikepolicy['id'],
|
||||
'tenant_id': ikepolicy['tenant_id'],
|
||||
'name': ikepolicy['name'],
|
||||
'description': ikepolicy['description'],
|
||||
'auth_algorithm': ikepolicy['auth_algorithm'],
|
||||
'encryption_algorithm': ikepolicy['encryption_algorithm'],
|
||||
'phase1_negotiation_mode': ikepolicy['phase1_negotiation_mode'],
|
||||
'lifetime': {
|
||||
'units': ikepolicy['lifetime_units'],
|
||||
'value': ikepolicy['lifetime_value'],
|
||||
},
|
||||
'ike_version': ikepolicy['ike_version'],
|
||||
'pfs': ikepolicy['pfs']
|
||||
}
|
||||
|
||||
return self._fields(res, fields)
|
||||
|
||||
def create_ikepolicy(self, context, ikepolicy):
|
||||
ike = ikepolicy['ikepolicy']
|
||||
tenant_id = self._get_tenant_id_for_create(context, ike)
|
||||
lifetime_info = ike.get('lifetime', [])
|
||||
lifetime_units = lifetime_info.get('unit', 'seconds')
|
||||
lifetime_value = lifetime_info.get('value', 3600)
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
ike_db = IKEPolicy(
|
||||
id=uuidutils.generate_uuid(),
|
||||
tenant_id=tenant_id,
|
||||
name=ike['name'],
|
||||
description=ike['description'],
|
||||
auth_algorithm=ike['auth_algorithm'],
|
||||
encryption_algorithm=ike['encryption_algorithm'],
|
||||
phase1_negotiation_mode=ike['phase1_negotiation_mode'],
|
||||
lifetime_units=lifetime_units,
|
||||
lifetime_value=lifetime_value,
|
||||
ike_version=ike['ike_version'],
|
||||
pfs=ike['pfs']
|
||||
)
|
||||
|
||||
context.session.add(ike_db)
|
||||
return self._make_ikepolicy_dict(ike_db)
|
||||
|
||||
def update_ikepolicy(self, context, ikepolicy_id, ikepolicy):
|
||||
ike = ikepolicy['ikepolicy']
|
||||
with context.session.begin(subtransactions=True):
|
||||
ikepolicy = context.session.query(IPsecSiteConnection).filter_by(
|
||||
ikepolicy_id=ikepolicy_id).first()
|
||||
if ikepolicy:
|
||||
raise vpnaas.IKEPolicyInUse(ikepolicy_id=ikepolicy_id)
|
||||
ike_db = self._get_resource(context, IKEPolicy, ikepolicy_id)
|
||||
if ike:
|
||||
lifetime_info = ike.get('lifetime')
|
||||
if lifetime_info:
|
||||
if lifetime_info.get('units'):
|
||||
ike['lifetime_units'] = lifetime_info['units']
|
||||
if lifetime_info.get('value'):
|
||||
ike['lifetime_value'] = lifetime_info['value']
|
||||
ike_db.update(ike)
|
||||
return self._make_ikepolicy_dict(ike_db)
|
||||
|
||||
def delete_ikepolicy(self, context, ikepolicy_id):
|
||||
with context.session.begin(subtransactions=True):
|
||||
ikepolicy = context.session.query(IPsecSiteConnection).filter_by(
|
||||
ikepolicy_id=ikepolicy_id).first()
|
||||
if ikepolicy:
|
||||
raise vpnaas.IKEPolicyInUse(ikepolicy_id=ikepolicy_id)
|
||||
ike_db = self._get_resource(context, IKEPolicy, ikepolicy_id)
|
||||
context.session.delete(ike_db)
|
||||
|
||||
def get_ikepolicy(self, context, ikepolicy_id, fields=None):
|
||||
ike_db = self._get_resource(context, IKEPolicy, ikepolicy_id)
|
||||
return self._make_ikepolicy_dict(ike_db, fields)
|
||||
|
||||
def get_ikepolicies(self, context, filters=None, fields=None):
|
||||
return self._get_collection(context, IKEPolicy,
|
||||
self._make_ikepolicy_dict,
|
||||
filters=filters, fields=fields)
|
||||
|
||||
def _make_ipsecpolicy_dict(self, ipsecpolicy, fields=None):
|
||||
|
||||
res = {'id': ipsecpolicy['id'],
|
||||
'tenant_id': ipsecpolicy['tenant_id'],
|
||||
'name': ipsecpolicy['name'],
|
||||
'description': ipsecpolicy['description'],
|
||||
'transform_protocol': ipsecpolicy['transform_protocol'],
|
||||
'auth_algorithm': ipsecpolicy['auth_algorithm'],
|
||||
'encryption_algorithm': ipsecpolicy['encryption_algorithm'],
|
||||
'encapsulation_mode': ipsecpolicy['encapsulation_mode'],
|
||||
'lifetime': {
|
||||
'units': ipsecpolicy['lifetime_units'],
|
||||
'value': ipsecpolicy['lifetime_value'],
|
||||
},
|
||||
'pfs': ipsecpolicy['pfs']
|
||||
}
|
||||
|
||||
return self._fields(res, fields)
|
||||
|
||||
def create_ipsecpolicy(self, context, ipsecpolicy):
|
||||
ipsecp = ipsecpolicy['ipsecpolicy']
|
||||
tenant_id = self._get_tenant_id_for_create(context, ipsecp)
|
||||
lifetime_info = ipsecp['lifetime']
|
||||
lifetime_units = lifetime_info.get('units', 'seconds')
|
||||
lifetime_value = lifetime_info.get('value', 3600)
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
ipsecp_db = IPsecPolicy(id=uuidutils.generate_uuid(),
|
||||
tenant_id=tenant_id,
|
||||
name=ipsecp['name'],
|
||||
description=ipsecp['description'],
|
||||
transform_protocol=ipsecp['transform_'
|
||||
'protocol'],
|
||||
auth_algorithm=ipsecp['auth_algorithm'],
|
||||
encryption_algorithm=ipsecp['encryption_'
|
||||
'algorithm'],
|
||||
encapsulation_mode=ipsecp['encapsulation_'
|
||||
'mode'],
|
||||
lifetime_units=lifetime_units,
|
||||
lifetime_value=lifetime_value,
|
||||
pfs=ipsecp['pfs'])
|
||||
context.session.add(ipsecp_db)
|
||||
return self._make_ipsecpolicy_dict(ipsecp_db)
|
||||
|
||||
def update_ipsecpolicy(self, context, ipsecpolicy_id, ipsecpolicy):
|
||||
ipsecp = ipsecpolicy['ipsecpolicy']
|
||||
with context.session.begin(subtransactions=True):
|
||||
ipsecpolicy = context.session.query(IPsecSiteConnection).filter_by(
|
||||
ipsecpolicy_id=ipsecpolicy_id).first()
|
||||
if ipsecpolicy:
|
||||
raise vpnaas.IPsecPolicyInUse(ipsecpolicy_id=ipsecpolicy_id)
|
||||
ipsecp_db = self._get_resource(context,
|
||||
IPsecPolicy,
|
||||
ipsecpolicy_id)
|
||||
if ipsecp:
|
||||
lifetime_info = ipsecp.get('lifetime')
|
||||
if lifetime_info:
|
||||
if lifetime_info.get('units'):
|
||||
ipsecp['lifetime_units'] = lifetime_info['units']
|
||||
if lifetime_info('value'):
|
||||
ipsecp['lifetime_value'] = lifetime_info['value']
|
||||
ipsecp_db.update(ipsecp)
|
||||
return self._make_ipsecpolicy_dict(ipsecp_db)
|
||||
|
||||
def delete_ipsecpolicy(self, context, ipsecpolicy_id):
|
||||
with context.session.begin(subtransactions=True):
|
||||
ipsecpolicy = context.session.query(IPsecSiteConnection).filter_by(
|
||||
ipsecpolicy_id=ipsecpolicy_id).first()
|
||||
if ipsecpolicy:
|
||||
raise vpnaas.IPsecPolicyInUse(ipsecpolicy_id=ipsecpolicy_id)
|
||||
ipsec_db = self._get_resource(context, IPsecPolicy, ipsecpolicy_id)
|
||||
context.session.delete(ipsec_db)
|
||||
|
||||
def get_ipsecpolicy(self, context, ipsecpolicy_id, fields=None):
|
||||
ipsec_db = self._get_resource(context, IPsecPolicy, ipsecpolicy_id)
|
||||
return self._make_ipsecpolicy_dict(ipsec_db, fields)
|
||||
|
||||
def get_ipsecpolicies(self, context, filters=None, fields=None):
|
||||
return self._get_collection(context, IPsecPolicy,
|
||||
self._make_ipsecpolicy_dict,
|
||||
filters=filters, fields=fields)
|
||||
|
||||
def _make_vpnservice_dict(self, vpnservice, fields=None):
|
||||
res = {'id': vpnservice['id'],
|
||||
'name': vpnservice['name'],
|
||||
'description': vpnservice['description'],
|
||||
'tenant_id': vpnservice['tenant_id'],
|
||||
'subnet_id': vpnservice['subnet_id'],
|
||||
'router_id': vpnservice['router_id'],
|
||||
'admin_state_up': vpnservice['admin_state_up'],
|
||||
'status': vpnservice['status']}
|
||||
return self._fields(res, fields)
|
||||
|
||||
def create_vpnservice(self, context, vpnservice):
|
||||
vpns = vpnservice['vpnservice']
|
||||
tenant_id = self._get_tenant_id_for_create(context, vpns)
|
||||
with context.session.begin(subtransactions=True):
|
||||
vpnservice_db = VPNService(id=uuidutils.generate_uuid(),
|
||||
tenant_id=tenant_id,
|
||||
name=vpns['name'],
|
||||
description=vpns['description'],
|
||||
subnet_id=vpns['subnet_id'],
|
||||
router_id=vpns['router_id'],
|
||||
admin_state_up=vpns['admin_state_up'],
|
||||
status=constants.PENDING_CREATE)
|
||||
context.session.add(vpnservice_db)
|
||||
return self._make_vpnservice_dict(vpnservice_db)
|
||||
|
||||
def update_vpnservice(self, context, vpnservice_id, vpnservice):
|
||||
vpns = vpnservice['vpnservice']
|
||||
with context.session.begin(subtransactions=True):
|
||||
vpnservice = context.session.query(IPsecSiteConnection).filter_by(
|
||||
vpnservice_id=vpnservice_id).first()
|
||||
if vpnservice:
|
||||
raise vpnaas.VPNServiceInUse(vpnservice_id=vpnservice_id)
|
||||
vpns_db = self._get_resource(context, VPNService, vpnservice_id)
|
||||
self.assert_update_allowed(vpns_db)
|
||||
if vpns:
|
||||
vpns_db.update(vpns)
|
||||
return self._make_vpnservice_dict(vpns_db)
|
||||
|
||||
def delete_vpnservice(self, context, vpnservice_id):
|
||||
with context.session.begin(subtransactions=True):
|
||||
if context.session.query(IPsecSiteConnection).filter_by(
|
||||
vpnservice_id=vpnservice_id
|
||||
).first():
|
||||
raise vpnaas.VPNServiceInUse(vpnservice_id=vpnservice_id)
|
||||
vpns_db = self._get_resource(context, VPNService, vpnservice_id)
|
||||
context.session.delete(vpns_db)
|
||||
|
||||
def _get_vpnservice(self, context, vpnservice_id):
|
||||
return self._get_resource(context, VPNService, vpnservice_id)
|
||||
|
||||
def get_vpnservice(self, context, vpnservice_id, fields=None):
|
||||
vpns_db = self._get_resource(context, VPNService, vpnservice_id)
|
||||
return self._make_vpnservice_dict(vpns_db, fields)
|
||||
|
||||
def get_vpnservices(self, context, filters=None, fields=None):
|
||||
return self._get_collection(context, VPNService,
|
||||
self._make_vpnservice_dict,
|
||||
filters=filters, fields=fields)
|
||||
|
||||
|
||||
class VPNPluginRpcDbMixin():
|
||||
def _get_agent_hosting_vpn_services(self, context, host):
|
||||
|
||||
plugin = manager.NeutronManager.get_plugin()
|
||||
agent = plugin._get_agent_by_type_and_host(
|
||||
context, q_constants.AGENT_TYPE_L3, host)
|
||||
if not agent.admin_state_up:
|
||||
return []
|
||||
query = context.session.query(VPNService)
|
||||
query = query.join(IPsecSiteConnection)
|
||||
query = query.join(IKEPolicy)
|
||||
query = query.join(IPsecPolicy)
|
||||
query = query.join(IPsecPeerCidr)
|
||||
query = query.join(agent_db.RouterL3AgentBinding,
|
||||
agent_db.RouterL3AgentBinding.router_id ==
|
||||
VPNService.router_id)
|
||||
query = query.filter(
|
||||
agent_db.RouterL3AgentBinding.l3_agent_id == agent.id)
|
||||
return query
|
||||
|
||||
def update_status_on_host(self, context, host, active_services):
|
||||
with context.session.begin(subtransactions=True):
|
||||
vpnservices = self._get_agent_hosting_vpn_services(
|
||||
context, host)
|
||||
for vpnservice in vpnservices:
|
||||
if vpnservice.id in active_services:
|
||||
if vpnservice.status != constants.ACTIVE:
|
||||
vpnservice.status = constants.ACTIVE
|
||||
else:
|
||||
if vpnservice.status != constants.ERROR:
|
||||
vpnservice.status = constants.ERROR
|
477
neutron/extensions/vpnaas.py
Normal file
477
neutron/extensions/vpnaas.py
Normal file
@ -0,0 +1,477 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||
# 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: Swaminathan Vasudevan, Hewlett-Packard.
|
||||
|
||||
import abc
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.api.v2 import attributes as attr
|
||||
from neutron.api.v2 import base
|
||||
from neutron.common import exceptions as qexception
|
||||
from neutron import manager
|
||||
from neutron.plugins.common import constants
|
||||
from neutron import quota
|
||||
from neutron.services.service_base import ServicePluginBase
|
||||
|
||||
|
||||
class VPNServiceNotFound(qexception.NotFound):
|
||||
message = _("VPNService %(vpnservice_id)s could not be found")
|
||||
|
||||
|
||||
class IPsecSiteConnectionNotFound(qexception.NotFound):
|
||||
message = _("ipsec_site_connection %(ipsecsite_conn_id)s not found")
|
||||
|
||||
|
||||
class IPsecSiteConnectionDpdIntervalValueError(qexception.InvalidInput):
|
||||
message = _("ipsec_site_connection %(attribute_a)s less than dpd_interval")
|
||||
|
||||
|
||||
class IKEPolicyNotFound(qexception.NotFound):
|
||||
message = _("IKEPolicy %(ikepolicy_id)s could not be found")
|
||||
|
||||
|
||||
class IPsecPolicyNotFound(qexception.NotFound):
|
||||
message = _("IPsecPolicy %(ipsecpolicy_id)s could not be found")
|
||||
|
||||
|
||||
class IKEPolicyInUse(qexception.InUse):
|
||||
message = _("IKEPolicy %(ikepolicy_id)s is still in use")
|
||||
|
||||
|
||||
class VPNServiceInUse(qexception.InUse):
|
||||
message = _("VPNService %(vpnservice_id)s is still in use")
|
||||
|
||||
|
||||
class VPNStateInvalid(qexception.BadRequest):
|
||||
message = _("Invalid state %(state)s of vpnaas resource %(id)s")
|
||||
|
||||
|
||||
class IPsecPolicyInUse(qexception.InUse):
|
||||
message = _("IPsecPolicy %(ipsecpolicy_id)s is still in use")
|
||||
|
||||
|
||||
vpn_supported_initiators = ['bi-directional', 'response-only']
|
||||
vpn_supported_encryption_algorithms = ['3des', 'aes-128',
|
||||
'aes-192', 'aes-256']
|
||||
vpn_dpd_supported_actions = [
|
||||
'hold', 'clear', 'restart', 'restart-by-peer', 'disabled'
|
||||
]
|
||||
vpn_supported_transform_protocols = ['esp', 'ah', 'ah-esp']
|
||||
vpn_supported_encapsulation_mode = ['tunnel', 'transport']
|
||||
vpn_supported_lifetime_units = ['seconds', 'kilobytes']
|
||||
vpn_supported_pfs = ['group2', 'group5', 'group14']
|
||||
vpn_supported_ike_versions = ['v1', 'v2']
|
||||
vpn_supported_auth_mode = ['psk']
|
||||
vpn_supported_auth_algorithms = ['sha1']
|
||||
vpn_supported_phase1_negotiation_mode = ['main']
|
||||
|
||||
|
||||
RESOURCE_ATTRIBUTE_MAP = {
|
||||
|
||||
'vpnservices': {
|
||||
'id': {'allow_post': False, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True,
|
||||
'primary_key': True},
|
||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||
'validate': {'type:string': None},
|
||||
'required_by_policy': True,
|
||||
'is_visible': True},
|
||||
'name': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True, 'default': ''},
|
||||
'description': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True, 'default': ''},
|
||||
'subnet_id': {'allow_post': True, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True},
|
||||
'router_id': {'allow_post': True, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True},
|
||||
'admin_state_up': {'allow_post': True, 'allow_put': True,
|
||||
'default': True,
|
||||
'convert_to': attr.convert_to_boolean,
|
||||
'is_visible': True},
|
||||
'status': {'allow_post': False, 'allow_put': False,
|
||||
'is_visible': True}
|
||||
},
|
||||
|
||||
'ipsec_site_connections': {
|
||||
'id': {'allow_post': False, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True,
|
||||
'primary_key': True},
|
||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||
'validate': {'type:string': None},
|
||||
'required_by_policy': True,
|
||||
'is_visible': True},
|
||||
'name': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True, 'default': ''},
|
||||
'description': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True, 'default': ''},
|
||||
'peer_address': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True},
|
||||
'peer_id': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True},
|
||||
'peer_cidrs': {'allow_post': True, 'allow_put': True,
|
||||
'convert_to': attr.convert_to_list,
|
||||
'validate': {'type:subnet_list': None},
|
||||
'is_visible': True},
|
||||
'route_mode': {'allow_post': False, 'allow_put': False,
|
||||
'default': 'static',
|
||||
'is_visible': True},
|
||||
'mtu': {'allow_post': True, 'allow_put': True,
|
||||
'default': '1500',
|
||||
'validate': {'type:non_negative': None},
|
||||
'convert_to': attr.convert_to_int,
|
||||
'is_visible': True},
|
||||
'initiator': {'allow_post': True, 'allow_put': True,
|
||||
'default': 'bi-directional',
|
||||
'validate': {'type:values': vpn_supported_initiators},
|
||||
'is_visible': True},
|
||||
'auth_mode': {'allow_post': False, 'allow_put': False,
|
||||
'default': 'psk',
|
||||
'validate': {'type:values': vpn_supported_auth_mode},
|
||||
'is_visible': True},
|
||||
'psk': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True},
|
||||
'dpd': {'allow_post': True, 'allow_put': True,
|
||||
'convert_to': attr.convert_none_to_empty_dict,
|
||||
'is_visible': True,
|
||||
'default': {},
|
||||
'validate': {
|
||||
'type:dict_or_empty': {
|
||||
'actions': {
|
||||
'type:values': vpn_dpd_supported_actions,
|
||||
},
|
||||
'interval': {
|
||||
'type:non_negative': None
|
||||
},
|
||||
'timeout': {
|
||||
'type:non_negative': None
|
||||
}}}},
|
||||
'admin_state_up': {'allow_post': True, 'allow_put': True,
|
||||
'default': True,
|
||||
'convert_to': attr.convert_to_boolean,
|
||||
'is_visible': True},
|
||||
'status': {'allow_post': False, 'allow_put': False,
|
||||
'is_visible': True},
|
||||
'vpnservice_id': {'allow_post': True, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True},
|
||||
'ikepolicy_id': {'allow_post': True, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True},
|
||||
'ipsecpolicy_id': {'allow_post': True, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True}
|
||||
},
|
||||
|
||||
'ipsecpolicies': {
|
||||
'id': {'allow_post': False, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True,
|
||||
'primary_key': True},
|
||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||
'validate': {'type:string': None},
|
||||
'required_by_policy': True,
|
||||
'is_visible': True},
|
||||
'name': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True, 'default': ''},
|
||||
'description': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True, 'default': ''},
|
||||
'transform_protocol': {
|
||||
'allow_post': True,
|
||||
'allow_put': True,
|
||||
'default': 'esp',
|
||||
'validate': {
|
||||
'type:values': vpn_supported_transform_protocols},
|
||||
'is_visible': True},
|
||||
'auth_algorithm': {
|
||||
'allow_post': True,
|
||||
'allow_put': True,
|
||||
'default': 'sha1',
|
||||
'validate': {
|
||||
'type:values': vpn_supported_auth_algorithms
|
||||
},
|
||||
'is_visible': True},
|
||||
'encryption_algorithm': {
|
||||
'allow_post': True,
|
||||
'allow_put': True,
|
||||
'default': 'aes-128',
|
||||
'validate': {
|
||||
'type:values': vpn_supported_encryption_algorithms
|
||||
},
|
||||
'is_visible': True},
|
||||
'encapsulation_mode': {
|
||||
'allow_post': True,
|
||||
'allow_put': True,
|
||||
'default': 'tunnel',
|
||||
'validate': {
|
||||
'type:values': vpn_supported_encapsulation_mode
|
||||
},
|
||||
'is_visible': True},
|
||||
'lifetime': {'allow_post': True, 'allow_put': True,
|
||||
'convert_to': attr.convert_none_to_empty_dict,
|
||||
'default': {},
|
||||
'validate': {
|
||||
'type:dict_or_empty': {
|
||||
'units': {
|
||||
'type:values': vpn_supported_lifetime_units,
|
||||
},
|
||||
'value': {
|
||||
'type:non_negative': None}}},
|
||||
'is_visible': True},
|
||||
'pfs': {'allow_post': True, 'allow_put': True,
|
||||
'default': 'group5',
|
||||
'validate': {'type:values': vpn_supported_pfs},
|
||||
'is_visible': True}
|
||||
},
|
||||
|
||||
'ikepolicies': {
|
||||
'id': {'allow_post': False, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True,
|
||||
'primary_key': True},
|
||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||
'validate': {'type:string': None},
|
||||
'required_by_policy': True,
|
||||
'is_visible': True},
|
||||
'name': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True, 'default': ''},
|
||||
'description': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True, 'default': ''},
|
||||
'auth_algorithm': {'allow_post': True, 'allow_put': True,
|
||||
'default': 'sha1',
|
||||
'validate': {
|
||||
'type:values': vpn_supported_auth_algorithms},
|
||||
'is_visible': True},
|
||||
'encryption_algorithm': {
|
||||
'allow_post': True, 'allow_put': True,
|
||||
'default': 'aes-128',
|
||||
'validate': {'type:values': vpn_supported_encryption_algorithms},
|
||||
'is_visible': True},
|
||||
'phase1_negotiation_mode': {
|
||||
'allow_post': True, 'allow_put': True,
|
||||
'default': 'main',
|
||||
'validate': {
|
||||
'type:values': vpn_supported_phase1_negotiation_mode
|
||||
},
|
||||
'is_visible': True},
|
||||
'lifetime': {'allow_post': True, 'allow_put': True,
|
||||
'convert_to': attr.convert_none_to_empty_dict,
|
||||
'default': {},
|
||||
'validate': {
|
||||
'type:dict_or_empty': {
|
||||
'units': {
|
||||
'type:values': vpn_supported_lifetime_units,
|
||||
},
|
||||
'value': {
|
||||
'type:non_negative': None,
|
||||
}}},
|
||||
'is_visible': True},
|
||||
'ike_version': {'allow_post': True, 'allow_put': True,
|
||||
'default': 'v1',
|
||||
'validate': {
|
||||
'type:values': vpn_supported_ike_versions},
|
||||
'is_visible': True},
|
||||
'pfs': {'allow_post': True, 'allow_put': True,
|
||||
'default': 'group5',
|
||||
'validate': {'type:values': vpn_supported_pfs},
|
||||
'is_visible': True}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Vpnaas(extensions.ExtensionDescriptor):
|
||||
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
return "VPN service"
|
||||
|
||||
@classmethod
|
||||
def get_alias(cls):
|
||||
return "vpnaas"
|
||||
|
||||
@classmethod
|
||||
def get_description(cls):
|
||||
return "Extension for VPN service"
|
||||
|
||||
@classmethod
|
||||
def get_namespace(cls):
|
||||
return "https://wiki.openstack.org/Neutron/VPNaaS"
|
||||
|
||||
@classmethod
|
||||
def get_updated(cls):
|
||||
return "2013-05-29T10:00:00-00:00"
|
||||
|
||||
@classmethod
|
||||
def get_resources(cls):
|
||||
plural_mapping = {
|
||||
'ikepolicies': 'ikepolicy',
|
||||
'ipsecpolicies': 'ipsecpolicy'
|
||||
}
|
||||
my_plurals = []
|
||||
for plural in RESOURCE_ATTRIBUTE_MAP:
|
||||
singular = plural_mapping.get(plural, plural[:-1])
|
||||
my_plurals.append((plural, singular))
|
||||
my_plurals.append(('peer_cidrs', 'peer_cidr'))
|
||||
attr.PLURALS.update(dict(my_plurals))
|
||||
resources = []
|
||||
plugin = manager.NeutronManager.get_service_plugins()[
|
||||
constants.VPN]
|
||||
for collection_name in RESOURCE_ATTRIBUTE_MAP:
|
||||
resource_name = plural_mapping.get(
|
||||
collection_name, collection_name[:-1])
|
||||
params = RESOURCE_ATTRIBUTE_MAP[collection_name]
|
||||
collection_name = collection_name.replace('_', '-')
|
||||
|
||||
quota.QUOTAS.register_resource_by_name(resource_name)
|
||||
controller = base.create_resource(
|
||||
collection_name, resource_name, plugin, params,
|
||||
allow_pagination=cfg.CONF.allow_pagination,
|
||||
allow_sorting=cfg.CONF.allow_sorting)
|
||||
|
||||
resource = extensions.ResourceExtension(
|
||||
collection_name,
|
||||
controller,
|
||||
path_prefix=constants.COMMON_PREFIXES[constants.VPN],
|
||||
attr_map=params)
|
||||
resources.append(resource)
|
||||
return resources
|
||||
|
||||
@classmethod
|
||||
def get_plugin_interface(cls):
|
||||
return VPNPluginBase
|
||||
|
||||
def update_attributes_map(self, attributes):
|
||||
super(Vpnaas, self).update_attributes_map(
|
||||
attributes, extension_attrs_map=RESOURCE_ATTRIBUTE_MAP)
|
||||
|
||||
def get_extended_resources(self, version):
|
||||
if version == "2.0":
|
||||
return RESOURCE_ATTRIBUTE_MAP
|
||||
else:
|
||||
return {}
|
||||
|
||||
|
||||
class VPNPluginBase(ServicePluginBase):
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
def get_plugin_name(self):
|
||||
return constants.VPN
|
||||
|
||||
def get_plugin_type(self):
|
||||
return constants.VPN
|
||||
|
||||
def get_plugin_description(self):
|
||||
return 'VPN service plugin'
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_vpnservices(self, context, filters=None, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_vpnservice(self, context, vpnservice_id, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_vpnservice(self, context, vpnservice):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_vpnservice(self, context, vpnservice_id, vpnservice):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_vpnservice(self, context, vpnservice_id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_ipsec_site_connections(self, context, filters=None, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_ipsec_site_connection(self, context,
|
||||
ipsecsite_conn_id, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_ipsec_site_connection(self, context, ipsec_site_connection):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_ipsec_site_connection(self, context,
|
||||
ipsecsite_conn_id, ipsec_site_connection):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_ipsec_site_connection(self, context, ipsecsite_conn_id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_ikepolicy(self, context, ikepolicy_id, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_ikepolicies(self, context, filters=None, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_ikepolicy(self, context, ikepolicy):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_ikepolicy(self, context, ikepolicy_id, ikepolicy):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_ikepolicy(self, context, ikepolicy_id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_ipsecpolicies(self, context, filters=None, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_ipsecpolicy(self, context, ipsecpolicy_id, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_ipsecpolicy(self, context, ipsecpolicy):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_ipsecpolicy(self, context, ipsecpolicy_id, ipsecpolicy):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_ipsecpolicy(self, context, ipsecpolicy_id):
|
||||
pass
|
@ -20,22 +20,25 @@ CORE = "CORE"
|
||||
DUMMY = "DUMMY"
|
||||
LOADBALANCER = "LOADBALANCER"
|
||||
FIREWALL = "FIREWALL"
|
||||
VPN = "VPN"
|
||||
|
||||
#maps extension alias to service type
|
||||
EXT_TO_SERVICE_MAPPING = {
|
||||
'dummy': DUMMY,
|
||||
'lbaas': LOADBALANCER,
|
||||
'fwaas': FIREWALL
|
||||
'fwaas': FIREWALL,
|
||||
'vpnaas': VPN,
|
||||
}
|
||||
|
||||
# TODO(salvatore-orlando): Move these (or derive them) from conf file
|
||||
ALLOWED_SERVICES = [CORE, DUMMY, LOADBALANCER, FIREWALL]
|
||||
ALLOWED_SERVICES = [CORE, DUMMY, LOADBALANCER, FIREWALL, VPN]
|
||||
|
||||
COMMON_PREFIXES = {
|
||||
CORE: "",
|
||||
DUMMY: "/dummy_svc",
|
||||
LOADBALANCER: "/lb",
|
||||
FIREWALL: "/fw",
|
||||
VPN: "/vpn",
|
||||
}
|
||||
|
||||
# Service operation status constants
|
||||
|
18
neutron/services/vpn/__init__.py
Normal file
18
neutron/services/vpn/__init__.py
Normal file
@ -0,0 +1,18 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||
# 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: Swaminathan Vasudevan, Hewlett-Packard
|
32
neutron/services/vpn/plugin.py
Normal file
32
neutron/services/vpn/plugin.py
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||
# 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: Swaminathan Vasudevan, Hewlett-Packard
|
||||
|
||||
from neutron.db.vpn import vpn_db
|
||||
|
||||
|
||||
class VPNPlugin(vpn_db.VPNPluginDb):
|
||||
|
||||
"""Implementation of the VPN Service Plugin.
|
||||
|
||||
This class manages the workflow of VPNaaS request/response.
|
||||
Most DB related works are implemented in class
|
||||
vpn_db.VPNPluginDb.
|
||||
"""
|
||||
supported_extension_aliases = ["vpnaas"]
|
17
neutron/tests/unit/db/vpn/__init__.py
Normal file
17
neutron/tests/unit/db/vpn/__init__.py
Normal file
@ -0,0 +1,17 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||
# 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: Swaminathan Vasudevan, Hewlett-Packard.
|
1541
neutron/tests/unit/db/vpn/test_db_vpnaas.py
Normal file
1541
neutron/tests/unit/db/vpn/test_db_vpnaas.py
Normal file
File diff suppressed because it is too large
Load Diff
17
neutron/tests/unit/services/vpn/__init__.py
Normal file
17
neutron/tests/unit/services/vpn/__init__.py
Normal file
@ -0,0 +1,17 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||
# 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: Swaminathan Vasudevan, Hewlett-Packard.
|
592
neutron/tests/unit/services/vpn/test_vpnaas_extension.py
Normal file
592
neutron/tests/unit/services/vpn/test_vpnaas_extension.py
Normal file
@ -0,0 +1,592 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||
# 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: Swaminathan Vasudevan, Hewlett-Packard.
|
||||
|
||||
import copy
|
||||
|
||||
import mock
|
||||
from oslo.config import cfg
|
||||
from webob import exc
|
||||
import webtest
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.api.v2 import attributes
|
||||
from neutron.common import config
|
||||
from neutron.extensions import vpnaas
|
||||
from neutron import manager
|
||||
from neutron.openstack.common import uuidutils
|
||||
from neutron.plugins.common import constants
|
||||
from neutron.tests.unit import test_api_v2
|
||||
from neutron.tests.unit import test_extensions
|
||||
from neutron.tests.unit import testlib_api
|
||||
|
||||
|
||||
_uuid = uuidutils.generate_uuid
|
||||
_get_path = test_api_v2._get_path
|
||||
|
||||
|
||||
class VpnaasTestExtensionManager(object):
|
||||
|
||||
def get_resources(self):
|
||||
# Add the resources to the global attribute map
|
||||
# This is done here as the setup process won't
|
||||
# initialize the main API router which extends
|
||||
# the global attribute map
|
||||
attributes.RESOURCE_ATTRIBUTE_MAP.update(
|
||||
vpnaas.RESOURCE_ATTRIBUTE_MAP)
|
||||
return vpnaas.Vpnaas.get_resources()
|
||||
|
||||
def get_actions(self):
|
||||
return []
|
||||
|
||||
def get_request_extensions(self):
|
||||
return []
|
||||
|
||||
|
||||
class VpnaasExtensionTestCase(testlib_api.WebTestCase):
|
||||
fmt = 'json'
|
||||
|
||||
def setUp(self):
|
||||
super(VpnaasExtensionTestCase, self).setUp()
|
||||
plugin = 'neutron.extensions.vpnaas.VPNPluginBase'
|
||||
# Ensure 'stale' patched copies of the plugin are never returned
|
||||
manager.NeutronManager._instance = None
|
||||
|
||||
# Ensure existing ExtensionManager is not used
|
||||
extensions.PluginAwareExtensionManager._instance = None
|
||||
|
||||
# Create the default configurations
|
||||
args = ['--config-file', test_api_v2.etcdir('neutron.conf.test')]
|
||||
config.parse(args)
|
||||
|
||||
#just stubbing core plugin with LoadBalancer plugin
|
||||
cfg.CONF.set_override('core_plugin', plugin)
|
||||
cfg.CONF.set_override('service_plugins', [plugin])
|
||||
|
||||
self._plugin_patcher = mock.patch(plugin, autospec=True)
|
||||
self.plugin = self._plugin_patcher.start()
|
||||
instance = self.plugin.return_value
|
||||
instance.get_plugin_type.return_value = constants.VPN
|
||||
|
||||
ext_mgr = VpnaasTestExtensionManager()
|
||||
self.ext_mdw = test_extensions.setup_extensions_middleware(ext_mgr)
|
||||
self.api = webtest.TestApp(self.ext_mdw)
|
||||
super(VpnaasExtensionTestCase, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
self._plugin_patcher.stop()
|
||||
self.api = None
|
||||
self.plugin = None
|
||||
cfg.CONF.reset()
|
||||
super(VpnaasExtensionTestCase, self).tearDown()
|
||||
|
||||
def test_ikepolicy_create(self):
|
||||
"""Test case to create an ikepolicy."""
|
||||
ikepolicy_id = _uuid()
|
||||
data = {'ikepolicy': {'name': 'ikepolicy1',
|
||||
'description': 'myikepolicy1',
|
||||
'auth_algorithm': 'sha1',
|
||||
'encryption_algorithm': 'aes-128',
|
||||
'phase1_negotiation_mode': 'main',
|
||||
'lifetime': {
|
||||
'units': 'seconds',
|
||||
'value': 3600},
|
||||
'ike_version': 'v1',
|
||||
'pfs': 'group5',
|
||||
'tenant_id': _uuid()}}
|
||||
|
||||
return_value = copy.copy(data['ikepolicy'])
|
||||
return_value.update({'id': ikepolicy_id})
|
||||
|
||||
instance = self.plugin.return_value
|
||||
instance.create_ikepolicy.return_value = return_value
|
||||
res = self.api.post(_get_path('vpn/ikepolicies', fmt=self.fmt),
|
||||
self.serialize(data),
|
||||
content_type='application/%s' % self.fmt)
|
||||
instance.create_ikepolicy.assert_called_with(mock.ANY,
|
||||
ikepolicy=data)
|
||||
self.assertEqual(res.status_int, exc.HTTPCreated.code)
|
||||
res = self.deserialize(res)
|
||||
self.assertIn('ikepolicy', res)
|
||||
self.assertEqual(res['ikepolicy'], return_value)
|
||||
|
||||
def test_ikepolicy_list(self):
|
||||
"""Test case to list all ikepolicies."""
|
||||
ikepolicy_id = _uuid()
|
||||
return_value = [{'name': 'ikepolicy1',
|
||||
'auth_algorithm': 'sha1',
|
||||
'encryption_algorithm': 'aes-128',
|
||||
'pfs': 'group5',
|
||||
'ike_version': 'v1',
|
||||
'id': ikepolicy_id}]
|
||||
|
||||
instance = self.plugin.return_value
|
||||
instance.get_ikepolicies.return_value = return_value
|
||||
|
||||
res = self.api.get(_get_path('vpn/ikepolicies', fmt=self.fmt))
|
||||
|
||||
instance.get_ikepolicies.assert_called_with(mock.ANY,
|
||||
fields=mock.ANY,
|
||||
filters=mock.ANY)
|
||||
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||
|
||||
def test_ikepolicy_update(self):
|
||||
"""Test case to update an ikepolicy."""
|
||||
ikepolicy_id = _uuid()
|
||||
update_data = {'ikepolicy': {'name': 'ikepolicy1',
|
||||
'encryption_algorithm': 'aes-256'}}
|
||||
return_value = {'name': 'ikepolicy1',
|
||||
'auth_algorithm': 'sha1',
|
||||
'encryption_algorithm': 'aes-256',
|
||||
'phase1_negotiation_mode': 'main',
|
||||
'lifetime': {
|
||||
'units': 'seconds',
|
||||
'value': 3600},
|
||||
'ike_version': 'v1',
|
||||
'pfs': 'group5',
|
||||
'tenant_id': _uuid(),
|
||||
'id': ikepolicy_id}
|
||||
|
||||
instance = self.plugin.return_value
|
||||
instance.update_ikepolicy.return_value = return_value
|
||||
|
||||
res = self.api.put(_get_path('vpn/ikepolicies', id=ikepolicy_id,
|
||||
fmt=self.fmt),
|
||||
self.serialize(update_data))
|
||||
|
||||
instance.update_ikepolicy.assert_called_with(mock.ANY, ikepolicy_id,
|
||||
ikepolicy=update_data)
|
||||
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||
res = self.deserialize(res)
|
||||
self.assertIn('ikepolicy', res)
|
||||
self.assertEqual(res['ikepolicy'], return_value)
|
||||
|
||||
def test_ikepolicy_get(self):
|
||||
"""Test case to get or show an ikepolicy."""
|
||||
ikepolicy_id = _uuid()
|
||||
return_value = {'name': 'ikepolicy1',
|
||||
'auth_algorithm': 'sha1',
|
||||
'encryption_algorithm': 'aes-128',
|
||||
'phase1_negotiation_mode': 'main',
|
||||
'lifetime': {
|
||||
'units': 'seconds',
|
||||
'value': 3600},
|
||||
'ike_version': 'v1',
|
||||
'pfs': 'group5',
|
||||
'tenant_id': _uuid(),
|
||||
'id': ikepolicy_id}
|
||||
|
||||
instance = self.plugin.return_value
|
||||
instance.get_ikepolicy.return_value = return_value
|
||||
|
||||
res = self.api.get(_get_path('vpn/ikepolicies', id=ikepolicy_id,
|
||||
fmt=self.fmt))
|
||||
|
||||
instance.get_ikepolicy.assert_called_with(mock.ANY,
|
||||
ikepolicy_id,
|
||||
fields=mock.ANY)
|
||||
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||
res = self.deserialize(res)
|
||||
self.assertIn('ikepolicy', res)
|
||||
self.assertEqual(res['ikepolicy'], return_value)
|
||||
|
||||
def test_ikepolicy_delete(self):
|
||||
"""Test case to delete an ikepolicy."""
|
||||
self._test_entity_delete('ikepolicy')
|
||||
|
||||
def test_ipsecpolicy_create(self):
|
||||
"""Test case to create an ipsecpolicy."""
|
||||
ipsecpolicy_id = _uuid()
|
||||
data = {'ipsecpolicy': {'name': 'ipsecpolicy1',
|
||||
'description': 'myipsecpolicy1',
|
||||
'auth_algorithm': 'sha1',
|
||||
'encryption_algorithm': 'aes-128',
|
||||
'encapsulation_mode': 'tunnel',
|
||||
'lifetime': {
|
||||
'units': 'seconds',
|
||||
'value': 3600},
|
||||
'transform_protocol': 'esp',
|
||||
'pfs': 'group5',
|
||||
'tenant_id': _uuid()}}
|
||||
return_value = copy.copy(data['ipsecpolicy'])
|
||||
return_value.update({'id': ipsecpolicy_id})
|
||||
|
||||
instance = self.plugin.return_value
|
||||
instance.create_ipsecpolicy.return_value = return_value
|
||||
res = self.api.post(_get_path('vpn/ipsecpolicies', fmt=self.fmt),
|
||||
self.serialize(data),
|
||||
content_type='application/%s' % self.fmt)
|
||||
instance.create_ipsecpolicy.assert_called_with(mock.ANY,
|
||||
ipsecpolicy=data)
|
||||
self.assertEqual(res.status_int, exc.HTTPCreated.code)
|
||||
res = self.deserialize(res)
|
||||
self.assertIn('ipsecpolicy', res)
|
||||
self.assertEqual(res['ipsecpolicy'], return_value)
|
||||
|
||||
def test_ipsecpolicy_list(self):
|
||||
"""Test case to list an ipsecpolicy."""
|
||||
ipsecpolicy_id = _uuid()
|
||||
return_value = [{'name': 'ipsecpolicy1',
|
||||
'auth_algorithm': 'sha1',
|
||||
'encryption_algorithm': 'aes-128',
|
||||
'pfs': 'group5',
|
||||
'id': ipsecpolicy_id}]
|
||||
|
||||
instance = self.plugin.return_value
|
||||
instance.get_ipsecpolicies.return_value = return_value
|
||||
|
||||
res = self.api.get(_get_path('vpn/ipsecpolicies', fmt=self.fmt))
|
||||
|
||||
instance.get_ipsecpolicies.assert_called_with(mock.ANY,
|
||||
fields=mock.ANY,
|
||||
filters=mock.ANY)
|
||||
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||
|
||||
def test_ipsecpolicy_update(self):
|
||||
"""Test case to update an ipsecpolicy."""
|
||||
ipsecpolicy_id = _uuid()
|
||||
update_data = {'ipsecpolicy': {'name': 'ipsecpolicy1',
|
||||
'encryption_algorithm': 'aes-256'}}
|
||||
return_value = {'name': 'ipsecpolicy1',
|
||||
'auth_algorithm': 'sha1',
|
||||
'encryption_algorithm': 'aes-128',
|
||||
'encapsulation_mode': 'tunnel',
|
||||
'lifetime': {
|
||||
'units': 'seconds',
|
||||
'value': 3600},
|
||||
'transform_protocol': 'esp',
|
||||
'pfs': 'group5',
|
||||
'tenant_id': _uuid(),
|
||||
'id': ipsecpolicy_id}
|
||||
|
||||
instance = self.plugin.return_value
|
||||
instance.update_ipsecpolicy.return_value = return_value
|
||||
|
||||
res = self.api.put(_get_path('vpn/ipsecpolicies',
|
||||
id=ipsecpolicy_id,
|
||||
fmt=self.fmt),
|
||||
self.serialize(update_data))
|
||||
|
||||
instance.update_ipsecpolicy.assert_called_with(mock.ANY,
|
||||
ipsecpolicy_id,
|
||||
ipsecpolicy=update_data)
|
||||
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||
res = self.deserialize(res)
|
||||
self.assertIn('ipsecpolicy', res)
|
||||
self.assertEqual(res['ipsecpolicy'], return_value)
|
||||
|
||||
def test_ipsecpolicy_get(self):
|
||||
"""Test case to get or show an ipsecpolicy."""
|
||||
ipsecpolicy_id = _uuid()
|
||||
return_value = {'name': 'ipsecpolicy1',
|
||||
'auth_algorithm': 'sha1',
|
||||
'encryption_algorithm': 'aes-128',
|
||||
'encapsulation_mode': 'tunnel',
|
||||
'lifetime': {
|
||||
'units': 'seconds',
|
||||
'value': 3600},
|
||||
'transform_protocol': 'esp',
|
||||
'pfs': 'group5',
|
||||
'tenant_id': _uuid(),
|
||||
'id': ipsecpolicy_id}
|
||||
|
||||
instance = self.plugin.return_value
|
||||
instance.get_ipsecpolicy.return_value = return_value
|
||||
|
||||
res = self.api.get(_get_path('vpn/ipsecpolicies',
|
||||
id=ipsecpolicy_id,
|
||||
fmt=self.fmt))
|
||||
|
||||
instance.get_ipsecpolicy.assert_called_with(mock.ANY,
|
||||
ipsecpolicy_id,
|
||||
fields=mock.ANY)
|
||||
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||
res = self.deserialize(res)
|
||||
self.assertIn('ipsecpolicy', res)
|
||||
self.assertEqual(res['ipsecpolicy'], return_value)
|
||||
|
||||
def test_ipsecpolicy_delete(self):
|
||||
"""Test case to delete an ipsecpolicy."""
|
||||
self._test_entity_delete('ipsecpolicy')
|
||||
|
||||
def test_vpnservice_create(self):
|
||||
"""Test case to create a vpnservice."""
|
||||
vpnservice_id = _uuid()
|
||||
data = {'vpnservice': {'name': 'vpnservice1',
|
||||
'description': 'descr_vpn1',
|
||||
'subnet_id': _uuid(),
|
||||
'router_id': _uuid(),
|
||||
'admin_state_up': True,
|
||||
'tenant_id': _uuid()}}
|
||||
return_value = copy.copy(data['vpnservice'])
|
||||
return_value.update({'status': "ACTIVE", 'id': vpnservice_id})
|
||||
|
||||
instance = self.plugin.return_value
|
||||
instance.create_vpnservice.return_value = return_value
|
||||
res = self.api.post(_get_path('vpn/vpnservices', fmt=self.fmt),
|
||||
self.serialize(data),
|
||||
content_type='application/%s' % self.fmt)
|
||||
instance.create_vpnservice.assert_called_with(mock.ANY,
|
||||
vpnservice=data)
|
||||
self.assertEqual(res.status_int, exc.HTTPCreated.code)
|
||||
res = self.deserialize(res)
|
||||
self.assertIn('vpnservice', res)
|
||||
self.assertEqual(res['vpnservice'], return_value)
|
||||
|
||||
def test_vpnservice_list(self):
|
||||
"""Test case to list all vpnservices."""
|
||||
vpnservice_id = _uuid()
|
||||
return_value = [{'name': 'vpnservice1',
|
||||
'tenant_id': _uuid(),
|
||||
'status': 'ACTIVE',
|
||||
'id': vpnservice_id}]
|
||||
|
||||
instance = self.plugin.return_value
|
||||
instance.get_vpnservice.return_value = return_value
|
||||
|
||||
res = self.api.get(_get_path('vpn/vpnservices', fmt=self.fmt))
|
||||
|
||||
instance.get_vpnservices.assert_called_with(mock.ANY,
|
||||
fields=mock.ANY,
|
||||
filters=mock.ANY)
|
||||
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||
|
||||
def test_vpnservice_update(self):
|
||||
"""Test case to update a vpnservice."""
|
||||
vpnservice_id = _uuid()
|
||||
update_data = {'vpnservice': {'admin_state_up': False}}
|
||||
return_value = {'name': 'vpnservice1',
|
||||
'admin_state_up': False,
|
||||
'subnet_id': _uuid(),
|
||||
'router_id': _uuid(),
|
||||
'tenant_id': _uuid(),
|
||||
'status': "ACTIVE",
|
||||
'id': vpnservice_id}
|
||||
|
||||
instance = self.plugin.return_value
|
||||
instance.update_vpnservice.return_value = return_value
|
||||
|
||||
res = self.api.put(_get_path('vpn/vpnservices',
|
||||
id=vpnservice_id,
|
||||
fmt=self.fmt),
|
||||
self.serialize(update_data))
|
||||
|
||||
instance.update_vpnservice.assert_called_with(mock.ANY,
|
||||
vpnservice_id,
|
||||
vpnservice=update_data)
|
||||
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||
res = self.deserialize(res)
|
||||
self.assertIn('vpnservice', res)
|
||||
self.assertEqual(res['vpnservice'], return_value)
|
||||
|
||||
def test_vpnservice_get(self):
|
||||
"""Test case to get or show a vpnservice."""
|
||||
vpnservice_id = _uuid()
|
||||
return_value = {'name': 'vpnservice1',
|
||||
'admin_state_up': True,
|
||||
'subnet_id': _uuid(),
|
||||
'router_id': _uuid(),
|
||||
'tenant_id': _uuid(),
|
||||
'status': "ACTIVE",
|
||||
'id': vpnservice_id}
|
||||
|
||||
instance = self.plugin.return_value
|
||||
instance.get_vpnservice.return_value = return_value
|
||||
|
||||
res = self.api.get(_get_path('vpn/vpnservices',
|
||||
id=vpnservice_id,
|
||||
fmt=self.fmt))
|
||||
|
||||
instance.get_vpnservice.assert_called_with(mock.ANY,
|
||||
vpnservice_id,
|
||||
fields=mock.ANY)
|
||||
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||
res = self.deserialize(res)
|
||||
self.assertIn('vpnservice', res)
|
||||
self.assertEqual(res['vpnservice'], return_value)
|
||||
|
||||
def _test_entity_delete(self, entity):
|
||||
"""does the entity deletion based on naming convention."""
|
||||
entity_id = _uuid()
|
||||
path_map = {'ipsecpolicy': 'vpn/ipsecpolicies',
|
||||
'ikepolicy': 'vpn/ikepolicies',
|
||||
'ipsec_site_connection': 'vpn/ipsec-site-connections'}
|
||||
path = path_map.get(entity, 'vpn/' + entity + 's')
|
||||
res = self.api.delete(_get_path(path,
|
||||
id=entity_id,
|
||||
fmt=self.fmt))
|
||||
delete_entity = getattr(self.plugin.return_value, "delete_" + entity)
|
||||
delete_entity.assert_called_with(mock.ANY, entity_id)
|
||||
self.assertEqual(res.status_int, exc.HTTPNoContent.code)
|
||||
|
||||
def test_vpnservice_delete(self):
|
||||
"""Test case to delete a vpnservice."""
|
||||
self._test_entity_delete('vpnservice')
|
||||
|
||||
def test_ipsec_site_connection_create(self):
|
||||
"""Test case to create a ipsec_site_connection."""
|
||||
ipsecsite_con_id = _uuid()
|
||||
ikepolicy_id = _uuid()
|
||||
ipsecpolicy_id = _uuid()
|
||||
data = {
|
||||
'ipsec_site_connection': {'name': 'connection1',
|
||||
'description': 'Remote-connection1',
|
||||
'peer_address': '192.168.1.10',
|
||||
'peer_id': '192.168.1.10',
|
||||
'peer_cidrs': ['192.168.2.0/24',
|
||||
'192.168.3.0/24'],
|
||||
'mtu': 1500,
|
||||
'psk': 'abcd',
|
||||
'initiator': 'bi-directional',
|
||||
'dpd': {
|
||||
'action': 'hold',
|
||||
'interval': 30,
|
||||
'timeout': 120},
|
||||
'ikepolicy_id': ikepolicy_id,
|
||||
'ipsecpolicy_id': ipsecpolicy_id,
|
||||
'vpnservice_id': _uuid(),
|
||||
'admin_state_up': True,
|
||||
'tenant_id': _uuid()}
|
||||
}
|
||||
return_value = copy.copy(data['ipsec_site_connection'])
|
||||
return_value.update({'status': "ACTIVE", 'id': ipsecsite_con_id})
|
||||
|
||||
instance = self.plugin.return_value
|
||||
instance.create_ipsec_site_connection.return_value = return_value
|
||||
res = self.api.post(_get_path('vpn/ipsec-site-connections',
|
||||
fmt=self.fmt),
|
||||
self.serialize(data),
|
||||
content_type='application/%s' % self.fmt)
|
||||
instance.create_ipsec_site_connection.assert_called_with(
|
||||
mock.ANY, ipsec_site_connection=data
|
||||
)
|
||||
self.assertEqual(res.status_int, exc.HTTPCreated.code)
|
||||
res = self.deserialize(res)
|
||||
self.assertIn('ipsec_site_connection', res)
|
||||
self.assertEqual(res['ipsec_site_connection'], return_value)
|
||||
|
||||
def test_ipsec_site_connection_list(self):
|
||||
"""Test case to list all ipsec_site_connections."""
|
||||
ipsecsite_con_id = _uuid()
|
||||
return_value = [{'name': 'connection1',
|
||||
'peer_address': '192.168.1.10',
|
||||
'peer_cidrs': ['192.168.2.0/24', '192.168.3.0/24'],
|
||||
'route_mode': 'static',
|
||||
'auth_mode': 'psk',
|
||||
'tenant_id': _uuid(),
|
||||
'status': 'ACTIVE',
|
||||
'id': ipsecsite_con_id}]
|
||||
|
||||
instance = self.plugin.return_value
|
||||
instance.get_ipsec_site_connections.return_value = return_value
|
||||
|
||||
res = self.api.get(
|
||||
_get_path('vpn/ipsec-site-connections', fmt=self.fmt))
|
||||
|
||||
instance.get_ipsec_site_connections.assert_called_with(
|
||||
mock.ANY, fields=mock.ANY, filters=mock.ANY
|
||||
)
|
||||
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||
|
||||
def test_ipsec_site_connection_update(self):
|
||||
"""Test case to update a ipsec_site_connection."""
|
||||
ipsecsite_con_id = _uuid()
|
||||
update_data = {'ipsec_site_connection': {'admin_state_up': False}}
|
||||
return_value = {'name': 'connection1',
|
||||
'description': 'Remote-connection1',
|
||||
'peer_address': '192.168.1.10',
|
||||
'peer_id': '192.168.1.10',
|
||||
'peer_cidrs': ['192.168.2.0/24', '192.168.3.0/24'],
|
||||
'mtu': 1500,
|
||||
'psk': 'abcd',
|
||||
'initiator': 'bi-directional',
|
||||
'dpd': {
|
||||
'action': 'hold',
|
||||
'interval': 30,
|
||||
'timeout': 120},
|
||||
'ikepolicy_id': _uuid(),
|
||||
'ipsecpolicy_id': _uuid(),
|
||||
'vpnservice_id': _uuid(),
|
||||
'admin_state_up': False,
|
||||
'tenant_id': _uuid(),
|
||||
'status': 'ACTIVE',
|
||||
'id': ipsecsite_con_id}
|
||||
|
||||
instance = self.plugin.return_value
|
||||
instance.update_ipsec_site_connection.return_value = return_value
|
||||
|
||||
res = self.api.put(_get_path('vpn/ipsec-site-connections',
|
||||
id=ipsecsite_con_id,
|
||||
fmt=self.fmt),
|
||||
self.serialize(update_data))
|
||||
|
||||
instance.update_ipsec_site_connection.assert_called_with(
|
||||
mock.ANY, ipsecsite_con_id, ipsec_site_connection=update_data
|
||||
)
|
||||
|
||||
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||
res = self.deserialize(res)
|
||||
self.assertIn('ipsec_site_connection', res)
|
||||
self.assertEqual(res['ipsec_site_connection'], return_value)
|
||||
|
||||
def test_ipsec_site_connection_get(self):
|
||||
"""Test case to get or show a ipsec_site_connection."""
|
||||
ipsecsite_con_id = _uuid()
|
||||
return_value = {'name': 'connection1',
|
||||
'description': 'Remote-connection1',
|
||||
'peer_address': '192.168.1.10',
|
||||
'peer_id': '192.168.1.10',
|
||||
'peer_cidrs': ['192.168.2.0/24',
|
||||
'192.168.3.0/24'],
|
||||
'mtu': 1500,
|
||||
'psk': 'abcd',
|
||||
'initiator': 'bi-directional',
|
||||
'dpd': {
|
||||
'action': 'hold',
|
||||
'interval': 30,
|
||||
'timeout': 120},
|
||||
'ikepolicy_id': _uuid(),
|
||||
'ipsecpolicy_id': _uuid(),
|
||||
'vpnservice_id': _uuid(),
|
||||
'admin_state_up': True,
|
||||
'tenant_id': _uuid(),
|
||||
'status': 'ACTIVE',
|
||||
'id': ipsecsite_con_id}
|
||||
|
||||
instance = self.plugin.return_value
|
||||
instance.get_ipsec_site_connection.return_value = return_value
|
||||
|
||||
res = self.api.get(_get_path('vpn/ipsec-site-connections',
|
||||
id=ipsecsite_con_id,
|
||||
fmt=self.fmt))
|
||||
|
||||
instance.get_ipsec_site_connection.assert_called_with(
|
||||
mock.ANY, ipsecsite_con_id, fields=mock.ANY
|
||||
)
|
||||
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||
res = self.deserialize(res)
|
||||
self.assertIn('ipsec_site_connection', res)
|
||||
self.assertEqual(res['ipsec_site_connection'], return_value)
|
||||
|
||||
def test_ipsec_site_connection_delete(self):
|
||||
"""Test case to delete a ipsec_site_connection."""
|
||||
self._test_entity_delete('ipsec_site_connection')
|
||||
|
||||
|
||||
class VpnaasExtensionTestCaseXML(VpnaasExtensionTestCase):
|
||||
fmt = 'xml'
|
@ -568,84 +568,96 @@ class NeutronDbPluginV2TestCase(testlib_api.WebTestCase):
|
||||
if not no_delete:
|
||||
self._delete('ports', port['port']['id'])
|
||||
|
||||
def _test_list_with_sort(self, collection, items, sorts, query_params=''):
|
||||
def _test_list_with_sort(self, resource,
|
||||
items, sorts, resources=None, query_params=''):
|
||||
query_str = query_params
|
||||
for key, direction in sorts:
|
||||
query_str = query_str + "&sort_key=%s&sort_dir=%s" % (key,
|
||||
direction)
|
||||
req = self.new_list_request('%ss' % collection,
|
||||
if not resources:
|
||||
resources = '%ss' % resource
|
||||
req = self.new_list_request(resources,
|
||||
params=query_str)
|
||||
api = self._api_for_resource('%ss' % collection)
|
||||
api = self._api_for_resource(resources)
|
||||
res = self.deserialize(self.fmt, req.get_response(api))
|
||||
collection = collection.replace('-', '_')
|
||||
expected_res = [item[collection]['id'] for item in items]
|
||||
self.assertEqual(sorted([n['id'] for n in res["%ss" % collection]]),
|
||||
resource = resource.replace('-', '_')
|
||||
resources = resources.replace('-', '_')
|
||||
expected_res = [item[resource]['id'] for item in items]
|
||||
self.assertEqual(sorted([n['id'] for n in res[resources]]),
|
||||
sorted(expected_res))
|
||||
|
||||
def _test_list_with_pagination(self, collection, items, sort,
|
||||
limit, expected_page_num, query_params='',
|
||||
def _test_list_with_pagination(self, resource, items, sort,
|
||||
limit, expected_page_num,
|
||||
resources=None,
|
||||
query_params='',
|
||||
verify_key='id'):
|
||||
if not resources:
|
||||
resources = '%ss' % resource
|
||||
query_str = query_params + '&' if query_params else ''
|
||||
query_str = query_str + ("limit=%s&sort_key=%s&"
|
||||
"sort_dir=%s") % (limit, sort[0], sort[1])
|
||||
req = self.new_list_request("%ss" % collection, params=query_str)
|
||||
req = self.new_list_request(resources, params=query_str)
|
||||
items_res = []
|
||||
page_num = 0
|
||||
api = self._api_for_resource('%ss' % collection)
|
||||
collection = collection.replace('-', '_')
|
||||
api = self._api_for_resource(resources)
|
||||
resource = resource.replace('-', '_')
|
||||
resources = resources.replace('-', '_')
|
||||
while req:
|
||||
page_num = page_num + 1
|
||||
res = self.deserialize(self.fmt, req.get_response(api))
|
||||
self.assertThat(len(res["%ss" % collection]),
|
||||
self.assertThat(len(res[resources]),
|
||||
matchers.LessThan(limit + 1))
|
||||
items_res = items_res + res["%ss" % collection]
|
||||
items_res = items_res + res[resources]
|
||||
req = None
|
||||
if '%ss_links' % collection in res:
|
||||
for link in res['%ss_links' % collection]:
|
||||
if '%s_links' % resources in res:
|
||||
for link in res['%s_links' % resources]:
|
||||
if link['rel'] == 'next':
|
||||
content_type = 'application/%s' % self.fmt
|
||||
req = testlib_api.create_request(link['href'],
|
||||
'', content_type)
|
||||
self.assertEqual(len(res["%ss" % collection]),
|
||||
self.assertEqual(len(res[resources]),
|
||||
limit)
|
||||
self.assertEqual(page_num, expected_page_num)
|
||||
self.assertEqual(sorted([n[verify_key] for n in items_res]),
|
||||
sorted([item[collection][verify_key]
|
||||
sorted([item[resource][verify_key]
|
||||
for item in items]))
|
||||
|
||||
def _test_list_with_pagination_reverse(self, collection, items, sort,
|
||||
def _test_list_with_pagination_reverse(self, resource, items, sort,
|
||||
limit, expected_page_num,
|
||||
resources=None,
|
||||
query_params=''):
|
||||
resources = '%ss' % collection
|
||||
collection = collection.replace('-', '_')
|
||||
if not resources:
|
||||
resources = '%ss' % resource
|
||||
resource = resource.replace('-', '_')
|
||||
api = self._api_for_resource(resources)
|
||||
marker = items[-1][collection]['id']
|
||||
marker = items[-1][resource]['id']
|
||||
query_str = query_params + '&' if query_params else ''
|
||||
query_str = query_str + ("limit=%s&page_reverse=True&"
|
||||
"sort_key=%s&sort_dir=%s&"
|
||||
"marker=%s") % (limit, sort[0], sort[1],
|
||||
marker)
|
||||
req = self.new_list_request(resources, params=query_str)
|
||||
item_res = [items[-1][collection]]
|
||||
item_res = [items[-1][resource]]
|
||||
page_num = 0
|
||||
resources = resources.replace('-', '_')
|
||||
while req:
|
||||
page_num = page_num + 1
|
||||
res = self.deserialize(self.fmt, req.get_response(api))
|
||||
self.assertThat(len(res["%ss" % collection]),
|
||||
self.assertThat(len(res[resources]),
|
||||
matchers.LessThan(limit + 1))
|
||||
res["%ss" % collection].reverse()
|
||||
item_res = item_res + res["%ss" % collection]
|
||||
res[resources].reverse()
|
||||
item_res = item_res + res[resources]
|
||||
req = None
|
||||
if '%ss_links' % collection in res:
|
||||
for link in res['%ss_links' % collection]:
|
||||
if '%s_links' % resources in res:
|
||||
for link in res['%s_links' % resources]:
|
||||
if link['rel'] == 'previous':
|
||||
content_type = 'application/%s' % self.fmt
|
||||
req = testlib_api.create_request(link['href'],
|
||||
'', content_type)
|
||||
self.assertEqual(len(res["%ss" % collection]),
|
||||
self.assertEqual(len(res[resources]),
|
||||
limit)
|
||||
self.assertEqual(page_num, expected_page_num)
|
||||
expected_res = [item[collection]['id'] for item in items]
|
||||
expected_res = [item[resource]['id'] for item in items]
|
||||
expected_res.reverse()
|
||||
self.assertEqual(sorted([n['id'] for n in item_res]),
|
||||
sorted(expected_res))
|
||||
|
Loading…
Reference in New Issue
Block a user