jamesren | 883492a | 2010-02-12 00:45:18 +0000 | [diff] [blame] | 1 | from autotest_lib.client.common_lib import utils |
| 2 | |
| 3 | class HostSchedulingUtility(object): |
| 4 | """Interface to host availability information from the scheduler.""" |
| 5 | def hosts_in_label(self, label_id): |
| 6 | """Return potentially usable hosts with the given label.""" |
| 7 | raise NotImplementedError |
| 8 | |
| 9 | |
| 10 | def remove_host_from_label(self, host_id, label_id): |
| 11 | """Remove this host from the internal list of usable hosts in the label. |
| 12 | |
| 13 | This is provided as an optimization -- when code gets a host from a |
| 14 | label and concludes it's unusable, it can call this to avoid getting |
| 15 | that host again in the future (within this tick). This function should |
| 16 | not affect correctness. |
| 17 | """ |
| 18 | raise NotImplementedError |
| 19 | |
| 20 | |
| 21 | def pop_host(self, host_id): |
| 22 | """Remove and return a host from the internal list of available hosts. |
| 23 | """ |
| 24 | raise NotImplementedError |
| 25 | |
| 26 | |
| 27 | def ineligible_hosts_for_entry(self, queue_entry): |
| 28 | """Get the list of hosts ineligible to run the given queue entry.""" |
| 29 | raise NotImplementedError |
| 30 | |
| 31 | |
| 32 | def is_host_usable(self, host_id): |
| 33 | """Determine if the host is currently usable at all.""" |
| 34 | raise NotImplementedError |
| 35 | |
| 36 | |
| 37 | def is_host_eligible_for_job(self, host_id, queue_entry): |
| 38 | """Determine if the host is eligible specifically for this queue entry. |
| 39 | |
| 40 | @param queue_entry: a HostQueueEntry DBObject |
| 41 | """ |
| 42 | raise NotImplementedError |
| 43 | |
| 44 | |
| 45 | class MetahostScheduler(object): |
| 46 | def can_schedule_metahost(self, queue_entry): |
| 47 | """Return true if this object can schedule the given queue entry. |
| 48 | |
| 49 | At most one MetahostScheduler should return true for any given entry. |
| 50 | |
| 51 | @param queue_entry: a HostQueueEntry DBObject |
| 52 | """ |
| 53 | raise NotImplementedError |
| 54 | |
| 55 | |
| 56 | def schedule_metahost(self, queue_entry, scheduling_utility): |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame^] | 57 | """Schedule the given queue entry, if possible. |
jamesren | 883492a | 2010-02-12 00:45:18 +0000 | [diff] [blame] | 58 | |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame^] | 59 | This method should make necessary database changes culminating in |
| 60 | assigning a host to the given queue entry in the database. It may |
| 61 | take no action if no host can be assigned currently. |
jamesren | 883492a | 2010-02-12 00:45:18 +0000 | [diff] [blame] | 62 | |
Eric Li | 861b2d5 | 2011-02-04 14:50:35 -0800 | [diff] [blame^] | 63 | @param queue_entry: a HostQueueEntry DBObject |
| 64 | @param scheduling_utility: a HostSchedulingUtility object |
| 65 | """ |
| 66 | raise NotImplementedError |
jamesren | 883492a | 2010-02-12 00:45:18 +0000 | [diff] [blame] | 67 | |
| 68 | |
| 69 | def recovery_on_startup(self): |
| 70 | """Perform any necessary recovery upon scheduler startup.""" |
| 71 | pass |
| 72 | |
| 73 | |
| 74 | def tick(self): |
| 75 | """Called once per scheduler cycle; any actions are allowed.""" |
| 76 | pass |
| 77 | |
| 78 | |
| 79 | class LabelMetahostScheduler(MetahostScheduler): |
| 80 | def can_schedule_metahost(self, queue_entry): |
| 81 | return bool(queue_entry.meta_host) |
| 82 | |
| 83 | |
| 84 | def schedule_metahost(self, queue_entry, scheduling_utility): |
| 85 | label_id = queue_entry.meta_host |
| 86 | hosts_in_label = scheduling_utility.hosts_in_label(label_id) |
| 87 | ineligible_host_ids = scheduling_utility.ineligible_hosts_for_entry( |
| 88 | queue_entry) |
| 89 | |
| 90 | for host_id in hosts_in_label: |
| 91 | if not scheduling_utility.is_host_usable(host_id): |
| 92 | scheduling_utility.remove_host_from_label(host_id, label_id) |
| 93 | continue |
| 94 | if host_id in ineligible_host_ids: |
| 95 | continue |
| 96 | if not scheduling_utility.is_host_eligible_for_job(host_id, |
| 97 | queue_entry): |
| 98 | continue |
| 99 | |
| 100 | # Remove the host from our cached internal state before returning |
| 101 | scheduling_utility.remove_host_from_label(host_id, label_id) |
| 102 | host = scheduling_utility.pop_host(host_id) |
| 103 | queue_entry.set_host(host) |
| 104 | return |
| 105 | |
| 106 | |
| 107 | def get_metahost_schedulers(): |
| 108 | return [LabelMetahostScheduler()] |