blob: 07dc0ec82880edfa5e3be10c354f5295900faf99 [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:
12 http://autotest/afe/server/noauth/rpc/
13 http://autotest/new_tko/server/noauth/rpc/
14 http://docs.djangoproject.com/en/dev/ref/models/querysets/#queryset-api
mbligh67647152008-11-19 00:18:14 +000015"""
16
mbligh1f23f362008-12-22 14:46:12 +000017import os, time, traceback, re
mbligh67647152008-11-19 00:18:14 +000018import common
19from autotest_lib.frontend.afe import rpc_client_lib
mbligh37eceaa2008-12-15 22:56:37 +000020from autotest_lib.client.common_lib import global_config
mbligh67647152008-11-19 00:18:14 +000021from autotest_lib.client.common_lib import utils
22
mbligh37eceaa2008-12-15 22:56:37 +000023GLOBAL_CONFIG = global_config.global_config
24DEFAULT_SERVER = 'autotest'
25
mbligh67647152008-11-19 00:18:14 +000026
27def dump_object(header, obj):
28 """
29 Standard way to print out the frontend objects (eg job, host, acl, label)
30 in a human-readable fashion for debugging
31 """
32 result = header + '\n'
33 for key in obj.hash:
34 if key == 'afe' or key == 'hash':
35 continue
36 result += '%20s: %s\n' % (key, obj.hash[key])
37 return result
38
39
mbligh5280e3b2008-12-22 14:39:28 +000040class RpcClient(object):
mbligh67647152008-11-19 00:18:14 +000041 """
42 AFE class for communicating with the autotest frontend
43
44 All the constructors go in the afe class.
45 Manipulating methods go in the classes themselves
46 """
mblighc31e4022008-12-11 19:32:30 +000047 def __init__(self, path, user, web_server, print_log, debug):
mbligh67647152008-11-19 00:18:14 +000048 """
49 Create a cached instance of a connection to the AFE
50
51 user: username to connect as
52 web_server: AFE instance to connect to
53 print_log: pring a logging message to stdout on every operation
54 debug: print out all RPC traffic
55 """
mblighc31e4022008-12-11 19:32:30 +000056 if not user:
57 user = os.environ.get('LOGNAME')
58 if not web_server:
mbligh37eceaa2008-12-15 22:56:37 +000059 web_server = 'http://' + GLOBAL_CONFIG.get_config_value(
60 'SERVER', 'hostname', default=DEFAULT_SERVER)
mbligh67647152008-11-19 00:18:14 +000061 self.user = user
62 self.print_log = print_log
63 self.debug = debug
64 headers = {'AUTHORIZATION' : self.user}
mblighc31e4022008-12-11 19:32:30 +000065 rpc_server = web_server + path
mbligh1354c9d2008-12-22 14:56:13 +000066 if debug:
67 print 'SERVER: %s' % rpc_server
68 print 'HEADERS: %s' % headers
mbligh67647152008-11-19 00:18:14 +000069 self.proxy = rpc_client_lib.get_proxy(rpc_server, headers=headers)
70
71
72 def run(self, call, **dargs):
73 """
74 Make a RPC call to the AFE server
75 """
76 rpc_call = getattr(self.proxy, call)
77 if self.debug:
78 print 'DEBUG: %s %s' % (call, dargs)
79 return utils.strip_unicode(rpc_call(**dargs))
80
81
82 def log(self, message):
83 if self.print_log:
84 print message
85
86
mbligh5280e3b2008-12-22 14:39:28 +000087class TKO(RpcClient):
mblighc31e4022008-12-11 19:32:30 +000088 def __init__(self, user=None, web_server=None, print_log=True, debug=False):
mbligh5280e3b2008-12-22 14:39:28 +000089 super(TKO, self).__init__('/new_tko/server/noauth/rpc/', user,
mblighc31e4022008-12-11 19:32:30 +000090 web_server, print_log, debug)
91
92
93 def get_status_counts(self, job, **data):
94 entries = self.run('get_status_counts',
95 group_by=['hostname', 'test_name'],
96 job_tag__startswith='%s-' % job, **data)
mbligh5280e3b2008-12-22 14:39:28 +000097 return [TestStatus(self, e) for e in entries['groups']]
mblighc31e4022008-12-11 19:32:30 +000098
99
mbligh5280e3b2008-12-22 14:39:28 +0000100class AFE(RpcClient):
mblighc31e4022008-12-11 19:32:30 +0000101 def __init__(self, user=None, web_server=None, print_log=True, debug=False):
mbligh5280e3b2008-12-22 14:39:28 +0000102 super(AFE, self).__init__('/afe/server/noauth/rpc/', user, web_server,
mblighc31e4022008-12-11 19:32:30 +0000103 print_log, debug)
104
105
mbligh67647152008-11-19 00:18:14 +0000106 def host_statuses(self, live=None):
107 dead_statuses = ['Dead', 'Repair Failed']
108 statuses = self.run('get_static_data')['host_statuses']
109 if live == True:
110 return list(set(statuses) - set(['Dead', 'Repair Failed']))
111 if live == False:
112 return dead_statuses
113 else:
114 return statuses
115
116
117 def get_hosts(self, **dargs):
118 hosts = self.run('get_hosts', **dargs)
mbligh5280e3b2008-12-22 14:39:28 +0000119 return [Host(self, h) for h in hosts]
mbligh67647152008-11-19 00:18:14 +0000120
121
122 def create_host(self, hostname, **dargs):
123 id = self.run('add_host', **dargs)
124 return self.get_hosts(id=id)[0]
125
126
127 def get_labels(self, **dargs):
128 labels = self.run('get_labels', **dargs)
mbligh5280e3b2008-12-22 14:39:28 +0000129 return [Label(self, l) for l in labels]
mbligh67647152008-11-19 00:18:14 +0000130
131
132 def create_label(self, name, **dargs):
133 id = self.run('add_label', **dargs)
134 return self.get_labels(id=id)[0]
135
136
137 def get_acls(self, **dargs):
138 acls = self.run('get_acl_groups', **dargs)
mbligh5280e3b2008-12-22 14:39:28 +0000139 return [Acl(self, a) for a in acls]
mbligh67647152008-11-19 00:18:14 +0000140
141
142 def create_acl(self, name, **dargs):
143 id = self.run('add_acl_group', **dargs)
144 return self.get_acls(id=id)[0]
145
146
mbligh1354c9d2008-12-22 14:56:13 +0000147 def generate_control_file(self, tests, **dargs):
148 ret = self.run('generate_control_file', tests=tests, **dargs)
149 return ControlFile(self, ret)
150
151
mbligh67647152008-11-19 00:18:14 +0000152 def get_jobs(self, summary=False, **dargs):
153 if summary:
154 jobs_data = self.run('get_jobs_summary', **dargs)
155 else:
156 jobs_data = self.run('get_jobs', **dargs)
mbligh5280e3b2008-12-22 14:39:28 +0000157 return [Job(self, j) for j in jobs_data]
mbligh67647152008-11-19 00:18:14 +0000158
159
160 def get_host_queue_entries(self, **data):
161 entries = self.run('get_host_queue_entries', **data)
mbligh5280e3b2008-12-22 14:39:28 +0000162 return [JobStatus(self, e) for e in entries]
mbligh67647152008-11-19 00:18:14 +0000163
164
mbligh1354c9d2008-12-22 14:56:13 +0000165 def create_job_by_test(self, tests, kernel=None, use_container=False,
166 **dargs):
mbligh67647152008-11-19 00:18:14 +0000167 """
168 Given a test name, fetch the appropriate control file from the server
169 and submit it
170 """
mbligh1354c9d2008-12-22 14:56:13 +0000171 control_file = self.generate_control_file(tests=tests, kernel=kernel,
172 use_container=use_container,
173 do_push_packages=True)
174 if control_file.is_server:
mbligh67647152008-11-19 00:18:14 +0000175 dargs['control_type'] = 'Server'
176 else:
177 dargs['control_type'] = 'Client'
178 dargs['dependencies'] = dargs.get('dependencies', []) + \
mbligh1354c9d2008-12-22 14:56:13 +0000179 control_file.dependencies
180 dargs['control_file'] = control_file.control_file
181 dargs['synch_count'] = control_file.synch_count
mbligh67647152008-11-19 00:18:14 +0000182 return self.create_job(**dargs)
183
184
185 def create_job(self, control_file, name=' ', priority='Medium',
186 control_type='Client', **dargs):
187 id = self.run('create_job', name=name, priority=priority,
188 control_file=control_file, control_type=control_type, **dargs)
189 return self.get_jobs(id=id)[0]
190
191
mbligh1f23f362008-12-22 14:46:12 +0000192 def run_test_suites(self, pairings, kernel, kernel_label, priority='Medium',
193 wait=True, poll_interval=5, email_from=None,
194 email_to=None):
mbligh5b618382008-12-03 15:24:01 +0000195 """
196 Run a list of test suites on a particular kernel.
197
198 Poll for them to complete, and return whether they worked or not.
199
200 pairings: list of MachineTestPairing objects to invoke
201 kernel: name of the kernel to run
202 kernel_label: label of the kernel to run
203 (<kernel-version> : <config> : <date>)
204 wait: boolean - wait for the results to come back?
205 poll_interval: interval between polling for job results (in minutes)
mbligh45ffc432008-12-09 23:35:17 +0000206 email_from: send notification email upon completion from here
207 email_from: send notification email upon completion to here
mbligh5b618382008-12-03 15:24:01 +0000208 """
209 jobs = []
210 for pairing in pairings:
mbligh1f23f362008-12-22 14:46:12 +0000211 job = self.invoke_test(pairing, kernel, kernel_label, priority)
mbligh45ffc432008-12-09 23:35:17 +0000212 job.notified = False
213 jobs.append(job)
mbligh5280e3b2008-12-22 14:39:28 +0000214 # disabled - this is just for debugging: mbligh
215 # if email_from and email_to:
216 # subject = 'Testing started: %s : %s' % (job.name, job.id)
217 # utils.send_email(email_from, email_to, subject, subject)
mbligh5b618382008-12-03 15:24:01 +0000218 if not wait:
219 return
mbligh5280e3b2008-12-22 14:39:28 +0000220 tko = TKO()
mbligh5b618382008-12-03 15:24:01 +0000221 while True:
222 time.sleep(60 * poll_interval)
mbligh5280e3b2008-12-22 14:39:28 +0000223 result = self.poll_all_jobs(tko, jobs, email_from, email_to)
mbligh5b618382008-12-03 15:24:01 +0000224 if result is not None:
225 return result
226
227
mbligh45ffc432008-12-09 23:35:17 +0000228 def result_notify(self, job, email_from, email_to):
mbligh5b618382008-12-03 15:24:01 +0000229 """
mbligh45ffc432008-12-09 23:35:17 +0000230 Notify about the result of a job. Will always print, if email data
231 is provided, will send email for it as well.
232
233 job: job object to notify about
234 email_from: send notification email upon completion from here
235 email_from: send notification email upon completion to here
236 """
237 if job.result == True:
238 subject = 'Testing PASSED: '
239 else:
240 subject = 'Testing FAILED: '
241 subject += '%s : %s\n' % (job.name, job.id)
242 text = []
243 for platform in job.results_platform_map:
244 for status in job.results_platform_map[platform]:
245 if status == 'Total':
246 continue
247 hosts = ','.join(job.results_platform_map[platform][status])
mbligh37eceaa2008-12-15 22:56:37 +0000248 text.append('%20s %10s %s\n' % (platform, status, hosts))
249
250 tko_base_url = 'http://%s/tko' % GLOBAL_CONFIG.get_config_value(
251 'SERVER', 'hostname', default=DEFAULT_SERVER)
252
253 params = ('columns=test',
254 'rows=machine_group',
255 "condition=tag~'%s-%%25'" % job.id,
256 'title=Report')
257 query_string = '&'.join(params)
258 url = '%s/compose_query.cgi?%s' % (tko_base_url, query_string)
259 text.append('\n')
260 text.append(url)
261
262 body = '\n'.join(text)
263 print '---------------------------------------------------'
264 print 'Subject: ', subject
mbligh45ffc432008-12-09 23:35:17 +0000265 print body
mbligh37eceaa2008-12-15 22:56:37 +0000266 print '---------------------------------------------------'
mbligh45ffc432008-12-09 23:35:17 +0000267 if email_from and email_to:
mbligh37eceaa2008-12-15 22:56:37 +0000268 print 'Sending email ...'
mbligh45ffc432008-12-09 23:35:17 +0000269 utils.send_email(email_from, email_to, subject, body)
270 print
mbligh37eceaa2008-12-15 22:56:37 +0000271
mbligh45ffc432008-12-09 23:35:17 +0000272
mbligh1354c9d2008-12-22 14:56:13 +0000273 def print_job_result(self, job):
274 """
275 Print the result of a single job.
276 job: a job object
277 """
278 if job.result is None:
279 print 'PENDING',
280 elif job.result == True:
281 print 'PASSED',
282 elif job.result == False:
283 print 'FAILED',
284 print ' %s : %s' % (job.id, job.name)
285
286
mbligh5280e3b2008-12-22 14:39:28 +0000287 def poll_all_jobs(self, tko, jobs, email_from, email_to):
mbligh45ffc432008-12-09 23:35:17 +0000288 """
289 Poll all jobs in a list.
290 jobs: list of job objects to poll
291 email_from: send notification email upon completion from here
292 email_from: send notification email upon completion to here
293
294 Returns:
mbligh5b618382008-12-03 15:24:01 +0000295 a) All complete successfully (return True)
296 b) One or more has failed (return False)
297 c) Cannot tell yet (return None)
298 """
mbligh45ffc432008-12-09 23:35:17 +0000299 results = []
mbligh5b618382008-12-03 15:24:01 +0000300 for job in jobs:
mbligh5280e3b2008-12-22 14:39:28 +0000301 job.result = self.poll_job_results(tko, job, debug=False)
mbligh45ffc432008-12-09 23:35:17 +0000302 results.append(job.result)
303 if job.result is not None and not job.notified:
304 self.result_notify(job, email_from, email_to)
305 job.notified = True
306
mbligh1354c9d2008-12-22 14:56:13 +0000307 self.print_job_result(job)
mbligh45ffc432008-12-09 23:35:17 +0000308
309 if None in results:
310 return None
311 elif False in results:
312 return False
313 else:
314 return True
mbligh5b618382008-12-03 15:24:01 +0000315
316
mbligh1f23f362008-12-22 14:46:12 +0000317 def _included_platform(self, host, platforms):
318 """
319 See if host's platforms matches any of the patterns in the included
320 platforms list.
321 """
322 if not platforms:
323 return True # No filtering of platforms
324 for platform in platforms:
325 if re.search(platform, host.platform):
326 return True
327 return False
328
329
mbligh5b618382008-12-03 15:24:01 +0000330 def invoke_test(self, pairing, kernel, kernel_label, priority='Medium'):
331 """
332 Given a pairing of a control file to a machine label, find all machines
333 with that label, and submit that control file to them.
334
335 Returns a job object
336 """
337 job_name = '%s : %s' % (pairing.machine_label, kernel_label)
338 hosts = self.get_hosts(multiple_labels=[pairing.machine_label])
mbligh1f23f362008-12-22 14:46:12 +0000339 platforms = pairing.platforms
340 hosts = [h for h in hosts if self._included_platform(h, platforms)]
mbligh45ffc432008-12-09 23:35:17 +0000341 host_list = [h.hostname for h in hosts if h.status != 'Repair Failed']
mbligh1f23f362008-12-22 14:46:12 +0000342 print 'HOSTS: %s' % host_list
mbligh5b618382008-12-03 15:24:01 +0000343 new_job = self.create_job_by_test(name=job_name,
344 dependencies=[pairing.machine_label],
345 tests=[pairing.control_file],
346 priority=priority,
347 hosts=host_list,
mbligh1354c9d2008-12-22 14:56:13 +0000348 kernel=kernel,
349 use_container=pairing.container)
mbligh5b618382008-12-03 15:24:01 +0000350 print 'Invoked test %s : %s' % (new_job.id, job_name)
351 return new_job
352
353
mbligh5280e3b2008-12-22 14:39:28 +0000354 def _job_test_results(self, tko, job):
mbligh5b618382008-12-03 15:24:01 +0000355 """
mbligh5280e3b2008-12-22 14:39:28 +0000356 Retrieve test results for a job
mbligh5b618382008-12-03 15:24:01 +0000357 """
mbligh5280e3b2008-12-22 14:39:28 +0000358 job.test_status = {}
359 try:
360 test_statuses = tko.get_status_counts(job=job.id)
361 except Exception:
362 print "Ignoring exception on poll job; RPC interface is flaky"
363 traceback.print_exc()
364 return
365
366 for test_status in test_statuses:
367 hostname = test_status.hostname
368 if hostname not in job.test_status:
369 job.test_status[hostname] = TestResults()
370 job.test_status[hostname].add(test_status)
371
372
373 def _job_results_platform_map(self, job):
374 job.results_platform_map = {}
mbligh5b618382008-12-03 15:24:01 +0000375 try:
mbligh45ffc432008-12-09 23:35:17 +0000376 job_statuses = self.get_host_queue_entries(job=job.id)
mbligh5b618382008-12-03 15:24:01 +0000377 except Exception:
378 print "Ignoring exception on poll job; RPC interface is flaky"
379 traceback.print_exc()
380 return None
mbligh5280e3b2008-12-22 14:39:28 +0000381
mbligh5b618382008-12-03 15:24:01 +0000382 platform_map = {}
mbligh5280e3b2008-12-22 14:39:28 +0000383 job.job_status = {}
mbligh5b618382008-12-03 15:24:01 +0000384 for job_status in job_statuses:
385 hostname = job_status.host.hostname
mbligh5280e3b2008-12-22 14:39:28 +0000386 job.job_status[hostname] = job_status.status
mbligh5b618382008-12-03 15:24:01 +0000387 status = job_status.status
mbligh5280e3b2008-12-22 14:39:28 +0000388 if hostname in job.test_status and job.test_status[hostname].fail:
389 # Job status doesn't reflect failed tests, override that
390 status = 'Failed'
mbligh5b618382008-12-03 15:24:01 +0000391 platform = job_status.host.platform
392 if platform not in platform_map:
393 platform_map[platform] = {'Total' : [hostname]}
394 else:
395 platform_map[platform]['Total'].append(hostname)
396 new_host_list = platform_map[platform].get(status, []) + [hostname]
397 platform_map[platform][status] = new_host_list
mbligh45ffc432008-12-09 23:35:17 +0000398 job.results_platform_map = platform_map
mbligh5280e3b2008-12-22 14:39:28 +0000399
400
401 def poll_job_results(self, tko, job, debug=False):
402 """
403 Analyse all job results by platform, return:
mbligh5b618382008-12-03 15:24:01 +0000404
mbligh5280e3b2008-12-22 14:39:28 +0000405 False: if any platform has more than one failure
406 None: if any platform has more than one machine not yet Good.
407 True: if all platforms have at least all-but-one machines Good.
408 """
409 self._job_test_results(tko, job)
410 self._job_results_platform_map(job)
411
mbligh5b618382008-12-03 15:24:01 +0000412 good_platforms = []
413 bad_platforms = []
414 unknown_platforms = []
mbligh5280e3b2008-12-22 14:39:28 +0000415 platform_map = job.results_platform_map
mbligh5b618382008-12-03 15:24:01 +0000416 for platform in platform_map:
417 total = len(platform_map[platform]['Total'])
418 completed = len(platform_map[platform].get('Completed', []))
419 failed = len(platform_map[platform].get('Failed', []))
420 if failed > 1:
421 bad_platforms.append(platform)
422 elif completed + 1 >= total:
423 # if all or all but one are good, call the job good.
424 good_platforms.append(platform)
425 else:
426 unknown_platforms.append(platform)
427 detail = []
428 for status in platform_map[platform]:
429 if status == 'Total':
430 continue
431 detail.append('%s=%s' % (status,platform_map[platform][status]))
432 if debug:
433 print '%20s %d/%d %s' % (platform, completed, total,
434 ' '.join(detail))
435 print
436
437 if len(bad_platforms) > 0:
438 if debug:
439 print 'Result bad - platforms: ' + ' '.join(bad_platforms)
440 return False
441 if len(unknown_platforms) > 0:
442 if debug:
443 platform_list = ' '.join(unknown_platforms)
444 print 'Result unknown - platforms: ', platform_list
445 return None
446 if debug:
447 platform_list = ' '.join(good_platforms)
448 print 'Result good - all platforms passed: ', platform_list
449 return True
450
451
mbligh5280e3b2008-12-22 14:39:28 +0000452class TestResults(object):
453 """
454 Container class used to hold the results of the tests for a job
455 """
456 def __init__(self):
457 self.good = []
458 self.fail = []
459
460
461 def add(self, result):
462 if result.complete_count - result.pass_count > 0:
463 self.fail.append(result.test_name)
464 else:
465 self.good.append(result.test_name)
466
467
468class RpcObject(object):
mbligh67647152008-11-19 00:18:14 +0000469 """
470 Generic object used to construct python objects from rpc calls
471 """
472 def __init__(self, afe, hash):
473 self.afe = afe
474 self.hash = hash
475 self.__dict__.update(hash)
476
477
478 def __str__(self):
479 return dump_object(self.__repr__(), self)
480
481
mbligh1354c9d2008-12-22 14:56:13 +0000482class ControlFile(RpcObject):
483 """
484 AFE control file object
485
486 Fields: synch_count, dependencies, control_file, is_server
487 """
488 def __repr__(self):
489 return 'CONTROL FILE: %s' % self.control_file
490
491
mbligh5280e3b2008-12-22 14:39:28 +0000492class Label(RpcObject):
mbligh67647152008-11-19 00:18:14 +0000493 """
494 AFE label object
495
496 Fields:
497 name, invalid, platform, kernel_config, id, only_if_needed
498 """
499 def __repr__(self):
500 return 'LABEL: %s' % self.name
501
502
503 def add_hosts(self, hosts):
504 return self.afe.run('label_add_hosts', self.id, hosts)
505
506
507 def remove_hosts(self, hosts):
508 return self.afe.run('label_remove_hosts', self.id, hosts)
509
510
mbligh5280e3b2008-12-22 14:39:28 +0000511class Acl(RpcObject):
mbligh67647152008-11-19 00:18:14 +0000512 """
513 AFE acl object
514
515 Fields:
516 users, hosts, description, name, id
517 """
518 def __repr__(self):
519 return 'ACL: %s' % self.name
520
521
522 def add_hosts(self, hosts):
523 self.afe.log('Adding hosts %s to ACL %s' % (hosts, self.name))
524 return self.afe.run('acl_group_add_hosts', self.id, hosts)
525
526
527 def remove_hosts(self, hosts):
528 self.afe.log('Removing hosts %s from ACL %s' % (hosts, self.name))
529 return self.afe.run('acl_group_remove_hosts', self.id, hosts)
530
531
mbligh5280e3b2008-12-22 14:39:28 +0000532class Job(RpcObject):
mbligh67647152008-11-19 00:18:14 +0000533 """
534 AFE job object
535
536 Fields:
537 name, control_file, control_type, synch_count, reboot_before,
538 run_verify, priority, email_list, created_on, dependencies,
539 timeout, owner, reboot_after, id
540 """
541 def __repr__(self):
542 return 'JOB: %s' % self.id
543
544
mbligh5280e3b2008-12-22 14:39:28 +0000545class JobStatus(RpcObject):
mbligh67647152008-11-19 00:18:14 +0000546 """
547 AFE job_status object
548
549 Fields:
550 status, complete, deleted, meta_host, host, active, execution_subdir, id
551 """
552 def __init__(self, afe, hash):
553 # This should call super
554 self.afe = afe
555 self.hash = hash
556 self.__dict__.update(hash)
mbligh5280e3b2008-12-22 14:39:28 +0000557 self.job = Job(afe, self.job)
mbligh67647152008-11-19 00:18:14 +0000558 if self.host:
559 self.host = afe.get_hosts(hostname=self.host['hostname'])[0]
560
561
562 def __repr__(self):
563 return 'JOB STATUS: %s-%s' % (self.job.id, self.host.hostname)
564
565
mbligh5280e3b2008-12-22 14:39:28 +0000566class Host(RpcObject):
mbligh67647152008-11-19 00:18:14 +0000567 """
568 AFE host object
569
570 Fields:
571 status, lock_time, locked_by, locked, hostname, invalid,
572 synch_id, labels, platform, protection, dirty, id
573 """
574 def __repr__(self):
575 return 'HOST OBJECT: %s' % self.hostname
576
577
578 def show(self):
579 labels = list(set(self.labels) - set([self.platform]))
580 print '%-6s %-7s %-7s %-16s %s' % (self.hostname, self.status,
581 self.locked, self.platform,
582 ', '.join(labels))
583
584
585 def get_acls(self):
586 return self.afe.get_acls(hosts__hostname=self.hostname)
587
588
589 def add_acl(self, acl_name):
590 self.afe.log('Adding ACL %s to host %s' % (acl_name, self.hostname))
591 return self.afe.run('acl_group_add_hosts', id=acl_name,
592 hosts=[self.hostname])
593
594
595 def remove_acl(self, acl_name):
596 self.afe.log('Removing ACL %s from host %s' % (acl_name, self.hostname))
597 return self.afe.run('acl_group_remove_hosts', id=acl_name,
598 hosts=[self.hostname])
599
600
601 def get_labels(self):
602 return self.afe.get_labels(host__hostname__in=[self.hostname])
603
604
605 def add_labels(self, labels):
606 self.afe.log('Adding labels %s to host %s' % (labels, self.hostname))
607 return self.afe.run('host_add_labels', id=self.id, labels=labels)
608
609
610 def remove_labels(self, labels):
611 self.afe.log('Removing labels %s from host %s' % (labels,self.hostname))
612 return self.afe.run('host_remove_labels', id=self.id, labels=labels)
mbligh5b618382008-12-03 15:24:01 +0000613
614
mbligh5280e3b2008-12-22 14:39:28 +0000615class TestStatus(RpcObject):
mblighc31e4022008-12-11 19:32:30 +0000616 """
617 TKO test status object
618
619 Fields:
620 test_idx, hostname, testname, id
621 complete_count, incomplete_count, group_count, pass_count
622 """
623 def __repr__(self):
624 return 'TEST STATUS: %s' % self.id
625
626
mbligh5b618382008-12-03 15:24:01 +0000627class MachineTestPairing(object):
628 """
629 Object representing the pairing of a machine label with a control file
mbligh1f23f362008-12-22 14:46:12 +0000630
631 machine_label: use machines from this label
632 control_file: use this control file (by name in the frontend)
633 platforms: list of rexeps to filter platforms by. [] => no filtering
mbligh5b618382008-12-03 15:24:01 +0000634 """
mbligh1354c9d2008-12-22 14:56:13 +0000635 def __init__(self, machine_label, control_file, platforms=[],
636 container=False):
mbligh5b618382008-12-03 15:24:01 +0000637 self.machine_label = machine_label
638 self.control_file = control_file
mbligh1f23f362008-12-22 14:46:12 +0000639 self.platforms = platforms
mbligh1354c9d2008-12-22 14:56:13 +0000640 self.container = container
641
642
643 def __repr__(self):
644 return '%s %s %s %s' % (self.machine_label, self.control_file,
645 self.platforms, self.container)