OpenStack Networking (Neutron)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

271 lines
12 KiB

# Copyright 2013, Nachi Ueno, NTT I3, Inc.
# 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.
import mock
# TODO(pcm): Uncomment once oslo.messaging 1.4.0.0a2 or newer is available
# from oslo.config import cfg
from neutron import context as n_ctx
from neutron.db import l3_db
from neutron.db.vpn import vpn_validator
from neutron.extensions import vpnaas
from neutron.openstack.common import uuidutils
from neutron.plugins.common import constants
# TODO(pcm): Uncomment once oslo.messaging 1.4.0.0a2 or newer is available
# from neutron.services.vpn import plugin as vpn_plugin
from neutron.services.vpn.service_drivers import ipsec as ipsec_driver
from neutron.tests import base
_uuid = uuidutils.generate_uuid
FAKE_SERVICE_ID = _uuid()
FAKE_VPN_CONNECTION = {
'vpnservice_id': FAKE_SERVICE_ID
}
FAKE_ROUTER_ID = _uuid()
FAKE_VPN_SERVICE = {
'router_id': FAKE_ROUTER_ID
}
FAKE_HOST = 'fake_host'
FAKE_ROUTER = {l3_db.EXTERNAL_GW_INFO: FAKE_ROUTER_ID}
FAKE_SUBNET_ID = _uuid()
IPV4 = 4
IPV6 = 6
IPSEC_SERVICE_DRIVER = ('neutron.services.vpn.service_drivers.'
'ipsec.IPsecVPNDriver')
# TODO(pcm): Uncomment, once oslo.messaging package 1.4.0.0a2 or
# newer is released and available for Neutron.
#
# class TestValidatorSelection(base.BaseTestCase):
#
# def setUp(self):
# super(TestValidatorSelection, self).setUp()
# vpnaas_provider = (constants.VPN + ':vpnaas:' +
# IPSEC_SERVICE_DRIVER + ':default')
# cfg.CONF.set_override('service_provider',
# [vpnaas_provider],
# 'service_providers')
# mock.patch('neutron.common.rpc.create_connection').start()
# self.vpn_plugin = vpn_plugin.VPNDriverPlugin()
#
# def test_reference_driver_used(self):
# self.assertIsInstance(self.vpn_plugin._get_validator(),
# vpn_validator.VpnReferenceValidator)
class TestIPsecDriverValidation(base.BaseTestCase):
def setUp(self):
super(TestIPsecDriverValidation, self).setUp()
self.l3_plugin = mock.Mock()
mock.patch(
'neutron.manager.NeutronManager.get_service_plugins',
return_value={constants.L3_ROUTER_NAT: self.l3_plugin}).start()
self.core_plugin = mock.Mock()
mock.patch('neutron.manager.NeutronManager.get_plugin',
return_value=self.core_plugin).start()
self.context = n_ctx.Context('some_user', 'some_tenant')
self.validator = vpn_validator.VpnReferenceValidator()
def test_non_public_router_for_vpn_service(self):
"""Failure test of service validate, when router missing ext. I/F."""
self.l3_plugin.get_router.return_value = {} # No external gateway
vpnservice = {'router_id': 123, 'subnet_id': 456}
self.assertRaises(vpnaas.RouterIsNotExternal,
self.validator.validate_vpnservice,
self.context, vpnservice)
def test_subnet_not_connected_for_vpn_service(self):
"""Failure test of service validate, when subnet not on router."""
self.l3_plugin.get_router.return_value = FAKE_ROUTER
self.core_plugin.get_ports.return_value = None
vpnservice = {'router_id': FAKE_ROUTER_ID, 'subnet_id': FAKE_SUBNET_ID}
self.assertRaises(vpnaas.SubnetIsNotConnectedToRouter,
self.validator.validate_vpnservice,
self.context, vpnservice)
def test_defaults_for_ipsec_site_connections_on_create(self):
"""Check that defaults are applied correctly.
MTU has a default and will always be present on create.
However, the DPD settings do not have a default, so
database create method will assign default values for any
missing. In addition, the DPD dict will be flattened
for storage into the database, so we'll do it as part of
assigning defaults.
"""
ipsec_sitecon = {}
self.validator.assign_sensible_ipsec_sitecon_defaults(ipsec_sitecon)
expected = {
'dpd_action': 'hold',
'dpd_timeout': 120,
'dpd_interval': 30
}
self.assertEqual(expected, ipsec_sitecon)
ipsec_sitecon = {'dpd': {'interval': 50}}
self.validator.assign_sensible_ipsec_sitecon_defaults(ipsec_sitecon)
expected = {
'dpd': {'interval': 50},
'dpd_action': 'hold',
'dpd_timeout': 120,
'dpd_interval': 50
}
self.assertEqual(expected, ipsec_sitecon)
def test_defaults_for_ipsec_site_connections_on_update(self):
"""Check that defaults are used for any values not specified."""
ipsec_sitecon = {}
prev_connection = {'dpd_action': 'clear',
'dpd_timeout': 500,
'dpd_interval': 250}
self.validator.assign_sensible_ipsec_sitecon_defaults(ipsec_sitecon,
prev_connection)
expected = {
'dpd_action': 'clear',
'dpd_timeout': 500,
'dpd_interval': 250
}
self.assertEqual(expected, ipsec_sitecon)
ipsec_sitecon = {'dpd': {'timeout': 200}}
prev_connection = {'dpd_action': 'clear',
'dpd_timeout': 500,
'dpd_interval': 100}
self.validator.assign_sensible_ipsec_sitecon_defaults(ipsec_sitecon,
prev_connection)
expected = {
'dpd': {'timeout': 200},
'dpd_action': 'clear',
'dpd_timeout': 200,
'dpd_interval': 100
}
self.assertEqual(expected, ipsec_sitecon)
def test_bad_dpd_settings_on_create(self):
"""Failure tests of DPD settings for IPSec conn during create."""
ipsec_sitecon = {'mtu': 1500, 'dpd_action': 'hold',
'dpd_interval': 100, 'dpd_timeout': 100}
self.assertRaises(vpnaas.IPsecSiteConnectionDpdIntervalValueError,
self.validator.validate_ipsec_site_connection,
self.context, ipsec_sitecon, IPV4)
ipsec_sitecon = {'mtu': 1500, 'dpd_action': 'hold',
'dpd_interval': 100, 'dpd_timeout': 99}
self.assertRaises(vpnaas.IPsecSiteConnectionDpdIntervalValueError,
self.validator.validate_ipsec_site_connection,
self.context, ipsec_sitecon, IPV4)
def test_bad_dpd_settings_on_update(self):
"""Failure tests of DPD settings for IPSec conn. during update.
Note: On an update, the user may specify only some of the DPD settings.
Previous values will be assigned for any missing items, so by the
time the validation occurs, all items will be available for checking.
The MTU may not be provided, during validation and will be ignored,
if that is the case.
"""
prev_connection = {'mtu': 2000,
'dpd_action': 'hold',
'dpd_interval': 100,
'dpd_timeout': 120}
ipsec_sitecon = {'dpd': {'interval': 120}}
self.validator.assign_sensible_ipsec_sitecon_defaults(ipsec_sitecon,
prev_connection)
self.assertRaises(vpnaas.IPsecSiteConnectionDpdIntervalValueError,
self.validator.validate_ipsec_site_connection,
self.context, ipsec_sitecon, IPV4)
prev_connection = {'mtu': 2000,
'dpd_action': 'hold',
'dpd_interval': 100,
'dpd_timeout': 120}
ipsec_sitecon = {'dpd': {'timeout': 99}}
self.validator.assign_sensible_ipsec_sitecon_defaults(ipsec_sitecon,
prev_connection)
self.assertRaises(vpnaas.IPsecSiteConnectionDpdIntervalValueError,
self.validator.validate_ipsec_site_connection,
self.context, ipsec_sitecon, IPV4)
def test_bad_mtu_for_ipsec_connection(self):
"""Failure test of invalid MTU values for IPSec conn create/update."""
ip_version_limits = vpn_validator.VpnReferenceValidator.IP_MIN_MTU
for version, limit in ip_version_limits.items():
ipsec_sitecon = {'mtu': limit - 1,
'dpd_action': 'hold',
'dpd_interval': 100,
'dpd_timeout': 120}
self.assertRaises(
vpnaas.IPsecSiteConnectionMtuError,
self.validator.validate_ipsec_site_connection,
self.context, ipsec_sitecon, version)
class TestIPsecDriver(base.BaseTestCase):
def setUp(self):
super(TestIPsecDriver, self).setUp()
mock.patch('neutron.common.rpc.create_connection').start()
l3_agent = mock.Mock()
l3_agent.host = FAKE_HOST
plugin = mock.Mock()
plugin.get_l3_agents_hosting_routers.return_value = [l3_agent]
plugin_p = mock.patch('neutron.manager.NeutronManager.get_plugin')
get_plugin = plugin_p.start()
get_plugin.return_value = plugin
service_plugin_p = mock.patch(
'neutron.manager.NeutronManager.get_service_plugins')
get_service_plugin = service_plugin_p.start()
get_service_plugin.return_value = {constants.L3_ROUTER_NAT: plugin}
service_plugin = mock.Mock()
service_plugin.get_l3_agents_hosting_routers.return_value = [l3_agent]
service_plugin._get_vpnservice.return_value = {
'router_id': _uuid()
}
self.driver = ipsec_driver.IPsecVPNDriver(service_plugin)
def _test_update(self, func, args):
ctxt = n_ctx.Context('', 'somebody')
with mock.patch.object(self.driver.agent_rpc, 'cast') as cast:
func(ctxt, *args)
cast.assert_called_once_with(
ctxt,
{'args': {},
'namespace': None,
'method': 'vpnservice_updated'},
version='1.0',
topic='ipsec_agent.fake_host')
def test_create_ipsec_site_connection(self):
self._test_update(self.driver.create_ipsec_site_connection,
[FAKE_VPN_CONNECTION])
def test_update_ipsec_site_connection(self):
self._test_update(self.driver.update_ipsec_site_connection,
[FAKE_VPN_CONNECTION, FAKE_VPN_CONNECTION])
def test_delete_ipsec_site_connection(self):
self._test_update(self.driver.delete_ipsec_site_connection,
[FAKE_VPN_CONNECTION])
def test_update_vpnservice(self):
self._test_update(self.driver.update_vpnservice,
[FAKE_VPN_SERVICE, FAKE_VPN_SERVICE])
def test_delete_vpnservice(self):
self._test_update(self.driver.delete_vpnservice,
[FAKE_VPN_SERVICE])