neutron-dynamic-routing/neutron_dynamic_routing/tests/functional/services/bgp/scheduler/test_bgp_dragent_scheduler.py

208 lines
8.1 KiB
Python

# Copyright 2016 Huawei Technologies India Pvt. Ltd.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutron_lib import context
import testscenarios
from neutron.db import agents_db
from neutron.tests.unit import testlib_api
from neutron_dynamic_routing.db import bgp_db
from neutron_dynamic_routing.db import bgp_dragentscheduler_db as bgp_dras_db
from neutron_dynamic_routing.services.bgp.scheduler import bgp_dragent_scheduler as bgp_dras # noqa
from neutron_dynamic_routing.tests.common import helpers
# Required to generate tests from scenarios. Not compatible with nose.
load_tests = testscenarios.load_tests_apply_scenarios
class TestAutoSchedule(testlib_api.SqlTestCase,
bgp_dras_db.BgpDrAgentSchedulerDbMixin,
agents_db.AgentDbMixin):
"""Test various scenarios for schedule_unscheduled_bgp_speakers.
Below is the brief description of the scenario variables
--------------------------------------------------------
host_count
number of hosts.
agent_count
number of BGP dynamic routing agents.
down_agent_count
number of DRAgents which are inactive.
bgp_speaker_count
Number of bgp_speakers.
hosted_bgp_speakers
A mapping of agent id to the ids of the bgp_speakers that they
should be initially hosting.
expected_schedule_return_value
Expected return value of 'schedule_unscheduled_bgp_speakers'.
expected_hosted_bgp_speakers
This stores the expected bgp_speakers that should have been
scheduled (or that could have already been scheduled) for each
agent after the 'schedule_unscheduled_bgp_speakers' function is
called.
"""
scenarios = [
('No BgpDrAgent scheduled, if no DRAgent is present',
dict(host_count=1,
agent_count=0,
down_agent_count=0,
bgp_speaker_count=1,
hosted_bgp_speakers={},
expected_schedule_return_value=False)),
('No BgpDrAgent scheduled, if no BGP speaker are present',
dict(host_count=1,
agent_count=1,
down_agent_count=0,
bgp_speaker_count=0,
hosted_bgp_speakers={},
expected_schedule_return_value=False,
expected_hosted_bgp_speakers={'agent-0': []})),
('No BgpDrAgent scheduled, if BGP speaker already hosted',
dict(host_count=1,
agent_count=1,
down_agent_count=0,
bgp_speaker_count=1,
hosted_bgp_speakers={'agent-0': ['bgp-speaker-0']},
expected_schedule_return_value=False,
expected_hosted_bgp_speakers={'agent-0': ['bgp-speaker-0']})),
('BgpDrAgent scheduled to the speaker, if the speaker is not hosted',
dict(host_count=1,
agent_count=1,
down_agent_count=0,
bgp_speaker_count=1,
hosted_bgp_speakers={},
expected_schedule_return_value=True,
expected_hosted_bgp_speakers={'agent-0': ['bgp-speaker-0']})),
('No BgpDrAgent scheduled, if all the agents are down',
dict(host_count=2,
agent_count=2,
down_agent_count=2,
bgp_speaker_count=1,
hosted_bgp_speakers={},
expected_schedule_return_value=False,
expected_hosted_bgp_speakers={'agent-0': [],
'agent-1': [], })),
]
def _strip_host_index(self, name):
"""Strips the host index.
Eg. if name = '2-agent-3', then 'agent-3' is returned.
"""
return name[name.find('-') + 1:]
def _extract_index(self, name):
"""Extracts the index number and returns.
Eg. if name = '2-agent-3', then 3 is returned
"""
return int(name.split('-')[-1])
def _get_hosted_bgp_speakers_on_dragent(self, agent_id):
query = self.ctx.session.query(
bgp_dras_db.BgpSpeakerDrAgentBinding.bgp_speaker_id)
query = query.filter(
bgp_dras_db.BgpSpeakerDrAgentBinding.agent_id ==
agent_id)
return [item[0] for item in query]
def _create_and_set_agents_down(self, hosts, agent_count=0,
down_agent_count=0, admin_state_up=True):
agents = []
if agent_count:
for i, host in enumerate(hosts):
is_alive = i >= down_agent_count
agents.append(helpers.register_bgp_dragent(
host,
admin_state_up=admin_state_up,
alive=is_alive))
return agents
def _save_bgp_speakers(self, bgp_speakers):
cls = bgp_db.BgpDbMixin()
bgp_speaker_body = {
'bgp_speaker': {'name': 'fake_bgp_speaker',
'ip_version': '4',
'local_as': '123',
'advertise_floating_ip_host_routes': False,
'advertise_tenant_networks': False,
'peers': [],
'networks': []}}
i = 1
for bgp_speaker_id in bgp_speakers:
bgp_speaker_body['bgp_speaker']['local_as'] = i
cls._save_bgp_speaker(self.ctx, bgp_speaker_body,
uuid=bgp_speaker_id)
i = i + 1
def _test_auto_schedule(self, host_index):
scheduler = bgp_dras.ChanceScheduler()
self.ctx = context.get_admin_context()
msg = 'host_index = %s' % host_index
# create hosts
hosts = ['%s-agent-%s' % (host_index, i)
for i in range(self.host_count)]
bgp_dragents = self._create_and_set_agents_down(hosts,
self.agent_count,
self.down_agent_count)
# create bgp_speakers
self._bgp_speakers = ['%s-bgp-speaker-%s' % (host_index, i)
for i in range(self.bgp_speaker_count)]
self._save_bgp_speakers(self._bgp_speakers)
# pre schedule the bgp_speakers to the agents defined in
# self.hosted_bgp_speakers before calling auto_schedule_bgp_speaker
for agent, bgp_speakers in self.hosted_bgp_speakers.items():
agent_index = self._extract_index(agent)
for bgp_speaker in bgp_speakers:
bs_index = self._extract_index(bgp_speaker)
scheduler.bind(self.ctx, [bgp_dragents[agent_index]],
self._bgp_speakers[bs_index])
retval = scheduler.schedule_unscheduled_bgp_speakers(self.ctx,
hosts[host_index])
self.assertEqual(self.expected_schedule_return_value, retval,
message=msg)
if self.agent_count:
agent_id = bgp_dragents[host_index].id
hosted_bgp_speakers = self._get_hosted_bgp_speakers_on_dragent(
agent_id)
hosted_bs_ids = [self._strip_host_index(net)
for net in hosted_bgp_speakers]
expected_hosted_bgp_speakers = self.expected_hosted_bgp_speakers[
'agent-%s' % host_index]
self.assertCountEqual(hosted_bs_ids, expected_hosted_bgp_speakers,
msg)
def test_auto_schedule(self):
for i in range(self.host_count):
self._test_auto_schedule(i)