blob: a28ca4f78356d6220c4211237ba3e62cdff9b8bc [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
11from autotest_lib.client.common_lib import site_utils, error
Chris Masone2d61ca22012-04-02 16:52:46 -070012
13class Driver(object):
14 """Implements the main loop of the suite_scheduler.
15
Chris Masonebf8775a2012-09-10 10:44:18 -070016 @var EVENT_CLASSES: list of the event classes Driver supports.
Chris Masonefe5a5092012-04-11 18:29:07 -070017 @var _LOOP_INTERVAL_SECONDS: seconds to wait between loop iterations.
Chris Masone2d61ca22012-04-02 16:52:46 -070018
19 @var _scheduler: a DedupingScheduler, used to schedule jobs with the AFE.
Chris Masone3fba86f2012-04-03 10:06:56 -070020 @var _enumerator: a BoardEnumerator, used to list plaforms known to
Chris Masone2d61ca22012-04-02 16:52:46 -070021 the AFE
Chris Masone855d86f2012-05-07 13:48:07 -070022 @var _events: dict of BaseEvents to be handled each time through main loop.
Chris Masone2d61ca22012-04-02 16:52:46 -070023 """
24
Chris Masonebf8775a2012-09-10 10:44:18 -070025 EVENT_CLASSES = [timed_event.Nightly, timed_event.Weekly,
26 build_event.NewBuild]
Chris Masonefe5a5092012-04-11 18:29:07 -070027 _LOOP_INTERVAL_SECONDS = 5 * 60
Chris Masone2d61ca22012-04-02 16:52:46 -070028
29
Chris Masone67f06d62012-04-12 15:16:56 -070030 def __init__(self, scheduler, enumerator):
Chris Masone2d61ca22012-04-02 16:52:46 -070031 """Constructor
32
Chris Masone67f06d62012-04-12 15:16:56 -070033 @param scheduler: an instance of deduping_scheduler.DedupingScheduler.
34 @param enumerator: an instance of board_enumerator.BoardEnumerator.
Chris Masone2d61ca22012-04-02 16:52:46 -070035 """
Chris Masone67f06d62012-04-12 15:16:56 -070036 self._scheduler = scheduler
37 self._enumerator = enumerator
Chris Masone2d61ca22012-04-02 16:52:46 -070038
Chris Masone2d61ca22012-04-02 16:52:46 -070039
Chris Masone855d86f2012-05-07 13:48:07 -070040 def RereadAndReprocessConfig(self, config, mv):
41 """Re-read config, re-populate self._events and recreate task lists.
42
43 @param config: an instance of ForgivingConfigParser.
44 @param mv: an instance of ManifestVersions.
45 """
46 config.reread()
47 new_events = self._CreateEventsWithTasks(config, mv)
48 for keyword, event in self._events.iteritems():
49 event.Merge(new_events[keyword])
50
51
Chris Masone93f51d42012-04-18 08:46:52 -070052 def SetUpEventsAndTasks(self, config, mv):
Chris Masone67f06d62012-04-12 15:16:56 -070053 """Populate self._events and create task lists from config.
54
Chris Masone96f16632012-04-04 18:36:03 -070055 @param config: an instance of ForgivingConfigParser.
Chris Masone93f51d42012-04-18 08:46:52 -070056 @param mv: an instance of ManifestVersions.
Chris Masone96f16632012-04-04 18:36:03 -070057 """
Chris Masone855d86f2012-05-07 13:48:07 -070058 self._events = self._CreateEventsWithTasks(config, mv)
59
60
61 def _CreateEventsWithTasks(self, config, mv):
62 """Create task lists from config, and assign to newly-minted events.
63
64 Calling multiple times should start afresh each time.
65
66 @param config: an instance of ForgivingConfigParser.
67 @param mv: an instance of ManifestVersions.
68 """
Chris Masone855d86f2012-05-07 13:48:07 -070069 events = {}
Chris Masonebf8775a2012-09-10 10:44:18 -070070 for klass in self.EVENT_CLASSES:
Chris Masone855d86f2012-05-07 13:48:07 -070071 events[klass.KEYWORD] = klass.CreateFromConfig(config, mv)
Chris Masone96f16632012-04-04 18:36:03 -070072
73 tasks = self.TasksFromConfig(config)
Chris Masone645c7e42012-05-17 17:28:40 -070074 for keyword, task_list in tasks.iteritems():
75 if keyword in events:
76 events[keyword].tasks = task_list
77 else:
78 logging.warn('%s, is an unknown keyword.', keyword)
Chris Masone855d86f2012-05-07 13:48:07 -070079 return events
Chris Masone96f16632012-04-04 18:36:03 -070080
81
82 def TasksFromConfig(self, config):
83 """Generate a dict of {event_keyword: [tasks]} mappings from |config|.
84
85 For each section in |config| that encodes a Task, instantiate a Task
86 object. Determine the event that Task is supposed to run_on and
87 append the object to a list associated with the appropriate event
88 keyword. Return a dictionary of these keyword: list of task mappings.
89
90 @param config: a ForgivingConfigParser containing tasks to be parsed.
91 @return dict of {event_keyword: [tasks]} mappings.
92 @raise MalformedConfigEntry on a task parsing error.
93 """
94 tasks = {}
95 for section in config.sections():
Chris Masone93f51d42012-04-18 08:46:52 -070096 if not base_event.HonoredSection(section):
Chris Masone96f16632012-04-04 18:36:03 -070097 try:
98 keyword, new_task = task.Task.CreateFromConfigSection(
99 config, section)
100 except task.MalformedConfigEntry as e:
101 logging.warn('%s is malformed: %s', section, e)
102 continue
103 tasks.setdefault(keyword, []).append(new_task)
104 return tasks
Chris Masone2d61ca22012-04-02 16:52:46 -0700105
106
Chris Masone855d86f2012-05-07 13:48:07 -0700107 def RunForever(self, config, mv):
Chris Masone67f06d62012-04-12 15:16:56 -0700108 """Main loop of the scheduler. Runs til the process is killed.
109
Chris Masone855d86f2012-05-07 13:48:07 -0700110 @param config: an instance of ForgivingConfigParser.
Chris Masone67f06d62012-04-12 15:16:56 -0700111 @param mv: an instance of manifest_versions.ManifestVersions.
112 """
Chris Masone855d86f2012-05-07 13:48:07 -0700113 for event in self._events.itervalues():
Chris Masone73a78382012-04-20 13:25:51 -0700114 event.Prepare()
Chris Masone2d61ca22012-04-02 16:52:46 -0700115 while True:
Chris Masone645c7e42012-05-17 17:28:40 -0700116 try:
117 self.HandleEventsOnce(mv)
Scott Zawalskic15c6b42012-07-09 13:16:05 -0400118 except board_enumerator.EnumeratorException as e:
Chris Masone645c7e42012-05-17 17:28:40 -0700119 logging.warn('Failed to enumerate boards: %r', e)
Chris Masone67f06d62012-04-12 15:16:56 -0700120 mv.Update()
Chris Masonefe5a5092012-04-11 18:29:07 -0700121 time.sleep(self._LOOP_INTERVAL_SECONDS)
Chris Masone855d86f2012-05-07 13:48:07 -0700122 self.RereadAndReprocessConfig(config, mv)
Chris Masone2d61ca22012-04-02 16:52:46 -0700123
124
Chris Masone67f06d62012-04-12 15:16:56 -0700125 def HandleEventsOnce(self, mv):
126 """One turn through the loop. Separated out for unit testing.
127
128 @param mv: an instance of manifest_versions.ManifestVersions.
Chris Masone645c7e42012-05-17 17:28:40 -0700129 @raise EnumeratorException if we can't enumerate any supported boards.
Chris Masone67f06d62012-04-12 15:16:56 -0700130 """
Chris Masone92874d32012-04-03 10:13:04 -0700131 boards = self._enumerator.Enumerate()
Chris Masonea3a38172012-05-14 15:19:56 -0700132 logging.info('Boards currently in the lab: %r', boards)
Chris Masone855d86f2012-05-07 13:48:07 -0700133 for e in self._events.itervalues():
Chris Masone2d61ca22012-04-02 16:52:46 -0700134 if e.ShouldHandle():
Aviv Keshet4e7722b2013-02-14 15:07:46 -0800135 try:
136 site_utils.check_lab_status()
137 except error.LabIsDownException as ex:
138 logging.warn('Skipping event %s, because lab is down '
139 'with message: %s', e.keyword, ex.message)
140 continue
141
Chris Masonea3a38172012-05-14 15:19:56 -0700142 logging.info('Handling %s event', e.keyword)
Chris Masone96f16632012-04-04 18:36:03 -0700143 for board in boards:
Chris Masoned17d1852012-04-20 11:52:49 -0700144 branch_builds = e.GetBranchBuildsForBoard(board)
Chris Masone96f16632012-04-04 18:36:03 -0700145 e.Handle(self._scheduler, branch_builds, board)
Chris Masonebbde3862012-05-07 14:29:51 -0700146 e.UpdateCriteria()
Chris Masone67f06d62012-04-12 15:16:56 -0700147
148
149 def ForceEventsOnceForBuild(self, keywords, build_name):
150 """Force events with provided keywords to happen, with given build.
151
152 @param keywords: iterable of event keywords to force
153 @param build_name: instead of looking up builds to test, test this one.
154 """
155 board, type, milestone, manifest = base_event.ParseBuildName(build_name)
Chris Masonecbe42772012-04-30 22:18:23 -0700156 branch_builds = {task.PickBranchName(type, milestone): [build_name]}
Alex Miller71384cf2013-03-04 12:09:05 -0800157 logging.info('Testing build %s-%s on %s', milestone, manifest, board)
Chris Masone67f06d62012-04-12 15:16:56 -0700158
Chris Masone855d86f2012-05-07 13:48:07 -0700159 for e in self._events.itervalues():
Chris Masone67f06d62012-04-12 15:16:56 -0700160 if e.keyword in keywords:
161 e.Handle(self._scheduler, branch_builds, board, force=True)