Merge "VPNaaS support for VPN service admin state change and reporting"
This commit is contained in:
@@ -77,6 +77,8 @@ STATUS_MAP = {
|
|||||||
'unrouted': constants.DOWN
|
'unrouted': constants.DOWN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IPSEC_CONNS = 'ipsec_site_connections'
|
||||||
|
|
||||||
|
|
||||||
def _get_template(template_file):
|
def _get_template(template_file):
|
||||||
global JINJA_ENV
|
global JINJA_ENV
|
||||||
@@ -622,14 +624,32 @@ class IPsecDriver(device_drivers.DeviceDriver):
|
|||||||
'ipsec_site_connections': copy.deepcopy(process.connection_status)
|
'ipsec_site_connections': copy.deepcopy(process.connection_status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def update_downed_connections(self, process_id, new_status):
|
||||||
|
"""Update info to be reported, if connections just went down.
|
||||||
|
|
||||||
|
If there is no longer any information for a connection (because it
|
||||||
|
has been removed (e.g. due to an admin down of VPN service or IPSec
|
||||||
|
connection), but there was previous status information for the
|
||||||
|
connection, mark the connection as down for reporting purposes.
|
||||||
|
"""
|
||||||
|
if process_id in self.process_status_cache:
|
||||||
|
for conn in self.process_status_cache[process_id][IPSEC_CONNS]:
|
||||||
|
if conn not in new_status[IPSEC_CONNS]:
|
||||||
|
new_status[IPSEC_CONNS][conn] = {
|
||||||
|
'status': constants.DOWN,
|
||||||
|
'updated_pending_status': True
|
||||||
|
}
|
||||||
|
|
||||||
def report_status(self, context):
|
def report_status(self, context):
|
||||||
status_changed_vpn_services = []
|
status_changed_vpn_services = []
|
||||||
for process in self.processes.values():
|
for process in self.processes.values():
|
||||||
previous_status = self.get_process_status_cache(process)
|
previous_status = self.get_process_status_cache(process)
|
||||||
if self.is_status_updated(process, previous_status):
|
if self.is_status_updated(process, previous_status):
|
||||||
new_status = self.copy_process_status(process)
|
new_status = self.copy_process_status(process)
|
||||||
self.process_status_cache[process.id] = new_status
|
self.update_downed_connections(process.id, new_status)
|
||||||
status_changed_vpn_services.append(new_status)
|
status_changed_vpn_services.append(new_status)
|
||||||
|
self.process_status_cache[process.id] = (
|
||||||
|
self.copy_process_status(process))
|
||||||
# We need unset updated_pending status after it
|
# We need unset updated_pending status after it
|
||||||
# is reported to the server side
|
# is reported to the server side
|
||||||
self.unset_updated_pending_status(process)
|
self.unset_updated_pending_status(process)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ conn %default
|
|||||||
ikelifetime=480m
|
ikelifetime=480m
|
||||||
keylife=60m
|
keylife=60m
|
||||||
keyingtries=%forever
|
keyingtries=%forever
|
||||||
{% for ipsec_site_connection in vpnservice.ipsec_site_connections
|
{% for ipsec_site_connection in vpnservice.ipsec_site_connections if ipsec_site_connection.admin_state_up
|
||||||
%}conn {{ipsec_site_connection.id}}
|
%}conn {{ipsec_site_connection.id}}
|
||||||
# NOTE: a default route is required for %defaultroute to work...
|
# NOTE: a default route is required for %defaultroute to work...
|
||||||
left={{vpnservice.external_ip}}
|
left={{vpnservice.external_ip}}
|
||||||
|
|||||||
@@ -91,6 +91,15 @@ class VPNDriverPlugin(VPNPlugin, vpn_db.VPNPluginRpcDbMixin):
|
|||||||
context, old_ipsec_site_connection, ipsec_site_connection)
|
context, old_ipsec_site_connection, ipsec_site_connection)
|
||||||
return ipsec_site_connection
|
return ipsec_site_connection
|
||||||
|
|
||||||
|
def update_vpnservice(self, context, vpnservice_id, vpnservice):
|
||||||
|
old_vpn_service = self.get_vpnservice(context, vpnservice_id)
|
||||||
|
new_vpn_service = super(
|
||||||
|
VPNDriverPlugin, self).update_vpnservice(context, vpnservice_id,
|
||||||
|
vpnservice)
|
||||||
|
driver = self._get_driver_for_vpnservice(old_vpn_service)
|
||||||
|
driver.update_vpnservice(context, old_vpn_service, new_vpn_service)
|
||||||
|
return new_vpn_service
|
||||||
|
|
||||||
def delete_vpnservice(self, context, vpnservice_id):
|
def delete_vpnservice(self, context, vpnservice_id):
|
||||||
vpnservice = self._get_vpnservice(context, vpnservice_id)
|
vpnservice = self._get_vpnservice(context, vpnservice_id)
|
||||||
super(VPNDriverPlugin, self).delete_vpnservice(context, vpnservice_id)
|
super(VPNDriverPlugin, self).delete_vpnservice(context, vpnservice_id)
|
||||||
|
|||||||
@@ -190,3 +190,69 @@ class TestIPsecDeviceDriver(base.BaseTestCase):
|
|||||||
process_id = _uuid()
|
process_id = _uuid()
|
||||||
self.driver.sync(context, [{'id': process_id}])
|
self.driver.sync(context, [{'id': process_id}])
|
||||||
self.assertNotIn(process_id, self.driver.processes)
|
self.assertNotIn(process_id, self.driver.processes)
|
||||||
|
|
||||||
|
def test_status_updated_on_connection_admin_down(self):
|
||||||
|
self.driver.process_status_cache = {
|
||||||
|
'1': {
|
||||||
|
'status': constants.ACTIVE,
|
||||||
|
'id': 123,
|
||||||
|
'updated_pending_status': False,
|
||||||
|
'ipsec_site_connections': {
|
||||||
|
'10': {
|
||||||
|
'status': constants.ACTIVE,
|
||||||
|
'updated_pending_status': False,
|
||||||
|
},
|
||||||
|
'20': {
|
||||||
|
'status': constants.ACTIVE,
|
||||||
|
'updated_pending_status': False,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# Simulate that there is no longer status for connection '20'
|
||||||
|
# e.g. connection admin down
|
||||||
|
new_status = {
|
||||||
|
'ipsec_site_connections': {
|
||||||
|
'10': {
|
||||||
|
'status': constants.ACTIVE,
|
||||||
|
'updated_pending_status': False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.driver.update_downed_connections('1', new_status)
|
||||||
|
existing_conn = new_status['ipsec_site_connections'].get('10')
|
||||||
|
self.assertIsNotNone(existing_conn)
|
||||||
|
self.assertEqual(constants.ACTIVE, existing_conn['status'])
|
||||||
|
missing_conn = new_status['ipsec_site_connections'].get('20')
|
||||||
|
self.assertIsNotNone(missing_conn)
|
||||||
|
self.assertEqual(constants.DOWN, missing_conn['status'])
|
||||||
|
|
||||||
|
def test_status_updated_on_service_admin_down(self):
|
||||||
|
self.driver.process_status_cache = {
|
||||||
|
'1': {
|
||||||
|
'status': constants.ACTIVE,
|
||||||
|
'id': 123,
|
||||||
|
'updated_pending_status': False,
|
||||||
|
'ipsec_site_connections': {
|
||||||
|
'10': {
|
||||||
|
'status': constants.ACTIVE,
|
||||||
|
'updated_pending_status': False,
|
||||||
|
},
|
||||||
|
'20': {
|
||||||
|
'status': constants.ACTIVE,
|
||||||
|
'updated_pending_status': False,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# Simulate that there are no connections now
|
||||||
|
new_status = {
|
||||||
|
'ipsec_site_connections': {}
|
||||||
|
}
|
||||||
|
self.driver.update_downed_connections('1', new_status)
|
||||||
|
missing_conn = new_status['ipsec_site_connections'].get('10')
|
||||||
|
self.assertIsNotNone(missing_conn)
|
||||||
|
self.assertEqual(constants.DOWN, missing_conn['status'])
|
||||||
|
missing_conn = new_status['ipsec_site_connections'].get('20')
|
||||||
|
self.assertIsNotNone(missing_conn)
|
||||||
|
self.assertEqual(constants.DOWN, missing_conn['status'])
|
||||||
|
|||||||
@@ -58,6 +58,11 @@ class TestVPNDriverPlugin(test_db_vpnaas.TestVpnaas,
|
|||||||
self.driver.delete_vpnservice.assert_called_once_with(
|
self.driver.delete_vpnservice.assert_called_once_with(
|
||||||
mock.ANY, mock.ANY)
|
mock.ANY, mock.ANY)
|
||||||
|
|
||||||
|
def test_update_vpnservice(self, **extras):
|
||||||
|
super(TestVPNDriverPlugin, self).test_update_vpnservice()
|
||||||
|
self.driver.update_vpnservice.assert_called_once_with(
|
||||||
|
mock.ANY, mock.ANY, mock.ANY)
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def vpnservice_set(self):
|
def vpnservice_set(self):
|
||||||
"""Test case to create a ipsec_site_connection."""
|
"""Test case to create a ipsec_site_connection."""
|
||||||
|
|||||||
Reference in New Issue
Block a user