summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSandy Walsh <sandy.walsh@rackspace.com>2011-03-21 18:16:35 -0700
committerSandy Walsh <sandy.walsh@rackspace.com>2011-03-21 18:16:35 -0700
commit08d06d1219a00b90ae211fb44fc7e33ba71c7a76 (patch)
tree8725afb9895df532481b14ba8e30f57e71dc6c85
parentb1def6b2b104a143b7491cef9a01babe9ab3e75d (diff)
downloadnova-08d06d1219a00b90ae211fb44fc7e33ba71c7a76.tar.gz
nova-08d06d1219a00b90ae211fb44fc7e33ba71c7a76.tar.xz
nova-08d06d1219a00b90ae211fb44fc7e33ba71c7a76.zip
better comments. First redirect test
-rw-r--r--nova/scheduler/api.py49
-rw-r--r--nova/tests/test_scheduler.py70
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
+
+