Merge "Support advanced NVP IPsec VPN Service"

This commit is contained in:
Jenkins 2014-03-03 22:40:10 +00:00 committed by Gerrit Code Review
commit 78366adca8
8 changed files with 773 additions and 58 deletions

View File

@ -24,6 +24,7 @@ from neutron.db.firewall import firewall_db
from neutron.db import l3_db from neutron.db import l3_db
from neutron.db.loadbalancer import loadbalancer_db from neutron.db.loadbalancer import loadbalancer_db
from neutron.db import routedserviceinsertion_db as rsi_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 firewall as fw_ext
from neutron.extensions import l3 from neutron.extensions import l3
from neutron.extensions import routedserviceinsertion as rsi from neutron.extensions import routedserviceinsertion as rsi
@ -79,7 +80,8 @@ class NsxAdvancedPlugin(sr_db.ServiceRouter_mixin,
base.NsxPluginV2, base.NsxPluginV2,
rsi_db.RoutedServiceInsertionDbMixin, rsi_db.RoutedServiceInsertionDbMixin,
firewall_db.Firewall_db_mixin, firewall_db.Firewall_db_mixin,
loadbalancer_db.LoadBalancerPluginDb loadbalancer_db.LoadBalancerPluginDb,
vpn_db.VPNPluginDb
): ):
supported_extension_aliases = ( supported_extension_aliases = (
@ -87,7 +89,8 @@ class NsxAdvancedPlugin(sr_db.ServiceRouter_mixin,
"service-router", "service-router",
"routed-service-insertion", "routed-service-insertion",
"fwaas", "fwaas",
"lbaas" "lbaas",
"vpnaas"
]) ])
def __init__(self): def __init__(self):
@ -893,7 +896,7 @@ class NsxAdvancedPlugin(sr_db.ServiceRouter_mixin,
self._process_create_resource_router_id( self._process_create_resource_router_id(
context, res, firewall_db.Firewall) context, res, firewall_db.Firewall)
# Since there is only one firewall per edge, # Since there is only one firewall per edge,
#here would be bulk configureation operation on firewall # here would be bulk configuration operation on firewall
self._vcns_update_firewall(context, fw, router_id) self._vcns_update_firewall(context, fw, router_id)
self._firewall_set_status( self._firewall_set_status(
context, fw['id'], service_constants.ACTIVE, fw) context, fw['id'], service_constants.ACTIVE, fw)
@ -1570,6 +1573,153 @@ class NsxAdvancedPlugin(sr_db.ServiceRouter_mixin,
context, loadbalancer_db.Pool, context, loadbalancer_db.Pool,
pool_id, service_constants.ACTIVE) 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): class VcnsCallbacks(object):
"""Edge callback implementation Callback functions for """Edge callback implementation Callback functions for

View File

@ -0,0 +1,149 @@
# 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)

View File

