blob: f9d17e8b463c2eb212698426bea8bc5c5d9cc76a [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 Millera713e252013-03-01 10:45:44 -080036from autotest_lib.client.common_lib import error
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
Dan Shi4df39252013-03-19 13:19:45 -070039from autotest_lib.site_utils.graphite import stats
Aviv Keshet3dd8beb2013-05-13 17:36:04 -070040from autotest_lib.client.common_lib import control_data
mblighe8819cd2008-02-15 16:48:40 +000041
Eric Lid23bc192011-02-09 14:38:57 -080042def get_parameterized_autoupdate_image_url(job):
43 """Get the parameterized autoupdate image url from a parameterized job."""
44 known_test_obj = models.Test.smart_get('autoupdate_ParameterizedJob')
45 image_parameter = known_test_obj.testparameter_set.get(test=known_test_obj,
46 name='image')
47 para_set = job.parameterized_job.parameterizedjobparameter_set
48 job_test_para = para_set.get(test_parameter=image_parameter)
49 return job_test_para.parameter_value
50
51
mblighe8819cd2008-02-15 16:48:40 +000052# labels
53
showard989f25d2008-10-01 11:38:11 +000054def add_label(name, kernel_config=None, platform=None, only_if_needed=None):
showardc92da832009-04-07 18:14:34 +000055 return models.Label.add_object(
56 name=name, kernel_config=kernel_config, platform=platform,
57 only_if_needed=only_if_needed).id
mblighe8819cd2008-02-15 16:48:40 +000058
59
60def modify_label(id, **data):
jadmanski0afbb632008-06-06 21:10:57 +000061 models.Label.smart_get(id).update_object(data)
mblighe8819cd2008-02-15 16:48:40 +000062
63
64def delete_label(id):
jadmanski0afbb632008-06-06 21:10:57 +000065 models.Label.smart_get(id).delete()
mblighe8819cd2008-02-15 16:48:40 +000066
67
showardbbabf502008-06-06 00:02:02 +000068def label_add_hosts(id, hosts):
showardbe3ec042008-11-12 18:16:07 +000069 host_objs = models.Host.smart_get_bulk(hosts)
showardcafd16e2009-05-29 18:37:49 +000070 label = models.Label.smart_get(id)
71 if label.platform:
72 models.Host.check_no_platform(host_objs)
73 label.host_set.add(*host_objs)
showardbbabf502008-06-06 00:02:02 +000074
75
76def label_remove_hosts(id, hosts):
showardbe3ec042008-11-12 18:16:07 +000077 host_objs = models.Host.smart_get_bulk(hosts)
jadmanski0afbb632008-06-06 21:10:57 +000078 models.Label.smart_get(id).host_set.remove(*host_objs)
showardbbabf502008-06-06 00:02:02 +000079
80
mblighe8819cd2008-02-15 16:48:40 +000081def get_labels(**filter_data):
showardc92da832009-04-07 18:14:34 +000082 """\
83 @returns A sequence of nested dictionaries of label information.
84 """
85 return rpc_utils.prepare_rows_as_nested_dicts(
86 models.Label.query_objects(filter_data),
87 ('atomic_group',))
88
89
90# atomic groups
91
showarde9450c92009-06-30 01:58:52 +000092def add_atomic_group(name, max_number_of_machines=None, description=None):
showardc92da832009-04-07 18:14:34 +000093 return models.AtomicGroup.add_object(
94 name=name, max_number_of_machines=max_number_of_machines,
95 description=description).id
96
97
98def modify_atomic_group(id, **data):
99 models.AtomicGroup.smart_get(id).update_object(data)
100
101
102def delete_atomic_group(id):
103 models.AtomicGroup.smart_get(id).delete()
104
105
106def atomic_group_add_labels(id, labels):
107 label_objs = models.Label.smart_get_bulk(labels)
108 models.AtomicGroup.smart_get(id).label_set.add(*label_objs)
109
110
111def atomic_group_remove_labels(id, labels):
112 label_objs = models.Label.smart_get_bulk(labels)
113 models.AtomicGroup.smart_get(id).label_set.remove(*label_objs)
114
115
116def get_atomic_groups(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000117 return rpc_utils.prepare_for_serialization(
showardc92da832009-04-07 18:14:34 +0000118 models.AtomicGroup.list_objects(filter_data))
mblighe8819cd2008-02-15 16:48:40 +0000119
120
121# hosts
122
showarddf062562008-07-03 19:56:37 +0000123def add_host(hostname, status=None, locked=None, protection=None):
jadmanski0afbb632008-06-06 21:10:57 +0000124 return models.Host.add_object(hostname=hostname, status=status,
showarddf062562008-07-03 19:56:37 +0000125 locked=locked, protection=protection).id
mblighe8819cd2008-02-15 16:48:40 +0000126
127
128def modify_host(id, **data):
showardbe0d8692009-08-20 23:42:44 +0000129 rpc_utils.check_modify_host(data)
showardce7c0922009-09-11 18:39:24 +0000130 host = models.Host.smart_get(id)
131 rpc_utils.check_modify_host_locking(host, data)
132 host.update_object(data)
mblighe8819cd2008-02-15 16:48:40 +0000133
134
showard276f9442009-05-20 00:33:16 +0000135def modify_hosts(host_filter_data, update_data):
136 """
showardbe0d8692009-08-20 23:42:44 +0000137 @param host_filter_data: Filters out which hosts to modify.
138 @param update_data: A dictionary with the changes to make to the hosts.
showard276f9442009-05-20 00:33:16 +0000139 """
showardbe0d8692009-08-20 23:42:44 +0000140 rpc_utils.check_modify_host(update_data)
showard276f9442009-05-20 00:33:16 +0000141 hosts = models.Host.query_objects(host_filter_data)
Alex Miller9658a952013-05-14 16:40:02 -0700142 # Check all hosts before changing data for exception safety.
143 for host in hosts:
144 rpc_utils.check_modify_host_locking(host, update_data)
showard276f9442009-05-20 00:33:16 +0000145 for host in hosts:
146 host.update_object(update_data)
147
148
mblighe8819cd2008-02-15 16:48:40 +0000149def host_add_labels(id, labels):
showardbe3ec042008-11-12 18:16:07 +0000150 labels = models.Label.smart_get_bulk(labels)
showardcafd16e2009-05-29 18:37:49 +0000151 host = models.Host.smart_get(id)
152
153 platforms = [label.name for label in labels if label.platform]
154 if len(platforms) > 1:
155 raise model_logic.ValidationError(
156 {'labels': 'Adding more than one platform label: %s' %
157 ', '.join(platforms)})
158 if len(platforms) == 1:
159 models.Host.check_no_platform([host])
160 host.labels.add(*labels)
mblighe8819cd2008-02-15 16:48:40 +0000161
162
163def host_remove_labels(id, labels):
showardbe3ec042008-11-12 18:16:07 +0000164 labels = models.Label.smart_get_bulk(labels)
jadmanski0afbb632008-06-06 21:10:57 +0000165 models.Host.smart_get(id).labels.remove(*labels)
mblighe8819cd2008-02-15 16:48:40 +0000166
167
showard0957a842009-05-11 19:25:08 +0000168def set_host_attribute(attribute, value, **host_filter_data):
169 """
170 @param attribute string name of attribute
171 @param value string, or None to delete an attribute
172 @param host_filter_data filter data to apply to Hosts to choose hosts to act
173 upon
174 """
175 assert host_filter_data # disallow accidental actions on all hosts
176 hosts = models.Host.query_objects(host_filter_data)
177 models.AclGroup.check_for_acl_violation_hosts(hosts)
178
179 for host in hosts:
showardf8b19042009-05-12 17:22:49 +0000180 host.set_or_delete_attribute(attribute, value)
showard0957a842009-05-11 19:25:08 +0000181
182
mblighe8819cd2008-02-15 16:48:40 +0000183def delete_host(id):
jadmanski0afbb632008-06-06 21:10:57 +0000184 models.Host.smart_get(id).delete()
mblighe8819cd2008-02-15 16:48:40 +0000185
186
showard87cc38f2009-08-20 23:37:04 +0000187def get_hosts(multiple_labels=(), exclude_only_if_needed_labels=False,
showard8aa84fc2009-09-16 17:17:55 +0000188 exclude_atomic_group_hosts=False, valid_only=True, **filter_data):
showard87cc38f2009-08-20 23:37:04 +0000189 """
190 @param multiple_labels: match hosts in all of the labels given. Should
191 be a list of label names.
192 @param exclude_only_if_needed_labels: Exclude hosts with at least one
193 "only_if_needed" label applied.
194 @param exclude_atomic_group_hosts: Exclude hosts that have one or more
195 atomic group labels associated with them.
jadmanski0afbb632008-06-06 21:10:57 +0000196 """
showard43a3d262008-11-12 18:17:05 +0000197 hosts = rpc_utils.get_host_query(multiple_labels,
198 exclude_only_if_needed_labels,
showard87cc38f2009-08-20 23:37:04 +0000199 exclude_atomic_group_hosts,
showard8aa84fc2009-09-16 17:17:55 +0000200 valid_only, filter_data)
showard0957a842009-05-11 19:25:08 +0000201 hosts = list(hosts)
202 models.Host.objects.populate_relationships(hosts, models.Label,
203 'label_list')
204 models.Host.objects.populate_relationships(hosts, models.AclGroup,
205 'acl_list')
206 models.Host.objects.populate_relationships(hosts, models.HostAttribute,
207 'attribute_list')
showard43a3d262008-11-12 18:17:05 +0000208 host_dicts = []
209 for host_obj in hosts:
210 host_dict = host_obj.get_object_dict()
showard0957a842009-05-11 19:25:08 +0000211 host_dict['labels'] = [label.name for label in host_obj.label_list]
showard909c9142009-07-07 20:54:42 +0000212 host_dict['platform'], host_dict['atomic_group'] = (rpc_utils.
213 find_platform_and_atomic_group(host_obj))
showard0957a842009-05-11 19:25:08 +0000214 host_dict['acls'] = [acl.name for acl in host_obj.acl_list]
215 host_dict['attributes'] = dict((attribute.attribute, attribute.value)
216 for attribute in host_obj.attribute_list)
showard43a3d262008-11-12 18:17:05 +0000217 host_dicts.append(host_dict)
218 return rpc_utils.prepare_for_serialization(host_dicts)
mblighe8819cd2008-02-15 16:48:40 +0000219
220
showard87cc38f2009-08-20 23:37:04 +0000221def get_num_hosts(multiple_labels=(), exclude_only_if_needed_labels=False,
showard8aa84fc2009-09-16 17:17:55 +0000222 exclude_atomic_group_hosts=False, valid_only=True,
223 **filter_data):
showard87cc38f2009-08-20 23:37:04 +0000224 """
225 Same parameters as get_hosts().
226
227 @returns The number of matching hosts.
228 """
showard43a3d262008-11-12 18:17:05 +0000229 hosts = rpc_utils.get_host_query(multiple_labels,
230 exclude_only_if_needed_labels,
showard87cc38f2009-08-20 23:37:04 +0000231 exclude_atomic_group_hosts,
showard8aa84fc2009-09-16 17:17:55 +0000232 valid_only, filter_data)
showard43a3d262008-11-12 18:17:05 +0000233 return hosts.count()
showard1385b162008-03-13 15:59:40 +0000234
mblighe8819cd2008-02-15 16:48:40 +0000235
236# tests
237
showard909c7a62008-07-15 21:52:38 +0000238def add_test(name, test_type, path, author=None, dependencies=None,
showard3d9899a2008-07-31 02:11:58 +0000239 experimental=True, run_verify=None, test_class=None,
showard909c7a62008-07-15 21:52:38 +0000240 test_time=None, test_category=None, description=None,
241 sync_count=1):
jadmanski0afbb632008-06-06 21:10:57 +0000242 return models.Test.add_object(name=name, test_type=test_type, path=path,
showard909c7a62008-07-15 21:52:38 +0000243 author=author, dependencies=dependencies,
244 experimental=experimental,
245 run_verify=run_verify, test_time=test_time,
246 test_category=test_category,
247 sync_count=sync_count,
jadmanski0afbb632008-06-06 21:10:57 +0000248 test_class=test_class,
249 description=description).id
mblighe8819cd2008-02-15 16:48:40 +0000250
251
252def modify_test(id, **data):
jadmanski0afbb632008-06-06 21:10:57 +0000253 models.Test.smart_get(id).update_object(data)
mblighe8819cd2008-02-15 16:48:40 +0000254
255
256def delete_test(id):
jadmanski0afbb632008-06-06 21:10:57 +0000257 models.Test.smart_get(id).delete()
mblighe8819cd2008-02-15 16:48:40 +0000258
259
260def get_tests(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000261 return rpc_utils.prepare_for_serialization(
262 models.Test.list_objects(filter_data))
mblighe8819cd2008-02-15 16:48:40 +0000263
264
showard2b9a88b2008-06-13 20:55:03 +0000265# profilers
266
267def add_profiler(name, description=None):
268 return models.Profiler.add_object(name=name, description=description).id
269
270
271def modify_profiler(id, **data):
272 models.Profiler.smart_get(id).update_object(data)
273
274
275def delete_profiler(id):
276 models.Profiler.smart_get(id).delete()
277
278
279def get_profilers(**filter_data):
280 return rpc_utils.prepare_for_serialization(
281 models.Profiler.list_objects(filter_data))
282
283
mblighe8819cd2008-02-15 16:48:40 +0000284# users
285
286def add_user(login, access_level=None):
jadmanski0afbb632008-06-06 21:10:57 +0000287 return models.User.add_object(login=login, access_level=access_level).id
mblighe8819cd2008-02-15 16:48:40 +0000288
289
290def modify_user(id, **data):
jadmanski0afbb632008-06-06 21:10:57 +0000291 models.User.smart_get(id).update_object(data)
mblighe8819cd2008-02-15 16:48:40 +0000292
293
294def delete_user(id):
jadmanski0afbb632008-06-06 21:10:57 +0000295 models.User.smart_get(id).delete()
mblighe8819cd2008-02-15 16:48:40 +0000296
297
298def get_users(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000299 return rpc_utils.prepare_for_serialization(
300 models.User.list_objects(filter_data))
mblighe8819cd2008-02-15 16:48:40 +0000301
302
303# acl groups
304
305def add_acl_group(name, description=None):
showard04f2cd82008-07-25 20:53:31 +0000306 group = models.AclGroup.add_object(name=name, description=description)
showard64a95952010-01-13 21:27:16 +0000307 group.users.add(models.User.current_user())
showard04f2cd82008-07-25 20:53:31 +0000308 return group.id
mblighe8819cd2008-02-15 16:48:40 +0000309
310
311def modify_acl_group(id, **data):
showard04f2cd82008-07-25 20:53:31 +0000312 group = models.AclGroup.smart_get(id)
313 group.check_for_acl_violation_acl_group()
314 group.update_object(data)
315 group.add_current_user_if_empty()
mblighe8819cd2008-02-15 16:48:40 +0000316
317
318def acl_group_add_users(id, users):
jadmanski0afbb632008-06-06 21:10:57 +0000319 group = models.AclGroup.smart_get(id)
showard04f2cd82008-07-25 20:53:31 +0000320 group.check_for_acl_violation_acl_group()
showardbe3ec042008-11-12 18:16:07 +0000321 users = models.User.smart_get_bulk(users)
jadmanski0afbb632008-06-06 21:10:57 +0000322 group.users.add(*users)
mblighe8819cd2008-02-15 16:48:40 +0000323
324
325def acl_group_remove_users(id, users):
jadmanski0afbb632008-06-06 21:10:57 +0000326 group = models.AclGroup.smart_get(id)
showard04f2cd82008-07-25 20:53:31 +0000327 group.check_for_acl_violation_acl_group()
showardbe3ec042008-11-12 18:16:07 +0000328 users = models.User.smart_get_bulk(users)
jadmanski0afbb632008-06-06 21:10:57 +0000329 group.users.remove(*users)
showard04f2cd82008-07-25 20:53:31 +0000330 group.add_current_user_if_empty()
mblighe8819cd2008-02-15 16:48:40 +0000331
332
333def acl_group_add_hosts(id, hosts):
jadmanski0afbb632008-06-06 21:10:57 +0000334 group = models.AclGroup.smart_get(id)
showard04f2cd82008-07-25 20:53:31 +0000335 group.check_for_acl_violation_acl_group()
showardbe3ec042008-11-12 18:16:07 +0000336 hosts = models.Host.smart_get_bulk(hosts)
jadmanski0afbb632008-06-06 21:10:57 +0000337 group.hosts.add(*hosts)
showard08f981b2008-06-24 21:59:03 +0000338 group.on_host_membership_change()
mblighe8819cd2008-02-15 16:48:40 +0000339
340
341def acl_group_remove_hosts(id, hosts):
jadmanski0afbb632008-06-06 21:10:57 +0000342 group = models.AclGroup.smart_get(id)
showard04f2cd82008-07-25 20:53:31 +0000343 group.check_for_acl_violation_acl_group()
showardbe3ec042008-11-12 18:16:07 +0000344 hosts = models.Host.smart_get_bulk(hosts)
jadmanski0afbb632008-06-06 21:10:57 +0000345 group.hosts.remove(*hosts)
showard08f981b2008-06-24 21:59:03 +0000346 group.on_host_membership_change()
mblighe8819cd2008-02-15 16:48:40 +0000347
348
349def delete_acl_group(id):
jadmanski0afbb632008-06-06 21:10:57 +0000350 models.AclGroup.smart_get(id).delete()
mblighe8819cd2008-02-15 16:48:40 +0000351
352
353def get_acl_groups(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000354 acl_groups = models.AclGroup.list_objects(filter_data)
355 for acl_group in acl_groups:
356 acl_group_obj = models.AclGroup.objects.get(id=acl_group['id'])
357 acl_group['users'] = [user.login
358 for user in acl_group_obj.users.all()]
359 acl_group['hosts'] = [host.hostname
360 for host in acl_group_obj.hosts.all()]
361 return rpc_utils.prepare_for_serialization(acl_groups)
mblighe8819cd2008-02-15 16:48:40 +0000362
363
364# jobs
365
mbligh120351e2009-01-24 01:40:45 +0000366def generate_control_file(tests=(), kernel=None, label=None, profilers=(),
showard91f85102009-10-12 20:34:52 +0000367 client_control_file='', use_container=False,
showard232b7ae2009-11-10 00:46:48 +0000368 profile_only=None, upload_kernel_config=False):
jadmanski0afbb632008-06-06 21:10:57 +0000369 """
mbligh120351e2009-01-24 01:40:45 +0000370 Generates a client-side control file to load a kernel and run tests.
371
372 @param tests List of tests to run.
mbligha3c58d22009-08-24 22:01:51 +0000373 @param kernel A list of kernel info dictionaries configuring which kernels
374 to boot for this job and other options for them
mbligh120351e2009-01-24 01:40:45 +0000375 @param label Name of label to grab kernel config from.
376 @param profilers List of profilers to activate during the job.
377 @param client_control_file The contents of a client-side control file to
378 run at the end of all tests. If this is supplied, all tests must be
379 client side.
380 TODO: in the future we should support server control files directly
381 to wrap with a kernel. That'll require changing the parameter
382 name and adding a boolean to indicate if it is a client or server
383 control file.
384 @param use_container unused argument today. TODO: Enable containers
385 on the host during a client side test.
showard91f85102009-10-12 20:34:52 +0000386 @param profile_only A boolean that indicates what default profile_only
387 mode to use in the control file. Passing None will generate a
388 control file that does not explcitly set the default mode at all.
showard232b7ae2009-11-10 00:46:48 +0000389 @param upload_kernel_config: if enabled it will generate server control
390 file code that uploads the kernel config file to the client and
391 tells the client of the new (local) path when compiling the kernel;
392 the tests must be server side tests
mbligh120351e2009-01-24 01:40:45 +0000393
394 @returns a dict with the following keys:
395 control_file: str, The control file text.
396 is_server: bool, is the control file a server-side control file?
397 synch_count: How many machines the job uses per autoserv execution.
398 synch_count == 1 means the job is asynchronous.
399 dependencies: A list of the names of labels on which the job depends.
400 """
showardd86debe2009-06-10 17:37:56 +0000401 if not tests and not client_control_file:
showard2bab8f42008-11-12 18:15:22 +0000402 return dict(control_file='', is_server=False, synch_count=1,
showard989f25d2008-10-01 11:38:11 +0000403 dependencies=[])
mblighe8819cd2008-02-15 16:48:40 +0000404
showard989f25d2008-10-01 11:38:11 +0000405 cf_info, test_objects, profiler_objects, label = (
showard2b9a88b2008-06-13 20:55:03 +0000406 rpc_utils.prepare_generate_control_file(tests, kernel, label,
407 profilers))
showard989f25d2008-10-01 11:38:11 +0000408 cf_info['control_file'] = control_file.generate_control(
mbligha3c58d22009-08-24 22:01:51 +0000409 tests=test_objects, kernels=kernel, platform=label,
mbligh120351e2009-01-24 01:40:45 +0000410 profilers=profiler_objects, is_server=cf_info['is_server'],
showard232b7ae2009-11-10 00:46:48 +0000411 client_control_file=client_control_file, profile_only=profile_only,
412 upload_kernel_config=upload_kernel_config)
showard989f25d2008-10-01 11:38:11 +0000413 return cf_info
mblighe8819cd2008-02-15 16:48:40 +0000414
415
jamesren4a41e012010-07-16 22:33:48 +0000416def create_parameterized_job(name, priority, test, parameters, kernel=None,
417 label=None, profilers=(), profiler_parameters=None,
418 use_container=False, profile_only=None,
419 upload_kernel_config=False, hosts=(),
420 meta_hosts=(), one_time_hosts=(),
421 atomic_group_name=None, synch_count=None,
422 is_template=False, timeout=None,
Simran Basi34217022012-11-06 13:43:15 -0800423 max_runtime_mins=None, run_verify=True,
jamesren4a41e012010-07-16 22:33:48 +0000424 email_list='', dependencies=(), reboot_before=None,
425 reboot_after=None, parse_failed_repair=None,
426 hostless=False, keyvals=None, drone_set=None):
427 """
428 Creates and enqueues a parameterized job.
429
430 Most parameters a combination of the parameters for generate_control_file()
431 and create_job(), with the exception of:
432
433 @param test name or ID of the test to run
434 @param parameters a map of parameter name ->
435 tuple of (param value, param type)
436 @param profiler_parameters a dictionary of parameters for the profilers:
437 key: profiler name
438 value: dict of param name -> tuple of
439 (param value,
440 param type)
441 """
442 # Save the values of the passed arguments here. What we're going to do with
443 # them is pass them all to rpc_utils.get_create_job_common_args(), which
444 # will extract the subset of these arguments that apply for
445 # rpc_utils.create_job_common(), which we then pass in to that function.
446 args = locals()
447
448 # Set up the parameterized job configs
449 test_obj = models.Test.smart_get(test)
Aviv Keshet3dd8beb2013-05-13 17:36:04 -0700450 control_type = test_obj.test_type
jamesren4a41e012010-07-16 22:33:48 +0000451
452 try:
453 label = models.Label.smart_get(label)
454 except models.Label.DoesNotExist:
455 label = None
456
457 kernel_objs = models.Kernel.create_kernels(kernel)
458 profiler_objs = [models.Profiler.smart_get(profiler)
459 for profiler in profilers]
460
461 parameterized_job = models.ParameterizedJob.objects.create(
462 test=test_obj, label=label, use_container=use_container,
463 profile_only=profile_only,
464 upload_kernel_config=upload_kernel_config)
465 parameterized_job.kernels.add(*kernel_objs)
466
467 for profiler in profiler_objs:
468 parameterized_profiler = models.ParameterizedJobProfiler.objects.create(
469 parameterized_job=parameterized_job,
470 profiler=profiler)
471 profiler_params = profiler_parameters.get(profiler.name, {})
472 for name, (value, param_type) in profiler_params.iteritems():
473 models.ParameterizedJobProfilerParameter.objects.create(
474 parameterized_job_profiler=parameterized_profiler,
475 parameter_name=name,
476 parameter_value=value,
477 parameter_type=param_type)
478
479 try:
480 for parameter in test_obj.testparameter_set.all():
481 if parameter.name in parameters:
482 param_value, param_type = parameters.pop(parameter.name)
483 parameterized_job.parameterizedjobparameter_set.create(
484 test_parameter=parameter, parameter_value=param_value,
485 parameter_type=param_type)
486
487 if parameters:
488 raise Exception('Extra parameters remain: %r' % parameters)
489
490 return rpc_utils.create_job_common(
491 parameterized_job=parameterized_job.id,
492 control_type=control_type,
493 **rpc_utils.get_create_job_common_args(args))
494 except:
495 parameterized_job.delete()
496 raise
497
498
showard12f3e322009-05-13 21:27:42 +0000499def create_job(name, priority, control_file, control_type,
500 hosts=(), meta_hosts=(), one_time_hosts=(),
501 atomic_group_name=None, synch_count=None, is_template=False,
Simran Basi34217022012-11-06 13:43:15 -0800502 timeout=None, max_runtime_mins=None, run_verify=True,
showard12f3e322009-05-13 21:27:42 +0000503 email_list='', dependencies=(), reboot_before=None,
showardc1a98d12010-01-15 00:22:22 +0000504 reboot_after=None, parse_failed_repair=None, hostless=False,
Aviv Keshetcd1ff9b2013-03-01 14:55:19 -0800505 keyvals=None, drone_set=None, image=None, parent_job_id=None,
506 test_retry=0):
jadmanski0afbb632008-06-06 21:10:57 +0000507 """\
508 Create and enqueue a job.
mblighe8819cd2008-02-15 16:48:40 +0000509
showarda1e74b32009-05-12 17:32:04 +0000510 @param name name of this job
511 @param priority Low, Medium, High, Urgent
512 @param control_file String contents of the control file.
513 @param control_type Type of control file, Client or Server.
514 @param synch_count How many machines the job uses per autoserv execution.
515 synch_count == 1 means the job is asynchronous. If an atomic group is
516 given this value is treated as a minimum.
517 @param is_template If true then create a template job.
518 @param timeout Hours after this call returns until the job times out.
Simran Basi34217022012-11-06 13:43:15 -0800519 @param max_runtime_mins Minutes from job starting time until job times out
showarda1e74b32009-05-12 17:32:04 +0000520 @param run_verify Should the host be verified before running the test?
521 @param email_list String containing emails to mail when the job is done
522 @param dependencies List of label names on which this job depends
523 @param reboot_before Never, If dirty, or Always
524 @param reboot_after Never, If all tests passed, or Always
525 @param parse_failed_repair if true, results of failed repairs launched by
526 this job will be parsed as part of the job.
showarda9545c02009-12-18 22:44:26 +0000527 @param hostless if true, create a hostless job
showardc1a98d12010-01-15 00:22:22 +0000528 @param keyvals dict of keyvals to associate with the job
showarda1e74b32009-05-12 17:32:04 +0000529
530 @param hosts List of hosts to run job on.
531 @param meta_hosts List where each entry is a label name, and for each entry
532 one host will be chosen from that label to run the job on.
533 @param one_time_hosts List of hosts not in the database to run the job on.
534 @param atomic_group_name The name of an atomic group to schedule the job on.
jamesren76fcf192010-04-21 20:39:50 +0000535 @param drone_set The name of the drone set to run this test on.
Paul Pendlebury5a8c6ad2011-02-01 07:20:17 -0800536 @param image OS image to install before running job.
Aviv Keshet0b9cfc92013-02-05 11:36:02 -0800537 @param parent_job_id id of a job considered to be parent of created job.
Aviv Keshetcd1ff9b2013-03-01 14:55:19 -0800538 @param test_retry: Number of times to retry test if the test did not
539 complete successfully. (optional, default: 0)
showardc92da832009-04-07 18:14:34 +0000540
541 @returns The created Job id number.
jadmanski0afbb632008-06-06 21:10:57 +0000542 """
Paul Pendlebury5a8c6ad2011-02-01 07:20:17 -0800543
Dan Shi4df39252013-03-19 13:19:45 -0700544 stats.Counter('create_job').increment()
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)
showard0c185192009-01-16 03:07:57 +0000589 query = query.filter(complete=False)
showarddc817512008-11-12 18:16:41 +0000590 models.AclGroup.check_abort_permissions(query)
showard9dbdcda2008-10-14 17:34:36 +0000591 host_queue_entries = list(query.select_related())
showard2bab8f42008-11-12 18:15:22 +0000592 rpc_utils.check_abort_synchronous_jobs(host_queue_entries)
mblighe8819cd2008-02-15 16:48:40 +0000593
showard9dbdcda2008-10-14 17:34:36 +0000594 for queue_entry in host_queue_entries:
showard64a95952010-01-13 21:27:16 +0000595 queue_entry.abort()
showard9d821ab2008-07-11 16:54:29 +0000596
597
Simran Basi73dae552013-02-25 14:57:46 -0800598def _call_special_tasks_on_hosts(task, hosts):
599 """\
600 Schedules a set of hosts for a special task.
601
602 @returns A list of hostnames that a special task was created for.
603 """
604 models.AclGroup.check_for_acl_violation_hosts(hosts)
605 for host in hosts:
606 models.SpecialTask.schedule_special_task(host, task)
607 return list(sorted(host.hostname for host in hosts))
608
609
showard1ff7b2e2009-05-15 23:17:18 +0000610def reverify_hosts(**filter_data):
611 """\
612 Schedules a set of hosts for verify.
mbligh4e545a52009-12-19 05:30:39 +0000613
614 @returns A list of hostnames that a verify task was created for.
showard1ff7b2e2009-05-15 23:17:18 +0000615 """
Simran Basi73dae552013-02-25 14:57:46 -0800616 return _call_special_tasks_on_hosts(models.SpecialTask.Task.VERIFY,
617 models.Host.query_objects(filter_data))
618
619
620def repair_hosts(**filter_data):
621 """\
622 Schedules a set of hosts for repair.
623
624 @returns A list of hostnames that a repair task was created for.
625 """
626 return _call_special_tasks_on_hosts(models.SpecialTask.Task.REPAIR,
627 models.Host.query_objects(filter_data))
showard1ff7b2e2009-05-15 23:17:18 +0000628
629
mblighe8819cd2008-02-15 16:48:40 +0000630def get_jobs(not_yet_run=False, running=False, finished=False, **filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000631 """\
632 Extra filter args for get_jobs:
633 -not_yet_run: Include only jobs that have not yet started running.
634 -running: Include only jobs that have start running but for which not
635 all hosts have completed.
636 -finished: Include only jobs for which all hosts have completed (or
637 aborted).
638 At most one of these three fields should be specified.
639 """
640 filter_data['extra_args'] = rpc_utils.extra_job_filters(not_yet_run,
641 running,
642 finished)
showard0957a842009-05-11 19:25:08 +0000643 job_dicts = []
644 jobs = list(models.Job.query_objects(filter_data))
645 models.Job.objects.populate_relationships(jobs, models.Label,
646 'dependencies')
showardc1a98d12010-01-15 00:22:22 +0000647 models.Job.objects.populate_relationships(jobs, models.JobKeyval, 'keyvals')
showard0957a842009-05-11 19:25:08 +0000648 for job in jobs:
649 job_dict = job.get_object_dict()
650 job_dict['dependencies'] = ','.join(label.name
651 for label in job.dependencies)
showardc1a98d12010-01-15 00:22:22 +0000652 job_dict['keyvals'] = dict((keyval.key, keyval.value)
653 for keyval in job.keyvals)
Eric Lid23bc192011-02-09 14:38:57 -0800654 if job.parameterized_job:
655 job_dict['image'] = get_parameterized_autoupdate_image_url(job)
showard0957a842009-05-11 19:25:08 +0000656 job_dicts.append(job_dict)
657 return rpc_utils.prepare_for_serialization(job_dicts)
mblighe8819cd2008-02-15 16:48:40 +0000658
659
660def get_num_jobs(not_yet_run=False, running=False, finished=False,
jadmanski0afbb632008-06-06 21:10:57 +0000661 **filter_data):
662 """\
663 See get_jobs() for documentation of extra filter parameters.
664 """
665 filter_data['extra_args'] = rpc_utils.extra_job_filters(not_yet_run,
666 running,
667 finished)
668 return models.Job.query_count(filter_data)
mblighe8819cd2008-02-15 16:48:40 +0000669
670
mblighe8819cd2008-02-15 16:48:40 +0000671def get_jobs_summary(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000672 """\
showarda8709c52008-07-03 19:44:54 +0000673 Like get_jobs(), but adds a 'status_counts' field, which is a dictionary
jadmanski0afbb632008-06-06 21:10:57 +0000674 mapping status strings to the number of hosts currently with that
675 status, i.e. {'Queued' : 4, 'Running' : 2}.
676 """
677 jobs = get_jobs(**filter_data)
678 ids = [job['id'] for job in jobs]
679 all_status_counts = models.Job.objects.get_status_counts(ids)
680 for job in jobs:
681 job['status_counts'] = all_status_counts[job['id']]
682 return rpc_utils.prepare_for_serialization(jobs)
mblighe8819cd2008-02-15 16:48:40 +0000683
684
showarda965cef2009-05-15 23:17:41 +0000685def get_info_for_clone(id, preserve_metahosts, queue_entry_filter_data=None):
showarda8709c52008-07-03 19:44:54 +0000686 """\
687 Retrieves all the information needed to clone a job.
688 """
showarda8709c52008-07-03 19:44:54 +0000689 job = models.Job.objects.get(id=id)
showard29f7cd22009-04-29 21:16:24 +0000690 job_info = rpc_utils.get_job_info(job,
showarda965cef2009-05-15 23:17:41 +0000691 preserve_metahosts,
692 queue_entry_filter_data)
showard945072f2008-09-03 20:34:59 +0000693
showardd9992fe2008-07-31 02:15:03 +0000694 host_dicts = []
showard29f7cd22009-04-29 21:16:24 +0000695 for host in job_info['hosts']:
696 host_dict = get_hosts(id=host.id)[0]
697 other_labels = host_dict['labels']
698 if host_dict['platform']:
699 other_labels.remove(host_dict['platform'])
700 host_dict['other_labels'] = ', '.join(other_labels)
showardd9992fe2008-07-31 02:15:03 +0000701 host_dicts.append(host_dict)
showarda8709c52008-07-03 19:44:54 +0000702
showard29f7cd22009-04-29 21:16:24 +0000703 for host in job_info['one_time_hosts']:
704 host_dict = dict(hostname=host.hostname,
705 id=host.id,
706 platform='(one-time host)',
707 locked_text='')
708 host_dicts.append(host_dict)
showarda8709c52008-07-03 19:44:54 +0000709
showard4d077562009-05-08 18:24:36 +0000710 # convert keys from Label objects to strings (names of labels)
showard29f7cd22009-04-29 21:16:24 +0000711 meta_host_counts = dict((meta_host.name, count) for meta_host, count
showard4d077562009-05-08 18:24:36 +0000712 in job_info['meta_host_counts'].iteritems())
showard29f7cd22009-04-29 21:16:24 +0000713
714 info = dict(job=job.get_object_dict(),
715 meta_host_counts=meta_host_counts,
716 hosts=host_dicts)
717 info['job']['dependencies'] = job_info['dependencies']
718 if job_info['atomic_group']:
719 info['atomic_group_name'] = (job_info['atomic_group']).name
720 else:
721 info['atomic_group_name'] = None
jamesren2275ef12010-04-12 18:25:06 +0000722 info['hostless'] = job_info['hostless']
jamesren76fcf192010-04-21 20:39:50 +0000723 info['drone_set'] = job.drone_set and job.drone_set.name
showarda8709c52008-07-03 19:44:54 +0000724
Eric Lid23bc192011-02-09 14:38:57 -0800725 if job.parameterized_job:
726 info['job']['image'] = get_parameterized_autoupdate_image_url(job)
727
showarda8709c52008-07-03 19:44:54 +0000728 return rpc_utils.prepare_for_serialization(info)
729
730
showard34dc5fa2008-04-24 20:58:40 +0000731# host queue entries
732
733def get_host_queue_entries(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000734 """\
showardc92da832009-04-07 18:14:34 +0000735 @returns A sequence of nested dictionaries of host and job information.
jadmanski0afbb632008-06-06 21:10:57 +0000736 """
showardc92da832009-04-07 18:14:34 +0000737 return rpc_utils.prepare_rows_as_nested_dicts(
738 models.HostQueueEntry.query_objects(filter_data),
739 ('host', 'atomic_group', 'job'))
showard34dc5fa2008-04-24 20:58:40 +0000740
741
742def get_num_host_queue_entries(**filter_data):
jadmanski0afbb632008-06-06 21:10:57 +0000743 """\
744 Get the number of host queue entries associated with this job.
745 """
746 return models.HostQueueEntry.query_count(filter_data)
showard34dc5fa2008-04-24 20:58:40 +0000747
748
showard1e935f12008-07-11 00:11:36 +0000749def get_hqe_percentage_complete(**filter_data):
750 """
showardc92da832009-04-07 18:14:34 +0000751 Computes the fraction of host queue entries matching the given filter data
showard1e935f12008-07-11 00:11:36 +0000752 that are complete.
753 """
754 query = models.HostQueueEntry.query_objects(filter_data)
755 complete_count = query.filter(complete=True).count()
756 total_count = query.count()
757 if total_count == 0:
758 return 1
759 return float(complete_count) / total_count
760
761
showard1a5a4082009-07-28 20:01:37 +0000762# special tasks
763
764def get_special_tasks(**filter_data):
765 return rpc_utils.prepare_rows_as_nested_dicts(
766 models.SpecialTask.query_objects(filter_data),
767 ('host', 'queue_entry'))
768
769
showardc0ac3a72009-07-08 21:14:45 +0000770# support for host detail view
771
772def get_host_queue_entries_and_special_tasks(hostname, query_start=None,
773 query_limit=None):
774 """
775 @returns an interleaved list of HostQueueEntries and SpecialTasks,
776 in approximate run order. each dict contains keys for type, host,
777 job, status, started_on, execution_path, and ID.
778 """
779 total_limit = None
780 if query_limit is not None:
781 total_limit = query_start + query_limit
782 filter_data = {'host__hostname': hostname,
783 'query_limit': total_limit,
784 'sort_by': ['-id']}
785
786 queue_entries = list(models.HostQueueEntry.query_objects(filter_data))
787 special_tasks = list(models.SpecialTask.query_objects(filter_data))
788
789 interleaved_entries = rpc_utils.interleave_entries(queue_entries,
790 special_tasks)
791 if query_start is not None:
792 interleaved_entries = interleaved_entries[query_start:]
793 if query_limit is not None:
794 interleaved_entries = interleaved_entries[:query_limit]
795 return rpc_utils.prepare_for_serialization(interleaved_entries)
796
797
798def get_num_host_queue_entries_and_special_tasks(hostname):
799 filter_data = {'host__hostname': hostname}
800 return (models.HostQueueEntry.query_count(filter_data)
801 + models.SpecialTask.query_count(filter_data))
802
803
showard29f7cd22009-04-29 21:16:24 +0000804# recurring run
805
806def get_recurring(**filter_data):
807 return rpc_utils.prepare_rows_as_nested_dicts(
808 models.RecurringRun.query_objects(filter_data),
809 ('job', 'owner'))
810
811
812def get_num_recurring(**filter_data):
813 return models.RecurringRun.query_count(filter_data)
814
815
816def delete_recurring_runs(**filter_data):
817 to_delete = models.RecurringRun.query_objects(filter_data)
818 to_delete.delete()
819
820
821def create_recurring_run(job_id, start_date, loop_period, loop_count):
showard64a95952010-01-13 21:27:16 +0000822 owner = models.User.current_user().login
showard29f7cd22009-04-29 21:16:24 +0000823 job = models.Job.objects.get(id=job_id)
824 return job.create_recurring_job(start_date=start_date,
825 loop_period=loop_period,
826 loop_count=loop_count,
827 owner=owner)
828
829
mblighe8819cd2008-02-15 16:48:40 +0000830# other
831
showarde0b63622008-08-04 20:58:47 +0000832def echo(data=""):
833 """\
834 Returns a passed in string. For doing a basic test to see if RPC calls
835 can successfully be made.
836 """
837 return data
838
839
showardb7a52fd2009-04-27 20:10:56 +0000840def get_motd():
841 """\
842 Returns the message of the day as a string.
843 """
844 return rpc_utils.get_motd()
845
846
mblighe8819cd2008-02-15 16:48:40 +0000847def get_static_data():
jadmanski0afbb632008-06-06 21:10:57 +0000848 """\
849 Returns a dictionary containing a bunch of data that shouldn't change
850 often and is otherwise inaccessible. This includes:
showardc92da832009-04-07 18:14:34 +0000851
852 priorities: List of job priority choices.
853 default_priority: Default priority value for new jobs.
854 users: Sorted list of all users.
855 labels: Sorted list of all labels.
856 atomic_groups: Sorted list of all atomic groups.
857 tests: Sorted list of all tests.
858 profilers: Sorted list of all profilers.
859 current_user: Logged-in username.
860 host_statuses: Sorted list of possible Host statuses.
861 job_statuses: Sorted list of possible HostQueueEntry statuses.
862 job_timeout_default: The default job timeout length in hours.
showarda1e74b32009-05-12 17:32:04 +0000863 parse_failed_repair_default: Default value for the parse_failed_repair job
864 option.
showardc92da832009-04-07 18:14:34 +0000865 reboot_before_options: A list of valid RebootBefore string enums.
866 reboot_after_options: A list of valid RebootAfter string enums.
867 motd: Server's message of the day.
868 status_dictionary: A mapping from one word job status names to a more
869 informative description.
jadmanski0afbb632008-06-06 21:10:57 +0000870 """
showard21baa452008-10-21 00:08:39 +0000871
872 job_fields = models.Job.get_field_dict()
jamesren76fcf192010-04-21 20:39:50 +0000873 default_drone_set_name = models.DroneSet.default_drone_set_name()
874 drone_sets = ([default_drone_set_name] +
875 sorted(drone_set.name for drone_set in
876 models.DroneSet.objects.exclude(
877 name=default_drone_set_name)))
showard21baa452008-10-21 00:08:39 +0000878
jadmanski0afbb632008-06-06 21:10:57 +0000879 result = {}
880 result['priorities'] = models.Job.Priority.choices()
showard21baa452008-10-21 00:08:39 +0000881 default_priority = job_fields['priority'].default
jadmanski0afbb632008-06-06 21:10:57 +0000882 default_string = models.Job.Priority.get_string(default_priority)
883 result['default_priority'] = default_string
884 result['users'] = get_users(sort_by=['login'])
885 result['labels'] = get_labels(sort_by=['-platform', 'name'])
showardc92da832009-04-07 18:14:34 +0000886 result['atomic_groups'] = get_atomic_groups(sort_by=['name'])
jadmanski0afbb632008-06-06 21:10:57 +0000887 result['tests'] = get_tests(sort_by=['name'])
showard2b9a88b2008-06-13 20:55:03 +0000888 result['profilers'] = get_profilers(sort_by=['name'])
showard0fc38302008-10-23 00:44:07 +0000889 result['current_user'] = rpc_utils.prepare_for_serialization(
showard64a95952010-01-13 21:27:16 +0000890 models.User.current_user().get_object_dict())
showard2b9a88b2008-06-13 20:55:03 +0000891 result['host_statuses'] = sorted(models.Host.Status.names)
mbligh5a198b92008-12-11 19:33:29 +0000892 result['job_statuses'] = sorted(models.HostQueueEntry.Status.names)
showardb1e51872008-10-07 11:08:18 +0000893 result['job_timeout_default'] = models.Job.DEFAULT_TIMEOUT
Simran Basi34217022012-11-06 13:43:15 -0800894 result['job_max_runtime_mins_default'] = (
895 models.Job.DEFAULT_MAX_RUNTIME_MINS)
showarda1e74b32009-05-12 17:32:04 +0000896 result['parse_failed_repair_default'] = bool(
897 models.Job.DEFAULT_PARSE_FAILED_REPAIR)
jamesrendd855242010-03-02 22:23:44 +0000898 result['reboot_before_options'] = model_attributes.RebootBefore.names
899 result['reboot_after_options'] = model_attributes.RebootAfter.names
showard8fbae652009-01-20 23:23:10 +0000900 result['motd'] = rpc_utils.get_motd()
jamesren76fcf192010-04-21 20:39:50 +0000901 result['drone_sets_enabled'] = models.DroneSet.drone_sets_enabled()
902 result['drone_sets'] = drone_sets
jamesren4a41e012010-07-16 22:33:48 +0000903 result['parameterized_jobs'] = models.Job.parameterized_jobs_enabled()
showard8ac29b42008-07-17 17:01:55 +0000904
showardd3dc1992009-04-22 21:01:40 +0000905 result['status_dictionary'] = {"Aborted": "Aborted",
showard8ac29b42008-07-17 17:01:55 +0000906 "Verifying": "Verifying Host",
907 "Pending": "Waiting on other hosts",
908 "Running": "Running autoserv",
909 "Completed": "Autoserv completed",
910 "Failed": "Failed to complete",
showardd823b362008-07-24 16:35:46 +0000911 "Queued": "Queued",
showard5deb6772008-11-04 21:54:33 +0000912 "Starting": "Next in host's queue",
913 "Stopped": "Other host(s) failed verify",
showardd3dc1992009-04-22 21:01:40 +0000914 "Parsing": "Awaiting parse of final results",
showard29f7cd22009-04-29 21:16:24 +0000915 "Gathering": "Gathering log files",
showard8cc058f2009-09-08 16:26:33 +0000916 "Template": "Template job for recurring run",
mbligh4608b002010-01-05 18:22:35 +0000917 "Waiting": "Waiting for scheduler action",
918 "Archiving": "Archiving results"}
jadmanski0afbb632008-06-06 21:10:57 +0000919 return result
showard29f7cd22009-04-29 21:16:24 +0000920
921
922def get_server_time():
923 return datetime.datetime.now().strftime("%Y-%m-%d %H:%M")