Merge "Bump major version of Scheduler RPC API to 4.0"

This commit is contained in:
Jenkins 2014-12-12 22:09:08 +00:00 committed by Gerrit Code Review
commit 614d88f817
9 changed files with 52 additions and 818 deletions

View File

@ -23,7 +23,6 @@ import random
from oslo.config import cfg
from nova.compute import rpcapi as compute_rpcapi
from nova import exception
from nova.i18n import _
from nova.scheduler import driver
@ -35,10 +34,6 @@ CONF.import_opt('compute_topic', 'nova.compute.rpcapi')
class ChanceScheduler(driver.Scheduler):
"""Implements Scheduler as a random node selector."""
def __init__(self, *args, **kwargs):
super(ChanceScheduler, self).__init__(*args, **kwargs)
self.compute_rpcapi = compute_rpcapi.ComputeAPI()
def _filter_hosts(self, request_spec, hosts, filter_properties):
"""Filter a list of hosts based on request_spec."""
@ -77,34 +72,3 @@ class ChanceScheduler(driver.Scheduler):
if len(dests) < num_instances:
raise exception.NoValidHost(reason='')
return dests
# NOTE(alaski): Remove this method when the scheduler rpc interface is
# bumped to 4.x as it is no longer used.
def schedule_run_instance(self, context, request_spec,
admin_password, injected_files,
requested_networks, is_first_time,
filter_properties, legacy_bdm_in_spec):
"""Create and run an instance or instances."""
instance_uuids = request_spec.get('instance_uuids')
for num, instance_uuid in enumerate(instance_uuids):
request_spec['instance_properties']['launch_index'] = num
try:
host = self._schedule(context, CONF.compute_topic,
request_spec, filter_properties)
updated_instance = driver.instance_update_db(context,
instance_uuid)
self.compute_rpcapi.run_instance(context,
instance=updated_instance, host=host,
requested_networks=requested_networks,
injected_files=injected_files,
admin_password=admin_password,
is_first_time=is_first_time,
request_spec=request_spec,
filter_properties=filter_properties,
legacy_bdm_in_spec=legacy_bdm_in_spec)
except Exception as ex:
# NOTE(vish): we don't reraise the exception here to make sure
# that all instances in the request get set to
# error properly
driver.handle_schedule_error(context, ex, instance_uuid,
request_spec)

View File

