start of zone_aware_scheduler test
This commit is contained in:
parent
eb0619c91b
commit
3470ed651b
@ -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}})
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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):
|
||||
@ -42,23 +43,29 @@ class ZoneAwareScheduler(object):
|
||||
anything about the children."""
|
||||
return self._schedule(context, "compute", *args, **kwargs)
|
||||
|
||||
def schedule(self, context, topic, *args, **kwargs):
|
||||
def schedule(self, context, topic, *args, **kwargs):
|
||||
"""The schedule() contract requires we return the one
|
||||
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):
|
||||
"""Derived classes must override this method and return
|
||||
a list of hosts in [?] format."""
|
||||
raise NotImplemented()
|
||||
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):
|
||||
"""Derived classes must override this method and return
|
||||
a lists of hosts in [?] format."""
|
||||
raise NotImplemented()
|
||||
def weigh_hosts(self, num, specs, hosts):
|
||||
"""Derived classes must override this method and return
|
||||
a lists of hosts in [?] format."""
|
||||
raise NotImplemented()
|
||||
|
Loading…
Reference in New Issue
Block a user