nova/nova/tests/cells/test_cells_scheduler.py

207 lines
8.2 KiB
Python

# Copyright (c) 2012 Rackspace Hosting
# 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.
"""
Tests For CellsScheduler
"""
import time
from nova.compute import vm_states
from nova import context
from nova import db
from nova import exception
from nova.openstack.common import cfg
from nova.openstack.common import uuidutils
from nova import test
from nova.tests.cells import fakes
CONF = cfg.CONF
CONF.import_opt('scheduler_retries', 'nova.cells.scheduler', group='cells')
class CellsSchedulerTestCase(test.TestCase):
"""Test case for CellsScheduler class."""
def setUp(self):
super(CellsSchedulerTestCase, self).setUp()
fakes.init(self)
self.msg_runner = fakes.get_message_runner('api-cell')
self.scheduler = self.msg_runner.scheduler
self.state_manager = self.msg_runner.state_manager
self.my_cell_state = self.state_manager.get_my_state()
self.ctxt = context.RequestContext('fake', 'fake')
instance_uuids = []
for x in xrange(3):
instance_uuids.append(uuidutils.generate_uuid())
self.instance_uuids = instance_uuids
self.request_spec = {'instance_uuids': instance_uuids,
'other': 'stuff'}
def test_create_instances_here(self):
# Just grab the first instance type
inst_type = db.instance_type_get(self.ctxt, 1)
image = {'properties': {}}
instance_props = {'hostname': 'meow',
'display_name': 'moo',
'image_ref': 'fake_image_ref',
'user_id': self.ctxt.user_id,
'project_id': self.ctxt.project_id}
request_spec = {'instance_type': inst_type,
'image': image,
'security_group': ['default'],
'block_device_mapping': [],
'instance_properties': instance_props,
'instance_uuids': self.instance_uuids}
call_info = {'uuids': []}
def _fake_instance_update_at_top(_ctxt, instance):
call_info['uuids'].append(instance['uuid'])
self.stubs.Set(self.msg_runner, 'instance_update_at_top',
_fake_instance_update_at_top)
self.scheduler._create_instances_here(self.ctxt, request_spec)
self.assertEqual(self.instance_uuids, call_info['uuids'])
for instance_uuid in self.instance_uuids:
instance = db.instance_get_by_uuid(self.ctxt, instance_uuid)
self.assertEqual('meow', instance['hostname'])
self.assertEqual('moo', instance['display_name'])
self.assertEqual('fake_image_ref', instance['image_ref'])
def test_run_instance_selects_child_cell(self):
# Make sure there's no capacity info so we're sure to
# select a child cell
our_cell_info = self.state_manager.get_my_state()
our_cell_info.capacities = {}
call_info = {'times': 0}
orig_fn = self.msg_runner.schedule_run_instance
def msg_runner_schedule_run_instance(ctxt, target_cell,
host_sched_kwargs):
# This gets called twice. Once for our running it
# in this cell.. and then it'll get called when the
# child cell is picked. So, first time.. just run it
# like normal.
if not call_info['times']:
call_info['times'] += 1
return orig_fn(ctxt, target_cell, host_sched_kwargs)
call_info['ctxt'] = ctxt
call_info['target_cell'] = target_cell
call_info['host_sched_kwargs'] = host_sched_kwargs
self.stubs.Set(self.msg_runner, 'schedule_run_instance',
msg_runner_schedule_run_instance)
host_sched_kwargs = {'request_spec': self.request_spec}
self.msg_runner.schedule_run_instance(self.ctxt,
self.my_cell_state, host_sched_kwargs)
self.assertEqual(self.ctxt, call_info['ctxt'])
self.assertEqual(host_sched_kwargs, call_info['host_sched_kwargs'])
child_cells = self.state_manager.get_child_cells()
self.assertIn(call_info['target_cell'], child_cells)
def test_run_instance_selects_current_cell(self):
# Make sure there's no child cells so that we will be
# selected
self.state_manager.child_cells = {}
call_info = {}
def fake_create_instances_here(ctxt, request_spec):
call_info['ctxt'] = ctxt
call_info['request_spec'] = request_spec
def fake_rpc_run_instance(ctxt, **host_sched_kwargs):
call_info['host_sched_kwargs'] = host_sched_kwargs
self.stubs.Set(self.scheduler, '_create_instances_here',
fake_create_instances_here)
self.stubs.Set(self.scheduler.scheduler_rpcapi,
'run_instance', fake_rpc_run_instance)
host_sched_kwargs = {'request_spec': self.request_spec,
'other': 'stuff'}
self.msg_runner.schedule_run_instance(self.ctxt,
self.my_cell_state, host_sched_kwargs)
self.assertEqual(self.ctxt, call_info['ctxt'])
self.assertEqual(self.request_spec, call_info['request_spec'])
self.assertEqual(host_sched_kwargs, call_info['host_sched_kwargs'])
def test_run_instance_retries_when_no_cells_avail(self):
self.flags(scheduler_retries=7, group='cells')
host_sched_kwargs = {'request_spec': self.request_spec}
call_info = {'num_tries': 0, 'errored_uuids': []}
def fake_run_instance(message, host_sched_kwargs):
call_info['num_tries'] += 1
raise exception.NoCellsAvailable()
def fake_sleep(_secs):
return
def fake_instance_update(ctxt, instance_uuid, values):
self.assertEqual(vm_states.ERROR, values['vm_state'])
call_info['errored_uuids'].append(instance_uuid)
self.stubs.Set(self.scheduler, '_run_instance', fake_run_instance)
self.stubs.Set(time, 'sleep', fake_sleep)
self.stubs.Set(db, 'instance_update', fake_instance_update)
self.msg_runner.schedule_run_instance(self.ctxt,
self.my_cell_state, host_sched_kwargs)
self.assertEqual(8, call_info['num_tries'])
self.assertEqual(self.instance_uuids, call_info['errored_uuids'])
def test_run_instance_on_random_exception(self):
self.flags(scheduler_retries=7, group='cells')
host_sched_kwargs = {'request_spec': self.request_spec}
call_info = {'num_tries': 0,
'errored_uuids1': [],
'errored_uuids2': []}
def fake_run_instance(message, host_sched_kwargs):
call_info['num_tries'] += 1
raise test.TestingException()
def fake_instance_update(ctxt, instance_uuid, values):
self.assertEqual(vm_states.ERROR, values['vm_state'])
call_info['errored_uuids1'].append(instance_uuid)
def fake_instance_update_at_top(ctxt, instance):
self.assertEqual(vm_states.ERROR, instance['vm_state'])
call_info['errored_uuids2'].append(instance['uuid'])
self.stubs.Set(self.scheduler, '_run_instance', fake_run_instance)
self.stubs.Set(db, 'instance_update', fake_instance_update)
self.stubs.Set(self.msg_runner, 'instance_update_at_top',
fake_instance_update_at_top)
self.msg_runner.schedule_run_instance(self.ctxt,
self.my_cell_state, host_sched_kwargs)
# Shouldn't retry
self.assertEqual(1, call_info['num_tries'])
self.assertEqual(self.instance_uuids, call_info['errored_uuids1'])
self.assertEqual(self.instance_uuids, call_info['errored_uuids2'])