@ -115,16 +115,6 @@ class Scheduler(object):
for service in services
if self.servicegroup_api.service_is_up(service)]
# NOTE(alaski): Remove this method when the scheduler rpc interface is
# bumped to 4.x as it is no longer used.
def schedule_run_instance(self, context, request_spec,
admin_password, injected_files,
requested_networks, is_first_time,
filter_properties, legacy_bdm_in_spec):
"""Must override schedule_run_instance method for scheduler to work."""
msg = _("Driver must implement schedule_run_instance")
raise NotImplementedError(msg)
def select_destinations(self, context, request_spec, filter_properties):
"""Must override select_destinations method.

View File

@ -23,14 +23,12 @@ import random
from oslo.config import cfg
from nova.compute import rpcapi as compute_rpcapi
from nova import exception
from nova.i18n import _, _LI, _LW
from nova.i18n import _
from nova.openstack.common import log as logging
from nova import rpc
from nova.scheduler import driver
from nova.scheduler import scheduler_options
from nova.scheduler import utils as scheduler_utils
CONF = cfg.CONF
@ -57,81 +55,8 @@ class FilterScheduler(driver.Scheduler):
def __init__(self, *args, **kwargs):
super(FilterScheduler, self).__init__(*args, **kwargs)
self.options = scheduler_options.SchedulerOptions()
self.compute_rpcapi = compute_rpcapi.ComputeAPI()
self.notifier = rpc.get_notifier('scheduler')
# NOTE(alaski): Remove this method when the scheduler rpc interface is
# bumped to 4.x as it is no longer used.
def schedule_run_instance(self, context, request_spec,
admin_password, injected_files,
requested_networks, is_first_time,
filter_properties, legacy_bdm_in_spec):
"""Provisions instances that needs to be scheduled
Applies filters and weighters on request properties to get a list of
compute hosts and calls them to spawn instance(s).
"""
payload = dict(request_spec=request_spec)
self.notifier.info(context, 'scheduler.run_instance.start', payload)
instance_uuids = request_spec.get('instance_uuids')
LOG.info(_LI("Attempting to build %(num_instances)d instance(s) "
"uuids: %(instance_uuids)s"),
{'num_instances': len(instance_uuids),
'instance_uuids': instance_uuids})
LOG.debug("Request Spec: %s" % request_spec)
# check retry policy. Rather ugly use of instance_uuids[0]...
# but if we've exceeded max retries... then we really only
# have a single instance.
scheduler_utils.populate_retry(filter_properties,
instance_uuids[0])
weighed_hosts = self._schedule(context, request_spec,
filter_properties)
# NOTE: Pop instance_uuids as individual creates do not need the
# set of uuids. Do not pop before here as the upper exception
# handler fo NoValidHost needs the uuid to set error state
instance_uuids = request_spec.pop('instance_uuids')
# NOTE(comstud): Make sure we do not pass this through. It
# contains an instance of RpcContext that cannot be serialized.
filter_properties.pop('context', None)
for num, instance_uuid in enumerate(instance_uuids):
request_spec['instance_properties']['launch_index'] = num
try:
try:
weighed_host = weighed_hosts.pop(0)
LOG.info(_LI("Choosing host %(weighed_host)s "
"for instance %(instance_uuid)s"),
{'weighed_host': weighed_host,
'instance_uuid': instance_uuid})
except IndexError:
raise exception.NoValidHost(reason="")
self._provision_resource(context, weighed_host,
request_spec,
filter_properties,
requested_networks,
injected_files, admin_password,
is_first_time,
instance_uuid=instance_uuid,
legacy_bdm_in_spec=legacy_bdm_in_spec)
except Exception as ex:
# NOTE(vish): we don't reraise the exception here to make sure
# that all instances in the request get set to
# error properly
driver.handle_schedule_error(context, ex, instance_uuid,
request_spec)
# scrub retry host list in case we're scheduling multiple
# instances:
retry = filter_properties.get('retry', {})
retry['hosts'] = []
self.notifier.info(context, 'scheduler.run_instance.end', payload)
def select_destinations(self, context, request_spec, filter_properties):
"""Selects a filtered set of hosts and nodes."""
self.notifier.info(context, 'scheduler.select_destinations.start',
@ -161,42 +86,6 @@ class FilterScheduler(driver.Scheduler):
dict(request_spec=request_spec))
return dests
def _provision_resource(self, context, weighed_host, request_spec,
filter_properties, requested_networks, injected_files,
admin_password, is_first_time, instance_uuid=None,
legacy_bdm_in_spec=True):
"""Create the requested resource in this Zone."""
# NOTE(vish): add our current instance back into the request spec
request_spec['instance_uuids'] = [instance_uuid]
payload = dict(request_spec=request_spec,
weighted_host=weighed_host.to_dict(),
instance_id=instance_uuid)
self.notifier.info(context,
'scheduler.run_instance.scheduled', payload)
# Update the metadata if necessary
try:
updated_instance = driver.instance_update_db(context,
instance_uuid)
except exception.InstanceNotFound:
LOG.warning(_LW("Instance disappeared during scheduling"),
context=context, instance_uuid=instance_uuid)
else:
scheduler_utils.populate_filter_properties(filter_properties,
weighed_host.obj)
self.compute_rpcapi.run_instance(context,
instance=updated_instance,
host=weighed_host.obj.host,
request_spec=request_spec,
filter_properties=filter_properties,
requested_networks=requested_networks,
injected_files=injected_files,
admin_password=admin_password, is_first_time=is_first_time,
node=weighed_host.obj.nodename,
legacy_bdm_in_spec=legacy_bdm_in_spec)
def _get_configuration_options(self):
"""Fetch options dictionary. Broken out for testing."""
return self.options.get_configuration()

View File

@ -22,19 +22,14 @@ Scheduler Service
from oslo.config import cfg
from oslo import messaging
from oslo.serialization import jsonutils
from oslo.utils import excutils
from oslo.utils import importutils
from nova.compute import rpcapi as compute_rpcapi
from nova.compute import utils as compute_utils
from nova.compute import vm_states
from nova import exception
from nova import manager
from nova import objects
from nova.openstack.common import log as logging
from nova.openstack.common import periodic_task
from nova import quota
from nova.scheduler import utils as scheduler_utils
LOG = logging.getLogger(__name__)
@ -60,99 +55,15 @@ QUOTAS = quota.QUOTAS
class SchedulerManager(manager.Manager):
"""Chooses a host to run instances on."""
target = messaging.Target(version='3.1')
target = messaging.Target(version='4.0')
def __init__(self, scheduler_driver=None, *args, **kwargs):
if not scheduler_driver:
scheduler_driver = CONF.scheduler_driver
self.driver = importutils.import_object(scheduler_driver)
self.compute_rpcapi = compute_rpcapi.ComputeAPI()
super(SchedulerManager, self).__init__(service_name='scheduler',
*args, **kwargs)
# NOTE(alaski): Remove this method when the scheduler rpc interface is
# bumped to 4.x as it is no longer used.
def run_instance(self, context, request_spec, admin_password,
injected_files, requested_networks, is_first_time,
filter_properties, legacy_bdm_in_spec):
"""Tries to call schedule_run_instance on the driver.
Sets instance vm_state to ERROR on exceptions
"""
instance_uuids = request_spec['instance_uuids']
with compute_utils.EventReporter(context, 'schedule', *instance_uuids):
try:
return self.driver.schedule_run_instance(context,
request_spec, admin_password, injected_files,
requested_networks, is_first_time, filter_properties,
legacy_bdm_in_spec)
except exception.NoValidHost as ex:
# don't re-raise
self._set_vm_state_and_notify('run_instance',
{'vm_state': vm_states.ERROR,
'task_state': None},
context, ex, request_spec)
except Exception as ex:
with excutils.save_and_reraise_exception():
self._set_vm_state_and_notify('run_instance',
{'vm_state': vm_states.ERROR,
'task_state': None},
context, ex, request_spec)
# NOTE(sbauza): Remove this method when the scheduler rpc interface is
# bumped to 4.x as it is no longer used.
def prep_resize(self, context, image, request_spec, filter_properties,
instance, instance_type, reservations):
"""Tries to call schedule_prep_resize on the driver.
Sets instance vm_state to ACTIVE on NoHostFound
Sets vm_state to ERROR on other exceptions
"""
instance_uuid = instance['uuid']
with compute_utils.EventReporter(context, 'schedule', instance_uuid):
try:
request_spec['num_instances'] = len(
request_spec['instance_uuids'])
hosts = self.driver.select_destinations(
context, request_spec, filter_properties)
host_state = hosts[0]
scheduler_utils.populate_filter_properties(filter_properties,
host_state)
# context is not serializable
filter_properties.pop('context', None)
(host, node) = (host_state['host'], host_state['nodename'])
attrs = ['metadata', 'system_metadata', 'info_cache',
'security_groups']
inst_obj = objects.Instance._from_db_object(
context, objects.Instance(), instance,
expected_attrs=attrs)
self.compute_rpcapi.prep_resize(
context, image, inst_obj, instance_type, host,
reservations, request_spec=request_spec,
filter_properties=filter_properties, node=node)
except exception.NoValidHost as ex:
vm_state = instance.get('vm_state', vm_states.ACTIVE)
self._set_vm_state_and_notify('prep_resize',
{'vm_state': vm_state,
'task_state': None},
context, ex, request_spec)
if reservations:
QUOTAS.rollback(context, reservations)
except Exception as ex:
with excutils.save_and_reraise_exception():
self._set_vm_state_and_notify('prep_resize',
{'vm_state': vm_states.ERROR,
'task_state': None},
context, ex, request_spec)
if reservations:
QUOTAS.rollback(context, reservations)
def _set_vm_state_and_notify(self, method, updates, context, ex,
request_spec):
scheduler_utils.set_vm_state_and_notify(
context, 'scheduler', method, updates, ex, request_spec, self.db)
self.additional_endpoints.append(_SchedulerManagerV3Proxy(self))
@periodic_task.periodic_task
def _expire_reservations(self, context):
@ -163,6 +74,30 @@ class SchedulerManager(manager.Manager):
def _run_periodic_tasks(self, context):
self.driver.run_periodic_tasks(context)
@messaging.expected_exceptions(exception.NoValidHost)
def select_destinations(self, context, request_spec, filter_properties):
"""Returns destinations(s) best suited for this request_spec and
filter_properties.
The result should be a list of dicts with 'host', 'nodename' and
'limits' as keys.
"""
dests = self.driver.select_destinations(context, request_spec,
filter_properties)
return jsonutils.to_primitive(dests)
class _SchedulerManagerV3Proxy(object):
target = messaging.Target(version='3.0')
def __init__(self, manager):
self.manager = manager
# NOTE(sbauza): Previous run_instance() and prep_resize() methods were
# removed from the Juno branch before Juno released, so we can safely
# remove them even from the V3.1 proxy as there is no Juno RPC client
# that can call them
@messaging.expected_exceptions(exception.NoValidHost)
def select_destinations(self, context, request_spec, filter_properties):
"""Returns destinations(s) best suited for this request_spec and
@ -178,6 +113,6 @@ class SchedulerManager(manager.Manager):
# is receiving an object, so lookup the flavor to ensure this.
flavor = objects.Flavor.get_by_id(context, flavor['id'])
filter_properties = dict(filter_properties, instance_type=flavor)
dests = self.driver.select_destinations(context, request_spec,
dests = self.manager.select_destinations(context, request_spec,
filter_properties)
return jsonutils.to_primitive(dests)
return dests

View File

@ -86,6 +86,9 @@ class SchedulerAPI(object):
* 3.1 - Made select_destinations() send flavor object
* 4.0 - Removed backwards compat for Icehouse
'''
VERSION_ALIASES = {
@ -93,11 +96,12 @@ class SchedulerAPI(object):
'havana': '2.9',
'icehouse': '3.0',
'juno': '3.0',
'kilo': '4.0',
}
def __init__(self):
super(SchedulerAPI, self).__init__()
target = messaging.Target(topic=CONF.scheduler_topic, version='3.0')
target = messaging.Target(topic=CONF.scheduler_topic, version='4.0')
version_cap = self.VERSION_ALIASES.get(CONF.upgrade_levels.scheduler,
CONF.upgrade_levels.scheduler)
serializer = objects_base.NovaObjectSerializer()
@ -105,14 +109,6 @@ class SchedulerAPI(object):
serializer=serializer)
def select_destinations(self, ctxt, request_spec, filter_properties):
version = '3.1'
if not self.client.can_send_version(version):
version = '3.0'
if 'instance_type' in filter_properties:
flavor = filter_properties['instance_type']
flavor_p = objects_base.obj_to_primitive(flavor)
filter_properties = dict(filter_properties,
instance_type=flavor_p)
cctxt = self.client.prepare(version=version)
cctxt = self.client.prepare(version='4.0')
return cctxt.call(ctxt, 'select_destinations',
request_spec=request_spec, filter_properties=filter_properties)

View File

@ -20,14 +20,9 @@ import random
from mox3 import mox
from nova.compute import rpcapi as compute_rpcapi
from nova.compute import utils as compute_utils
from nova.compute import vm_states
from nova import context
from nova import db
from nova import exception
from nova.scheduler import chance
from nova.scheduler import driver
from nova.tests.unit.scheduler import test_scheduler
@ -62,80 +57,6 @@ class ChanceSchedulerTestCase(test_scheduler.SchedulerTestCase):
filter_properties=filter_properties)
self.assertEqual(filtered, hosts)
def test_basic_schedule_run_instance(self):
ctxt = context.RequestContext('fake', 'fake', False)
ctxt_elevated = 'fake-context-elevated'
instance_opts = {'fake_opt1': 'meow', 'launch_index': -1}
instance1 = {'uuid': 'fake-uuid1'}
instance2 = {'uuid': 'fake-uuid2'}
request_spec = {'instance_uuids': ['fake-uuid1', 'fake-uuid2'],
'instance_properties': instance_opts}
def inc_launch_index(*args):
request_spec['instance_properties']['launch_index'] = (
request_spec['instance_properties']['launch_index'] + 1)
self.mox.StubOutWithMock(ctxt, 'elevated')
self.mox.StubOutWithMock(self.driver, 'hosts_up')
self.mox.StubOutWithMock(random, 'choice')
self.mox.StubOutWithMock(driver, 'instance_update_db')
self.mox.StubOutWithMock(compute_rpcapi.ComputeAPI, 'run_instance')
ctxt.elevated().AndReturn(ctxt_elevated)
# instance 1
hosts_full = ['host1', 'host2', 'host3', 'host4']
self.driver.hosts_up(ctxt_elevated, 'compute').AndReturn(hosts_full)
random.choice(hosts_full).AndReturn('host3')
driver.instance_update_db(ctxt, instance1['uuid']).WithSideEffects(
inc_launch_index).AndReturn(instance1)
compute_rpcapi.ComputeAPI.run_instance(ctxt, host='host3',
instance=instance1, requested_networks=None,
injected_files=None, admin_password=None, is_first_time=None,
request_spec=request_spec, filter_properties={},
legacy_bdm_in_spec=False)
# instance 2
ctxt.elevated().AndReturn(ctxt_elevated)
self.driver.hosts_up(ctxt_elevated, 'compute').AndReturn(hosts_full)
random.choice(hosts_full).AndReturn('host1')
driver.instance_update_db(ctxt, instance2['uuid']).WithSideEffects(
inc_launch_index).AndReturn(instance2)
compute_rpcapi.ComputeAPI.run_instance(ctxt, host='host1',
instance=instance2, requested_networks=None,
injected_files=None, admin_password=None, is_first_time=None,
request_spec=request_spec, filter_properties={},
legacy_bdm_in_spec=False)
self.mox.ReplayAll()
self.driver.schedule_run_instance(ctxt, request_spec,
None, None, None, None, {}, False)
def test_basic_schedule_run_instance_no_hosts(self):
ctxt = context.RequestContext('fake', 'fake', False)
ctxt_elevated = 'fake-context-elevated'
uuid = 'fake-uuid1'
instance_opts = {'fake_opt1': 'meow', 'launch_index': -1}
request_spec = {'instance_uuids': [uuid],
'instance_properties': instance_opts}
self.mox.StubOutWithMock(ctxt, 'elevated')
self.mox.StubOutWithMock(self.driver, 'hosts_up')
self.mox.StubOutWithMock(compute_utils, 'add_instance_fault_from_exc')
self.mox.StubOutWithMock(db, 'instance_update_and_get_original')
# instance 1
ctxt.elevated().AndReturn(ctxt_elevated)
self.driver.hosts_up(ctxt_elevated, 'compute').AndReturn([])
old_ref, new_ref = db.instance_update_and_get_original(ctxt, uuid,
{'vm_state': vm_states.ERROR,
'task_state': None}).AndReturn(({}, {}))
compute_utils.add_instance_fault_from_exc(ctxt, new_ref,
mox.IsA(exception.NoValidHost), mox.IgnoreArg())
self.mox.ReplayAll()
self.driver.schedule_run_instance(
ctxt, request_spec, None, None, None, None, {}, False)
def test_select_destinations(self):
ctxt = context.RequestContext('fake', 'fake', False)
ctxt_elevated = 'fake-context-elevated'

View File

@ -17,14 +17,9 @@ Tests For Filter Scheduler.
"""
import mock
from mox3 import mox
from nova.compute import utils as compute_utils
from nova.compute import vm_states
from nova import context
from nova import db
from nova import exception
from nova.scheduler import driver
from nova.scheduler import filter_scheduler
from nova.scheduler import host_manager
from nova.scheduler import utils as scheduler_utils
@ -42,108 +37,6 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
driver_cls = filter_scheduler.FilterScheduler
def test_run_instance_no_hosts(self):
sched = fakes.FakeFilterScheduler()
uuid = 'fake-uuid1'
fake_context = context.RequestContext('user', 'project')
instance_properties = {'project_id': 1, 'os_type': 'Linux'}
request_spec = {'instance_type': {'memory_mb': 1, 'root_gb': 1,
'ephemeral_gb': 0},
'instance_properties': instance_properties,
'instance_uuids': [uuid]}
self.mox.StubOutWithMock(compute_utils, 'add_instance_fault_from_exc')
self.mox.StubOutWithMock(db, 'instance_update_and_get_original')
old_ref, new_ref = db.instance_update_and_get_original(fake_context,
uuid, {'vm_state': vm_states.ERROR, 'task_state':
None}).AndReturn(({}, {}))
compute_utils.add_instance_fault_from_exc(fake_context, new_ref,
mox.IsA(exception.NoValidHost), mox.IgnoreArg())
self.mox.StubOutWithMock(db, 'compute_node_get_all')
db.compute_node_get_all(mox.IgnoreArg()).AndReturn([])
self.mox.ReplayAll()
sched.schedule_run_instance(
fake_context, request_spec, None, None,
None, None, {}, False)
def test_run_instance_non_admin(self):
self.was_admin = False
def fake_get(context, *args, **kwargs):
# make sure this is called with admin context, even though
# we're using user context below
self.was_admin = context.is_admin
return {}
sched = fakes.FakeFilterScheduler()
self.stubs.Set(sched.host_manager, 'get_all_host_states', fake_get)
fake_context = context.RequestContext('user', 'project')
uuid = 'fake-uuid1'
instance_properties = {'project_id': 1, 'os_type': 'Linux'}
request_spec = {'instance_type': {'memory_mb': 1, 'local_gb': 1},
'instance_properties': instance_properties,
'instance_uuids': [uuid]}
self.mox.StubOutWithMock(compute_utils, 'add_instance_fault_from_exc')
self.mox.StubOutWithMock(db, 'instance_update_and_get_original')
old_ref, new_ref = db.instance_update_and_get_original(fake_context,
uuid, {'vm_state': vm_states.ERROR, 'task_state':
None}).AndReturn(({}, {}))
compute_utils.add_instance_fault_from_exc(fake_context, new_ref,
mox.IsA(exception.NoValidHost), mox.IgnoreArg())
self.mox.ReplayAll()
sched.schedule_run_instance(
fake_context, request_spec, None, None, None, None, {}, False)
self.assertTrue(self.was_admin)
def test_scheduler_includes_launch_index(self):
fake_context = context.RequestContext('user', 'project')
instance_opts = {'fake_opt1': 'meow'}
request_spec = {'instance_uuids': ['fake-uuid1', 'fake-uuid2'],
'instance_properties': instance_opts}
instance1 = {'uuid': 'fake-uuid1'}
instance2 = {'uuid': 'fake-uuid2'}
def _has_launch_index(expected_index):
"""Return a function that verifies the expected index."""
def _check_launch_index(value):
if 'instance_properties' in value:
if 'launch_index' in value['instance_properties']:
index = value['instance_properties']['launch_index']
if index == expected_index:
return True
return False
return _check_launch_index
self.mox.StubOutWithMock(self.driver, '_schedule')
self.mox.StubOutWithMock(self.driver, '_provision_resource')
expected_filter_properties = {'retry': {'num_attempts': 1,
'hosts': []}}
self.driver._schedule(fake_context, request_spec,
expected_filter_properties).AndReturn(['host1', 'host2'])
# instance 1
self.driver._provision_resource(
fake_context, 'host1',
mox.Func(_has_launch_index(0)), expected_filter_properties,
None, None, None, None,
instance_uuid='fake-uuid1',
legacy_bdm_in_spec=False).AndReturn(instance1)
# instance 2
self.driver._provision_resource(
fake_context, 'host2',
mox.Func(_has_launch_index(1)), expected_filter_properties,
None, None, None, None,
instance_uuid='fake-uuid2',
legacy_bdm_in_spec=False).AndReturn(instance2)
self.mox.ReplayAll()
self.driver.schedule_run_instance(fake_context, request_spec,
None, None, None, None, {}, False)
@mock.patch('nova.db.instance_extra_get_by_instance_uuid',
return_value={'numa_topology': None,
'pci_requests': None})
@ -195,148 +88,6 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
self.assertRaises(exception.NovaException,
scheduler_utils._max_attempts)
def test_retry_disabled(self):
# Retry info should not get populated when re-scheduling is off.
self.flags(scheduler_max_attempts=1)
sched = fakes.FakeFilterScheduler()
request_spec = dict(instance_properties={},
instance_uuids=['fake-uuid1'])
filter_properties = {}
self.mox.StubOutWithMock(sched, '_schedule')
self.mox.StubOutWithMock(sched, '_provision_resource')
sched._schedule(self.context, request_spec,
filter_properties).AndReturn(['host1'])
sched._provision_resource(
self.context, 'host1',
request_spec, filter_properties,
None, None, None, None,
instance_uuid='fake-uuid1',
legacy_bdm_in_spec=False)
self.mox.ReplayAll()
sched.schedule_run_instance(self.context, request_spec, None, None,
None, None, filter_properties, False)
def test_retry_force_hosts(self):
# Retry info should not get populated when re-scheduling is off.
self.flags(scheduler_max_attempts=2)
sched = fakes.FakeFilterScheduler()
request_spec = dict(instance_properties={},
instance_uuids=['fake-uuid1'])
filter_properties = {'force_hosts': ['force_host']}
self.mox.StubOutWithMock(sched, '_schedule')
self.mox.StubOutWithMock(sched, '_provision_resource')
sched._schedule(self.context, request_spec,
filter_properties).AndReturn(['host1'])
sched._provision_resource(
self.context, 'host1',
request_spec, filter_properties,
None, None, None, None,
instance_uuid='fake-uuid1',
legacy_bdm_in_spec=False)
self.mox.ReplayAll()
sched.schedule_run_instance(self.context, request_spec, None, None,
None, None, filter_properties, False)
def test_retry_force_nodes(self):
# Retry info should not get populated when re-scheduling is off.
self.flags(scheduler_max_attempts=2)
sched = fakes.FakeFilterScheduler()
request_spec = dict(instance_properties={},
instance_uuids=['fake-uuid1'])
filter_properties = {'force_nodes': ['force_node']}
self.mox.StubOutWithMock(sched, '_schedule')
self.mox.StubOutWithMock(sched, '_provision_resource')
sched._schedule(self.context, request_spec,
filter_properties).AndReturn(['host1'])
sched._provision_resource(
self.context, 'host1',
request_spec, filter_properties,
None, None, None, None,
instance_uuid='fake-uuid1',
legacy_bdm_in_spec=False)
self.mox.ReplayAll()
sched.schedule_run_instance(self.context, request_spec, None, None,
None, None, filter_properties, False)
def test_retry_attempt_one(self):
# Test retry logic on initial scheduling attempt.
self.flags(scheduler_max_attempts=2)
sched = fakes.FakeFilterScheduler()
request_spec = dict(instance_properties={},
instance_uuids=['fake-uuid1'])
filter_properties = {}
expected_filter_properties = {'retry': {'num_attempts': 1,
'hosts': []}}
self.mox.StubOutWithMock(sched, '_schedule')
self.mox.StubOutWithMock(sched, '_provision_resource')
sched._schedule(self.context, request_spec,
expected_filter_properties).AndReturn(['host1'])
sched._provision_resource(
self.context, 'host1',
request_spec, expected_filter_properties,
None, None, None, None,
instance_uuid='fake-uuid1',
legacy_bdm_in_spec=False)
self.mox.ReplayAll()
sched.schedule_run_instance(self.context, request_spec, None, None,
None, None, filter_properties, False)
def test_retry_attempt_two(self):
# Test retry logic when re-scheduling.
self.flags(scheduler_max_attempts=2)
sched = fakes.FakeFilterScheduler()
request_spec = dict(instance_properties={},
instance_uuids=['fake-uuid1'])
filter_properties = {'retry': {'num_attempts': 1}}
expected_filter_properties = {'retry': {'num_attempts': 2}}
self.mox.StubOutWithMock(sched, '_schedule')
self.mox.StubOutWithMock(sched, '_provision_resource')
sched._schedule(self.context, request_spec,
expected_filter_properties).AndReturn(['host1'])
sched._provision_resource(
self.context, 'host1',
request_spec, expected_filter_properties,
None, None, None, None,
instance_uuid='fake-uuid1',
legacy_bdm_in_spec=False)
self.mox.ReplayAll()
sched.schedule_run_instance(self.context, request_spec, None, None,
None, None, filter_properties, False)
def test_retry_exceeded_max_attempts(self):
# Test for necessary explosion when max retries is exceeded and that
# the information needed in request_spec is still present for error
# handling
self.flags(scheduler_max_attempts=2)
sched = fakes.FakeFilterScheduler()
request_spec = dict(instance_properties={},
instance_uuids=['fake-uuid1'])
filter_properties = {'retry': {'num_attempts': 2}}
self.mox.ReplayAll()
self.assertRaises(exception.NoValidHost, sched.schedule_run_instance,
self.context, request_spec, None, None,
None, None, filter_properties, False)
def test_add_retry_host(self):
retry = dict(num_attempts=1, hosts=[])
filter_properties = dict(retry=retry)
@ -569,28 +320,3 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
# Make sure that we provided a reason why NoValidHost.
self.assertIn('reason', e.kwargs)
self.assertTrue(len(e.kwargs['reason']) > 0)
def test_handles_deleted_instance(self):
"""Test instance deletion while being scheduled."""
def _raise_instance_not_found(*args, **kwargs):
raise exception.InstanceNotFound(instance_id='123')
self.stubs.Set(driver, 'instance_update_db',
_raise_instance_not_found)
sched = fakes.FakeFilterScheduler()
fake_context = context.RequestContext('user', 'project')
host_state = host_manager.HostState('host2', 'node2')
weighted_host = weights.WeighedHost(host_state, 1.42)
filter_properties = {}
uuid = 'fake-uuid1'
instance_properties = {'project_id': 1, 'os_type': 'Linux'}
request_spec = {'instance_type': {'memory_mb': 1, 'local_gb': 1},
'instance_properties': instance_properties,
'instance_uuids': [uuid]}
sched._provision_resource(fake_context, weighted_host,
request_spec, filter_properties,
None, None, None, None)

View File

@ -67,4 +67,4 @@ class SchedulerRpcAPITestCase(test.NoDBTestCase):
self._test_scheduler_api('select_destinations', rpc_method='call',
request_spec='fake_request_spec',
filter_properties='fake_prop',
version='3.1')
version='4.0')

View File

@ -17,23 +17,20 @@
Tests For Scheduler
"""
import mock
from mox3 import mox
from oslo.config import cfg
from nova.compute import api as compute_api
from nova.compute import utils as compute_utils
from nova.compute import vm_states
from nova import context
from nova import db
from nova import exception
from nova.image import glance
from nova import objects
from nova import rpc
from nova.scheduler import driver
from nova.scheduler import manager
from nova import servicegroup
from nova import test
from nova.tests.unit import fake_instance
from nova.tests.unit import fake_server_actions
from nova.tests.unit.image import fake as fake_image
from nova.tests.unit.objects import test_instance_fault
@ -75,199 +72,24 @@ class SchedulerManagerTestCase(test.NoDBTestCase):
self.mox.StubOutWithMock(self.manager.driver,
method_name)
def test_run_instance_exception_puts_instance_in_error_state(self):
fake_instance_uuid = 'fake-instance-id'
inst = {"vm_state": "", "task_state": ""}
def test_select_destination(self):
with mock.patch.object(self.manager, 'select_destinations'
) as select_destinations:
self.manager.select_destinations(None, None, {})
select_destinations.assert_called_once_with(None, None, {})
self._mox_schedule_method_helper('schedule_run_instance')
self.mox.StubOutWithMock(compute_utils, 'add_instance_fault_from_exc')
self.mox.StubOutWithMock(db, 'instance_update_and_get_original')
request_spec = {'instance_properties': inst,
'instance_uuids': [fake_instance_uuid]}
class SchedulerV3PassthroughTestCase(test.TestCase):
def setUp(self):
super(SchedulerV3PassthroughTestCase, self).setUp()
self.manager = manager.SchedulerManager()
self.proxy = manager._SchedulerManagerV3Proxy(self.manager)
self.manager.driver.schedule_run_instance(self.context,
request_spec, None, None, None, None, {}, False).AndRaise(
exception.NoValidHost(reason=""))
old, new_ref = db.instance_update_and_get_original(self.context,
fake_instance_uuid,
{"vm_state": vm_states.ERROR,
"task_state": None}).AndReturn((inst, inst))
compute_utils.add_instance_fault_from_exc(self.context,
new_ref, mox.IsA(exception.NoValidHost), mox.IgnoreArg())
self.mox.ReplayAll()
self.manager.run_instance(self.context, request_spec,
None, None, None, None, {}, False)
def test_prep_resize_no_valid_host_back_in_active_state(self):
fake_instance_uuid = 'fake-instance-id'
fake_instance = {'uuid': fake_instance_uuid}
inst = {"vm_state": "", "task_state": ""}
self._mox_schedule_method_helper('select_destinations')
self.mox.StubOutWithMock(compute_utils, 'add_instance_fault_from_exc')
self.mox.StubOutWithMock(db, 'instance_update_and_get_original')
request_spec = {'instance_type': 'fake_type',
'instance_uuids': [fake_instance_uuid],
'instance_properties': {'uuid': fake_instance_uuid}}
kwargs = {
'context': self.context,
'image': 'fake_image',
'request_spec': request_spec,
'filter_properties': 'fake_props',
'instance': fake_instance,
'instance_type': 'fake_type',
'reservations': list('fake_res'),
}
self.manager.driver.select_destinations(
self.context, request_spec, 'fake_props').AndRaise(
exception.NoValidHost(reason=""))
old_ref, new_ref = db.instance_update_and_get_original(self.context,
fake_instance_uuid,
{"vm_state": vm_states.ACTIVE, "task_state": None}).AndReturn(
(inst, inst))
compute_utils.add_instance_fault_from_exc(self.context, new_ref,
mox.IsA(exception.NoValidHost), mox.IgnoreArg())
self.mox.ReplayAll()
self.manager.prep_resize(**kwargs)
def test_prep_resize_no_valid_host_back_in_shutoff_state(self):
fake_instance_uuid = 'fake-instance-id'
fake_instance = {'uuid': fake_instance_uuid, "vm_state": "stopped"}
inst = {"vm_state": "stopped", "task_state": ""}
self._mox_schedule_method_helper('select_destinations')
self.mox.StubOutWithMock(compute_utils, 'add_instance_fault_from_exc')
self.mox.StubOutWithMock(db, 'instance_update_and_get_original')
request_spec = {'instance_type': 'fake_type',
'instance_uuids': [fake_instance_uuid],
'instance_properties': {'uuid': fake_instance_uuid}}
kwargs = {
'context': self.context,
'image': 'fake_image',
'request_spec': request_spec,
'filter_properties': 'fake_props',
'instance': fake_instance,
'instance_type': 'fake_type',
'reservations': list('fake_res'),
}
self.manager.driver.select_destinations(
self.context, request_spec, 'fake_props').AndRaise(
exception.NoValidHost(reason=""))
old_ref, new_ref = db.instance_update_and_get_original(self.context,
fake_instance_uuid,
{"vm_state": vm_states.STOPPED, "task_state": None}).AndReturn(
(inst, inst))
compute_utils.add_instance_fault_from_exc(self.context, new_ref,
mox.IsA(exception.NoValidHost), mox.IgnoreArg())
self.mox.ReplayAll()
self.manager.prep_resize(**kwargs)
def test_prep_resize_exception_host_in_error_state_and_raise(self):
fake_instance_uuid = 'fake-instance-id'
fake_instance = {'uuid': fake_instance_uuid}
self._mox_schedule_method_helper('select_destinations')
self.mox.StubOutWithMock(compute_utils, 'add_instance_fault_from_exc')
self.mox.StubOutWithMock(db, 'instance_update_and_get_original')
request_spec = {
'instance_properties': {'uuid': fake_instance_uuid},
'instance_uuids': [fake_instance_uuid]
}
kwargs = {
'context': self.context,
'image': 'fake_image',
'request_spec': request_spec,
'filter_properties': 'fake_props',
'instance': fake_instance,
'instance_type': 'fake_type',
'reservations': list('fake_res'),
}
self.manager.driver.select_destinations(
self.context, request_spec, 'fake_props').AndRaise(
test.TestingException('something happened'))
inst = {
"vm_state": "",
"task_state": "",
}
old_ref, new_ref = db.instance_update_and_get_original(self.context,
fake_instance_uuid,
{"vm_state": vm_states.ERROR,
"task_state": None}).AndReturn((inst, inst))
compute_utils.add_instance_fault_from_exc(self.context, new_ref,
mox.IsA(test.TestingException), mox.IgnoreArg())
self.mox.ReplayAll()
self.assertRaises(test.TestingException, self.manager.prep_resize,
**kwargs)
def test_set_vm_state_and_notify_adds_instance_fault(self):
request = {'instance_properties': {'uuid': 'fake-uuid'}}
updates = {'vm_state': 'foo'}
fake_inst = {'uuid': 'fake-uuid'}
self.mox.StubOutWithMock(db, 'instance_update_and_get_original')
self.mox.StubOutWithMock(db, 'instance_fault_create')
self.mox.StubOutWithMock(rpc, 'get_notifier')
notifier = self.mox.CreateMockAnything()
rpc.get_notifier('scheduler').AndReturn(notifier)
db.instance_update_and_get_original(self.context, 'fake-uuid',
updates).AndReturn((None,
fake_inst))
db.instance_fault_create(self.context, mox.IgnoreArg()).AndReturn(
test_instance_fault.fake_faults['fake-uuid'][0])
notifier.error(self.context, 'scheduler.foo', mox.IgnoreArg())
self.mox.ReplayAll()
self.manager._set_vm_state_and_notify('foo', {'vm_state': 'foo'},
self.context, None, request)
def test_prep_resize_post_populates_retry(self):
self.manager.driver = fakes.FakeFilterScheduler()
image = 'image'
instance_uuid = 'fake-instance-id'
instance = fake_instance.fake_db_instance(uuid=instance_uuid)
instance_properties = {'project_id': 'fake', 'os_type': 'Linux'}
instance_type = "m1.tiny"
request_spec = {'instance_properties': instance_properties,
'instance_type': instance_type,
'instance_uuids': [instance_uuid]}
retry = {'hosts': [], 'num_attempts': 1}
filter_properties = {'retry': retry}
reservations = None
hosts = [dict(host='host', nodename='node', limits={})]
self._mox_schedule_method_helper('select_destinations')
self.manager.driver.select_destinations(
self.context, request_spec, filter_properties).AndReturn(hosts)
self.mox.StubOutWithMock(self.manager.compute_rpcapi, 'prep_resize')
self.manager.compute_rpcapi.prep_resize(self.context, image,
mox.IsA(objects.Instance),
instance_type, 'host', reservations, request_spec=request_spec,
filter_properties=filter_properties, node='node')
self.mox.ReplayAll()
self.manager.prep_resize(self.context, image, request_spec,
filter_properties, instance, instance_type, reservations)
self.assertEqual([['host', 'node']],
filter_properties['retry']['hosts'])
def test_select_destination(self):
with mock.patch.object(self.manager, 'select_destinations'
) as select_destinations:
self.proxy.select_destinations(None, None, {})
select_destinations.assert_called_once_with(None, None, {})
class SchedulerTestCase(test.NoDBTestCase):
@ -342,15 +164,6 @@ class SchedulerDriverBaseTestCase(SchedulerTestCase):
that will fail if the driver is changed.
"""
def test_unimplemented_schedule_run_instance(self):
fake_request_spec = {'instance_properties':
{'uuid': 'uuid'}}
self.assertRaises(NotImplementedError,
self.driver.schedule_run_instance,
self.context, fake_request_spec, None, None, None,
None, None, False)
def test_unimplemented_select_destinations(self):
self.assertRaises(NotImplementedError,
self.driver.select_destinations, self.context, {}, {})