blob: 558f114ae634f0202ef0f833bcacc929ffbce493 [file] [log] [blame]
mbligh67647152008-11-19 00:18:14 +00001# Copyright Martin J. Bligh, Google Inc 2008
2# Released under the GPL v2
3
4"""
5This class allows you to communicate with the frontend to submit jobs etc
6It is designed for writing more sophisiticated server-side control files that
7can recursively add and manage other jobs.
8
9We turn the JSON dictionaries into real objects that are more idiomatic
10
mblighc31e4022008-12-11 19:32:30 +000011For docs, see:
Aviv Keshet2c709f62013-05-07 12:52:15 -070012 http://www.chromium.org/chromium-os/testing/afe-rpc-infrastructure
mblighc31e4022008-12-11 19:32:30 +000013 http://docs.djangoproject.com/en/dev/ref/models/querysets/#queryset-api
mbligh67647152008-11-19 00:18:14 +000014"""
15
Richard Barnetteb9b37982016-05-20 19:23:39 -070016#pylint: disable=missing-docstring
17
Dan Shie8e0c052015-09-01 00:27:27 -070018import getpass
19import os
20import re
Dan Shie8e0c052015-09-01 00:27:27 -070021
mbligh67647152008-11-19 00:18:14 +000022import common
23from autotest_lib.frontend.afe import rpc_client_lib
Dan Shie8e0c052015-09-01 00:27:27 -070024from autotest_lib.client.common_lib import control_data
mbligh37eceaa2008-12-15 22:56:37 +000025from autotest_lib.client.common_lib import global_config
mbligh67647152008-11-19 00:18:14 +000026from autotest_lib.client.common_lib import utils
Dan Shie8e0c052015-09-01 00:27:27 -070027from autotest_lib.client.common_lib.cros.graphite import autotest_stats
Scott Zawalski63470dd2012-09-05 00:49:43 -040028from autotest_lib.tko import db
29
30
mbligh4e576612008-12-22 14:56:36 +000031try:
32 from autotest_lib.server.site_common import site_utils as server_utils
33except:
34 from autotest_lib.server import utils as server_utils
35form_ntuples_from_machines = server_utils.form_ntuples_from_machines
mbligh67647152008-11-19 00:18:14 +000036
mbligh37eceaa2008-12-15 22:56:37 +000037GLOBAL_CONFIG = global_config.global_config
38DEFAULT_SERVER = 'autotest'
39
Dan Shie8e0c052015-09-01 00:27:27 -070040_tko_timer = autotest_stats.Timer('tko')
41
mbligh67647152008-11-19 00:18:14 +000042def dump_object(header, obj):
43 """
44 Standard way to print out the frontend objects (eg job, host, acl, label)
45 in a human-readable fashion for debugging
46 """
47 result = header + '\n'
48 for key in obj.hash:
49 if key == 'afe' or key == 'hash':
50 continue
51 result += '%20s: %s\n' % (key, obj.hash[key])
52 return result
53
54
mbligh5280e3b2008-12-22 14:39:28 +000055class RpcClient(object):
mbligh67647152008-11-19 00:18:14 +000056 """
mbligh451ede12009-02-12 21:54:03 +000057 Abstract RPC class for communicating with the autotest frontend
58 Inherited for both TKO and AFE uses.
mbligh67647152008-11-19 00:18:14 +000059
mbligh1ef218d2009-08-03 16:57:56 +000060 All the constructors go in the afe / tko class.
mbligh451ede12009-02-12 21:54:03 +000061 Manipulating methods go in the object classes themselves
mbligh67647152008-11-19 00:18:14 +000062 """
mbligh99b24f42009-06-08 16:45:55 +000063 def __init__(self, path, user, server, print_log, debug, reply_debug):
mbligh67647152008-11-19 00:18:14 +000064 """
mbligh451ede12009-02-12 21:54:03 +000065 Create a cached instance of a connection to the frontend
mbligh67647152008-11-19 00:18:14 +000066
67 user: username to connect as
mbligh451ede12009-02-12 21:54:03 +000068 server: frontend server to connect to
mbligh67647152008-11-19 00:18:14 +000069 print_log: pring a logging message to stdout on every operation
70 debug: print out all RPC traffic
71 """
Dan Shiff78f112015-06-12 13:34:02 -070072 if not user and utils.is_in_container():
73 user = GLOBAL_CONFIG.get_config_value('SSP', 'user', default=None)
mblighc31e4022008-12-11 19:32:30 +000074 if not user:
mblighdb59e3c2009-11-21 01:45:18 +000075 user = getpass.getuser()
mbligh451ede12009-02-12 21:54:03 +000076 if not server:
mbligh475f7762009-01-30 00:34:04 +000077 if 'AUTOTEST_WEB' in os.environ:
mbligh451ede12009-02-12 21:54:03 +000078 server = os.environ['AUTOTEST_WEB']
mbligh475f7762009-01-30 00:34:04 +000079 else:
mbligh451ede12009-02-12 21:54:03 +000080 server = GLOBAL_CONFIG.get_config_value('SERVER', 'hostname',
81 default=DEFAULT_SERVER)
82 self.server = server
mbligh67647152008-11-19 00:18:14 +000083 self.user = user
84 self.print_log = print_log
85 self.debug = debug
mbligh99b24f42009-06-08 16:45:55 +000086 self.reply_debug = reply_debug
Scott Zawalski347aaf42012-04-03 16:33:00 -040087 headers = {'AUTHORIZATION': self.user}
88 rpc_server = 'http://' + server + path
mbligh1354c9d2008-12-22 14:56:13 +000089 if debug:
90 print 'SERVER: %s' % rpc_server
91 print 'HEADERS: %s' % headers
mbligh67647152008-11-19 00:18:14 +000092 self.proxy = rpc_client_lib.get_proxy(rpc_server, headers=headers)
93
94
95 def run(self, call, **dargs):
96 """
97 Make a RPC call to the AFE server
98 """
99 rpc_call = getattr(self.proxy, call)
100 if self.debug:
101 print 'DEBUG: %s %s' % (call, dargs)
mbligh451ede12009-02-12 21:54:03 +0000102 try:
mbligh99b24f42009-06-08 16:45:55 +0000103 result = utils.strip_unicode(rpc_call(**dargs))
104 if self.reply_debug:
105 print result
106 return result
mbligh451ede12009-02-12 21:54:03 +0000107 except Exception:
mbligh451ede12009-02-12 21:54:03 +0000108 raise
mbligh67647152008-11-19 00:18:14 +0000109
110
111 def log(self, message):
112 if self.print_log:
113 print message
114
115
jamesrenc3940222010-02-19 21:57:37 +0000116class Planner(RpcClient):
117 def __init__(self, user=None, server=None, print_log=True, debug=False,
118 reply_debug=False):
119 super(Planner, self).__init__(path='/planner/server/rpc/',
120 user=user,
121 server=server,
122 print_log=print_log,
123 debug=debug,
124 reply_debug=reply_debug)
125
126
mbligh5280e3b2008-12-22 14:39:28 +0000127class TKO(RpcClient):
mbligh99b24f42009-06-08 16:45:55 +0000128 def __init__(self, user=None, server=None, print_log=True, debug=False,
129 reply_debug=False):
Scott Zawalski347aaf42012-04-03 16:33:00 -0400130 super(TKO, self).__init__(path='/new_tko/server/noauth/rpc/',
mbligh99b24f42009-06-08 16:45:55 +0000131 user=user,
132 server=server,
133 print_log=print_log,
134 debug=debug,
135 reply_debug=reply_debug)
Scott Zawalski63470dd2012-09-05 00:49:43 -0400136 self._db = None
137
138
Dan Shie8e0c052015-09-01 00:27:27 -0700139 @_tko_timer.decorate
Scott Zawalski63470dd2012-09-05 00:49:43 -0400140 def get_job_test_statuses_from_db(self, job_id):
141 """Get job test statuses from the database.
142
143 Retrieve a set of fields from a job that reflect the status of each test
144 run within a job.
145 fields retrieved: status, test_name, reason, test_started_time,
146 test_finished_time, afe_job_id, job_owner, hostname.
147
148 @param job_id: The afe job id to look up.
149 @returns a TestStatus object of the resulting information.
150 """
151 if self._db is None:
Dan Shie8e0c052015-09-01 00:27:27 -0700152 self._db = db.db()
Fang Deng5c508332014-03-19 10:26:00 -0700153 fields = ['status', 'test_name', 'subdir', 'reason',
154 'test_started_time', 'test_finished_time', 'afe_job_id',
155 'job_owner', 'hostname', 'job_tag']
Scott Zawalski63470dd2012-09-05 00:49:43 -0400156 table = 'tko_test_view_2'
157 where = 'job_tag like "%s-%%"' % job_id
158 test_status = []
159 # Run commit before we query to ensure that we are pulling the latest
160 # results.
161 self._db.commit()
162 for entry in self._db.select(','.join(fields), table, (where, None)):
163 status_dict = {}
164 for key,value in zip(fields, entry):
165 # All callers expect values to be a str object.
166 status_dict[key] = str(value)
167 # id is used by TestStatus to uniquely identify each Test Status
168 # obj.
169 status_dict['id'] = [status_dict['reason'], status_dict['hostname'],
170 status_dict['test_name']]
171 test_status.append(status_dict)
172
173 return [TestStatus(self, e) for e in test_status]
mblighc31e4022008-12-11 19:32:30 +0000174
175
176 def get_status_counts(self, job, **data):
177 entries = self.run('get_status_counts',
mbligh1ef218d2009-08-03 16:57:56 +0000178 group_by=['hostname', 'test_name', 'reason'],
mblighc31e4022008-12-11 19:32:30 +0000179 job_tag__startswith='%s-' % job, **data)
mbligh5280e3b2008-12-22 14:39:28 +0000180 return [TestStatus(self, e) for e in entries['groups']]
mblighc31e4022008-12-11 19:32:30 +0000181
182
mbligh5280e3b2008-12-22 14:39:28 +0000183class AFE(RpcClient):
mbligh17c75e62009-06-08 16:18:21 +0000184 def __init__(self, user=None, server=None, print_log=True, debug=False,
mbligh99b24f42009-06-08 16:45:55 +0000185 reply_debug=False, job=None):
mbligh17c75e62009-06-08 16:18:21 +0000186 self.job = job
Scott Zawalski347aaf42012-04-03 16:33:00 -0400187 super(AFE, self).__init__(path='/afe/server/noauth/rpc/',
mbligh99b24f42009-06-08 16:45:55 +0000188 user=user,
189 server=server,
190 print_log=print_log,
191 debug=debug,
192 reply_debug=reply_debug)
mblighc31e4022008-12-11 19:32:30 +0000193
mbligh1ef218d2009-08-03 16:57:56 +0000194
mbligh67647152008-11-19 00:18:14 +0000195 def host_statuses(self, live=None):
jamesren121eee62010-04-13 19:10:12 +0000196 dead_statuses = ['Repair Failed', 'Repairing']
mbligh67647152008-11-19 00:18:14 +0000197 statuses = self.run('get_static_data')['host_statuses']
198 if live == True:
mblighc2847b72009-03-25 19:32:20 +0000199 return list(set(statuses) - set(dead_statuses))
mbligh67647152008-11-19 00:18:14 +0000200 if live == False:
201 return dead_statuses
202 else:
203 return statuses
204
205
mbligh71094012009-12-19 05:35:21 +0000206 @staticmethod
207 def _dict_for_host_query(hostnames=(), status=None, label=None):
208 query_args = {}
mbligh4e545a52009-12-19 05:30:39 +0000209 if hostnames:
210 query_args['hostname__in'] = hostnames
211 if status:
212 query_args['status'] = status
213 if label:
214 query_args['labels__name'] = label
mbligh71094012009-12-19 05:35:21 +0000215 return query_args
216
217
218 def get_hosts(self, hostnames=(), status=None, label=None, **dargs):
219 query_args = dict(dargs)
220 query_args.update(self._dict_for_host_query(hostnames=hostnames,
221 status=status,
222 label=label))
223 hosts = self.run('get_hosts', **query_args)
224 return [Host(self, h) for h in hosts]
225
226
227 def get_hostnames(self, status=None, label=None, **dargs):
228 """Like get_hosts() but returns hostnames instead of Host objects."""
229 # This implementation can be replaced with a more efficient one
230 # that does not query for entire host objects in the future.
231 return [host_obj.hostname for host_obj in
232 self.get_hosts(status=status, label=label, **dargs)]
233
234
235 def reverify_hosts(self, hostnames=(), status=None, label=None):
236 query_args = dict(locked=False,
237 aclgroup__users__login=self.user)
238 query_args.update(self._dict_for_host_query(hostnames=hostnames,
239 status=status,
240 label=label))
mbligh4e545a52009-12-19 05:30:39 +0000241 return self.run('reverify_hosts', **query_args)
242
243
mbligh67647152008-11-19 00:18:14 +0000244 def create_host(self, hostname, **dargs):
mbligh54459c72009-01-21 19:26:44 +0000245 id = self.run('add_host', hostname=hostname, **dargs)
mbligh67647152008-11-19 00:18:14 +0000246 return self.get_hosts(id=id)[0]
247
248
MK Ryuacf35922014-10-03 14:56:49 -0700249 def get_host_attribute(self, attr, **dargs):
250 host_attrs = self.run('get_host_attribute', attribute=attr, **dargs)
251 return [HostAttribute(self, a) for a in host_attrs]
252
253
Chris Masone8abb6fc2012-01-31 09:27:36 -0800254 def set_host_attribute(self, attr, val, **dargs):
255 self.run('set_host_attribute', attribute=attr, value=val, **dargs)
256
257
mbligh67647152008-11-19 00:18:14 +0000258 def get_labels(self, **dargs):
259 labels = self.run('get_labels', **dargs)
mbligh5280e3b2008-12-22 14:39:28 +0000260 return [Label(self, l) for l in labels]
mbligh67647152008-11-19 00:18:14 +0000261
262
263 def create_label(self, name, **dargs):
mbligh54459c72009-01-21 19:26:44 +0000264 id = self.run('add_label', name=name, **dargs)
mbligh67647152008-11-19 00:18:14 +0000265 return self.get_labels(id=id)[0]
266
267
268 def get_acls(self, **dargs):
269 acls = self.run('get_acl_groups', **dargs)
mbligh5280e3b2008-12-22 14:39:28 +0000270 return [Acl(self, a) for a in acls]
mbligh67647152008-11-19 00:18:14 +0000271
272
273 def create_acl(self, name, **dargs):
mbligh54459c72009-01-21 19:26:44 +0000274 id = self.run('add_acl_group', name=name, **dargs)
mbligh67647152008-11-19 00:18:14 +0000275 return self.get_acls(id=id)[0]
276
277
mbligh54459c72009-01-21 19:26:44 +0000278 def get_users(self, **dargs):
279 users = self.run('get_users', **dargs)
280 return [User(self, u) for u in users]
281
282
mbligh1354c9d2008-12-22 14:56:13 +0000283 def generate_control_file(self, tests, **dargs):
284 ret = self.run('generate_control_file', tests=tests, **dargs)
285 return ControlFile(self, ret)
286
287
mbligh67647152008-11-19 00:18:14 +0000288 def get_jobs(self, summary=False, **dargs):
289 if summary:
290 jobs_data = self.run('get_jobs_summary', **dargs)
291 else:
292 jobs_data = self.run('get_jobs', **dargs)
mblighafbba0c2009-06-08 16:44:45 +0000293 jobs = []
294 for j in jobs_data:
295 job = Job(self, j)
296 # Set up some extra information defaults
297 job.testname = re.sub('\s.*', '', job.name) # arbitrary default
298 job.platform_results = {}
299 job.platform_reasons = {}
300 jobs.append(job)
301 return jobs
mbligh67647152008-11-19 00:18:14 +0000302
303
304 def get_host_queue_entries(self, **data):
305 entries = self.run('get_host_queue_entries', **data)
mblighf9e35862009-02-26 01:03:11 +0000306 job_statuses = [JobStatus(self, e) for e in entries]
mbligh99b24f42009-06-08 16:45:55 +0000307
308 # Sadly, get_host_queue_entries doesn't return platforms, we have
309 # to get those back from an explicit get_hosts queury, then patch
310 # the new host objects back into the host list.
311 hostnames = [s.host.hostname for s in job_statuses if s.host]
312 host_hash = {}
313 for host in self.get_hosts(hostname__in=hostnames):
314 host_hash[host.hostname] = host
315 for status in job_statuses:
316 if status.host:
Fang Deng97dafbc2015-04-23 23:06:18 -0700317 status.host = host_hash.get(status.host.hostname)
mblighf9e35862009-02-26 01:03:11 +0000318 # filter job statuses that have either host or meta_host
319 return [status for status in job_statuses if (status.host or
320 status.meta_host)]
mbligh67647152008-11-19 00:18:14 +0000321
322
MK Ryu1b2d7f92015-02-24 17:45:02 -0800323 def get_special_tasks(self, **data):
324 tasks = self.run('get_special_tasks', **data)
325 return [SpecialTask(self, t) for t in tasks]
326
327
J. Richard Barnette9f10c9f2015-04-13 16:44:50 -0700328 def get_host_special_tasks(self, host_id, **data):
329 tasks = self.run('get_host_special_tasks',
330 host_id=host_id, **data)
331 return [SpecialTask(self, t) for t in tasks]
332
333
J. Richard Barnette8dbd6d32015-05-01 11:01:12 -0700334 def get_host_status_task(self, host_id, end_time):
335 task = self.run('get_host_status_task',
J. Richard Barnette8abbfd62015-06-23 12:46:54 -0700336 host_id=host_id, end_time=end_time)
J. Richard Barnettebc9a7952015-04-16 17:43:27 -0700337 return SpecialTask(self, task) if task else None
338
339
J. Richard Barnette8abbfd62015-06-23 12:46:54 -0700340 def get_host_diagnosis_interval(self, host_id, end_time, success):
341 return self.run('get_host_diagnosis_interval',
342 host_id=host_id, end_time=end_time,
343 success=success)
344
345
mbligh67647152008-11-19 00:18:14 +0000346 def create_job(self, control_file, name=' ', priority='Medium',
Aviv Keshet3dd8beb2013-05-13 17:36:04 -0700347 control_type=control_data.CONTROL_TYPE_NAMES.CLIENT, **dargs):
mbligh67647152008-11-19 00:18:14 +0000348 id = self.run('create_job', name=name, priority=priority,
349 control_file=control_file, control_type=control_type, **dargs)
350 return self.get_jobs(id=id)[0]
351
352
Simran Basi01984f52015-10-12 15:36:45 -0700353 def abort_jobs(self, jobs):
354 """Abort a list of jobs.
355
356 Already completed jobs will not be affected.
357
358 @param jobs: List of job ids to abort.
359 """
360 for job in jobs:
361 self.run('abort_host_queue_entries', job_id=job)
362
363
Kevin Cheng19521982016-09-22 12:27:23 -0700364 def get_hosts_by_attribute(self, attribute, value):
365 """
366 Get the list of hosts that share the same host attribute value.
367
368 @param attribute: String of the host attribute to check.
369 @param value: String of the value that is shared between hosts.
370
371 @returns List of hostnames that all have the same host attribute and
372 value.
373 """
374 return self.run('get_hosts_by_attribute',
375 attribute=attribute, value=value)
376
377
378 def lock_host(self, host, lock_reason, fail_if_locked=False):
379 """
380 Lock the given host with the given lock reason.
381
382 Locking a host that's already locked using the 'modify_hosts' rpc
383 will raise an exception. That's why fail_if_locked exists so the
384 caller can determine if the lock succeeded or failed. This will
385 save every caller from wrapping lock_host in a try-except.
386
387 @param host: hostname of host to lock.
388 @param lock_reason: Reason for locking host.
389 @param fail_if_locked: Return False if host is already locked.
390
391 @returns Boolean, True if lock was successful, False otherwise.
392 """
393 try:
394 self.run('modify_hosts',
395 host_filter_data={'hostname': host},
396 update_data={'locked': True,
397 'lock_reason': lock_reason})
398 except Exception:
399 return not fail_if_locked
400 return True
401
402
403 def unlock_hosts(self, locked_hosts):
404 """
405 Unlock the hosts.
406
407 Unlocking a host that's already unlocked will do nothing so we don't
408 need any special try-except clause here.
409
410 @param locked_hosts: List of hostnames of hosts to unlock.
411 """
412 self.run('modify_hosts',
413 host_filter_data={'hostname__in': locked_hosts},
414 update_data={'locked': False,
415 'lock_reason': ''})
416
417
mbligh5280e3b2008-12-22 14:39:28 +0000418class TestResults(object):
419 """
420 Container class used to hold the results of the tests for a job
421 """
422 def __init__(self):
423 self.good = []
424 self.fail = []
mbligh451ede12009-02-12 21:54:03 +0000425 self.pending = []
mbligh5280e3b2008-12-22 14:39:28 +0000426
427
428 def add(self, result):
mbligh451ede12009-02-12 21:54:03 +0000429 if result.complete_count > result.pass_count:
430 self.fail.append(result)
431 elif result.incomplete_count > 0:
432 self.pending.append(result)
mbligh5280e3b2008-12-22 14:39:28 +0000433 else:
mbligh451ede12009-02-12 21:54:03 +0000434 self.good.append(result)
mbligh5280e3b2008-12-22 14:39:28 +0000435
436
437class RpcObject(object):
mbligh67647152008-11-19 00:18:14 +0000438 """
439 Generic object used to construct python objects from rpc calls
440 """
441 def __init__(self, afe, hash):
442 self.afe = afe
443 self.hash = hash
444 self.__dict__.update(hash)
445
446
447 def __str__(self):
448 return dump_object(self.__repr__(), self)
449
450
mbligh1354c9d2008-12-22 14:56:13 +0000451class ControlFile(RpcObject):
452 """
453 AFE control file object
454
455 Fields: synch_count, dependencies, control_file, is_server
456 """
457 def __repr__(self):
458 return 'CONTROL FILE: %s' % self.control_file
459
460
mbligh5280e3b2008-12-22 14:39:28 +0000461class Label(RpcObject):
mbligh67647152008-11-19 00:18:14 +0000462 """
463 AFE label object
464
465 Fields:
466 name, invalid, platform, kernel_config, id, only_if_needed
467 """
468 def __repr__(self):
469 return 'LABEL: %s' % self.name
470
471
472 def add_hosts(self, hosts):
Chris Masone3a560bd2011-11-14 16:53:56 -0800473 return self.afe.run('label_add_hosts', id=self.id, hosts=hosts)
mbligh67647152008-11-19 00:18:14 +0000474
475
476 def remove_hosts(self, hosts):
Chris Masone3a560bd2011-11-14 16:53:56 -0800477 return self.afe.run('label_remove_hosts', id=self.id, hosts=hosts)
mbligh67647152008-11-19 00:18:14 +0000478
479
mbligh5280e3b2008-12-22 14:39:28 +0000480class Acl(RpcObject):
mbligh67647152008-11-19 00:18:14 +0000481 """
482 AFE acl object
483
484 Fields:
485 users, hosts, description, name, id
486 """
487 def __repr__(self):
488 return 'ACL: %s' % self.name
489
490
491 def add_hosts(self, hosts):
492 self.afe.log('Adding hosts %s to ACL %s' % (hosts, self.name))
493 return self.afe.run('acl_group_add_hosts', self.id, hosts)
494
495
496 def remove_hosts(self, hosts):
497 self.afe.log('Removing hosts %s from ACL %s' % (hosts, self.name))
498 return self.afe.run('acl_group_remove_hosts', self.id, hosts)
499
500
mbligh54459c72009-01-21 19:26:44 +0000501 def add_users(self, users):
502 self.afe.log('Adding users %s to ACL %s' % (users, self.name))
503 return self.afe.run('acl_group_add_users', id=self.name, users=users)
504
505
mbligh5280e3b2008-12-22 14:39:28 +0000506class Job(RpcObject):
mbligh67647152008-11-19 00:18:14 +0000507 """
508 AFE job object
509
510 Fields:
511 name, control_file, control_type, synch_count, reboot_before,
512 run_verify, priority, email_list, created_on, dependencies,
513 timeout, owner, reboot_after, id
514 """
515 def __repr__(self):
516 return 'JOB: %s' % self.id
517
518
mbligh5280e3b2008-12-22 14:39:28 +0000519class JobStatus(RpcObject):
mbligh67647152008-11-19 00:18:14 +0000520 """
521 AFE job_status object
522
523 Fields:
524 status, complete, deleted, meta_host, host, active, execution_subdir, id
525 """
526 def __init__(self, afe, hash):
MK Ryu1b2d7f92015-02-24 17:45:02 -0800527 super(JobStatus, self).__init__(afe, hash)
mbligh5280e3b2008-12-22 14:39:28 +0000528 self.job = Job(afe, self.job)
Dale Curtis8adf7892011-09-08 16:13:36 -0700529 if getattr(self, 'host'):
mbligh99b24f42009-06-08 16:45:55 +0000530 self.host = Host(afe, self.host)
mbligh67647152008-11-19 00:18:14 +0000531
532
533 def __repr__(self):
mbligh451ede12009-02-12 21:54:03 +0000534 if self.host and self.host.hostname:
535 hostname = self.host.hostname
536 else:
537 hostname = 'None'
538 return 'JOB STATUS: %s-%s' % (self.job.id, hostname)
mbligh67647152008-11-19 00:18:14 +0000539
540
MK Ryu1b2d7f92015-02-24 17:45:02 -0800541class SpecialTask(RpcObject):
542 """
543 AFE special task object
544 """
545 def __init__(self, afe, hash):
546 super(SpecialTask, self).__init__(afe, hash)
547 self.host = Host(afe, self.host)
548
549
550 def __repr__(self):
551 return 'SPECIAL TASK: %s' % self.id
552
553
mbligh5280e3b2008-12-22 14:39:28 +0000554class Host(RpcObject):
mbligh67647152008-11-19 00:18:14 +0000555 """
556 AFE host object
557
558 Fields:
559 status, lock_time, locked_by, locked, hostname, invalid,
560 synch_id, labels, platform, protection, dirty, id
561 """
562 def __repr__(self):
563 return 'HOST OBJECT: %s' % self.hostname
564
565
566 def show(self):
567 labels = list(set(self.labels) - set([self.platform]))
568 print '%-6s %-7s %-7s %-16s %s' % (self.hostname, self.status,
569 self.locked, self.platform,
570 ', '.join(labels))
571
572
mbligh54459c72009-01-21 19:26:44 +0000573 def delete(self):
574 return self.afe.run('delete_host', id=self.id)
575
576
mbligh6463c4b2009-01-30 00:33:37 +0000577 def modify(self, **dargs):
578 return self.afe.run('modify_host', id=self.id, **dargs)
579
580
mbligh67647152008-11-19 00:18:14 +0000581 def get_acls(self):
582 return self.afe.get_acls(hosts__hostname=self.hostname)
583
584
585 def add_acl(self, acl_name):
586 self.afe.log('Adding ACL %s to host %s' % (acl_name, self.hostname))
587 return self.afe.run('acl_group_add_hosts', id=acl_name,
588 hosts=[self.hostname])
589
590
591 def remove_acl(self, acl_name):
592 self.afe.log('Removing ACL %s from host %s' % (acl_name, self.hostname))
593 return self.afe.run('acl_group_remove_hosts', id=acl_name,
594 hosts=[self.hostname])
595
596
597 def get_labels(self):
598 return self.afe.get_labels(host__hostname__in=[self.hostname])
599
600
601 def add_labels(self, labels):
602 self.afe.log('Adding labels %s to host %s' % (labels, self.hostname))
603 return self.afe.run('host_add_labels', id=self.id, labels=labels)
604
605
606 def remove_labels(self, labels):
607 self.afe.log('Removing labels %s from host %s' % (labels,self.hostname))
608 return self.afe.run('host_remove_labels', id=self.id, labels=labels)
mbligh5b618382008-12-03 15:24:01 +0000609
610
mbligh54459c72009-01-21 19:26:44 +0000611class User(RpcObject):
612 def __repr__(self):
613 return 'USER: %s' % self.login
614
615
mbligh5280e3b2008-12-22 14:39:28 +0000616class TestStatus(RpcObject):
mblighc31e4022008-12-11 19:32:30 +0000617 """
618 TKO test status object
619
620 Fields:
621 test_idx, hostname, testname, id
622 complete_count, incomplete_count, group_count, pass_count
623 """
624 def __repr__(self):
625 return 'TEST STATUS: %s' % self.id
626
627
MK Ryuacf35922014-10-03 14:56:49 -0700628class HostAttribute(RpcObject):
629 """
630 AFE host attribute object
631
632 Fields:
633 id, host, attribute, value
634 """
635 def __repr__(self):
636 return 'HOST ATTRIBUTE %d' % self.id