Use write connection for get_vpn_services_on_host

The OVN IPSEC implementation requires write connection.
And it will raise errors when try to bind routers with
`Can't upgrade a READER transaction to a WRITER mid-transaction`.

This alias both to write transation declear so no above error will
raise.

Closes-Bug: 2100911
Change-Id: I1f5ddbaae7b9a45382ee1307c13f26d346b03644
This commit is contained in:
ricolin
2025-03-05 09:03:40 +08:00
parent 57c118f8de
commit 5cf0516b78
3 changed files with 93 additions and 1 deletions

View File

@@ -71,7 +71,7 @@ class IPsecVpnDriverCallBack:
self.driver.name)
return query
@db_api.CONTEXT_READER
@db_api.CONTEXT_WRITER
def get_vpn_services_on_host(self, context, host=None):
"""Returns the vpnservices on the host."""
vpnservices = self._get_agent_hosting_vpn_services(

View File

@@ -24,6 +24,7 @@ from neutron.tests.unit.api import test_extensions
from neutron.tests.unit.extensions import test_l3
from neutron.tests.unit import testlib_api
from neutron_lib import context
from neutron_lib.db import api as db_api
from neutron_lib import exceptions as n_exc
from neutron_lib.plugins import constants as plugin_constants
from neutron_lib.plugins import directory
@@ -330,6 +331,46 @@ class VPNAgentSchedulerTestCase(VPNAgentSchedulerTestCaseBase):
self.assertEqual(VPN_HOSTA, host_before)
self.assertEqual(VPN_HOSTB, host_after)
def test_router_reschedule_with_write_db_wrap(self):
self._register_agent_states()
agent_a = self.service_plugin.get_vpn_agent_on_host(
self.adminContext, VPN_HOSTA)
with self.vpnservice() as service:
# schedule the vpn routers to agent A
with db_api.CONTEXT_WRITER.using(self.adminContext):
self.service_plugin.auto_schedule_routers(
self.adminContext, agent_a)
ctxt_mock = mock.MagicMock()
call_mock = mock.MagicMock(
side_effect=[oslo_messaging.MessagingTimeout, None])
ctxt_mock.call = call_mock
self.client_mock.prepare = mock.MagicMock(return_value=ctxt_mock)
self._take_down_agent_and_run_reschedule(VPN_HOSTA)
self.assertEqual(2, call_mock.call_count)
# make sure vpn service was rescheduled even when first attempt
# failed to notify VPN agent
router_id = service['vpnservice']['router_id']
host = self._get_agent_host_by_router(router_id)
vpn_agents = self._list_vpn_agents_hosting_router(router_id)
self.assertEqual(1, len(vpn_agents['agents']))
self.assertEqual(VPN_HOSTB, host)
def test_router_reschedule_with_read_db_wrap(self):
self._register_agent_states()
agent_a = self.service_plugin.get_vpn_agent_on_host(
self.adminContext, VPN_HOSTA)
with self.vpnservice():
# schedule the vpn routers to agent A
with db_api.CONTEXT_READER.using(self.adminContext):
self.assertRaises(
TypeError,
self.service_plugin.auto_schedule_routers,
self.adminContext,
agent_a)
def test_router_reschedule_succeeded_after_failed_notification(self):
self._register_agent_states()
agent_a = self.service_plugin.get_vpn_agent_on_host(

View File

@@ -130,9 +130,12 @@ class TestOvnIPsecDriver(base.BaseTestCase):
router_id=FAKE_ROUTER_ID,
router=self._fake_router
)
self.svc_plugin.get_vpn_agent_on_host.return_value = {'id': FAKE_HOST}
self.svc_plugin.get_vpnservice.return_value = FAKE_VPNSERVICE_1
self.svc_plugin.get_vpnservice_router_id.return_value = FAKE_ROUTER_ID
self.driver = ipsec_driver.IPsecOvnVPNDriver(self.svc_plugin)
self.driver.make_vpnservice_dict = mock.Mock(
return_value={'id': FAKE_HOST})
self.validator = ipsec_validator.IpsecVpnValidator(self.driver)
self.context = n_ctx.get_admin_context()
@@ -304,3 +307,51 @@ class TestOvnIPsecDriver(base.BaseTestCase):
[FAKE_VPN_CONNECTION_1],
expected_add, expected_remove
)
class TestOvnIPsecCallBackDriver(base.BaseTestCase):
def setUp(self):
super().setUp()
vpn_agent = {'host': FAKE_HOST}
self.core_plugin = mock.Mock()
self.core_plugin.get_vpn_agents_hosting_routers.return_value = \
[vpn_agent]
directory.add_plugin(constants.CORE, self.core_plugin)
self._fake_router = FakeSqlQueryObject(
id=FAKE_ROUTER_ID,
gw_port=FakeSqlQueryObject(network_id=_uuid())
)
self.svc_plugin = mock.Mock()
self.svc_plugin.get_vpn_agents_hosting_routers.return_value = \
[vpn_agent]
self.svc_plugin.schedule_router.return_value = vpn_agent
self.svc_plugin._get_vpnservice.return_value = FakeSqlQueryObject(
router_id=FAKE_ROUTER_ID,
router=self._fake_router
)
self.svc_plugin.get_vpn_agent_on_host.return_value = {'id': FAKE_HOST}
self.svc_plugin.get_vpnservice.return_value = FAKE_VPNSERVICE_1
self.svc_plugin.get_vpnservice_router_id.return_value = FAKE_ROUTER_ID
self.driver = ipsec_driver.IPsecOvnVPNDriver(self.svc_plugin)
self.driver.make_vpnservice_dict = mock.Mock(
return_value={'id': FAKE_HOST})
def test_get_vpn_services_on_host(self):
with mock.patch('neutron_lib.context.get_admin_context') as get_ctx:
mock_ctx = mock.Mock()
mock_ctx.session.query().join().join().filter.return_value = [
{'id': FAKE_HOST}]
get_ctx.return_value = mock_ctx
context = n_ctx.get_admin_context()
driver_callback = ipsec_driver.IPsecVpnOvnDriverCallBack(
self.driver)
self.assertEqual(
[{'id': FAKE_HOST}],
driver_callback.get_vpn_services_on_host(
context, FAKE_HOST)
)
self.svc_plugin.get_vpn_agent_on_host.assert_called_once_with(
mock.ANY, FAKE_HOST)
self.svc_plugin.auto_schedule_routers.assert_called_once_with(
mock.ANY, {'id': FAKE_HOST})