from neutron.db import l3_db
from neutron.db.loadbalancer import loadbalancer_db
from neutron.db import routedserviceinsertion_db as rsi_db
+from neutron.db.vpn import vpn_db
from neutron.extensions import firewall as fw_ext
from neutron.extensions import l3
from neutron.extensions import routedserviceinsertion as rsi
base.NsxPluginV2,
rsi_db.RoutedServiceInsertionDbMixin,
firewall_db.Firewall_db_mixin,
- loadbalancer_db.LoadBalancerPluginDb
+ loadbalancer_db.LoadBalancerPluginDb,
+ vpn_db.VPNPluginDb
):
supported_extension_aliases = (
"service-router",
"routed-service-insertion",
"fwaas",
- "lbaas"
+ "lbaas",
+ "vpnaas"
])
def __init__(self):
}
self._process_create_resource_router_id(
context, res, firewall_db.Firewall)
- #Since there is only one firewall per edge,
- #here would be bulk configureation operation on firewall
+ # Since there is only one firewall per edge,
+ # here would be bulk configuration operation on firewall
self._vcns_update_firewall(context, fw, router_id)
self._firewall_set_status(
context, fw['id'], service_constants.ACTIVE, fw)
context, loadbalancer_db.Pool,
pool_id, service_constants.ACTIVE)
+ def _vcns_update_ipsec_config(
+ self, context, vpnservice_id, removed_ipsec_conn_id=None):
+ sites = []
+ vpn_service = self._get_vpnservice(context, vpnservice_id)
+ edge_id = self._get_edge_id_by_vcns_edge_binding(
+ context, vpn_service.router_id)
+ if not vpn_service.router.gw_port:
+ msg = _("Failed to update ipsec vpn configuration on edge, since "
+ "the router: %s does not have a gateway yet!"
+ ) % vpn_service.router_id
+ LOG.error(msg)
+ raise exceptions.VcnsBadRequest(resource='router', msg=msg)
+
+ external_ip = vpn_service.router.gw_port['fixed_ips'][0]['ip_address']
+ subnet = self._make_subnet_dict(vpn_service.subnet)
+ for ipsec_site_conn in vpn_service.ipsec_site_connections:
+ if ipsec_site_conn.id != removed_ipsec_conn_id:
+ site = self._make_ipsec_site_connection_dict(ipsec_site_conn)
+ ikepolicy = self._make_ikepolicy_dict(
+ ipsec_site_conn.ikepolicy)
+ ipsecpolicy = self._make_ipsecpolicy_dict(
+ ipsec_site_conn.ipsecpolicy)
+ sites.append({'site': site,
+ 'ikepolicy': ikepolicy,
+ 'ipsecpolicy': ipsecpolicy,
+ 'subnet': subnet,
+ 'external_ip': external_ip})
+ try:
+ self.vcns_driver.update_ipsec_config(
+ edge_id, sites, enabled=vpn_service.admin_state_up)
+ except exceptions.VcnsBadRequest:
+ LOG.exception(_("Bad or unsupported Input request!"))
+ raise
+ except exceptions.VcnsApiException:
+ msg = (_("Failed to update ipsec VPN configuration "
+ "with vpnservice: %(vpnservice_id)s on vShield Edge: "
+ "%(edge_id)s") % {'vpnservice_id': vpnservice_id,
+ 'edge_id': edge_id})
+ LOG.exception(msg)
+ raise
+
+ def create_vpnservice(self, context, vpnservice):
+ LOG.debug(_("create_vpnservice() called"))
+ router_id = vpnservice['vpnservice'].get('router_id')
+ if not self._is_advanced_service_router(context, router_id):
+ msg = _("router_id:%s is not an advanced router!") % router_id
+ LOG.warning(msg)
+ raise exceptions.VcnsBadRequest(resource='router', msg=msg)
+
+ if self.get_vpnservices(context, filters={'router_id': [router_id]}):
+ msg = _("a vpnservice is already associated with the router: %s"
+ ) % router_id
+ LOG.warning(msg)
+ raise nsx_exc.ServiceOverQuota(
+ overs='vpnservice', err_msg=msg)
+
+ service = super(NvpAdvancedPlugin, self).create_vpnservice(
+ context, vpnservice)
+ self._resource_set_status(
+ context, vpn_db.VPNService,
+ service['id'], service_constants.ACTIVE, service)
+ return service
+
+ def update_vpnservice(self, context, vpnservice_id, vpnservice):
+ vpnservice['vpnservice']['status'] = service_constants.PENDING_UPDATE
+ service = super(NvpAdvancedPlugin, self).update_vpnservice(
+ context, vpnservice_id, vpnservice)
+ # Only admin_state_up attribute is configurable on Edge.
+ if vpnservice['vpnservice'].get('admin_state_up') is None:
+ self._resource_set_status(
+ context, vpn_db.VPNService,
+ service['id'], service_constants.ACTIVE, service)
+ return service
+ # Test whether there is one ipsec site connection attached to
+ # the vpnservice. If not, just return without updating ipsec
+ # config on edge side.
+ vpn_service_db = self._get_vpnservice(context, vpnservice_id)
+ if not vpn_service_db.ipsec_site_connections:
+ self._resource_set_status(
+ context, vpn_db.VPNService,
+ service['id'], service_constants.ACTIVE, service)
+ return service
+ try:
+ self._vcns_update_ipsec_config(context, service['id'])
+ except Exception:
+ with excutils.save_and_reraise_exception():
+ self._resource_set_status(
+ context, vpn_db.VPNService,
+ service['id'], service_constants.ERROR, service)
+ self._resource_set_status(
+ context, vpn_db.VPNService,
+ service['id'], service_constants.ACTIVE, service)
+ return service
+
+ def create_ipsec_site_connection(self, context, ipsec_site_connection):
+ ipsec_site_conn = super(
+ NvpAdvancedPlugin, self).create_ipsec_site_connection(
+ context, ipsec_site_connection)
+ try:
+ self._vcns_update_ipsec_config(
+ context, ipsec_site_conn['vpnservice_id'])
+ except Exception:
+ with excutils.save_and_reraise_exception():
+ super(NvpAdvancedPlugin, self).delete_ipsec_site_connection(
+ context, ipsec_site_conn['id'])
+ self._resource_set_status(
+ context, vpn_db.IPsecSiteConnection,
+ ipsec_site_conn['id'], service_constants.ACTIVE, ipsec_site_conn)
+ return ipsec_site_conn
+
+ def update_ipsec_site_connection(self, context, ipsec_site_connection_id,
+ ipsec_site_connection):
+ ipsec_site_connection['ipsec_site_connection']['status'] = (
+ service_constants.PENDING_UPDATE)
+ ipsec_site_conn = super(
+ NvpAdvancedPlugin, self).update_ipsec_site_connection(
+ context, ipsec_site_connection_id, ipsec_site_connection)
+ try:
+ self._vcns_update_ipsec_config(
+ context, ipsec_site_conn['vpnservice_id'])
+ except Exception:
+ with excutils.save_and_reraise_exception():
+ self._resource_set_status(
+ context, vpn_db.IPsecSiteConnection, ipsec_site_conn['id'],
+ service_constants.ERROR, ipsec_site_conn)
+ self._resource_set_status(
+ context, vpn_db.IPsecSiteConnection,
+ ipsec_site_conn['id'], service_constants.ACTIVE, ipsec_site_conn)
+ return ipsec_site_conn
+
+ def delete_ipsec_site_connection(self, context, ipsec_site_conn_id):
+ self._resource_set_status(
+ context, vpn_db.IPsecSiteConnection,
+ ipsec_site_conn_id, service_constants.PENDING_DELETE)
+ vpnservice_id = self.get_ipsec_site_connection(
+ context, ipsec_site_conn_id)['vpnservice_id']
+ try:
+ self._vcns_update_ipsec_config(
+ context, vpnservice_id, ipsec_site_conn_id)
+ except Exception:
+ with excutils.save_and_reraise_exception():
+ self._resource_set_status(
+ context, vpn_db.IPsecSiteConnection, ipsec_site_conn_id,
+ service_constants.ERROR)
+ super(NvpAdvancedPlugin, self).delete_ipsec_site_connection(
+ context, ipsec_site_conn_id)
+
class VcnsCallbacks(object):
"""Edge callback implementation Callback functions for
--- /dev/null
+# Copyright 2014 VMware, Inc
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from neutron.openstack.common import log as logging
+from neutron.plugins.vmware.vshield.common import (
+ exceptions as vcns_exc)
+
+LOG = logging.getLogger(__name__)
+
+ENCRYPTION_ALGORITHM_MAP = {
+ '3des': '3des',
+ 'aes-128': 'aes',
+ 'aes-256': 'aes256'
+}
+
+PFS_MAP = {
+ 'group2': 'dh2',
+ 'group5': 'dh5'}
+
+TRANSFORM_PROTOCOL_ALLOWED = ('esp',)
+
+ENCAPSULATION_MODE_ALLOWED = ('tunnel',)
+
+
+class EdgeIPsecVpnDriver():
+
+ """Driver APIs for Edge IPsec VPN bulk configuration."""
+
+ def _check_ikepolicy_ipsecpolicy_allowed(self, ikepolicy, ipsecpolicy):
+ """Check whether ikepolicy and ipsecpolicy are allowed on vshield edge.
+
+ Some IPsec VPN configurations and features are configured by default or
+ not supported on vshield edge.
+
+ """
+ # Check validation of IKEPolicy.
+ if ikepolicy['ike_version'] != 'v1':
+ msg = _("Unsupported ike_version: %s! Only 'v1' ike version is "
+ "supported on vshield Edge!"
+ ) % ikepolicy['ike_version']
+ LOG.warning(msg)
+ raise vcns_exc.VcnsBadRequest(resource='ikepolicy',
+ msg=msg)
+
+ # In VSE, Phase 1 and Phase 2 share the same encryption_algorithm
+ # and authentication algorithms setting. At present, just record the
+ # discrepancy error in log and take ipsecpolicy to do configuration.
+ if (ikepolicy['auth_algorithm'] != ipsecpolicy['auth_algorithm'] or
+ ikepolicy['encryption_algorithm'] != ipsecpolicy[
+ 'encryption_algorithm'] or
+ ikepolicy['pfs'] != ipsecpolicy['pfs']):
+ msg = _("IKEPolicy and IPsecPolicy should have consistent "
+ "auth_algorithm, encryption_algorithm and pfs for VSE!")
+ LOG.warning(msg)
+
+ # Check whether encryption_algorithm is allowed.
+ encryption_algorithm = ENCRYPTION_ALGORITHM_MAP.get(
+ ipsecpolicy.get('encryption_algorithm'), None)
+ if not encryption_algorithm:
+ msg = _("Unsupported encryption_algorithm: %s! '3des', "
+ "'aes-128' and 'aes-256' are supported on VSE right now."
+ ) % ipsecpolicy['encryption_algorithm']
+ LOG.warning(msg)
+ raise vcns_exc.VcnsBadRequest(resource='ipsecpolicy',
+ msg=msg)
+
+ # Check whether pfs is allowed.
+ if not PFS_MAP.get(ipsecpolicy['pfs']):
+ msg = _("Unsupported pfs: %s! 'group2' and 'group5' "
+ "are supported on VSE right now.") % ipsecpolicy['pfs']
+ LOG.warning(msg)
+ raise vcns_exc.VcnsBadRequest(resource='ipsecpolicy',
+ msg=msg)
+
+ # Check whether transform protocol is allowed.
+ if ipsecpolicy['transform_protocol'] not in TRANSFORM_PROTOCOL_ALLOWED:
+ msg = _("Unsupported transform protocol: %s! 'esp' is supported "
+ "by default on VSE right now."
+ ) % ipsecpolicy['transform_protocol']
+ LOG.warning(msg)
+ raise vcns_exc.VcnsBadRequest(resource='ipsecpolicy',
+ msg=msg)
+
+ # Check whether encapsulation mode is allowed.
+ if ipsecpolicy['encapsulation_mode'] not in ENCAPSULATION_MODE_ALLOWED:
+ msg = _("Unsupported encapsulation mode: %s! 'tunnel' is "
+ "supported by default on VSE right now."
+ ) % ipsecpolicy['encapsulation_mode']
+ LOG.warning(msg)
+ raise vcns_exc.VcnsBadRequest(resource='ipsecpolicy',
+ msg=msg)
+
+ def _convert_ipsec_site(self, site, enablePfs=True):
+ self._check_ikepolicy_ipsecpolicy_allowed(
+ site['ikepolicy'], site['ipsecpolicy'])
+ return {
+ 'enabled': site['site'].get('admin_state_up'),
+ 'enablePfs': enablePfs,
+ 'dhGroup': PFS_MAP.get(site['ipsecpolicy']['pfs']),
+ 'name': site['site'].get('name'),
+ 'description': site['site'].get('description'),
+ 'localId': site['external_ip'],
+ 'localIp': site['external_ip'],
+ 'peerId': site['site'].get('peer_id'),
+ 'peerIp': site['site'].get('peer_address'),
+ 'localSubnets': {
+ 'subnets': [site['subnet'].get('cidr')]},
+ 'peerSubnets': {
+ 'subnets': site['site'].get('peer_cidrs')},
+ 'authenticationMode': site['site'].get('auth_mode'),
+ 'psk': site['site'].get('psk'),
+ 'encryptionAlgorithm': ENCRYPTION_ALGORITHM_MAP.get(
+ site['ipsecpolicy'].get('encryption_algorithm'))}
+
+ def update_ipsec_config(self, edge_id, sites, enabled=True):
+ ipsec_config = {'featureType': "ipsec_4.0",
+ 'enabled': enabled}
+ vse_sites = [self._convert_ipsec_site(site) for site in sites]
+ ipsec_config['sites'] = {'sites': vse_sites}
+ try:
+ self.vcns.update_ipsec_config(edge_id, ipsec_config)
+ except vcns_exc.VcnsApiException:
+ LOG.exception(_("Failed to update ipsec vpn configuration "
+ "with edge_id: %s"), edge_id)
+ raise
+
+ def delete_ipsec_config(self, edge_id):
+ try:
+ self.vcns.delete_ipsec_config(edge_id)
+ except vcns_exc.ResourceNotFound:
+ LOG.warning(_("IPsec config not found on edge: %s"), edge_id)
+ except vcns_exc.VcnsApiException:
+ LOG.exception(_("Failed to delete ipsec vpn configuration "
+ "with edge_id: %s"), edge_id)
+ raise
+
+ def get_ipsec_config(self, edge_id):
+ return self.vcns.get_ipsec_config(edge_id)
MONITOR_RESOURCE = "monitors"
APP_PROFILE_RESOURCE = "applicationprofiles"
+# IPsec VPNaaS Constants
+IPSEC_VPN_SERVICE = 'ipsec/config'
+
class Vcns(object):
app_profileid)
return self.do_request(HTTP_DELETE, uri)
+ def update_ipsec_config(self, edge_id, ipsec_config):
+ uri = self._build_uri_path(edge_id, IPSEC_VPN_SERVICE)
+ return self.do_request(HTTP_PUT, uri, ipsec_config)
+
+ def delete_ipsec_config(self, edge_id):
+ uri = self._build_uri_path(edge_id, IPSEC_VPN_SERVICE)
+ return self.do_request(HTTP_DELETE, uri)
+
+ def get_ipsec_config(self, edge_id):
+ uri = self._build_uri_path(edge_id, IPSEC_VPN_SERVICE)
+ return self.do_request(HTTP_GET, uri)
+
def _build_uri_path(self, edge_id,
service,
resource=None,
from neutron.plugins.vmware.common import config # noqa
from neutron.plugins.vmware.vshield import edge_appliance_driver
from neutron.plugins.vmware.vshield import edge_firewall_driver
+from neutron.plugins.vmware.vshield import edge_ipsecvpn_driver
from neutron.plugins.vmware.vshield import edge_loadbalancer_driver
from neutron.plugins.vmware.vshield.tasks import tasks
from neutron.plugins.vmware.vshield import vcns
class VcnsDriver(edge_appliance_driver.EdgeApplianceDriver,
edge_firewall_driver.EdgeFirewallDriver,
- edge_loadbalancer_driver.EdgeLbDriver):
+ edge_loadbalancer_driver.EdgeLbDriver,
+ edge_ipsecvpn_driver.EdgeIPsecVpnDriver):
def __init__(self, callbacks):
super(VcnsDriver, self).__init__()
from neutron import extensions
from neutron.extensions import vpnaas
from neutron import manager
+from neutron.openstack.common import uuidutils
from neutron.plugins.common import constants
from neutron.scheduler import l3_agent_scheduler
from neutron.services.vpn import plugin as vpn_plugin
self.router_scheduler = l3_agent_scheduler.ChanceScheduler()
-class VPNPluginDbTestCase(test_l3_plugin.L3NatTestCaseMixin,
- test_db_plugin.NeutronDbPluginV2TestCase):
+class VPNTestMixin(object):
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',
'ipsec_site_connection']['id']
)
+ def _check_ipsec_site_connection(self, ipsec_site_connection, keys, dpd):
+ self.assertEqual(
+ keys,
+ dict((k, v) for k, v
+ in ipsec_site_connection.items()
+ if k in keys))
+ self.assertEqual(
+ dpd,
+ dict((k, v) for k, v
+ in ipsec_site_connection['dpd'].items()
+ if k in dpd))
+
+ 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
+
+
+class VPNPluginDbTestCase(VPNTestMixin,
+ test_l3_plugin.L3NatTestCaseMixin,
+ test_db_plugin.NeutronDbPluginV2TestCase):
+ 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 = uuidutils.generate_uuid()
+ 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)
+
class TestVpnaas(VPNPluginDbTestCase):
self._delete('routers', router['router']['id'],
expected_code=webob.exc.HTTPConflict.code)
- 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'
setup_overrides=ipv6_setup_params,
expected_status_int=400)
- def _check_ipsec_site_connection(self, ipsec_site_connection, keys, dpd):
- self.assertEqual(
- keys,
- dict((k, v) for k, v
- in ipsec_site_connection.items()
- if k in keys))
- self.assertEqual(
- dpd,
- dict((k, v) for k, v
- in ipsec_site_connection['dpd'].items()
- if k in dpd))
-
def test_delete_ipsec_site_connection(self):
"""Test case to delete a ipsec_site_connection."""
with self.ipsec_site_connection(
plugin_instance.__class__.__name__)
self._plugin_class = plugin_instance.__class__
-
-class TestL3NatTestCase(L3NatTest,
- test_l3_plugin.L3NatDBIntTestCase,
- NsxPluginV2TestCase):
-
def _create_l3_ext_network(self, vlan_id=None):
name = 'l3_ext_net'
net_type = NetworkTypes.L3_EXT
pnet.PHYSICAL_NETWORK,
pnet.SEGMENTATION_ID))
+
+class TestL3NatTestCase(L3NatTest,
+ test_l3_plugin.L3NatDBIntTestCase,
+ NsxPluginV2TestCase):
+
def _test_create_l3_ext_network(self, vlan_id=None):
name = 'l3_ext_net'
net_type = NetworkTypes.L3_EXT
"firewallRules": []
}
}
+ self.fake_ipsecvpn_dict = {}
+ self.temp_ipsecvpn = {
+ 'featureType': "ipsec_4.0",
+ 'enabled': True,
+ 'sites': {'sites': []}}
self._fake_virtualservers_dict = {}
self._fake_pools_dict = {}
self._fake_monitors_dict = {}
break
return self.return_helper(header, response)
- #
- #Fake Edge LBAAS call
- #
def create_vip(self, edge_id, vip_new):
if not self._fake_virtualservers_dict.get(edge_id):
self._fake_virtualservers_dict[edge_id] = {}
response['config'] = self._fake_loadbalancer_config[edge_id]
return self.return_helper(header, response)
+ def update_ipsec_config(self, edge_id, ipsec_config):
+ self.fake_ipsecvpn_dict[edge_id] = ipsec_config
+ header = {'status': 204}
+ response = ""
+ return self.return_helper(header, response)
+
+ def delete_ipsec_config(self, edge_id):
+ header = {'status': 404}
+ if edge_id in self.fake_ipsecvpn_dict:
+ header = {'status': 204}
+ del self.fake_ipsecvpn_dict[edge_id]
+ response = ""
+ return self.return_helper(header, response)
+
+ def get_ipsec_config(self, edge_id):
+ if edge_id not in self.fake_ipsecvpn_dict:
+ self.fake_ipsecvpn_dict[edge_id] = self.temp_ipsecvpn
+ header = {'status': 204}
+ response = self.fake_ipsecvpn_dict[edge_id]
+ return self.return_helper(header, response)
+
def enable_service_loadbalancer(self, edge_id, config):
header = {'status': 204}
response = ""
--- /dev/null
+# Copyright 2014 VMware, Inc
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import contextlib
+import copy
+
+import webob.exc
+
+from neutron.api.v2 import attributes
+from neutron.db.vpn import vpn_db
+from neutron.extensions import vpnaas
+from neutron import manager
+from neutron.openstack.common import uuidutils
+from neutron.tests.unit.db.vpn import test_db_vpnaas
+from neutron.tests.unit.vmware.vshield import test_edge_router
+
+_uuid = uuidutils.generate_uuid
+
+
+class VPNTestExtensionManager(
+ test_edge_router.ServiceRouterTestExtensionManager):
+
+ def get_resources(self):
+ # If l3 resources have been loaded and updated by main API
+ # router, update the map in the l3 extension so it will load
+ # the same attributes as the API router
+ resources = super(VPNTestExtensionManager, self).get_resources()
+ vpn_attr_map = copy.deepcopy(vpnaas.RESOURCE_ATTRIBUTE_MAP)
+ for res in vpnaas.RESOURCE_ATTRIBUTE_MAP.keys():
+ attr_info = attributes.RESOURCE_ATTRIBUTE_MAP.get(res)
+ if attr_info:
+ vpnaas.RESOURCE_ATTRIBUTE_MAP[res] = attr_info
+ vpn_resources = vpnaas.Vpnaas.get_resources()
+ # restore the original resources once the controllers are created
+ vpnaas.RESOURCE_ATTRIBUTE_MAP = vpn_attr_map
+ resources.extend(vpn_resources)
+ return resources
+
+
+class TestVpnPlugin(test_db_vpnaas.VPNTestMixin,
+ test_edge_router.ServiceRouterTest):
+
+ def vcns_vpn_patch(self):
+ instance = self.vcns_instance
+ instance.return_value.update_ipsec_config.side_effect = (
+ self.fc2.update_ipsec_config)
+ instance.return_value.get_ipsec_config.side_effect = (
+ self.fc2.get_ipsec_config)
+ instance.return_value.delete_ipsec_config.side_effect = (
+ self.fc2.delete_ipsec_config)
+
+ def setUp(self):
+ # Save the global RESOURCE_ATTRIBUTE_MAP
+ self.saved_attr_map = {}
+ for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.items():
+ self.saved_attr_map[resource] = attrs.copy()
+
+ super(TestVpnPlugin, self).setUp(ext_mgr=VPNTestExtensionManager())
+ self.vcns_vpn_patch()
+ self.plugin = manager.NeutronManager.get_plugin()
+ self.router_id = None
+
+ def tearDown(self):
+ super(TestVpnPlugin, self).tearDown()
+ # Restore the global RESOURCE_ATTRIBUTE_MAP
+ attributes.RESOURCE_ATTRIBUTE_MAP = self.saved_attr_map
+ self.ext_api = None
+ self.plugin = None
+
+ @contextlib.contextmanager
+ def router(self, vlan_id=None):
+ with self._create_l3_ext_network(vlan_id) as net:
+ with self.subnet(cidr='100.0.0.0/24', network=net) as s:
+ data = {'router': {'tenant_id': self._tenant_id}}
+ data['router']['service_router'] = True
+ router_req = self.new_create_request('routers', data, self.fmt)
+ try:
+ res = router_req.get_response(self.ext_api)
+ router = self.deserialize(self.fmt, res)
+ self._add_external_gateway_to_router(
+ router['router']['id'],
+ s['subnet']['network_id'])
+ router = self._show('routers', router['router']['id'])
+ yield router
+ finally:
+ self._delete('routers', router['router']['id'])
+
+ 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': 'ACTIVE',
+ '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)
+
+ def test_create_vpnservices_with_same_router(self, **extras):
+ """Test case to create two vpnservices with same router."""
+ with self.subnet(cidr='10.2.0.0/24') as subnet:
+ with self.router() as router:
+ with self.vpnservice(name='vpnservice1',
+ subnet=subnet,
+ router=router):
+ res = self._create_vpnservice(
+ 'json', 'vpnservice2', True,
+ router_id=(router['router']['id']),
+ subnet_id=(subnet['subnet']['id']))
+ self.assertEqual(
+ res.status_int, webob.exc.HTTPConflict.code)
+
+ def test_update_vpnservice(self):
+ """Test case to update a vpnservice."""
+ name = 'new_vpnservice1'
+ expected = [('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:
+ expected.append(('subnet_id',
+ vpnservice['vpnservice']['subnet_id']))
+ expected.append(('router_id',
+ vpnservice['vpnservice']['router_id']))
+ data = {'vpnservice': {'name': name,
+ 'admin_state_up': False}}
+ expected.append(('admin_state_up', False))
+ 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 expected:
+ self.assertEqual(res['vpnservice'][k], v)
+
+ def _test_create_ipsec_site_connection(self, key_overrides=None,
+ ike_key_overrides=None,
+ ipsec_key_overrides=None,
+ setup_overrides=None,
+ expected_status_int=200):
+ """Create ipsec_site_connection and check results."""
+ params = {'ikename': 'ikepolicy1',
+ 'ipsecname': 'ipsecpolicy1',
+ 'vpnsname': 'vpnservice1',
+ 'subnet_cidr': '10.2.0.0/24',
+ 'subnet_version': 4}
+ if setup_overrides:
+ params.update(setup_overrides)
+ expected = {'name': 'connection1',
+ '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}
+ if key_overrides:
+ expected.update(key_overrides)
+
+ ike_expected = {'name': params['ikename'],
+ 'auth_algorithm': 'sha1',
+ 'encryption_algorithm': 'aes-128',
+ 'ike_version': 'v1',
+ 'pfs': 'group5'}
+ if ike_key_overrides:
+ ike_expected.update(ike_key_overrides)
+
+ ipsec_expected = {'name': params['ipsecname'],
+ 'auth_algorithm': 'sha1',
+ 'encryption_algorithm': 'aes-128',
+ 'pfs': 'group5'}
+ if ipsec_key_overrides:
+ ipsec_expected.update(ipsec_key_overrides)
+
+ dpd = {'action': 'hold',
+ 'interval': 40,
+ 'timeout': 120}
+ with contextlib.nested(
+ self.ikepolicy(self.fmt, ike_expected['name'],
+ ike_expected['auth_algorithm'],
+ ike_expected['encryption_algorithm'],
+ ike_version=ike_expected['ike_version'],
+ pfs=ike_expected['pfs']),
+ self.ipsecpolicy(self.fmt, ipsec_expected['name'],
+ ipsec_expected['auth_algorithm'],
+ ipsec_expected['encryption_algorithm'],
+ pfs=ipsec_expected['pfs']),
+ self.subnet(cidr=params['subnet_cidr'],
+ ip_version=params['subnet_version']),
+ self.router()) as (
+ ikepolicy, ipsecpolicy, subnet, router):
+ with self.vpnservice(name=params['vpnsname'], subnet=subnet,
+ router=router) as vpnservice1:
+ expected['ikepolicy_id'] = ikepolicy['ikepolicy']['id']
+ expected['ipsecpolicy_id'] = (
+ ipsecpolicy['ipsecpolicy']['id']
+ )
+ expected['vpnservice_id'] = (
+ vpnservice1['vpnservice']['id']
+ )
+ try:
+ with self.ipsec_site_connection(
+ self.fmt,
+ expected['name'],
+ expected['peer_address'],
+ expected['peer_id'],
+ expected['peer_cidrs'],
+ expected['mtu'],
+ expected['psk'],
+ expected['initiator'],
+ dpd['action'],
+ dpd['interval'],
+ dpd['timeout'],
+ vpnservice1,
+ ikepolicy,
+ ipsecpolicy,
+ expected['admin_state_up'],
+ description=expected['description']
+ ) as ipsec_site_connection:
+ if expected_status_int != 200:
+ self.fail("Expected failure on create")
+ self._check_ipsec_site_connection(
+ ipsec_site_connection['ipsec_site_connection'],
+ expected,
+ dpd)
+ except webob.exc.HTTPClientError as ce:
+ self.assertEqual(ce.code, expected_status_int)
+
+ def test_create_ipsec_site_connection(self, **extras):
+ """Test case to create an ipsec_site_connection."""
+ self._test_create_ipsec_site_connection(key_overrides=extras)
+
+ def test_create_ipsec_site_connection_invalid_ikepolicy(self):
+ self._test_create_ipsec_site_connection(
+ ike_key_overrides={'ike_version': 'v2'},
+ expected_status_int=400)
+
+ def test_create_ipsec_site_connection_invalid_ipsecpolicy(self):
+ self._test_create_ipsec_site_connection(
+ ipsec_key_overrides={'encryption_algorithm': 'aes-192'},
+ expected_status_int=400)
+ self._test_create_ipsec_site_connection(
+ ipsec_key_overrides={'pfs': 'group14'},
+ expected_status_int=400)
+
+ def _test_update_ipsec_site_connection(self,
+ update={'name': 'new name'},
+ overrides=None,
+ expected_status_int=200):
+ """Creates and then updates ipsec_site_connection."""
+ expected = {'name': 'new_ipsec_site_connection',
+ 'ikename': 'ikepolicy1',
+ 'ipsecname': 'ipsecpolicy1',
+ 'vpnsname': 'vpnservice1',
+ '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,
+ 'action': 'hold',
+ 'interval': 40,
+ 'timeout': 120,
+ 'subnet_cidr': '10.2.0.0/24',
+ 'subnet_version': 4,
+ 'make_active': True}
+ if overrides:
+ expected.update(overrides)
+
+ with contextlib.nested(
+ self.ikepolicy(name=expected['ikename']),
+ self.ipsecpolicy(name=expected['ipsecname']),
+ self.subnet(cidr=expected['subnet_cidr'],
+ ip_version=expected['subnet_version']),
+ self.router()
+ ) as (ikepolicy, ipsecpolicy, subnet, router):
+ with self.vpnservice(name=expected['vpnsname'], subnet=subnet,
+ router=router) as vpnservice1:
+ expected['vpnservice_id'] = vpnservice1['vpnservice']['id']
+ expected['ikepolicy_id'] = ikepolicy['ikepolicy']['id']
+ expected['ipsecpolicy_id'] = ipsecpolicy['ipsecpolicy']['id']
+ with self.ipsec_site_connection(
+ self.fmt,
+ expected['name'],
+ expected['peer_address'],
+ expected['peer_id'],
+ expected['peer_cidrs'],
+ expected['mtu'],
+ expected['psk'],
+ expected['initiator'],
+ expected['action'],
+ expected['interval'],
+ expected['timeout'],
+ vpnservice1,
+ ikepolicy,
+ ipsecpolicy,
+ expected['admin_state_up'],
+ description=expected['description']
+ ) as ipsec_site_connection:
+ data = {'ipsec_site_connection': update}
+ if expected.get('make_active'):
+ 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 = req.get_response(self.ext_api)
+ self.assertEqual(expected_status_int, res.status_int)
+ if expected_status_int == 200:
+ res_dict = self.deserialize(self.fmt, res)
+ for k, v in update.items():
+ self.assertEqual(
+ res_dict['ipsec_site_connection'][k], v)
+
+ def test_update_ipsec_site_connection(self):
+ """Test case for valid updates to IPSec site connection."""
+ dpd = {'action': 'hold',
+ 'interval': 40,
+ 'timeout': 120}
+ self._test_update_ipsec_site_connection(update={'dpd': dpd})
+ self._test_update_ipsec_site_connection(update={'mtu': 2000})
+
+ 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)