Support VPNaaS with L3 HA
VPNaaS with a HA router is not supported now. This patch will enable support for VPNaaS with an HA router. When VPN service is created for HA router, it should run only on master node. On transition from master to backup, vpn service should be shutdown (same like disabling radvd) on that agent. On transition from backup to master, vpn service should be enabled and running on that agent. Closes-bug: #1478012 Change-Id: I22f55b72cdc6cf608f50db902e4e3636fd59a16c
This commit is contained in:
parent
819c7b8bec
commit
33c3fd0302
@ -38,6 +38,24 @@ class VPNAgent(l3_agent.L3NATAgentWithStateReport):
|
||||
self.service = vpn_service.VPNService(self)
|
||||
self.device_drivers = self.service.load_device_drivers(host)
|
||||
|
||||
def process_state_change(self, router_id, state):
|
||||
"""Enable the vpn process when router transitioned to master.
|
||||
|
||||
And disable vpn process for backup router.
|
||||
"""
|
||||
for device_driver in self.device_drivers:
|
||||
if router_id in device_driver.processes:
|
||||
process = device_driver.processes[router_id]
|
||||
if state == 'master':
|
||||
process.enable()
|
||||
else:
|
||||
process.disable()
|
||||
|
||||
def enqueue_state_change(self, router_id, state):
|
||||
"""Handle HA router state changes for vpn process"""
|
||||
self.process_state_change(router_id, state)
|
||||
super(VPNAgent, self).enqueue_state_change(router_id, state)
|
||||
|
||||
|
||||
def main():
|
||||
entry.main(manager='neutron_vpnaas.services.vpn.agent.VPNAgent')
|
||||
|
@ -144,7 +144,7 @@ class BaseSwanProcess(object):
|
||||
self.namespace = namespace
|
||||
self.connection_status = {}
|
||||
self.config_dir = os.path.join(
|
||||
cfg.CONF.ipsec.config_base_dir, self.id)
|
||||
self.conf.ipsec.config_base_dir, self.id)
|
||||
self.etc_dir = os.path.join(self.config_dir, 'etc')
|
||||
self.log_dir = os.path.join(self.config_dir, 'logs')
|
||||
self.update_vpnservice(vpnservice)
|
||||
@ -204,7 +204,7 @@ class BaseSwanProcess(object):
|
||||
template = _get_template(template_file)
|
||||
return template.render(
|
||||
{'vpnservice': vpnservice,
|
||||
'state_path': cfg.CONF.state_path})
|
||||
'state_path': self.conf.state_path})
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_status(self):
|
||||
@ -703,6 +703,9 @@ class IPsecDriver(device_drivers.DeviceDriver):
|
||||
# before router's namespace
|
||||
process = self.processes[process_id]
|
||||
self._update_nat(process.vpnservice, self.add_nat_rule)
|
||||
# Don't run ipsec process for backup HA router
|
||||
if router.router['ha'] and router.ha_state == 'backup':
|
||||
return
|
||||
process.enable()
|
||||
|
||||
def destroy_process(self, process_id):
|
||||
@ -833,7 +836,15 @@ class IPsecDriver(device_drivers.DeviceDriver):
|
||||
process = self.ensure_process(vpnservice['router_id'],
|
||||
vpnservice=vpnservice)
|
||||
self._update_nat(vpnservice, self.add_nat_rule)
|
||||
process.update()
|
||||
router = self.routers.get(vpnservice['router_id'])
|
||||
if not router:
|
||||
continue
|
||||
# For HA router, spawn vpn process on master router
|
||||
# and terminate vpn process on backup router
|
||||
if router.router['ha'] and router.ha_state == 'backup':
|
||||
process.disable()
|
||||
else:
|
||||
process.update()
|
||||
|
||||
def _delete_vpn_processes(self, sync_router_ids, vpn_router_ids):
|
||||
# Delete any IPSec processes that are
|
||||
|
@ -151,6 +151,9 @@ class StrongSwanProcess(ipsec.BaseSwanProcess):
|
||||
if not self.namespace:
|
||||
return
|
||||
self._execute([self.binary, 'start'])
|
||||
# initiate ipsec connection
|
||||
for ipsec_site_conn in self.vpnservice['ipsec_site_connections']:
|
||||
self._execute([self.binary, 'up', ipsec_site_conn['id']])
|
||||
|
||||
def stop(self):
|
||||
self._execute([self.binary, 'stop'])
|
||||
|
@ -11,19 +11,26 @@
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
import os
|
||||
|
||||
import fixtures
|
||||
import functools
|
||||
import mock
|
||||
import netaddr
|
||||
import os
|
||||
|
||||
from neutron.agent.common import config as agent_config
|
||||
from neutron.agent.common import ovs_lib
|
||||
from neutron.agent.l3 import namespaces
|
||||
from neutron.agent.l3 import router_info
|
||||
from neutron.agent import l3_agent as l3_agent_main
|
||||
from neutron.agent.linux import external_process
|
||||
from neutron.agent.linux import interface
|
||||
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 constants as l3_constants
|
||||
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 l3_test_common
|
||||
from neutron.tests.common import net_helpers
|
||||
from neutron.tests.functional import base
|
||||
from oslo_config import cfg
|
||||
@ -34,6 +41,7 @@ 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',
|
||||
@ -143,20 +151,98 @@ FAKE_ROUTER = {
|
||||
}
|
||||
|
||||
|
||||
class RouterFixture(fixtures.Fixture):
|
||||
def get_ovs_bridge(br_name):
|
||||
return ovs_lib.OVSBridge(br_name)
|
||||
|
||||
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']
|
||||
|
||||
class TestIPSecScenario(base.BaseSudoTestCase):
|
||||
|
||||
vpn_agent_ini = os.environ.get('VPN_AGENT_INI',
|
||||
'/etc/neutron/vpn_agent.ini')
|
||||
NESTED_NAMESPACE_SEPARATOR = '@'
|
||||
|
||||
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)
|
||||
super(TestIPSecScenario, self).setUp()
|
||||
mock.patch('neutron.agent.l3.agent.L3PluginApi').start()
|
||||
# avoid report_status running periodically
|
||||
mock.patch('oslo_service.loopingcall.FixedIntervalLoopingCall').start()
|
||||
# Both the vpn agents try to use execute_rootwrap_daemon's socket
|
||||
# simultaneously during test cleanup, but execute_rootwrap_daemon has
|
||||
# limitations with simultaneous reads. So avoid using
|
||||
# root_helper_daemon and instead use root_helper
|
||||
# https://bugs.launchpad.net/neutron/+bug/1482622
|
||||
cfg.CONF.set_override('root_helper_daemon', None, group='AGENT')
|
||||
self.vpn_agent = self._configure_agent('agent1')
|
||||
|
||||
def _generate_info(self, public_ip, private_cidr):
|
||||
def connect_agents(self, agent1, agent2):
|
||||
"""Simulate both agents in the same host.
|
||||
|
||||
For packet flow between resources connected to these two agents,
|
||||
agent's ovs bridges are connected through patch ports.
|
||||
"""
|
||||
br_int_1 = get_ovs_bridge(agent1.conf.ovs_integration_bridge)
|
||||
br_int_2 = get_ovs_bridge(agent2.conf.ovs_integration_bridge)
|
||||
net_helpers.create_patch_ports(br_int_1, br_int_2)
|
||||
|
||||
br_ex_1 = get_ovs_bridge(agent1.conf.external_network_bridge)
|
||||
br_ex_2 = get_ovs_bridge(agent2.conf.external_network_bridge)
|
||||
net_helpers.create_patch_ports(br_ex_1, br_ex_2)
|
||||
|
||||
def _get_config_opts(self):
|
||||
"""Register default config options"""
|
||||
config = cfg.ConfigOpts()
|
||||
config.register_opts(common_config.core_opts)
|
||||
config.register_opts(common_config.core_cli_opts)
|
||||
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')
|
||||
|
||||
logging.register_options(config)
|
||||
agent_config.register_process_monitor_opts(config)
|
||||
return config
|
||||
|
||||
def _configure_agent(self, host):
|
||||
"""Override specific config options"""
|
||||
config = self._get_config_opts()
|
||||
l3_agent_main.register_opts(config)
|
||||
cfg.CONF.set_override('debug', True)
|
||||
agent_config.setup_logging()
|
||||
config.set_override(
|
||||
'interface_driver',
|
||||
'neutron.agent.linux.interface.OVSInterfaceDriver')
|
||||
config.set_override('router_delete_namespaces', True)
|
||||
|
||||
br_int = self.useFixture(net_helpers.OVSBridgeFixture()).bridge
|
||||
br_ex = self.useFixture(net_helpers.OVSBridgeFixture()).bridge
|
||||
config.set_override('ovs_integration_bridge', br_int.br_name)
|
||||
config.set_override('external_network_bridge', br_ex.br_name)
|
||||
|
||||
temp_dir = self.get_new_temp_dir()
|
||||
get_temp_file_path = functools.partial(self.get_temp_file_path,
|
||||
root=temp_dir)
|
||||
config.set_override('state_path', temp_dir.path)
|
||||
config.set_override('metadata_proxy_socket',
|
||||
get_temp_file_path('metadata_proxy'))
|
||||
config.set_override('ha_confs_path',
|
||||
get_temp_file_path('ha_confs'))
|
||||
config.set_override('external_pids',
|
||||
get_temp_file_path('external/pids'))
|
||||
config.set_override('host', host)
|
||||
ipsec_config_base_dir = '%s/%s' % (temp_dir.path, 'ipsec')
|
||||
config.set_override('config_base_dir',
|
||||
ipsec_config_base_dir, group='ipsec')
|
||||
|
||||
config(['--config-file', self.vpn_agent_ini])
|
||||
|
||||
# Assign ip address to br-ex port because it is a gateway
|
||||
ex_port = ip_lib.IPDevice(br_ex.br_name)
|
||||
ex_port.addr.add(str(PUBLIC_NET[1]))
|
||||
|
||||
return vpn_agent.VPNAgent(host, config)
|
||||
|
||||
def _generate_info(self, public_ip, private_cidr, enable_ha=False):
|
||||
"""Generate router info"""
|
||||
info = copy.deepcopy(FAKE_ROUTER)
|
||||
info['id'] = _uuid()
|
||||
info['_interfaces'][0]['id'] = _uuid()
|
||||
@ -170,48 +256,49 @@ class RouterFixture(fixtures.Fixture):
|
||||
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)
|
||||
if enable_ha:
|
||||
info['ha'] = True
|
||||
info['ha_vr_id'] = 1
|
||||
info[l3_constants.HA_INTERFACE_KEY] = (
|
||||
l3_test_common.get_ha_interface())
|
||||
else:
|
||||
info['ha'] = False
|
||||
return info
|
||||
|
||||
def manage_router(self, agent, router):
|
||||
"""Create router from router_info"""
|
||||
self.addCleanup(agent._safe_router_removed, router['id'])
|
||||
|
||||
class TestIPSecScenario(base.BaseSudoTestCase):
|
||||
# Generate unique internal and external router device names using the
|
||||
# agent's hostname. This is to allow multiple HA router replicas to
|
||||
# co-exist on the same machine, otherwise they'd all use the same
|
||||
# device names and OVS would freak out(OVS won't allow a port with
|
||||
# same name connected to two bridges).
|
||||
def _append_suffix(dev_name):
|
||||
# If dev_name = 'xyz123' and the suffix is 'agent2' then the result
|
||||
# will be 'xy-nt2'
|
||||
return "{0}-{1}".format(dev_name[:-4], agent.host[-3:])
|
||||
|
||||
vpn_agent_ini = os.environ.get('VPN_AGENT_INI',
|
||||
'/etc/neutron/vpn_agent.ini')
|
||||
def get_internal_device_name(port_id):
|
||||
return _append_suffix(
|
||||
(namespaces.INTERNAL_DEV_PREFIX + port_id)
|
||||
[:interface.LinuxInterfaceDriver.DEV_NAME_LEN])
|
||||
|
||||
def setUp(self):
|
||||
super(TestIPSecScenario, self).setUp()
|
||||
def get_external_device_name(port_id):
|
||||
return _append_suffix(
|
||||
(namespaces.EXTERNAL_DEV_PREFIX + port_id)
|
||||
[:interface.LinuxInterfaceDriver.DEV_NAME_LEN])
|
||||
|
||||
mock.patch('neutron.agent.l3.agent.L3PluginApi').start()
|
||||
mock_get_internal_device_name = mock.patch.object(
|
||||
router_info.RouterInfo, 'get_internal_device_name').start()
|
||||
mock_get_internal_device_name.side_effect = get_internal_device_name
|
||||
mock_get_external_device_name = mock.patch.object(
|
||||
router_info.RouterInfo, 'get_external_device_name').start()
|
||||
mock_get_external_device_name.side_effect = get_external_device_name
|
||||
|
||||
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)
|
||||
agent._process_added_router(router)
|
||||
|
||||
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]))
|
||||
return agent.router_info[router['id']]
|
||||
|
||||
def prepare_vpn_service_info(self, router_id, external_ip, subnet_cidr):
|
||||
service = copy.deepcopy(FAKE_VPN_SERVICE)
|
||||
@ -234,17 +321,24 @@ class TestIPSecScenario(base.BaseSudoTestCase):
|
||||
})
|
||||
vpn_service['ipsec_site_connections'] = [ipsec_conn]
|
||||
|
||||
def port_setup(self, router):
|
||||
def port_setup(self, router, bridge=None, offset=1, namespace=None):
|
||||
"""Creates namespace and a port inside it on a client site."""
|
||||
client_ns = self.useFixture(net_helpers.NamespaceFixture()).ip_wrapper
|
||||
if not namespace:
|
||||
client_ns = self.useFixture(
|
||||
net_helpers.NamespaceFixture()).ip_wrapper
|
||||
namespace = client_ns.namespace
|
||||
router_ip_cidr = self._port_first_ip_cidr(router.internal_ports[0])
|
||||
|
||||
port_ip_cidr = net_helpers.increment_ip_cidr(router_ip_cidr)
|
||||
port_ip_cidr = net_helpers.increment_ip_cidr(router_ip_cidr, offset)
|
||||
|
||||
if not bridge:
|
||||
bridge = get_ovs_bridge(self.vpn_agent.conf.ovs_integration_bridge)
|
||||
|
||||
port = self.useFixture(
|
||||
net_helpers.OVSPortFixture(self.br_int, client_ns.namespace)).port
|
||||
net_helpers.OVSPortFixture(bridge, 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]
|
||||
return namespace, port_ip_cidr.partition('/')[0]
|
||||
|
||||
def _port_first_ip_cidr(self, port):
|
||||
fixed_ip = port['fixed_ips'][0]
|
||||
@ -252,9 +346,8 @@ class TestIPSecScenario(base.BaseSudoTestCase):
|
||||
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
|
||||
router_info = self._generate_info(router_public_ip, private_net_cidr)
|
||||
router = self.manage_router(self.vpn_agent, router_info)
|
||||
port_namespace, port_ip = self.port_setup(router)
|
||||
|
||||
vpn_service = self.prepare_vpn_service_info(
|
||||
@ -262,6 +355,36 @@ class TestIPSecScenario(base.BaseSudoTestCase):
|
||||
return {"router": router, "port_namespace": port_namespace,
|
||||
"port_ip": port_ip, "vpn_service": vpn_service}
|
||||
|
||||
def setup_ha_routers(self, router_public_ip, private_net_cidr):
|
||||
"""Setup HA master router on agent1 and backup router on agent2"""
|
||||
router_info = self._generate_info(router_public_ip,
|
||||
private_net_cidr, enable_ha=True)
|
||||
get_ns_name = mock.patch.object(
|
||||
namespaces.RouterNamespace, '_get_ns_name').start()
|
||||
get_ns_name.return_value = "qrouter-{0}-{1}".format(
|
||||
router_info['id'], self.vpn_agent.host)
|
||||
|
||||
router1 = self.manage_router(self.vpn_agent, router_info)
|
||||
|
||||
router_info_2 = copy.deepcopy(router_info)
|
||||
router_info_2[l3_constants.HA_INTERFACE_KEY] = (
|
||||
l3_test_common.get_ha_interface(ip='169.254.192.2',
|
||||
mac='22:22:22:22:22:22'))
|
||||
get_ns_name.return_value = "qrouter-{0}-{1}".format(
|
||||
router_info['id'], self.failover_agent.host)
|
||||
router2 = self.manage_router(self.failover_agent, router_info_2)
|
||||
|
||||
linux_utils.wait_until_true(lambda: router1.ha_state == 'master')
|
||||
linux_utils.wait_until_true(lambda: router2.ha_state == 'backup')
|
||||
|
||||
port_namespace, port_ip = self.port_setup(router1)
|
||||
|
||||
vpn_service = self.prepare_vpn_service_info(
|
||||
router1.router_id, router_public_ip, private_net_cidr)
|
||||
return {"router1": router1, "router2": router2,
|
||||
"port_namespace": port_namespace, "port_ip": port_ip,
|
||||
"vpn_service": vpn_service}
|
||||
|
||||
def _ping(self, namespace, ip):
|
||||
"""Pings ip address from network namespace.
|
||||
|
||||
@ -272,11 +395,29 @@ class TestIPSecScenario(base.BaseSudoTestCase):
|
||||
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)
|
||||
linux_utils.execute(cmd, check_exit_code=True,
|
||||
extra_ok_codes=[0], run_as_root=True)
|
||||
return True
|
||||
except RuntimeError:
|
||||
return False
|
||||
|
||||
def _fail_ha_router(self, router):
|
||||
"""Down the HA router."""
|
||||
device_name = router.get_ha_device_name()
|
||||
ha_device = ip_lib.IPDevice(device_name, router.ns_name)
|
||||
ha_device.link.set_down()
|
||||
|
||||
def _ipsec_process_exists(self, conf, router, pid_files):
|
||||
"""Check if *Swan process has started up."""
|
||||
for pid_file in pid_files:
|
||||
pm = external_process.ProcessManager(
|
||||
conf,
|
||||
"ipsec",
|
||||
router.ns_name, pid_file=pid_file)
|
||||
if pm.active:
|
||||
break
|
||||
return pm.active
|
||||
|
||||
def test_ipsec_site_connections(self):
|
||||
device = self.vpn_agent.device_drivers[0]
|
||||
# Mock the method below because it causes Exception:
|
||||
@ -317,3 +458,92 @@ class TestIPSecScenario(base.BaseSudoTestCase):
|
||||
|
||||
self.assertTrue(self._ping(site1['port_namespace'], site2['port_ip']))
|
||||
self.assertTrue(self._ping(site2['port_namespace'], site1['port_ip']))
|
||||
|
||||
def test_ipsec_site_connections_with_l3ha_routers(self):
|
||||
"""Test ipsec site connection with HA routers.
|
||||
This test creates two agents. First agent will have Legacy and HA
|
||||
routers. Second agent will host only HA router. We setup ipsec
|
||||
connection between legacy and HA router.
|
||||
|
||||
When HA router is created, agent1 will have master router and
|
||||
agent2 will have backup router. Ipsec connection will be established
|
||||
between legacy router and agent1's master HA router.
|
||||
|
||||
Then we fail the agent1's master HA router. Agent1's HA router will
|
||||
transition to backup and agent2's HA router will become master.
|
||||
Now ipsec connection will be established between legacy router and
|
||||
agent2's master HA router
|
||||
"""
|
||||
self.failover_agent = self._configure_agent('agent2')
|
||||
self.connect_agents(self.vpn_agent, self.failover_agent)
|
||||
|
||||
vpn_agent_driver = self.vpn_agent.device_drivers[0]
|
||||
failover_agent_driver = self.failover_agent.device_drivers[0]
|
||||
ip_lib.send_ip_addr_adv_notif = mock.Mock()
|
||||
|
||||
# There are no vpn services yet. get_vpn_services_on_host returns
|
||||
# empty list
|
||||
vpn_agent_driver.agent_rpc.get_vpn_services_on_host = mock.Mock(
|
||||
return_value=[])
|
||||
failover_agent_driver.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.setup_ha_routers(PUBLIC_NET[5], private_nets[2])
|
||||
router = site1['router']
|
||||
router1 = site2['router1']
|
||||
router2 = site2['router2']
|
||||
|
||||
# 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'])
|
||||
|
||||
vpn_agent_driver.report_status = mock.Mock()
|
||||
failover_agent_driver.report_status = mock.Mock()
|
||||
|
||||
vpn_agent_driver.agent_rpc.get_vpn_services_on_host = mock.Mock(
|
||||
return_value=[site1['vpn_service'],
|
||||
site2['vpn_service']])
|
||||
failover_agent_driver.agent_rpc.get_vpn_services_on_host = mock.Mock(
|
||||
return_value=[site2['vpn_service']])
|
||||
|
||||
# No ipsec connection between legacy router and HA routers
|
||||
self.assertFalse(self._ping(site1['port_namespace'], site2['port_ip']))
|
||||
self.assertFalse(self._ping(site2['port_namespace'], site1['port_ip']))
|
||||
|
||||
# sync the routers
|
||||
vpn_agent_driver.sync(mock.Mock(), [{'id': router.router_id},
|
||||
{'id': router1.router_id}])
|
||||
failover_agent_driver.sync(mock.Mock(), [{'id': router1.router_id}])
|
||||
|
||||
self.addCleanup(
|
||||
vpn_agent_driver._delete_vpn_processes,
|
||||
[router.router_id, router1.router_id], [])
|
||||
|
||||
# Test ipsec connection between legacy router and agent2's HA router
|
||||
self.assertTrue(self._ping(site1['port_namespace'], site2['port_ip']))
|
||||
self.assertTrue(self._ping(site2['port_namespace'], site1['port_ip']))
|
||||
|
||||
# Fail the agent1's HA router. Agent1's HA router will transition
|
||||
# to backup and agent2's HA router will become master.
|
||||
self._fail_ha_router(router1)
|
||||
|
||||
linux_utils.wait_until_true(lambda: router2.ha_state == 'master')
|
||||
linux_utils.wait_until_true(lambda: router1.ha_state == 'backup')
|
||||
|
||||
# wait until ipsec process running in failover agent's HA router
|
||||
# check for both strongswan and openswan processes
|
||||
path = failover_agent_driver.processes[router2.router_id].config_dir
|
||||
pid_files = ['%s/var/run/charon.pid' % path,
|
||||
'%s/var/run/pluto.pid' % path]
|
||||
linux_utils.wait_until_true(
|
||||
lambda: self._ipsec_process_exists(
|
||||
self.failover_agent.conf, router2, pid_files))
|
||||
|
||||
# Test ipsec connection between legacy router and agent2's HA router
|
||||
self.assertTrue(self._ping(site1['port_namespace'], site2['port_ip']))
|
||||
self.assertTrue(self._ping(site2['port_namespace'], site1['port_ip']))
|
||||
|
@ -109,8 +109,10 @@ class TestStrongSwanDeviceDriver(base.BaseSudoTestCase):
|
||||
'oslo_service.loopingcall.FixedIntervalLoopingCall')
|
||||
looping_call_p.start()
|
||||
|
||||
vpn_service = mock.Mock()
|
||||
vpn_service.conf = self.conf
|
||||
self.driver = strongswan_ipsec.StrongSwanDriver(
|
||||
vpn_service=mock.Mock(), host=mock.sentinel.host)
|
||||
vpn_service, host=mock.sentinel.host)
|
||||
self.driver.routers[FAKE_ROUTER_ID] = self.router
|
||||
self.driver.agent_rpc = mock.Mock()
|
||||
self.driver._update_nat = mock.Mock()
|
||||
|
@ -261,13 +261,14 @@ class BaseIPsecDeviceDriver(base.BaseTestCase):
|
||||
mock.patch(klass).start()
|
||||
self._execute = mock.patch.object(ipsec_process, '_execute').start()
|
||||
self.agent = mock.Mock()
|
||||
self.conf = cfg.CONF
|
||||
self.agent.conf = self.conf
|
||||
self.driver = driver(
|
||||
self.agent,
|
||||
FAKE_HOST)
|
||||
self.conf = cfg.CONF
|
||||
self.conf.use_namespaces = True
|
||||
self.driver.agent_rpc = mock.Mock()
|
||||
self.ri_kwargs = {'router': {'id': FAKE_ROUTER_ID},
|
||||
self.ri_kwargs = {'router': {'id': FAKE_ROUTER_ID, 'ha': False},
|
||||
'agent_conf': self.conf,
|
||||
'interface_driver': mock.sentinel.interface_driver}
|
||||
self.iptables = mock.Mock()
|
||||
@ -309,7 +310,7 @@ class IPSecDeviceLegacy(BaseIPsecDeviceDriver):
|
||||
self._test_vpnservice_updated([])
|
||||
|
||||
def test_vpnservice_updated_with_router_info(self):
|
||||
router_info = {'id': FAKE_ROUTER_ID}
|
||||
router_info = {'id': FAKE_ROUTER_ID, 'ha': False}
|
||||
kwargs = {'router': router_info}
|
||||
self._test_vpnservice_updated([router_info], **kwargs)
|
||||
|
||||
@ -825,7 +826,7 @@ class TestLibreSwanProcess(base.BaseTestCase):
|
||||
'OpenSwanProcess.stop').start()
|
||||
self.os_remove = mock.patch('os.remove').start()
|
||||
|
||||
self.ipsec_process = libreswan_ipsec.LibreSwanProcess(mock.ANY,
|
||||
self.ipsec_process = libreswan_ipsec.LibreSwanProcess(cfg.CONF,
|
||||
'foo-process-id',
|
||||
self.vpnservice,
|
||||
mock.ANY)
|
||||
|
@ -52,7 +52,7 @@ class VPNBaseTestCase(base.BaseTestCase):
|
||||
super(VPNBaseTestCase, self).setUp()
|
||||
self.conf = cfg.CONF
|
||||
self.conf.use_namespaces = True
|
||||
self.ri_kwargs = {'router': {'id': FAKE_ROUTER_ID},
|
||||
self.ri_kwargs = {'router': {'id': FAKE_ROUTER_ID, 'ha': False},
|
||||
'agent_conf': self.conf,
|
||||
'interface_driver': mock.sentinel.interface_driver}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user