blob: e6bf5526c08178c0c085313a34df03473674e583 [file] [log] [blame]
Chris Masone2d61ca22012-04-02 16:52:46 -07001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Chris Masone96f16632012-04-04 18:36:03 -07005import logging, time
Chris Masone2d61ca22012-04-02 16:52:46 -07006
Aviv Keshet4e7722b2013-02-14 15:07:46 -08007import base_event, board_enumerator, build_event
8import task, timed_event
Chris Masone2d61ca22012-04-02 16:52:46 -07009
Aviv Keshet4e7722b2013-02-14 15:07:46 -080010import common
Dan Shi098d1e22015-09-02 10:00:24 -070011from autotest_lib.client.common_lib.cros.graphite import autotest_stats
J. Richard Barnette3cbd76b2013-11-27 12:11:25 -080012from autotest_lib.server import utils
Chris Masone2d61ca22012-04-02 16:52:46 -070013
Dan Shi098d1e22015-09-02 10:00:24 -070014
15_timer = autotest_stats.Timer('suite_scheduler')
16
Chris Masone2d61ca22012-04-02 16:52:46 -070017class Driver(object):
18 """Implements the main loop of the suite_scheduler.
19
Chris Masonebf8775a2012-09-10 10:44:18 -070020 @var EVENT_CLASSES: list of the event classes Driver supports.
Chris Masonefe5a5092012-04-11 18:29:07 -070021 @var _LOOP_INTERVAL_SECONDS: seconds to wait between loop iterations.
Chris Masone2d61ca22012-04-02 16:52:46 -070022
23 @var _scheduler: a DedupingScheduler, used to schedule jobs with the AFE.
Chris Masone3fba86f2012-04-03 10:06:56 -070024 @var _enumerator: a BoardEnumerator, used to list plaforms known to
Chris Masone2d61ca22012-04-02 16:52:46 -070025 the AFE
Chris Masone855d86f2012-05-07 13:48:07 -070026 @var _events: dict of BaseEvents to be handled each time through main loop.
Chris Masone2d61ca22012-04-02 16:52:46 -070027 """
28
Chris Masonebf8775a2012-09-10 10:44:18 -070029 EVENT_CLASSES = [timed_event.Nightly, timed_event.Weekly,
30 build_event.NewBuild]
Chris Masonefe5a5092012-04-11 18:29:07 -070031 _LOOP_INTERVAL_SECONDS = 5 * 60
Chris Masone2d61ca22012-04-02 16:52:46 -070032
33
Dan Shi23245142015-01-22 13:22:28 -080034 def __init__(self, scheduler, enumerator, is_sanity=False):
Chris Masone2d61ca22012-04-02 16:52:46 -070035 """Constructor
36
Chris Masone67f06d62012-04-12 15:16:56 -070037 @param scheduler: an instance of deduping_scheduler.DedupingScheduler.
38 @param enumerator: an instance of board_enumerator.BoardEnumerator.
Dan Shi23245142015-01-22 13:22:28 -080039 @param is_sanity: Set to True if the driver is created for sanity check.
40 Default is set to False.
Chris Masone2d61ca22012-04-02 16:52:46 -070041 """
Chris Masone67f06d62012-04-12 15:16:56 -070042 self._scheduler = scheduler
43 self._enumerator = enumerator
Dan Shi23245142015-01-22 13:22:28 -080044 task.TotMilestoneManager.is_sanity = is_sanity
Chris Masone2d61ca22012-04-02 16:52:46 -070045
Chris Masone2d61ca22012-04-02 16:52:46 -070046
Chris Masone855d86f2012-05-07 13:48:07 -070047 def RereadAndReprocessConfig(self, config, mv):
48 """Re-read config, re-populate self._events and recreate task lists.
49
50 @param config: an instance of ForgivingConfigParser.
51 @param mv: an instance of ManifestVersions.
52 """
53 config.reread()
54 new_events = self._CreateEventsWithTasks(config, mv)
55 for keyword, event in self._events.iteritems():
56 event.Merge(new_events[keyword])
57
58
Chris Masone93f51d42012-04-18 08:46:52 -070059 def SetUpEventsAndTasks(self, config, mv):
Chris Masone67f06d62012-04-12 15:16:56 -070060 """Populate self._events and create task lists from config.
61
Chris Masone96f16632012-04-04 18:36:03 -070062 @param config: an instance of ForgivingConfigParser.
Chris Masone93f51d42012-04-18 08:46:52 -070063 @param mv: an instance of ManifestVersions.
Chris Masone96f16632012-04-04 18:36:03 -070064 """
Chris Masone855d86f2012-05-07 13:48:07 -070065 self._events = self._CreateEventsWithTasks(config, mv)
66
67
68 def _CreateEventsWithTasks(self, config, mv):
69 """Create task lists from config, and assign to newly-minted events.
70
71 Calling multiple times should start afresh each time.
72
73 @param config: an instance of ForgivingConfigParser.
74 @param mv: an instance of ManifestVersions.
75 """
Chris Masone855d86f2012-05-07 13:48:07 -070076 events = {}
Chris Masonebf8775a2012-09-10 10:44:18 -070077 for klass in self.EVENT_CLASSES:
Chris Masone855d86f2012-05-07 13:48:07 -070078 events[klass.KEYWORD] = klass.CreateFromConfig(config, mv)
Chris Masone96f16632012-04-04 18:36:03 -070079
80 tasks = self.TasksFromConfig(config)
Chris Masone645c7e42012-05-17 17:28:40 -070081 for keyword, task_list in tasks.iteritems():
82 if keyword in events:
83 events[keyword].tasks = task_list
84 else:
Ilja H. Friedel04be2bd2014-05-07 21:29:59 -070085 logging.warning('%s, is an unknown keyword.', keyword)
Chris Masone855d86f2012-05-07 13:48:07 -070086 return events
Chris Masone96f16632012-04-04 18:36:03 -070087
88
89 def TasksFromConfig(self, config):
90 """Generate a dict of {event_keyword: [tasks]} mappings from |config|.
91
92 For each section in |config| that encodes a Task, instantiate a Task
93 object. Determine the event that Task is supposed to run_on and
94 append the object to a list associated with the appropriate event
95 keyword. Return a dictionary of these keyword: list of task mappings.
96
97 @param config: a ForgivingConfigParser containing tasks to be parsed.
98 @return dict of {event_keyword: [tasks]} mappings.
99 @raise MalformedConfigEntry on a task parsing error.
100 """
101 tasks = {}
102 for section in config.sections():
Chris Masone93f51d42012-04-18 08:46:52 -0700103 if not base_event.HonoredSection(section):
Chris Masone96f16632012-04-04 18:36:03 -0700104 try:
105 keyword, new_task = task.Task.CreateFromConfigSection(
106 config, section)
107 except task.MalformedConfigEntry as e:
Ilja H. Friedel04be2bd2014-05-07 21:29:59 -0700108 logging.warning('%s is malformed: %s', section, e)
Chris Masone96f16632012-04-04 18:36:03 -0700109 continue
110 tasks.setdefault(keyword, []).append(new_task)
111 return tasks
Chris Masone2d61ca22012-04-02 16:52:46 -0700112
113
Chris Masone855d86f2012-05-07 13:48:07 -0700114 def RunForever(self, config, mv):
Chris Masone67f06d62012-04-12 15:16:56 -0700115 """Main loop of the scheduler. Runs til the process is killed.
116
Chris Masone855d86f2012-05-07 13:48:07 -0700117 @param config: an instance of ForgivingConfigParser.
Chris Masone67f06d62012-04-12 15:16:56 -0700118 @param mv: an instance of manifest_versions.ManifestVersions.
119 """
Chris Masone855d86f2012-05-07 13:48:07 -0700120 for event in self._events.itervalues():
Chris Masone73a78382012-04-20 13:25:51 -0700121 event.Prepare()
Chris Masone2d61ca22012-04-02 16:52:46 -0700122 while True:
Chris Masone645c7e42012-05-17 17:28:40 -0700123 try:
124 self.HandleEventsOnce(mv)
Scott Zawalskic15c6b42012-07-09 13:16:05 -0400125 except board_enumerator.EnumeratorException as e:
Ilja H. Friedel04be2bd2014-05-07 21:29:59 -0700126 logging.warning('Failed to enumerate boards: %r', e)
Dan Shi098d1e22015-09-02 10:00:24 -0700127 with _timer.get_client('manifest_versions_update'):
128 mv.Update()
129 with _timer.get_client('tot_milestone_manager_refresh'):
130 task.TotMilestoneManager().refresh()
Chris Masonefe5a5092012-04-11 18:29:07 -0700131 time.sleep(self._LOOP_INTERVAL_SECONDS)
Chris Masone855d86f2012-05-07 13:48:07 -0700132 self.RereadAndReprocessConfig(config, mv)
Chris Masone2d61ca22012-04-02 16:52:46 -0700133
134
Dan Shi098d1e22015-09-02 10:00:24 -0700135 @_timer.decorate
Chris Masone67f06d62012-04-12 15:16:56 -0700136 def HandleEventsOnce(self, mv):
137 """One turn through the loop. Separated out for unit testing.
138
139 @param mv: an instance of manifest_versions.ManifestVersions.
Chris Masone645c7e42012-05-17 17:28:40 -0700140 @raise EnumeratorException if we can't enumerate any supported boards.
Chris Masone67f06d62012-04-12 15:16:56 -0700141 """
Chris Masone92874d32012-04-03 10:13:04 -0700142 boards = self._enumerator.Enumerate()
Chris Masonea3a38172012-05-14 15:19:56 -0700143 logging.info('Boards currently in the lab: %r', boards)
Chris Masone855d86f2012-05-07 13:48:07 -0700144 for e in self._events.itervalues():
Chris Masone2d61ca22012-04-02 16:52:46 -0700145 if e.ShouldHandle():
Chris Masonea3a38172012-05-14 15:19:56 -0700146 logging.info('Handling %s event', e.keyword)
Chris Masone96f16632012-04-04 18:36:03 -0700147 for board in boards:
Chris Masoned17d1852012-04-20 11:52:49 -0700148 branch_builds = e.GetBranchBuildsForBoard(board)
Chris Masone96f16632012-04-04 18:36:03 -0700149 e.Handle(self._scheduler, branch_builds, board)
Chris Masonebbde3862012-05-07 14:29:51 -0700150 e.UpdateCriteria()
Chris Masone67f06d62012-04-12 15:16:56 -0700151
152
153 def ForceEventsOnceForBuild(self, keywords, build_name):
154 """Force events with provided keywords to happen, with given build.
155
156 @param keywords: iterable of event keywords to force
157 @param build_name: instead of looking up builds to test, test this one.
158 """
J. Richard Barnette3cbd76b2013-11-27 12:11:25 -0800159 board, type, milestone, manifest = utils.ParseBuildName(build_name)
Chris Masonecbe42772012-04-30 22:18:23 -0700160 branch_builds = {task.PickBranchName(type, milestone): [build_name]}
Alex Millerda26f4f2013-03-07 14:07:44 -0800161 logging.info('Testing build R%s-%s on %s', milestone, manifest, board)
Chris Masone67f06d62012-04-12 15:16:56 -0700162
Chris Masone855d86f2012-05-07 13:48:07 -0700163 for e in self._events.itervalues():
Chris Masone67f06d62012-04-12 15:16:56 -0700164 if e.keyword in keywords:
165 e.Handle(self._scheduler, branch_builds, board, force=True)