blob: cfd861d086682ede379cea70d6032c51de198922 [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
showard0957a842009-05-11 19:25:08 +0000173def set_host_attribute(attribute, value, **host_filter_data):
174 """
175 @param attribute string name of attribute
176 @param value string, or None to delete an attribute
177 @param host_filter_data filter data to apply to Hosts to choose hosts to act
178 upon
179 """
180 assert host_filter_data # disallow accidental actions on all hosts
181 hosts = models.Host.query_objects(host_filter_data)
182 models.AclGroup.check_for_acl_violation_hosts(hosts)
183
184 for host in hosts:
showardf8b19042009-05-12 17:22:49 +0000185 host.set_or_delete_attribute(attribute, value)
showard0957a842009-05-11 19:25:08 +0000186
187
mblighe8819cd2008-02-15 16:48:40 +0000188def delete_host(id):
jadmanski0afbb632008-06-06 21:10:57 +0000189 models.Host.smart_get(id).delete()
mblighe8819cd2008-02-15 16:48:40 +0000190
191
showard87cc38f2009-08-20 23:37:04 +0000192def get_hosts(multiple_labels=(), exclude_only_if_needed_labels=False,
showard8aa84fc2009-09-16 17:17:55 +0000193 exclude_atomic_group_hosts=False, valid_only=True, **filter_data):
showard87cc38f2009-08-20 23:37:04 +0000194 """
195 @param multiple_labels: match hosts in all of the labels given. Should
196 be a list of label names.
197 @param exclude_only_if_needed_labels: Exclude hosts with at least one
198 "only_if_needed" label applied.
199 @param exclude_atomic_group_hosts: Exclude hosts that have one or more
200 atomic group labels associated with them.
jadmanski0afbb632008-06-06 21:10:57 +0000201 """
showard43a3d262008-11-12 18:17:05 +0000202 hosts = rpc_utils.get_host_query(multiple_labels,
203 exclude_only_if_needed_labels,
showard87cc38f2009-08-20 23:37:04 +0000204 exclude_atomic_group_hosts,
showard8aa84fc2009-09-16 17:17:55 +0000205 valid_only, filter_data)
showard0957a842009-05-11 19:25:08 +0000206 hosts = list(hosts)
207 models.Host.objects.populate_relationships(hosts, models.Label,
208 'label_list')
209 models.Host.objects.populate_relationships(hosts, models.AclGroup,
210 'acl_list')
211 models.Host.objects.populate_relationships(hosts, models.HostAttribute,
212 'attribute_list')
showard43a3d262008-11-12 18:17:05 +0000213 host_dicts = []
214 for host_obj in hosts:
215 host_dict = host_obj.get_object_dict()
showard0957a842009-05-11 19:25:08 +0000216 host_dict['labels'] = [label.name for label in host_obj.label_list]
showard909c9142009-07-07 20:54:42 +0000217 host_dict['platform'], host_dict['atomic_group'] = (rpc_utils.
218 find_platform_and_atomic_group(host_obj))
showard0957a842009-05-11 19:25:08 +0000219 host_dict['acls'] = [acl.name for acl in host_obj.acl_list]
220 host_dict['attributes'] = dict((attribute.attribute, attribute.value)
221 for attribute in host_obj.attribute_list)
showard43a3d262008-11-12 18:17:05 +0000222 host_dicts.append(host_dict)
223 return rpc_utils.prepare_for_serialization(host_dicts)
mblighe8819cd2008-02-15 16:48:40 +0000224
225
showard87cc38f2009-08-20 23:37:04 +0000226def get_num_hosts(multiple_labels=(), exclude_only_if_needed_labels=False,
showard8aa84fc2009-09-16 17:17:55 +0000227 exclude_atomic_group_hosts=False, valid_only=True,
228 **filter_data):
showard87cc38f2009-08-20 23:37:04 +0000229 """
230 Same parameters as get_hosts().
231
232 @returns The number of matching hosts.
233 """
showard43a3d262008-11-12 18:17:05 +0000234 hosts = rpc_utils.get_host_query(multiple_labels,
235 exclude_only_if_needed_labels,
showard87cc38f2009-08-20 23:37:04 +0000236 exclude_atomic_group_hosts,
showard8aa84fc2009-09-16 17:17:55 +0000237 valid_only, filter_data)
showard43a3d262008-11-12 18:17:05 +0000238 return hosts.count()
showard1385b162008-03-13 15:59:40 +0000239
mblighe8819cd2008-02-15 16:48:40 +0000240
241# tests
242
showard909c7a62008-07-15 21:52:38 +0000243def add_test(name, test_type, path, author=None, dependencies=None,
showard3d9899a2008-07-31 02:11:58 +0000244 experimental=True, run_verify=None, test_class=None,
showard909c7a62008-07-15 21:52:38 +0000245 test_time=None, test_category=None, description=None,
246 sync_count=1):
jadmanski0afbb632008-06-06 21:10:57 +0000247 return models.Test.add_object(name=name, test_type=test_type, path=path,
showard909c7a62008-07-15 21:52:38 +0000248 author=author, dependencies=dependencies,
249 experimental=experimental,
250 run_verify=run_verify, test_time=test_time,
251 test_category=test_category,
252 sync_count=sync_count,
jadmanski0afbb632008-06-06 21:10:57 +0000253 test_class=test_class,
254 description=description).id
mblighe8819cd2008-02-15 16:48:40 +0000255
256
257def modify_test(id, **data):
jadmanski0afbb632008-06-06 21:10:57 +0000258 models.Test.smart_get(id).update_object(data)
mblighe8819cd2008-02-15 16:48:40 +0000259
260
261def delete_test(id):
jadmanski0afbb632008-06-06 21:10:57 +0000262 models.Test.smart_get(id).delete()
mblighe8819cd2008-02-15 16:48:40 +0000263
264
265def get_tests(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000266 return rpc_utils.prepare_for_serialization(
267 models.Test.list_objects(filter_data))
mblighe8819cd2008-02-15 16:48:40 +0000268
269
showard2b9a88b2008-06-13 20:55:03 +0000270# profilers
271
272def add_profiler(name, description=None):
273 return models.Profiler.add_object(name=name, description=description).id
274
275
276def modify_profiler(id, **data):
277 models.Profiler.smart_get(id).update_object(data)
278
279
280def delete_profiler(id):
281 models.Profiler.smart_get(id).delete()
282
283
284def get_profilers(**filter_data):
285 return rpc_utils.prepare_for_serialization(
286 models.Profiler.list_objects(filter_data))
287
288
mblighe8819cd2008-02-15 16:48:40 +0000289# users
290
291def add_user(login, access_level=None):
jadmanski0afbb632008-06-06 21:10:57 +0000292 return models.User.add_object(login=login, access_level=access_level).id
mblighe8819cd2008-02-15 16:48:40 +0000293
294
295def modify_user(id, **data):
jadmanski0afbb632008-06-06 21:10:57 +0000296 models.User.smart_get(id).update_object(data)
mblighe8819cd2008-02-15 16:48:40 +0000297
298
299def delete_user(id):
jadmanski0afbb632008-06-06 21:10:57 +0000300 models.User.smart_get(id).delete()
mblighe8819cd2008-02-15 16:48:40 +0000301
302
303def get_users(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000304 return rpc_utils.prepare_for_serialization(
305 models.User.list_objects(filter_data))
mblighe8819cd2008-02-15 16:48:40 +0000306
307
308# acl groups
309
310def add_acl_group(name, description=None):
showard04f2cd82008-07-25 20:53:31 +0000311 group = models.AclGroup.add_object(name=name, description=description)
showard64a95952010-01-13 21:27:16 +0000312 group.users.add(models.User.current_user())
showard04f2cd82008-07-25 20:53:31 +0000313 return group.id
mblighe8819cd2008-02-15 16:48:40 +0000314
315
316def modify_acl_group(id, **data):
showard04f2cd82008-07-25 20:53:31 +0000317 group = models.AclGroup.smart_get(id)
318 group.check_for_acl_violation_acl_group()
319 group.update_object(data)
320 group.add_current_user_if_empty()
mblighe8819cd2008-02-15 16:48:40 +0000321
322
323def acl_group_add_users(id, users):
jadmanski0afbb632008-06-06 21:10:57 +0000324 group = models.AclGroup.smart_get(id)
showard04f2cd82008-07-25 20:53:31 +0000325 group.check_for_acl_violation_acl_group()
showardbe3ec042008-11-12 18:16:07 +0000326 users = models.User.smart_get_bulk(users)
jadmanski0afbb632008-06-06 21:10:57 +0000327 group.users.add(*users)
mblighe8819cd2008-02-15 16:48:40 +0000328
329
330def acl_group_remove_users(id, users):
jadmanski0afbb632008-06-06 21:10:57 +0000331 group = models.AclGroup.smart_get(id)
showard04f2cd82008-07-25 20:53:31 +0000332 group.check_for_acl_violation_acl_group()
showardbe3ec042008-11-12 18:16:07 +0000333 users = models.User.smart_get_bulk(users)
jadmanski0afbb632008-06-06 21:10:57 +0000334 group.users.remove(*users)
showard04f2cd82008-07-25 20:53:31 +0000335 group.add_current_user_if_empty()
mblighe8819cd2008-02-15 16:48:40 +0000336
337
338def acl_group_add_hosts(id, hosts):
jadmanski0afbb632008-06-06 21:10:57 +0000339 group = models.AclGroup.smart_get(id)
showard04f2cd82008-07-25 20:53:31 +0000340 group.check_for_acl_violation_acl_group()
showardbe3ec042008-11-12 18:16:07 +0000341 hosts = models.Host.smart_get_bulk(hosts)
jadmanski0afbb632008-06-06 21:10:57 +0000342 group.hosts.add(*hosts)
showard08f981b2008-06-24 21:59:03 +0000343 group.on_host_membership_change()
mblighe8819cd2008-02-15 16:48:40 +0000344
345
346def acl_group_remove_hosts(id, hosts):
jadmanski0afbb632008-06-06 21:10:57 +0000347 group = models.AclGroup.smart_get(id)
showard04f2cd82008-07-25 20:53:31 +0000348 group.check_for_acl_violation_acl_group()
showardbe3ec042008-11-12 18:16:07 +0000349 hosts = models.Host.smart_get_bulk(hosts)
jadmanski0afbb632008-06-06 21:10:57 +0000350 group.hosts.remove(*hosts)
showard08f981b2008-06-24 21:59:03 +0000351 group.on_host_membership_change()
mblighe8819cd2008-02-15 16:48:40 +0000352
353
354def delete_acl_group(id):
jadmanski0afbb632008-06-06 21:10:57 +0000355 models.AclGroup.smart_get(id).delete()
mblighe8819cd2008-02-15 16:48:40 +0000356
357
358def get_acl_groups(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000359 acl_groups = models.AclGroup.list_objects(filter_data)
360 for acl_group in acl_groups:
361 acl_group_obj = models.AclGroup.objects.get(id=acl_group['id'])
362 acl_group['users'] = [user.login
363 for user in acl_group_obj.users.all()]
364 acl_group['hosts'] = [host.hostname
365 for host in acl_group_obj.hosts.all()]
366 return rpc_utils.prepare_for_serialization(acl_groups)
mblighe8819cd2008-02-15 16:48:40 +0000367
368
369# jobs
370
mbligh120351e2009-01-24 01:40:45 +0000371def generate_control_file(tests=(), kernel=None, label=None, profilers=(),
showard91f85102009-10-12 20:34:52 +0000372 client_control_file='', use_container=False,
showard232b7ae2009-11-10 00:46:48 +0000373 profile_only=None, upload_kernel_config=False):
jadmanski0afbb632008-06-06 21:10:57 +0000374 """
mbligh120351e2009-01-24 01:40:45 +0000375 Generates a client-side control file to load a kernel and run tests.
376
377 @param tests List of tests to run.
mbligha3c58d22009-08-24 22:01:51 +0000378 @param kernel A list of kernel info dictionaries configuring which kernels
379 to boot for this job and other options for them
mbligh120351e2009-01-24 01:40:45 +0000380 @param label Name of label to grab kernel config from.
381 @param profilers List of profilers to activate during the job.
382 @param client_control_file The contents of a client-side control file to
383 run at the end of all tests. If this is supplied, all tests must be
384 client side.
385 TODO: in the future we should support server control files directly
386 to wrap with a kernel. That'll require changing the parameter
387 name and adding a boolean to indicate if it is a client or server
388 control file.
389 @param use_container unused argument today. TODO: Enable containers
390 on the host during a client side test.
showard91f85102009-10-12 20:34:52 +0000391 @param profile_only A boolean that indicates what default profile_only
392 mode to use in the control file. Passing None will generate a
393 control file that does not explcitly set the default mode at all.
showard232b7ae2009-11-10 00:46:48 +0000394 @param upload_kernel_config: if enabled it will generate server control
395 file code that uploads the kernel config file to the client and
396 tells the client of the new (local) path when compiling the kernel;
397 the tests must be server side tests
mbligh120351e2009-01-24 01:40:45 +0000398
399 @returns a dict with the following keys:
400 control_file: str, The control file text.
401 is_server: bool, is the control file a server-side control file?
402 synch_count: How many machines the job uses per autoserv execution.
403 synch_count == 1 means the job is asynchronous.
404 dependencies: A list of the names of labels on which the job depends.
405 """
showardd86debe2009-06-10 17:37:56 +0000406 if not tests and not client_control_file:
showard2bab8f42008-11-12 18:15:22 +0000407 return dict(control_file='', is_server=False, synch_count=1,
showard989f25d2008-10-01 11:38:11 +0000408 dependencies=[])
mblighe8819cd2008-02-15 16:48:40 +0000409
showard989f25d2008-10-01 11:38:11 +0000410 cf_info, test_objects, profiler_objects, label = (
showard2b9a88b2008-06-13 20:55:03 +0000411 rpc_utils.prepare_generate_control_file(tests, kernel, label,
412 profilers))
showard989f25d2008-10-01 11:38:11 +0000413 cf_info['control_file'] = control_file.generate_control(
mbligha3c58d22009-08-24 22:01:51 +0000414 tests=test_objects, kernels=kernel, platform=label,
mbligh120351e2009-01-24 01:40:45 +0000415 profilers=profiler_objects, is_server=cf_info['is_server'],
showard232b7ae2009-11-10 00:46:48 +0000416 client_control_file=client_control_file, profile_only=profile_only,
417 upload_kernel_config=upload_kernel_config)
showard989f25d2008-10-01 11:38:11 +0000418 return cf_info
mblighe8819cd2008-02-15 16:48:40 +0000419
420
jamesren4a41e012010-07-16 22:33:48 +0000421def create_parameterized_job(name, priority, test, parameters, kernel=None,
422 label=None, profilers=(), profiler_parameters=None,
423 use_container=False, profile_only=None,
424 upload_kernel_config=False, hosts=(),
425 meta_hosts=(), one_time_hosts=(),
426 atomic_group_name=None, synch_count=None,
427 is_template=False, timeout=None,
Simran Basi7e605742013-11-12 13:43:36 -0800428 timeout_mins=None, max_runtime_mins=None,
429 run_verify=False, email_list='', dependencies=(),
430 reboot_before=None, reboot_after=None,
431 parse_failed_repair=None, hostless=False,
432 keyvals=None, drone_set=None, run_reset=True):
jamesren4a41e012010-07-16 22:33:48 +0000433 """
434 Creates and enqueues a parameterized job.
435
436 Most parameters a combination of the parameters for generate_control_file()
437 and create_job(), with the exception of:
438
439 @param test name or ID of the test to run
440 @param parameters a map of parameter name ->
441 tuple of (param value, param type)
442 @param profiler_parameters a dictionary of parameters for the profilers:
443 key: profiler name
444 value: dict of param name -> tuple of
445 (param value,
446 param type)
447 """
448 # Save the values of the passed arguments here. What we're going to do with
449 # them is pass them all to rpc_utils.get_create_job_common_args(), which
450 # will extract the subset of these arguments that apply for
451 # rpc_utils.create_job_common(), which we then pass in to that function.
452 args = locals()
453
454 # Set up the parameterized job configs
455 test_obj = models.Test.smart_get(test)
Aviv Keshet3dd8beb2013-05-13 17:36:04 -0700456 control_type = test_obj.test_type
jamesren4a41e012010-07-16 22:33:48 +0000457
458 try:
459 label = models.Label.smart_get(label)
460 except models.Label.DoesNotExist:
461 label = None
462
463 kernel_objs = models.Kernel.create_kernels(kernel)
464 profiler_objs = [models.Profiler.smart_get(profiler)
465 for profiler in profilers]
466
467 parameterized_job = models.ParameterizedJob.objects.create(
468 test=test_obj, label=label, use_container=use_container,
469 profile_only=profile_only,
470 upload_kernel_config=upload_kernel_config)
471 parameterized_job.kernels.add(*kernel_objs)
472
473 for profiler in profiler_objs:
474 parameterized_profiler = models.ParameterizedJobProfiler.objects.create(
475 parameterized_job=parameterized_job,
476 profiler=profiler)
477 profiler_params = profiler_parameters.get(profiler.name, {})
478 for name, (value, param_type) in profiler_params.iteritems():
479 models.ParameterizedJobProfilerParameter.objects.create(
480 parameterized_job_profiler=parameterized_profiler,
481 parameter_name=name,
482 parameter_value=value,
483 parameter_type=param_type)
484
485 try:
486 for parameter in test_obj.testparameter_set.all():
487 if parameter.name in parameters:
488 param_value, param_type = parameters.pop(parameter.name)
489 parameterized_job.parameterizedjobparameter_set.create(
490 test_parameter=parameter, parameter_value=param_value,
491 parameter_type=param_type)
492
493 if parameters:
494 raise Exception('Extra parameters remain: %r' % parameters)
495
496 return rpc_utils.create_job_common(
497 parameterized_job=parameterized_job.id,
498 control_type=control_type,
499 **rpc_utils.get_create_job_common_args(args))
500 except:
501 parameterized_job.delete()
502 raise
503
504
Simran Basib6ec8ae2014-04-23 12:05:08 -0700505def create_job_page_handler(name, priority, control_file, control_type,
506 image=None, hostless=False, **kwargs):
507 """\
508 Create and enqueue a job.
509
510 @param name name of this job
511 @param priority Integer priority of this job. Higher is more important.
512 @param control_file String contents of the control file.
513 @param control_type Type of control file, Client or Server.
514 @param kwargs extra args that will be required by create_suite_job or
515 create_job.
516
517 @returns The created Job id number.
518 """
519 control_file = rpc_utils.encode_ascii(control_file)
Jiaxi Luodd67beb2014-07-18 16:28:31 -0700520 if not control_file:
521 raise model_logic.ValidationError({
522 'control_file' : "Control file cannot be empty"})
Simran Basib6ec8ae2014-04-23 12:05:08 -0700523
524 if image and hostless:
525 return site_rpc_interface.create_suite_job(
526 name=name, control_file=control_file, priority=priority,
527 build=image, **kwargs)
528 return create_job(name, priority, control_file, control_type, image=image,
529 hostless=hostless, **kwargs)
530
531
showard12f3e322009-05-13 21:27:42 +0000532def create_job(name, priority, control_file, control_type,
533 hosts=(), meta_hosts=(), one_time_hosts=(),
534 atomic_group_name=None, synch_count=None, is_template=False,
Simran Basi7e605742013-11-12 13:43:36 -0800535 timeout=None, timeout_mins=None, max_runtime_mins=None,
536 run_verify=False, email_list='', dependencies=(),
537 reboot_before=None, reboot_after=None, parse_failed_repair=None,
538 hostless=False, keyvals=None, drone_set=None, image=None,
Jiaxi Luo90190c92014-06-18 12:35:57 -0700539 parent_job_id=None, test_retry=0, run_reset=True, args=(),
540 **kwargs):
jadmanski0afbb632008-06-06 21:10:57 +0000541 """\
542 Create and enqueue a job.
mblighe8819cd2008-02-15 16:48:40 +0000543
showarda1e74b32009-05-12 17:32:04 +0000544 @param name name of this job
Alex Miller7d658cf2013-09-04 16:00:35 -0700545 @param priority Integer priority of this job. Higher is more important.
showarda1e74b32009-05-12 17:32:04 +0000546 @param control_file String contents of the control file.
547 @param control_type Type of control file, Client or Server.
548 @param synch_count How many machines the job uses per autoserv execution.
Jiaxi Luo90190c92014-06-18 12:35:57 -0700549 synch_count == 1 means the job is asynchronous. If an atomic group is
550 given this value is treated as a minimum.
showarda1e74b32009-05-12 17:32:04 +0000551 @param is_template If true then create a template job.
552 @param timeout Hours after this call returns until the job times out.
Simran Basi7e605742013-11-12 13:43:36 -0800553 @param timeout_mins Minutes after this call returns until the job times
Jiaxi Luo90190c92014-06-18 12:35:57 -0700554 out.
Simran Basi34217022012-11-06 13:43:15 -0800555 @param max_runtime_mins Minutes from job starting time until job times out
showarda1e74b32009-05-12 17:32:04 +0000556 @param run_verify Should the host be verified before running the test?
557 @param email_list String containing emails to mail when the job is done
558 @param dependencies List of label names on which this job depends
559 @param reboot_before Never, If dirty, or Always
560 @param reboot_after Never, If all tests passed, or Always
561 @param parse_failed_repair if true, results of failed repairs launched by
Jiaxi Luo90190c92014-06-18 12:35:57 -0700562 this job will be parsed as part of the job.
showarda9545c02009-12-18 22:44:26 +0000563 @param hostless if true, create a hostless job
showardc1a98d12010-01-15 00:22:22 +0000564 @param keyvals dict of keyvals to associate with the job
showarda1e74b32009-05-12 17:32:04 +0000565 @param hosts List of hosts to run job on.
566 @param meta_hosts List where each entry is a label name, and for each entry
Jiaxi Luo90190c92014-06-18 12:35:57 -0700567 one host will be chosen from that label to run the job on.
showarda1e74b32009-05-12 17:32:04 +0000568 @param one_time_hosts List of hosts not in the database to run the job on.
569 @param atomic_group_name The name of an atomic group to schedule the job on.
jamesren76fcf192010-04-21 20:39:50 +0000570 @param drone_set The name of the drone set to run this test on.
Paul Pendlebury5a8c6ad2011-02-01 07:20:17 -0800571 @param image OS image to install before running job.
Aviv Keshet0b9cfc92013-02-05 11:36:02 -0800572 @param parent_job_id id of a job considered to be parent of created job.
Simran Basib6ec8ae2014-04-23 12:05:08 -0700573 @param test_retry Number of times to retry test if the test did not
Jiaxi Luo90190c92014-06-18 12:35:57 -0700574 complete successfully. (optional, default: 0)
Simran Basib6ec8ae2014-04-23 12:05:08 -0700575 @param run_reset Should the host be reset before running the test?
Jiaxi Luo90190c92014-06-18 12:35:57 -0700576 @param args A list of args to be injected into control file.
Simran Basib6ec8ae2014-04-23 12:05:08 -0700577 @param kwargs extra keyword args. NOT USED.
showardc92da832009-04-07 18:14:34 +0000578
579 @returns The created Job id number.
jadmanski0afbb632008-06-06 21:10:57 +0000580 """
Jiaxi Luo90190c92014-06-18 12:35:57 -0700581 if args:
582 control_file = tools.inject_vars({'args': args}, control_file)
583
Simran Basiab5a1bf2014-05-28 15:39:44 -0700584 if image is None:
585 return rpc_utils.create_job_common(
586 **rpc_utils.get_create_job_common_args(locals()))
587
588 # When image is supplied use a known parameterized test already in the
589 # database to pass the OS image path from the front end, through the
590 # scheduler, and finally to autoserv as the --image parameter.
591
592 # The test autoupdate_ParameterizedJob is in afe_autotests and used to
593 # instantiate a Test object and from there a ParameterizedJob.
594 known_test_obj = models.Test.smart_get('autoupdate_ParameterizedJob')
595 known_parameterized_job = models.ParameterizedJob.objects.create(
596 test=known_test_obj)
597
598 # autoupdate_ParameterizedJob has a single parameter, the image parameter,
599 # stored in the table afe_test_parameters. We retrieve and set this
600 # instance of the parameter to the OS image path.
601 image_parameter = known_test_obj.testparameter_set.get(test=known_test_obj,
602 name='image')
603 known_parameterized_job.parameterizedjobparameter_set.create(
604 test_parameter=image_parameter, parameter_value=image,
605 parameter_type='string')
606
607 # By passing a parameterized_job to create_job_common the job entry in
608 # the afe_jobs table will have the field parameterized_job_id set.
609 # The scheduler uses this id in the afe_parameterized_jobs table to
610 # match this job to our known test, and then with the
611 # afe_parameterized_job_parameters table to get the actual image path.
jamesren4a41e012010-07-16 22:33:48 +0000612 return rpc_utils.create_job_common(
Simran Basiab5a1bf2014-05-28 15:39:44 -0700613 parameterized_job=known_parameterized_job.id,
jamesren4a41e012010-07-16 22:33:48 +0000614 **rpc_utils.get_create_job_common_args(locals()))
mblighe8819cd2008-02-15 16:48:40 +0000615
616
showard9dbdcda2008-10-14 17:34:36 +0000617def abort_host_queue_entries(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000618 """\
showard9dbdcda2008-10-14 17:34:36 +0000619 Abort a set of host queue entries.
jadmanski0afbb632008-06-06 21:10:57 +0000620 """
showard9dbdcda2008-10-14 17:34:36 +0000621 query = models.HostQueueEntry.query_objects(filter_data)
beepsfaecbce2013-10-29 11:35:10 -0700622
623 # Dont allow aborts on:
624 # 1. Jobs that have already completed (whether or not they were aborted)
625 # 2. Jobs that we have already been aborted (but may not have completed)
626 query = query.filter(complete=False).filter(aborted=False)
showarddc817512008-11-12 18:16:41 +0000627 models.AclGroup.check_abort_permissions(query)
showard9dbdcda2008-10-14 17:34:36 +0000628 host_queue_entries = list(query.select_related())
showard2bab8f42008-11-12 18:15:22 +0000629 rpc_utils.check_abort_synchronous_jobs(host_queue_entries)
mblighe8819cd2008-02-15 16:48:40 +0000630
Simran Basic1b26762013-06-26 14:23:21 -0700631 models.HostQueueEntry.abort_host_queue_entries(host_queue_entries)
showard9d821ab2008-07-11 16:54:29 +0000632
633
beeps8bb1f7d2013-08-05 01:30:09 -0700634def abort_special_tasks(**filter_data):
635 """\
636 Abort the special task, or tasks, specified in the filter.
637 """
638 query = models.SpecialTask.query_objects(filter_data)
639 special_tasks = query.filter(is_active=True)
640 for task in special_tasks:
641 task.abort()
642
643
Simran Basi73dae552013-02-25 14:57:46 -0800644def _call_special_tasks_on_hosts(task, hosts):
645 """\
646 Schedules a set of hosts for a special task.
647
648 @returns A list of hostnames that a special task was created for.
649 """
650 models.AclGroup.check_for_acl_violation_hosts(hosts)
651 for host in hosts:
652 models.SpecialTask.schedule_special_task(host, task)
653 return list(sorted(host.hostname for host in hosts))
654
655
showard1ff7b2e2009-05-15 23:17:18 +0000656def reverify_hosts(**filter_data):
657 """\
658 Schedules a set of hosts for verify.
mbligh4e545a52009-12-19 05:30:39 +0000659
660 @returns A list of hostnames that a verify task was created for.
showard1ff7b2e2009-05-15 23:17:18 +0000661 """
Simran Basi73dae552013-02-25 14:57:46 -0800662 return _call_special_tasks_on_hosts(models.SpecialTask.Task.VERIFY,
663 models.Host.query_objects(filter_data))
664
665
666def repair_hosts(**filter_data):
667 """\
668 Schedules a set of hosts for repair.
669
670 @returns A list of hostnames that a repair task was created for.
671 """
672 return _call_special_tasks_on_hosts(models.SpecialTask.Task.REPAIR,
673 models.Host.query_objects(filter_data))
showard1ff7b2e2009-05-15 23:17:18 +0000674
675
Jiaxi Luo15cbf372014-07-01 19:20:20 -0700676def get_jobs(not_yet_run=False, running=False, finished=False,
677 suite=False, sub=False, standalone=False, **filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000678 """\
Jiaxi Luo15cbf372014-07-01 19:20:20 -0700679 Extra status filter args for get_jobs:
jadmanski0afbb632008-06-06 21:10:57 +0000680 -not_yet_run: Include only jobs that have not yet started running.
681 -running: Include only jobs that have start running but for which not
682 all hosts have completed.
683 -finished: Include only jobs for which all hosts have completed (or
684 aborted).
685 At most one of these three fields should be specified.
Jiaxi Luo15cbf372014-07-01 19:20:20 -0700686
687 Extra type filter args for get_jobs:
688 -suite: Include only jobs with child jobs.
689 -sub: Include only jobs with a parent job.
690 -standalone: Inlcude only jobs with no child or parent jobs.
691 At most one of these three fields should be specified.
jadmanski0afbb632008-06-06 21:10:57 +0000692 """
Jiaxi Luo15cbf372014-07-01 19:20:20 -0700693 extra_args = rpc_utils.extra_job_status_filters(not_yet_run,
694 running,
695 finished)
696 filter_data['extra_args'] = rpc_utils.extra_job_type_filters(extra_args,
697 suite,
698 sub,
699 standalone)
showard0957a842009-05-11 19:25:08 +0000700 job_dicts = []
701 jobs = list(models.Job.query_objects(filter_data))
702 models.Job.objects.populate_relationships(jobs, models.Label,
703 'dependencies')
showardc1a98d12010-01-15 00:22:22 +0000704 models.Job.objects.populate_relationships(jobs, models.JobKeyval, 'keyvals')
showard0957a842009-05-11 19:25:08 +0000705 for job in jobs:
706 job_dict = job.get_object_dict()
707 job_dict['dependencies'] = ','.join(label.name
708 for label in job.dependencies)
showardc1a98d12010-01-15 00:22:22 +0000709 job_dict['keyvals'] = dict((keyval.key, keyval.value)
710 for keyval in job.keyvals)
Eric Lid23bc192011-02-09 14:38:57 -0800711 if job.parameterized_job:
712 job_dict['image'] = get_parameterized_autoupdate_image_url(job)
showard0957a842009-05-11 19:25:08 +0000713 job_dicts.append(job_dict)
714 return rpc_utils.prepare_for_serialization(job_dicts)
mblighe8819cd2008-02-15 16:48:40 +0000715
716
717def get_num_jobs(not_yet_run=False, running=False, finished=False,
Jiaxi Luo15cbf372014-07-01 19:20:20 -0700718 suite=False, sub=False, standalone=False,
jadmanski0afbb632008-06-06 21:10:57 +0000719 **filter_data):
720 """\
721 See get_jobs() for documentation of extra filter parameters.
722 """
Jiaxi Luo15cbf372014-07-01 19:20:20 -0700723 extra_args = rpc_utils.extra_job_status_filters(not_yet_run,
724 running,
725 finished)
726 filter_data['extra_args'] = rpc_utils.extra_job_type_filters(extra_args,
727 suite,
728 sub,
729 standalone)
jadmanski0afbb632008-06-06 21:10:57 +0000730 return models.Job.query_count(filter_data)
mblighe8819cd2008-02-15 16:48:40 +0000731
732
mblighe8819cd2008-02-15 16:48:40 +0000733def get_jobs_summary(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000734 """\
Jiaxi Luoaac54572014-06-04 13:57:02 -0700735 Like get_jobs(), but adds 'status_counts' and 'result_counts' field.
736
737 'status_counts' filed is a dictionary mapping status strings to the number
738 of hosts currently with that status, i.e. {'Queued' : 4, 'Running' : 2}.
739
740 'result_counts' field is piped to tko's rpc_interface and has the return
741 format specified under get_group_counts.
jadmanski0afbb632008-06-06 21:10:57 +0000742 """
743 jobs = get_jobs(**filter_data)
744 ids = [job['id'] for job in jobs]
745 all_status_counts = models.Job.objects.get_status_counts(ids)
746 for job in jobs:
747 job['status_counts'] = all_status_counts[job['id']]
Jiaxi Luoaac54572014-06-04 13:57:02 -0700748 job['result_counts'] = tko_rpc_interface.get_status_counts(
749 ['afe_job_id', 'afe_job_id'],
750 header_groups=[['afe_job_id'], ['afe_job_id']],
751 **{'afe_job_id': job['id']})
jadmanski0afbb632008-06-06 21:10:57 +0000752 return rpc_utils.prepare_for_serialization(jobs)
mblighe8819cd2008-02-15 16:48:40 +0000753
754
showarda965cef2009-05-15 23:17:41 +0000755def get_info_for_clone(id, preserve_metahosts, queue_entry_filter_data=None):
showarda8709c52008-07-03 19:44:54 +0000756 """\
757 Retrieves all the information needed to clone a job.
758 """
showarda8709c52008-07-03 19:44:54 +0000759 job = models.Job.objects.get(id=id)
showard29f7cd22009-04-29 21:16:24 +0000760 job_info = rpc_utils.get_job_info(job,
showarda965cef2009-05-15 23:17:41 +0000761 preserve_metahosts,
762 queue_entry_filter_data)
showard945072f2008-09-03 20:34:59 +0000763
showardd9992fe2008-07-31 02:15:03 +0000764 host_dicts = []
showard29f7cd22009-04-29 21:16:24 +0000765 for host in job_info['hosts']:
766 host_dict = get_hosts(id=host.id)[0]
767 other_labels = host_dict['labels']
768 if host_dict['platform']:
769 other_labels.remove(host_dict['platform'])
770 host_dict['other_labels'] = ', '.join(other_labels)
showardd9992fe2008-07-31 02:15:03 +0000771 host_dicts.append(host_dict)
showarda8709c52008-07-03 19:44:54 +0000772
showard29f7cd22009-04-29 21:16:24 +0000773 for host in job_info['one_time_hosts']:
774 host_dict = dict(hostname=host.hostname,
775 id=host.id,
776 platform='(one-time host)',
777 locked_text='')
778 host_dicts.append(host_dict)
showarda8709c52008-07-03 19:44:54 +0000779
showard4d077562009-05-08 18:24:36 +0000780 # convert keys from Label objects to strings (names of labels)
showard29f7cd22009-04-29 21:16:24 +0000781 meta_host_counts = dict((meta_host.name, count) for meta_host, count
showard4d077562009-05-08 18:24:36 +0000782 in job_info['meta_host_counts'].iteritems())
showard29f7cd22009-04-29 21:16:24 +0000783
784 info = dict(job=job.get_object_dict(),
785 meta_host_counts=meta_host_counts,
786 hosts=host_dicts)
787 info['job']['dependencies'] = job_info['dependencies']
788 if job_info['atomic_group']:
789 info['atomic_group_name'] = (job_info['atomic_group']).name
790 else:
791 info['atomic_group_name'] = None
jamesren2275ef12010-04-12 18:25:06 +0000792 info['hostless'] = job_info['hostless']
jamesren76fcf192010-04-21 20:39:50 +0000793 info['drone_set'] = job.drone_set and job.drone_set.name
showarda8709c52008-07-03 19:44:54 +0000794
Eric Lid23bc192011-02-09 14:38:57 -0800795 if job.parameterized_job:
796 info['job']['image'] = get_parameterized_autoupdate_image_url(job)
797
showarda8709c52008-07-03 19:44:54 +0000798 return rpc_utils.prepare_for_serialization(info)
799
800
showard34dc5fa2008-04-24 20:58:40 +0000801# host queue entries
802
Jiaxi Luo57bc1952014-07-22 15:27:30 -0700803def get_host_queue_entries(start_time=None, end_time=None, **filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000804 """\
showardc92da832009-04-07 18:14:34 +0000805 @returns A sequence of nested dictionaries of host and job information.
jadmanski0afbb632008-06-06 21:10:57 +0000806 """
Jiaxi Luo57bc1952014-07-22 15:27:30 -0700807 filter_data = rpc_utils.inject_times_to_filter('started_on__gte',
808 'started_on__lte',
809 start_time,
810 end_time,
811 **filter_data)
showardc92da832009-04-07 18:14:34 +0000812 return rpc_utils.prepare_rows_as_nested_dicts(
813 models.HostQueueEntry.query_objects(filter_data),
814 ('host', 'atomic_group', 'job'))
showard34dc5fa2008-04-24 20:58:40 +0000815
816
Jiaxi Luo57bc1952014-07-22 15:27:30 -0700817def get_num_host_queue_entries(start_time=None, end_time=None, **filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000818 """\
819 Get the number of host queue entries associated with this job.
820 """
Jiaxi Luo57bc1952014-07-22 15:27:30 -0700821 filter_data = rpc_utils.inject_times_to_filter('started_on__gte',
822 'started_on__lte',
823 start_time,
824 end_time,
825 **filter_data)
jadmanski0afbb632008-06-06 21:10:57 +0000826 return models.HostQueueEntry.query_count(filter_data)
showard34dc5fa2008-04-24 20:58:40 +0000827
828
showard1e935f12008-07-11 00:11:36 +0000829def get_hqe_percentage_complete(**filter_data):
830 """
showardc92da832009-04-07 18:14:34 +0000831 Computes the fraction of host queue entries matching the given filter data
showard1e935f12008-07-11 00:11:36 +0000832 that are complete.
833 """
834 query = models.HostQueueEntry.query_objects(filter_data)
835 complete_count = query.filter(complete=True).count()
836 total_count = query.count()
837 if total_count == 0:
838 return 1
839 return float(complete_count) / total_count
840
841
showard1a5a4082009-07-28 20:01:37 +0000842# special tasks
843
844def get_special_tasks(**filter_data):
845 return rpc_utils.prepare_rows_as_nested_dicts(
846 models.SpecialTask.query_objects(filter_data),
847 ('host', 'queue_entry'))
848
849
showardc0ac3a72009-07-08 21:14:45 +0000850# support for host detail view
851
Jiaxi Luo79ce6422014-06-13 17:08:09 -0700852def get_host_queue_entries_and_special_tasks(host_id, query_start=None,
Jiaxi Luo57bc1952014-07-22 15:27:30 -0700853 query_limit=None, start_time=None,
854 end_time=None):
showardc0ac3a72009-07-08 21:14:45 +0000855 """
856 @returns an interleaved list of HostQueueEntries and SpecialTasks,
857 in approximate run order. each dict contains keys for type, host,
858 job, status, started_on, execution_path, and ID.
859 """
860 total_limit = None
861 if query_limit is not None:
862 total_limit = query_start + query_limit
Jiaxi Luo57bc1952014-07-22 15:27:30 -0700863 filter_data_common = {'host': host_id,
864 'query_limit': total_limit,
865 'sort_by': ['-id']}
showardc0ac3a72009-07-08 21:14:45 +0000866
Jiaxi Luo57bc1952014-07-22 15:27:30 -0700867 filter_data_queue_entries, filter_data_special_tasks = (
868 rpc_utils.inject_times_to_hqe_special_tasks_filters(
869 filter_data_common, start_time, end_time))
870
871 queue_entries = list(models.HostQueueEntry.query_objects(
872 filter_data_queue_entries))
873 special_tasks = list(models.SpecialTask.query_objects(
874 filter_data_special_tasks))
showardc0ac3a72009-07-08 21:14:45 +0000875
876 interleaved_entries = rpc_utils.interleave_entries(queue_entries,
877 special_tasks)
878 if query_start is not None:
879 interleaved_entries = interleaved_entries[query_start:]
880 if query_limit is not None:
881 interleaved_entries = interleaved_entries[:query_limit]
882 return rpc_utils.prepare_for_serialization(interleaved_entries)
883
884
Jiaxi Luo57bc1952014-07-22 15:27:30 -0700885def get_num_host_queue_entries_and_special_tasks(host_id, start_time=None,
886 end_time=None):
887 filter_data_common = {'host': host_id}
888
889 filter_data_queue_entries, filter_data_special_tasks = (
890 rpc_utils.inject_times_to_hqe_special_tasks_filters(
891 filter_data_common, start_time, end_time))
892
893 return (models.HostQueueEntry.query_count(filter_data_queue_entries)
894 + models.SpecialTask.query_count(filter_data_special_tasks))
showardc0ac3a72009-07-08 21:14:45 +0000895
896
showard29f7cd22009-04-29 21:16:24 +0000897# recurring run
898
899def get_recurring(**filter_data):
900 return rpc_utils.prepare_rows_as_nested_dicts(
901 models.RecurringRun.query_objects(filter_data),
902 ('job', 'owner'))
903
904
905def get_num_recurring(**filter_data):
906 return models.RecurringRun.query_count(filter_data)
907
908
909def delete_recurring_runs(**filter_data):
910 to_delete = models.RecurringRun.query_objects(filter_data)
911 to_delete.delete()
912
913
914def create_recurring_run(job_id, start_date, loop_period, loop_count):
showard64a95952010-01-13 21:27:16 +0000915 owner = models.User.current_user().login
showard29f7cd22009-04-29 21:16:24 +0000916 job = models.Job.objects.get(id=job_id)
917 return job.create_recurring_job(start_date=start_date,
918 loop_period=loop_period,
919 loop_count=loop_count,
920 owner=owner)
921
922
mblighe8819cd2008-02-15 16:48:40 +0000923# other
924
showarde0b63622008-08-04 20:58:47 +0000925def echo(data=""):
926 """\
927 Returns a passed in string. For doing a basic test to see if RPC calls
928 can successfully be made.
929 """
930 return data
931
932
showardb7a52fd2009-04-27 20:10:56 +0000933def get_motd():
934 """\
935 Returns the message of the day as a string.
936 """
937 return rpc_utils.get_motd()
938
939
mblighe8819cd2008-02-15 16:48:40 +0000940def get_static_data():
jadmanski0afbb632008-06-06 21:10:57 +0000941 """\
942 Returns a dictionary containing a bunch of data that shouldn't change
943 often and is otherwise inaccessible. This includes:
showardc92da832009-04-07 18:14:34 +0000944
945 priorities: List of job priority choices.
946 default_priority: Default priority value for new jobs.
947 users: Sorted list of all users.
Jiaxi Luo31874592014-06-11 10:36:35 -0700948 labels: Sorted list of labels not start with 'cros-version' and
949 'fw-version'.
showardc92da832009-04-07 18:14:34 +0000950 atomic_groups: Sorted list of all atomic groups.
951 tests: Sorted list of all tests.
952 profilers: Sorted list of all profilers.
953 current_user: Logged-in username.
954 host_statuses: Sorted list of possible Host statuses.
955 job_statuses: Sorted list of possible HostQueueEntry statuses.
Simran Basi7e605742013-11-12 13:43:36 -0800956 job_timeout_default: The default job timeout length in minutes.
showarda1e74b32009-05-12 17:32:04 +0000957 parse_failed_repair_default: Default value for the parse_failed_repair job
Jiaxi Luo31874592014-06-11 10:36:35 -0700958 option.
showardc92da832009-04-07 18:14:34 +0000959 reboot_before_options: A list of valid RebootBefore string enums.
960 reboot_after_options: A list of valid RebootAfter string enums.
961 motd: Server's message of the day.
962 status_dictionary: A mapping from one word job status names to a more
963 informative description.
jadmanski0afbb632008-06-06 21:10:57 +0000964 """
showard21baa452008-10-21 00:08:39 +0000965
966 job_fields = models.Job.get_field_dict()
jamesren76fcf192010-04-21 20:39:50 +0000967 default_drone_set_name = models.DroneSet.default_drone_set_name()
968 drone_sets = ([default_drone_set_name] +
969 sorted(drone_set.name for drone_set in
970 models.DroneSet.objects.exclude(
971 name=default_drone_set_name)))
showard21baa452008-10-21 00:08:39 +0000972
jadmanski0afbb632008-06-06 21:10:57 +0000973 result = {}
Alex Miller7d658cf2013-09-04 16:00:35 -0700974 result['priorities'] = priorities.Priority.choices()
975 default_priority = priorities.Priority.DEFAULT
976 result['default_priority'] = 'Default'
977 result['max_schedulable_priority'] = priorities.Priority.DEFAULT
jadmanski0afbb632008-06-06 21:10:57 +0000978 result['users'] = get_users(sort_by=['login'])
Jiaxi Luo31874592014-06-11 10:36:35 -0700979
980 label_exclude_filters = [{'name__startswith': 'cros-version'},
981 {'name__startswith': 'fw-version'}]
982 result['labels'] = get_labels(
983 label_exclude_filters,
984 sort_by=['-platform', 'name'])
985
showardc92da832009-04-07 18:14:34 +0000986 result['atomic_groups'] = get_atomic_groups(sort_by=['name'])
jadmanski0afbb632008-06-06 21:10:57 +0000987 result['tests'] = get_tests(sort_by=['name'])
showard2b9a88b2008-06-13 20:55:03 +0000988 result['profilers'] = get_profilers(sort_by=['name'])
showard0fc38302008-10-23 00:44:07 +0000989 result['current_user'] = rpc_utils.prepare_for_serialization(
showard64a95952010-01-13 21:27:16 +0000990 models.User.current_user().get_object_dict())
showard2b9a88b2008-06-13 20:55:03 +0000991 result['host_statuses'] = sorted(models.Host.Status.names)
mbligh5a198b92008-12-11 19:33:29 +0000992 result['job_statuses'] = sorted(models.HostQueueEntry.Status.names)
Simran Basi7e605742013-11-12 13:43:36 -0800993 result['job_timeout_mins_default'] = models.Job.DEFAULT_TIMEOUT_MINS
Simran Basi34217022012-11-06 13:43:15 -0800994 result['job_max_runtime_mins_default'] = (
995 models.Job.DEFAULT_MAX_RUNTIME_MINS)
showarda1e74b32009-05-12 17:32:04 +0000996 result['parse_failed_repair_default'] = bool(
997 models.Job.DEFAULT_PARSE_FAILED_REPAIR)
jamesrendd855242010-03-02 22:23:44 +0000998 result['reboot_before_options'] = model_attributes.RebootBefore.names
999 result['reboot_after_options'] = model_attributes.RebootAfter.names
showard8fbae652009-01-20 23:23:10 +00001000 result['motd'] = rpc_utils.get_motd()
jamesren76fcf192010-04-21 20:39:50 +00001001 result['drone_sets_enabled'] = models.DroneSet.drone_sets_enabled()
1002 result['drone_sets'] = drone_sets
jamesren4a41e012010-07-16 22:33:48 +00001003 result['parameterized_jobs'] = models.Job.parameterized_jobs_enabled()
showard8ac29b42008-07-17 17:01:55 +00001004
showardd3dc1992009-04-22 21:01:40 +00001005 result['status_dictionary'] = {"Aborted": "Aborted",
showard8ac29b42008-07-17 17:01:55 +00001006 "Verifying": "Verifying Host",
Alex Millerdfff2fd2013-05-28 13:05:06 -07001007 "Provisioning": "Provisioning Host",
showard8ac29b42008-07-17 17:01:55 +00001008 "Pending": "Waiting on other hosts",
1009 "Running": "Running autoserv",
1010 "Completed": "Autoserv completed",
1011 "Failed": "Failed to complete",
showardd823b362008-07-24 16:35:46 +00001012 "Queued": "Queued",
showard5deb6772008-11-04 21:54:33 +00001013 "Starting": "Next in host's queue",
1014 "Stopped": "Other host(s) failed verify",
showardd3dc1992009-04-22 21:01:40 +00001015 "Parsing": "Awaiting parse of final results",
showard29f7cd22009-04-29 21:16:24 +00001016 "Gathering": "Gathering log files",
showard8cc058f2009-09-08 16:26:33 +00001017 "Template": "Template job for recurring run",
mbligh4608b002010-01-05 18:22:35 +00001018 "Waiting": "Waiting for scheduler action",
Dan Shi07e09af2013-04-12 09:31:29 -07001019 "Archiving": "Archiving results",
1020 "Resetting": "Resetting hosts"}
Jiaxi Luo421608e2014-07-07 14:38:00 -07001021
1022 result['wmatrix_url'] = rpc_utils.get_wmatrix_url()
Simran Basi71206ef2014-08-13 13:51:18 -07001023 result['is_moblab'] = bool(utils.is_moblab())
Jiaxi Luo421608e2014-07-07 14:38:00 -07001024
jadmanski0afbb632008-06-06 21:10:57 +00001025 return result
showard29f7cd22009-04-29 21:16:24 +00001026
1027
1028def get_server_time():
1029 return datetime.datetime.now().strftime("%Y-%m-%d %H:%M")