diff options
author | Russell Bryant <rbryant@redhat.com> | 2012-08-01 16:48:03 -0400 |
---|---|---|
committer | Russell Bryant <rbryant@redhat.com> | 2012-08-03 22:13:28 -0400 |
commit | 6e134c9df2ec05ebce9f62c6d85988ece18620ad (patch) | |
tree | 4aa467c5fe04990c3c51d7cfa5efd26b6f862117 | |
parent | 5fb51ea04b2ccff55f45af9e99cecd5d22f27a42 (diff) | |
download | nova-6e134c9df2ec05ebce9f62c6d85988ece18620ad.tar.gz nova-6e134c9df2ec05ebce9f62c6d85988ece18620ad.tar.xz nova-6e134c9df2ec05ebce9f62c6d85988ece18620ad.zip |
Updates to the prep_resize scheduler rpc call.
I started looking at this because of the prep_resize rpc call in the compute
manager. An API server calls prep_resize on the scheduler which then calls it
on a compute node. I will need to make the same changes on the compute side,
but this is the first step.
The prep_resize call was taking two object IDs, an instance UUID and an
instance_type ID. Both of these have been converted. It now takes an instance
dict and an instance_type dict, instead. It can also handle receiving the old
IDs for backwards compatibility. prep_resize also took a topic argument that
was unused, so it has just been removed.
There are a number of changes in the scheduler code tied up in this to make it
more explicit about exactly what arguments are expected instead of just using
*args, **kwargs.
Part of blueprint no-db-messaging.
Change-Id: I4af18e5575e2bb60a410fc8edabf3d607c72aabc
-rw-r--r-- | nova/compute/api.py | 5 | ||||
-rw-r--r-- | nova/scheduler/chance.py | 24 | ||||
-rw-r--r-- | nova/scheduler/driver.py | 3 | ||||
-rw-r--r-- | nova/scheduler/filter_scheduler.py | 17 | ||||
-rw-r--r-- | nova/scheduler/manager.py | 30 | ||||
-rw-r--r-- | nova/scheduler/rpcapi.py | 15 | ||||
-rw-r--r-- | nova/tests/scheduler/test_chance_scheduler.py | 6 | ||||
-rw-r--r-- | nova/tests/scheduler/test_filter_scheduler.py | 2 | ||||
-rw-r--r-- | nova/tests/scheduler/test_rpcapi.py | 9 | ||||
-rw-r--r-- | nova/tests/scheduler/test_scheduler.py | 39 |
10 files changed, 96 insertions, 54 deletions
diff --git a/nova/compute/api.py b/nova/compute/api.py index 4f7e67105..834f7bd38 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1441,9 +1441,8 @@ class API(base.Base): filter_properties['ignore_hosts'].append(instance['host']) args = { - "topic": FLAGS.compute_topic, - "instance_uuid": instance['uuid'], - "instance_type_id": new_instance_type['id'], + "instance": instance, + "instance_type": new_instance_type, "image": image, "update_db": False, "request_spec": jsonutils.to_primitive(request_spec), diff --git a/nova/scheduler/chance.py b/nova/scheduler/chance.py index b9fab9540..1be86dda6 100644 --- a/nova/scheduler/chance.py +++ b/nova/scheduler/chance.py @@ -30,15 +30,14 @@ from nova.scheduler import driver class ChanceScheduler(driver.Scheduler): """Implements Scheduler as a random node selector.""" - def _filter_hosts(self, request_spec, hosts, **kwargs): + def _filter_hosts(self, request_spec, hosts, filter_properties): """Filter a list of hosts based on request_spec.""" - filter_properties = kwargs.get('filter_properties', {}) ignore_hosts = filter_properties.get('ignore_hosts', []) hosts = [host for host in hosts if host not in ignore_hosts] return hosts - def _schedule(self, context, topic, request_spec, **kwargs): + def _schedule(self, context, topic, request_spec, filter_properties): """Picks a host that is up at random.""" elevated = context.elevated() @@ -47,7 +46,7 @@ class ChanceScheduler(driver.Scheduler): msg = _("Is the appropriate service running?") raise exception.NoValidHost(reason=msg) - hosts = self._filter_hosts(request_spec, hosts, **kwargs) + hosts = self._filter_hosts(request_spec, hosts, filter_properties) if not hosts: msg = _("Could not find another compute") raise exception.NoValidHost(reason=msg) @@ -57,16 +56,19 @@ class ChanceScheduler(driver.Scheduler): def schedule(self, context, topic, method, *_args, **kwargs): """Picks a host that is up at random.""" - host = self._schedule(context, topic, None, **kwargs) + filter_properties = kwargs.get('filter_properties', {}) + host = self._schedule(context, topic, None, filter_properties) driver.cast_to_host(context, topic, host, method, **kwargs) def schedule_run_instance(self, context, request_spec, reservations, *_args, **kwargs): """Create and run an instance or instances""" num_instances = request_spec.get('num_instances', 1) + filter_properties = kwargs.get('filter_properties', {}) instances = [] for num in xrange(num_instances): - host = self._schedule(context, 'compute', request_spec, **kwargs) + host = self._schedule(context, 'compute', request_spec, + filter_properties) request_spec['instance_properties']['launch_index'] = num instance = self.create_instance_db_entry(context, request_spec, reservations) @@ -79,7 +81,11 @@ class ChanceScheduler(driver.Scheduler): del request_spec['instance_properties']['uuid'] return instances - def schedule_prep_resize(self, context, request_spec, *args, **kwargs): + def schedule_prep_resize(self, context, image, update_db, request_spec, + filter_properties, instance, instance_type): """Select a target for resize.""" - host = self._schedule(context, 'compute', request_spec, **kwargs) - driver.cast_to_compute_host(context, host, 'prep_resize', **kwargs) + host = self._schedule(context, 'compute', request_spec, + filter_properties) + driver.cast_to_compute_host(context, host, 'prep_resize', + instance_uuid=instance['uuid'], + instance_type_id=instance_type['id'], image=image) diff --git a/nova/scheduler/driver.py b/nova/scheduler/driver.py index 94fc6f5fe..39d3446c6 100644 --- a/nova/scheduler/driver.py +++ b/nova/scheduler/driver.py @@ -179,7 +179,8 @@ class Scheduler(object): """Must override schedule method for scheduler to work.""" raise NotImplementedError(_("Must implement a fallback schedule")) - def schedule_prep_resize(self, context, request_spec, *_args, **_kwargs): + def schedule_prep_resize(self, context, image, update_db, request_spec, + filter_properties, instance, instance_type): """Must override schedule_prep_resize method for scheduler to work.""" msg = _("Driver must implement schedule_prep_resize") raise NotImplementedError(msg) diff --git a/nova/scheduler/filter_scheduler.py b/nova/scheduler/filter_scheduler.py index 5b0bcd4f1..63405541b 100644 --- a/nova/scheduler/filter_scheduler.py +++ b/nova/scheduler/filter_scheduler.py @@ -70,7 +70,7 @@ class FilterScheduler(driver.Scheduler): filter_properties = kwargs.pop('filter_properties', {}) weighted_hosts = self._schedule(context, "compute", request_spec, - filter_properties, *args, **kwargs) + filter_properties) if not weighted_hosts: raise exception.NoValidHost(reason="") @@ -103,7 +103,8 @@ class FilterScheduler(driver.Scheduler): return instances - def schedule_prep_resize(self, context, request_spec, *args, **kwargs): + def schedule_prep_resize(self, context, image, update_db, request_spec, + filter_properties, instance, instance_type): """Select a target for resize. Selects a target host for the instance, post-resize, and casts @@ -111,18 +112,15 @@ class FilterScheduler(driver.Scheduler): """ hosts = self._schedule(context, 'compute', request_spec, - *args, **kwargs) + filter_properties) if not hosts: raise exception.NoValidHost(reason="") host = hosts.pop(0) - # NOTE(comstud): Make sure we do not pass this through. It - # contains an instance of RpcContext that cannot be serialized. - kwargs.pop('filter_properties', None) - # Forward off to the host driver.cast_to_compute_host(context, host.host_state.host, - 'prep_resize', **kwargs) + 'prep_resize', instance_uuid=instance['uuid'], + instance_type_id=instance_type['id'], image=image) def _provision_resource(self, context, weighted_host, request_spec, reservations, filter_properties, kwargs): @@ -207,8 +205,7 @@ class FilterScheduler(driver.Scheduler): msg = _("Exceeded max scheduling attempts %d ") % max_attempts raise exception.NoValidHost(msg, instance_uuid=uuid) - def _schedule(self, context, topic, request_spec, filter_properties, *args, - **kwargs): + def _schedule(self, context, topic, request_spec, filter_properties): """Returns a list of hosts that meet the required specs, ordered by their fitness. """ diff --git a/nova/scheduler/manager.py b/nova/scheduler/manager.py index e243e4518..b63de6c4d 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.0' + RPC_API_VERSION = '1.1' def __init__(self, scheduler_driver=None, *args, **kwargs): if not scheduler_driver: @@ -138,24 +138,42 @@ class SchedulerManager(manager.Manager): if reservations: QUOTAS.rollback(context, reservations) - def prep_resize(self, context, topic, *args, **kwargs): + def prep_resize(self, context, image, update_db, request_spec, + filter_properties, instance=None, instance_uuid=None, + instance_type=None, instance_type_id=None, topic=None): """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 """ - args = (context,) + args + if not instance: + instance = db.instance_get_by_uuid(context, instance_uuid) + + if not instance_type: + instance_type = db.instance_type_get(context, instance_type_id) + try: - return self.driver.schedule_prep_resize(*args, **kwargs) + kwargs = { + 'context': context, + 'image': image, + 'update_db': update_db, + 'request_spec': request_spec, + 'filter_properties': filter_properties, + 'instance': instance, + 'instance_type': instance_type, + } + return self.driver.schedule_prep_resize(**kwargs) except exception.NoValidHost as ex: self._set_vm_state_and_notify('prep_resize', {'vm_state': vm_states.ACTIVE, 'task_state': None}, - context, ex, *args, **kwargs) + context, ex, + request_spec=request_spec) except Exception as ex: with excutils.save_and_reraise_exception(): self._set_vm_state_and_notify('prep_resize', {'vm_state': vm_states.ERROR}, - context, ex, *args, **kwargs) + context, ex, + request_spec=request_spec) def _set_vm_state_and_notify(self, method, updates, context, ex, *args, **kwargs): diff --git a/nova/scheduler/rpcapi.py b/nova/scheduler/rpcapi.py index b2522ab53..60de98c91 100644 --- a/nova/scheduler/rpcapi.py +++ b/nova/scheduler/rpcapi.py @@ -19,6 +19,7 @@ Client side of the scheduler manager RPC API. """ from nova import flags +from nova.openstack.common import jsonutils import nova.openstack.common.rpc.proxy @@ -31,6 +32,10 @@ class SchedulerAPI(nova.openstack.common.rpc.proxy.RpcProxy): API version history: 1.0 - Initial version. + 1.1 - Changes to prep_resize(): + - remove instance_uuid, add instance + - remove instance_type_id, add instance_type + - remove topic, it was unused ''' BASE_RPC_API_VERSION = '1.0' @@ -51,12 +56,14 @@ class SchedulerAPI(nova.openstack.common.rpc.proxy.RpcProxy): filter_properties=filter_properties, reservations=reservations)) - def prep_resize(self, ctxt, topic, instance_uuid, instance_type_id, image, + def prep_resize(self, ctxt, instance, instance_type, image, update_db, request_spec, filter_properties): - self.cast(ctxt, self.make_msg('prep_resize', topic=topic, - instance_uuid=instance_uuid, instance_type_id=instance_type_id, + instance_p = jsonutils.to_primitive(instance) + instance_type_p = jsonutils.to_primitive(instance_type) + self.cast(ctxt, self.make_msg('prep_resize', + instance=instance_p, instance_type=instance_type_p, image=image, update_db=update_db, request_spec=request_spec, - filter_properties=filter_properties)) + filter_properties=filter_properties), version='1.1') def show_host_resources(self, ctxt, host): return self.call(ctxt, self.make_msg('show_host_resources', host=host)) diff --git a/nova/tests/scheduler/test_chance_scheduler.py b/nova/tests/scheduler/test_chance_scheduler.py index ec853594b..eabfa93dc 100644 --- a/nova/tests/scheduler/test_chance_scheduler.py +++ b/nova/tests/scheduler/test_chance_scheduler.py @@ -149,7 +149,8 @@ class ChanceSchedulerTestCase(test_scheduler.SchedulerTestCase): self.mox.StubOutWithMock(driver, 'cast_to_compute_host') self.mox.StubOutWithMock(driver, 'encode_instance') # instance 1 - self.driver._schedule(ctxt, 'compute', request_spec).AndReturn('host') + self.driver._schedule(ctxt, 'compute', request_spec, + {}).AndReturn('host') self.driver.create_instance_db_entry( ctxt, mox.Func(_has_launch_index(0)), None ).WithSideEffects(_add_uuid(1)).AndReturn(instance1) @@ -157,7 +158,8 @@ class ChanceSchedulerTestCase(test_scheduler.SchedulerTestCase): instance_uuid=instance1['uuid']) driver.encode_instance(instance1).AndReturn(instance1) # instance 2 - self.driver._schedule(ctxt, 'compute', request_spec).AndReturn('host') + self.driver._schedule(ctxt, 'compute', request_spec, + {}).AndReturn('host') self.driver.create_instance_db_entry( ctxt, mox.Func(_has_launch_index(1)), None ).WithSideEffects(_add_uuid(2)).AndReturn(instance2) diff --git a/nova/tests/scheduler/test_filter_scheduler.py b/nova/tests/scheduler/test_filter_scheduler.py index 158fc0d83..648373945 100644 --- a/nova/tests/scheduler/test_filter_scheduler.py +++ b/nova/tests/scheduler/test_filter_scheduler.py @@ -111,7 +111,7 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase): self.mox.StubOutWithMock(self.driver, '_provision_resource') self.driver._schedule(context_fake, 'compute', - request_spec, {}, **fake_kwargs + request_spec, {} ).AndReturn(['host1', 'host2']) # instance 1 self.driver._provision_resource( diff --git a/nova/tests/scheduler/test_rpcapi.py b/nova/tests/scheduler/test_rpcapi.py index 000138bc9..c881bc306 100644 --- a/nova/tests/scheduler/test_rpcapi.py +++ b/nova/tests/scheduler/test_rpcapi.py @@ -40,8 +40,9 @@ class SchedulerRpcAPITestCase(test.TestCase): ctxt = context.RequestContext('fake_user', 'fake_project') rpcapi = scheduler_rpcapi.SchedulerAPI() expected_retval = 'foo' if method == 'call' else None + expected_version = kwargs.pop('version', rpcapi.BASE_RPC_API_VERSION) expected_msg = rpcapi.make_msg(method, **kwargs) - expected_msg['version'] = rpcapi.BASE_RPC_API_VERSION + expected_msg['version'] = expected_version if rpc_method == 'cast' and method == 'run_instance': kwargs['call'] = False @@ -81,10 +82,10 @@ class SchedulerRpcAPITestCase(test.TestCase): def test_prep_resize(self): self._test_scheduler_api('prep_resize', rpc_method='cast', - topic='fake_topic', instance_uuid='fake_uuid', - instance_type_id='fake_type_id', image='fake_image', + instance='fake_instance', + instance_type='fake_type', image='fake_image', update_db='fake_update_db', request_spec='fake_request_spec', - filter_properties='fake_props') + filter_properties='fake_props', version='1.1') def test_show_host_resources(self): self._test_scheduler_api('show_host_resources', rpc_method='call', diff --git a/nova/tests/scheduler/test_scheduler.py b/nova/tests/scheduler/test_scheduler.py index ec30321d0..b9cb4de59 100644 --- a/nova/tests/scheduler/test_scheduler.py +++ b/nova/tests/scheduler/test_scheduler.py @@ -245,18 +245,23 @@ class SchedulerManagerTestCase(test.TestCase): request_spec = {'instance_properties': {'uuid': fake_instance_uuid}} - self.fake_kwargs['request_spec'] = request_spec - - self.manager.driver.schedule_prep_resize(self.context, - *self.fake_args, **self.fake_kwargs).AndRaise( - exception.NoValidHost(reason="")) + kwargs = { + 'context': self.context, + 'image': 'fake_image', + 'update_db': True, + 'request_spec': request_spec, + 'filter_properties': 'fake_props', + 'instance': 'fake_instance', + 'instance_type': 'fake_type', + } + self.manager.driver.schedule_prep_resize(**kwargs).AndRaise( + exception.NoValidHost(reason="")) db.instance_update_and_get_original(self.context, fake_instance_uuid, {"vm_state": vm_states.ACTIVE, "task_state": None}).AndReturn( (inst, inst)) self.mox.ReplayAll() - self.manager.prep_resize(self.context, self.topic, - *self.fake_args, **self.fake_kwargs) + self.manager.prep_resize(**kwargs) def test_prep_resize_exception_host_in_error_state_and_raise(self): """Test that a NoValidHost exception for prep_resize puts @@ -270,10 +275,17 @@ class SchedulerManagerTestCase(test.TestCase): request_spec = {'instance_properties': {'uuid': fake_instance_uuid}} - self.fake_kwargs['request_spec'] = request_spec + kwargs = { + 'context': self.context, + 'image': 'fake_image', + 'update_db': True, + 'request_spec': request_spec, + 'filter_properties': 'fake_props', + 'instance': 'fake_instance', + 'instance_type': 'fake_type', + } - self.manager.driver.schedule_prep_resize(self.context, - *self.fake_args, **self.fake_kwargs).AndRaise( + self.manager.driver.schedule_prep_resize(**kwargs).AndRaise( self.AnException('something happened')) inst = { @@ -286,8 +298,7 @@ class SchedulerManagerTestCase(test.TestCase): self.mox.ReplayAll() self.assertRaises(self.AnException, self.manager.prep_resize, - self.context, self.topic, - *self.fake_args, **self.fake_kwargs) + **kwargs) class SchedulerTestCase(test.TestCase): @@ -772,8 +783,8 @@ class SchedulerDriverBaseTestCase(SchedulerTestCase): self.assertRaises(NotImplementedError, self.driver.schedule_prep_resize, - self.context, fake_request_spec, - *fake_args, **fake_kwargs) + self.context, {}, False, + fake_request_spec, {}, {}, {}) class SchedulerDriverModuleTestCase(test.TestCase): |