Merge "Scenario test for vpnaas: ipsec-site-connection"

This commit is contained in:
Jenkins 2015-07-16 16:17:09 +00:00 committed by Gerrit Code Review
commit 22468ce55d

View File

@ -10,17 +10,310 @@
# License for the specific language governing permissions and limitations
# under the License.
# NOTE: The purpose of this module is to provide nop tests to verify that
# the functional gate is working.
# TODO(pcm): In the future, this will be replaced with a real scenario test.
import copy
import os
import fixtures
import mock
import netaddr
from neutron.agent.common import config as agent_config
from neutron.agent import l3_agent as l3_agent_main
from neutron.agent.linux import ip_lib
from neutron.agent.linux import utils as linux_utils
from neutron.common import config as common_config
from neutron.common import utils as common_utils
from neutron.plugins.common import constants
from neutron.services.provider_configuration import serviceprovider_opts
from neutron.tests.common import net_helpers
from neutron.tests.functional import base
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import uuidutils
from neutron_vpnaas.services.vpn import agent as vpn_agent
from neutron_vpnaas.services.vpn.agent import vpn_agent_opts
from neutron_vpnaas.services.vpn.device_drivers import ipsec
_uuid = uuidutils.generate_uuid
FAKE_IKE_POLICY = {
'auth_algorithm': 'sha1',
"ike_version": "v1",
'encryption_algorithm': 'aes-128',
'pfs': 'group5',
'phase1_negotiation_mode': 'main',
'lifetime_units': 'seconds',
'lifetime_value': 3600
}
FAKE_IPSEC_POLICY = {
"encapsulation_mode": "tunnel",
"encryption_algorithm": "aes-128",
"pfs": "group5",
"lifetime_units": "seconds",
"lifetime_value": 3600,
"transform_protocol": "esp",
"auth_algorithm": "sha1",
}
FAKE_VPN_SERVICE = {
"id": _uuid(),
"router_id": _uuid(),
"status": constants.PENDING_CREATE,
"admin_state_up": True,
'external_ip': "172.24.4.8",
'subnet': {'cidr': "10.100.255.224/28"}
}
FAKE_IPSEC_CONNECTION = {
"vpnservice_id": _uuid(),
"status": "PENDING_CREATE",
"psk": "969022489",
"initiator": "bi-directional",
"admin_state_up": True,
"auth_mode": "psk",
'external_ip': "172.24.4.8",
"peer_cidrs": ["10.100.255.224/28"],
"mtu": 1500,
"dpd_action": "hold",
"dpd_interval": 30,
"dpd_timeout": 120,
"route_mode": "static",
"ikepolicy": FAKE_IKE_POLICY,
"ipsecpolicy": FAKE_IPSEC_POLICY,
"peer_address": "172.24.4.8",
"peer_id": "172.24.4.8",
"id": _uuid()
}
PUBLIC_NET = netaddr.IPNetwork('19.4.4.0/24')
PRIVATE_NET = netaddr.IPNetwork('35.4.0.0/16')
FAKE_PUBLIC_SUBNET_ID = _uuid()
FAKE_PRIVATE_SUBNET_ID = _uuid()
MAC_BASE = cfg.CONF.base_mac.split(':')
FAKE_ROUTER = {
'id': _uuid(),
'_interfaces': [
{
'id': _uuid(),
'admin_state_up': True,
'network_id': _uuid(),
'mac_address': common_utils.get_random_mac(MAC_BASE),
'subnets': [
{
'ipv6_ra_mode': None,
'cidr': str(PRIVATE_NET),
'gateway_ip': str(PRIVATE_NET[1]),
'id': FAKE_PRIVATE_SUBNET_ID,
'ipv6_address_mode': None
}
],
'fixed_ips': [
{
'subnet_id': FAKE_PRIVATE_SUBNET_ID,
'prefixlen': 24,
'ip_address': PRIVATE_NET[4]
}
]
}
],
'enable_snat': True,
'gw_port': {
'network_id': _uuid(),
'subnets': [
{
'cidr': str(PUBLIC_NET),
'gateway_ip': str(PUBLIC_NET[1]),
'id': FAKE_PUBLIC_SUBNET_ID
}
],
'fixed_ips': [
{
'subnet_id': FAKE_PUBLIC_SUBNET_ID,
'prefixlen': PUBLIC_NET.prefixlen,
'ip_address': str(PUBLIC_NET[4])
}
],
'id': _uuid(),
'mac_address': common_utils.get_random_mac(MAC_BASE)
},
'distributed': False,
'_floatingips': [],
'routes': []
}
class RouterFixture(fixtures.Fixture):
def __init__(self, l3_agent, public_ip, private_cidr):
self.l3_agent = l3_agent
self.router_info = self._generate_info(public_ip, private_cidr)
self.router_id = self.router_info['id']
def setUp(self):
super(RouterFixture, self).setUp()
self.l3_agent._process_added_router(self.router_info)
self.router = self.l3_agent.router_info[self.router_id]
self.addCleanup(self.l3_agent._router_removed, self.router_id)
def _generate_info(self, public_ip, private_cidr):
info = copy.deepcopy(FAKE_ROUTER)
info['id'] = _uuid()
info['_interfaces'][0]['id'] = _uuid()
(info['_interfaces'][0]
['mac_address']) = common_utils.get_random_mac(MAC_BASE)
(info['_interfaces'][0]['fixed_ips'][0]
['ip_address']) = str(private_cidr[4])
info['_interfaces'][0]['subnets'][0].update({
'cidr': str(private_cidr),
'gateway_ip': str(private_cidr[1])})
info['gw_port']['id'] = _uuid()
info['gw_port']['fixed_ips'][0]['ip_address'] = str(public_ip)
info['gw_port']['mac_address'] = common_utils.get_random_mac(MAC_BASE)
return info
class TestIPSecScenario(base.BaseSudoTestCase):
"""Test end-to-end IPSec connection."""
vpn_agent_ini = os.environ.get('VPN_AGENT_INI',
'/etc/neutron/vpn_agent.ini')
def test_dummy(self):
pass
def setUp(self):
super(TestIPSecScenario, self).setUp()
mock.patch('neutron.agent.l3.agent.L3PluginApi').start()
cfg.CONF.set_override('debug', True)
agent_config.setup_logging()
config = cfg.ConfigOpts()
config.register_opts(common_config.core_opts)
config.register_opts(common_config.core_cli_opts)
logging.register_options(config)
agent_config.register_process_monitor_opts(config)
l3_agent_main.register_opts(config)
config.set_override(
'interface_driver',
'neutron.agent.linux.interface.OVSInterfaceDriver')
config.set_override('router_delete_namespaces', True)
config.register_opts(serviceprovider_opts, 'service_providers')
config.register_opts(vpn_agent_opts, 'vpnagent')
config.register_opts(ipsec.ipsec_opts, 'ipsec')
config.register_opts(ipsec.openswan_opts, 'openswan')
config.set_override('state_path', self.get_new_temp_dir().path)
self.br_int = self.useFixture(net_helpers.OVSBridgeFixture()).bridge
self.br_ex = self.useFixture(net_helpers.OVSBridgeFixture()).bridge
config.set_override('ovs_integration_bridge', self.br_int.br_name)
config.set_override('external_network_bridge', self.br_ex.br_name)
config(['--config-file', self.vpn_agent_ini])
self.vpn_agent = vpn_agent.VPNAgent('agent1', config)
# Assign ip address to br-ex port because it is a gateway
ex_port = ip_lib.IPDevice(self.br_ex.br_name)
ex_port.addr.add(str(PUBLIC_NET[1]))
def prepare_vpn_service_info(self, router_id, external_ip, subnet_cidr):
service = copy.deepcopy(FAKE_VPN_SERVICE)
service.update({
'id': _uuid(),
'router_id': router_id,
'external_ip': str(external_ip),
'subnet': {'cidr': str(subnet_cidr)}})
return service
def prepare_ipsec_conn_info(self, vpn_service, peer_vpn_service):
ipsec_conn = copy.deepcopy(FAKE_IPSEC_CONNECTION)
ipsec_conn.update({
'id': _uuid(),
'vpnservice_id': vpn_service['id'],
'external_ip': vpn_service['external_ip'],
'peer_cidrs': [peer_vpn_service['subnet']['cidr']],
'peer_address': peer_vpn_service['external_ip'],
'peer_id': peer_vpn_service['external_ip']
})
vpn_service['ipsec_site_connections'] = [ipsec_conn]
def port_setup(self, router):
"""Creates namespace and a port inside it on a client site."""
client_ns = self.useFixture(net_helpers.NamespaceFixture()).ip_wrapper
router_ip_cidr = self._port_first_ip_cidr(router.internal_ports[0])
port_ip_cidr = net_helpers.increment_ip_cidr(router_ip_cidr)
port = self.useFixture(
net_helpers.OVSPortFixture(self.br_int, client_ns.namespace)).port
port.addr.add(port_ip_cidr)
port.route.add_gateway(router_ip_cidr.partition('/')[0])
return client_ns.namespace, port_ip_cidr.partition('/')[0]
def _port_first_ip_cidr(self, port):
fixed_ip = port['fixed_ips'][0]
return common_utils.ip_to_cidr(fixed_ip['ip_address'],
fixed_ip['prefixlen'])
def site_setup(self, router_public_ip, private_net_cidr):
router = self.useFixture(
RouterFixture(self.vpn_agent, router_public_ip,
private_net_cidr)).router
port_namespace, port_ip = self.port_setup(router)
vpn_service = self.prepare_vpn_service_info(
router.router_id, router_public_ip, private_net_cidr)
return {"router": router, "port_namespace": port_namespace,
"port_ip": port_ip, "vpn_service": vpn_service}
def _ping(self, namespace, ip):
"""Pings ip address from network namespace.
In order to ping it uses following cli command:
ip netns exec <namespace> ping -c 4 -q <ip>
"""
try:
count = 4
cmd = ['ping', '-w', 2 * count, '-c', count, ip]
cmd = ip_lib.add_namespace_to_cmd(cmd, namespace)
linux_utils.execute(cmd, run_as_root=True)
return True
except RuntimeError:
return False
def test_ipsec_site_connections(self):
device = self.vpn_agent.device_drivers[0]
# Mock the method below because it causes Exception:
# RuntimeError: Second simultaneous read on fileno 5 detected.
# Unless you really know what you're doing, make sure that only
# one greenthread can read any particular socket. Consider using
# a pools.Pool. If you do know what you're doing and want to disable
# this error, call eventlet.debug.hub_prevent_multiple_readers(False)
# Can reproduce the exception in the test only
ip_lib.send_ip_addr_adv_notif = mock.Mock()
# There are no vpn services yet. get_vpn_services_on_host returns
# empty list
device.agent_rpc.get_vpn_services_on_host = mock.Mock(
return_value=[])
# instantiate network resources "router", "private network"
private_nets = list(PRIVATE_NET.subnet(24))
site1 = self.site_setup(PUBLIC_NET[4], private_nets[1])
site2 = self.site_setup(PUBLIC_NET[5], private_nets[2])
# build vpn resources
self.prepare_ipsec_conn_info(site1['vpn_service'],
site2['vpn_service'])
self.prepare_ipsec_conn_info(site2['vpn_service'],
site1['vpn_service'])
device.report_status = mock.Mock()
device.agent_rpc.get_vpn_services_on_host = mock.Mock(
return_value=[site1['vpn_service'],
site2['vpn_service']])
self.assertFalse(self._ping(site1['port_namespace'], site2['port_ip']))
self.assertFalse(self._ping(site2['port_namespace'], site1['port_ip']))
device.sync(mock.Mock(), [{'id': site1['router'].router_id},
{'id': site2['router'].router_id}])
self.addCleanup(
device._delete_vpn_processes,
[site1['router'].router_id, site2['router'].router_id], [])
self.assertTrue(self._ping(site1['port_namespace'], site2['port_ip']))
self.assertTrue(self._ping(site2['port_namespace'], site1['port_ip']))