summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authorSandy Walsh <sandy.walsh@rackspace.com>2011-05-11 11:12:31 -0700
committerSandy Walsh <sandy.walsh@rackspace.com>2011-05-11 11:12:31 -0700
commit3470ed651b837106bf8afe736adfda63ad8d746e (patch)
tree617d79dce26c7b57b1559be42b2e819232429787 /nova
parenteb0619c91b4756d355b7a5cd5c1f16d342f14a6b (diff)
start of zone_aware_scheduler test
Diffstat (limited to 'nova')
-rw-r--r--nova/compute/api.py7
-rw-r--r--nova/scheduler/api.py39
-rw-r--r--nova/scheduler/zone_aware_scheduler.py31
3 files changed, 65 insertions, 12 deletions
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 63884be97..8a7c713a2 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -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}})
diff --git a/nova/scheduler/api.py b/nova/scheduler/api.py
index d8a0025ed..55f8e0a6d 100644
--- a/nova/scheduler/api.py
+++ b/nova/scheduler/api.py
@@ -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.
diff --git a/nova/scheduler/zone_aware_scheduler.py b/nova/scheduler/zone_aware_scheduler.py
index b849e8de1..b85cdfe6d 100644
--- a/nova/scheduler/zone_aware_scheduler.py
+++ b/nova/scheduler/zone_aware_scheduler.py
@@ -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()