summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSandy Walsh <sandy.walsh@rackspace.com>2011-03-16 11:44:40 -0700
committerSandy Walsh <sandy.walsh@rackspace.com>2011-03-16 11:44:40 -0700
commit4d057c9c2df77816ead6f30fa2795148aa8148d3 (patch)
treef91a0f49d789f3fd531ed89f6d14faf0e946ba83
parent8dffae687e78a1fa2a8cf0d321d64ee95a35cc1f (diff)
Refactored ZoneRedirect into ZoneChildHelper so ZoneManager can use this too.
-rw-r--r--nova/api/zone_redirect.py79
-rw-r--r--nova/compute/api.py8
-rw-r--r--nova/scheduler/api.py40
-rw-r--r--nova/scheduler/zone_manager.py2
4 files changed, 79 insertions, 50 deletions
diff --git a/nova/api/zone_redirect.py b/nova/api/zone_redirect.py
index fec1b1af3..0adf94046 100644
--- a/nova/api/zone_redirect.py
+++ b/nova/api/zone_redirect.py
@@ -28,6 +28,7 @@ import urllib
from nova import exception
from nova import log as logging
from nova import wsgi
+from nova.scheduler import api
import novaclient.client as client
import novaclient.exceptions as osexceptions
@@ -41,6 +42,43 @@ except ImportError:
LOG = logging.getLogger('server')
+class RequestForwarder(api.ChildZoneHelper):
+
+ def __init__(self, resource, method, body):
+ self.resource = resource
+ self.method = method
+ self.body = body
+
+ def process(self, client, zone):
+ api_url = zone.api_url
+ LOG.debug(_("Zone redirect to: %(api_url)s, " % locals()))
+ try:
+ if self.method == 'GET':
+ response, body = client.get(self.resource, body=self.body)
+ elif self.method == 'POST':
+ response, body = client.post(self.resource, body=self.body)
+ elif self.method == 'PUT':
+ response, body = client.put(self.resource, body=self.body)
+ elif self.method == 'DELETE':
+ response, body = client.delete(self.resource, body=self.body)
+ except osexceptions.OpenStackException, e:
+ LOG.info(_("Zone returned error: %s ('%s', '%s')"),
+ e.code, e.message, e.details)
+ res = webob.Response()
+ res.status = "404"
+ return res
+
+ status = response.status
+ LOG.debug(_("Zone %(api_url)s response: "
+ "%(response)s [%(status)s]/ %(body)s") %
+ locals())
+ res = webob.Response()
+ res.status = response['status']
+ res.content_type = response['content-type']
+ res.body = json.dumps(body)
+ return res
+
+
class ZoneRedirectMiddleware(wsgi.Middleware):
"""Catches Zone Routing exceptions and delegates the call
to child zones."""
@@ -57,10 +95,8 @@ class ZoneRedirectMiddleware(wsgi.Middleware):
# Todo(sandy): This only works for OpenStack API currently.
# Needs to be broken out into a driver.
- new_req = req.copy()
-
scheme, netloc, path, query, frag = \
- urlparse.urlsplit(new_req.path_qs)
+ urlparse.urlsplit(req.path_qs)
query = urlparse.parse_qsl(query)
query = [(key, value) for key, value in query if key != 'fresh']
query = urllib.urlencode(query)
@@ -69,38 +105,11 @@ class ZoneRedirectMiddleware(wsgi.Middleware):
m = re.search('/v\d+\.\d+/(.+)', url)
resource = m.group(1)
- for zone in e.zones:
- LOG.debug(_("Zone redirect to:[url:%(api_url)s, "
- "username:%(username)s]"
- % dict(api_url=zone.api_url,
- username=zone.username)))
-
- nova = client.OpenStackClient(zone.username, zone.password,
- zone.api_url)
- nova.authenticate()
- try:
- if req.method == 'GET':
- response, body = nova.get(resource, body=new_req.body)
- elif req.method == 'POST':
- response, body = nova.post(resource, body=new_req.body)
- elif req.method == 'PUT':
- response, body = nova.put(resource, body=new_req.body)
- elif req.method == 'DELETE':
- response, body = nova.delete(resource,
- body=new_req.body)
- except osexceptions.OpenStackException, e:
- LOG.info(_("Zone returned error: %s ('%s', '%s')"),
- e.code, e.message, e.details)
- continue
-
- LOG.debug(_("Zone Response: %s [%s]/ %s"), response,
- response.status, body)
- if response.status == 200:
- res = webob.Response()
- res.status = response['status']
- res.content_type = response['content-type']
- res.body = json.dumps(body)
- return res
+ forwarder = RequestForwarder(resource, req.method, req.body)
+ for result in forwarder.start(e.zones):
+ # Todo(sandy): We need to aggregate multiple successes.
+ if result.status_int == 200:
+ return result
LOG.debug(_("Zone Redirect Middleware returning 404 ..."))
res = webob.Response()
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 1185b9964..215257217 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -385,9 +385,7 @@ class API(base.Base):
if not host:
instance = self.get(context, instance_id)
host = instance['host']
- #queue = self.db.queue_get_for(context, FLAGS.compute_topic, host)
- queue = self.scheduler_api.get_queue_for_instance(context,
- FLAGS.compute_topic, host)
+ queue = self.db.queue_get_for(context, FLAGS.compute_topic, host)
params['instance_id'] = instance_id
kwargs = {'method': method, 'args': params}
rpc.cast(context, queue, kwargs)
@@ -406,9 +404,7 @@ class API(base.Base):
if not host:
instance = self.get(context, instance_id)
host = instance["host"]
- #queue = self.db.queue_get_for(context, FLAGS.compute_topic, host)
- queue = self.scheduler_api.get_queue_for_instance(context,
- FLAGS.compute_topic, host)
+ queue = self.db.queue_get_for(context, FLAGS.compute_topic, host)
params['instance_id'] = instance_id
kwargs = {'method': method, 'args': params}
return rpc.call(context, queue, kwargs)
diff --git a/nova/scheduler/api.py b/nova/scheduler/api.py
index 48da5bcfc..073784f31 100644
--- a/nova/scheduler/api.py
+++ b/nova/scheduler/api.py
@@ -23,6 +23,10 @@ from nova import flags
from nova import log as logging
from nova import rpc
+import novaclient.client as client
+
+from eventlet import greenpool
+
FLAGS = flags.FLAGS
LOG = logging.getLogger('nova.scheduler.api')
@@ -76,6 +80,8 @@ class API(object):
@classmethod
def get_instance_or_reroute(cls, context, instance_id):
+ """Return an instance from the db or throw a ZoneRouteException
+ if not found."""
try:
instance = db.instance_get(context, instance_id)
return instance
@@ -88,12 +94,30 @@ class API(object):
zones = db.zone_get_all(context)
raise exception.ZoneRouteException(zones)
- @classmethod
- def get_queue_for_instance(cls, context, service, instance_id):
- instance = db.instance_get(context, instance_id)
- zone = db.get_zone(instance.zone.id)
- if cls._is_current_zone(zone):
- return db.queue_get_for(context, service, instance['host'])
- # Throw a reroute Exception for the middleware to pick up.
- raise exception.ZoneRouteException(zone)
+def _wrap_method(function, self):
+ def _wrap(*args, **kwargs):
+ return function(self, *args, **kwargs)
+ return _wrap
+
+
+def _process(self, zone):
+ nova = client.OpenStackClient(zone.username, zone.password,
+ zone.api_url)
+ nova.authenticate()
+ return self.process(nova, zone)
+
+
+class ChildZoneHelper(object):
+ """Delegate a call to a set of Child Zones and wait for their
+ responses. Could be used for Zone Redirect or by the Scheduler
+ plug-ins to query the children."""
+
+ def start(self, zone_list):
+ self.green_pool = greenpool.GreenPool()
+ return [ result for result in self.green_pool.imap(
+ _wrap_method(_process, self), zone_list)]
+
+ def process(self, client, zone):
+ """Derived class must override."""
+ pass
diff --git a/nova/scheduler/zone_manager.py b/nova/scheduler/zone_manager.py
index c1a50dbc3..d32cc2e8f 100644
--- a/nova/scheduler/zone_manager.py
+++ b/nova/scheduler/zone_manager.py
@@ -104,7 +104,7 @@ class ZoneManager(object):
"""Keeps the zone states updated."""
def __init__(self):
self.last_zone_db_check = datetime.min
- self.zone_states = {}
+ self.zone_states = {} # { <zone_id> : ZoneState }
self.service_states = {} # { <service> : { <host> : { cap k : v }}}
self.green_pool = greenpool.GreenPool()