Do not count dvr agents while creating HA ports
Presently dvr agents are not excluded when a ha router interface is created, because of which an interface is created even in the dvr agent namespace. This patch fixes the issue by supporting a filter - 'agent_modes' in the function L3AgentSchedulerDbMixin.get_l3_agents. If this filter is defined, only the l3 agents whose modes defined in this filter are returned Change-Id: I9383e2a30ddc4f2c3e04ff0821726b8dc3ec89a0 Closes-bug: #1397209
This commit is contained in:
parent
844a453a6a
commit
787c8dd29f
@ -22,6 +22,7 @@ from oslo import messaging
|
||||
from oslo.utils import timeutils
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy import or_
|
||||
from sqlalchemy import orm
|
||||
from sqlalchemy.orm import exc
|
||||
from sqlalchemy.orm import joinedload
|
||||
@ -382,6 +383,15 @@ class L3AgentSchedulerDbMixin(l3agentscheduler.L3AgentSchedulerPluginBase,
|
||||
if column:
|
||||
query = query.filter(column.in_(value))
|
||||
|
||||
agent_modes = filters.get('agent_modes', [])
|
||||
if agent_modes:
|
||||
agent_mode_key = '\"agent_mode\": \"'
|
||||
configuration_filter = (
|
||||
[agents_db.Agent.configurations.contains('%s%s\"' %
|
||||
(agent_mode_key, agent_mode))
|
||||
for agent_mode in agent_modes])
|
||||
query = query.filter(or_(*configuration_filter))
|
||||
|
||||
return [l3_agent
|
||||
for l3_agent in query
|
||||
if agentschedulers_db.AgentSchedulerDbMixin.is_eligible_agent(
|
||||
|
@ -255,7 +255,8 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin):
|
||||
"""
|
||||
|
||||
min_agents = cfg.CONF.min_l3_agents_per_router
|
||||
num_agents = len(self.get_l3_agents(context))
|
||||
num_agents = len(self.get_l3_agents(context,
|
||||
filters={'agent_modes': ['legacy', 'dvr_snat']}))
|
||||
max_agents = cfg.CONF.max_l3_agents_per_router
|
||||
if max_agents:
|
||||
if max_agents > num_agents:
|
||||
|
@ -58,11 +58,13 @@ class L3HATestFramework(testlib_api.SqlTestCase,
|
||||
'agent_type': constants.AGENT_TYPE_L3,
|
||||
'binary': 'neutron-l3-agent',
|
||||
'host': 'l3host',
|
||||
'topic': 'N/A'
|
||||
'topic': 'N/A',
|
||||
'configurations': {'agent_mode': 'legacy'}
|
||||
}
|
||||
|
||||
self.plugin.create_or_update_agent(self.admin_ctx, agent_status)
|
||||
agent_status['host'] = 'l3host_2'
|
||||
agent_status['configurations'] = {'agent_mode': 'dvr_snat'}
|
||||
self.plugin.create_or_update_agent(self.admin_ctx, agent_status)
|
||||
self.agent1, self.agent2 = self.plugin.get_agents(self.admin_ctx)
|
||||
|
||||
@ -395,6 +397,27 @@ class L3HATestCase(L3HATestFramework):
|
||||
routers_after = self.plugin.get_routers(self.admin_ctx)
|
||||
self.assertEqual(routers_before, routers_after)
|
||||
|
||||
def test_exclude_dvr_agents_for_ha_candidates(self):
|
||||
"""Test dvr agents are not counted in the ha candidates.
|
||||
|
||||
This test case tests that when get_number_of_agents_for_scheduling
|
||||
is called, it doesn't count dvr agents.
|
||||
"""
|
||||
# Test setup registers two l3 agents.
|
||||
# Register another l3 agent with dvr mode and assert that
|
||||
# get_number_of_ha_agent_candidates return 2.
|
||||
dvr_agent_status = {
|
||||
'agent_type': constants.AGENT_TYPE_L3,
|
||||
'binary': 'neutron-l3-agent',
|
||||
'host': 'l3host_3',
|
||||
'topic': 'N/A',
|
||||
'configurations': {'agent_mode': 'dvr'}
|
||||
}
|
||||
self.plugin.create_or_update_agent(self.admin_ctx, dvr_agent_status)
|
||||
num_ha_candidates = self.plugin.get_number_of_agents_for_scheduling(
|
||||
self.admin_ctx)
|
||||
self.assertEqual(2, num_ha_candidates)
|
||||
|
||||
|
||||
class L3HAUserTestCase(L3HATestFramework):
|
||||
|
||||
|
@ -18,6 +18,8 @@ import datetime
|
||||
import uuid
|
||||
|
||||
import mock
|
||||
import testscenarios
|
||||
|
||||
from oslo.config import cfg
|
||||
from oslo.db import exception as db_exc
|
||||
from oslo.utils import importutils
|
||||
@ -44,45 +46,13 @@ from neutron.tests.unit import test_l3_plugin
|
||||
from neutron.tests.unit import testlib_api
|
||||
from neutron.tests.unit import testlib_plugin
|
||||
|
||||
HOST = 'my_l3_host'
|
||||
FIRST_L3_AGENT = {
|
||||
'binary': 'neutron-l3-agent',
|
||||
'host': HOST,
|
||||
'topic': topics.L3_AGENT,
|
||||
'configurations': {},
|
||||
'agent_type': constants.AGENT_TYPE_L3,
|
||||
'start_flag': True
|
||||
}
|
||||
|
||||
HOST_2 = 'my_l3_host_2'
|
||||
SECOND_L3_AGENT = {
|
||||
'binary': 'neutron-l3-agent',
|
||||
'host': HOST_2,
|
||||
'topic': topics.L3_AGENT,
|
||||
'configurations': {},
|
||||
'agent_type': constants.AGENT_TYPE_L3,
|
||||
'start_flag': True
|
||||
}
|
||||
|
||||
HOST_3 = 'my_l3_host_3'
|
||||
THIRD_L3_AGENT = {
|
||||
'binary': 'neutron-l3-agent',
|
||||
'host': HOST_3,
|
||||
'topic': topics.L3_AGENT,
|
||||
'configurations': {},
|
||||
'agent_type': constants.AGENT_TYPE_L3,
|
||||
'start_flag': True
|
||||
}
|
||||
|
||||
HOST_4 = 'my_l3_host_4'
|
||||
FOURTH_L3_AGENT = {
|
||||
'binary': 'neutron-l3-agent',
|
||||
'host': HOST_4,
|
||||
'topic': topics.L3_AGENT,
|
||||
'configurations': {},
|
||||
'agent_type': constants.AGENT_TYPE_L3,
|
||||
'start_flag': True
|
||||
}
|
||||
# the below code is required for the following reason
|
||||
# (as documented in testscenarios)
|
||||
"""Multiply tests depending on their 'scenarios' attribute.
|
||||
This can be assigned to 'load_tests' in any test module to make this
|
||||
automatically work across tests in the module.
|
||||
"""
|
||||
load_tests = testscenarios.load_tests_apply_scenarios
|
||||
|
||||
HOST_DVR = 'my_l3_host_dvr'
|
||||
DVR_L3_AGENT = {
|
||||
@ -267,10 +237,18 @@ class L3SchedulerBaseTestCase(base.BaseTestCase):
|
||||
|
||||
class L3SchedulerBaseMixin(object):
|
||||
|
||||
def _register_l3_agent(self, agent, plugin=None):
|
||||
def _register_l3_agent(self, host, agent_mode='legacy', plugin=None):
|
||||
if not plugin:
|
||||
plugin = self.plugin
|
||||
|
||||
agent = {
|
||||
'binary': 'neutron-l3-agent',
|
||||
'host': host,
|
||||
'topic': topics.L3_AGENT,
|
||||
'configurations': {'agent_mode': agent_mode},
|
||||
'agent_type': constants.AGENT_TYPE_L3,
|
||||
'start_flag': True
|
||||
}
|
||||
callback = agents_db.AgentExtRpcCallback()
|
||||
callback.report_state(self.adminContext,
|
||||
agent_state={'agent_state': agent},
|
||||
@ -280,10 +258,10 @@ class L3SchedulerBaseMixin(object):
|
||||
return agent_db[0]
|
||||
|
||||
def _register_l3_agents(self, plugin=None):
|
||||
self.agent1 = self._register_l3_agent(FIRST_L3_AGENT, plugin)
|
||||
self.agent1 = self._register_l3_agent('host_1', plugin=plugin)
|
||||
self.agent_id1 = self.agent1.id
|
||||
|
||||
self.agent2 = self._register_l3_agent(SECOND_L3_AGENT, plugin)
|
||||
self.agent2 = self._register_l3_agent('host_2', plugin=plugin)
|
||||
self.agent_id2 = self.agent2.id
|
||||
|
||||
def _register_l3_dvr_agents(self):
|
||||
@ -597,7 +575,7 @@ class L3SchedulerTestBaseMixin(object):
|
||||
|
||||
# test legacy agent_mode case: only legacy agent should be candidate
|
||||
router['distributed'] = False
|
||||
exp_host = FIRST_L3_AGENT.get('host')
|
||||
exp_host = 'host_1'
|
||||
self._check_get_l3_agent_candidates(router, agent_list, exp_host)
|
||||
|
||||
def test_get_l3_agent_candidates_dvr(self):
|
||||
@ -676,7 +654,7 @@ class L3SchedulerTestBaseMixin(object):
|
||||
def _prepare_check_ports_exist_tests(self):
|
||||
l3_agent = agents_db.Agent()
|
||||
l3_agent.admin_state_up = True
|
||||
l3_agent.host = HOST
|
||||
l3_agent.host = 'host_1'
|
||||
router = self._make_router(self.fmt,
|
||||
tenant_id=str(uuid.uuid4()),
|
||||
name='r2')
|
||||
@ -714,7 +692,7 @@ class L3SchedulerTestBaseMixin(object):
|
||||
getp.return_value = self.plugin
|
||||
# matching subnet
|
||||
port = {'subnet_id': str(uuid.uuid4()),
|
||||
'binding:host_id': HOST,
|
||||
'binding:host_id': 'host_1',
|
||||
'device_owner': 'compute:',
|
||||
'id': 1234}
|
||||
self.plugin.get_ports.return_value = [port]
|
||||
@ -796,13 +774,13 @@ class L3AgentChanceSchedulerTestCase(L3SchedulerTestCase):
|
||||
self._set_l3_agent_admin_state(self.adminContext,
|
||||
self.agent_id1, True)
|
||||
self.plugin.auto_schedule_routers(self.adminContext,
|
||||
FIRST_L3_AGENT['host'],
|
||||
'host_1',
|
||||
[r1['router']['id']])
|
||||
|
||||
agents = self.get_l3_agents_hosting_routers(
|
||||
self.adminContext, [r1['router']['id']],
|
||||
admin_state_up=True)
|
||||
self.assertEqual(FIRST_L3_AGENT['host'], agents[0]['host'])
|
||||
self.assertEqual('host_1', agents[0]['host'])
|
||||
|
||||
|
||||
class L3AgentLeastRoutersSchedulerTestCase(L3SchedulerTestCase):
|
||||
@ -1168,10 +1146,10 @@ class L3_HA_scheduler_db_mixinTestCase(L3HATestCaseMixin):
|
||||
super(L3_HA_scheduler_db_mixinTestCase,
|
||||
self)._register_l3_agents(plugin=plugin)
|
||||
|
||||
self.agent3 = self._register_l3_agent(THIRD_L3_AGENT, plugin)
|
||||
self.agent3 = self._register_l3_agent('host_3', plugin=plugin)
|
||||
self.agent_id3 = self.agent3.id
|
||||
|
||||
self.agent4 = self._register_l3_agent(FOURTH_L3_AGENT, plugin)
|
||||
self.agent4 = self._register_l3_agent('host_4', plugin=plugin)
|
||||
self.agent_id4 = self.agent4.id
|
||||
|
||||
def test_get_ha_routers_l3_agents_count(self):
|
||||
@ -1275,11 +1253,11 @@ class L3HAChanceSchedulerTestCase(L3HATestCaseMixin):
|
||||
self.assertIn(self.agent_id1, agent_ids)
|
||||
self.assertIn(self.agent_id2, agent_ids)
|
||||
|
||||
agent = self._register_l3_agent(THIRD_L3_AGENT)
|
||||
agent = self._register_l3_agent('host_3')
|
||||
self.agent_id3 = agent.id
|
||||
routers_to_auto_schedule = [router['id']] if specific_router else []
|
||||
self.plugin.auto_schedule_routers(self.adminContext,
|
||||
THIRD_L3_AGENT['host'],
|
||||
'host_3',
|
||||
routers_to_auto_schedule)
|
||||
|
||||
agents = self.plugin.get_l3_agents_hosting_routers(
|
||||
@ -1289,7 +1267,7 @@ class L3HAChanceSchedulerTestCase(L3HATestCaseMixin):
|
||||
|
||||
# Simulate agent restart to make sure we don't try to re-bind
|
||||
self.plugin.auto_schedule_routers(self.adminContext,
|
||||
THIRD_L3_AGENT['host'],
|
||||
'host_3',
|
||||
routers_to_auto_schedule)
|
||||
|
||||
def test_scheduler_with_ha_enabled_not_enough_agent(self):
|
||||
@ -1320,10 +1298,10 @@ class L3HALeastRoutersSchedulerTestCase(L3HATestCaseMixin):
|
||||
super(L3HALeastRoutersSchedulerTestCase,
|
||||
self)._register_l3_agents(plugin=plugin)
|
||||
|
||||
agent = self._register_l3_agent(THIRD_L3_AGENT, plugin)
|
||||
agent = self._register_l3_agent('host_3', plugin=plugin)
|
||||
self.agent_id3 = agent.id
|
||||
|
||||
agent = self._register_l3_agent(FOURTH_L3_AGENT, plugin)
|
||||
agent = self._register_l3_agent('host_4', plugin=plugin)
|
||||
self.agent_id4 = agent.id
|
||||
|
||||
def setUp(self):
|
||||
@ -1366,3 +1344,78 @@ class L3HALeastRoutersSchedulerTestCase(L3HATestCaseMixin):
|
||||
agent_ids = [agent['id'] for agent in agents]
|
||||
self.assertIn(self.agent_id3, agent_ids)
|
||||
self.assertIn(self.agent_id4, agent_ids)
|
||||
|
||||
|
||||
class TestGetL3AgentsWithAgentModeFilter(testlib_api.SqlTestCase,
|
||||
testlib_plugin.PluginSetupHelper,
|
||||
L3SchedulerBaseMixin):
|
||||
"""Test cases to test get_l3_agents.
|
||||
|
||||
This class tests the L3AgentSchedulerDbMixin.get_l3_agents()
|
||||
for the 'agent_mode' filter with various values.
|
||||
|
||||
5 l3 agents are registered in the order - legacy, dvr_snat, dvr, fake_mode
|
||||
and legacy
|
||||
"""
|
||||
|
||||
scenarios = [
|
||||
('no filter',
|
||||
dict(agent_modes=[],
|
||||
expected_agent_modes=['legacy', 'dvr_snat', 'dvr',
|
||||
'fake_mode', 'legacy'])),
|
||||
|
||||
('legacy',
|
||||
dict(agent_modes=['legacy'],
|
||||
expected_agent_modes=['legacy', 'legacy'])),
|
||||
|
||||
('dvr_snat',
|
||||
dict(agent_modes=['dvr_snat'],
|
||||
expected_agent_modes=['dvr_snat'])),
|
||||
|
||||
('dvr ',
|
||||
dict(agent_modes=['dvr'],
|
||||
expected_agent_modes=['dvr'])),
|
||||
|
||||
('legacy and dvr snat',
|
||||
dict(agent_modes=['legacy', 'dvr_snat', 'legacy'],
|
||||
expected_agent_modes=['legacy', 'dvr_snat', 'legacy'])),
|
||||
|
||||
('legacy and dvr',
|
||||
dict(agent_modes=['legacy', 'dvr'],
|
||||
expected_agent_modes=['legacy', 'dvr', 'legacy'])),
|
||||
|
||||
('dvr_snat and dvr',
|
||||
dict(agent_modes=['dvr_snat', 'dvr'],
|
||||
expected_agent_modes=['dvr_snat', 'dvr'])),
|
||||
|
||||
('legacy, dvr_snat and dvr',
|
||||
dict(agent_modes=['legacy', 'dvr_snat', 'dvr'],
|
||||
expected_agent_modes=['legacy', 'dvr_snat', 'dvr',
|
||||
'legacy'])),
|
||||
|
||||
('invalid',
|
||||
dict(agent_modes=['invalid'],
|
||||
expected_agent_modes=[])),
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(TestGetL3AgentsWithAgentModeFilter, self).setUp()
|
||||
self.plugin = L3HAPlugin()
|
||||
self.setup_coreplugin('neutron.plugins.ml2.plugin.Ml2Plugin')
|
||||
self.adminContext = q_context.get_admin_context()
|
||||
hosts = ['host_1', 'host_2', 'host_3', 'host_4', 'host_5']
|
||||
agent_modes = ['legacy', 'dvr_snat', 'dvr', 'fake_mode', 'legacy']
|
||||
for host, agent_mode in zip(hosts, agent_modes):
|
||||
self._register_l3_agent(host, agent_mode, self.plugin)
|
||||
|
||||
def _get_agent_mode(self, agent):
|
||||
agent_conf = self.plugin.get_configuration_dict(agent)
|
||||
return agent_conf.get('agent_mode', 'None')
|
||||
|
||||
def test_get_l3_agents(self):
|
||||
l3_agents = self.plugin.get_l3_agents(
|
||||
self.adminContext, filters={'agent_modes': self.agent_modes})
|
||||
self.assertEqual(len(self.expected_agent_modes), len(l3_agents))
|
||||
returned_agent_modes = [self._get_agent_mode(agent)
|
||||
for agent in l3_agents]
|
||||
self.assertEqual(self.expected_agent_modes, returned_agent_modes)
|
||||
|
Loading…
Reference in New Issue
Block a user