blob: b3acb0eb3ca420a26ba8ec0e6131c9b11426462a [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
Alex Miller7d658cf2013-09-04 16:00:35 -070036from autotest_lib.client.common_lib import error, 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
mblighe8819cd2008-02-15 16:48:40 +000039
Eric Lid23bc192011-02-09 14:38:57 -080040def get_parameterized_autoupdate_image_url(job):
41 """Get the parameterized autoupdate image url from a parameterized job."""
42 known_test_obj = models.Test.smart_get('autoupdate_ParameterizedJob')
43 image_parameter = known_test_obj.testparameter_set.get(test=known_test_obj,
beeps8bb1f7d2013-08-05 01:30:09 -070044 name='image')
Eric Lid23bc192011-02-09 14:38:57 -080045 para_set = job.parameterized_job.parameterizedjobparameter_set
46 job_test_para = para_set.get(test_parameter=image_parameter)
47 return job_test_para.parameter_value
48
49
mblighe8819cd2008-02-15 16:48:40 +000050# labels
51
showard989f25d2008-10-01 11:38:11 +000052def add_label(name, kernel_config=None, platform=None, only_if_needed=None):
showardc92da832009-04-07 18:14:34 +000053 return models.Label.add_object(
54 name=name, kernel_config=kernel_config, platform=platform,
55 only_if_needed=only_if_needed).id
mblighe8819cd2008-02-15 16:48:40 +000056
57
58def modify_label(id, **data):
jadmanski0afbb632008-06-06 21:10:57 +000059 models.Label.smart_get(id).update_object(data)
mblighe8819cd2008-02-15 16:48:40 +000060
61
62def delete_label(id):
jadmanski0afbb632008-06-06 21:10:57 +000063 models.Label.smart_get(id).delete()
mblighe8819cd2008-02-15 16:48:40 +000064
65
showardbbabf502008-06-06 00:02:02 +000066def label_add_hosts(id, hosts):
showardbe3ec042008-11-12 18:16:07 +000067 host_objs = models.Host.smart_get_bulk(hosts)
showardcafd16e2009-05-29 18:37:49 +000068 label = models.Label.smart_get(id)
69 if label.platform:
70 models.Host.check_no_platform(host_objs)
71 label.host_set.add(*host_objs)
showardbbabf502008-06-06 00:02:02 +000072
73
74def label_remove_hosts(id, hosts):
showardbe3ec042008-11-12 18:16:07 +000075 host_objs = models.Host.smart_get_bulk(hosts)
jadmanski0afbb632008-06-06 21:10:57 +000076 models.Label.smart_get(id).host_set.remove(*host_objs)
showardbbabf502008-06-06 00:02:02 +000077
78
mblighe8819cd2008-02-15 16:48:40 +000079def get_labels(**filter_data):
showardc92da832009-04-07 18:14:34 +000080 """\
81 @returns A sequence of nested dictionaries of label information.
82 """
83 return rpc_utils.prepare_rows_as_nested_dicts(
84 models.Label.query_objects(filter_data),
85 ('atomic_group',))
86
87
88# atomic groups
89
showarde9450c92009-06-30 01:58:52 +000090def add_atomic_group(name, max_number_of_machines=None, description=None):
showardc92da832009-04-07 18:14:34 +000091 return models.AtomicGroup.add_object(
92 name=name, max_number_of_machines=max_number_of_machines,
93 description=description).id
94
95
96def modify_atomic_group(id, **data):
97 models.AtomicGroup.smart_get(id).update_object(data)
98
99
100def delete_atomic_group(id):
101 models.AtomicGroup.smart_get(id).delete()
102
103
104def atomic_group_add_labels(id, labels):
105 label_objs = models.Label.smart_get_bulk(labels)
106 models.AtomicGroup.smart_get(id).label_set.add(*label_objs)
107
108
109def atomic_group_remove_labels(id, labels):
110 label_objs = models.Label.smart_get_bulk(labels)
111 models.AtomicGroup.smart_get(id).label_set.remove(*label_objs)
112
113
114def get_atomic_groups(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000115 return rpc_utils.prepare_for_serialization(
showardc92da832009-04-07 18:14:34 +0000116 models.AtomicGroup.list_objects(filter_data))
mblighe8819cd2008-02-15 16:48:40 +0000117
118
119# hosts
120
showarddf062562008-07-03 19:56:37 +0000121def add_host(hostname, status=None, locked=None, protection=None):
jadmanski0afbb632008-06-06 21:10:57 +0000122 return models.Host.add_object(hostname=hostname, status=status,
showarddf062562008-07-03 19:56:37 +0000123 locked=locked, protection=protection).id
mblighe8819cd2008-02-15 16:48:40 +0000124
125
126def modify_host(id, **data):
showardbe0d8692009-08-20 23:42:44 +0000127 rpc_utils.check_modify_host(data)
showardce7c0922009-09-11 18:39:24 +0000128 host = models.Host.smart_get(id)
129 rpc_utils.check_modify_host_locking(host, data)
130 host.update_object(data)
mblighe8819cd2008-02-15 16:48:40 +0000131
132
showard276f9442009-05-20 00:33:16 +0000133def modify_hosts(host_filter_data, update_data):
134 """
showardbe0d8692009-08-20 23:42:44 +0000135 @param host_filter_data: Filters out which hosts to modify.
136 @param update_data: A dictionary with the changes to make to the hosts.
showard276f9442009-05-20 00:33:16 +0000137 """
showardbe0d8692009-08-20 23:42:44 +0000138 rpc_utils.check_modify_host(update_data)
showard276f9442009-05-20 00:33:16 +0000139 hosts = models.Host.query_objects(host_filter_data)
Alex Miller9658a952013-05-14 16:40:02 -0700140 # Check all hosts before changing data for exception safety.
141 for host in hosts:
142 rpc_utils.check_modify_host_locking(host, update_data)
showard276f9442009-05-20 00:33:16 +0000143 for host in hosts:
144 host.update_object(update_data)
145
146
mblighe8819cd2008-02-15 16:48:40 +0000147def host_add_labels(id, labels):
showardbe3ec042008-11-12 18:16:07 +0000148 labels = models.Label.smart_get_bulk(labels)
showardcafd16e2009-05-29 18:37:49 +0000149 host = models.Host.smart_get(id)
150
151 platforms = [label.name for label in labels if label.platform]
152 if len(platforms) > 1:
153 raise model_logic.ValidationError(
154 {'labels': 'Adding more than one platform label: %s' %
155 ', '.join(platforms)})
156 if len(platforms) == 1:
157 models.Host.check_no_platform([host])
158 host.labels.add(*labels)
mblighe8819cd2008-02-15 16:48:40 +0000159
160
161def host_remove_labels(id, labels):
showardbe3ec042008-11-12 18:16:07 +0000162 labels = models.Label.smart_get_bulk(labels)
jadmanski0afbb632008-06-06 21:10:57 +0000163 models.Host.smart_get(id).labels.remove(*labels)
mblighe8819cd2008-02-15 16:48:40 +0000164
165
showard0957a842009-05-11 19:25:08 +0000166def set_host_attribute(attribute, value, **host_filter_data):
167 """
168 @param attribute string name of attribute
169 @param value string, or None to delete an attribute
170 @param host_filter_data filter data to apply to Hosts to choose hosts to act
171 upon
172 """
173 assert host_filter_data # disallow accidental actions on all hosts
174 hosts = models.Host.query_objects(host_filter_data)
175 models.AclGroup.check_for_acl_violation_hosts(hosts)
176
177 for host in hosts:
showardf8b19042009-05-12 17:22:49 +0000178 host.set_or_delete_attribute(attribute, value)
showard0957a842009-05-11 19:25:08 +0000179
180
mblighe8819cd2008-02-15 16:48:40 +0000181def delete_host(id):
jadmanski0afbb632008-06-06 21:10:57 +0000182 models.Host.smart_get(id).delete()
mblighe8819cd2008-02-15 16:48:40 +0000183
184
showard87cc38f2009-08-20 23:37:04 +0000185def get_hosts(multiple_labels=(), exclude_only_if_needed_labels=False,
showard8aa84fc2009-09-16 17:17:55 +0000186 exclude_atomic_group_hosts=False, valid_only=True, **filter_data):
showard87cc38f2009-08-20 23:37:04 +0000187 """
188 @param multiple_labels: match hosts in all of the labels given. Should
189 be a list of label names.
190 @param exclude_only_if_needed_labels: Exclude hosts with at least one
191 "only_if_needed" label applied.
192 @param exclude_atomic_group_hosts: Exclude hosts that have one or more
193 atomic group labels associated with them.
jadmanski0afbb632008-06-06 21:10:57 +0000194 """
showard43a3d262008-11-12 18:17:05 +0000195 hosts = rpc_utils.get_host_query(multiple_labels,
196 exclude_only_if_needed_labels,
showard87cc38f2009-08-20 23:37:04 +0000197 exclude_atomic_group_hosts,
showard8aa84fc2009-09-16 17:17:55 +0000198 valid_only, filter_data)
showard0957a842009-05-11 19:25:08 +0000199 hosts = list(hosts)
200 models.Host.objects.populate_relationships(hosts, models.Label,
201 'label_list')
202 models.Host.objects.populate_relationships(hosts, models.AclGroup,
203 'acl_list')
204 models.Host.objects.populate_relationships(hosts, models.HostAttribute,
205 'attribute_list')
showard43a3d262008-11-12 18:17:05 +0000206 host_dicts = []
207 for host_obj in hosts:
208 host_dict = host_obj.get_object_dict()
showard0957a842009-05-11 19:25:08 +0000209 host_dict['labels'] = [label.name for label in host_obj.label_list]
showard909c9142009-07-07 20:54:42 +0000210 host_dict['platform'], host_dict['atomic_group'] = (rpc_utils.
211 find_platform_and_atomic_group(host_obj))
showard0957a842009-05-11 19:25:08 +0000212 host_dict['acls'] = [acl.name for acl in host_obj.acl_list]
213 host_dict['attributes'] = dict((attribute.attribute, attribute.value)
214 for attribute in host_obj.attribute_list)
showard43a3d262008-11-12 18:17:05 +0000215 host_dicts.append(host_dict)
216 return rpc_utils.prepare_for_serialization(host_dicts)
mblighe8819cd2008-02-15 16:48:40 +0000217
218
showard87cc38f2009-08-20 23:37:04 +0000219def get_num_hosts(multiple_labels=(), exclude_only_if_needed_labels=False,
showard8aa84fc2009-09-16 17:17:55 +0000220 exclude_atomic_group_hosts=False, valid_only=True,
221 **filter_data):
showard87cc38f2009-08-20 23:37:04 +0000222 """
223 Same parameters as get_hosts().
224
225 @returns The number of matching hosts.
226 """
showard43a3d262008-11-12 18:17:05 +0000227 hosts = rpc_utils.get_host_query(multiple_labels,
228 exclude_only_if_needed_labels,
showard87cc38f2009-08-20 23:37:04 +0000229 exclude_atomic_group_hosts,
showard8aa84fc2009-09-16 17:17:55 +0000230 valid_only, filter_data)
showard43a3d262008-11-12 18:17:05 +0000231 return hosts.count()
showard1385b162008-03-13 15:59:40 +0000232
mblighe8819cd2008-02-15 16:48:40 +0000233
234# tests
235
showard909c7a62008-07-15 21:52:38 +0000236def add_test(name, test_type, path, author=None, dependencies=None,
showard3d9899a2008-07-31 02:11:58 +0000237 experimental=True, run_verify=None, test_class=None,
showard909c7a62008-07-15 21:52:38 +0000238 test_time=None, test_category=None, description=None,
239 sync_count=1):
jadmanski0afbb632008-06-06 21:10:57 +0000240 return models.Test.add_object(name=name, test_type=test_type, path=path,
showard909c7a62008-07-15 21:52:38 +0000241 author=author, dependencies=dependencies,
242 experimental=experimental,
243 run_verify=run_verify, test_time=test_time,
244 test_category=test_category,
245 sync_count=sync_count,
jadmanski0afbb632008-06-06 21:10:57 +0000246 test_class=test_class,
247 description=description).id
mblighe8819cd2008-02-15 16:48:40 +0000248
249
250def modify_test(id, **data):
jadmanski0afbb632008-06-06 21:10:57 +0000251 models.Test.smart_get(id).update_object(data)
mblighe8819cd2008-02-15 16:48:40 +0000252
253
254def delete_test(id):
jadmanski0afbb632008-06-06 21:10:57 +0000255 models.Test.smart_get(id).delete()
mblighe8819cd2008-02-15 16:48:40 +0000256
257
258def get_tests(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000259 return rpc_utils.prepare_for_serialization(
260 models.Test.list_objects(filter_data))
mblighe8819cd2008-02-15 16:48:40 +0000261
262
showard2b9a88b2008-06-13 20:55:03 +0000263# profilers
264
265def add_profiler(name, description=None):
266 return models.Profiler.add_object(name=name, description=description).id
267
268
269def modify_profiler(id, **data):
270 models.Profiler.smart_get(id).update_object(data)
271
272
273def delete_profiler(id):
274 models.Profiler.smart_get(id).delete()
275
276
277def get_profilers(**filter_data):
278 return rpc_utils.prepare_for_serialization(
279 models.Profiler.list_objects(filter_data))
280
281
mblighe8819cd2008-02-15 16:48:40 +0000282# users
283
284def add_user(login, access_level=None):
jadmanski0afbb632008-06-06 21:10:57 +0000285 return models.User.add_object(login=login, access_level=access_level).id
mblighe8819cd2008-02-15 16:48:40 +0000286
287
288def modify_user(id, **data):
jadmanski0afbb632008-06-06 21:10:57 +0000289 models.User.smart_get(id).update_object(data)
mblighe8819cd2008-02-15 16:48:40 +0000290
291
292def delete_user(id):
jadmanski0afbb632008-06-06 21:10:57 +0000293 models.User.smart_get(id).delete()
mblighe8819cd2008-02-15 16:48:40 +0000294
295
296def get_users(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000297 return rpc_utils.prepare_for_serialization(
298 models.User.list_objects(filter_data))
mblighe8819cd2008-02-15 16:48:40 +0000299
300
301# acl groups
302
303def add_acl_group(name, description=None):
showard04f2cd82008-07-25 20:53:31 +0000304 group = models.AclGroup.add_object(name=name, description=description)
showard64a95952010-01-13 21:27:16 +0000305 group.users.add(models.User.current_user())
showard04f2cd82008-07-25 20:53:31 +0000306 return group.id
mblighe8819cd2008-02-15 16:48:40 +0000307
308
309def modify_acl_group(id, **data):
showard04f2cd82008-07-25 20:53:31 +0000310 group = models.AclGroup.smart_get(id)
311 group.check_for_acl_violation_acl_group()
312 group.update_object(data)
313 group.add_current_user_if_empty()
mblighe8819cd2008-02-15 16:48:40 +0000314
315
316def acl_group_add_users(id, users):
jadmanski0afbb632008-06-06 21:10:57 +0000317 group = models.AclGroup.smart_get(id)
showard04f2cd82008-07-25 20:53:31 +0000318 group.check_for_acl_violation_acl_group()
showardbe3ec042008-11-12 18:16:07 +0000319 users = models.User.smart_get_bulk(users)
jadmanski0afbb632008-06-06 21:10:57 +0000320 group.users.add(*users)
mblighe8819cd2008-02-15 16:48:40 +0000321
322
323def acl_group_remove_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.remove(*users)
showard04f2cd82008-07-25 20:53:31 +0000328 group.add_current_user_if_empty()
mblighe8819cd2008-02-15 16:48:40 +0000329
330
331def acl_group_add_hosts(id, hosts):
jadmanski0afbb632008-06-06 21:10:57 +0000332 group = models.AclGroup.smart_get(id)
showard04f2cd82008-07-25 20:53:31 +0000333 group.check_for_acl_violation_acl_group()
showardbe3ec042008-11-12 18:16:07 +0000334 hosts = models.Host.smart_get_bulk(hosts)
jadmanski0afbb632008-06-06 21:10:57 +0000335 group.hosts.add(*hosts)
showard08f981b2008-06-24 21:59:03 +0000336 group.on_host_membership_change()
mblighe8819cd2008-02-15 16:48:40 +0000337
338
339def acl_group_remove_hosts(id, hosts):
jadmanski0afbb632008-06-06 21:10:57 +0000340 group = models.AclGroup.smart_get(id)
showard04f2cd82008-07-25 20:53:31 +0000341 group.check_for_acl_violation_acl_group()
showardbe3ec042008-11-12 18:16:07 +0000342 hosts = models.Host.smart_get_bulk(hosts)
jadmanski0afbb632008-06-06 21:10:57 +0000343 group.hosts.remove(*hosts)
showard08f981b2008-06-24 21:59:03 +0000344 group.on_host_membership_change()
mblighe8819cd2008-02-15 16:48:40 +0000345
346
347def delete_acl_group(id):
jadmanski0afbb632008-06-06 21:10:57 +0000348 models.AclGroup.smart_get(id).delete()
mblighe8819cd2008-02-15 16:48:40 +0000349
350
351def get_acl_groups(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000352 acl_groups = models.AclGroup.list_objects(filter_data)
353 for acl_group in acl_groups:
354 acl_group_obj = models.AclGroup.objects.get(id=acl_group['id'])
355 acl_group['users'] = [user.login
356 for user in acl_group_obj.users.all()]
357 acl_group['hosts'] = [host.hostname
358 for host in acl_group_obj.hosts.all()]
359 return rpc_utils.prepare_for_serialization(acl_groups)
mblighe8819cd2008-02-15 16:48:40 +0000360
361
362# jobs
363
mbligh120351e2009-01-24 01:40:45 +0000364def generate_control_file(tests=(), kernel=None, label=None, profilers=(),
showard91f85102009-10-12 20:34:52 +0000365 client_control_file='', use_container=False,
showard232b7ae2009-11-10 00:46:48 +0000366 profile_only=None, upload_kernel_config=False):
jadmanski0afbb632008-06-06 21:10:57 +0000367 """
mbligh120351e2009-01-24 01:40:45 +0000368 Generates a client-side control file to load a kernel and run tests.
369
370 @param tests List of tests to run.
mbligha3c58d22009-08-24 22:01:51 +0000371 @param kernel A list of kernel info dictionaries configuring which kernels
372 to boot for this job and other options for them
mbligh120351e2009-01-24 01:40:45 +0000373 @param label Name of label to grab kernel config from.
374 @param profilers List of profilers to activate during the job.
375 @param client_control_file The contents of a client-side control file to
376 run at the end of all tests. If this is supplied, all tests must be
377 client side.
378 TODO: in the future we should support server control files directly
379 to wrap with a kernel. That'll require changing the parameter
380 name and adding a boolean to indicate if it is a client or server
381 control file.
382 @param use_container unused argument today. TODO: Enable containers
383 on the host during a client side test.
showard91f85102009-10-12 20:34:52 +0000384 @param profile_only A boolean that indicates what default profile_only
385 mode to use in the control file. Passing None will generate a
386 control file that does not explcitly set the default mode at all.
showard232b7ae2009-11-10 00:46:48 +0000387 @param upload_kernel_config: if enabled it will generate server control
388 file code that uploads the kernel config file to the client and
389 tells the client of the new (local) path when compiling the kernel;
390 the tests must be server side tests
mbligh120351e2009-01-24 01:40:45 +0000391
392 @returns a dict with the following keys:
393 control_file: str, The control file text.
394 is_server: bool, is the control file a server-side control file?
395 synch_count: How many machines the job uses per autoserv execution.
396 synch_count == 1 means the job is asynchronous.
397 dependencies: A list of the names of labels on which the job depends.
398 """
showardd86debe2009-06-10 17:37:56 +0000399 if not tests and not client_control_file:
showard2bab8f42008-11-12 18:15:22 +0000400 return dict(control_file='', is_server=False, synch_count=1,
showard989f25d2008-10-01 11:38:11 +0000401 dependencies=[])
mblighe8819cd2008-02-15 16:48:40 +0000402
showard989f25d2008-10-01 11:38:11 +0000403 cf_info, test_objects, profiler_objects, label = (
showard2b9a88b2008-06-13 20:55:03 +0000404 rpc_utils.prepare_generate_control_file(tests, kernel, label,
405 profilers))
showard989f25d2008-10-01 11:38:11 +0000406 cf_info['control_file'] = control_file.generate_control(
mbligha3c58d22009-08-24 22:01:51 +0000407 tests=test_objects, kernels=kernel, platform=label,
mbligh120351e2009-01-24 01:40:45 +0000408 profilers=profiler_objects, is_server=cf_info['is_server'],
showard232b7ae2009-11-10 00:46:48 +0000409 client_control_file=client_control_file, profile_only=profile_only,
410 upload_kernel_config=upload_kernel_config)
showard989f25d2008-10-01 11:38:11 +0000411 return cf_info
mblighe8819cd2008-02-15 16:48:40 +0000412
413
jamesren4a41e012010-07-16 22:33:48 +0000414def create_parameterized_job(name, priority, test, parameters, kernel=None,
415 label=None, profilers=(), profiler_parameters=None,
416 use_container=False, profile_only=None,
417 upload_kernel_config=False, hosts=(),
418 meta_hosts=(), one_time_hosts=(),
419 atomic_group_name=None, synch_count=None,
420 is_template=False, timeout=None,
Simran Basi7e605742013-11-12 13:43:36 -0800421 timeout_mins=None, max_runtime_mins=None,
422 run_verify=False, email_list='', dependencies=(),
423 reboot_before=None, reboot_after=None,
424 parse_failed_repair=None, hostless=False,
425 keyvals=None, drone_set=None, run_reset=True):
jamesren4a41e012010-07-16 22:33:48 +0000426 """
427 Creates and enqueues a parameterized job.
428
429 Most parameters a combination of the parameters for generate_control_file()
430 and create_job(), with the exception of:
431
432 @param test name or ID of the test to run
433 @param parameters a map of parameter name ->
434 tuple of (param value, param type)
435 @param profiler_parameters a dictionary of parameters for the profilers:
436 key: profiler name
437 value: dict of param name -> tuple of
438 (param value,
439 param type)
440 """
441 # Save the values of the passed arguments here. What we're going to do with
442 # them is pass them all to rpc_utils.get_create_job_common_args(), which
443 # will extract the subset of these arguments that apply for
444 # rpc_utils.create_job_common(), which we then pass in to that function.
445 args = locals()
446
447 # Set up the parameterized job configs
448 test_obj = models.Test.smart_get(test)
Aviv Keshet3dd8beb2013-05-13 17:36:04 -0700449 control_type = test_obj.test_type
jamesren4a41e012010-07-16 22:33:48 +0000450
451 try:
452 label = models.Label.smart_get(label)
453 except models.Label.DoesNotExist:
454 label = None
455
456 kernel_objs = models.Kernel.create_kernels(kernel)
457 profiler_objs = [models.Profiler.smart_get(profiler)
458 for profiler in profilers]
459
460 parameterized_job = models.ParameterizedJob.objects.create(
461 test=test_obj, label=label, use_container=use_container,
462 profile_only=profile_only,
463 upload_kernel_config=upload_kernel_config)
464 parameterized_job.kernels.add(*kernel_objs)
465
466 for profiler in profiler_objs:
467 parameterized_profiler = models.ParameterizedJobProfiler.objects.create(
468 parameterized_job=parameterized_job,
469 profiler=profiler)
470 profiler_params = profiler_parameters.get(profiler.name, {})
471 for name, (value, param_type) in profiler_params.iteritems():
472 models.ParameterizedJobProfilerParameter.objects.create(
473 parameterized_job_profiler=parameterized_profiler,
474 parameter_name=name,
475 parameter_value=value,
476 parameter_type=param_type)
477
478 try:
479 for parameter in test_obj.testparameter_set.all():
480 if parameter.name in parameters:
481 param_value, param_type = parameters.pop(parameter.name)
482 parameterized_job.parameterizedjobparameter_set.create(
483 test_parameter=parameter, parameter_value=param_value,
484 parameter_type=param_type)
485
486 if parameters:
487 raise Exception('Extra parameters remain: %r' % parameters)
488
489 return rpc_utils.create_job_common(
490 parameterized_job=parameterized_job.id,
491 control_type=control_type,
492 **rpc_utils.get_create_job_common_args(args))
493 except:
494 parameterized_job.delete()
495 raise
496
497
showard12f3e322009-05-13 21:27:42 +0000498def create_job(name, priority, control_file, control_type,
499 hosts=(), meta_hosts=(), one_time_hosts=(),
500 atomic_group_name=None, synch_count=None, is_template=False,
Simran Basi7e605742013-11-12 13:43:36 -0800501 timeout=None, timeout_mins=None, max_runtime_mins=None,
502 run_verify=False, email_list='', dependencies=(),
503 reboot_before=None, reboot_after=None, parse_failed_repair=None,
504 hostless=False, keyvals=None, drone_set=None, image=None,
505 parent_job_id=None, test_retry=0, run_reset=True):
jadmanski0afbb632008-06-06 21:10:57 +0000506 """\
507 Create and enqueue a job.
mblighe8819cd2008-02-15 16:48:40 +0000508
showarda1e74b32009-05-12 17:32:04 +0000509 @param name name of this job
Alex Miller7d658cf2013-09-04 16:00:35 -0700510 @param priority Integer priority of this job. Higher is more important.
showarda1e74b32009-05-12 17:32:04 +0000511 @param control_file String contents of the control file.
512 @param control_type Type of control file, Client or Server.
513 @param synch_count How many machines the job uses per autoserv execution.
514 synch_count == 1 means the job is asynchronous. If an atomic group is
515 given this value is treated as a minimum.
516 @param is_template If true then create a template job.
517 @param timeout Hours after this call returns until the job times out.
Simran Basi7e605742013-11-12 13:43:36 -0800518 @param timeout_mins Minutes after this call returns until the job times
519 out.
Simran Basi34217022012-11-06 13:43:15 -0800520 @param max_runtime_mins Minutes from job starting time until job times out
showarda1e74b32009-05-12 17:32:04 +0000521 @param run_verify Should the host be verified before running the test?
522 @param email_list String containing emails to mail when the job is done
523 @param dependencies List of label names on which this job depends
524 @param reboot_before Never, If dirty, or Always
525 @param reboot_after Never, If all tests passed, or Always
526 @param parse_failed_repair if true, results of failed repairs launched by
527 this job will be parsed as part of the job.
showarda9545c02009-12-18 22:44:26 +0000528 @param hostless if true, create a hostless job
showardc1a98d12010-01-15 00:22:22 +0000529 @param keyvals dict of keyvals to associate with the job
showarda1e74b32009-05-12 17:32:04 +0000530
531 @param hosts List of hosts to run job on.
532 @param meta_hosts List where each entry is a label name, and for each entry
533 one host will be chosen from that label to run the job on.
534 @param one_time_hosts List of hosts not in the database to run the job on.
535 @param atomic_group_name The name of an atomic group to schedule the job on.
jamesren76fcf192010-04-21 20:39:50 +0000536 @param drone_set The name of the drone set to run this test on.
Paul Pendlebury5a8c6ad2011-02-01 07:20:17 -0800537 @param image OS image to install before running job.
Aviv Keshet0b9cfc92013-02-05 11:36:02 -0800538 @param parent_job_id id of a job considered to be parent of created job.
Aviv Keshetcd1ff9b2013-03-01 14:55:19 -0800539 @param test_retry: Number of times to retry test if the test did not
540 complete successfully. (optional, default: 0)
Dan Shi07e09af2013-04-12 09:31:29 -0700541 @param run_reset: Should the host be reset before running the test?
showardc92da832009-04-07 18:14:34 +0000542
543 @returns The created Job id number.
jadmanski0afbb632008-06-06 21:10:57 +0000544 """
Alex Millera713e252013-03-01 10:45:44 -0800545 # Force control files to only contain ascii characters.
546 try:
547 control_file.encode('ascii')
548 except UnicodeDecodeError as e:
549 raise error.ControlFileMalformed(str(e))
550
Paul Pendlebury5a8c6ad2011-02-01 07:20:17 -0800551 if image is None:
552 return rpc_utils.create_job_common(
553 **rpc_utils.get_create_job_common_args(locals()))
554
555 # When image is supplied use a known parameterized test already in the
556 # database to pass the OS image path from the front end, through the
557 # scheduler, and finally to autoserv as the --image parameter.
558
559 # The test autoupdate_ParameterizedJob is in afe_autotests and used to
560 # instantiate a Test object and from there a ParameterizedJob.
561 known_test_obj = models.Test.smart_get('autoupdate_ParameterizedJob')
562 known_parameterized_job = models.ParameterizedJob.objects.create(
563 test=known_test_obj)
564
565 # autoupdate_ParameterizedJob has a single parameter, the image parameter,
566 # stored in the table afe_test_parameters. We retrieve and set this
567 # instance of the parameter to the OS image path.
Eric Lid23bc192011-02-09 14:38:57 -0800568 image_parameter = known_test_obj.testparameter_set.get(test=known_test_obj,
569 name='image')
Paul Pendlebury5a8c6ad2011-02-01 07:20:17 -0800570 known_parameterized_job.parameterizedjobparameter_set.create(
571 test_parameter=image_parameter, parameter_value=image,
572 parameter_type='string')
573
574 # By passing a parameterized_job to create_job_common the job entry in
575 # the afe_jobs table will have the field parameterized_job_id set.
576 # The scheduler uses this id in the afe_parameterized_jobs table to
577 # match this job to our known test, and then with the
578 # afe_parameterized_job_parameters table to get the actual image path.
jamesren4a41e012010-07-16 22:33:48 +0000579 return rpc_utils.create_job_common(
Paul Pendlebury5a8c6ad2011-02-01 07:20:17 -0800580 parameterized_job=known_parameterized_job.id,
jamesren4a41e012010-07-16 22:33:48 +0000581 **rpc_utils.get_create_job_common_args(locals()))
mblighe8819cd2008-02-15 16:48:40 +0000582
583
showard9dbdcda2008-10-14 17:34:36 +0000584def abort_host_queue_entries(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000585 """\
showard9dbdcda2008-10-14 17:34:36 +0000586 Abort a set of host queue entries.
jadmanski0afbb632008-06-06 21:10:57 +0000587 """
showard9dbdcda2008-10-14 17:34:36 +0000588 query = models.HostQueueEntry.query_objects(filter_data)
beepsfaecbce2013-10-29 11:35:10 -0700589
590 # Dont allow aborts on:
591 # 1. Jobs that have already completed (whether or not they were aborted)
592 # 2. Jobs that we have already been aborted (but may not have completed)
593 query = query.filter(complete=False).filter(aborted=False)
showarddc817512008-11-12 18:16:41 +0000594 models.AclGroup.check_abort_permissions(query)
showard9dbdcda2008-10-14 17:34:36 +0000595 host_queue_entries = list(query.select_related())
showard2bab8f42008-11-12 18:15:22 +0000596 rpc_utils.check_abort_synchronous_jobs(host_queue_entries)
mblighe8819cd2008-02-15 16:48:40 +0000597
Simran Basic1b26762013-06-26 14:23:21 -0700598 models.HostQueueEntry.abort_host_queue_entries(host_queue_entries)
showard9d821ab2008-07-11 16:54:29 +0000599
600
beeps8bb1f7d2013-08-05 01:30:09 -0700601def abort_special_tasks(**filter_data):
602 """\
603 Abort the special task, or tasks, specified in the filter.
604 """
605 query = models.SpecialTask.query_objects(filter_data)
606 special_tasks = query.filter(is_active=True)
607 for task in special_tasks:
608 task.abort()
609
610
Simran Basi73dae552013-02-25 14:57:46 -0800611def _call_special_tasks_on_hosts(task, hosts):
612 """\
613 Schedules a set of hosts for a special task.
614
615 @returns A list of hostnames that a special task was created for.
616 """
617 models.AclGroup.check_for_acl_violation_hosts(hosts)
618 for host in hosts:
619 models.SpecialTask.schedule_special_task(host, task)
620 return list(sorted(host.hostname for host in hosts))
621
622
showard1ff7b2e2009-05-15 23:17:18 +0000623def reverify_hosts(**filter_data):
624 """\
625 Schedules a set of hosts for verify.
mbligh4e545a52009-12-19 05:30:39 +0000626
627 @returns A list of hostnames that a verify task was created for.
showard1ff7b2e2009-05-15 23:17:18 +0000628 """
Simran Basi73dae552013-02-25 14:57:46 -0800629 return _call_special_tasks_on_hosts(models.SpecialTask.Task.VERIFY,
630 models.Host.query_objects(filter_data))
631
632
633def repair_hosts(**filter_data):
634 """\
635 Schedules a set of hosts for repair.
636
637 @returns A list of hostnames that a repair task was created for.
638 """
639 return _call_special_tasks_on_hosts(models.SpecialTask.Task.REPAIR,
640 models.Host.query_objects(filter_data))
showard1ff7b2e2009-05-15 23:17:18 +0000641
642
mblighe8819cd2008-02-15 16:48:40 +0000643def get_jobs(not_yet_run=False, running=False, finished=False, **filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000644 """\
645 Extra filter args for get_jobs:
646 -not_yet_run: Include only jobs that have not yet started running.
647 -running: Include only jobs that have start running but for which not
648 all hosts have completed.
649 -finished: Include only jobs for which all hosts have completed (or
650 aborted).
651 At most one of these three fields should be specified.
652 """
653 filter_data['extra_args'] = rpc_utils.extra_job_filters(not_yet_run,
654 running,
655 finished)
showard0957a842009-05-11 19:25:08 +0000656 job_dicts = []
657 jobs = list(models.Job.query_objects(filter_data))
658 models.Job.objects.populate_relationships(jobs, models.Label,
659 'dependencies')
showardc1a98d12010-01-15 00:22:22 +0000660 models.Job.objects.populate_relationships(jobs, models.JobKeyval, 'keyvals')
showard0957a842009-05-11 19:25:08 +0000661 for job in jobs:
662 job_dict = job.get_object_dict()
663 job_dict['dependencies'] = ','.join(label.name
664 for label in job.dependencies)
showardc1a98d12010-01-15 00:22:22 +0000665 job_dict['keyvals'] = dict((keyval.key, keyval.value)
666 for keyval in job.keyvals)
Eric Lid23bc192011-02-09 14:38:57 -0800667 if job.parameterized_job:
668 job_dict['image'] = get_parameterized_autoupdate_image_url(job)
showard0957a842009-05-11 19:25:08 +0000669 job_dicts.append(job_dict)
670 return rpc_utils.prepare_for_serialization(job_dicts)
mblighe8819cd2008-02-15 16:48:40 +0000671
672
673def get_num_jobs(not_yet_run=False, running=False, finished=False,
jadmanski0afbb632008-06-06 21:10:57 +0000674 **filter_data):
675 """\
676 See get_jobs() for documentation of extra filter parameters.
677 """
678 filter_data['extra_args'] = rpc_utils.extra_job_filters(not_yet_run,
679 running,
680 finished)
681 return models.Job.query_count(filter_data)
mblighe8819cd2008-02-15 16:48:40 +0000682
683
mblighe8819cd2008-02-15 16:48:40 +0000684def get_jobs_summary(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000685 """\
showarda8709c52008-07-03 19:44:54 +0000686 Like get_jobs(), but adds a 'status_counts' field, which is a dictionary
jadmanski0afbb632008-06-06 21:10:57 +0000687 mapping status strings to the number of hosts currently with that
688 status, i.e. {'Queued' : 4, 'Running' : 2}.
689 """
690 jobs = get_jobs(**filter_data)
691 ids = [job['id'] for job in jobs]
692 all_status_counts = models.Job.objects.get_status_counts(ids)
693 for job in jobs:
694 job['status_counts'] = all_status_counts[job['id']]
695 return rpc_utils.prepare_for_serialization(jobs)
mblighe8819cd2008-02-15 16:48:40 +0000696
697
showarda965cef2009-05-15 23:17:41 +0000698def get_info_for_clone(id, preserve_metahosts, queue_entry_filter_data=None):
showarda8709c52008-07-03 19:44:54 +0000699 """\
700 Retrieves all the information needed to clone a job.
701 """
showarda8709c52008-07-03 19:44:54 +0000702 job = models.Job.objects.get(id=id)
showard29f7cd22009-04-29 21:16:24 +0000703 job_info = rpc_utils.get_job_info(job,
showarda965cef2009-05-15 23:17:41 +0000704 preserve_metahosts,
705 queue_entry_filter_data)
showard945072f2008-09-03 20:34:59 +0000706
showardd9992fe2008-07-31 02:15:03 +0000707 host_dicts = []
showard29f7cd22009-04-29 21:16:24 +0000708 for host in job_info['hosts']:
709 host_dict = get_hosts(id=host.id)[0]
710 other_labels = host_dict['labels']
711 if host_dict['platform']:
712 other_labels.remove(host_dict['platform'])
713 host_dict['other_labels'] = ', '.join(other_labels)
showardd9992fe2008-07-31 02:15:03 +0000714 host_dicts.append(host_dict)
showarda8709c52008-07-03 19:44:54 +0000715
showard29f7cd22009-04-29 21:16:24 +0000716 for host in job_info['one_time_hosts']:
717 host_dict = dict(hostname=host.hostname,
718 id=host.id,
719 platform='(one-time host)',
720 locked_text='')
721 host_dicts.append(host_dict)
showarda8709c52008-07-03 19:44:54 +0000722
showard4d077562009-05-08 18:24:36 +0000723 # convert keys from Label objects to strings (names of labels)
showard29f7cd22009-04-29 21:16:24 +0000724 meta_host_counts = dict((meta_host.name, count) for meta_host, count
showard4d077562009-05-08 18:24:36 +0000725 in job_info['meta_host_counts'].iteritems())
showard29f7cd22009-04-29 21:16:24 +0000726
727 info = dict(job=job.get_object_dict(),
728 meta_host_counts=meta_host_counts,
729 hosts=host_dicts)
730 info['job']['dependencies'] = job_info['dependencies']
731 if job_info['atomic_group']:
732 info['atomic_group_name'] = (job_info['atomic_group']).name
733 else:
734 info['atomic_group_name'] = None
jamesren2275ef12010-04-12 18:25:06 +0000735 info['hostless'] = job_info['hostless']
jamesren76fcf192010-04-21 20:39:50 +0000736 info['drone_set'] = job.drone_set and job.drone_set.name
showarda8709c52008-07-03 19:44:54 +0000737
Eric Lid23bc192011-02-09 14:38:57 -0800738 if job.parameterized_job:
739 info['job']['image'] = get_parameterized_autoupdate_image_url(job)
740
showarda8709c52008-07-03 19:44:54 +0000741 return rpc_utils.prepare_for_serialization(info)
742
743
showard34dc5fa2008-04-24 20:58:40 +0000744# host queue entries
745
746def get_host_queue_entries(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000747 """\
showardc92da832009-04-07 18:14:34 +0000748 @returns A sequence of nested dictionaries of host and job information.
jadmanski0afbb632008-06-06 21:10:57 +0000749 """
showardc92da832009-04-07 18:14:34 +0000750 return rpc_utils.prepare_rows_as_nested_dicts(
751 models.HostQueueEntry.query_objects(filter_data),
752 ('host', 'atomic_group', 'job'))
showard34dc5fa2008-04-24 20:58:40 +0000753
754
755def get_num_host_queue_entries(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000756 """\
757 Get the number of host queue entries associated with this job.
758 """
759 return models.HostQueueEntry.query_count(filter_data)
showard34dc5fa2008-04-24 20:58:40 +0000760
761
showard1e935f12008-07-11 00:11:36 +0000762def get_hqe_percentage_complete(**filter_data):
763 """
showardc92da832009-04-07 18:14:34 +0000764 Computes the fraction of host queue entries matching the given filter data
showard1e935f12008-07-11 00:11:36 +0000765 that are complete.
766 """
767 query = models.HostQueueEntry.query_objects(filter_data)
768 complete_count = query.filter(complete=True).count()
769 total_count = query.count()
770 if total_count == 0:
771 return 1
772 return float(complete_count) / total_count
773
774
showard1a5a4082009-07-28 20:01:37 +0000775# special tasks
776
777def get_special_tasks(**filter_data):
778 return rpc_utils.prepare_rows_as_nested_dicts(
779 models.SpecialTask.query_objects(filter_data),
780 ('host', 'queue_entry'))
781
782
showardc0ac3a72009-07-08 21:14:45 +0000783# support for host detail view
784
785def get_host_queue_entries_and_special_tasks(hostname, query_start=None,
786 query_limit=None):
787 """
788 @returns an interleaved list of HostQueueEntries and SpecialTasks,
789 in approximate run order. each dict contains keys for type, host,
790 job, status, started_on, execution_path, and ID.
791 """
792 total_limit = None
793 if query_limit is not None:
794 total_limit = query_start + query_limit
795 filter_data = {'host__hostname': hostname,
796 'query_limit': total_limit,
797 'sort_by': ['-id']}
798
799 queue_entries = list(models.HostQueueEntry.query_objects(filter_data))
800 special_tasks = list(models.SpecialTask.query_objects(filter_data))
801
802 interleaved_entries = rpc_utils.interleave_entries(queue_entries,
803 special_tasks)
804 if query_start is not None:
805 interleaved_entries = interleaved_entries[query_start:]
806 if query_limit is not None:
807 interleaved_entries = interleaved_entries[:query_limit]
808 return rpc_utils.prepare_for_serialization(interleaved_entries)
809
810
811def get_num_host_queue_entries_and_special_tasks(hostname):
812 filter_data = {'host__hostname': hostname}
813 return (models.HostQueueEntry.query_count(filter_data)
814 + models.SpecialTask.query_count(filter_data))
815
816
showard29f7cd22009-04-29 21:16:24 +0000817# recurring run
818
819def get_recurring(**filter_data):
820 return rpc_utils.prepare_rows_as_nested_dicts(
821 models.RecurringRun.query_objects(filter_data),
822 ('job', 'owner'))
823
824
825def get_num_recurring(**filter_data):
826 return models.RecurringRun.query_count(filter_data)
827
828
829def delete_recurring_runs(**filter_data):
830 to_delete = models.RecurringRun.query_objects(filter_data)
831 to_delete.delete()
832
833
834def create_recurring_run(job_id, start_date, loop_period, loop_count):
showard64a95952010-01-13 21:27:16 +0000835 owner = models.User.current_user().login
showard29f7cd22009-04-29 21:16:24 +0000836 job = models.Job.objects.get(id=job_id)
837 return job.create_recurring_job(start_date=start_date,
838 loop_period=loop_period,
839 loop_count=loop_count,
840 owner=owner)
841
842
mblighe8819cd2008-02-15 16:48:40 +0000843# other
844
showarde0b63622008-08-04 20:58:47 +0000845def echo(data=""):
846 """\
847 Returns a passed in string. For doing a basic test to see if RPC calls
848 can successfully be made.
849 """
850 return data
851
852
showardb7a52fd2009-04-27 20:10:56 +0000853def get_motd():
854 """\
855 Returns the message of the day as a string.
856 """
857 return rpc_utils.get_motd()
858
859
mblighe8819cd2008-02-15 16:48:40 +0000860def get_static_data():
jadmanski0afbb632008-06-06 21:10:57 +0000861 """\
862 Returns a dictionary containing a bunch of data that shouldn't change
863 often and is otherwise inaccessible. This includes:
showardc92da832009-04-07 18:14:34 +0000864
865 priorities: List of job priority choices.
866 default_priority: Default priority value for new jobs.
867 users: Sorted list of all users.
868 labels: Sorted list of all labels.
869 atomic_groups: Sorted list of all atomic groups.
870 tests: Sorted list of all tests.
871 profilers: Sorted list of all profilers.
872 current_user: Logged-in username.
873 host_statuses: Sorted list of possible Host statuses.
874 job_statuses: Sorted list of possible HostQueueEntry statuses.
Simran Basi7e605742013-11-12 13:43:36 -0800875 job_timeout_default: The default job timeout length in minutes.
showarda1e74b32009-05-12 17:32:04 +0000876 parse_failed_repair_default: Default value for the parse_failed_repair job
877 option.
showardc92da832009-04-07 18:14:34 +0000878 reboot_before_options: A list of valid RebootBefore string enums.
879 reboot_after_options: A list of valid RebootAfter string enums.
880 motd: Server's message of the day.
881 status_dictionary: A mapping from one word job status names to a more
882 informative description.
jadmanski0afbb632008-06-06 21:10:57 +0000883 """
showard21baa452008-10-21 00:08:39 +0000884
885 job_fields = models.Job.get_field_dict()
jamesren76fcf192010-04-21 20:39:50 +0000886 default_drone_set_name = models.DroneSet.default_drone_set_name()
887 drone_sets = ([default_drone_set_name] +
888 sorted(drone_set.name for drone_set in
889 models.DroneSet.objects.exclude(
890 name=default_drone_set_name)))
showard21baa452008-10-21 00:08:39 +0000891
jadmanski0afbb632008-06-06 21:10:57 +0000892 result = {}
Alex Miller7d658cf2013-09-04 16:00:35 -0700893 result['priorities'] = priorities.Priority.choices()
894 default_priority = priorities.Priority.DEFAULT
895 result['default_priority'] = 'Default'
896 result['max_schedulable_priority'] = priorities.Priority.DEFAULT
jadmanski0afbb632008-06-06 21:10:57 +0000897 result['users'] = get_users(sort_by=['login'])
898 result['labels'] = get_labels(sort_by=['-platform', 'name'])
showardc92da832009-04-07 18:14:34 +0000899 result['atomic_groups'] = get_atomic_groups(sort_by=['name'])
jadmanski0afbb632008-06-06 21:10:57 +0000900 result['tests'] = get_tests(sort_by=['name'])
showard2b9a88b2008-06-13 20:55:03 +0000901 result['profilers'] = get_profilers(sort_by=['name'])
showard0fc38302008-10-23 00:44:07 +0000902 result['current_user'] = rpc_utils.prepare_for_serialization(
showard64a95952010-01-13 21:27:16 +0000903 models.User.current_user().get_object_dict())
showard2b9a88b2008-06-13 20:55:03 +0000904 result['host_statuses'] = sorted(models.Host.Status.names)
mbligh5a198b92008-12-11 19:33:29 +0000905 result['job_statuses'] = sorted(models.HostQueueEntry.Status.names)
Simran Basi7e605742013-11-12 13:43:36 -0800906 result['job_timeout_mins_default'] = models.Job.DEFAULT_TIMEOUT_MINS
Simran Basi34217022012-11-06 13:43:15 -0800907 result['job_max_runtime_mins_default'] = (
908 models.Job.DEFAULT_MAX_RUNTIME_MINS)
showarda1e74b32009-05-12 17:32:04 +0000909 result['parse_failed_repair_default'] = bool(
910 models.Job.DEFAULT_PARSE_FAILED_REPAIR)
jamesrendd855242010-03-02 22:23:44 +0000911 result['reboot_before_options'] = model_attributes.RebootBefore.names
912 result['reboot_after_options'] = model_attributes.RebootAfter.names
showard8fbae652009-01-20 23:23:10 +0000913 result['motd'] = rpc_utils.get_motd()
jamesren76fcf192010-04-21 20:39:50 +0000914 result['drone_sets_enabled'] = models.DroneSet.drone_sets_enabled()
915 result['drone_sets'] = drone_sets
jamesren4a41e012010-07-16 22:33:48 +0000916 result['parameterized_jobs'] = models.Job.parameterized_jobs_enabled()
showard8ac29b42008-07-17 17:01:55 +0000917
showardd3dc1992009-04-22 21:01:40 +0000918 result['status_dictionary'] = {"Aborted": "Aborted",
showard8ac29b42008-07-17 17:01:55 +0000919 "Verifying": "Verifying Host",
Alex Millerdfff2fd2013-05-28 13:05:06 -0700920 "Provisioning": "Provisioning Host",
showard8ac29b42008-07-17 17:01:55 +0000921 "Pending": "Waiting on other hosts",
922 "Running": "Running autoserv",
923 "Completed": "Autoserv completed",
924 "Failed": "Failed to complete",
showardd823b362008-07-24 16:35:46 +0000925 "Queued": "Queued",
showard5deb6772008-11-04 21:54:33 +0000926 "Starting": "Next in host's queue",
927 "Stopped": "Other host(s) failed verify",
showardd3dc1992009-04-22 21:01:40 +0000928 "Parsing": "Awaiting parse of final results",
showard29f7cd22009-04-29 21:16:24 +0000929 "Gathering": "Gathering log files",
showard8cc058f2009-09-08 16:26:33 +0000930 "Template": "Template job for recurring run",
mbligh4608b002010-01-05 18:22:35 +0000931 "Waiting": "Waiting for scheduler action",
Dan Shi07e09af2013-04-12 09:31:29 -0700932 "Archiving": "Archiving results",
933 "Resetting": "Resetting hosts"}
jadmanski0afbb632008-06-06 21:10:57 +0000934 return result
showard29f7cd22009-04-29 21:16:24 +0000935
936
937def get_server_time():
938 return datetime.datetime.now().strftime("%Y-%m-%d %H:%M")