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
|
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):
|
def _validate_regex(data, valid_values=None):
|
||||||
try:
|
try:
|
||||||
if re.match(valid_values, data):
|
if re.match(valid_values, data):
|
||||||
@ -474,6 +491,7 @@ validators = {'type:dict': _validate_dict,
|
|||||||
'type:regex': _validate_regex,
|
'type:regex': _validate_regex,
|
||||||
'type:string': _validate_string,
|
'type:string': _validate_string,
|
||||||
'type:subnet': _validate_subnet,
|
'type:subnet': _validate_subnet,
|
||||||
|
'type:subnet_list': _validate_subnet_list,
|
||||||
'type:uuid': _validate_uuid,
|
'type:uuid': _validate_uuid,
|
||||||
'type:uuid_or_none': _validate_uuid_or_none,
|
'type:uuid_or_none': _validate_uuid_or_none,
|
||||||
'type:uuid_list': _validate_uuid_list,
|
'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"
|
DUMMY = "DUMMY"
|
||||||
LOADBALANCER = "LOADBALANCER"
|
LOADBALANCER = "LOADBALANCER"
|
||||||
FIREWALL = "FIREWALL"
|
FIREWALL = "FIREWALL"
|
||||||
|
VPN = "VPN"
|
||||||
|
|
||||||
#maps extension alias to service type
|
#maps extension alias to service type
|
||||||
EXT_TO_SERVICE_MAPPING = {
|
EXT_TO_SERVICE_MAPPING = {
|
||||||
'dummy': DUMMY,
|
'dummy': DUMMY,
|
||||||
'lbaas': LOADBALANCER,
|
'lbaas': LOADBALANCER,
|
||||||
'fwaas': FIREWALL
|
'fwaas': FIREWALL,
|
||||||
|
'vpnaas': VPN,
|
||||||
}
|
}
|
||||||
|
|
||||||
# TODO(salvatore-orlando): Move these (or derive them) from conf file
|
# 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 = {
|
COMMON_PREFIXES = {
|
||||||
CORE: "",
|
CORE: "",
|
||||||
DUMMY: "/dummy_svc",
|
DUMMY: "/dummy_svc",
|
||||||
LOADBALANCER: "/lb",
|
LOADBALANCER: "/lb",
|
||||||
FIREWALL: "/fw",
|
FIREWALL: "/fw",
|
||||||
|
VPN: "/vpn",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Service operation status constants
|
# 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:
|
if not no_delete:
|
||||||
self._delete('ports', port['port']['id'])
|
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
|
query_str = query_params
|
||||||
for key, direction in sorts:
|
for key, direction in sorts:
|
||||||
query_str = query_str + "&sort_key=%s&sort_dir=%s" % (key,
|
query_str = query_str + "&sort_key=%s&sort_dir=%s" % (key,
|
||||||
direction)
|
direction)
|
||||||
req = self.new_list_request('%ss' % collection,
|
if not resources:
|
||||||
|
resources = '%ss' % resource
|
||||||
|
req = self.new_list_request(resources,
|
||||||
params=query_str)
|
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))
|
res = self.deserialize(self.fmt, req.get_response(api))
|
||||||
collection = collection.replace('-', '_')
|
resource = resource.replace('-', '_')
|
||||||
expected_res = [item[collection]['id'] for item in items]
|
resources = resources.replace('-', '_')
|
||||||
self.assertEqual(sorted([n['id'] for n in res["%ss" % collection]]),
|
expected_res = [item[resource]['id'] for item in items]
|
||||||
|
self.assertEqual(sorted([n['id'] for n in res[resources]]),
|
||||||
sorted(expected_res))
|
sorted(expected_res))
|
||||||
|
|
||||||
def _test_list_with_pagination(self, collection, items, sort,
|
def _test_list_with_pagination(self, resource, items, sort,
|
||||||
limit, expected_page_num, query_params='',
|
limit, expected_page_num,
|
||||||
|
resources=None,
|
||||||
|
query_params='',
|
||||||
verify_key='id'):
|
verify_key='id'):
|
||||||
|
if not resources:
|
||||||
|
resources = '%ss' % resource
|
||||||
query_str = query_params + '&' if query_params else ''
|
query_str = query_params + '&' if query_params else ''
|
||||||
query_str = query_str + ("limit=%s&sort_key=%s&"
|
query_str = query_str + ("limit=%s&sort_key=%s&"
|
||||||
"sort_dir=%s") % (limit, sort[0], sort[1])
|
"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 = []
|
items_res = []
|
||||||
page_num = 0
|
page_num = 0
|
||||||
api = self._api_for_resource('%ss' % collection)
|
api = self._api_for_resource(resources)
|
||||||
collection = collection.replace('-', '_')
|
resource = resource.replace('-', '_')
|
||||||
|
resources = resources.replace('-', '_')
|
||||||
while req:
|
while req:
|
||||||
page_num = page_num + 1
|
page_num = page_num + 1
|
||||||
res = self.deserialize(self.fmt, req.get_response(api))
|
res = self.deserialize(self.fmt, req.get_response(api))
|
||||||
self.assertThat(len(res["%ss" % collection]),
|
self.assertThat(len(res[resources]),
|
||||||
matchers.LessThan(limit + 1))
|
matchers.LessThan(limit + 1))
|
||||||
items_res = items_res + res["%ss" % collection]
|
items_res = items_res + res[resources]
|
||||||
req = None
|
req = None
|
||||||
if '%ss_links' % collection in res:
|
if '%s_links' % resources in res:
|
||||||
for link in res['%ss_links' % collection]:
|
for link in res['%s_links' % resources]:
|
||||||
if link['rel'] == 'next':
|
if link['rel'] == 'next':
|
||||||
content_type = 'application/%s' % self.fmt
|
content_type = 'application/%s' % self.fmt
|
||||||
req = testlib_api.create_request(link['href'],
|
req = testlib_api.create_request(link['href'],
|
||||||
'', content_type)
|
'', content_type)
|
||||||
self.assertEqual(len(res["%ss" % collection]),
|
self.assertEqual(len(res[resources]),
|
||||||
limit)
|
limit)
|
||||||
self.assertEqual(page_num, expected_page_num)
|
self.assertEqual(page_num, expected_page_num)
|
||||||
self.assertEqual(sorted([n[verify_key] for n in items_res]),
|
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]))
|
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,
|
limit, expected_page_num,
|
||||||
|
resources=None,
|
||||||
query_params=''):
|
query_params=''):
|
||||||
resources = '%ss' % collection
|
if not resources:
|
||||||
collection = collection.replace('-', '_')
|
resources = '%ss' % resource
|
||||||
|
resource = resource.replace('-', '_')
|
||||||
api = self._api_for_resource(resources)
|
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_params + '&' if query_params else ''
|
||||||
query_str = query_str + ("limit=%s&page_reverse=True&"
|
query_str = query_str + ("limit=%s&page_reverse=True&"
|
||||||
"sort_key=%s&sort_dir=%s&"
|
"sort_key=%s&sort_dir=%s&"
|
||||||
"marker=%s") % (limit, sort[0], sort[1],
|
"marker=%s") % (limit, sort[0], sort[1],
|
||||||
marker)
|
marker)
|
||||||
req = self.new_list_request(resources, params=query_str)
|
req = self.new_list_request(resources, params=query_str)
|
||||||
item_res = [items[-1][collection]]
|
item_res = [items[-1][resource]]
|
||||||
page_num = 0
|
page_num = 0
|
||||||
|
resources = resources.replace('-', '_')
|
||||||
while req:
|
while req:
|
||||||
page_num = page_num + 1
|
page_num = page_num + 1
|
||||||
res = self.deserialize(self.fmt, req.get_response(api))
|
res = self.deserialize(self.fmt, req.get_response(api))
|
||||||
self.assertThat(len(res["%ss" % collection]),
|
self.assertThat(len(res[resources]),
|
||||||
matchers.LessThan(limit + 1))
|
matchers.LessThan(limit + 1))
|
||||||
res["%ss" % collection].reverse()
|
res[resources].reverse()
|
||||||
item_res = item_res + res["%ss" % collection]
|
item_res = item_res + res[resources]
|
||||||
req = None
|
req = None
|
||||||
if '%ss_links' % collection in res:
|
if '%s_links' % resources in res:
|
||||||
for link in res['%ss_links' % collection]:
|
for link in res['%s_links' % resources]:
|
||||||
if link['rel'] == 'previous':
|
if link['rel'] == 'previous':
|
||||||
content_type = 'application/%s' % self.fmt
|
content_type = 'application/%s' % self.fmt
|
||||||
req = testlib_api.create_request(link['href'],
|
req = testlib_api.create_request(link['href'],
|
||||||
'', content_type)
|
'', content_type)
|
||||||
self.assertEqual(len(res["%ss" % collection]),
|
self.assertEqual(len(res[resources]),
|
||||||
limit)
|
limit)
|
||||||
self.assertEqual(page_num, expected_page_num)
|
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()
|
expected_res.reverse()
|
||||||
self.assertEqual(sorted([n['id'] for n in item_res]),
|
self.assertEqual(sorted([n['id'] for n in item_res]),
|
||||||
sorted(expected_res))
|
sorted(expected_res))
|
||||||
|
Loading…
Reference in New Issue
Block a user