First iteration of pluggable metahost handlers. This change adds the basic framework and moves the default, label-based metahost assignment code into a handler. It includes some refactorings to the basic scheduling code to make things a bit cleaner.
Signed-off-by: Steve Howard <showard@google.com>
git-svn-id: http://test.kernel.org/svn/autotest/trunk@4232 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/scheduler/metahost_scheduler.py b/scheduler/metahost_scheduler.py
new file mode 100644
index 0000000..9588e95
--- /dev/null
+++ b/scheduler/metahost_scheduler.py
@@ -0,0 +1,108 @@
+from autotest_lib.client.common_lib import utils
+
+class HostSchedulingUtility(object):
+ """Interface to host availability information from the scheduler."""
+ def hosts_in_label(self, label_id):
+ """Return potentially usable hosts with the given label."""
+ raise NotImplementedError
+
+
+ def remove_host_from_label(self, host_id, label_id):
+ """Remove this host from the internal list of usable hosts in the label.
+
+ This is provided as an optimization -- when code gets a host from a
+ label and concludes it's unusable, it can call this to avoid getting
+ that host again in the future (within this tick). This function should
+ not affect correctness.
+ """
+ raise NotImplementedError
+
+
+ def pop_host(self, host_id):
+ """Remove and return a host from the internal list of available hosts.
+ """
+ raise NotImplementedError
+
+
+ def ineligible_hosts_for_entry(self, queue_entry):
+ """Get the list of hosts ineligible to run the given queue entry."""
+ raise NotImplementedError
+
+
+ def is_host_usable(self, host_id):
+ """Determine if the host is currently usable at all."""
+ raise NotImplementedError
+
+
+ def is_host_eligible_for_job(self, host_id, queue_entry):
+ """Determine if the host is eligible specifically for this queue entry.
+
+ @param queue_entry: a HostQueueEntry DBObject
+ """
+ raise NotImplementedError
+
+
+class MetahostScheduler(object):
+ def can_schedule_metahost(self, queue_entry):
+ """Return true if this object can schedule the given queue entry.
+
+ At most one MetahostScheduler should return true for any given entry.
+
+ @param queue_entry: a HostQueueEntry DBObject
+ """
+ raise NotImplementedError
+
+
+ def schedule_metahost(self, queue_entry, scheduling_utility):
+ """Schedule the given queue entry, if possible.
+
+ This method should make necessary database changes culminating in
+ assigning a host to the given queue entry in the database. It may
+ take no action if no host can be assigned currently.
+
+ @param queue_entry: a HostQueueEntry DBObject
+ @param scheduling_utility: a HostSchedulingUtility object
+ """
+ raise NotImplementedError
+
+
+ def recovery_on_startup(self):
+ """Perform any necessary recovery upon scheduler startup."""
+ pass
+
+
+ def tick(self):
+ """Called once per scheduler cycle; any actions are allowed."""
+ pass
+
+
+class LabelMetahostScheduler(MetahostScheduler):
+ def can_schedule_metahost(self, queue_entry):
+ return bool(queue_entry.meta_host)
+
+
+ def schedule_metahost(self, queue_entry, scheduling_utility):
+ label_id = queue_entry.meta_host
+ hosts_in_label = scheduling_utility.hosts_in_label(label_id)
+ ineligible_host_ids = scheduling_utility.ineligible_hosts_for_entry(
+ queue_entry)
+
+ for host_id in hosts_in_label:
+ if not scheduling_utility.is_host_usable(host_id):
+ scheduling_utility.remove_host_from_label(host_id, label_id)
+ continue
+ if host_id in ineligible_host_ids:
+ continue
+ if not scheduling_utility.is_host_eligible_for_job(host_id,
+ queue_entry):
+ continue
+
+ # Remove the host from our cached internal state before returning
+ scheduling_utility.remove_host_from_label(host_id, label_id)
+ host = scheduling_utility.pop_host(host_id)
+ queue_entry.set_host(host)
+ return
+
+
+def get_metahost_schedulers():
+ return [LabelMetahostScheduler()]