start of zone_aware_scheduler test

This commit is contained in:
Sandy Walsh 2011-05-11 11:12:31 -07:00
parent eb0619c91b
commit 3470ed651b
3 changed files with 65 additions and 12 deletions

View File

@ -248,11 +248,18 @@ class API(base.Base):
uid = context.user_id
LOG.debug(_("Casting to scheduler for %(pid)s/%(uid)s's"
" instance %(instance_id)s") % locals())
# NOTE(sandy): For now we're just going to pass in the
# instance_type record to the scheduler. In a later phase
# we'll be ripping this whole for-loop out and deferring the
# creation of the Instance record. At that point all this will
# change.
rpc.cast(context,
FLAGS.scheduler_topic,
{"method": "run_instance",
"args": {"topic": FLAGS.compute_topic,
"instance_id": instance_id,
"instance_type": instance_type,
"availability_zone": availability_zone,
"injected_files": injected_files}})

View File

@ -111,6 +111,45 @@ def _process(func, zone):
return func(nova, zone)
def call_zone_method(context, method, errors_to_ignore=None, *args, **kwargs):
"""Returns a list of (zone, call_result) objects."""
if not isinstance(errors_to_ignore, (list, tuple)):
# This will also handle the default None
errors_to_ignore = [errors_to_ignore]
pool = greenpool.GreenPool()
results = []
for zone in db.zone_get_all(context):
try:
nova = novaclient.OpenStack(zone.username, zone.password,
zone.api_url)
nova.authenticate()
except novaclient.exceptions.BadRequest, e:
url = zone.api_url
LOG.warn(_("Failed request to zone; URL=%(url)s: %(e)s")
% locals())
#TODO (dabo) - add logic for failure counts per zone,
# with escalation after a given number of failures.
continue
zone_method = getattr(nova.zones, method)
def _error_trap(*args, **kwargs):
try:
return zone_method(*args, **kwargs)
except Exception as e:
if type(e) in errors_to_ignore:
return None
# TODO (dabo) - want to be able to re-raise here.
# Returning a string now; raising was causing issues.
# raise e
return "ERROR", "%s" % e
res = pool.spawn(_error_trap, *args, **kwargs)
results.append((zone, res))
pool.waitall()
return [(zone.id, res.wait()) for zone, res in results]
def child_zone_helper(zone_list, func):
"""Fire off a command to each zone in the list.
The return is [novaclient return objects] from each child zone.

View File

@ -24,11 +24,12 @@ import operator
from nova import log as logging
from nova.scheduler import api
from nova.scheduler import driver
LOG = logging.getLogger('nova.scheduler.zone_aware_scheduler')
class ZoneAwareScheduler(object):
class ZoneAwareScheduler(driver.Scheduler):
"""Base class for creating Zone Aware Schedulers."""
def _call_zone_method(self, context, method, specs):
@ -47,18 +48,24 @@ class ZoneAwareScheduler(object):
best-suited host for this request.
"""
res = self._schedule(context, topic, *args, **kwargs)
# TODO(sirp): should this be a host object rather than a weight-dict?
return res[0]
def _schedule(self, context, topic, *args, **kwargs):
"""Returns a list of hosts that meet the required specs,
ordered by their fitness.
"""
#TODO(sandy): extract these from args.
num_instances = 1
specs = {}
# Filter local hosts based on requirements ...
host_list = self.filter_hosts()
host_list = self.filter_hosts(num_instances, specs)
# then weigh the selected hosts.
# weighted = [ { 'weight':#, 'name':host, ...}, ]
weighted = self.weight_hosts(host_list)
weighted = self.weigh_hosts(num_instances, specs, host_list)
# Next, tack on the best weights from the child zones ...
child_results = self._call_zone_method(context, "select",
@ -77,12 +84,12 @@ class ZoneAwareScheduler(object):
weighted.sort(key=operator.itemgetter('weight'))
return weighted
def filter_hosts(self):
def filter_hosts(self, num, specs):
"""Derived classes must override this method and return
a list of hosts in [?] format."""
raise NotImplemented()
def weigh_hosts(self, hosts):
def weigh_hosts(self, num, specs, hosts):
"""Derived classes must override this method and return
a lists of hosts in [?] format."""
raise NotImplemented()