@ -39,6 +39,9 @@ POOL_RESOURCE = "pools"
MONITOR_RESOURCE = "monitors" MONITOR_RESOURCE = "monitors"
APP_PROFILE_RESOURCE = "applicationprofiles" APP_PROFILE_RESOURCE = "applicationprofiles"
# IPsec VPNaaS Constants
IPSEC_VPN_SERVICE = 'ipsec/config'
class Vcns(object): class Vcns(object):
@ -264,6 +267,18 @@ class Vcns(object):
app_profileid) app_profileid)
return self.do_request(HTTP_DELETE, uri) 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, def _build_uri_path(self, edge_id,
service, service,
resource=None, resource=None,

View File

@ -22,6 +22,7 @@ from neutron.openstack.common import log as logging
from neutron.plugins.vmware.common import config # noqa from neutron.plugins.vmware.common import config # noqa
from neutron.plugins.vmware.vshield import edge_appliance_driver 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_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 import edge_loadbalancer_driver
from neutron.plugins.vmware.vshield.tasks import tasks from neutron.plugins.vmware.vshield.tasks import tasks
from neutron.plugins.vmware.vshield import vcns from neutron.plugins.vmware.vshield import vcns
@ -31,7 +32,8 @@ LOG = logging.getLogger(__name__)
class VcnsDriver(edge_appliance_driver.EdgeApplianceDriver, class VcnsDriver(edge_appliance_driver.EdgeApplianceDriver,
edge_firewall_driver.EdgeFirewallDriver, edge_firewall_driver.EdgeFirewallDriver,
edge_loadbalancer_driver.EdgeLbDriver): edge_loadbalancer_driver.EdgeLbDriver,
edge_ipsecvpn_driver.EdgeIPsecVpnDriver):
def __init__(self, callbacks): def __init__(self, callbacks):
super(VcnsDriver, self).__init__() super(VcnsDriver, self).__init__()

View File

@ -32,6 +32,7 @@ from neutron.db.vpn import vpn_db
from neutron import extensions from neutron import extensions
from neutron.extensions import vpnaas from neutron.extensions import vpnaas
from neutron import manager from neutron import manager
from neutron.openstack.common import uuidutils
from neutron.plugins.common import constants from neutron.plugins.common import constants
from neutron.scheduler import l3_agent_scheduler from neutron.scheduler import l3_agent_scheduler
from neutron.services.vpn import plugin as vpn_plugin from neutron.services.vpn import plugin as vpn_plugin
@ -55,34 +56,13 @@ class TestVpnCorePlugin(test_l3_plugin.TestL3NatIntPlugin,
self.router_scheduler = l3_agent_scheduler.ChanceScheduler() self.router_scheduler = l3_agent_scheduler.ChanceScheduler()
class VPNPluginDbTestCase(test_l3_plugin.L3NatTestCaseMixin, class VPNTestMixin(object):
test_db_plugin.NeutronDbPluginV2TestCase):
resource_prefix_map = dict( resource_prefix_map = dict(
(k.replace('_', '-'), (k.replace('_', '-'),
constants.COMMON_PREFIXES[constants.VPN]) constants.COMMON_PREFIXES[constants.VPN])
for k in vpnaas.RESOURCE_ATTRIBUTE_MAP 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, def _create_ikepolicy(self, fmt,
name='ikepolicy1', name='ikepolicy1',
auth_algorithm='sha1', auth_algorithm='sha1',
@ -410,6 +390,53 @@ class VPNPluginDbTestCase(test_l3_plugin.L3NatTestCaseMixin,
'ipsec_site_connection']['id'] '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): class TestVpnaas(VPNPluginDbTestCase):
@ -890,17 +917,6 @@ class TestVpnaas(VPNPluginDbTestCase):
self._delete('routers', router['router']['id'], self._delete('routers', router['router']['id'],
expected_code=webob.exc.HTTPConflict.code) 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): def test_update_vpnservice(self):
"""Test case to update a vpnservice.""" """Test case to update a vpnservice."""
name = 'new_vpnservice1' name = 'new_vpnservice1'
@ -1198,18 +1214,6 @@ class TestVpnaas(VPNPluginDbTestCase):
setup_overrides=ipv6_setup_params, setup_overrides=ipv6_setup_params,
expected_status_int=400) 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): def test_delete_ipsec_site_connection(self):
"""Test case to delete a ipsec_site_connection.""" """Test case to delete a ipsec_site_connection."""
with self.ipsec_site_connection( with self.ipsec_site_connection(

View File

@ -455,11 +455,6 @@ class L3NatTest(test_l3_plugin.L3BaseForIntTests, NsxPluginV2TestCase):
plugin_instance.__class__.__name__) plugin_instance.__class__.__name__)
self._plugin_class = plugin_instance.__class__ self._plugin_class = plugin_instance.__class__
class TestL3NatTestCase(L3NatTest,
test_l3_plugin.L3NatDBIntTestCase,
NsxPluginV2TestCase):
def _create_l3_ext_network(self, vlan_id=None): def _create_l3_ext_network(self, vlan_id=None):
name = 'l3_ext_net' name = 'l3_ext_net'
net_type = NetworkTypes.L3_EXT net_type = NetworkTypes.L3_EXT
@ -474,6 +469,11 @@ class TestL3NatTestCase(L3NatTest,
pnet.PHYSICAL_NETWORK, pnet.PHYSICAL_NETWORK,
pnet.SEGMENTATION_ID)) pnet.SEGMENTATION_ID))
class TestL3NatTestCase(L3NatTest,
test_l3_plugin.L3NatDBIntTestCase,
NsxPluginV2TestCase):
def _test_create_l3_ext_network(self, vlan_id=None): def _test_create_l3_ext_network(self, vlan_id=None):
name = 'l3_ext_net' name = 'l3_ext_net'
net_type = NetworkTypes.L3_EXT net_type = NetworkTypes.L3_EXT

View File

@ -44,6 +44,11 @@ class FakeVcns(object):
"firewallRules": [] "firewallRules": []
} }
} }
self.fake_ipsecvpn_dict = {}
self.temp_ipsecvpn = {
'featureType': "ipsec_4.0",
'enabled': True,
'sites': {'sites': []}}
self._fake_virtualservers_dict = {} self._fake_virtualservers_dict = {}
self._fake_pools_dict = {} self._fake_pools_dict = {}
self._fake_monitors_dict = {} self._fake_monitors_dict = {}
@ -364,9 +369,6 @@ class FakeVcns(object):
break break
return self.return_helper(header, response) return self.return_helper(header, response)
#
#Fake Edge LBAAS call
#
def create_vip(self, edge_id, vip_new): def create_vip(self, edge_id, vip_new):
if not self._fake_virtualservers_dict.get(edge_id): if not self._fake_virtualservers_dict.get(edge_id):
self._fake_virtualservers_dict[edge_id] = {} self._fake_virtualservers_dict[edge_id] = {}
@ -525,6 +527,27 @@ class FakeVcns(object):
response['config'] = self._fake_loadbalancer_config[edge_id] response['config'] = self._fake_loadbalancer_config[edge_id]
return self.return_helper(header, response) 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): def enable_service_loadbalancer(self, edge_id, config):
header = {'status': 204} header = {'status': 204}
response = "" response = ""

View File

@ -0,0 +1,372 @@
# 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)