From 0a8369cc6944d3886d05f8f7734c6d5dfdf3aa6e Mon Sep 17 00:00:00 2001 From: Ritesh Anand Date: Fri, 24 Apr 2015 12:29:22 -0700 Subject: [PATCH] Added functional tests for L3 schedulers. Legacy mode agents considered. Following test cases are added: Common scenarios: 1. No routers scheduled if no agents are present 2. No routers scheduled if it is already hosted 3. No routers scheduled if all agents are down 4. Router scheduled to the agent if router is not yet hosted 5. Router scheduled to the agent even if it already hosts a router Following scenario specific to least routers scheduler is added: 1. Router is scheduled to agent hosting least routers For each of Chance and Least Router schedulers auto scheduling is also verified. A total of 22 test cases are added. Change-Id: Ic4df299bac83c80abf0890a81d2dd36d15993b33 --- .../scheduler/test_l3_agent_scheduler.py | 281 ++++++++++++++++++ 1 file changed, 281 insertions(+) create mode 100644 neutron/tests/functional/scheduler/test_l3_agent_scheduler.py diff --git a/neutron/tests/functional/scheduler/test_l3_agent_scheduler.py b/neutron/tests/functional/scheduler/test_l3_agent_scheduler.py new file mode 100644 index 000000000..7c3b2e81b --- /dev/null +++ b/neutron/tests/functional/scheduler/test_l3_agent_scheduler.py @@ -0,0 +1,281 @@ +# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. +# 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. + +import random +import testscenarios + +import neutron.extensions.l3 as l3_ext + +from neutron import context +from neutron.scheduler import l3_agent_scheduler +from neutron.tests.common import helpers +from neutron.tests.unit.db import test_db_base_plugin_v2 + +# Required to generate tests from scenarios. Not compatible with nose. +load_tests = testscenarios.load_tests_apply_scenarios + + +class L3SchedulerBaseTest(test_db_base_plugin_v2.NeutronDbPluginV2TestCase): + + """Base class for functional test of L3 schedulers. + Provides basic setup and utility functions. + """ + + def setUp(self): + ext_mgr = l3_ext.L3() + plugin_str = ('neutron.services.l3_router.l3_router_plugin.' + 'L3RouterPlugin') + super(L3SchedulerBaseTest, self).setUp(plugin=plugin_str, + ext_mgr=ext_mgr) + + self.adminContext = context.get_admin_context() + self.adminContext.tenant_id = '_func_test_tenant_' + + def _create_l3_agent(self, host, context, agent_mode='legacy', plugin=None, + state=True): + agent = helpers.register_l3_agent(host, agent_mode) + helpers.set_agent_admin_state(agent.id, state) + return agent + + def _create_router(self, name): + router = {'name': name, 'admin_state_up': True} + return self.plugin.create_router(self.adminContext, {'router': router}) + + def _create_legacy_agents(self, agent_count, down_agent_count): + # Creates legacy l3 agents and sets admin state based on + # down agent count. + self.hosts = ['host-%s' % i for i in range(agent_count)] + self.l3_agents = [self._create_l3_agent(self.hosts[i], + self.adminContext, 'legacy', self.plugin, + (i >= down_agent_count)) for i in range(agent_count)] + + def _create_routers(self, scheduled_router_count, + expected_scheduled_router_count): + routers = [] + if (scheduled_router_count + expected_scheduled_router_count): + for i in range(scheduled_router_count + + expected_scheduled_router_count): + router = self._create_router('schd_rtr' + str(i)) + routers.append(router) + else: + # create at least one router to test scheduling + routers.append(self._create_router('schd_rtr0')) + + return routers + + def _pre_scheduler_routers(self, scheduler, count): + hosting_agents = [] + # schedule routers before calling schedule: + for i in range(count): + router = self.routers[i] + agent = random.choice(self.l3_agents) + scheduler.bind_router(self.adminContext, router['id'], agent) + hosting_agents.append(agent) + return hosting_agents + + def _test_auto_schedule(self, expected_count): + router_ids = [rtr['id'] for rtr in self.routers] + + did_it_schedule = False + + # Try scheduling on each host + for host in self.hosts: + did_it_schedule = self.scheduler.auto_schedule_routers( + self.plugin, + self.adminContext, + host, + router_ids) + if did_it_schedule: + break + + if expected_count: + self.assertTrue(did_it_schedule, 'Failed to schedule agent') + else: + self.assertFalse(did_it_schedule, 'Agent scheduled, not expected') + + +class L3ChanceSchedulerTestCase(L3SchedulerBaseTest): + + """Test various scenarios for chance scheduler. + + agent_count + Number of l3 agents (also number of hosts). + + down_agent_count + Number of l3 agents which are down. + + scheduled_router_count + Number of routers that have been previously scheduled. + + expected_scheduled_router_count + Number of newly scheduled routers. + """ + + scenarios = [ + ('No routers scheduled if no agents are present', + dict(agent_count=0, + down_agent_count=0, + scheduled_router_count=0, + expected_scheduled_router_count=0)), + + ('No routers scheduled if it is already hosted', + dict(agent_count=1, + down_agent_count=0, + scheduled_router_count=1, + expected_scheduled_router_count=0)), + + ('No routers scheduled if all agents are down', + dict(agent_count=2, + down_agent_count=2, + scheduled_router_count=0, + expected_scheduled_router_count=0)), + + ('Router scheduled to the agent if router is not yet hosted', + dict(agent_count=1, + down_agent_count=0, + scheduled_router_count=0, + expected_scheduled_router_count=1)), + + ('Router scheduled to the agent even if it already hosts a router', + dict(agent_count=1, + down_agent_count=0, + scheduled_router_count=1, + expected_scheduled_router_count=1)), + ] + + def setUp(self): + super(L3ChanceSchedulerTestCase, self).setUp() + self._create_legacy_agents(self.agent_count, self.down_agent_count) + self.routers = self._create_routers(self.scheduled_router_count, + self.expected_scheduled_router_count) + self.scheduler = l3_agent_scheduler.ChanceScheduler() + + def test_chance_schedule_router(self): + # Pre schedule routers + self._pre_scheduler_routers(self.scheduler, + self.scheduled_router_count) + # schedule: + actual_scheduled_agent = self.scheduler.schedule( + self.plugin, + self.adminContext, + self.routers[-1]['id']) + + if self.expected_scheduled_router_count: + self.assertIsNotNone(actual_scheduled_agent, + message='Failed to schedule agent') + else: + self.assertIsNone(actual_scheduled_agent, + message='Agent scheduled but not expected') + + def test_auto_schedule_routers(self): + # Pre schedule routers + self._pre_scheduler_routers(self.scheduler, + self.scheduled_router_count) + # The test + self._test_auto_schedule(self.expected_scheduled_router_count) + + +class L3LeastRoutersSchedulerTestCase(L3SchedulerBaseTest): + + """Test various scenarios for least router scheduler. + + agent_count + Number of l3 agents (also number of hosts). + + down_agent_count + Number of l3 agents which are down. + + scheduled_router_count + Number of routers that have been previously scheduled + + expected_scheduled_router_count + Number of newly scheduled routers + """ + + scenarios = [ + ('No routers scheduled if no agents are present', + dict(agent_count=0, + down_agent_count=0, + scheduled_router_count=0, + expected_scheduled_router_count=0)), + + ('No routers scheduled if it is already hosted', + dict(agent_count=1, + down_agent_count=0, + scheduled_router_count=1, + expected_scheduled_router_count=1)), + + ('No routers scheduled if all agents are down', + dict(agent_count=2, + down_agent_count=2, + scheduled_router_count=0, + expected_scheduled_router_count=0)), + + ('Router scheduled to the agent if router is not yet hosted', + dict(agent_count=1, + down_agent_count=0, + scheduled_router_count=0, + expected_scheduled_router_count=1)), + + ('Router scheduled to the agent even if it already hosts a router', + dict(agent_count=1, + down_agent_count=0, + scheduled_router_count=1, + expected_scheduled_router_count=1)), + + ('Router is scheduled to agent hosting least routers', + dict(agent_count=2, + down_agent_count=0, + scheduled_router_count=1, + expected_scheduled_router_count=1)), + ] + + def setUp(self): + super(L3LeastRoutersSchedulerTestCase, self).setUp() + self._create_legacy_agents(self.agent_count, self.down_agent_count) + self.routers = self._create_routers(self.scheduled_router_count, + self.expected_scheduled_router_count) + self.scheduler = l3_agent_scheduler.LeastRoutersScheduler() + + def test_least_routers_schedule(self): + # Pre schedule routers + hosting_agents = self._pre_scheduler_routers(self.scheduler, + self.scheduled_router_count) + + actual_scheduled_agent = self.scheduler.schedule( + self.plugin, + self.adminContext, + self.routers[-1]['id']) + + if self.expected_scheduled_router_count: + # For case where there is just one agent: + if self.agent_count == 1: + self.assertEqual(actual_scheduled_agent.id, + self.l3_agents[0].id) + else: + self.assertNotIn(actual_scheduled_agent.id, + [x.id for x in hosting_agents], + message='The expected agent was not scheduled') + else: + self.assertIsNone(actual_scheduled_agent, + message='Expected no agent to be scheduled,' + ' but it got scheduled') + + def test_auto_schedule_routers(self): + # Pre schedule routers + self._pre_scheduler_routers(self.scheduler, + self.scheduled_router_count) + # The test + self._test_auto_schedule(self.expected_scheduled_router_count) -- 2.45.2