return msg
+def _validate_subnet_list(data, valid_values=None):
+ if not isinstance(data, list):
+ msg = _("'%s' is not a list") % data
+ LOG.debug(msg)
+ return msg
+
+ if len(set(data)) != len(data):
+ msg = _("Duplicate items in the list: '%s'") % ', '.join(data)
+ LOG.debug(msg)
+ return msg
+
+ for item in data:
+ msg = _validate_subnet(item)
+ if msg:
+ return msg
+
+
def _validate_regex(data, valid_values=None):
try:
if re.match(valid_values, data):
'type:regex': _validate_regex,
'type:string': _validate_string,
'type:subnet': _validate_subnet,
+ 'type:subnet_list': _validate_subnet_list,
'type:uuid': _validate_uuid,
'type:uuid_or_none': _validate_uuid_or_none,
'type:uuid_list': _validate_uuid_list,
--- /dev/null
+# 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')
--- /dev/null
+# 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.
--- /dev/null
+# 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
--- /dev/null
+# 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
DUMMY = "DUMMY"
LOADBALANCER = "LOADBALANCER"
FIREWALL = "FIREWALL"
+VPN = "VPN"
#maps extension alias to service type
EXT_TO_SERVICE_MAPPING = {
'dummy': DUMMY,
'lbaas': LOADBALANCER,
- 'fwaas': FIREWALL
+ 'fwaas': FIREWALL,
+ 'vpnaas': VPN,
}
# TODO(salvatore-orlando): Move these (or derive them) from conf file
-ALLOWED_SERVICES = [CORE, DUMMY, LOADBALANCER, FIREWALL]
+ALLOWED_SERVICES = [CORE, DUMMY, LOADBALANCER, FIREWALL, VPN]
COMMON_PREFIXES = {
CORE: "",
DUMMY: "/dummy_svc",
LOADBALANCER: "/lb",
FIREWALL: "/fw",
+ VPN: "/vpn",
}
# Service operation status constants
--- /dev/null
+# 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
--- /dev/null
+
+# 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"]
--- /dev/null
+# 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.
--- /dev/null
+# 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 contextlib
+import os
+
+import webob.exc
+
+from neutron.api.extensions import ExtensionMiddleware
+from neutron.api.extensions import PluginAwareExtensionManager
+from neutron.common import config
+from neutron import context
+from neutron.db import agentschedulers_db
+from neutron.db.vpn import vpn_db
+from neutron import extensions
+from neutron.extensions import vpnaas
+from neutron import manager
+from neutron.plugins.common import constants
+from neutron.scheduler import l3_agent_scheduler
+from neutron.services.vpn import plugin as vpn_plugin
+from neutron.tests.unit import test_db_plugin
+from neutron.tests.unit import test_l3_plugin
+
+DB_CORE_PLUGIN_KLASS = 'neutron.db.db_base_plugin_v2.NeutronDbPluginV2'
+DB_VPN_PLUGIN_KLASS = "neutron.services.vpn.plugin.VPNPlugin"
+ROOTDIR = os.path.normpath(os.path.join(
+ os.path.dirname(__file__),
+ '..', '..', '..', '..'))
+
+extensions_path = ':'.join(extensions.__path__)
+
+
+class TestVpnCorePlugin(test_l3_plugin.TestL3NatPlugin,
+ agentschedulers_db.L3AgentSchedulerDbMixin,
+ agentschedulers_db.DhcpAgentSchedulerDbMixin):
+ def __init__(self, configfile=None):
+ super(TestVpnCorePlugin, self).__init__()
+ self.router_scheduler = l3_agent_scheduler.ChanceScheduler()
+
+
+class VPNPluginDbTestCase(test_l3_plugin.L3NatTestCaseMixin,
+ test_db_plugin.NeutronDbPluginV2TestCase):
+ resource_prefix_map = dict(
+ (k.replace('_', '-'),
+ constants.COMMON_PREFIXES[constants.VPN])
+ for k in vpnaas.RESOURCE_ATTRIBUTE_MAP
+ )
+
+ def setUp(self, core_plugin=None, vpnaas_plugin=DB_VPN_PLUGIN_KLASS):
+ service_plugins = {'vpnaas_plugin': vpnaas_plugin}
+ plugin_str = ('neutron.tests.unit.db.vpn.'
+ 'test_db_vpnaas.TestVpnCorePlugin')
+
+ super(VPNPluginDbTestCase, self).setUp(
+ plugin_str,
+ service_plugins=service_plugins
+ )
+ self._subnet_id = "0c798ed8-33ba-11e2-8b28-000c291c4d14"
+ self.core_plugin = TestVpnCorePlugin
+ self.plugin = vpn_plugin.VPNPlugin()
+ ext_mgr = PluginAwareExtensionManager(
+ extensions_path,
+ {constants.CORE: self.core_plugin,
+ constants.VPN: self.plugin}
+ )
+ app = config.load_paste_app('extensions_test_app')
+ self.ext_api = ExtensionMiddleware(app, ext_mgr=ext_mgr)
+
+ def _create_ikepolicy(self, fmt,
+ name='ikepolicy1',
+ auth_algorithm='sha1',
+ encryption_algorithm='aes-128',
+ phase1_negotiation_mode='main',
+ lifetime_units='seconds',
+ lifetime_value=3600,
+ ike_version='v1',
+ pfs='group5',
+ expected_res_status=None, **kwargs):
+
+ data = {'ikepolicy': {
+ 'name': name,
+ 'auth_algorithm': auth_algorithm,
+ 'encryption_algorithm': encryption_algorithm,
+ 'phase1_negotiation_mode': phase1_negotiation_mode,
+ 'lifetime': {
+ 'units': lifetime_units,
+ 'value': lifetime_value},
+ 'ike_version': ike_version,
+ 'pfs': pfs,
+ 'tenant_id': self._tenant_id
+ }}
+ for arg in ['description']:
+ if arg in kwargs and kwargs[arg] is not None:
+ data['ikepolicy'][arg] = kwargs[arg]
+
+ ikepolicy_req = self.new_create_request('ikepolicies', data, fmt)
+ ikepolicy_res = ikepolicy_req.get_response(self.ext_api)
+ if expected_res_status:
+ self.assertEqual(ikepolicy_res.status_int, expected_res_status)
+
+ return ikepolicy_res
+
+ @contextlib.contextmanager
+ def ikepolicy(self, fmt=None,
+ name='ikepolicy1',
+ auth_algorithm='sha1',
+ encryption_algorithm='aes-128',
+ phase1_negotiation_mode='main',
+ lifetime_units='seconds',
+ lifetime_value=3600,
+ ike_version='v1',
+ pfs='group5',
+ no_delete=False,
+ **kwargs):
+ if not fmt:
+ fmt = self.fmt
+ res = self._create_ikepolicy(fmt,
+ name,
+ auth_algorithm,
+ encryption_algorithm,
+ phase1_negotiation_mode,
+ lifetime_units,
+ lifetime_value,
+ ike_version,
+ pfs,
+ **kwargs)
+ if res.status_int >= 400:
+ raise webob.exc.HTTPClientError(code=res.status_int)
+ try:
+ ikepolicy = self.deserialize(fmt or self.fmt, res)
+ yield ikepolicy
+ finally:
+ if not no_delete:
+ self._delete('ikepolicies', ikepolicy['ikepolicy']['id'])
+
+ def _create_ipsecpolicy(self, fmt,
+ name='ipsecpolicy1',
+ auth_algorithm='sha1',
+ encryption_algorithm='aes-128',
+ encapsulation_mode='tunnel',
+ transform_protocol='esp',
+ lifetime_units='seconds',
+ lifetime_value=3600,
+ pfs='group5',
+ expected_res_status=None,
+ **kwargs):
+
+ data = {'ipsecpolicy': {'name': name,
+ 'auth_algorithm': auth_algorithm,
+ 'encryption_algorithm': encryption_algorithm,
+ 'encapsulation_mode': encapsulation_mode,
+ 'transform_protocol': transform_protocol,
+ 'lifetime': {'units': lifetime_units,
+ 'value': lifetime_value},
+ 'pfs': pfs,
+ 'tenant_id': self._tenant_id}}
+ for arg in ['description']:
+ if arg in kwargs and kwargs[arg] is not None:
+ data['ipsecpolicy'][arg] = kwargs[arg]
+ ipsecpolicy_req = self.new_create_request('ipsecpolicies', data, fmt)
+ ipsecpolicy_res = ipsecpolicy_req.get_response(self.ext_api)
+ if expected_res_status:
+ self.assertEqual(ipsecpolicy_res.status_int, expected_res_status)
+
+ return ipsecpolicy_res
+
+ @contextlib.contextmanager
+ def ipsecpolicy(self, fmt=None,
+ name='ipsecpolicy1',
+ auth_algorithm='sha1',
+ encryption_algorithm='aes-128',
+ encapsulation_mode='tunnel',
+ transform_protocol='esp',
+ lifetime_units='seconds',
+ lifetime_value=3600,
+ pfs='group5',
+ no_delete=False, **kwargs):
+ if not fmt:
+ fmt = self.fmt
+ res = self._create_ipsecpolicy(fmt,
+ name,
+ auth_algorithm,
+ encryption_algorithm,
+ encapsulation_mode,
+ transform_protocol,
+ lifetime_units,
+ lifetime_value,
+ pfs,
+ **kwargs)
+ if res.status_int >= 400:
+ raise webob.exc.HTTPClientError(code=res.status_int)
+ try:
+ ipsecpolicy = self.deserialize(fmt or self.fmt, res)
+ yield ipsecpolicy
+ finally:
+ if not no_delete:
+ self._delete('ipsecpolicies', ipsecpolicy['ipsecpolicy']['id'])
+
+ def _create_vpnservice(self, fmt, name,
+ admin_state_up,
+ router_id, subnet_id,
+ expected_res_status=None, **kwargs):
+ data = {'vpnservice': {'name': name,
+ 'subnet_id': subnet_id,
+ 'router_id': router_id,
+ 'admin_state_up': admin_state_up,
+ 'tenant_id': self._tenant_id}}
+ for arg in ['description']:
+ if arg in kwargs and kwargs[arg] is not None:
+ data['vpnservice'][arg] = kwargs[arg]
+ vpnservice_req = self.new_create_request('vpnservices', data, fmt)
+ vpnservice_res = vpnservice_req.get_response(self.ext_api)
+ if expected_res_status:
+ self.assertEqual(vpnservice_res.status_int, expected_res_status)
+ return vpnservice_res
+
+ @contextlib.contextmanager
+ def vpnservice(self, fmt=None, name='vpnservice1',
+ subnet=None,
+ router=None,
+ admin_state_up=True,
+ no_delete=False, **kwargs):
+ if not fmt:
+ fmt = self.fmt
+ with test_db_plugin.optional_ctx(subnet, self.subnet) as tmp_subnet:
+ with test_db_plugin.optional_ctx(router,
+ self.router) as tmp_router:
+ res = self._create_vpnservice(fmt,
+ name,
+ admin_state_up,
+ router_id=(tmp_router['router']
+ ['id']),
+ subnet_id=(tmp_subnet['subnet']
+ ['id']),
+ **kwargs)
+ if res.status_int >= 400:
+ raise webob.exc.HTTPClientError(code=res.status_int)
+ try:
+ vpnservice = self.deserialize(fmt or self.fmt, res)
+ yield vpnservice
+ finally:
+ if not no_delete:
+ self._delete('vpnservices',
+ vpnservice['vpnservice']['id'])
+
+ def _create_ipsec_site_connection(self, fmt, name='test',
+ peer_address='192.168.1.10',
+ peer_id='192.168.1.10',
+ peer_cidrs=None,
+ mtu=1500,
+ psk='abcdefg',
+ initiator='bi-directional',
+ dpd_action='hold',
+ dpd_interval=30,
+ dpd_timeout=120,
+ vpnservice_id='fake_id',
+ ikepolicy_id='fake_id',
+ ipsecpolicy_id='fake_id',
+ admin_state_up=True,
+ expected_res_status=None, **kwargs):
+ data = {
+ 'ipsec_site_connection': {'name': name,
+ 'peer_address': peer_address,
+ 'peer_id': peer_id,
+ 'peer_cidrs': peer_cidrs,
+ 'mtu': mtu,
+ 'psk': psk,
+ 'initiator': initiator,
+ 'dpd': {
+ 'action': dpd_action,
+ 'interval': dpd_interval,
+ 'timeout': dpd_timeout,
+ },
+ 'vpnservice_id': vpnservice_id,
+ 'ikepolicy_id': ikepolicy_id,
+ 'ipsecpolicy_id': ipsecpolicy_id,
+ 'admin_state_up': admin_state_up,
+ 'tenant_id': self._tenant_id}
+ }
+ for arg in ['description']:
+ if arg in kwargs and kwargs[arg] is not None:
+ data['ipsec_site_connection'][arg] = kwargs[arg]
+
+ ipsec_site_connection_req = self.new_create_request(
+ 'ipsec-site-connections', data, fmt
+ )
+ ipsec_site_connection_res = ipsec_site_connection_req.get_response(
+ self.ext_api
+ )
+ if expected_res_status:
+ self.assertEqual(
+ ipsec_site_connection_res.status_int, expected_res_status
+ )
+
+ return ipsec_site_connection_res
+
+ @contextlib.contextmanager
+ def ipsec_site_connection(self, fmt=None, name='ipsec_site_connection1',
+ peer_address='192.168.1.10',
+ peer_id='192.168.1.10',
+ peer_cidrs=None,
+ mtu=1500,
+ psk='abcdefg',
+ initiator='bi-directional',
+ dpd_action='hold',
+ dpd_interval=30,
+ dpd_timeout=120,
+ vpnservice=None,
+ ikepolicy=None,
+ ipsecpolicy=None,
+ admin_state_up=True, no_delete=False,
+ **kwargs):
+ if not fmt:
+ fmt = self.fmt
+ with contextlib.nested(
+ test_db_plugin.optional_ctx(vpnservice,
+ self.vpnservice),
+ test_db_plugin.optional_ctx(ikepolicy,
+ self.ikepolicy),
+ test_db_plugin.optional_ctx(ipsecpolicy,
+ self.ipsecpolicy)
+ ) as (tmp_vpnservice, tmp_ikepolicy, tmp_ipsecpolicy):
+ vpnservice_id = tmp_vpnservice['vpnservice']['id']
+ ikepolicy_id = tmp_ikepolicy['ikepolicy']['id']
+ ipsecpolicy_id = tmp_ipsecpolicy['ipsecpolicy']['id']
+ res = self._create_ipsec_site_connection(fmt,
+ name,
+ peer_address,
+ peer_id,
+ peer_cidrs,
+ mtu,
+ psk,
+ initiator,
+ dpd_action,
+ dpd_interval,
+ dpd_timeout,
+ vpnservice_id,
+ ikepolicy_id,
+ ipsecpolicy_id,
+ admin_state_up,
+ **kwargs)
+ if res.status_int >= 400:
+ raise webob.exc.HTTPClientError(code=res.status_int)
+ try:
+ ipsec_site_connection = self.deserialize(
+ fmt or self.fmt, res
+ )
+ yield ipsec_site_connection
+ finally:
+ if not no_delete:
+ self._delete(
+ 'ipsec-site-connections',
+ ipsec_site_connection[
+ 'ipsec_site_connection']['id']
+ )
+
+
+class TestVpnaas(VPNPluginDbTestCase):
+
+ def _check_policy(self, policy, keys, lifetime):
+ for k, v in keys:
+ self.assertEqual(policy[k], v)
+ for k, v in lifetime.iteritems():
+ self.assertEqual(policy['lifetime'][k], v)
+
+ def test_create_ikepolicy(self):
+ """Test case to create an ikepolicy."""
+ name = "ikepolicy1"
+ description = 'ipsec-ikepolicy'
+ keys = [('name', name),
+ ('description', 'ipsec-ikepolicy'),
+ ('auth_algorithm', 'sha1'),
+ ('encryption_algorithm', 'aes-128'),
+ ('phase1_negotiation_mode', 'main'),
+ ('ike_version', 'v1'),
+ ('pfs', 'group5'),
+ ('tenant_id', self._tenant_id)]
+ lifetime = {
+ 'units': 'seconds',
+ 'value': 3600}
+ with self.ikepolicy(name=name, description=description) as ikepolicy:
+ self._check_policy(ikepolicy['ikepolicy'], keys, lifetime)
+
+ def test_delete_ikepolicy(self):
+ """Test case to delete an ikepolicy."""
+ with self.ikepolicy(no_delete=True) as ikepolicy:
+ req = self.new_delete_request('ikepolicies',
+ ikepolicy['ikepolicy']['id'])
+ res = req.get_response(self.ext_api)
+ self.assertEqual(res.status_int, 204)
+
+ def test_show_ikepolicy(self):
+ """Test case to show or get an ikepolicy."""
+ name = "ikepolicy1"
+ description = 'ipsec-ikepolicy'
+ keys = [('name', name),
+ ('auth_algorithm', 'sha1'),
+ ('encryption_algorithm', 'aes-128'),
+ ('phase1_negotiation_mode', 'main'),
+ ('ike_version', 'v1'),
+ ('pfs', 'group5'),
+ ('tenant_id', self._tenant_id)]
+ lifetime = {
+ 'units': 'seconds',
+ 'value': 3600}
+ with self.ikepolicy(name=name, description=description) as ikepolicy:
+ req = self.new_show_request('ikepolicies',
+ ikepolicy['ikepolicy']['id'],
+ fmt=self.fmt)
+ res = self.deserialize(self.fmt, req.get_response(self.ext_api))
+ self._check_policy(res['ikepolicy'], keys, lifetime)
+
+ def test_list_ikepolicies(self):
+ """Test case to list all ikepolicies."""
+ name = "ikepolicy_list"
+ keys = [('name', name),
+ ('auth_algorithm', 'sha1'),
+ ('encryption_algorithm', 'aes-128'),
+ ('phase1_negotiation_mode', 'main'),
+ ('ike_version', 'v1'),
+ ('pfs', 'group5'),
+ ('tenant_id', self._tenant_id)]
+ lifetime = {
+ 'units': 'seconds',
+ 'value': 3600}
+ with self.ikepolicy(name=name) as ikepolicy:
+ keys.append(('id', ikepolicy['ikepolicy']['id']))
+ req = self.new_list_request('ikepolicies')
+ res = self.deserialize(self.fmt, req.get_response(self.ext_api))
+ self.assertEqual(len(res), 1)
+ for k, v in keys:
+ self.assertEqual(res['ikepolicies'][0][k], v)
+ for k, v in lifetime.iteritems():
+ self.assertEqual(res['ikepolicies'][0]['lifetime'][k], v)
+
+ def test_list_ikepolicies_with_sort_emulated(self):
+ """Test case to list all ikepolicies."""
+ with contextlib.nested(self.ikepolicy(name='ikepolicy1'),
+ self.ikepolicy(name='ikepolicy2'),
+ self.ikepolicy(name='ikepolicy3')
+ ) as (ikepolicy1, ikepolicy2, ikepolicy3):
+ self._test_list_with_sort('ikepolicy', (ikepolicy3,
+ ikepolicy2,
+ ikepolicy1),
+ [('name', 'desc')],
+ 'ikepolicies')
+
+ def test_list_ikepolicies_with_pagination_emulated(self):
+ """Test case to list all ikepolicies with pagination."""
+ with contextlib.nested(self.ikepolicy(name='ikepolicy1'),
+ self.ikepolicy(name='ikepolicy2'),
+ self.ikepolicy(name='ikepolicy3')
+ ) as (ikepolicy1, ikepolicy2, ikepolicy3):
+ self._test_list_with_pagination('ikepolicy',
+ (ikepolicy1,
+ ikepolicy2,
+ ikepolicy3),
+ ('name', 'asc'), 2, 2,
+ 'ikepolicies')
+
+ def test_list_ikepolicies_with_pagination_reverse_emulated(self):
+ """Test case to list all ikepolicies with reverse pagination."""
+ with contextlib.nested(self.ikepolicy(name='ikepolicy1'),
+ self.ikepolicy(name='ikepolicy2'),
+ self.ikepolicy(name='ikepolicy3')
+ ) as (ikepolicy1, ikepolicy2, ikepolicy3):
+ self._test_list_with_pagination_reverse('ikepolicy',
+ (ikepolicy1,
+ ikepolicy2,
+ ikepolicy3),
+ ('name', 'asc'), 2, 2,
+ 'ikepolicies')
+
+ def test_update_ikepolicy(self):
+ """Test case to update an ikepolicy."""
+ name = "new_ikepolicy1"
+ keys = [('name', name),
+ ('auth_algorithm', 'sha1'),
+ ('encryption_algorithm', 'aes-128'),
+ ('phase1_negotiation_mode', 'main'),
+ ('ike_version', 'v1'),
+ ('pfs', 'group5'),
+ ('tenant_id', self._tenant_id)]
+ with self.ikepolicy(name=name) as ikepolicy:
+ data = {'ikepolicy': {'name': name}}
+ req = self.new_update_request("ikepolicies",
+ data,
+ ikepolicy['ikepolicy']['id'])
+ res = self.deserialize(self.fmt, req.get_response(self.ext_api))
+ for k, v in keys:
+ self.assertEqual(res['ikepolicy'][k], v)
+
+ def test_create_ikepolicy_with_invalid_values(self):
+ """Test case to test invalid values."""
+ name = 'ikepolicy1'
+ self._create_ikepolicy(name=name,
+ fmt=self.fmt,
+ auth_algorithm='md5',
+ expected_res_status=400)
+ self._create_ikepolicy(name=name,
+ fmt=self.fmt,
+ auth_algorithm=200,
+ expected_res_status=400)
+ self._create_ikepolicy(name=name,
+ fmt=self.fmt,
+ encryption_algorithm='des',
+ expected_res_status=400)
+ self._create_ikepolicy(name=name,
+ fmt=self.fmt,
+ encryption_algorithm=100,
+ expected_res_status=400)
+ self._create_ikepolicy(name=name,
+ fmt=self.fmt,
+ phase1_negotiation_mode='aggressive',
+ expected_res_status=400)
+ self._create_ikepolicy(name=name,
+ fmt=self.fmt,
+ phase1_negotiation_mode=-100,
+ expected_res_status=400)
+ self._create_ikepolicy(name=name,
+ fmt=self.fmt,
+ ike_version='v6',
+ expected_res_status=400)
+ self._create_ikepolicy(name=name,
+ fmt=self.fmt,
+ ike_version=500,
+ expected_res_status=400)
+ self._create_ikepolicy(name=name,
+ fmt=self.fmt,
+ pfs='group1',
+ expected_res_status=400)
+ self._create_ikepolicy(name=name,
+ fmt=self.fmt,
+ pfs=120,
+ expected_res_status=400)
+ self._create_ikepolicy(name=name,
+ fmt=self.fmt,
+ lifetime_units='Megabytes',
+ expected_res_status=400)
+ self._create_ikepolicy(name=name,
+ fmt=self.fmt,
+ lifetime_units=20000,
+ expected_res_status=400)
+ self._create_ikepolicy(name=name,
+ fmt=self.fmt,
+ lifetime_value=-20,
+ expected_res_status=400)
+ self._create_ikepolicy(name=name,
+ fmt=self.fmt,
+ lifetime_value='Megabytes',
+ expected_res_status=400)
+
+ def test_create_ipsecpolicy(self):
+ """Test case to create an ipsecpolicy."""
+ name = "ipsecpolicy1"
+ description = 'my-ipsecpolicy'
+ keys = [('name', name),
+ ('description', 'my-ipsecpolicy'),
+ ('auth_algorithm', 'sha1'),
+ ('encryption_algorithm', 'aes-128'),
+ ('encapsulation_mode', 'tunnel'),
+ ('transform_protocol', 'esp'),
+ ('pfs', 'group5'),
+ ('tenant_id', self._tenant_id)]
+ lifetime = {
+ 'units': 'seconds',
+ 'value': 3600}
+ with self.ipsecpolicy(name=name,
+ description=description) as ipsecpolicy:
+ self._check_policy(ipsecpolicy['ipsecpolicy'], keys, lifetime)
+
+ def test_delete_ipsecpolicy(self):
+ """Test case to delete an ipsecpolicy."""
+ with self.ipsecpolicy(no_delete=True) as ipsecpolicy:
+ req = self.new_delete_request('ipsecpolicies',
+ ipsecpolicy['ipsecpolicy']['id'])
+ res = req.get_response(self.ext_api)
+ self.assertEqual(res.status_int, 204)
+
+ def test_show_ipsecpolicy(self):
+ """Test case to show or get an ipsecpolicy."""
+ name = "ipsecpolicy1"
+ keys = [('name', name),
+ ('auth_algorithm', 'sha1'),
+ ('encryption_algorithm', 'aes-128'),
+ ('encapsulation_mode', 'tunnel'),
+ ('transform_protocol', 'esp'),
+ ('pfs', 'group5'),
+ ('tenant_id', self._tenant_id)]
+ lifetime = {
+ 'units': 'seconds',
+ 'value': 3600}
+ with self.ipsecpolicy(name=name) as ipsecpolicy:
+ req = self.new_show_request('ipsecpolicies',
+ ipsecpolicy['ipsecpolicy']['id'],
+ fmt=self.fmt)
+ res = self.deserialize(self.fmt, req.get_response(self.ext_api))
+ self._check_policy(res['ipsecpolicy'], keys, lifetime)
+
+ def test_list_ipsecpolicies(self):
+ """Test case to list all ipsecpolicies."""
+ name = "ipsecpolicy_list"
+ keys = [('name', name),
+ ('auth_algorithm', 'sha1'),
+ ('encryption_algorithm', 'aes-128'),
+ ('encapsulation_mode', 'tunnel'),
+ ('transform_protocol', 'esp'),
+ ('pfs', 'group5'),
+ ('tenant_id', self._tenant_id)]
+ lifetime = {
+ 'units': 'seconds',
+ 'value': 3600}
+ with self.ipsecpolicy(name=name) as ipsecpolicy:
+ keys.append(('id', ipsecpolicy['ipsecpolicy']['id']))
+ req = self.new_list_request('ipsecpolicies')
+ res = self.deserialize(self.fmt, req.get_response(self.ext_api))
+ self.assertEqual(len(res), 1)
+ self._check_policy(res['ipsecpolicies'][0], keys, lifetime)
+
+ def test_list_ipsecpolicies_with_sort_emulated(self):
+ """Test case to list all ipsecpolicies."""
+ with contextlib.nested(self.ipsecpolicy(name='ipsecpolicy1'),
+ self.ipsecpolicy(name='ipsecpolicy2'),
+ self.ipsecpolicy(name='ipsecpolicy3')
+ ) as(ipsecpolicy1, ipsecpolicy2, ipsecpolicy3):
+ self._test_list_with_sort('ipsecpolicy', (ipsecpolicy3,
+ ipsecpolicy2,
+ ipsecpolicy1),
+ [('name', 'desc')],
+ 'ipsecpolicies')
+
+ def test_list_ipsecpolicies_with_pagination_emulated(self):
+ """Test case to list all ipsecpolicies with pagination."""
+ with contextlib.nested(self.ipsecpolicy(name='ipsecpolicy1'),
+ self.ipsecpolicy(name='ipsecpolicy2'),
+ self.ipsecpolicy(name='ipsecpolicy3')
+ ) as(ipsecpolicy1, ipsecpolicy2, ipsecpolicy3):
+ self._test_list_with_pagination('ipsecpolicy',
+ (ipsecpolicy1,
+ ipsecpolicy2,
+ ipsecpolicy3),
+ ('name', 'asc'), 2, 2,
+ 'ipsecpolicies')
+
+ def test_list_ipsecpolicies_with_pagination_reverse_emulated(self):
+ """Test case to list all ipsecpolicies with reverse pagination."""
+ with contextlib.nested(self.ipsecpolicy(name='ipsecpolicy1'),
+ self.ipsecpolicy(name='ipsecpolicy2'),
+ self.ipsecpolicy(name='ipsecpolicy3')
+ ) as(ipsecpolicy1, ipsecpolicy2, ipsecpolicy3):
+ self._test_list_with_pagination_reverse('ipsecpolicy',
+ (ipsecpolicy1,
+ ipsecpolicy2,
+ ipsecpolicy3),
+ ('name', 'asc'), 2, 2,
+ 'ipsecpolicies')
+
+ def test_update_ipsecpolicy(self):
+ """Test case to update an ipsecpolicy."""
+ name = "new_ipsecpolicy1"
+ keys = [('name', name),
+ ('auth_algorithm', 'sha1'),
+ ('encryption_algorithm', 'aes-128'),
+ ('encapsulation_mode', 'tunnel'),
+ ('transform_protocol', 'esp'),
+ ('pfs', 'group5'),
+ ('tenant_id', self._tenant_id)]
+ with self.ipsecpolicy(name=name) as ipsecpolicy:
+ data = {'ipsecpolicy': {'name': name}}
+ req = self.new_update_request("ipsecpolicies",
+ data,
+ ipsecpolicy['ipsecpolicy']['id'])
+ res = self.deserialize(self.fmt, req.get_response(self.ext_api))
+ for k, v in keys:
+ self.assertEqual(res['ipsecpolicy'][k], v)
+
+ def test_create_ipsecpolicy_with_invalid_values(self):
+ """Test case to test invalid values."""
+ name = 'ipsecpolicy1'
+
+ self._create_ipsecpolicy(
+ fmt=self.fmt,
+ name=name, auth_algorithm='md5', expected_res_status=400)
+ self._create_ipsecpolicy(
+ fmt=self.fmt,
+ name=name, auth_algorithm=100, expected_res_status=400)
+
+ self._create_ipsecpolicy(
+ fmt=self.fmt,
+ name=name, encryption_algorithm='des', expected_res_status=400)
+ self._create_ipsecpolicy(
+ fmt=self.fmt,
+ name=name, encryption_algorithm=200, expected_res_status=400)
+
+ self._create_ipsecpolicy(
+ fmt=self.fmt,
+ name=name, transform_protocol='abcd', expected_res_status=400)
+ self._create_ipsecpolicy(
+ fmt=self.fmt,
+ name=name, transform_protocol=500, expected_res_status=400)
+
+ self._create_ipsecpolicy(
+ fmt=self.fmt,
+ name=name,
+ encapsulation_mode='unsupported', expected_res_status=400)
+ self._create_ipsecpolicy(name=name,
+ fmt=self.fmt,
+ encapsulation_mode=100,
+ expected_res_status=400)
+
+ self._create_ipsecpolicy(name=name,
+ fmt=self.fmt,
+ pfs='group9', expected_res_status=400)
+ self._create_ipsecpolicy(
+ fmt=self.fmt, name=name, pfs=-1, expected_res_status=400)
+
+ self._create_ipsecpolicy(
+ fmt=self.fmt, name=name, lifetime_units='minutes',
+ expected_res_status=400)
+
+ self._create_ipsecpolicy(fmt=self.fmt, name=name, lifetime_units=100,
+ expected_res_status=400)
+
+ self._create_ipsecpolicy(fmt=self.fmt, name=name,
+ lifetime_value=-800, expected_res_status=400)
+ self._create_ipsecpolicy(fmt=self.fmt, name=name,
+ lifetime_value='Megabytes',
+ expected_res_status=400)
+
+ def test_create_vpnservice(self, **extras):
+ """Test case to create a vpnservice."""
+ description = 'my-vpn-service'
+ expected = {'name': 'vpnservice1',
+ 'description': 'my-vpn-service',
+ 'admin_state_up': True,
+ 'status': 'PENDING_CREATE',
+ 'tenant_id': self._tenant_id, }
+
+ expected.update(extras)
+ with self.subnet(cidr='10.2.0.0/24') as subnet:
+ with self.router() as router:
+ expected['router_id'] = router['router']['id']
+ expected['subnet_id'] = subnet['subnet']['id']
+ name = expected['name']
+ with self.vpnservice(name=name,
+ subnet=subnet,
+ router=router,
+ description=description,
+ **extras) as vpnservice:
+ self.assertEqual(dict((k, v) for k, v in
+ vpnservice['vpnservice'].items()
+ if k in expected),
+ expected)
+ return vpnservice
+
+ def _set_active(self, model, resource_id):
+ service_plugin = manager.NeutronManager.get_service_plugins()[
+ constants.VPN]
+ adminContext = context.get_admin_context()
+ with adminContext.session.begin(subtransactions=True):
+ resource_db = service_plugin._get_resource(
+ adminContext,
+ model,
+ resource_id)
+ resource_db.status = constants.ACTIVE
+
+ def test_update_vpnservice(self):
+ """Test case to update a vpnservice."""
+ name = 'new_vpnservice1'
+ keys = [('name', name)]
+ with contextlib.nested(
+ self.subnet(cidr='10.2.0.0/24'),
+ self.router()) as (subnet, router):
+ with self.vpnservice(name=name,
+ subnet=subnet,
+ router=router) as vpnservice:
+ keys.append(('subnet_id',
+ vpnservice['vpnservice']['subnet_id']))
+ keys.append(('router_id',
+ vpnservice['vpnservice']['router_id']))
+ data = {'vpnservice': {'name': name}}
+ self._set_active(vpn_db.VPNService,
+ vpnservice['vpnservice']['id'])
+ req = self.new_update_request(
+ 'vpnservices',
+ data,
+ vpnservice['vpnservice']['id'])
+ res = self.deserialize(self.fmt,
+ req.get_response(self.ext_api))
+ for k, v in keys:
+ self.assertEqual(res['vpnservice'][k], v)
+
+ def test_update_vpnservice_with_invalid_state(self):
+ """Test case to update a vpnservice in invalid state ."""
+ name = 'new_vpnservice1'
+ keys = [('name', name)]
+ with contextlib.nested(
+ self.subnet(cidr='10.2.0.0/24'),
+ self.router()) as (subnet, router):
+ with self.vpnservice(name=name,
+ subnet=subnet,
+ router=router) as vpnservice:
+ keys.append(('subnet_id',
+ vpnservice['vpnservice']['subnet_id']))
+ keys.append(('router_id',
+ vpnservice['vpnservice']['router_id']))
+ data = {'vpnservice': {'name': name}}
+ req = self.new_update_request(
+ 'vpnservices',
+ data,
+ vpnservice['vpnservice']['id'])
+ res = req.get_response(self.ext_api)
+ self.assertEqual(400, res.status_int)
+
+ def test_delete_vpnservice(self):
+ """Test case to delete a vpnservice."""
+ with self.vpnservice(name='vpnserver',
+ no_delete=True) as vpnservice:
+ req = self.new_delete_request('vpnservices',
+ vpnservice['vpnservice']['id'])
+ res = req.get_response(self.ext_api)
+ self.assertEqual(res.status_int, 204)
+
+ def test_show_vpnservice(self):
+ """Test case to show or get a vpnservice."""
+ name = "vpnservice1"
+ keys = [('name', name),
+ ('description', ''),
+ ('admin_state_up', True),
+ ('status', 'PENDING_CREATE')]
+ with self.vpnservice(name=name) as vpnservice:
+ req = self.new_show_request('vpnservices',
+ vpnservice['vpnservice']['id'])
+ res = self.deserialize(self.fmt, req.get_response(self.ext_api))
+ for k, v in keys:
+ self.assertEqual(res['vpnservice'][k], v)
+
+ def test_list_vpnservices(self):
+ """Test case to list all vpnservices."""
+ name = "vpnservice_list"
+ keys = [('name', name),
+ ('description', ''),
+ ('admin_state_up', True),
+ ('status', 'PENDING_CREATE')]
+ with self.vpnservice(name=name) as vpnservice:
+ keys.append(('subnet_id', vpnservice['vpnservice']['subnet_id']))
+ keys.append(('router_id', vpnservice['vpnservice']['router_id']))
+ req = self.new_list_request('vpnservices')
+ res = self.deserialize(self.fmt, req.get_response(self.ext_api))
+ self.assertEqual(len(res), 1)
+ for k, v in keys:
+ self.assertEqual(res['vpnservices'][0][k], v)
+
+ def test_list_vpnservices_with_sort_emulated(self):
+ """Test case to list all vpnservices with sorting."""
+ with self.subnet() as subnet:
+ with self.router() as router:
+ with contextlib.nested(
+ self.vpnservice(name='vpnservice1',
+ subnet=subnet,
+ router=router),
+ self.vpnservice(name='vpnservice2',
+ subnet=subnet,
+ router=router),
+ self.vpnservice(name='vpnservice3',
+ subnet=subnet,
+ router=router)
+ ) as(vpnservice1, vpnservice2, vpnservice3):
+ self._test_list_with_sort('vpnservice', (vpnservice3,
+ vpnservice2,
+ vpnservice1),
+ [('name', 'desc')])
+
+ def test_list_vpnservice_with_pagination_emulated(self):
+ """Test case to list all vpnservices with pagination."""
+ with self.subnet() as subnet:
+ with self.router() as router:
+ with contextlib.nested(
+ self.vpnservice(name='vpnservice1',
+ subnet=subnet,
+ router=router),
+ self.vpnservice(name='vpnservice2',
+ subnet=subnet,
+ router=router),
+ self.vpnservice(name='vpnservice3',
+ subnet=subnet,
+ router=router)
+ ) as(vpnservice1, vpnservice2, vpnservice3):
+ self._test_list_with_pagination('vpnservice',
+ (vpnservice1,
+ vpnservice2,
+ vpnservice3),
+ ('name', 'asc'), 2, 2)
+
+ def test_list_vpnservice_with_pagination_reverse_emulated(self):
+ """Test case to list all vpnservices with reverse pagination."""
+ with self.subnet() as subnet:
+ with self.router() as router:
+ with contextlib.nested(
+ self.vpnservice(name='vpnservice1',
+ subnet=subnet,
+ router=router),
+ self.vpnservice(name='vpnservice2',
+ subnet=subnet,
+ router=router),
+ self.vpnservice(name='vpnservice3',
+ subnet=subnet,
+ router=router)
+ ) as(vpnservice1, vpnservice2, vpnservice3):
+ self._test_list_with_pagination_reverse('vpnservice',
+ (vpnservice1,
+ vpnservice2,
+ vpnservice3),
+ ('name', 'asc'),
+ 2, 2)
+
+ def test_create_ipsec_site_connection_with_invalid_values(self):
+ """Test case to create an ipsec_site_connection with invalid values."""
+ name = 'connection1'
+ self._create_ipsec_site_connection(
+ fmt=self.fmt,
+ name=name, peer_cidrs='myname', expected_status_int=400)
+ self._create_ipsec_site_connection(
+ fmt=self.fmt,
+ name=name, mtu=-100, expected_status_int=400)
+ self._create_ipsec_site_connection(
+ fmt=self.fmt,
+ name=name, dpd_action='unsupported', expected_status_int=400)
+ self._create_ipsec_site_connection(
+ fmt=self.fmt,
+ name=name, dpd_interval=-1, expected_status_int=400)
+ self._create_ipsec_site_connection(
+ fmt=self.fmt,
+ name=name, dpd_timeout=-200, expected_status_int=400)
+ self._create_ipsec_site_connection(
+ fmt=self.fmt,
+ name=name, initiator='unsupported', expected_status_int=400)
+ self._create_ipsec_site_connection(
+ fmt=self.fmt,
+ name=name,
+ dpd_interval=30,
+ dpd_timeout=20, expected_status_int=400)
+
+ def test_create_ipsec_site_connection(self, **extras):
+ """Test case to create an ipsec_site_connection."""
+ ikename = "ikepolicy1"
+ ipsecname = "ipsecpolicy1"
+ vpnsname = "vpnservice1"
+ name = "connection1"
+ description = "my-ipsec-connection"
+ keys = {'name': name,
+ 'description': "my-ipsec-connection",
+ 'peer_address': '192.168.1.10',
+ 'peer_id': '192.168.1.10',
+ 'peer_cidrs': ['192.168.2.0/24', '192.168.3.0/24'],
+ 'initiator': 'bi-directional',
+ 'mtu': 1500,
+ 'tenant_id': self._tenant_id,
+ 'psk': 'abcd',
+ 'status': 'PENDING_CREATE',
+ 'admin_state_up': True}
+ dpd = {'action': 'hold',
+ 'interval': 40,
+ 'timeout': 120}
+ keys.update(extras)
+ with contextlib.nested(
+ self.ikepolicy(name=ikename),
+ self.ipsecpolicy(name=ipsecname),
+ self.subnet(),
+ self.router()) as (
+ ikepolicy, ipsecpolicy, subnet, router):
+ with self.vpnservice(name=vpnsname, subnet=subnet,
+ router=router) as vpnservice1:
+ keys['ikepolicy_id'] = ikepolicy['ikepolicy']['id']
+ keys['ipsecpolicy_id'] = (
+ ipsecpolicy['ipsecpolicy']['id']
+ )
+ keys['vpnservice_id'] = (
+ vpnservice1['vpnservice']['id']
+ )
+ with self.ipsec_site_connection(
+ self.fmt,
+ name,
+ keys['peer_address'],
+ keys['peer_id'],
+ keys['peer_cidrs'],
+ keys['mtu'],
+ keys['psk'],
+ keys['initiator'],
+ dpd['action'],
+ dpd['interval'],
+ dpd['timeout'],
+ vpnservice1,
+ ikepolicy,
+ ipsecpolicy,
+ keys['admin_state_up'],
+ description=description,
+ **extras
+ ) as ipsec_site_connection:
+ self._check_ipsec_site_connection(
+ ipsec_site_connection['ipsec_site_connection'],
+ keys,
+ dpd)
+
+ def _check_ipsec_site_connection(self, ipsec_site_connection, keys, dpd):
+ self.assertEqual(
+ dict((k, v) for k, v
+ in ipsec_site_connection.items()
+ if k in keys), keys)
+ self.assertEqual(
+ dict((k, v) for k, v
+ in ipsec_site_connection['dpd'].items()
+ if k in dpd), dpd)
+
+ def test_delete_ipsec_site_connection(self):
+ """Test case to delete a ipsec_site_connection."""
+ with self.ipsec_site_connection(
+ no_delete=True) as ipsec_site_connection:
+ req = self.new_delete_request(
+ 'ipsec-site-connections',
+ ipsec_site_connection['ipsec_site_connection']['id']
+ )
+ res = req.get_response(self.ext_api)
+ self.assertEqual(res.status_int, 204)
+
+ def test_update_ipsec_site_connection(self):
+ """Test case to update a ipsec_site_connection."""
+ name = 'new_ipsec_site_connection'
+ ikename = 'ikepolicy1'
+ ipsecname = 'ipsecpolicy1'
+ vpnsname = 'vpnservice1'
+ description = 'my-ipsec-connection'
+ keys = {'name': 'new_ipsec_site_connection',
+ 'description': "my-ipsec-connection",
+ 'peer_address': '192.168.1.10',
+ 'peer_id': '192.168.1.10',
+ 'peer_cidrs': ['192.168.2.0/24', '192.168.3.0/24'],
+ 'initiator': 'bi-directional',
+ 'mtu': 1500,
+ 'tenant_id': self._tenant_id,
+ 'psk': 'abcd',
+ 'status': 'ACTIVE',
+ 'admin_state_up': True}
+ dpd = {'action': 'hold',
+ 'interval': 40,
+ 'timeout': 120}
+ with contextlib.nested(
+ self.ikepolicy(name=ikename),
+ self.ipsecpolicy(name=ipsecname),
+ self.subnet(cidr='10.2.0.0/24'),
+ self.router()) as (
+ ikepolicy, ipsecpolicy, subnet, router):
+ with self.vpnservice(name=vpnsname, subnet=subnet,
+ router=router) as vpnservice1:
+ keys['vpnservice_id'] = (
+ vpnservice1['vpnservice']['id']
+ )
+ keys['ikepolicy_id'] = (
+ ikepolicy['ikepolicy']['id']
+ )
+ keys['ipsecpolicy_id'] = (
+ ipsecpolicy['ipsecpolicy']['id']
+ )
+ with self.ipsec_site_connection(
+ self.fmt,
+ name,
+ keys['peer_address'],
+ keys['peer_id'],
+ keys['peer_cidrs'],
+ keys['mtu'],
+ keys['psk'],
+ keys['initiator'],
+ dpd['action'],
+ dpd['interval'],
+ dpd['timeout'],
+ vpnservice1,
+ ikepolicy,
+ ipsecpolicy,
+ keys['admin_state_up'],
+ description=description
+ ) as ipsec_site_connection:
+ data = {'ipsec_site_connection': {'name': name}}
+ self._set_active(
+ vpn_db.IPsecSiteConnection,
+ ipsec_site_connection['ipsec_site_connection']['id'])
+ req = self.new_update_request(
+ 'ipsec-site-connections',
+ data,
+ ipsec_site_connection['ipsec_site_connection']['id']
+ )
+ res = self.deserialize(
+ self.fmt,
+ req.get_response(self.ext_api)
+ )
+ for k, v in keys.items():
+ self.assertEqual(res['ipsec_site_connection'][k], v)
+
+ def test_update_ipsec_site_connection_with_invalid_state(self):
+ """Test case to update an ipsec_site_connection in invalid state."""
+ name = 'new_ipsec_site_connection'
+ ikename = 'ikepolicy1'
+ ipsecname = 'ipsecpolicy1'
+ vpnsname = 'vpnservice1'
+ description = 'my-ipsec-connection'
+ keys = {'name': 'new_ipsec_site_connection',
+ 'description': "my-ipsec-connection",
+ 'peer_address': '192.168.1.10',
+ 'peer_id': '192.168.1.10',
+ 'peer_cidrs': ['192.168.2.0/24', '192.168.3.0/24'],
+ 'initiator': 'bi-directional',
+ 'mtu': 1500,
+ 'tenant_id': self._tenant_id,
+ 'psk': 'abcd',
+ 'status': 'ACTIVE',
+ 'admin_state_up': True}
+ dpd = {'action': 'hold',
+ 'interval': 40,
+ 'timeout': 120}
+ with contextlib.nested(
+ self.ikepolicy(name=ikename),
+ self.ipsecpolicy(name=ipsecname),
+ self.subnet(cidr='10.2.0.0/24'),
+ self.router()) as (
+ ikepolicy, ipsecpolicy, subnet, router):
+ with self.vpnservice(name=vpnsname, subnet=subnet,
+ router=router) as vpnservice1:
+ keys['vpnservice_id'] = (
+ vpnservice1['vpnservice']['id']
+ )
+ keys['ikepolicy_id'] = (
+ ikepolicy['ikepolicy']['id']
+ )
+ keys['ipsecpolicy_id'] = (
+ ipsecpolicy['ipsecpolicy']['id']
+ )
+ with self.ipsec_site_connection(
+ self.fmt,
+ name,
+ keys['peer_address'],
+ keys['peer_id'],
+ keys['peer_cidrs'],
+ keys['mtu'],
+ keys['psk'],
+ keys['initiator'],
+ dpd['action'],
+ dpd['interval'],
+ dpd['timeout'],
+ vpnservice1,
+ ikepolicy,
+ ipsecpolicy,
+ keys['admin_state_up'],
+ description=description
+ ) as ipsec_site_connection:
+ data = {'ipsec_site_connection': {'name': name}}
+ req = self.new_update_request(
+ 'ipsec-site-connections',
+ data,
+ ipsec_site_connection['ipsec_site_connection']['id']
+ )
+ res = req.get_response(self.ext_api)
+ self.assertEqual(400, res.status_int)
+
+ def test_update_ipsec_site_connection_peer_cidrs(self):
+ """Test case to update a ipsec_site_connection for peer_cidrs."""
+ name = 'ipsec_site_connection'
+ ikename = 'ikepolicy1'
+ ipsecname = 'ipsecpolicy1'
+ vpnsname = 'vpnservice1'
+ description = 'my-ipsec-connection'
+ keys = {'name': 'ipsec_site_connection',
+ 'description': "my-ipsec-connection",
+ 'peer_address': '192.168.1.10',
+ 'peer_id': '192.168.1.10',
+ 'peer_cidrs': ['192.168.2.0/24', '192.168.3.0/24'],
+ 'initiator': 'bi-directional',
+ 'mtu': 1500,
+ 'tenant_id': self._tenant_id,
+ 'psk': 'abcd',
+ 'status': 'ACTIVE',
+ 'admin_state_up': True}
+ dpd = {'action': 'hold',
+ 'interval': 40,
+ 'timeout': 120}
+ with contextlib.nested(
+ self.ikepolicy(name=ikename),
+ self.ipsecpolicy(name=ipsecname),
+ self.subnet(cidr='10.2.0.0/24'),
+ self.router()) as (
+ ikepolicy, ipsecpolicy, subnet, router):
+ with self.vpnservice(name=vpnsname, subnet=subnet,
+ router=router) as vpnservice1:
+ keys['vpnservice_id'] = vpnservice1['vpnservice']['id']
+ keys['ikepolicy_id'] = ikepolicy['ikepolicy']['id']
+ keys['ipsecpolicy_id'] = ipsecpolicy['ipsecpolicy']['id']
+ with self.ipsec_site_connection(
+ self.fmt,
+ name,
+ keys['peer_address'],
+ keys['peer_id'],
+ keys['peer_cidrs'],
+ keys['mtu'],
+ keys['psk'],
+ keys['initiator'],
+ dpd['action'],
+ dpd['interval'],
+ dpd['timeout'],
+ vpnservice1,
+ ikepolicy,
+ ipsecpolicy,
+ keys['admin_state_up'],
+ description=description
+ ) as ipsec_site_connection:
+ data = {'ipsec_site_connection': {
+ 'peer_cidrs': ['192.168.2.0/24',
+ '192.168.3.0/24']
+ }}
+ self._set_active(
+ vpn_db.IPsecSiteConnection,
+ ipsec_site_connection['ipsec_site_connection']['id'])
+ req = self.new_update_request(
+ 'ipsec-site-connections',
+ data,
+ ipsec_site_connection[
+ 'ipsec_site_connection']['id']
+ )
+ res = self.deserialize(
+ self.fmt,
+ req.get_response(self.ext_api)
+ )
+ self._check_ipsec_site_connection(
+ res['ipsec_site_connection'],
+ keys,
+ dpd)
+
+ def test_show_ipsec_site_connection(self):
+ """Test case to show a ipsec_site_connection."""
+ ikename = "ikepolicy1"
+ ipsecname = "ipsecpolicy1"
+ vpnsname = "vpnservice1"
+ name = "connection1"
+ description = "my-ipsec-connection"
+ keys = {'name': name,
+ 'description': "my-ipsec-connection",
+ 'peer_address': '192.168.1.10',
+ 'peer_id': '192.168.1.10',
+ 'peer_cidrs': ['192.168.2.0/24', '192.168.3.0/24'],
+ 'initiator': 'bi-directional',
+ 'mtu': 1500,
+ 'tenant_id': self._tenant_id,
+ 'psk': 'abcd',
+ 'status': 'PENDING_CREATE',
+ 'admin_state_up': True}
+ dpd = {'action': 'hold',
+ 'interval': 40,
+ 'timeout': 120}
+ with contextlib.nested(
+ self.ikepolicy(name=ikename),
+ self.ipsecpolicy(name=ipsecname),
+ self.subnet(),
+ self.router()) as (
+ ikepolicy, ipsecpolicy, subnet, router):
+ with self.vpnservice(name=vpnsname, subnet=subnet,
+ router=router) as vpnservice1:
+ keys['ikepolicy_id'] = ikepolicy['ikepolicy']['id']
+ keys['ipsecpolicy_id'] = ipsecpolicy['ipsecpolicy']['id']
+ keys['vpnservice_id'] = vpnservice1['vpnservice']['id']
+ with self.ipsec_site_connection(
+ self.fmt,
+ name,
+ keys['peer_address'],
+ keys['peer_id'],
+ keys['peer_cidrs'],
+ keys['mtu'],
+ keys['psk'],
+ keys['initiator'],
+ dpd['action'],
+ dpd['interval'],
+ dpd['timeout'],
+ vpnservice1,
+ ikepolicy,
+ ipsecpolicy,
+ keys['admin_state_up'],
+ description=description,
+ ) as ipsec_site_connection:
+
+ req = self.new_show_request(
+ 'ipsec-site-connections',
+ ipsec_site_connection[
+ 'ipsec_site_connection']['id'],
+ fmt=self.fmt
+ )
+ res = self.deserialize(
+ self.fmt,
+ req.get_response(self.ext_api)
+ )
+
+ self._check_ipsec_site_connection(
+ res['ipsec_site_connection'],
+ keys,
+ dpd)
+
+ def test_list_ipsec_site_connections_with_sort_emulated(self):
+ """Test case to list all ipsec_site_connections with sort."""
+ with self.subnet(cidr='10.2.0.0/24') as subnet:
+ with self.router() as router:
+ with self.vpnservice(subnet=subnet,
+ router=router
+ ) as vpnservice:
+ with contextlib.nested(
+ self.ipsec_site_connection(
+ name='connection1', vpnservice=vpnservice
+ ),
+ self.ipsec_site_connection(
+ name='connection2', vpnservice=vpnservice
+ ),
+ self.ipsec_site_connection(
+ name='connection3', vpnservice=vpnservice
+ )
+ ) as(ipsec_site_connection1,
+ ipsec_site_connection2,
+ ipsec_site_connection3):
+ self._test_list_with_sort('ipsec-site-connection',
+ (ipsec_site_connection3,
+ ipsec_site_connection2,
+ ipsec_site_connection1),
+ [('name', 'desc')])
+
+ def test_list_ipsec_site_connections_with_pagination_emulated(self):
+ """Test case to list all ipsec_site_connections with pagination."""
+ with self.subnet(cidr='10.2.0.0/24') as subnet:
+ with self.router() as router:
+ with self.vpnservice(subnet=subnet,
+ router=router
+ ) as vpnservice:
+ with contextlib.nested(
+ self.ipsec_site_connection(
+ name='ipsec_site_connection1',
+ vpnservice=vpnservice
+ ),
+ self.ipsec_site_connection(
+ name='ipsec_site_connection1',
+ vpnservice=vpnservice
+ ),
+ self.ipsec_site_connection(
+ name='ipsec_site_connection1',
+ vpnservice=vpnservice
+ )
+ ) as(ipsec_site_connection1,
+ ipsec_site_connection2,
+ ipsec_site_connection3):
+ self._test_list_with_pagination(
+ 'ipsec-site-connection',
+ (ipsec_site_connection1,
+ ipsec_site_connection2,
+ ipsec_site_connection3),
+ ('name', 'asc'), 2, 2)
+
+ def test_list_ipsec_site_conns_with_pagination_reverse_emulated(self):
+ """Test to list all ipsec_site_connections with reverse pagination."""
+ with self.subnet(cidr='10.2.0.0/24') as subnet:
+ with self.router() as router:
+ with self.vpnservice(subnet=subnet,
+ router=router
+ ) as vpnservice:
+ with contextlib.nested(
+ self.ipsec_site_connection(
+ name='connection1', vpnservice=vpnservice
+ ),
+ self.ipsec_site_connection(
+ name='connection2', vpnservice=vpnservice
+ ),
+ self.ipsec_site_connection(
+ name='connection3', vpnservice=vpnservice
+ )
+ ) as(ipsec_site_connection1,
+ ipsec_site_connection2,
+ ipsec_site_connection3):
+ self._test_list_with_pagination_reverse(
+ 'ipsec-site-connection',
+ (ipsec_site_connection1,
+ ipsec_site_connection2,
+ ipsec_site_connection3),
+ ('name', 'asc'), 2, 2
+ )
+
+ def test_create_vpn(self):
+ """Test case to create a vpn."""
+ vpns_name = "vpnservice1"
+ ike_name = "ikepolicy1"
+ ipsec_name = "ipsecpolicy1"
+ name1 = "ipsec_site_connection1"
+ with contextlib.nested(
+ self.ikepolicy(name=ike_name),
+ self.ipsecpolicy(name=ipsec_name),
+ self.vpnservice(name=vpns_name)) as (
+ ikepolicy, ipsecpolicy, vpnservice):
+ vpnservice_id = vpnservice['vpnservice']['id']
+ ikepolicy_id = ikepolicy['ikepolicy']['id']
+ ipsecpolicy_id = ipsecpolicy['ipsecpolicy']['id']
+ with self.ipsec_site_connection(
+ self.fmt,
+ name1,
+ '192.168.1.10',
+ '192.168.1.10',
+ ['192.168.2.0/24',
+ '192.168.3.0/24'],
+ 1500,
+ 'abcdef',
+ 'bi-directional',
+ 'hold',
+ 30,
+ 120,
+ vpnservice,
+ ikepolicy,
+ ipsecpolicy,
+ True
+ ) as vpnconn1:
+
+ vpnservice_req = self.new_show_request(
+ 'vpnservices',
+ vpnservice_id,
+ fmt=self.fmt)
+ vpnservice_updated = self.deserialize(
+ self.fmt,
+ vpnservice_req.get_response(self.ext_api)
+ )
+ self.assertEqual(
+ vpnservice_updated['vpnservice']['id'],
+ vpnconn1['ipsec_site_connection']['vpnservice_id']
+ )
+ ikepolicy_req = self.new_show_request('ikepolicies',
+ ikepolicy_id,
+ fmt=self.fmt)
+ ikepolicy_res = self.deserialize(
+ self.fmt,
+ ikepolicy_req.get_response(self.ext_api)
+ )
+ self.assertEqual(
+ ikepolicy_res['ikepolicy']['id'],
+ vpnconn1['ipsec_site_connection']['ikepolicy_id'])
+ ipsecpolicy_req = self.new_show_request(
+ 'ipsecpolicies',
+ ipsecpolicy_id,
+ fmt=self.fmt)
+ ipsecpolicy_res = self.deserialize(
+ self.fmt,
+ ipsecpolicy_req.get_response(self.ext_api)
+ )
+ self.assertEqual(
+ ipsecpolicy_res['ipsecpolicy']['id'],
+ vpnconn1['ipsec_site_connection']['ipsecpolicy_id']
+ )
+
+ def test_delete_ikepolicy_inuse(self):
+ """Test case to delete an ikepolicy, that is in use."""
+ vpns_name = "vpnservice1"
+ ike_name = "ikepolicy1"
+ ipsec_name = "ipsecpolicy1"
+ name1 = "ipsec_site_connection1"
+ with self.ikepolicy(name=ike_name) as ikepolicy:
+ with self.ipsecpolicy(name=ipsec_name) as ipsecpolicy:
+ with self.vpnservice(name=vpns_name) as vpnservice:
+ with self.ipsec_site_connection(
+ self.fmt,
+ name1,
+ '192.168.1.10',
+ '192.168.1.10',
+ ['192.168.2.0/24',
+ '192.168.3.0/24'],
+ 1500,
+ 'abcdef',
+ 'bi-directional',
+ 'hold',
+ 30,
+ 120,
+ vpnservice,
+ ikepolicy,
+ ipsecpolicy,
+ True
+ ):
+ delete_req = self.new_delete_request(
+ 'ikepolicies',
+ ikepolicy['ikepolicy']['id']
+ )
+ delete_res = delete_req.get_response(self.ext_api)
+ self.assertEqual(409, delete_res.status_int)
+
+ def test_delete_ipsecpolicy_inuse(self):
+ """Test case to delete an ipsecpolicy, that is in use."""
+ vpns_name = "vpnservice1"
+ ike_name = "ikepolicy1"
+ ipsec_name = "ipsecpolicy1"
+ name1 = "ipsec_site_connection1"
+ with self.ikepolicy(name=ike_name) as ikepolicy:
+ with self.ipsecpolicy(name=ipsec_name) as ipsecpolicy:
+ with self.vpnservice(name=vpns_name) as vpnservice:
+ with self.ipsec_site_connection(
+ self.fmt,
+ name1,
+ '192.168.1.10',
+ '192.168.1.10',
+ ['192.168.2.0/24',
+ '192.168.3.0/24'],
+ 1500,
+ 'abcdef',
+ 'bi-directional',
+ 'hold',
+ 30,
+ 120,
+ vpnservice,
+ ikepolicy,
+ ipsecpolicy,
+ True
+ ):
+
+ delete_req = self.new_delete_request(
+ 'ipsecpolicies',
+ ipsecpolicy['ipsecpolicy']['id']
+ )
+ delete_res = delete_req.get_response(self.ext_api)
+ self.assertEqual(409, delete_res.status_int)
+
+
+class TestVpnaasXML(TestVpnaas):
+ fmt = 'xml'
--- /dev/null
+# 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.
--- /dev/null
+# 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'
if not no_delete:
self._delete('ports', port['port']['id'])
- def _test_list_with_sort(self, collection, items, sorts, query_params=''):
+ def _test_list_with_sort(self, resource,
+ items, sorts, resources=None, query_params=''):
query_str = query_params
for key, direction in sorts:
query_str = query_str + "&sort_key=%s&sort_dir=%s" % (key,
direction)
- req = self.new_list_request('%ss' % collection,
+ if not resources:
+ resources = '%ss' % resource
+ req = self.new_list_request(resources,
params=query_str)
- api = self._api_for_resource('%ss' % collection)
+ api = self._api_for_resource(resources)
res = self.deserialize(self.fmt, req.get_response(api))
- collection = collection.replace('-', '_')
- expected_res = [item[collection]['id'] for item in items]
- self.assertEqual(sorted([n['id'] for n in res["%ss" % collection]]),
+ resource = resource.replace('-', '_')
+ resources = resources.replace('-', '_')
+ expected_res = [item[resource]['id'] for item in items]
+ self.assertEqual(sorted([n['id'] for n in res[resources]]),
sorted(expected_res))
- def _test_list_with_pagination(self, collection, items, sort,
- limit, expected_page_num, query_params='',
+ def _test_list_with_pagination(self, resource, items, sort,
+ limit, expected_page_num,
+ resources=None,
+ query_params='',
verify_key='id'):
+ if not resources:
+ resources = '%ss' % resource
query_str = query_params + '&' if query_params else ''
query_str = query_str + ("limit=%s&sort_key=%s&"
"sort_dir=%s") % (limit, sort[0], sort[1])
- req = self.new_list_request("%ss" % collection, params=query_str)
+ req = self.new_list_request(resources, params=query_str)
items_res = []
page_num = 0
- api = self._api_for_resource('%ss' % collection)
- collection = collection.replace('-', '_')
+ api = self._api_for_resource(resources)
+ resource = resource.replace('-', '_')
+ resources = resources.replace('-', '_')
while req:
page_num = page_num + 1
res = self.deserialize(self.fmt, req.get_response(api))
- self.assertThat(len(res["%ss" % collection]),
+ self.assertThat(len(res[resources]),
matchers.LessThan(limit + 1))
- items_res = items_res + res["%ss" % collection]
+ items_res = items_res + res[resources]
req = None
- if '%ss_links' % collection in res:
- for link in res['%ss_links' % collection]:
+ if '%s_links' % resources in res:
+ for link in res['%s_links' % resources]:
if link['rel'] == 'next':
content_type = 'application/%s' % self.fmt
req = testlib_api.create_request(link['href'],
'', content_type)
- self.assertEqual(len(res["%ss" % collection]),
+ self.assertEqual(len(res[resources]),
limit)
self.assertEqual(page_num, expected_page_num)
self.assertEqual(sorted([n[verify_key] for n in items_res]),
- sorted([item[collection][verify_key]
+ sorted([item[resource][verify_key]
for item in items]))
- def _test_list_with_pagination_reverse(self, collection, items, sort,
+ def _test_list_with_pagination_reverse(self, resource, items, sort,
limit, expected_page_num,
+ resources=None,
query_params=''):
- resources = '%ss' % collection
- collection = collection.replace('-', '_')
+ if not resources:
+ resources = '%ss' % resource
+ resource = resource.replace('-', '_')
api = self._api_for_resource(resources)
- marker = items[-1][collection]['id']
+ marker = items[-1][resource]['id']
query_str = query_params + '&' if query_params else ''
query_str = query_str + ("limit=%s&page_reverse=True&"
"sort_key=%s&sort_dir=%s&"
"marker=%s") % (limit, sort[0], sort[1],
marker)
req = self.new_list_request(resources, params=query_str)
- item_res = [items[-1][collection]]
+ item_res = [items[-1][resource]]
page_num = 0
+ resources = resources.replace('-', '_')
while req:
page_num = page_num + 1
res = self.deserialize(self.fmt, req.get_response(api))
- self.assertThat(len(res["%ss" % collection]),
+ self.assertThat(len(res[resources]),
matchers.LessThan(limit + 1))
- res["%ss" % collection].reverse()
- item_res = item_res + res["%ss" % collection]
+ res[resources].reverse()
+ item_res = item_res + res[resources]
req = None
- if '%ss_links' % collection in res:
- for link in res['%ss_links' % collection]:
+ if '%s_links' % resources in res:
+ for link in res['%s_links' % resources]:
if link['rel'] == 'previous':
content_type = 'application/%s' % self.fmt
req = testlib_api.create_request(link['href'],
'', content_type)
- self.assertEqual(len(res["%ss" % collection]),
+ self.assertEqual(len(res[resources]),
limit)
self.assertEqual(page_num, expected_page_num)
- expected_res = [item[collection]['id'] for item in items]
+ expected_res = [item[resource]['id'] for item in items]
expected_res.reverse()
self.assertEqual(sorted([n['id'] for n in item_res]),
sorted(expected_res))