blob: 5f3cbeed421347f4c0ce9ca7798c7c65aa3e93b9 [file] [log] [blame]
Xixuan Wu303a5192017-08-29 11:10:42 -07001# Copyright 2017 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
5"""Module of a basic event."""
6
7import datetime
8import logging
9
10import build_lib
11import constants
12import datastore_client
Xixuan Wua5a29442017-10-11 11:03:02 -070013import global_config
Xixuan Wu303a5192017-08-29 11:10:42 -070014import task
15
16# The suffix for section
17_SECTION_SUFFIX = '_params'
18
19
20class BaseEvent(object):
21 """Basic class for a suite scheduler event."""
22
23 # The default keyword and priority for base event. Will be overwritten by
24 # its subclass.
25 KEYWORD = 'base'
26 PRIORITY = constants.Priorities.DEFAULT
27
28 # The interval hours between consequent rounds of events. Default is 6.
29 LAST_EXEC_INTERVAL = 6
30
31 # The number of days between each event to trigger. Default is 1.
32 DAYS_INTERVAL = 1
33
34 # The max lifetime of suites kicked off by this event.
35 TIMEOUT = 24 # Hours
36
37 def __init__(self, event_settings, last_exec_utc, target_exec_utc):
38 """Initialize a base event.
39
40 Args:
41 event_settings: a config_reader.EventSettings object, indicating
42 the event settings.
43 last_exec_utc: The utc datetime.datetime timestamp of the last
44 execution of the event.
45 target_exec_utc: The utc datetime.datetime timestamp of the next
46 execution of the event.
47 """
48 self._update_with_settings(event_settings)
49 self._datastore_client = None
50 self.task_list = []
51
52 # Processing executing time.
53 self.target_exec_utc = target_exec_utc
54 self._set_last_exec(last_exec_utc)
55 self._set_should_handle()
56
57 logging.info('%s Event created:\ntarget_exec_time (utc): %s\n'
58 'last_exec_time (utc): %s\nshould_handle: %s',
59 self.keyword, self.target_exec_utc, self.last_exec_utc,
60 self.should_handle)
61
62 def set_task_list(self, task_list):
63 """Update task list with given input.
64
65 Args:
66 task_list: a new task list for this event.
67 """
68 self.task_list = list(task_list)
69
70 def filter_tasks(self):
71 """Filter tasks from original task list.
72
73 This could be overwritten by subclass of BaseEvent, like Nightly event, or
74 be directly used by event types like NewBuild.
75 """
76 self.task_list = list(self.task_list)
77
Xixuan Wu6fb16272017-10-19 13:16:00 -070078 def get_cros_builds(self, lab_config, db_client):
Xixuan Wu303a5192017-08-29 11:10:42 -070079 """Get CrOS builds to run on for this event.
80
81 Args:
Xixuan Wu6fb16272017-10-19 13:16:00 -070082 lab_config: a config_reader.LabConfig object, to read lab configs.
Xixuan Wu303a5192017-08-29 11:10:42 -070083 db_client: a cloud_sql_client.CIDBClient object, to call CIDB.
84
85 Returns:
Craig Bergstrom58263d32018-04-26 14:11:35 -060086 A two-tuples of dicts containing cros builds, see return from
Xixuan Wu303a5192017-08-29 11:10:42 -070087 |build_lib.get_cros_builds_since_date_from_db|.
88 """
89 return build_lib.get_cros_builds_since_date_from_db(
Xixuan Wu6fb16272017-10-19 13:16:00 -070090 db_client, lab_config.get_cros_board_list(), self.since_date)
Xixuan Wu303a5192017-08-29 11:10:42 -070091
92 def get_launch_control_builds(self, lab_config, android_client):
93 """Get launch control builds to run on for this event.
94
95 Args:
96 lab_config: a config_reader.LabConfig object, to read lab configs.
97 android_client: a rest_client.AndroidBuildRestClient object to call
98 android build API.
99
100 Returns:
101 a dict containing launch control builds for Android boards. See return
102 value of |build_lib.get_launch_control_builds_by_branch_targets|.
103 """
104 return build_lib.get_launch_control_builds_by_branch_targets(
105 android_client, lab_config.get_android_board_list(),
106 self.launch_control_branch_targets)
107
Craig Bergstrom58263d32018-04-26 14:11:35 -0600108 def process_tasks(self, launch_control_builds, cros_builds_tuple,
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700109 configs, db_client):
Xixuan Wu303a5192017-08-29 11:10:42 -0700110 """Schedule tasks in task_list.
111
112 Args:
113 launch_control_builds: the build dict for Android boards, see
114 return value of |get_launch_control_builds|.
Craig Bergstrom58263d32018-04-26 14:11:35 -0600115 cros_builds_tuple: a two-tuple of build dicts for ChromeOS boards,
116 see return value of |get_cros_builds|.
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700117 configs: a config_reader.Configs object, to contain several config
118 readers.
Xixuan Wu303a5192017-08-29 11:10:42 -0700119 db_client: a cloud_sql_client.CIDBClient object to connect to cidb.
120
121 Returns:
122 A list of finished tasks' names.
123 """
Xixuan Wu5451a662017-10-17 10:57:40 -0700124 scheduled_tasks = []
Xixuan Wu303a5192017-08-29 11:10:42 -0700125 for per_task in self.task_list:
126 try:
Craig Bergstrom58263d32018-04-26 14:11:35 -0600127 if per_task.schedule(launch_control_builds, cros_builds_tuple,
Xixuan Wuf4a4c882019-03-15 14:48:26 -0700128 configs, db_client):
Xixuan Wu5451a662017-10-17 10:57:40 -0700129 scheduled_tasks.append(per_task.name)
130 else:
131 logging.debug('No suites are scheduled in suites queue for '
132 'task %s', per_task.name)
Xixuan Wu303a5192017-08-29 11:10:42 -0700133 except task.SchedulingError:
134 logging.exception('Failed to schedule task: %s', per_task.name)
135 continue
136
Xixuan Wu5451a662017-10-17 10:57:40 -0700137 return scheduled_tasks
Xixuan Wu303a5192017-08-29 11:10:42 -0700138
139 def finish(self):
140 """Execute all actions that once an event is finished."""
141 self.datastore_client.set_last_execute_time(
142 self.keyword, self.target_exec_utc)
143
144 def _update_with_settings(self, event_settings):
145 """Update event with given settings from config file.
146
147 Args:
148 event_settings: a config_reader.EventSettings object, indicating
149 the event settings.
150 """
151 self.always_handle = event_settings.always_handle is not None
152 if self.always_handle:
153 self.always_handle = event_settings.always_handle
154
155 def _set_last_exec(self, last_exec_utc):
156 """Process and set last execute time.
157
158 Set last_exec_utc. If last_exec_utc is too old or None, set it as
159 target_exec_utc.
160
161 Args:
162 last_exec_utc: the utc datetime.datetime timestamp of last execute
163 time. None means no last_exec_utc saved for this event in
164 datastore.
165 """
166 if last_exec_utc is not None:
167 self.last_exec_utc = last_exec_utc
168
169 # If this TimedEvent has expired for a period of time, run its
170 # tasks on next available timepoint.
171 if (self.target_exec_utc - self.last_exec_utc > datetime.timedelta(
172 hours=self.LAST_EXEC_INTERVAL)):
173 self.last_exec_utc = self.target_exec_utc
174 else:
175 self.last_exec_utc = self.target_exec_utc
176
177 def _set_should_handle(self):
178 """Update it's the time for the event to be handled."""
Xixuan Wua5a29442017-10-11 11:03:02 -0700179 if self.always_handle or global_config.GAE_TESTING:
Xixuan Wu303a5192017-08-29 11:10:42 -0700180 self.should_handle = True
181 else:
182 if self.last_exec_utc and self.last_exec_utc == self.target_exec_utc:
183 self.should_handle = False
184 else:
185 self.should_handle = True
186
187 @classmethod
188 def section_name(cls):
189 """Getter for the section name of the event.
190
191 Returns:
192 A string representing section name, refers to a section in config file
193 that contains this event's params.
194 """
195 return cls.KEYWORD + _SECTION_SUFFIX
196
197 @property
198 def datastore_client(self):
199 """Getter for private |self._datastore_client| property."""
200 if self._datastore_client is None:
201 self._datastore_client = (
202 datastore_client.LastExecutionRecordStore())
203
204 return self._datastore_client
205
206 @property
207 def keyword(self):
208 """Getter for private |self.KEYWORD| property."""
209 return self.KEYWORD
210
211 @property
212 def launch_control_branch_targets(self):
213 """Get a dict of branch:targets for launch controls from all tasks."""
214 branches = {}
215 for per_task in self.task_list:
216 for branch in per_task.launch_control_branches:
217 branches.setdefault(branch, []).extend(
218 per_task.launch_control_targets)
219
220 return branches