NSX-v: Fix VPNaaS driver

Commit I0095e160481f1d4572e38ad1d3bbc8e183039b84 introduced some
changes to the VPNaaS driver and validator apis.
This patch closses this gap.

Change-Id: I46d2381e3a0b05551518d41a3f9957a1b9d2b834
This commit is contained in:
Adit Sarfaty 2017-12-25 13:23:06 +02:00
parent 97138d346a
commit cc098fddb1
4 changed files with 151 additions and 46 deletions

View File

@ -3899,7 +3899,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
vpn_plugin = directory.get_plugin(plugin_const.VPN)
if vpn_plugin:
vpn_driver = vpn_plugin.ipsec_driver
vpn_driver = vpn_plugin.drivers[vpn_plugin.default_provider]
vpn_rules = (
vpn_driver._generate_ipsecvpn_firewall_rules(edge_id))
fw_rules.extend(vpn_rules)

View File

@ -14,10 +14,10 @@
# under the License.
import netaddr
from neutron_lib import exceptions as n_exc
from neutron_lib.plugins import directory
from neutron_vpnaas.services.vpn import service_drivers
from oslo_log import log as logging
from oslo_utils import excutils
from vmware_nsx._i18n import _
from vmware_nsx.common import exceptions as nsxv_exc
@ -47,9 +47,6 @@ class NSXvIPsecVpnDriver(service_drivers.VpnDriver):
def service_type(self):
return IPSEC
def _is_shared_router(self, router):
return router.get('router_type') == nsxv_constants.SHARED
def _get_router_edge_id(self, context, vpnservice_id):
vpnservice = self.service_plugin._get_vpnservice(context,
vpnservice_id)
@ -122,7 +119,7 @@ class NSXvIPsecVpnDriver(service_drivers.VpnDriver):
peer_subnets = site['peerSubnets']['subnets']
local_subnets = site['localSubnets']['subnets']
ipsec_vpn_fw_rules.append({
'name': 'VPN ' + site['name'],
'name': 'VPN ' + site.get('name', 'rule'),
'action': 'allow',
'enabled': True,
'source_ip_address': peer_subnets,
@ -155,8 +152,6 @@ class NSXvIPsecVpnDriver(service_drivers.VpnDriver):
def create_ipsec_site_connection(self, context, ipsec_site_connection):
LOG.debug('Creating ipsec site connection %(conn_info)s.',
{"conn_info": ipsec_site_connection})
self.validator.validate_ipsec_conn(context, ipsec_site_connection)
new_ipsec = self._convert_ipsec_conn(context, ipsec_site_connection)
vpnservice_id = ipsec_site_connection['vpnservice_id']
edge_id = self._get_router_edge_id(context, vpnservice_id)[1]
@ -314,16 +309,13 @@ class NSXvIPsecVpnDriver(service_drivers.VpnDriver):
def create_vpnservice(self, context, vpnservice):
LOG.debug('Creating VPN service %(vpn)s', {'vpn': vpnservice})
# Only support distributed and exclusive router type
router_id = vpnservice['router_id']
vpnservice_id = vpnservice['id']
router = self._core_plugin.get_router(context, router_id)
if self._is_shared_router(router):
# Rolling back change on the neutron
self.service_plugin.delete_vpnservice(context, vpnservice_id)
msg = _("Router type is not supported for VPN service, only "
"support distributed and exclusive router")
raise n_exc.InvalidInput(error_message=msg)
try:
self.validator.validate_vpnservice(context, vpnservice)
except Exception:
with excutils.save_and_reraise_exception():
# Rolling back change on the neutron
self.service_plugin.delete_vpnservice(context, vpnservice_id)
vpnservice = self.service_plugin._get_vpnservice(context,
vpnservice_id)

View File

@ -79,15 +79,48 @@ class IPsecValidator(vpn_validator.VpnReferenceValidator):
"VSE!")
break
def validate_ipsec_conn(self, context, ipsec_site_conn):
ike_policy_id = ipsec_site_conn['ikepolicy_id']
ipsec_policy_id = ipsec_site_conn['ipsecpolicy_id']
ipsecpolicy = self.vpn_plugin.get_ipsecpolicy(context,
ipsec_policy_id)
ikepolicy = self.vpn_plugin.get_ikepolicy(context,
ike_policy_id)
self.validate_ikepolicy_version(ikepolicy)
self.validate_ikepolicy_pfs(ikepolicy)
self.validate_encryption_algorithm(ikepolicy)
self.validate_ipsec_policy(context, ipsecpolicy)
self.validate_policies_matching_algorithms(ikepolicy, ipsecpolicy)
def _is_shared_router(self, router):
return router.get('router_type') == nsxv_constants.SHARED
def _validate_router(self, context, router_id):
# Only support distributed and exclusive router type
router = self.core_plugin.get_router(context, router_id)
if self._is_shared_router(router):
msg = _("Router type is not supported for VPN service, only "
"support distributed and exclusive router")
raise nsxv_exc.NsxVpnValidationError(details=msg)
def validate_vpnservice(self, context, vpnservice):
"""Called upon create/update of a service"""
# Call general validations
super(IPsecValidator, self).validate_vpnservice(
context, vpnservice)
# Call specific NSX validations
self._validate_router(context, vpnservice['router_id'])
if not vpnservice['subnet_id']:
# we currently do not support multiple subnets so a subnet must
# be defined
msg = _("Subnet must be defined in a service")
raise nsxv_exc.NsxVpnValidationError(details=msg)
def validate_ipsec_site_connection(self, context, ipsec_site_conn):
ike_policy_id = ipsec_site_conn.get('ikepolicy_id')
if ike_policy_id:
ikepolicy = self.vpn_plugin.get_ikepolicy(context,
ike_policy_id)
self.validate_ikepolicy_version(ikepolicy)
self.validate_ikepolicy_pfs(ikepolicy)
self.validate_encryption_algorithm(ikepolicy)
ipsec_policy_id = ipsec_site_conn.get('ipsecpolicy_id')
if ipsec_policy_id:
ipsecpolicy = self.vpn_plugin.get_ipsecpolicy(context,
ipsec_policy_id)
self.validate_ipsec_policy(context, ipsecpolicy)
if ike_policy_id and ipsec_policy_id:
self.validate_policies_matching_algorithms(ikepolicy, ipsecpolicy)

View File

@ -16,10 +16,12 @@
import contextlib
import mock
from neutron_lib.api.definitions import external_net as extnet_apidef
from neutron_lib import context
from neutron_lib import exceptions as n_exc
from neutron_lib.plugins import directory
from neutron_vpnaas.db.vpn import vpn_models # noqa
from neutron_vpnaas.extensions import vpnaas
from oslo_utils import uuidutils
from vmware_nsx.common import exceptions as nsxv_exc
@ -66,7 +68,6 @@ class TestVpnaasDriver(test_plugin.NsxVPluginV2TestCase):
router = self.l3plugin.create_router(self.context, request)
yield router
@mock.patch('%s.validate_ipsec_conn' % VALI_PATH)
@mock.patch('%s._convert_ipsec_conn' % DRIVER_PATH)
@mock.patch('%s._get_router_edge_id' % DRIVER_PATH)
@mock.patch('%s._generate_new_sites' % DRIVER_PATH)
@ -77,15 +78,12 @@ class TestVpnaasDriver(test_plugin.NsxVPluginV2TestCase):
mock_update_status,
mock_update_ipsec, mock_gen_new,
mock_get_id,
mock_conv_ipsec,
mock_val_conn):
mock_conv_ipsec):
mock_get_id.return_value = (FAKE_ROUTER_ID, FAKE_EDGE_ID)
mock_conv_ipsec.return_value = FAKE_IPSEC_VPN_SITE
mock_gen_new.return_value = FAKE_IPSEC_VPN_SITE
self.driver.create_ipsec_site_connection(self.context,
FAKE_IPSEC_CONNECTION)
mock_val_conn.assert_called_with(self.context,
FAKE_IPSEC_CONNECTION)
mock_conv_ipsec.assert_called_with(self.context,
FAKE_IPSEC_CONNECTION)
mock_get_id.assert_called_with(self.context, FAKE_VPNSERVICE_ID)
@ -100,7 +98,6 @@ class TestVpnaasDriver(test_plugin.NsxVPluginV2TestCase):
FAKE_IPSEC_CONNECTION["id"],
"ACTIVE")
@mock.patch('%s.validate_ipsec_conn' % VALI_PATH)
@mock.patch('%s._convert_ipsec_conn' % DRIVER_PATH)
@mock.patch('%s._get_router_edge_id' % DRIVER_PATH)
@mock.patch('%s._generate_new_sites' % DRIVER_PATH)
@ -110,8 +107,7 @@ class TestVpnaasDriver(test_plugin.NsxVPluginV2TestCase):
mock_update_status,
mock_update_ipsec,
mock_gen_new, mock_get_id,
mock_conv_ipsec,
mock_val_conn):
mock_conv_ipsec):
mock_get_id.return_value = (FAKE_ROUTER_ID, FAKE_EDGE_ID)
mock_conv_ipsec.return_value = FAKE_IPSEC_VPN_SITE
mock_gen_new.return_value = FAKE_IPSEC_VPN_SITE
@ -120,7 +116,6 @@ class TestVpnaasDriver(test_plugin.NsxVPluginV2TestCase):
self.assertRaises(nsxv_exc.NsxPluginException,
self.driver.create_ipsec_site_connection,
self.context, FAKE_IPSEC_CONNECTION)
mock_val_conn.assert_called_with(self.context, FAKE_IPSEC_CONNECTION)
mock_conv_ipsec.assert_called_with(self.context, FAKE_IPSEC_CONNECTION)
mock_get_id.assert_called_with(self.context, FAKE_VPNSERVICE_ID)
mock_gen_new.assert_called_with(FAKE_EDGE_ID, FAKE_IPSEC_VPN_SITE)
@ -133,7 +128,6 @@ class TestVpnaasDriver(test_plugin.NsxVPluginV2TestCase):
FAKE_IPSEC_CONNECTION["id"],
"ERROR")
@mock.patch('%s.validate_ipsec_conn' % VALI_PATH)
@mock.patch('%s._convert_ipsec_conn' % DRIVER_PATH)
@mock.patch('%s._get_router_edge_id' % DRIVER_PATH)
@mock.patch('%s._generate_new_sites' % DRIVER_PATH)
@ -142,7 +136,7 @@ class TestVpnaasDriver(test_plugin.NsxVPluginV2TestCase):
@mock.patch('%s._update_firewall_rules' % DRIVER_PATH)
def test_update_fw_fail(self, mock_update_fw, mock_update_status,
mock_update_ipsec, mock_gen_new,
mock_get_id, mock_conv_ipsec, mock_val_conn):
mock_get_id, mock_conv_ipsec):
mock_get_id.return_value = (FAKE_ROUTER_ID, FAKE_EDGE_ID)
mock_conv_ipsec.return_value = FAKE_IPSEC_VPN_SITE
mock_gen_new.return_value = FAKE_IPSEC_VPN_SITE
@ -151,7 +145,6 @@ class TestVpnaasDriver(test_plugin.NsxVPluginV2TestCase):
self.assertRaises(nsxv_exc.NsxPluginException,
self.driver.create_ipsec_site_connection,
self.context, FAKE_IPSEC_CONNECTION)
mock_val_conn.assert_called_with(self.context, FAKE_IPSEC_CONNECTION)
mock_conv_ipsec.assert_called_with(self.context, FAKE_IPSEC_CONNECTION)
mock_get_id.assert_called_with(self.context, FAKE_VPNSERVICE_ID)
mock_gen_new.assert_called_with(FAKE_EDGE_ID, FAKE_IPSEC_VPN_SITE)
@ -246,10 +239,97 @@ class TestVpnaasDriver(test_plugin.NsxVPluginV2TestCase):
FAKE_IPSEC_CONNECTION["id"],
"ERROR")
def test_create_vpn_service_on_shared_router(self):
with self.router(router_type='shared') as router, self.subnet():
def test_create_vpn_service_legal(self):
"""Create a legal vpn service"""
# create an external network with a subnet, and an exclusive router
providernet_args = {extnet_apidef.EXTERNAL: True}
with self.network(name='ext-net',
providernet_args=providernet_args,
arg_list=(extnet_apidef.EXTERNAL, )) as ext_net,\
self.subnet(ext_net),\
self.router(router_type='exclusive',
external_gateway_info={'network_id':
ext_net['network']['id']}) as router,\
self.subnet() as sub:
# add an interface to the router
self.l3plugin.add_router_interface(
self.context,
router['id'],
{'subnet_id': sub['subnet']['id']})
# create the service
vpnservice = {'router_id': router['id'],
'id': _uuid()}
self.assertRaises(n_exc.InvalidInput,
'id': _uuid(),
'subnet_id': sub['subnet']['id']}
with mock.patch.object(self.driver, '_get_gateway_ips',
return_value=(None, None)):
self.driver.create_vpnservice(self.context, vpnservice)
def test_create_vpn_service_on_shared_router(self):
"""Creating a service with shared router is not allowed"""
# create an external network with a subnet, and a shared router
providernet_args = {extnet_apidef.EXTERNAL: True}
with self.network(name='ext-net',
providernet_args=providernet_args,
arg_list=(extnet_apidef.EXTERNAL, )) as ext_net,\
self.subnet(ext_net),\
self.router(router_type='shared',
external_gateway_info={'network_id':
ext_net['network']['id']}) as router,\
self.subnet() as sub:
# add an interface to the router
self.l3plugin.add_router_interface(
self.context,
router['id'],
{'subnet_id': sub['subnet']['id']})
# create the service
vpnservice = {'router_id': router['id'],
'id': _uuid(),
'subnet_id': sub['subnet']['id']}
self.assertRaises(nsxv_exc.NsxPluginException,
self.driver.create_vpnservice,
self.context, vpnservice)
def test_create_vpn_service_on_router_without_if(self):
"""Creating a service with unattached subnet is not allowed"""
# create an external network with a subnet, and an exclusive router
providernet_args = {extnet_apidef.EXTERNAL: True}
with self.network(name='ext-net',
providernet_args=providernet_args,
arg_list=(extnet_apidef.EXTERNAL, )) as ext_net,\
self.subnet(ext_net),\
self.router(router_type='exclusive',
external_gateway_info={'network_id':
ext_net['network']['id']}) as router,\
self.subnet() as sub:
# create the service
vpnservice = {'router_id': router['id'],
'id': _uuid(),
'subnet_id': sub['subnet']['id']}
self.assertRaises(vpnaas.SubnetIsNotConnectedToRouter,
self.driver.create_vpnservice,
self.context, vpnservice)
def test_create_vpn_service_without_subnet(self):
"""Creating a service without a subnet is not allowed"""
# create an external network with a subnet, and an exclusive router
providernet_args = {extnet_apidef.EXTERNAL: True}
with self.network(name='ext-net',
providernet_args=providernet_args,
arg_list=(extnet_apidef.EXTERNAL, )) as ext_net,\
self.subnet(ext_net),\
self.router(router_type='exclusive',
external_gateway_info={'network_id':
ext_net['network']['id']}) as router,\
self.subnet() as sub:
# add an interface to the router
self.l3plugin.add_router_interface(
self.context,
router['id'],
{'subnet_id': sub['subnet']['id']})
# create the service without the subnet
vpnservice = {'router_id': router['id'],
'id': _uuid(),
'subnet_id': None}
self.assertRaises(nsxv_exc.NsxPluginException,
self.driver.create_vpnservice,
self.context, vpnservice)