blob: 3b5eef3366f8ca62d71f24baa1b19db3578544c6 [file] [log] [blame]
Aviv Keshet0b9cfc92013-02-05 11:36:02 -08001# pylint: disable-msg=C0111
2
mblighe8819cd2008-02-15 16:48:40 +00003"""\
4Functions to expose over the RPC interface.
5
6For all modify* and delete* functions that ask for an 'id' parameter to
7identify the object to operate on, the id may be either
8 * the database row ID
9 * the name of the object (label name, hostname, user login, etc.)
10 * a dictionary containing uniquely identifying field (this option should seldom
11 be used)
12
13When specifying foreign key fields (i.e. adding hosts to a label, or adding
14users to an ACL group), the given value may be either the database row ID or the
15name of the object.
16
17All get* functions return lists of dictionaries. Each dictionary represents one
18object and maps field names to values.
19
20Some examples:
21modify_host(2, hostname='myhost') # modify hostname of host with database ID 2
22modify_host('ipaj2', hostname='myhost') # modify hostname of host 'ipaj2'
23modify_test('sleeptest', test_type='Client', params=', seconds=60')
24delete_acl_group(1) # delete by ID
25delete_acl_group('Everyone') # delete by name
26acl_group_add_users('Everyone', ['mbligh', 'showard'])
27get_jobs(owner='showard', status='Queued')
28
mbligh93c80e62009-02-03 17:48:30 +000029See doctests/001_rpc_test.txt for (lots) more examples.
mblighe8819cd2008-02-15 16:48:40 +000030"""
31
32__author__ = 'showard@google.com (Steve Howard)'
33
showard29f7cd22009-04-29 21:16:24 +000034import datetime
showardcafd16e2009-05-29 18:37:49 +000035import common
Simran Basib6ec8ae2014-04-23 12:05:08 -070036from autotest_lib.client.common_lib import priorities
jamesrendd855242010-03-02 22:23:44 +000037from autotest_lib.frontend.afe import models, model_logic, model_attributes
showard6d7b2ff2009-06-10 00:16:47 +000038from autotest_lib.frontend.afe import control_file, rpc_utils
Simran Basib6ec8ae2014-04-23 12:05:08 -070039from autotest_lib.frontend.afe import site_rpc_interface
Jiaxi Luoaac54572014-06-04 13:57:02 -070040from autotest_lib.frontend.tko import rpc_interface as tko_rpc_interface
Simran Basi71206ef2014-08-13 13:51:18 -070041from autotest_lib.server import utils
Jiaxi Luo90190c92014-06-18 12:35:57 -070042from autotest_lib.server.cros.dynamic_suite import tools
mblighe8819cd2008-02-15 16:48:40 +000043
Eric Lid23bc192011-02-09 14:38:57 -080044def get_parameterized_autoupdate_image_url(job):
45 """Get the parameterized autoupdate image url from a parameterized job."""
46 known_test_obj = models.Test.smart_get('autoupdate_ParameterizedJob')
47 image_parameter = known_test_obj.testparameter_set.get(test=known_test_obj,
beeps8bb1f7d2013-08-05 01:30:09 -070048 name='image')
Eric Lid23bc192011-02-09 14:38:57 -080049 para_set = job.parameterized_job.parameterizedjobparameter_set
50 job_test_para = para_set.get(test_parameter=image_parameter)
51 return job_test_para.parameter_value
52
53
mblighe8819cd2008-02-15 16:48:40 +000054# labels
55
showard989f25d2008-10-01 11:38:11 +000056def add_label(name, kernel_config=None, platform=None, only_if_needed=None):
showardc92da832009-04-07 18:14:34 +000057 return models.Label.add_object(
58 name=name, kernel_config=kernel_config, platform=platform,
59 only_if_needed=only_if_needed).id
mblighe8819cd2008-02-15 16:48:40 +000060
61
62def modify_label(id, **data):
jadmanski0afbb632008-06-06 21:10:57 +000063 models.Label.smart_get(id).update_object(data)
mblighe8819cd2008-02-15 16:48:40 +000064
65
66def delete_label(id):
jadmanski0afbb632008-06-06 21:10:57 +000067 models.Label.smart_get(id).delete()
mblighe8819cd2008-02-15 16:48:40 +000068
69
showardbbabf502008-06-06 00:02:02 +000070def label_add_hosts(id, hosts):
showardbe3ec042008-11-12 18:16:07 +000071 host_objs = models.Host.smart_get_bulk(hosts)
showardcafd16e2009-05-29 18:37:49 +000072 label = models.Label.smart_get(id)
73 if label.platform:
74 models.Host.check_no_platform(host_objs)
75 label.host_set.add(*host_objs)
showardbbabf502008-06-06 00:02:02 +000076
77
78def label_remove_hosts(id, hosts):
showardbe3ec042008-11-12 18:16:07 +000079 host_objs = models.Host.smart_get_bulk(hosts)
jadmanski0afbb632008-06-06 21:10:57 +000080 models.Label.smart_get(id).host_set.remove(*host_objs)
showardbbabf502008-06-06 00:02:02 +000081
82
Jiaxi Luo31874592014-06-11 10:36:35 -070083def get_labels(exclude_filters=(), **filter_data):
showardc92da832009-04-07 18:14:34 +000084 """\
Jiaxi Luo31874592014-06-11 10:36:35 -070085 @param exclude_filters: A sequence of dictionaries of filters.
86
showardc92da832009-04-07 18:14:34 +000087 @returns A sequence of nested dictionaries of label information.
88 """
Jiaxi Luo31874592014-06-11 10:36:35 -070089 labels = models.Label.query_objects(filter_data)
90 for exclude_filter in exclude_filters:
91 labels = labels.exclude(**exclude_filter)
92 return rpc_utils.prepare_rows_as_nested_dicts(labels, ('atomic_group',))
showardc92da832009-04-07 18:14:34 +000093
94
95# atomic groups
96
showarde9450c92009-06-30 01:58:52 +000097def add_atomic_group(name, max_number_of_machines=None, description=None):
showardc92da832009-04-07 18:14:34 +000098 return models.AtomicGroup.add_object(
99 name=name, max_number_of_machines=max_number_of_machines,
100 description=description).id
101
102
103def modify_atomic_group(id, **data):
104 models.AtomicGroup.smart_get(id).update_object(data)
105
106
107def delete_atomic_group(id):
108 models.AtomicGroup.smart_get(id).delete()
109
110
111def atomic_group_add_labels(id, labels):
112 label_objs = models.Label.smart_get_bulk(labels)
113 models.AtomicGroup.smart_get(id).label_set.add(*label_objs)
114
115
116def atomic_group_remove_labels(id, labels):
117 label_objs = models.Label.smart_get_bulk(labels)
118 models.AtomicGroup.smart_get(id).label_set.remove(*label_objs)
119
120
121def get_atomic_groups(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000122 return rpc_utils.prepare_for_serialization(
showardc92da832009-04-07 18:14:34 +0000123 models.AtomicGroup.list_objects(filter_data))
mblighe8819cd2008-02-15 16:48:40 +0000124
125
126# hosts
127
showarddf062562008-07-03 19:56:37 +0000128def add_host(hostname, status=None, locked=None, protection=None):
jadmanski0afbb632008-06-06 21:10:57 +0000129 return models.Host.add_object(hostname=hostname, status=status,
showarddf062562008-07-03 19:56:37 +0000130 locked=locked, protection=protection).id
mblighe8819cd2008-02-15 16:48:40 +0000131
132
133def modify_host(id, **data):
showardbe0d8692009-08-20 23:42:44 +0000134 rpc_utils.check_modify_host(data)
showardce7c0922009-09-11 18:39:24 +0000135 host = models.Host.smart_get(id)
136 rpc_utils.check_modify_host_locking(host, data)
137 host.update_object(data)
mblighe8819cd2008-02-15 16:48:40 +0000138
139
showard276f9442009-05-20 00:33:16 +0000140def modify_hosts(host_filter_data, update_data):
141 """
showardbe0d8692009-08-20 23:42:44 +0000142 @param host_filter_data: Filters out which hosts to modify.
143 @param update_data: A dictionary with the changes to make to the hosts.
showard276f9442009-05-20 00:33:16 +0000144 """
showardbe0d8692009-08-20 23:42:44 +0000145 rpc_utils.check_modify_host(update_data)
showard276f9442009-05-20 00:33:16 +0000146 hosts = models.Host.query_objects(host_filter_data)
Alex Miller9658a952013-05-14 16:40:02 -0700147 # Check all hosts before changing data for exception safety.
148 for host in hosts:
149 rpc_utils.check_modify_host_locking(host, update_data)
showard276f9442009-05-20 00:33:16 +0000150 for host in hosts:
151 host.update_object(update_data)
152
153
mblighe8819cd2008-02-15 16:48:40 +0000154def host_add_labels(id, labels):
showardbe3ec042008-11-12 18:16:07 +0000155 labels = models.Label.smart_get_bulk(labels)
showardcafd16e2009-05-29 18:37:49 +0000156 host = models.Host.smart_get(id)
157
158 platforms = [label.name for label in labels if label.platform]
159 if len(platforms) > 1:
160 raise model_logic.ValidationError(
161 {'labels': 'Adding more than one platform label: %s' %
162 ', '.join(platforms)})
163 if len(platforms) == 1:
164 models.Host.check_no_platform([host])
165 host.labels.add(*labels)
mblighe8819cd2008-02-15 16:48:40 +0000166
167
168def host_remove_labels(id, labels):
showardbe3ec042008-11-12 18:16:07 +0000169 labels = models.Label.smart_get_bulk(labels)
jadmanski0afbb632008-06-06 21:10:57 +0000170 models.Host.smart_get(id).labels.remove(*labels)
mblighe8819cd2008-02-15 16:48:40 +0000171
172
MK Ryuacf35922014-10-03 14:56:49 -0700173def get_host_attribute(attribute, **host_filter_data):
174 """
175 @param attribute: string name of attribute
176 @param host_filter_data: filter data to apply to Hosts to choose hosts to
177 act upon
178 """
179 hosts = rpc_utils.get_host_query((), False, False, True, host_filter_data)
180 hosts = list(hosts)
181 models.Host.objects.populate_relationships(hosts, models.HostAttribute,
182 'attribute_list')
183 host_attr_dicts = []
184 for host_obj in hosts:
185 for attr_obj in host_obj.attribute_list:
186 if attr_obj.attribute == attribute:
187 host_attr_dicts.append(attr_obj.get_object_dict())
188 return rpc_utils.prepare_for_serialization(host_attr_dicts)
189
190
showard0957a842009-05-11 19:25:08 +0000191def set_host_attribute(attribute, value, **host_filter_data):
192 """
193 @param attribute string name of attribute
194 @param value string, or None to delete an attribute
195 @param host_filter_data filter data to apply to Hosts to choose hosts to act
196 upon
197 """
198 assert host_filter_data # disallow accidental actions on all hosts
199 hosts = models.Host.query_objects(host_filter_data)
200 models.AclGroup.check_for_acl_violation_hosts(hosts)
201
202 for host in hosts:
showardf8b19042009-05-12 17:22:49 +0000203 host.set_or_delete_attribute(attribute, value)
showard0957a842009-05-11 19:25:08 +0000204
205
mblighe8819cd2008-02-15 16:48:40 +0000206def delete_host(id):
jadmanski0afbb632008-06-06 21:10:57 +0000207 models.Host.smart_get(id).delete()
mblighe8819cd2008-02-15 16:48:40 +0000208
209
showard87cc38f2009-08-20 23:37:04 +0000210def get_hosts(multiple_labels=(), exclude_only_if_needed_labels=False,
showard8aa84fc2009-09-16 17:17:55 +0000211 exclude_atomic_group_hosts=False, valid_only=True, **filter_data):
showard87cc38f2009-08-20 23:37:04 +0000212 """
213 @param multiple_labels: match hosts in all of the labels given. Should
214 be a list of label names.
215 @param exclude_only_if_needed_labels: Exclude hosts with at least one
216 "only_if_needed" label applied.
217 @param exclude_atomic_group_hosts: Exclude hosts that have one or more
218 atomic group labels associated with them.
jadmanski0afbb632008-06-06 21:10:57 +0000219 """
showard43a3d262008-11-12 18:17:05 +0000220 hosts = rpc_utils.get_host_query(multiple_labels,
221 exclude_only_if_needed_labels,
showard87cc38f2009-08-20 23:37:04 +0000222 exclude_atomic_group_hosts,
showard8aa84fc2009-09-16 17:17:55 +0000223 valid_only, filter_data)
showard0957a842009-05-11 19:25:08 +0000224 hosts = list(hosts)
225 models.Host.objects.populate_relationships(hosts, models.Label,
226 'label_list')
227 models.Host.objects.populate_relationships(hosts, models.AclGroup,
228 'acl_list')
229 models.Host.objects.populate_relationships(hosts, models.HostAttribute,
230 'attribute_list')
showard43a3d262008-11-12 18:17:05 +0000231 host_dicts = []
232 for host_obj in hosts:
233 host_dict = host_obj.get_object_dict()
showard0957a842009-05-11 19:25:08 +0000234 host_dict['labels'] = [label.name for label in host_obj.label_list]
showard909c9142009-07-07 20:54:42 +0000235 host_dict['platform'], host_dict['atomic_group'] = (rpc_utils.
236 find_platform_and_atomic_group(host_obj))
showard0957a842009-05-11 19:25:08 +0000237 host_dict['acls'] = [acl.name for acl in host_obj.acl_list]
238 host_dict['attributes'] = dict((attribute.attribute, attribute.value)
239 for attribute in host_obj.attribute_list)
showard43a3d262008-11-12 18:17:05 +0000240 host_dicts.append(host_dict)
241 return rpc_utils.prepare_for_serialization(host_dicts)
mblighe8819cd2008-02-15 16:48:40 +0000242
243
showard87cc38f2009-08-20 23:37:04 +0000244def get_num_hosts(multiple_labels=(), exclude_only_if_needed_labels=False,
showard8aa84fc2009-09-16 17:17:55 +0000245 exclude_atomic_group_hosts=False, valid_only=True,
246 **filter_data):
showard87cc38f2009-08-20 23:37:04 +0000247 """
248 Same parameters as get_hosts().
249
250 @returns The number of matching hosts.
251 """
showard43a3d262008-11-12 18:17:05 +0000252 hosts = rpc_utils.get_host_query(multiple_labels,
253 exclude_only_if_needed_labels,
showard87cc38f2009-08-20 23:37:04 +0000254 exclude_atomic_group_hosts,
showard8aa84fc2009-09-16 17:17:55 +0000255 valid_only, filter_data)
showard43a3d262008-11-12 18:17:05 +0000256 return hosts.count()
showard1385b162008-03-13 15:59:40 +0000257
mblighe8819cd2008-02-15 16:48:40 +0000258
259# tests
260
showard909c7a62008-07-15 21:52:38 +0000261def add_test(name, test_type, path, author=None, dependencies=None,
showard3d9899a2008-07-31 02:11:58 +0000262 experimental=True, run_verify=None, test_class=None,
showard909c7a62008-07-15 21:52:38 +0000263 test_time=None, test_category=None, description=None,
264 sync_count=1):
jadmanski0afbb632008-06-06 21:10:57 +0000265 return models.Test.add_object(name=name, test_type=test_type, path=path,
showard909c7a62008-07-15 21:52:38 +0000266 author=author, dependencies=dependencies,
267 experimental=experimental,
268 run_verify=run_verify, test_time=test_time,
269 test_category=test_category,
270 sync_count=sync_count,
jadmanski0afbb632008-06-06 21:10:57 +0000271 test_class=test_class,
272 description=description).id
mblighe8819cd2008-02-15 16:48:40 +0000273
274
275def modify_test(id, **data):
jadmanski0afbb632008-06-06 21:10:57 +0000276 models.Test.smart_get(id).update_object(data)
mblighe8819cd2008-02-15 16:48:40 +0000277
278
279def delete_test(id):
jadmanski0afbb632008-06-06 21:10:57 +0000280 models.Test.smart_get(id).delete()
mblighe8819cd2008-02-15 16:48:40 +0000281
282
283def get_tests(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000284 return rpc_utils.prepare_for_serialization(
285 models.Test.list_objects(filter_data))
mblighe8819cd2008-02-15 16:48:40 +0000286
287
showard2b9a88b2008-06-13 20:55:03 +0000288# profilers
289
290def add_profiler(name, description=None):
291 return models.Profiler.add_object(name=name, description=description).id
292
293
294def modify_profiler(id, **data):
295 models.Profiler.smart_get(id).update_object(data)
296
297
298def delete_profiler(id):
299 models.Profiler.smart_get(id).delete()
300
301
302def get_profilers(**filter_data):
303 return rpc_utils.prepare_for_serialization(
304 models.Profiler.list_objects(filter_data))
305
306
mblighe8819cd2008-02-15 16:48:40 +0000307# users
308
309def add_user(login, access_level=None):
jadmanski0afbb632008-06-06 21:10:57 +0000310 return models.User.add_object(login=login, access_level=access_level).id
mblighe8819cd2008-02-15 16:48:40 +0000311
312
313def modify_user(id, **data):
jadmanski0afbb632008-06-06 21:10:57 +0000314 models.User.smart_get(id).update_object(data)
mblighe8819cd2008-02-15 16:48:40 +0000315
316
317def delete_user(id):
jadmanski0afbb632008-06-06 21:10:57 +0000318 models.User.smart_get(id).delete()
mblighe8819cd2008-02-15 16:48:40 +0000319
320
321def get_users(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000322 return rpc_utils.prepare_for_serialization(
323 models.User.list_objects(filter_data))
mblighe8819cd2008-02-15 16:48:40 +0000324
325
326# acl groups
327
328def add_acl_group(name, description=None):
showard04f2cd82008-07-25 20:53:31 +0000329 group = models.AclGroup.add_object(name=name, description=description)
showard64a95952010-01-13 21:27:16 +0000330 group.users.add(models.User.current_user())
showard04f2cd82008-07-25 20:53:31 +0000331 return group.id
mblighe8819cd2008-02-15 16:48:40 +0000332
333
334def modify_acl_group(id, **data):
showard04f2cd82008-07-25 20:53:31 +0000335 group = models.AclGroup.smart_get(id)
336 group.check_for_acl_violation_acl_group()
337 group.update_object(data)
338 group.add_current_user_if_empty()
mblighe8819cd2008-02-15 16:48:40 +0000339
340
341def acl_group_add_users(id, users):
jadmanski0afbb632008-06-06 21:10:57 +0000342 group = models.AclGroup.smart_get(id)
showard04f2cd82008-07-25 20:53:31 +0000343 group.check_for_acl_violation_acl_group()
showardbe3ec042008-11-12 18:16:07 +0000344 users = models.User.smart_get_bulk(users)
jadmanski0afbb632008-06-06 21:10:57 +0000345 group.users.add(*users)
mblighe8819cd2008-02-15 16:48:40 +0000346
347
348def acl_group_remove_users(id, users):
jadmanski0afbb632008-06-06 21:10:57 +0000349 group = models.AclGroup.smart_get(id)
showard04f2cd82008-07-25 20:53:31 +0000350 group.check_for_acl_violation_acl_group()
showardbe3ec042008-11-12 18:16:07 +0000351 users = models.User.smart_get_bulk(users)
jadmanski0afbb632008-06-06 21:10:57 +0000352 group.users.remove(*users)
showard04f2cd82008-07-25 20:53:31 +0000353 group.add_current_user_if_empty()
mblighe8819cd2008-02-15 16:48:40 +0000354
355
356def acl_group_add_hosts(id, hosts):
jadmanski0afbb632008-06-06 21:10:57 +0000357 group = models.AclGroup.smart_get(id)
showard04f2cd82008-07-25 20:53:31 +0000358 group.check_for_acl_violation_acl_group()
showardbe3ec042008-11-12 18:16:07 +0000359 hosts = models.Host.smart_get_bulk(hosts)
jadmanski0afbb632008-06-06 21:10:57 +0000360 group.hosts.add(*hosts)
showard08f981b2008-06-24 21:59:03 +0000361 group.on_host_membership_change()
mblighe8819cd2008-02-15 16:48:40 +0000362
363
364def acl_group_remove_hosts(id, hosts):
jadmanski0afbb632008-06-06 21:10:57 +0000365 group = models.AclGroup.smart_get(id)
showard04f2cd82008-07-25 20:53:31 +0000366 group.check_for_acl_violation_acl_group()
showardbe3ec042008-11-12 18:16:07 +0000367 hosts = models.Host.smart_get_bulk(hosts)
jadmanski0afbb632008-06-06 21:10:57 +0000368 group.hosts.remove(*hosts)
showard08f981b2008-06-24 21:59:03 +0000369 group.on_host_membership_change()
mblighe8819cd2008-02-15 16:48:40 +0000370
371
372def delete_acl_group(id):
jadmanski0afbb632008-06-06 21:10:57 +0000373 models.AclGroup.smart_get(id).delete()
mblighe8819cd2008-02-15 16:48:40 +0000374
375
376def get_acl_groups(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000377 acl_groups = models.AclGroup.list_objects(filter_data)
378 for acl_group in acl_groups:
379 acl_group_obj = models.AclGroup.objects.get(id=acl_group['id'])
380 acl_group['users'] = [user.login
381 for user in acl_group_obj.users.all()]
382 acl_group['hosts'] = [host.hostname
383 for host in acl_group_obj.hosts.all()]
384 return rpc_utils.prepare_for_serialization(acl_groups)
mblighe8819cd2008-02-15 16:48:40 +0000385
386
387# jobs
388
mbligh120351e2009-01-24 01:40:45 +0000389def generate_control_file(tests=(), kernel=None, label=None, profilers=(),
showard91f85102009-10-12 20:34:52 +0000390 client_control_file='', use_container=False,
showard232b7ae2009-11-10 00:46:48 +0000391 profile_only=None, upload_kernel_config=False):
jadmanski0afbb632008-06-06 21:10:57 +0000392 """
mbligh120351e2009-01-24 01:40:45 +0000393 Generates a client-side control file to load a kernel and run tests.
394
395 @param tests List of tests to run.
mbligha3c58d22009-08-24 22:01:51 +0000396 @param kernel A list of kernel info dictionaries configuring which kernels
397 to boot for this job and other options for them
mbligh120351e2009-01-24 01:40:45 +0000398 @param label Name of label to grab kernel config from.
399 @param profilers List of profilers to activate during the job.
400 @param client_control_file The contents of a client-side control file to
401 run at the end of all tests. If this is supplied, all tests must be
402 client side.
403 TODO: in the future we should support server control files directly
404 to wrap with a kernel. That'll require changing the parameter
405 name and adding a boolean to indicate if it is a client or server
406 control file.
407 @param use_container unused argument today. TODO: Enable containers
408 on the host during a client side test.
showard91f85102009-10-12 20:34:52 +0000409 @param profile_only A boolean that indicates what default profile_only
410 mode to use in the control file. Passing None will generate a
411 control file that does not explcitly set the default mode at all.
showard232b7ae2009-11-10 00:46:48 +0000412 @param upload_kernel_config: if enabled it will generate server control
413 file code that uploads the kernel config file to the client and
414 tells the client of the new (local) path when compiling the kernel;
415 the tests must be server side tests
mbligh120351e2009-01-24 01:40:45 +0000416
417 @returns a dict with the following keys:
418 control_file: str, The control file text.
419 is_server: bool, is the control file a server-side control file?
420 synch_count: How many machines the job uses per autoserv execution.
421 synch_count == 1 means the job is asynchronous.
422 dependencies: A list of the names of labels on which the job depends.
423 """
showardd86debe2009-06-10 17:37:56 +0000424 if not tests and not client_control_file:
showard2bab8f42008-11-12 18:15:22 +0000425 return dict(control_file='', is_server=False, synch_count=1,
showard989f25d2008-10-01 11:38:11 +0000426 dependencies=[])
mblighe8819cd2008-02-15 16:48:40 +0000427
showard989f25d2008-10-01 11:38:11 +0000428 cf_info, test_objects, profiler_objects, label = (
showard2b9a88b2008-06-13 20:55:03 +0000429 rpc_utils.prepare_generate_control_file(tests, kernel, label,
430 profilers))
showard989f25d2008-10-01 11:38:11 +0000431 cf_info['control_file'] = control_file.generate_control(
mbligha3c58d22009-08-24 22:01:51 +0000432 tests=test_objects, kernels=kernel, platform=label,
mbligh120351e2009-01-24 01:40:45 +0000433 profilers=profiler_objects, is_server=cf_info['is_server'],
showard232b7ae2009-11-10 00:46:48 +0000434 client_control_file=client_control_file, profile_only=profile_only,
435 upload_kernel_config=upload_kernel_config)
showard989f25d2008-10-01 11:38:11 +0000436 return cf_info
mblighe8819cd2008-02-15 16:48:40 +0000437
438
jamesren4a41e012010-07-16 22:33:48 +0000439def create_parameterized_job(name, priority, test, parameters, kernel=None,
440 label=None, profilers=(), profiler_parameters=None,
441 use_container=False, profile_only=None,
442 upload_kernel_config=False, hosts=(),
443 meta_hosts=(), one_time_hosts=(),
444 atomic_group_name=None, synch_count=None,
445 is_template=False, timeout=None,
Simran Basi7e605742013-11-12 13:43:36 -0800446 timeout_mins=None, max_runtime_mins=None,
447 run_verify=False, email_list='', dependencies=(),
448 reboot_before=None, reboot_after=None,
449 parse_failed_repair=None, hostless=False,
450 keyvals=None, drone_set=None, run_reset=True):
jamesren4a41e012010-07-16 22:33:48 +0000451 """
452 Creates and enqueues a parameterized job.
453
454 Most parameters a combination of the parameters for generate_control_file()
455 and create_job(), with the exception of:
456
457 @param test name or ID of the test to run
458 @param parameters a map of parameter name ->
459 tuple of (param value, param type)
460 @param profiler_parameters a dictionary of parameters for the profilers:
461 key: profiler name
462 value: dict of param name -> tuple of
463 (param value,
464 param type)
465 """
466 # Save the values of the passed arguments here. What we're going to do with
467 # them is pass them all to rpc_utils.get_create_job_common_args(), which
468 # will extract the subset of these arguments that apply for
469 # rpc_utils.create_job_common(), which we then pass in to that function.
470 args = locals()
471
472 # Set up the parameterized job configs
473 test_obj = models.Test.smart_get(test)
Aviv Keshet3dd8beb2013-05-13 17:36:04 -0700474 control_type = test_obj.test_type
jamesren4a41e012010-07-16 22:33:48 +0000475
476 try:
477 label = models.Label.smart_get(label)
478 except models.Label.DoesNotExist:
479 label = None
480
481 kernel_objs = models.Kernel.create_kernels(kernel)
482 profiler_objs = [models.Profiler.smart_get(profiler)
483 for profiler in profilers]
484
485 parameterized_job = models.ParameterizedJob.objects.create(
486 test=test_obj, label=label, use_container=use_container,
487 profile_only=profile_only,
488 upload_kernel_config=upload_kernel_config)
489 parameterized_job.kernels.add(*kernel_objs)
490
491 for profiler in profiler_objs:
492 parameterized_profiler = models.ParameterizedJobProfiler.objects.create(
493 parameterized_job=parameterized_job,
494 profiler=profiler)
495 profiler_params = profiler_parameters.get(profiler.name, {})
496 for name, (value, param_type) in profiler_params.iteritems():
497 models.ParameterizedJobProfilerParameter.objects.create(
498 parameterized_job_profiler=parameterized_profiler,
499 parameter_name=name,
500 parameter_value=value,
501 parameter_type=param_type)
502
503 try:
504 for parameter in test_obj.testparameter_set.all():
505 if parameter.name in parameters:
506 param_value, param_type = parameters.pop(parameter.name)
507 parameterized_job.parameterizedjobparameter_set.create(
508 test_parameter=parameter, parameter_value=param_value,
509 parameter_type=param_type)
510
511 if parameters:
512 raise Exception('Extra parameters remain: %r' % parameters)
513
514 return rpc_utils.create_job_common(
515 parameterized_job=parameterized_job.id,
516 control_type=control_type,
517 **rpc_utils.get_create_job_common_args(args))
518 except:
519 parameterized_job.delete()
520 raise
521
522
Simran Basib6ec8ae2014-04-23 12:05:08 -0700523def create_job_page_handler(name, priority, control_file, control_type,
524 image=None, hostless=False, **kwargs):
525 """\
526 Create and enqueue a job.
527
528 @param name name of this job
529 @param priority Integer priority of this job. Higher is more important.
530 @param control_file String contents of the control file.
531 @param control_type Type of control file, Client or Server.
532 @param kwargs extra args that will be required by create_suite_job or
533 create_job.
534
535 @returns The created Job id number.
536 """
537 control_file = rpc_utils.encode_ascii(control_file)
Jiaxi Luodd67beb2014-07-18 16:28:31 -0700538 if not control_file:
539 raise model_logic.ValidationError({
540 'control_file' : "Control file cannot be empty"})
Simran Basib6ec8ae2014-04-23 12:05:08 -0700541
542 if image and hostless:
543 return site_rpc_interface.create_suite_job(
544 name=name, control_file=control_file, priority=priority,
545 build=image, **kwargs)
546 return create_job(name, priority, control_file, control_type, image=image,
547 hostless=hostless, **kwargs)
548
549
showard12f3e322009-05-13 21:27:42 +0000550def create_job(name, priority, control_file, control_type,
551 hosts=(), meta_hosts=(), one_time_hosts=(),
552 atomic_group_name=None, synch_count=None, is_template=False,
Simran Basi7e605742013-11-12 13:43:36 -0800553 timeout=None, timeout_mins=None, max_runtime_mins=None,
554 run_verify=False, email_list='', dependencies=(),
555 reboot_before=None, reboot_after=None, parse_failed_repair=None,
556 hostless=False, keyvals=None, drone_set=None, image=None,
Jiaxi Luo90190c92014-06-18 12:35:57 -0700557 parent_job_id=None, test_retry=0, run_reset=True, args=(),
558 **kwargs):
jadmanski0afbb632008-06-06 21:10:57 +0000559 """\
560 Create and enqueue a job.
mblighe8819cd2008-02-15 16:48:40 +0000561
showarda1e74b32009-05-12 17:32:04 +0000562 @param name name of this job
Alex Miller7d658cf2013-09-04 16:00:35 -0700563 @param priority Integer priority of this job. Higher is more important.
showarda1e74b32009-05-12 17:32:04 +0000564 @param control_file String contents of the control file.
565 @param control_type Type of control file, Client or Server.
566 @param synch_count How many machines the job uses per autoserv execution.
Jiaxi Luo90190c92014-06-18 12:35:57 -0700567 synch_count == 1 means the job is asynchronous. If an atomic group is
568 given this value is treated as a minimum.
showarda1e74b32009-05-12 17:32:04 +0000569 @param is_template If true then create a template job.
570 @param timeout Hours after this call returns until the job times out.
Simran Basi7e605742013-11-12 13:43:36 -0800571 @param timeout_mins Minutes after this call returns until the job times
Jiaxi Luo90190c92014-06-18 12:35:57 -0700572 out.
Simran Basi34217022012-11-06 13:43:15 -0800573 @param max_runtime_mins Minutes from job starting time until job times out
showarda1e74b32009-05-12 17:32:04 +0000574 @param run_verify Should the host be verified before running the test?
575 @param email_list String containing emails to mail when the job is done
576 @param dependencies List of label names on which this job depends
577 @param reboot_before Never, If dirty, or Always
578 @param reboot_after Never, If all tests passed, or Always
579 @param parse_failed_repair if true, results of failed repairs launched by
Jiaxi Luo90190c92014-06-18 12:35:57 -0700580 this job will be parsed as part of the job.
showarda9545c02009-12-18 22:44:26 +0000581 @param hostless if true, create a hostless job
showardc1a98d12010-01-15 00:22:22 +0000582 @param keyvals dict of keyvals to associate with the job
showarda1e74b32009-05-12 17:32:04 +0000583 @param hosts List of hosts to run job on.
584 @param meta_hosts List where each entry is a label name, and for each entry
Jiaxi Luo90190c92014-06-18 12:35:57 -0700585 one host will be chosen from that label to run the job on.
showarda1e74b32009-05-12 17:32:04 +0000586 @param one_time_hosts List of hosts not in the database to run the job on.
587 @param atomic_group_name The name of an atomic group to schedule the job on.
jamesren76fcf192010-04-21 20:39:50 +0000588 @param drone_set The name of the drone set to run this test on.
Paul Pendlebury5a8c6ad2011-02-01 07:20:17 -0800589 @param image OS image to install before running job.
Aviv Keshet0b9cfc92013-02-05 11:36:02 -0800590 @param parent_job_id id of a job considered to be parent of created job.
Simran Basib6ec8ae2014-04-23 12:05:08 -0700591 @param test_retry Number of times to retry test if the test did not
Jiaxi Luo90190c92014-06-18 12:35:57 -0700592 complete successfully. (optional, default: 0)
Simran Basib6ec8ae2014-04-23 12:05:08 -0700593 @param run_reset Should the host be reset before running the test?
Jiaxi Luo90190c92014-06-18 12:35:57 -0700594 @param args A list of args to be injected into control file.
Simran Basib6ec8ae2014-04-23 12:05:08 -0700595 @param kwargs extra keyword args. NOT USED.
showardc92da832009-04-07 18:14:34 +0000596
597 @returns The created Job id number.
jadmanski0afbb632008-06-06 21:10:57 +0000598 """
Jiaxi Luo90190c92014-06-18 12:35:57 -0700599 if args:
600 control_file = tools.inject_vars({'args': args}, control_file)
601
Simran Basiab5a1bf2014-05-28 15:39:44 -0700602 if image is None:
603 return rpc_utils.create_job_common(
604 **rpc_utils.get_create_job_common_args(locals()))
605
606 # When image is supplied use a known parameterized test already in the
607 # database to pass the OS image path from the front end, through the
608 # scheduler, and finally to autoserv as the --image parameter.
609
610 # The test autoupdate_ParameterizedJob is in afe_autotests and used to
611 # instantiate a Test object and from there a ParameterizedJob.
612 known_test_obj = models.Test.smart_get('autoupdate_ParameterizedJob')
613 known_parameterized_job = models.ParameterizedJob.objects.create(
614 test=known_test_obj)
615
616 # autoupdate_ParameterizedJob has a single parameter, the image parameter,
617 # stored in the table afe_test_parameters. We retrieve and set this
618 # instance of the parameter to the OS image path.
619 image_parameter = known_test_obj.testparameter_set.get(test=known_test_obj,
620 name='image')
621 known_parameterized_job.parameterizedjobparameter_set.create(
622 test_parameter=image_parameter, parameter_value=image,
623 parameter_type='string')
624
625 # By passing a parameterized_job to create_job_common the job entry in
626 # the afe_jobs table will have the field parameterized_job_id set.
627 # The scheduler uses this id in the afe_parameterized_jobs table to
628 # match this job to our known test, and then with the
629 # afe_parameterized_job_parameters table to get the actual image path.
jamesren4a41e012010-07-16 22:33:48 +0000630 return rpc_utils.create_job_common(
Simran Basiab5a1bf2014-05-28 15:39:44 -0700631 parameterized_job=known_parameterized_job.id,
jamesren4a41e012010-07-16 22:33:48 +0000632 **rpc_utils.get_create_job_common_args(locals()))
mblighe8819cd2008-02-15 16:48:40 +0000633
634
showard9dbdcda2008-10-14 17:34:36 +0000635def abort_host_queue_entries(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000636 """\
showard9dbdcda2008-10-14 17:34:36 +0000637 Abort a set of host queue entries.
jadmanski0afbb632008-06-06 21:10:57 +0000638 """
showard9dbdcda2008-10-14 17:34:36 +0000639 query = models.HostQueueEntry.query_objects(filter_data)
beepsfaecbce2013-10-29 11:35:10 -0700640
641 # Dont allow aborts on:
642 # 1. Jobs that have already completed (whether or not they were aborted)
643 # 2. Jobs that we have already been aborted (but may not have completed)
644 query = query.filter(complete=False).filter(aborted=False)
showarddc817512008-11-12 18:16:41 +0000645 models.AclGroup.check_abort_permissions(query)
showard9dbdcda2008-10-14 17:34:36 +0000646 host_queue_entries = list(query.select_related())
showard2bab8f42008-11-12 18:15:22 +0000647 rpc_utils.check_abort_synchronous_jobs(host_queue_entries)
mblighe8819cd2008-02-15 16:48:40 +0000648
Simran Basic1b26762013-06-26 14:23:21 -0700649 models.HostQueueEntry.abort_host_queue_entries(host_queue_entries)
showard9d821ab2008-07-11 16:54:29 +0000650
651
beeps8bb1f7d2013-08-05 01:30:09 -0700652def abort_special_tasks(**filter_data):
653 """\
654 Abort the special task, or tasks, specified in the filter.
655 """
656 query = models.SpecialTask.query_objects(filter_data)
657 special_tasks = query.filter(is_active=True)
658 for task in special_tasks:
659 task.abort()
660
661
Simran Basi73dae552013-02-25 14:57:46 -0800662def _call_special_tasks_on_hosts(task, hosts):
663 """\
664 Schedules a set of hosts for a special task.
665
666 @returns A list of hostnames that a special task was created for.
667 """
668 models.AclGroup.check_for_acl_violation_hosts(hosts)
669 for host in hosts:
670 models.SpecialTask.schedule_special_task(host, task)
671 return list(sorted(host.hostname for host in hosts))
672
673
showard1ff7b2e2009-05-15 23:17:18 +0000674def reverify_hosts(**filter_data):
675 """\
676 Schedules a set of hosts for verify.
mbligh4e545a52009-12-19 05:30:39 +0000677
678 @returns A list of hostnames that a verify task was created for.
showard1ff7b2e2009-05-15 23:17:18 +0000679 """
Simran Basi73dae552013-02-25 14:57:46 -0800680 return _call_special_tasks_on_hosts(models.SpecialTask.Task.VERIFY,
681 models.Host.query_objects(filter_data))
682
683
684def repair_hosts(**filter_data):
685 """\
686 Schedules a set of hosts for repair.
687
688 @returns A list of hostnames that a repair task was created for.
689 """
690 return _call_special_tasks_on_hosts(models.SpecialTask.Task.REPAIR,
691 models.Host.query_objects(filter_data))
showard1ff7b2e2009-05-15 23:17:18 +0000692
693
Jiaxi Luo15cbf372014-07-01 19:20:20 -0700694def get_jobs(not_yet_run=False, running=False, finished=False,
695 suite=False, sub=False, standalone=False, **filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000696 """\
Jiaxi Luo15cbf372014-07-01 19:20:20 -0700697 Extra status filter args for get_jobs:
jadmanski0afbb632008-06-06 21:10:57 +0000698 -not_yet_run: Include only jobs that have not yet started running.
699 -running: Include only jobs that have start running but for which not
700 all hosts have completed.
701 -finished: Include only jobs for which all hosts have completed (or
702 aborted).
703 At most one of these three fields should be specified.
Jiaxi Luo15cbf372014-07-01 19:20:20 -0700704
705 Extra type filter args for get_jobs:
706 -suite: Include only jobs with child jobs.
707 -sub: Include only jobs with a parent job.
708 -standalone: Inlcude only jobs with no child or parent jobs.
709 At most one of these three fields should be specified.
jadmanski0afbb632008-06-06 21:10:57 +0000710 """
Jiaxi Luo15cbf372014-07-01 19:20:20 -0700711 extra_args = rpc_utils.extra_job_status_filters(not_yet_run,
712 running,
713 finished)
714 filter_data['extra_args'] = rpc_utils.extra_job_type_filters(extra_args,
715 suite,
716 sub,
717 standalone)
showard0957a842009-05-11 19:25:08 +0000718 job_dicts = []
719 jobs = list(models.Job.query_objects(filter_data))
720 models.Job.objects.populate_relationships(jobs, models.Label,
721 'dependencies')
showardc1a98d12010-01-15 00:22:22 +0000722 models.Job.objects.populate_relationships(jobs, models.JobKeyval, 'keyvals')
showard0957a842009-05-11 19:25:08 +0000723 for job in jobs:
724 job_dict = job.get_object_dict()
725 job_dict['dependencies'] = ','.join(label.name
726 for label in job.dependencies)
showardc1a98d12010-01-15 00:22:22 +0000727 job_dict['keyvals'] = dict((keyval.key, keyval.value)
728 for keyval in job.keyvals)
Eric Lid23bc192011-02-09 14:38:57 -0800729 if job.parameterized_job:
730 job_dict['image'] = get_parameterized_autoupdate_image_url(job)
showard0957a842009-05-11 19:25:08 +0000731 job_dicts.append(job_dict)
732 return rpc_utils.prepare_for_serialization(job_dicts)
mblighe8819cd2008-02-15 16:48:40 +0000733
734
735def get_num_jobs(not_yet_run=False, running=False, finished=False,
Jiaxi Luo15cbf372014-07-01 19:20:20 -0700736 suite=False, sub=False, standalone=False,
jadmanski0afbb632008-06-06 21:10:57 +0000737 **filter_data):
738 """\
739 See get_jobs() for documentation of extra filter parameters.
740 """
Jiaxi Luo15cbf372014-07-01 19:20:20 -0700741 extra_args = rpc_utils.extra_job_status_filters(not_yet_run,
742 running,
743 finished)
744 filter_data['extra_args'] = rpc_utils.extra_job_type_filters(extra_args,
745 suite,
746 sub,
747 standalone)
jadmanski0afbb632008-06-06 21:10:57 +0000748 return models.Job.query_count(filter_data)
mblighe8819cd2008-02-15 16:48:40 +0000749
750
mblighe8819cd2008-02-15 16:48:40 +0000751def get_jobs_summary(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000752 """\
Jiaxi Luoaac54572014-06-04 13:57:02 -0700753 Like get_jobs(), but adds 'status_counts' and 'result_counts' field.
754
755 'status_counts' filed is a dictionary mapping status strings to the number
756 of hosts currently with that status, i.e. {'Queued' : 4, 'Running' : 2}.
757
758 'result_counts' field is piped to tko's rpc_interface and has the return
759 format specified under get_group_counts.
jadmanski0afbb632008-06-06 21:10:57 +0000760 """
761 jobs = get_jobs(**filter_data)
762 ids = [job['id'] for job in jobs]
763 all_status_counts = models.Job.objects.get_status_counts(ids)
764 for job in jobs:
765 job['status_counts'] = all_status_counts[job['id']]
Jiaxi Luoaac54572014-06-04 13:57:02 -0700766 job['result_counts'] = tko_rpc_interface.get_status_counts(
767 ['afe_job_id', 'afe_job_id'],
768 header_groups=[['afe_job_id'], ['afe_job_id']],
769 **{'afe_job_id': job['id']})
jadmanski0afbb632008-06-06 21:10:57 +0000770 return rpc_utils.prepare_for_serialization(jobs)
mblighe8819cd2008-02-15 16:48:40 +0000771
772
showarda965cef2009-05-15 23:17:41 +0000773def get_info_for_clone(id, preserve_metahosts, queue_entry_filter_data=None):
showarda8709c52008-07-03 19:44:54 +0000774 """\
775 Retrieves all the information needed to clone a job.
776 """
showarda8709c52008-07-03 19:44:54 +0000777 job = models.Job.objects.get(id=id)
showard29f7cd22009-04-29 21:16:24 +0000778 job_info = rpc_utils.get_job_info(job,
showarda965cef2009-05-15 23:17:41 +0000779 preserve_metahosts,
780 queue_entry_filter_data)
showard945072f2008-09-03 20:34:59 +0000781
showardd9992fe2008-07-31 02:15:03 +0000782 host_dicts = []
showard29f7cd22009-04-29 21:16:24 +0000783 for host in job_info['hosts']:
784 host_dict = get_hosts(id=host.id)[0]
785 other_labels = host_dict['labels']
786 if host_dict['platform']:
787 other_labels.remove(host_dict['platform'])
788 host_dict['other_labels'] = ', '.join(other_labels)
showardd9992fe2008-07-31 02:15:03 +0000789 host_dicts.append(host_dict)
showarda8709c52008-07-03 19:44:54 +0000790
showard29f7cd22009-04-29 21:16:24 +0000791 for host in job_info['one_time_hosts']:
792 host_dict = dict(hostname=host.hostname,
793 id=host.id,
794 platform='(one-time host)',
795 locked_text='')
796 host_dicts.append(host_dict)
showarda8709c52008-07-03 19:44:54 +0000797
showard4d077562009-05-08 18:24:36 +0000798 # convert keys from Label objects to strings (names of labels)
showard29f7cd22009-04-29 21:16:24 +0000799 meta_host_counts = dict((meta_host.name, count) for meta_host, count
showard4d077562009-05-08 18:24:36 +0000800 in job_info['meta_host_counts'].iteritems())
showard29f7cd22009-04-29 21:16:24 +0000801
802 info = dict(job=job.get_object_dict(),
803 meta_host_counts=meta_host_counts,
804 hosts=host_dicts)
805 info['job']['dependencies'] = job_info['dependencies']
806 if job_info['atomic_group']:
807 info['atomic_group_name'] = (job_info['atomic_group']).name
808 else:
809 info['atomic_group_name'] = None
jamesren2275ef12010-04-12 18:25:06 +0000810 info['hostless'] = job_info['hostless']
jamesren76fcf192010-04-21 20:39:50 +0000811 info['drone_set'] = job.drone_set and job.drone_set.name
showarda8709c52008-07-03 19:44:54 +0000812
Eric Lid23bc192011-02-09 14:38:57 -0800813 if job.parameterized_job:
814 info['job']['image'] = get_parameterized_autoupdate_image_url(job)
815
showarda8709c52008-07-03 19:44:54 +0000816 return rpc_utils.prepare_for_serialization(info)
817
818
showard34dc5fa2008-04-24 20:58:40 +0000819# host queue entries
820
Jiaxi Luo57bc1952014-07-22 15:27:30 -0700821def get_host_queue_entries(start_time=None, end_time=None, **filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000822 """\
showardc92da832009-04-07 18:14:34 +0000823 @returns A sequence of nested dictionaries of host and job information.
jadmanski0afbb632008-06-06 21:10:57 +0000824 """
Jiaxi Luo57bc1952014-07-22 15:27:30 -0700825 filter_data = rpc_utils.inject_times_to_filter('started_on__gte',
826 'started_on__lte',
827 start_time,
828 end_time,
829 **filter_data)
showardc92da832009-04-07 18:14:34 +0000830 return rpc_utils.prepare_rows_as_nested_dicts(
831 models.HostQueueEntry.query_objects(filter_data),
832 ('host', 'atomic_group', 'job'))
showard34dc5fa2008-04-24 20:58:40 +0000833
834
Jiaxi Luo57bc1952014-07-22 15:27:30 -0700835def get_num_host_queue_entries(start_time=None, end_time=None, **filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000836 """\
837 Get the number of host queue entries associated with this job.
838 """
Jiaxi Luo57bc1952014-07-22 15:27:30 -0700839 filter_data = rpc_utils.inject_times_to_filter('started_on__gte',
840 'started_on__lte',
841 start_time,
842 end_time,
843 **filter_data)
jadmanski0afbb632008-06-06 21:10:57 +0000844 return models.HostQueueEntry.query_count(filter_data)
showard34dc5fa2008-04-24 20:58:40 +0000845
846
showard1e935f12008-07-11 00:11:36 +0000847def get_hqe_percentage_complete(**filter_data):
848 """
showardc92da832009-04-07 18:14:34 +0000849 Computes the fraction of host queue entries matching the given filter data
showard1e935f12008-07-11 00:11:36 +0000850 that are complete.
851 """
852 query = models.HostQueueEntry.query_objects(filter_data)
853 complete_count = query.filter(complete=True).count()
854 total_count = query.count()
855 if total_count == 0:
856 return 1
857 return float(complete_count) / total_count
858
859
showard1a5a4082009-07-28 20:01:37 +0000860# special tasks
861
862def get_special_tasks(**filter_data):
863 return rpc_utils.prepare_rows_as_nested_dicts(
864 models.SpecialTask.query_objects(filter_data),
865 ('host', 'queue_entry'))
866
867
showardc0ac3a72009-07-08 21:14:45 +0000868# support for host detail view
869
Jiaxi Luo79ce6422014-06-13 17:08:09 -0700870def get_host_queue_entries_and_special_tasks(host_id, query_start=None,
Jiaxi Luo57bc1952014-07-22 15:27:30 -0700871 query_limit=None, start_time=None,
872 end_time=None):
showardc0ac3a72009-07-08 21:14:45 +0000873 """
874 @returns an interleaved list of HostQueueEntries and SpecialTasks,
875 in approximate run order. each dict contains keys for type, host,
876 job, status, started_on, execution_path, and ID.
877 """
878 total_limit = None
879 if query_limit is not None:
880 total_limit = query_start + query_limit
Jiaxi Luo57bc1952014-07-22 15:27:30 -0700881 filter_data_common = {'host': host_id,
882 'query_limit': total_limit,
883 'sort_by': ['-id']}
showardc0ac3a72009-07-08 21:14:45 +0000884
Jiaxi Luo57bc1952014-07-22 15:27:30 -0700885 filter_data_queue_entries, filter_data_special_tasks = (
886 rpc_utils.inject_times_to_hqe_special_tasks_filters(
887 filter_data_common, start_time, end_time))
888
889 queue_entries = list(models.HostQueueEntry.query_objects(
890 filter_data_queue_entries))
891 special_tasks = list(models.SpecialTask.query_objects(
892 filter_data_special_tasks))
showardc0ac3a72009-07-08 21:14:45 +0000893
894 interleaved_entries = rpc_utils.interleave_entries(queue_entries,
895 special_tasks)
896 if query_start is not None:
897 interleaved_entries = interleaved_entries[query_start:]
898 if query_limit is not None:
899 interleaved_entries = interleaved_entries[:query_limit]
900 return rpc_utils.prepare_for_serialization(interleaved_entries)
901
902
Jiaxi Luo57bc1952014-07-22 15:27:30 -0700903def get_num_host_queue_entries_and_special_tasks(host_id, start_time=None,
904 end_time=None):
905 filter_data_common = {'host': host_id}
906
907 filter_data_queue_entries, filter_data_special_tasks = (
908 rpc_utils.inject_times_to_hqe_special_tasks_filters(
909 filter_data_common, start_time, end_time))
910
911 return (models.HostQueueEntry.query_count(filter_data_queue_entries)
912 + models.SpecialTask.query_count(filter_data_special_tasks))
showardc0ac3a72009-07-08 21:14:45 +0000913
914
showard29f7cd22009-04-29 21:16:24 +0000915# recurring run
916
917def get_recurring(**filter_data):
918 return rpc_utils.prepare_rows_as_nested_dicts(
919 models.RecurringRun.query_objects(filter_data),
920 ('job', 'owner'))
921
922
923def get_num_recurring(**filter_data):
924 return models.RecurringRun.query_count(filter_data)
925
926
927def delete_recurring_runs(**filter_data):
928 to_delete = models.RecurringRun.query_objects(filter_data)
929 to_delete.delete()
930
931
932def create_recurring_run(job_id, start_date, loop_period, loop_count):
showard64a95952010-01-13 21:27:16 +0000933 owner = models.User.current_user().login
showard29f7cd22009-04-29 21:16:24 +0000934 job = models.Job.objects.get(id=job_id)
935 return job.create_recurring_job(start_date=start_date,
936 loop_period=loop_period,
937 loop_count=loop_count,
938 owner=owner)
939
940
mblighe8819cd2008-02-15 16:48:40 +0000941# other
942
showarde0b63622008-08-04 20:58:47 +0000943def echo(data=""):
944 """\
945 Returns a passed in string. For doing a basic test to see if RPC calls
946 can successfully be made.
947 """
948 return data
949
950
showardb7a52fd2009-04-27 20:10:56 +0000951def get_motd():
952 """\
953 Returns the message of the day as a string.
954 """
955 return rpc_utils.get_motd()
956
957
mblighe8819cd2008-02-15 16:48:40 +0000958def get_static_data():
jadmanski0afbb632008-06-06 21:10:57 +0000959 """\
960 Returns a dictionary containing a bunch of data that shouldn't change
961 often and is otherwise inaccessible. This includes:
showardc92da832009-04-07 18:14:34 +0000962
963 priorities: List of job priority choices.
964 default_priority: Default priority value for new jobs.
965 users: Sorted list of all users.
Jiaxi Luo31874592014-06-11 10:36:35 -0700966 labels: Sorted list of labels not start with 'cros-version' and
967 'fw-version'.
showardc92da832009-04-07 18:14:34 +0000968 atomic_groups: Sorted list of all atomic groups.
969 tests: Sorted list of all tests.
970 profilers: Sorted list of all profilers.
971 current_user: Logged-in username.
972 host_statuses: Sorted list of possible Host statuses.
973 job_statuses: Sorted list of possible HostQueueEntry statuses.
Simran Basi7e605742013-11-12 13:43:36 -0800974 job_timeout_default: The default job timeout length in minutes.
showarda1e74b32009-05-12 17:32:04 +0000975 parse_failed_repair_default: Default value for the parse_failed_repair job
Jiaxi Luo31874592014-06-11 10:36:35 -0700976 option.
showardc92da832009-04-07 18:14:34 +0000977 reboot_before_options: A list of valid RebootBefore string enums.
978 reboot_after_options: A list of valid RebootAfter string enums.
979 motd: Server's message of the day.
980 status_dictionary: A mapping from one word job status names to a more
981 informative description.
jadmanski0afbb632008-06-06 21:10:57 +0000982 """
showard21baa452008-10-21 00:08:39 +0000983
984 job_fields = models.Job.get_field_dict()
jamesren76fcf192010-04-21 20:39:50 +0000985 default_drone_set_name = models.DroneSet.default_drone_set_name()
986 drone_sets = ([default_drone_set_name] +
987 sorted(drone_set.name for drone_set in
988 models.DroneSet.objects.exclude(
989 name=default_drone_set_name)))
showard21baa452008-10-21 00:08:39 +0000990
jadmanski0afbb632008-06-06 21:10:57 +0000991 result = {}
Alex Miller7d658cf2013-09-04 16:00:35 -0700992 result['priorities'] = priorities.Priority.choices()
993 default_priority = priorities.Priority.DEFAULT
994 result['default_priority'] = 'Default'
995 result['max_schedulable_priority'] = priorities.Priority.DEFAULT
jadmanski0afbb632008-06-06 21:10:57 +0000996 result['users'] = get_users(sort_by=['login'])
Jiaxi Luo31874592014-06-11 10:36:35 -0700997
998 label_exclude_filters = [{'name__startswith': 'cros-version'},
999 {'name__startswith': 'fw-version'}]
1000 result['labels'] = get_labels(
1001 label_exclude_filters,
1002 sort_by=['-platform', 'name'])
1003
showardc92da832009-04-07 18:14:34 +00001004 result['atomic_groups'] = get_atomic_groups(sort_by=['name'])
jadmanski0afbb632008-06-06 21:10:57 +00001005 result['tests'] = get_tests(sort_by=['name'])
showard2b9a88b2008-06-13 20:55:03 +00001006 result['profilers'] = get_profilers(sort_by=['name'])
showard0fc38302008-10-23 00:44:07 +00001007 result['current_user'] = rpc_utils.prepare_for_serialization(
showard64a95952010-01-13 21:27:16 +00001008 models.User.current_user().get_object_dict())
showard2b9a88b2008-06-13 20:55:03 +00001009 result['host_statuses'] = sorted(models.Host.Status.names)
mbligh5a198b92008-12-11 19:33:29 +00001010 result['job_statuses'] = sorted(models.HostQueueEntry.Status.names)
Simran Basi7e605742013-11-12 13:43:36 -08001011 result['job_timeout_mins_default'] = models.Job.DEFAULT_TIMEOUT_MINS
Simran Basi34217022012-11-06 13:43:15 -08001012 result['job_max_runtime_mins_default'] = (
1013 models.Job.DEFAULT_MAX_RUNTIME_MINS)
showarda1e74b32009-05-12 17:32:04 +00001014 result['parse_failed_repair_default'] = bool(
1015 models.Job.DEFAULT_PARSE_FAILED_REPAIR)
jamesrendd855242010-03-02 22:23:44 +00001016 result['reboot_before_options'] = model_attributes.RebootBefore.names
1017 result['reboot_after_options'] = model_attributes.RebootAfter.names
showard8fbae652009-01-20 23:23:10 +00001018 result['motd'] = rpc_utils.get_motd()
jamesren76fcf192010-04-21 20:39:50 +00001019 result['drone_sets_enabled'] = models.DroneSet.drone_sets_enabled()
1020 result['drone_sets'] = drone_sets
jamesren4a41e012010-07-16 22:33:48 +00001021 result['parameterized_jobs'] = models.Job.parameterized_jobs_enabled()
showard8ac29b42008-07-17 17:01:55 +00001022
showardd3dc1992009-04-22 21:01:40 +00001023 result['status_dictionary'] = {"Aborted": "Aborted",
showard8ac29b42008-07-17 17:01:55 +00001024 "Verifying": "Verifying Host",
Alex Millerdfff2fd2013-05-28 13:05:06 -07001025 "Provisioning": "Provisioning Host",
showard8ac29b42008-07-17 17:01:55 +00001026 "Pending": "Waiting on other hosts",
1027 "Running": "Running autoserv",
1028 "Completed": "Autoserv completed",
1029 "Failed": "Failed to complete",
showardd823b362008-07-24 16:35:46 +00001030 "Queued": "Queued",
showard5deb6772008-11-04 21:54:33 +00001031 "Starting": "Next in host's queue",
1032 "Stopped": "Other host(s) failed verify",
showardd3dc1992009-04-22 21:01:40 +00001033 "Parsing": "Awaiting parse of final results",
showard29f7cd22009-04-29 21:16:24 +00001034 "Gathering": "Gathering log files",
showard8cc058f2009-09-08 16:26:33 +00001035 "Template": "Template job for recurring run",
mbligh4608b002010-01-05 18:22:35 +00001036 "Waiting": "Waiting for scheduler action",
Dan Shi07e09af2013-04-12 09:31:29 -07001037 "Archiving": "Archiving results",
1038 "Resetting": "Resetting hosts"}
Jiaxi Luo421608e2014-07-07 14:38:00 -07001039
1040 result['wmatrix_url'] = rpc_utils.get_wmatrix_url()
Simran Basi71206ef2014-08-13 13:51:18 -07001041 result['is_moblab'] = bool(utils.is_moblab())
Jiaxi Luo421608e2014-07-07 14:38:00 -07001042
jadmanski0afbb632008-06-06 21:10:57 +00001043 return result
showard29f7cd22009-04-29 21:16:24 +00001044
1045
1046def get_server_time():
1047 return datetime.datetime.now().strftime("%Y-%m-%d %H:%M")