blob: 107064475565a9967e30942db2265cd0ad000ceb [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
11For docs, see http://autotest//afe/server/noauth/rpc/
12http://docs.djangoproject.com/en/dev/ref/models/querysets/#queryset-api
13"""
14
15import os, time
16import common
17from autotest_lib.frontend.afe import rpc_client_lib
18from autotest_lib.client.common_lib import utils
19
20
21def dump_object(header, obj):
22 """
23 Standard way to print out the frontend objects (eg job, host, acl, label)
24 in a human-readable fashion for debugging
25 """
26 result = header + '\n'
27 for key in obj.hash:
28 if key == 'afe' or key == 'hash':
29 continue
30 result += '%20s: %s\n' % (key, obj.hash[key])
31 return result
32
33
34class afe(object):
35 """
36 AFE class for communicating with the autotest frontend
37
38 All the constructors go in the afe class.
39 Manipulating methods go in the classes themselves
40 """
41 def __init__(self, user=os.environ.get('LOGNAME'),
42 web_server='http://autotest', print_log=True, debug=False):
43 """
44 Create a cached instance of a connection to the AFE
45
46 user: username to connect as
47 web_server: AFE instance to connect to
48 print_log: pring a logging message to stdout on every operation
49 debug: print out all RPC traffic
50 """
51 self.user = user
52 self.print_log = print_log
53 self.debug = debug
54 headers = {'AUTHORIZATION' : self.user}
55 rpc_server = web_server + '/afe/server/noauth/rpc/'
56 self.proxy = rpc_client_lib.get_proxy(rpc_server, headers=headers)
57
58
59 def run(self, call, **dargs):
60 """
61 Make a RPC call to the AFE server
62 """
63 rpc_call = getattr(self.proxy, call)
64 if self.debug:
65 print 'DEBUG: %s %s' % (call, dargs)
66 return utils.strip_unicode(rpc_call(**dargs))
67
68
69 def log(self, message):
70 if self.print_log:
71 print message
72
73
74 def host_statuses(self, live=None):
75 dead_statuses = ['Dead', 'Repair Failed']
76 statuses = self.run('get_static_data')['host_statuses']
77 if live == True:
78 return list(set(statuses) - set(['Dead', 'Repair Failed']))
79 if live == False:
80 return dead_statuses
81 else:
82 return statuses
83
84
85 def get_hosts(self, **dargs):
86 hosts = self.run('get_hosts', **dargs)
87 return [host(self, h) for h in hosts]
88
89
90 def create_host(self, hostname, **dargs):
91 id = self.run('add_host', **dargs)
92 return self.get_hosts(id=id)[0]
93
94
95 def get_labels(self, **dargs):
96 labels = self.run('get_labels', **dargs)
97 return [label(self, l) for l in labels]
98
99
100 def create_label(self, name, **dargs):
101 id = self.run('add_label', **dargs)
102 return self.get_labels(id=id)[0]
103
104
105 def get_acls(self, **dargs):
106 acls = self.run('get_acl_groups', **dargs)
107 return [acl(self, a) for a in acls]
108
109
110 def create_acl(self, name, **dargs):
111 id = self.run('add_acl_group', **dargs)
112 return self.get_acls(id=id)[0]
113
114
115 def get_jobs(self, summary=False, **dargs):
116 if summary:
117 jobs_data = self.run('get_jobs_summary', **dargs)
118 else:
119 jobs_data = self.run('get_jobs', **dargs)
120 return [job(self, j) for j in jobs_data]
121
122
123 def get_host_queue_entries(self, **data):
124 entries = self.run('get_host_queue_entries', **data)
125 return [job_status(self, e) for e in entries]
126
127
128 def create_job_by_test(self, tests, kernel=None, **dargs):
129 """
130 Given a test name, fetch the appropriate control file from the server
131 and submit it
132 """
133 results = self.run('generate_control_file', tests=tests, kernel=kernel,
134 use_container=False, do_push_packages=True)
135 if results['is_server']:
136 dargs['control_type'] = 'Server'
137 else:
138 dargs['control_type'] = 'Client'
139 dargs['dependencies'] = dargs.get('dependencies', []) + \
140 results['dependencies']
141 dargs['control_file'] = results['control_file']
142 dargs['synch_count'] = results['synch_count']
143 return self.create_job(**dargs)
144
145
146 def create_job(self, control_file, name=' ', priority='Medium',
147 control_type='Client', **dargs):
148 id = self.run('create_job', name=name, priority=priority,
149 control_file=control_file, control_type=control_type, **dargs)
150 return self.get_jobs(id=id)[0]
151
152
153class rpc_object(object):
154 """
155 Generic object used to construct python objects from rpc calls
156 """
157 def __init__(self, afe, hash):
158 self.afe = afe
159 self.hash = hash
160 self.__dict__.update(hash)
161
162
163 def __str__(self):
164 return dump_object(self.__repr__(), self)
165
166
167class label(rpc_object):
168 """
169 AFE label object
170
171 Fields:
172 name, invalid, platform, kernel_config, id, only_if_needed
173 """
174 def __repr__(self):
175 return 'LABEL: %s' % self.name
176
177
178 def add_hosts(self, hosts):
179 return self.afe.run('label_add_hosts', self.id, hosts)
180
181
182 def remove_hosts(self, hosts):
183 return self.afe.run('label_remove_hosts', self.id, hosts)
184
185
186class acl(rpc_object):
187 """
188 AFE acl object
189
190 Fields:
191 users, hosts, description, name, id
192 """
193 def __repr__(self):
194 return 'ACL: %s' % self.name
195
196
197 def add_hosts(self, hosts):
198 self.afe.log('Adding hosts %s to ACL %s' % (hosts, self.name))
199 return self.afe.run('acl_group_add_hosts', self.id, hosts)
200
201
202 def remove_hosts(self, hosts):
203 self.afe.log('Removing hosts %s from ACL %s' % (hosts, self.name))
204 return self.afe.run('acl_group_remove_hosts', self.id, hosts)
205
206
207class job(rpc_object):
208 """
209 AFE job object
210
211 Fields:
212 name, control_file, control_type, synch_count, reboot_before,
213 run_verify, priority, email_list, created_on, dependencies,
214 timeout, owner, reboot_after, id
215 """
216 def __repr__(self):
217 return 'JOB: %s' % self.id
218
219
220class job_status(rpc_object):
221 """
222 AFE job_status object
223
224 Fields:
225 status, complete, deleted, meta_host, host, active, execution_subdir, id
226 """
227 def __init__(self, afe, hash):
228 # This should call super
229 self.afe = afe
230 self.hash = hash
231 self.__dict__.update(hash)
232 self.job = job(afe, self.job)
233 if self.host:
234 self.host = afe.get_hosts(hostname=self.host['hostname'])[0]
235
236
237 def __repr__(self):
238 return 'JOB STATUS: %s-%s' % (self.job.id, self.host.hostname)
239
240
241class host(rpc_object):
242 """
243 AFE host object
244
245 Fields:
246 status, lock_time, locked_by, locked, hostname, invalid,
247 synch_id, labels, platform, protection, dirty, id
248 """
249 def __repr__(self):
250 return 'HOST OBJECT: %s' % self.hostname
251
252
253 def show(self):
254 labels = list(set(self.labels) - set([self.platform]))
255 print '%-6s %-7s %-7s %-16s %s' % (self.hostname, self.status,
256 self.locked, self.platform,
257 ', '.join(labels))
258
259
260 def get_acls(self):
261 return self.afe.get_acls(hosts__hostname=self.hostname)
262
263
264 def add_acl(self, acl_name):
265 self.afe.log('Adding ACL %s to host %s' % (acl_name, self.hostname))
266 return self.afe.run('acl_group_add_hosts', id=acl_name,
267 hosts=[self.hostname])
268
269
270 def remove_acl(self, acl_name):
271 self.afe.log('Removing ACL %s from host %s' % (acl_name, self.hostname))
272 return self.afe.run('acl_group_remove_hosts', id=acl_name,
273 hosts=[self.hostname])
274
275
276 def get_labels(self):
277 return self.afe.get_labels(host__hostname__in=[self.hostname])
278
279
280 def add_labels(self, labels):
281 self.afe.log('Adding labels %s to host %s' % (labels, self.hostname))
282 return self.afe.run('host_add_labels', id=self.id, labels=labels)
283
284
285 def remove_labels(self, labels):
286 self.afe.log('Removing labels %s from host %s' % (labels,self.hostname))
287 return self.afe.run('host_remove_labels', id=self.id, labels=labels)