Merge "Add functional test for availability_zone support"

This commit is contained in:
Jenkins 2015-12-21 22:16:07 +00:00 committed by Gerrit Code Review
commit c4e1402e62
3 changed files with 439 additions and 4 deletions

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import collections
import six
import testscenarios
@ -212,6 +213,11 @@ class TestAutoSchedule(test_dhcp_sch.TestDhcpSchedulerBaseTestCase,
This stores the expected networks that should have been scheduled
(or that could have already been scheduled) for each agent
after the 'auto_schedule_networks' function is called.
no_network_with_az_match
If this parameter is True, there is no unscheduled network with
availability_zone_hints matches to an availability_zone of agents
to be scheduled. The default is False.
"""
scenarios = [
@ -320,6 +326,16 @@ class TestAutoSchedule(test_dhcp_sch.TestDhcpSchedulerBaseTestCase,
expected_auto_schedule_return_value=False,
expected_hosted_networks={'agent-0': [],
'agent-1': []})),
('No agents scheduled if unscheduled network does not match AZ',
dict(agent_count=1,
max_agents_per_network=1,
network_count=1,
networks_with_dhcp_disabled=[],
hosted_networks={},
expected_auto_schedule_return_value=True,
expected_hosted_networks={'agent-0': []},
no_network_with_az_match=True)),
]
def _strip_host_index(self, name):
@ -346,8 +362,10 @@ class TestAutoSchedule(test_dhcp_sch.TestDhcpSchedulerBaseTestCase,
return subnets
def get_network(self, context, net_id):
# TODO(hichihara): add test cases of AZ scheduler
return {'availability_zone_hints': []}
az_hints = []
if getattr(self, 'no_network_with_az_match', False):
az_hints = ['not-match']
return {'availability_zone_hints': az_hints}
def _get_hosted_networks_on_dhcp_agent(self, agent_id):
query = self.ctx.session.query(
@ -400,3 +418,144 @@ class TestAutoSchedule(test_dhcp_sch.TestDhcpSchedulerBaseTestCase,
def test_auto_schedule(self):
for i in range(self.agent_count):
self._test_auto_schedule(i)
class TestAZAwareWeightScheduler(test_dhcp_sch.TestDhcpSchedulerBaseTestCase,
agentschedulers_db.DhcpAgentSchedulerDbMixin,
agents_db.AgentDbMixin,
common_db_mixin.CommonDbMixin):
"""Test various scenarios for AZAwareWeightScheduler.schedule.
az_count
Number of AZs.
network_az_hints
Number of AZs in availability_zone_hints of the network.
agent_count[each az]
Number of dhcp agents (also number of hosts).
max_agents_per_network
Maximum DHCP Agents that can be scheduled for a network.
scheduled_agent_count[each az]
Number of agents the network has previously scheduled
down_agent_count[each az]
Number of dhcp agents which are down
expected_scheduled_agent_count[each az]
Number of scheduled agents the schedule() should return
or 'None' if the schedule() cannot schedule the network.
"""
scenarios = [
('Single hint, Single agent, Scheduled an agent of the specified AZ',
dict(az_count=2,
network_az_hints=1,
agent_count=[1, 1],
max_agents_per_network=1,
scheduled_agent_count=[0, 0],
down_agent_count=[0, 0],
expected_scheduled_agent_count=[1, 0])),
('Multi hints, Multi agents Scheduled agents of the specified AZs',
dict(az_count=3,
network_az_hints=2,
agent_count=[1, 1, 1],
max_agents_per_network=2,
scheduled_agent_count=[0, 0, 0],
down_agent_count=[0, 0, 0],
expected_scheduled_agent_count=[1, 1, 0])),
('Single hint, Multi agents, Scheduled agents of the specified AZ',
dict(az_count=2,
network_az_hints=1,
agent_count=[2, 1],
max_agents_per_network=2,
scheduled_agent_count=[0, 0],
down_agent_count=[0, 0],
expected_scheduled_agent_count=[2, 0])),
('Multi hints, Multi agents, Only single AZ available',
dict(az_count=2,
network_az_hints=2,
agent_count=[2, 1],
max_agents_per_network=2,
scheduled_agent_count=[0, 0],
down_agent_count=[0, 1],
expected_scheduled_agent_count=[2, 0])),
('Multi hints, Multi agents, Not enough agents',
dict(az_count=3,
network_az_hints=3,
agent_count=[1, 1, 1],
max_agents_per_network=3,
scheduled_agent_count=[0, 0, 0],
down_agent_count=[0, 1, 0],
expected_scheduled_agent_count=[1, 0, 1])),
('Multi hints, Multi agents, Partially scheduled, Another AZ selected',
dict(az_count=3,
network_az_hints=2,
agent_count=[1, 1, 1],
max_agents_per_network=2,
scheduled_agent_count=[1, 0, 0],
down_agent_count=[0, 0, 0],
expected_scheduled_agent_count=[0, 1, 0])),
('No hint, Scheduled independent to AZ',
dict(az_count=3,
network_az_hints=0,
agent_count=[1, 1, 1],
max_agents_per_network=3,
scheduled_agent_count=[0, 0, 0],
down_agent_count=[0, 0, 0],
expected_scheduled_agent_count=[1, 1, 1])),
]
def _set_network_az_hints(self):
self.network['availability_zone_hints'] = []
for i in range(self.network_az_hints):
self.network['availability_zone_hints'].append('az%s' % i)
def test_schedule_network(self):
self.config(dhcp_agents_per_network=self.max_agents_per_network)
scheduler = dhcp_agent_scheduler.AZAwareWeightScheduler()
self._set_network_az_hints()
# create dhcp agents
for i in range(self.az_count):
az = 'az%s' % i
hosts = ['%s-host-%s' % (az, j)
for j in range(self.agent_count[i])]
dhcp_agents = self._create_and_set_agents_down(
hosts, down_agent_count=self.down_agent_count[i], az=az)
active_agents = dhcp_agents[self.down_agent_count[i]:]
# schedule some agents before calling schedule
if self.scheduled_agent_count[i]:
# schedule the network
schedule_agents = active_agents[:self.scheduled_agent_count[i]]
scheduler.resource_filter.bind(
self.ctx, schedule_agents, self.network_id)
actual_scheduled_agents = scheduler.schedule(self, self.ctx,
self.network)
scheduled_azs = collections.defaultdict(int)
for agent in actual_scheduled_agents:
scheduled_azs[agent['availability_zone']] += 1
hosted_agents = self.list_dhcp_agents_hosting_network(
self.ctx, self.network_id)
hosted_azs = collections.defaultdict(int)
for agent in hosted_agents['agents']:
hosted_azs[agent['availability_zone']] += 1
for i in range(self.az_count):
self.assertEqual(self.expected_scheduled_agent_count[i],
scheduled_azs.get('az%s' % i, 0))
self.assertEqual(self.scheduled_agent_count[i] +
scheduled_azs.get('az%s' % i, 0),
hosted_azs.get('az%s' % i, 0))

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import collections
import random
import testscenarios
@ -272,3 +273,276 @@ class L3LeastRoutersSchedulerTestCase(L3SchedulerBaseTest):
self.scheduled_router_count)
# The test
self._test_auto_schedule(self.expected_scheduled_router_count)
class L3AZSchedulerBaseTest(test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
def setUp(self):
core_plugin = 'neutron.plugins.ml2.plugin.Ml2Plugin'
super(L3AZSchedulerBaseTest, self).setUp(plugin=core_plugin)
self.l3_plugin = l3_router_plugin.L3RouterPlugin()
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, az='nova'):
agent = helpers.register_l3_agent(host, agent_mode, az=az)
helpers.set_agent_admin_state(agent.id, state)
return agent
def _create_legacy_agents(self, agent_count, down_agent_count, az):
# Creates legacy l3 agents and sets admin state based on
# down agent count.
hosts = ['%s-host-%s' % (az, i) for i in range(agent_count)]
l3_agents = [
self._create_l3_agent(hosts[i], self.adminContext, 'legacy',
self.l3_plugin, (i >= down_agent_count),
az=az)
for i in range(agent_count)]
return l3_agents
def _create_router(self, az_hints, ha):
router = {'name': 'router1', 'admin_state_up': True,
'availability_zone_hints': az_hints}
if ha:
router['ha'] = True
return self.l3_plugin.create_router(
self.adminContext, {'router': router})
class L3AZLeastRoutersSchedulerTestCase(L3AZSchedulerBaseTest):
"""Test various scenarios for AZ router scheduler.
az_count
Number of AZs.
router_az_hints
Number of AZs in availability_zone_hints of the router.
agent_count[each az]
Number of l3 agents (also number of hosts).
max_l3_agents_per_router
Maximum number of agents on which a router will be scheduled.
0 means test for regular router.
min_l3_agents_per_router
Minimum number of agents on which a router will be scheduled.
N/A for regular router test.
down_agent_count[each az]
Number of l3 agents which are down.
expected_scheduled_agent_count[each az]
Number of newly scheduled l3 agents.
"""
scenarios = [
('Regular router, Scheduled specified AZ',
dict(az_count=2,
router_az_hints=1,
agent_count=[1, 1],
max_l3_agents_per_router=0,
min_l3_agents_per_router=0,
down_agent_count=[0, 0],
expected_scheduled_agent_count=[1, 0])),
('HA router, Scheduled specified AZs',
dict(az_count=3,
router_az_hints=2,
agent_count=[1, 1, 1],
max_l3_agents_per_router=2,
min_l3_agents_per_router=2,
down_agent_count=[0, 0, 0],
expected_scheduled_agent_count=[1, 1, 0])),
('HA router, max_l3_agents_per_routers > az_hints',
dict(az_count=2,
router_az_hints=2,
agent_count=[2, 1],
max_l3_agents_per_router=3,
min_l3_agents_per_router=2,
down_agent_count=[0, 0],
expected_scheduled_agent_count=[2, 1])),
('HA router, not enough agents',
dict(az_count=3,
router_az_hints=2,
agent_count=[2, 2, 2],
max_l3_agents_per_router=3,
min_l3_agents_per_router=2,
down_agent_count=[1, 1, 0],
expected_scheduled_agent_count=[1, 1, 0])),
]
def test_schedule_router(self):
scheduler = l3_agent_scheduler.AZLeastRoutersScheduler()
ha = False
if self.max_l3_agents_per_router:
self.config(max_l3_agents_per_router=self.max_l3_agents_per_router)
self.config(min_l3_agents_per_router=self.min_l3_agents_per_router)
ha = True
# create l3 agents
for i in range(self.az_count):
az = 'az%s' % i
self._create_legacy_agents(self.agent_count[i],
self.down_agent_count[i], az)
# create router.
# note that ha-router needs enough agents beforehand.
az_hints = ['az%s' % i for i in range(self.router_az_hints)]
router = self._create_router(az_hints, ha)
scheduler.schedule(self.l3_plugin, self.adminContext, router['id'])
# schedule returns only one agent. so get all agents scheduled.
scheduled_agents = self.l3_plugin.get_l3_agents_hosting_routers(
self.adminContext, [router['id']])
scheduled_azs = collections.defaultdict(int)
for agent in scheduled_agents:
scheduled_azs[agent['availability_zone']] += 1
for i in range(self.az_count):
self.assertEqual(self.expected_scheduled_agent_count[i],
scheduled_azs.get('az%s' % i, 0))
class L3AZAutoScheduleTestCaseBase(L3AZSchedulerBaseTest):
"""Test various scenarios for AZ router scheduler.
az_count
Number of AZs.
router_az_hints
Number of AZs in availability_zone_hints of the router.
agent_az
AZ of newly activated l3 agent.
agent_count[each az]
Number of l3 agents (also number of hosts).
max_l3_agents_per_router
Maximum number of agents on which a router will be scheduled.
0 means test for regular router.
min_l3_agents_per_router
Minimum number of agents on which a router will be scheduled.
N/A for regular router test.
down_agent_count[each az]
Number of l3 agents which are down.
scheduled_agent_count[each az]
Number of l3 agents that have been previously scheduled
expected_scheduled_agent_count[each az]
Number of newly scheduled l3 agents
"""
scenarios = [
('Regular router, not scheduled, agent in specified AZ activated',
dict(az_count=2,
router_az_hints=1,
agent_az='az0',
agent_count=[1, 1],
max_l3_agents_per_router=0,
min_l3_agents_per_router=0,
down_agent_count=[1, 1],
scheduled_agent_count=[0, 0],
expected_scheduled_agent_count=[1, 0])),
('Regular router, not scheduled, agent not in specified AZ activated',
dict(az_count=2,
router_az_hints=1,
agent_az='az1',
agent_count=[1, 1],
max_l3_agents_per_router=0,
min_l3_agents_per_router=0,
down_agent_count=[1, 1],
scheduled_agent_count=[0, 0],
expected_scheduled_agent_count=[0, 0])),
('HA router, not scheduled, agent in specified AZ activated',
dict(az_count=3,
router_az_hints=2,
agent_az='az1',
agent_count=[1, 1, 1],
max_l3_agents_per_router=2,
min_l3_agents_per_router=2,
down_agent_count=[0, 1, 0],
scheduled_agent_count=[0, 0, 0],
expected_scheduled_agent_count=[0, 1, 0])),
('HA router, not scheduled, agent not in specified AZ activated',
dict(az_count=3,
router_az_hints=2,
agent_az='az2',
agent_count=[1, 1, 1],
max_l3_agents_per_router=2,
min_l3_agents_per_router=2,
down_agent_count=[0, 0, 1],
scheduled_agent_count=[0, 0, 0],
expected_scheduled_agent_count=[0, 0, 0])),
('HA router, partial scheduled, agent in specified AZ activated',
dict(az_count=3,
router_az_hints=2,
agent_az='az1',
agent_count=[1, 1, 1],
max_l3_agents_per_router=2,
min_l3_agents_per_router=2,
down_agent_count=[0, 1, 0],
scheduled_agent_count=[1, 0, 0],
expected_scheduled_agent_count=[1, 1, 0])),
]
def test_auto_schedule_router(self):
scheduler = l3_agent_scheduler.AZLeastRoutersScheduler()
ha = False
if self.max_l3_agents_per_router:
self.config(max_l3_agents_per_router=self.max_l3_agents_per_router)
self.config(min_l3_agents_per_router=self.min_l3_agents_per_router)
ha = True
# create l3 agents
l3_agents = {}
for i in range(self.az_count):
az = 'az%s' % i
l3_agents[az] = self._create_legacy_agents(
self.agent_count[i], self.down_agent_count[i], az)
# create router.
# note that ha-router needs enough agents beforehand.
az_hints = ['az%s' % i for i in range(self.router_az_hints)]
router = self._create_router(az_hints, ha)
# schedule some agents before calling auto schedule
for i in range(self.az_count):
az = 'az%s' % i
for j in range(self.scheduled_agent_count[i]):
agent = l3_agents[az][j + self.down_agent_count[i]]
scheduler.bind_router(self.adminContext, router['id'], agent)
# activate down agent and call auto_schedule_routers
activate_agent = l3_agents[self.agent_az][0]
helpers.set_agent_admin_state(activate_agent['id'],
admin_state_up=True)
scheduler.auto_schedule_routers(self.l3_plugin, self.adminContext,
activate_agent['host'], None)
scheduled_agents = self.l3_plugin.get_l3_agents_hosting_routers(
self.adminContext, [router['id']])
scheduled_azs = collections.defaultdict(int)
for agent in scheduled_agents:
scheduled_azs[agent['availability_zone']] += 1
for i in range(self.az_count):
self.assertEqual(self.expected_scheduled_agent_count[i],
scheduled_azs.get('az%s' % i, 0))

View File

@ -45,14 +45,16 @@ class TestDhcpSchedulerBaseTestCase(testlib_api.SqlTestCase):
self._save_networks([self.network_id])
def _create_and_set_agents_down(self, hosts, down_agent_count=0,
admin_state_up=True):
admin_state_up=True,
az=helpers.DEFAULT_AZ):
agents = []
for i, host in enumerate(hosts):
is_alive = i >= down_agent_count
agents.append(helpers.register_dhcp_agent(
host,
admin_state_up=admin_state_up,
alive=is_alive))
alive=is_alive,
az=az))
return agents
def _save_networks(self, networks):