diff options
| author | Sandy Walsh <sandy.walsh@rackspace.com> | 2011-03-21 18:16:35 -0700 |
|---|---|---|
| committer | Sandy Walsh <sandy.walsh@rackspace.com> | 2011-03-21 18:16:35 -0700 |
| commit | 08d06d1219a00b90ae211fb44fc7e33ba71c7a76 (patch) | |
| tree | 8725afb9895df532481b14ba8e30f57e71dc6c85 | |
| parent | b1def6b2b104a143b7491cef9a01babe9ab3e75d (diff) | |
| download | nova-08d06d1219a00b90ae211fb44fc7e33ba71c7a76.tar.gz nova-08d06d1219a00b90ae211fb44fc7e33ba71c7a76.tar.xz nova-08d06d1219a00b90ae211fb44fc7e33ba71c7a76.zip | |
better comments. First redirect test
| -rw-r--r-- | nova/scheduler/api.py | 49 | ||||
| -rw-r--r-- | nova/tests/test_scheduler.py | 70 |
2 files changed, 107 insertions, 12 deletions
diff --git a/nova/scheduler/api.py b/nova/scheduler/api.py index aebfe1770..ff7e21679 100644 --- a/nova/scheduler/api.py +++ b/nova/scheduler/api.py @@ -84,13 +84,18 @@ def _wrap_method(function, self): def _process(func, zone): """Worker stub for green thread pool. Give the worker an authenticated nova client and zone info.""" + LOG.debug("*** PROCESS %s/%s" % (func, zone)) nova = novaclient.OpenStack(zone.username, zone.password, zone.api_url) nova.authenticate() return func(nova, zone) def child_zone_helper(zone_list, func): - """Fire off a command to each zone in the list.""" + """Fire off a command to each zone in the list. + The return is [novaclient return objects] from each child zone. + For example, if you are calling server.pause(), the list will + be whatever the response from server.pause() is. One entry + per child zone called.""" green_pool = greenpool.GreenPool() return [result for result in green_pool.imap( _wrap_method(_process, func), zone_list)] @@ -103,6 +108,7 @@ def _issue_novaclient_command(nova, zone, collection, method_name, \ result = None try: manager = getattr(nova, collection) + LOG.debug("***MANAGER %s" % manager) if isinstance(item_id, int) or item_id.isdigit(): result = manager.get(int(item_id)) else: @@ -115,9 +121,9 @@ def _issue_novaclient_command(nova, zone, collection, method_name, \ if method_name.lower() not in ['get', 'find']: LOG.debug("***CALLING CHILD ZONE") - m = getattr(item, method_name) + m = getattr(result, method_name) LOG.debug("***METHOD ATTR %s" % m) - result = getattr(item, method_name)() + result = getattr(result, method_name)() LOG.debug("***CHILD ZONE GAVE %s", result) return result @@ -152,6 +158,7 @@ class reroute_compute(object): collection, context, item_id = \ self.get_collection_context_and_id(args, kwargs) try: + # Call the original function ... return f(*args, **kwargs) except exception.InstanceNotFound, e: LOG.debug(_("Instance %(item_id)s not found " @@ -164,32 +171,50 @@ class reroute_compute(object): if not zones: raise + # Ask the children to provide an answer ... result = child_zone_helper(zones, wrap_novaclient_function(_issue_novaclient_command, collection, self.method_name, item_id)) LOG.debug("***REROUTE: %s" % result) + # Scrub the results and raise another exception + # so the API layers can bail out gracefully ... raise RedirectResult(self.unmarshall_result(result)) return wrapped_f def get_collection_context_and_id(self, args, kwargs): """Returns a tuple of (novaclient collection name, security context and resource id. Derived class should override this.""" + LOG.debug("***COLLECT: %s/%s" % (args, kwargs)) context = kwargs.get('context', None) instance_id = kwargs.get('instance_id', None) if len(args) > 0 and not context: context = args[1] if len(args) > 1 and not instance_id: - context = args[2] + instance_id = args[2] return ("servers", context, instance_id) - def unmarshall_result(self, result): - server = result[0].__dict__ - - for k in server.keys(): - if k[0] == '_' or k == 'manager': - del server[k] - - return dict(server=server) + def unmarshall_result(self, zone_responses): + """Result is a list of responses from each child zone. + Each decorator derivation is responsible to turning this + into a format expected by the calling method. For + example, this one is expected to return a single Server + dict {'server':{k:v}}. Others may return a list of them, like + {'servers':[{k,v}]}""" + reduced_response = [] + for zone_response in zone_responses: + if not zone_response: + continue + + server = zone_response.__dict__ + + for k in server.keys(): + if k[0] == '_' or k == 'manager': + del server[k] + + reduced_response.append(dict(server=server)) + if reduced_response: + return reduced_response[0] # first for now. + return {} def redirect_handler(f): diff --git a/nova/tests/test_scheduler.py b/nova/tests/test_scheduler.py index 244e43bd9..50e2429ba 100644 --- a/nova/tests/test_scheduler.py +++ b/nova/tests/test_scheduler.py @@ -21,6 +21,8 @@ Tests For Scheduler import datetime import mox +import stubout +import webob from mox import IgnoreArg from nova import context @@ -32,6 +34,7 @@ from nova import test from nova import rpc from nova import utils from nova.auth import manager as auth_manager +from nova.scheduler import api from nova.scheduler import manager from nova.scheduler import driver from nova.compute import power_state @@ -937,3 +940,70 @@ class SimpleDriverTestCase(test.TestCase): db.instance_destroy(self.context, instance_id) db.service_destroy(self.context, s_ref['id']) db.service_destroy(self.context, s_ref2['id']) + + +class FakeZone(object): + def __init__(self, api_url, username, password): + self.api_url = api_url + self.username = username + self.password = password + +def zone_get_all(context): + return [ + FakeZone('http://example.com', 'bob', 'xxx'), + ] + + +def go_boom(self, context, instance): + raise exception.InstanceNotFound("boom message", instance) + + +def fake_openstack_init(self, username, password, api): + servers=[] + + +def fake_auth(self): + pass + +class FakeServer: + def foo(self): + pass + +class FakeManager: + def get(self, id): + return FakeServer() + +class FakeOpenStack: + + def __init__(self, username, api, auth): + self.servers = FakeManager() + + def authenticate(self): + pass + + +class ZoneRedirectTest(test.TestCase): + def setUp(self): + super(ZoneRedirectTest, self).setUp() + self.stubs = stubout.StubOutForTesting() + + self.stubs.Set(api.novaclient, 'OpenStack', FakeOpenStack) + self.stubs.Set(db, 'zone_get_all', zone_get_all) + + self.enable_zone_routing = FLAGS.enable_zone_routing + FLAGS.enable_zone_routing = True + + def tearDown(self): + self.stubs.UnsetAll() + FLAGS.enable_zone_routing = self.enable_zone_routing + super(ZoneRedirectTest, self).tearDown() + + def test_trap_found_locally(self): + decorator = api.reroute_compute("foo") + try: + wrapper = decorator(go_boom) + result = wrapper(None, None, 1) # self, context, id + except api.RedirectResult, e: + pass + + |
