summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSandy Walsh <sandy.walsh@rackspace.com>2011-02-24 01:53:01 -0800
committerSandy Walsh <sandy.walsh@rackspace.com>2011-02-24 01:53:01 -0800
commit65b9dfbea28f1607ef471e78b73ba77183d943f6 (patch)
treebead79457678cae14b62e0e964cd6a6186cc74f0
parent05fc3ea219f36bc1c246179b25b1feb017888b01 (diff)
capability aggregation working
-rw-r--r--nova/api/openstack/zones.py15
-rw-r--r--nova/scheduler/api.py15
-rw-r--r--nova/scheduler/manager.py12
-rw-r--r--nova/scheduler/zone_manager.py35
-rw-r--r--nova/scheduler_manager.py6
5 files changed, 68 insertions, 15 deletions
diff --git a/nova/api/openstack/zones.py b/nova/api/openstack/zones.py
index 989b3a235..c6c27dd4b 100644
--- a/nova/api/openstack/zones.py
+++ b/nova/api/openstack/zones.py
@@ -15,9 +15,10 @@
import common
+from nova import db
from nova import flags
+from nova import log as logging
from nova import wsgi
-from nova import db
from nova.scheduler import api
@@ -67,8 +68,16 @@ class Controller(wsgi.Controller):
def info(self, req):
"""Return name and capabilities for this zone."""
- return dict(zone=dict(name=FLAGS.zone_name,
- capabilities=FLAGS.zone_capabilities))
+ items = api.API().get_zone_capabilities(req.environ['nova.context'])
+
+ zone = dict(name=FLAGS.zone_name)
+ caps = FLAGS.zone_capabilities.split(';')
+ for cap in caps:
+ key_values = cap.split(':')
+ zone[key_values[0]] = key_values[1]
+ for item, (min_value, max_value) in items.iteritems():
+ zone[item] = "%s,%s" % (min_value, max_value)
+ return dict(zone=zone)
def show(self, req, id):
"""Return data about the given zone id"""
diff --git a/nova/scheduler/api.py b/nova/scheduler/api.py
index 6a6bfc032..ac38350ed 100644
--- a/nova/scheduler/api.py
+++ b/nova/scheduler/api.py
@@ -43,13 +43,24 @@ class API:
return rpc.call(context, queue, kwargs)
def get_zone_list(self, context):
+ """Return a list of zones assoicated with this zone."""
items = self._call_scheduler('get_zone_list', context)
for item in items:
item['api_url'] = item['api_url'].replace('\\/', '/')
return items
+ def get_zone_capabilities(self, context, service=None):
+ """Returns a dict of key, value capabilities for this zone,
+ or for a particular class of services running in this zone."""
+ return self._call_scheduler('get_zone_capabilities', context=context,
+ params=dict(service=service))
+
@classmethod
- def update_service_capabilities(cls, context, service_name, capabilities):
+ def update_service_capabilities(cls, context, service_name, host,
+ capabilities):
+ """Send an update to all the scheduler services informing them
+ of the capabilities of this service."""
kwargs = dict(method='update_service_capabilities',
- service_name=service_name, capabilities=capabilities)
+ args=dict(service_name=service_name, host=host,
+ capabilities=capabilities))
return rpc.fanout_cast(context, 'scheduler', kwargs)
diff --git a/nova/scheduler/manager.py b/nova/scheduler/manager.py
index 6b5c6e246..1bda77d89 100644
--- a/nova/scheduler/manager.py
+++ b/nova/scheduler/manager.py
@@ -59,10 +59,16 @@ class SchedulerManager(manager.Manager):
"""Get a list of zones from the ZoneManager."""
return self.zone_manager.get_zone_list()
+ def get_zone_capabilities(self, context=None, service=None):
+ """Get the normalized set of capabilites for this zone,
+ or for a particular service."""
+ return self.zone_manager.get_zone_capabilities(context, service)
+
def update_service_capabilities(self, context=None, service_name=None,
- capabilities={}):
- """Process a compute node update."""
- return self.zone_manager.update_compute_capabilities()
+ host=None, capabilities={}):
+ """Process a capability update from a service node."""
+ self.zone_manager.update_service_capabilities(service_name,
+ host, capabilities)
def _schedule(self, method, context, topic, *args, **kwargs):
"""Tries to call schedule_* method on the driver to retrieve host.
diff --git a/nova/scheduler/zone_manager.py b/nova/scheduler/zone_manager.py
index eedc5c235..09c9811f3 100644
--- a/nova/scheduler/zone_manager.py
+++ b/nova/scheduler/zone_manager.py
@@ -105,13 +105,37 @@ class ZoneManager(object):
def __init__(self):
self.last_zone_db_check = datetime.min
self.zone_states = {}
- self.compute_states = {}
+ self.service_states = {} # { <service> : { <host> : { cap k : v }}}
self.green_pool = greenpool.GreenPool()
def get_zone_list(self):
"""Return the list of zones we know about."""
return [zone.to_dict() for zone in self.zone_states.values()]
+ def get_zone_capabilities(self, context, service=None):
+ """Roll up all the individual host info to generic 'service'
+ capabilities. Each capability is aggregated into
+ <cap>_min and <cap>_max values."""
+ service_dict = self.service_states
+ if service:
+ service_dict = dict(service_name=service,
+ hosts=self.service_states.get(service, {}))
+
+ # TODO(sandy) - be smarter about fabricating this structure.
+ # But it's likely to change once we understand what the Best-Match
+ # code will need better.
+ combined = {} # { <service>_<cap> : (min, max), ... }
+ for service_name, host_dict in service_dict.iteritems():
+ for host, caps_dict in host_dict.iteritems():
+ for cap, value in caps_dict.iteritems():
+ key = "%s_%s" % (service_name, cap)
+ min_value, max_value = combined.get(key, (value, value))
+ min_value = min(min_value, value)
+ max_value = max(max_value, value)
+ combined[key] = (min_value, max_value)
+
+ return combined
+
def _refresh_from_db(self, context):
"""Make our zone state map match the db."""
# Add/update existing zones ...
@@ -143,5 +167,10 @@ class ZoneManager(object):
self._refresh_from_db(context)
self._poll_zones(context)
- def update_compute_capabilities(self):
- logging.debug(_("****** UPDATE COMPUTE CAPABILITIES *******"))
+ def update_service_capabilities(self, service_name, host, capabilities):
+ """Update the per-service capabilities based on this notification."""
+ logging.debug(_("Received %(service_name)s service update from "
+ "%(host)s: %(capabilities)s") % locals())
+ service_caps = self.service_states.get(service_name, {})
+ service_caps[host] = capabilities
+ self.service_states[service_name] = service_caps
diff --git a/nova/scheduler_manager.py b/nova/scheduler_manager.py
index 65bd71c05..ca39b85dd 100644
--- a/nova/scheduler_manager.py
+++ b/nova/scheduler_manager.py
@@ -34,13 +34,11 @@ FLAGS = flags.FLAGS
class SchedulerDependentManager(manager.Manager):
-
"""Periodically send capability updates to the Scheduler services.
Services that need to update the Scheduler of their capabilities
should derive from this class. Otherwise they can derive from
manager.Manager directly. Updates are only sent after
update_service_capabilities is called with non-None values."""
-
def __init__(self, host=None, db_driver=None, service_name="undefined"):
self.last_capabilities = None
self.service_name = service_name
@@ -53,8 +51,8 @@ class SchedulerDependentManager(manager.Manager):
def periodic_tasks(self, context=None):
"""Pass data back to the scheduler at a periodic interval"""
if self.last_capabilities:
- logging.debug(_("*** Notifying Schedulers of capabilities ..."))
+ logging.debug(_("Notifying Schedulers of capabilities ..."))
api.API.update_service_capabilities(context, self.service_name,
- self.last_capabilities)
+ self.host, self.last_capabilities)
super(SchedulerDependentManager, self).periodic_tasks(context)