From 8cf635b08a57a9e3be2bef980ef38cf857b6525a Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 29 Aug 2012 09:21:03 +0100 Subject: Stop using scheduler RPC API magic If a scheduler RPC message isn't handled directly by a SchedulerManager method, the __getattr__() fallback passes the message to a driver method in the form of schedule_${method}() and, if that doesn't exist, instead calls the schedule() method supplying the topic and method args. This is pretty bizarre stuff and we appear to only use it in two cases: 1) live_migration - this is how the schedule_live_migration() method in the driver gets called, but the side-effect is that we require the client to pass a topic argument which is never used. This would be much more sanely handled with an explicit SchedulerManager.live_migration() method. 2) create_volume - the volume API asks the scheduler to pick a target host for create_volume() using this method. This would be easily handled with an SchedulerManager.create_volume() method. Change-Id: I1047489d85ac51d8d36fea1c4eb858df638ce349 --- nova/scheduler/chance.py | 9 +++++++++ nova/scheduler/driver.py | 5 +++++ nova/scheduler/filter_scheduler.py | 7 +++++++ nova/scheduler/manager.py | 28 +++++++++++++++++++++++++++- nova/scheduler/multi.py | 3 +++ nova/scheduler/rpcapi.py | 12 ++++++++++-- nova/scheduler/simple.py | 9 ++++++--- 7 files changed, 67 insertions(+), 6 deletions(-) (limited to 'nova/scheduler') diff --git a/nova/scheduler/chance.py b/nova/scheduler/chance.py index 9731a0a07..e74f34054 100644 --- a/nova/scheduler/chance.py +++ b/nova/scheduler/chance.py @@ -24,8 +24,11 @@ Chance (Random) Scheduler implementation import random from nova import exception +from nova import flags from nova.scheduler import driver +FLAGS = flags.FLAGS + class ChanceScheduler(driver.Scheduler): """Implements Scheduler as a random node selector.""" @@ -123,3 +126,9 @@ class ChanceScheduler(driver.Scheduler): filter_properties) self.compute_rpcapi.prep_resize(context, image, instance, instance_type, host, reservations) + + def schedule_create_volume(self, context, volume_id, snapshot_id, + reservations): + self.schedule(context, FLAGS.volume_topic, 'create_volume', + volume_id=volume_id, snapshot_id=snapshot_id, + reservations=reservations) diff --git a/nova/scheduler/driver.py b/nova/scheduler/driver.py index 42e05e903..f599965cd 100644 --- a/nova/scheduler/driver.py +++ b/nova/scheduler/driver.py @@ -202,6 +202,11 @@ class Scheduler(object): msg = _("Driver must implement schedule_run_instance") raise NotImplementedError(msg) + def schedule_create_volume(self, context, volume_id, snapshot_id, + reservations): + msg = _("Driver must implement schedule_create_volune") + raise NotImplementedError(msg) + def schedule_live_migration(self, context, dest, block_migration=False, disk_over_commit=False, instance=None, instance_id=None): diff --git a/nova/scheduler/filter_scheduler.py b/nova/scheduler/filter_scheduler.py index 9eea8dea6..258b66f7e 100644 --- a/nova/scheduler/filter_scheduler.py +++ b/nova/scheduler/filter_scheduler.py @@ -51,6 +51,13 @@ class FilterScheduler(driver.Scheduler): msg = _("No host selection for %s defined.") % topic raise exception.NoValidHost(reason=msg) + def schedule_create_volume(self, context, volume_id, snapshot_id, + reservations): + # NOTE: We're only focused on compute instances right now, + # so this method will always raise NoValidHost(). + msg = _("No host selection for %s defined.") % FLAGS.volume_topic + raise exception.NoValidHost(reason=msg) + def schedule_run_instance(self, context, request_spec, admin_password, injected_files, requested_networks, is_first_time, diff --git a/nova/scheduler/manager.py b/nova/scheduler/manager.py index e1030121a..36e9a8473 100644 --- a/nova/scheduler/manager.py +++ b/nova/scheduler/manager.py @@ -53,7 +53,7 @@ QUOTAS = quota.QUOTAS class SchedulerManager(manager.Manager): """Chooses a host to run instances on.""" - RPC_API_VERSION = '1.6' + RPC_API_VERSION = '1.7' def __init__(self, scheduler_driver=None, *args, **kwargs): if not scheduler_driver: @@ -66,6 +66,8 @@ class SchedulerManager(manager.Manager): # NOTE(russellb) Because of what this is doing, we must be careful # when changing the API of the scheduler drivers, as that changes # the rpc API as well, and the version should be updated accordingly. + # NOTE(markmc): This remains only for backwards compat support + # and can be removed when we bump the major version return functools.partial(self._schedule, key) def get_host_list(self, context): @@ -91,6 +93,30 @@ class SchedulerManager(manager.Manager): self.driver.update_service_capabilities(service_name, host, capabilities) + def create_volume(self, context, volume_id, snapshot_id, reservations): + try: + self.driver.schedule_create_volume( + context, volume_id, snapshot_id, reservations) + except Exception as ex: + with excutils.save_and_reraise_exception(): + self._set_vm_state_and_notify('create_volume', + {'vm_state': vm_states.ERROR}, + context, ex, {}) + + def live_migration(self, context, dest, + block_migration=False, disk_over_commit=False, + instance=None, instance_id=None, topic=None): + try: + return self.driver.schedule_live_migration( + context, dest, + block_migration, disk_over_commit, + instance, instance_id) + except Exception as ex: + with excutils.save_and_reraise_exception(): + self._set_vm_state_and_notify('live_migration', + {'vm_state': vm_states.ERROR}, + context, ex, {}) + def _schedule(self, method, context, topic, *args, **kwargs): """Tries to call schedule_* method on the driver to retrieve host. Falls back to schedule(context, topic) if method doesn't exist. diff --git a/nova/scheduler/multi.py b/nova/scheduler/multi.py index c6de3f825..59e1212c0 100644 --- a/nova/scheduler/multi.py +++ b/nova/scheduler/multi.py @@ -89,6 +89,9 @@ class MultiScheduler(driver.Scheduler): def schedule_prep_resize(self, *args, **kwargs): return self.drivers['compute'].schedule_prep_resize(*args, **kwargs) + def schedule_create_volume(self, *args, **kwargs): + return self.drivers['volume'].schedule_create_volume(*args, **kwargs) + def update_service_capabilities(self, service_name, host, capabilities): # Multi scheduler is only a holder of sub-schedulers, so # pass the capabilities to the schedulers that matter diff --git a/nova/scheduler/rpcapi.py b/nova/scheduler/rpcapi.py index 84d0286a2..8ff564a59 100644 --- a/nova/scheduler/rpcapi.py +++ b/nova/scheduler/rpcapi.py @@ -41,6 +41,7 @@ class SchedulerAPI(nova.openstack.common.rpc.proxy.RpcProxy): 1.4 - Remove update_db from prep_resize 1.5 - Add reservations argument to prep_resize() 1.6 - Remove reservations argument to run_instance() + 1.7 - Add create_volume() method, remove topic from live_migration() ''' BASE_RPC_API_VERSION = '1.0' @@ -73,14 +74,21 @@ class SchedulerAPI(nova.openstack.common.rpc.proxy.RpcProxy): return self.call(ctxt, self.make_msg('show_host_resources', host=host)) def live_migration(self, ctxt, block_migration, disk_over_commit, - instance, dest, topic): + instance, dest): # NOTE(comstud): Call vs cast so we can get exceptions back, otherwise # this call in the scheduler driver doesn't return anything. instance_p = jsonutils.to_primitive(instance) return self.call(ctxt, self.make_msg('live_migration', block_migration=block_migration, disk_over_commit=disk_over_commit, instance=instance_p, - dest=dest, topic=topic), version='1.3') + dest=dest), version='1.7') + + def create_volume(self, ctxt, volume_id, snapshot_id, reservations): + self.cast(ctxt, + self.make_msg('create_volume', + volume_id=volume_id, snapshot_id=snapshot_id, + reservations=reservations), + version='1.7') def update_service_capabilities(self, ctxt, service_name, host, capabilities): diff --git a/nova/scheduler/simple.py b/nova/scheduler/simple.py index f8a1e4154..273bb2cf8 100644 --- a/nova/scheduler/simple.py +++ b/nova/scheduler/simple.py @@ -54,7 +54,8 @@ class SimpleScheduler(chance.ChanceScheduler): super(SimpleScheduler, self).schedule_run_instance(context, request_spec, reservations, *_args, **_kwargs) - def schedule_create_volume(self, context, volume_id, *_args, **_kwargs): + def schedule_create_volume(self, context, volume_id, snapshot_id, + reservations): """Picks a host that is up and has the fewest volumes.""" deprecated.warn(_('nova-volume functionality is deprecated in Folsom ' 'and will be removed in Grizzly. Volumes are now handled ' @@ -72,7 +73,8 @@ class SimpleScheduler(chance.ChanceScheduler): if not utils.service_is_up(service): raise exception.WillNotSchedule(host=host) driver.cast_to_volume_host(context, host, 'create_volume', - volume_id=volume_id, **_kwargs) + volume_id=volume_id, snapshot_id=snapshot_id, + reservations=reservations) return None results = db.service_get_all_volume_sorted(elevated) @@ -86,7 +88,8 @@ class SimpleScheduler(chance.ChanceScheduler): raise exception.NoValidHost(reason=msg) if utils.service_is_up(service) and not service['disabled']: driver.cast_to_volume_host(context, service['host'], - 'create_volume', volume_id=volume_id, **_kwargs) + 'create_volume', volume_id=volume_id, + snapshot_id=snapshot_id, reservations=reservations) return None msg = _("Is the appropriate service running?") raise exception.NoValidHost(reason=msg) -- cgit