blob: 254701d54db05df6f395dd729adcf18bb93dee58 [file] [log] [blame]
mblighc6b01ed2006-10-13 17:03:26 +00001#!/usr/bin/python
mbligh26b992b2008-02-19 15:46:21 +00002import os, re, md5, sys, email.Message, smtplib, datetime
mblighc2514542008-02-19 15:54:26 +00003
mbligh532cb272007-11-26 18:54:20 +00004client_bin = os.path.join(os.path.dirname(__file__), '../client/bin')
5sys.path.insert(0, os.path.abspath(client_bin))
6from autotest_utils import read_keyval
mblighbb7b8912006-10-08 03:59:02 +00007
mblighb10a60f2007-10-17 00:03:32 +00008user = re.compile(r'user(\s*)=')
9label = re.compile(r'label(\s*)=')
mblighb85e6b02006-10-08 17:20:56 +000010
mbligh006f2302007-09-13 20:46:46 +000011debug = True
12
mbligh74fc0462007-11-05 20:24:17 +000013# XXX: these mail bits came almost verbatim from mirror/mirror and this should
14# probably be refactored into another file and used by both.
15def mail(from_address, to_addresses, cc_addresses, subject, message_text):
mbligh08415d82007-11-24 19:23:34 +000016 # if passed a string for the to_addresses convert it to a tuple
17 if type(to_addresses) is str:
18 to_addresses = (to_addresses,)
mbligh74fc0462007-11-05 20:24:17 +000019
mbligh08415d82007-11-24 19:23:34 +000020 message = email.Message.Message()
21 message["To"] = ", ".join(to_addresses)
22 message["Cc"] = ", ".join(cc_addresses)
23 message["From"] = from_address
24 message["Subject"] = subject
25 message.set_payload(message_text)
mbligh74fc0462007-11-05 20:24:17 +000026
mbligh08415d82007-11-24 19:23:34 +000027 try:
28 sendmail(message.as_string())
29 except SendmailException, e:
30 server = smtplib.SMTP("localhost")
31 server.sendmail(from_address, to_addresses, cc_addresses, message.as_string())
32 server.quit()
mbligh74fc0462007-11-05 20:24:17 +000033
34
35MAIL = "sendmail"
36
37class SendmailException(Exception):
mbligh08415d82007-11-24 19:23:34 +000038 pass
mbligh74fc0462007-11-05 20:24:17 +000039
40def sendmail(message):
mbligh08415d82007-11-24 19:23:34 +000041 """Send an email using sendmail"""
42 # open a pipe to the mail program and
43 # write the data to the pipe
44 p = os.popen("%s -t" % MAIL, 'w')
45 p.write(message)
46 exitcode = p.close()
47 if exitcode:
48 raise SendmailException("Exit code: %s" % exitcode)
mbligh74fc0462007-11-05 20:24:17 +000049
50# XXX: End of code from mirror/mirror
51
52
mblighb85e6b02006-10-08 17:20:56 +000053def shorten_patch(long):
mbligh340c9682006-10-08 18:26:08 +000054 short = os.path.basename(long)
mblighb85e6b02006-10-08 17:20:56 +000055 short = re.sub(r'^patch-', '', short)
56 short = re.sub(r'\.(bz2|gz)$', '', short)
57 short = re.sub(r'\.patch$', '', short)
58 short = re.sub(r'\+', '_', short)
59 return short
60
mblighbb7b8912006-10-08 03:59:02 +000061
mbligh006f2302007-09-13 20:46:46 +000062def dprint(info):
63 if debug:
64 sys.stderr.write(str(info) + '\n')
65
66
mblighc2514542008-02-19 15:54:26 +000067def get_timestamp(mapping, field):
68 val = mapping.get(field, None)
mbligh26b992b2008-02-19 15:46:21 +000069 if val is not None:
70 val = datetime.datetime.fromtimestamp(int(val))
71 return val
72
73
mblighe9cf9d42007-08-31 08:56:00 +000074class job:
mbligh532cb272007-11-26 18:54:20 +000075 def __init__(self, dir):
mblighe9cf9d42007-08-31 08:56:00 +000076 self.dir = dir
mblighe9cf9d42007-08-31 08:56:00 +000077 self.control = os.path.join(dir, "control")
mblighe8b37a92007-12-19 15:54:11 +000078 self.status = os.path.join(dir, "status.log")
79 if not os.path.exists(self.status):
80 self.status = os.path.join(dir, "status")
mblighbb7b8912006-10-08 03:59:02 +000081 self.variables = {}
mblighe9cf9d42007-08-31 08:56:00 +000082 self.tests = []
mblighbb7b8912006-10-08 03:59:02 +000083 self.kernel = None
84
mblighb10a60f2007-10-17 00:03:32 +000085 # Get the user + tag info from the keyval file.
mbligh8e1ab172007-09-13 17:29:56 +000086 try:
mbligh532cb272007-11-26 18:54:20 +000087 keyval = read_keyval(dir)
88 print keyval
mbligh8e1ab172007-09-13 17:29:56 +000089 except:
mbligh532cb272007-11-26 18:54:20 +000090 keyval = {}
91 self.user = keyval.get('user', None)
92 self.label = keyval.get('label', None)
93 self.machine = keyval.get('hostname', None)
mblighe8b37a92007-12-19 15:54:11 +000094 if self.machine:
95 assert ',' not in self.machine
mblighc2514542008-02-19 15:54:26 +000096 self.queued_time = get_timestamp(keyval, 'job_queued')
97 self.started_time = get_timestamp(keyval, 'job_started')
98 self.finished_time = get_timestamp(keyval, 'job_finished')
mbligh7a41a862007-11-30 17:44:24 +000099 self.machine_owner = keyval.get('owner', None)
mbligh532cb272007-11-26 18:54:20 +0000100
101 if not self.machine:
102 self.get_machine()
103
104 print 'MACHINE NAME: ' + self.machine
105 if not os.path.exists(self.status):
mbligh8e1ab172007-09-13 17:29:56 +0000106 return None
107
mbligh529f2f32007-08-30 11:22:50 +0000108 self.grope_status()
mblighbb7b8912006-10-08 03:59:02 +0000109
110
mbligh532cb272007-11-26 18:54:20 +0000111 def get_machine(self):
112 try:
mbligh7a41a862007-11-30 17:44:24 +0000113 hostname = os.path.join(self.dir, "sysinfo/hostname")
mbligh532cb272007-11-26 18:54:20 +0000114 self.machine = open(hostname, 'r').readline().rstrip()
115 return
116 except:
117 pass
118 try:
mbligh7a41a862007-11-30 17:44:24 +0000119 uname = os.path.join(self.dir, "sysinfo/uname_-a")
mbligh532cb272007-11-26 18:54:20 +0000120 self.machine = open(uname, 'r').readline().split()[1]
121 return
122 except:
123 pass
mbligh215a1662007-11-29 19:16:58 +0000124 raise "Could not figure out machine name"
mbligh532cb272007-11-26 18:54:20 +0000125
126
mblighd5c33db2006-10-08 21:34:16 +0000127 def grope_status(self):
mbligh215a1662007-11-29 19:16:58 +0000128 """
129 Note that what we're looking for here is level 1 groups
130 (ie end markers with 1 tab in front)
131
132 For back-compatiblity, we also count level 0 groups that
133 are not job-level events, if there's no start/end job level
134 markers: "START ---- ----"
135 """
mblighde7335d2007-09-26 16:53:20 +0000136 dprint('=====================================================')
137 dprint(self.dir)
138 dprint('=====================================================')
mbligh049f5e62007-09-30 02:00:14 +0000139 self.kernel = kernel(self.dir)
mbligh237bed32007-09-05 13:05:57 +0000140
mbligh05d81212008-01-10 16:37:35 +0000141 statuses = ['NOSTATUS', 'ERROR', 'ABORT', 'FAIL', 'WARN',
142 'GOOD', 'ALERT']
mbligh40d021b2007-12-03 17:35:51 +0000143 reboot_inprogress = 0 # Saw reboot start and not finish
mbligh9bcfef72008-02-12 20:55:34 +0000144 boot_count = 0
apw569f4782007-12-13 19:32:53 +0000145 alert_pending = None # Saw an ALERT for this test
mblighde7335d2007-09-26 16:53:20 +0000146 group_subdir = None
mbligh215a1662007-11-29 19:16:58 +0000147 sought_level = 0 # we log events at indent level 0
mbligh237bed32007-09-05 13:05:57 +0000148 for line in open(self.status, 'r').readlines():
mbligh215a1662007-11-29 19:16:58 +0000149 dprint('\nSTATUS: ' + line.rstrip())
150 if not re.search(r'^\t*\S', line):
151 dprint('Continuation line, ignoring')
mblighde7335d2007-09-26 16:53:20 +0000152 continue # ignore continuation lines
mbligh215a1662007-11-29 19:16:58 +0000153 if re.search(r'^START\t----\t----', line):
154 sought_level = 1
155 # we now log events at indent level 1
156 dprint('Found job level start marker. Looking for level 1 groups now')
157 continue
158 indent = re.search('^(\t*)', line).group(0).count('\t')
mblighc2514542008-02-19 15:54:26 +0000159 line = line.lstrip()
160 line = line.rstrip('\n')
mbligh215a1662007-11-29 19:16:58 +0000161 if line.startswith('START\t'):
mblighde7335d2007-09-26 16:53:20 +0000162 group_subdir = None
mbligh215a1662007-11-29 19:16:58 +0000163 dprint('start line, ignoring')
mblighde7335d2007-09-26 16:53:20 +0000164 continue # ignore start lines
165 reason = None
mblighc2514542008-02-19 15:54:26 +0000166 if line.startswith('END '):
167 elements = line.split('\t')
168 elements[0] = elements[0][4:] # remove 'END '
mblighbafa6ef2008-01-10 16:36:52 +0000169 end = True
mblighde7335d2007-09-26 16:53:20 +0000170 else:
mblighc2514542008-02-19 15:54:26 +0000171 elements = line.split('\t')
mblighbafa6ef2008-01-10 16:36:52 +0000172 end = False
mblighde7335d2007-09-26 16:53:20 +0000173 (status, subdir, testname, reason) = elements[0:4]
mblighc2514542008-02-19 15:54:26 +0000174 status, subdir, testname = elements[:3]
175 reason = elements[-1]
176 optional_fields = dict(element.split('=', 1)
177 for element in elements[3:-1])
178 dprint('GROPE_STATUS: ' +
179 str([status, subdir, testname, reason]))
apw569f4782007-12-13 19:32:53 +0000180 if status == 'ALERT':
181 dprint('job level alert, recording')
182 alert_pending = reason
183 continue
mblighbafa6ef2008-01-10 16:36:52 +0000184 if testname == 'Autotest.install' and status == 'GOOD':
185 dprint('Sucessful autotest install, ignoring')
mbligh59a479f2007-11-24 19:24:05 +0000186 continue
mblighbafa6ef2008-01-10 16:36:52 +0000187 if testname == '----':
188 if status == 'ABORT' and not end:
189 testname = 'JOB'
190 else:
191 dprint('job level event, ignoring')
192 # This is a job level event, not a test
193 continue
mblighde7335d2007-09-26 16:53:20 +0000194 ################################################
195 # REMOVE THIS SECTION ONCE OLD FORMAT JOBS ARE GONE
196 ################################################
mbligh215a1662007-11-29 19:16:58 +0000197 if re.search(r'^(GOOD|FAIL|WARN) ', line):
mblighde7335d2007-09-26 16:53:20 +0000198 (status, testname, reason) = line.split(None, 2)
199 if testname.startswith('kernel.'):
200 subdir = 'build'
201 else:
202 subdir = testname
203 if testname.startswith('completed'):
204 raise 'testname is crap'
205 ################################################
206 if subdir == '----':
207 subdir = None
208 if line.startswith('END'):
209 subdir = group_subdir
mblighbafa6ef2008-01-10 16:36:52 +0000210 if indent != sought_level and status != 'ABORT':
211 # we're in a block group
mblighde7335d2007-09-26 16:53:20 +0000212 if subdir:
mbligh215a1662007-11-29 19:16:58 +0000213 dprint('set group_subdir: %s' % subdir)
mblighde7335d2007-09-26 16:53:20 +0000214 group_subdir = subdir
mbligh215a1662007-11-29 19:16:58 +0000215 dprint('incorrect indent level %d != %d, ignoring' % (indent, sought_level))
mblighde7335d2007-09-26 16:53:20 +0000216 continue
mbligh215a1662007-11-29 19:16:58 +0000217 if not re.search(r'^(boot$|kernel\.)', testname):
mblighde7335d2007-09-26 16:53:20 +0000218 # This is a real test
219 if subdir and subdir.count('.'):
220 # eg dbench.ext3
221 testname = subdir
mbligh0e21c872008-01-03 16:36:56 +0000222 if testname == 'reboot.start':
223 dprint('reboot start event, ignoring')
224 reboot_inprogress = 1
225 continue
mbligh215a1662007-11-29 19:16:58 +0000226 if testname == 'reboot.verify':
mbligh9bcfef72008-02-12 20:55:34 +0000227 testname = 'boot.%d' % boot_count
mbligh0e21c872008-01-03 16:36:56 +0000228 dprint('reboot verified')
mbligh40d021b2007-12-03 17:35:51 +0000229 reboot_inprogress = 0
mbligh9bcfef72008-02-12 20:55:34 +0000230 boot_count += 1
apw569f4782007-12-13 19:32:53 +0000231 if alert_pending:
232 status = 'ALERT'
233 reason = alert_pending
234 alert_pending = None
mbligh05d81212008-01-10 16:37:35 +0000235 if status in statuses:
236 dprint('Adding: %s\nSubdir:%s\nTestname:%s\n%s'%
237 (status, subdir, testname, reason))
238 else:
239 dprint('WARNING: Invalid status code. Ignoring')
240 continue
mblighc2514542008-02-19 15:54:26 +0000241
242 finished_time = get_timestamp(optional_fields,
243 'timestamp')
244 self.tests.append(test(subdir, testname, status,
245 reason, self.kernel, self,
246 finished_time))
mblighde7335d2007-09-26 16:53:20 +0000247 dprint('')
mbligh05d81212008-01-10 16:37:35 +0000248
mbligh40d021b2007-12-03 17:35:51 +0000249 if reboot_inprogress:
250 dprint('Adding: %s\nSubdir:%s\nTestname:%s\n%s' %
251 (status, subdir, testname, reason))
252 self.tests.append(test('----', 'boot', 'ABORT',
253 'machine did not return from reboot',
254 self.kernel, self))
255 dprint('')
mblighe9cf9d42007-08-31 08:56:00 +0000256
257
258class kernel:
mbligh049f5e62007-09-30 02:00:14 +0000259 def __init__(self, topdir):
mblighe8b37a92007-12-19 15:54:11 +0000260 self.base = 'UNKNOWN'
mblighe9cf9d42007-08-31 08:56:00 +0000261 self.patches = []
mblighe9cf9d42007-08-31 08:56:00 +0000262 patch_hashes = []
mbligh049f5e62007-09-30 02:00:14 +0000263 # HACK. we don't have proper build tags in the status file yet
264 # so we hardcode build/ and do it at the start of the job
mbligh9c39d152007-11-24 19:11:58 +0000265 build_log = os.path.join(topdir, 'build/debug/build_log')
mbligh049f5e62007-09-30 02:00:14 +0000266
mbligh9c39d152007-11-24 19:11:58 +0000267 if os.path.exists(build_log):
268 for line in open(build_log, 'r'):
mbligh049f5e62007-09-30 02:00:14 +0000269 print line
270 (type, rest) = line.split(': ', 1)
271 words = rest.split()
272 if type == 'BASE':
273 self.base = words[0]
274 if type == 'PATCH':
275 print words
276 self.patches.append(patch(*words[0:]))
277 # patch_hashes.append(words[2])
mbligh9c39d152007-11-24 19:11:58 +0000278 else:
279 for sysinfo in ['sysinfo/reboot1', 'sysinfo']:
280 uname_file = os.path.join(topdir, sysinfo, 'uname_-a')
281 if not os.path.exists(uname_file):
282 continue
283 uname = open(uname_file, 'r').readline().split()
284 self.base = uname[2]
mbligh215a1662007-11-29 19:16:58 +0000285 re.sub(r'-autotest$', '', self.base)
mbligh9c39d152007-11-24 19:11:58 +0000286 break
287 print 'kernel.__init__() found kernel version %s' % self.base
mblighe8b37a92007-12-19 15:54:11 +0000288 if self.base == 'UNKNOWN':
289 self.kernel_hash = 'UNKNOWN'
290 else:
mbligh52f97442007-09-14 17:43:28 +0000291 self.kernel_hash = self.get_kver_hash(self.base, patch_hashes)
mblighe9cf9d42007-08-31 08:56:00 +0000292
293
mbligh237bed32007-09-05 13:05:57 +0000294 def get_kver_hash(self, base, patch_hashes):
mblighe9cf9d42007-08-31 08:56:00 +0000295 """\
296 Calculate a hash representing the unique combination of
297 the kernel base version plus
298 """
299 key_string = ','.join([base] + patch_hashes)
300 return md5.new(key_string).hexdigest()
301
302
mbligh237bed32007-09-05 13:05:57 +0000303class patch:
304 def __init__(self, spec, reference=None, hash=None):
305 # NEITHER OF THE ABOVE SHOULD HAVE DEFAULTS!!!! HACK HACK
306 if not reference:
307 reference = spec
308 print 'PATCH::%s %s %s' % (spec, reference, hash)
309 self.spec = spec
310 self.reference = reference
311 self.hash = hash
312
313
mblighe9cf9d42007-08-31 08:56:00 +0000314class test:
mblighc2514542008-02-19 15:54:26 +0000315 def __init__(self, subdir, testname, status, reason, kernel, job,
316 finished_time=None):
mblighde940942007-11-05 17:25:56 +0000317 # NOTE: subdir may be none here for lines that aren't an
318 # actual test
mbligh2bd48872007-09-20 18:32:25 +0000319 self.subdir = subdir
mblighde7335d2007-09-26 16:53:20 +0000320 self.testname = testname
mblighe9cf9d42007-08-31 08:56:00 +0000321 self.status = status
322 self.reason = reason
mblighde940942007-11-05 17:25:56 +0000323 self.version = None
324 self.keyval = None
mbligh994a23d2007-10-25 15:28:58 +0000325
mblighde7335d2007-09-26 16:53:20 +0000326 if subdir:
mblighde940942007-11-05 17:25:56 +0000327 keyval = os.path.join(job.dir, subdir, 'results/keyval')
328 if os.path.exists(keyval):
329 self.keyval = keyval
330 keyval2 = os.path.join(job.dir, subdir, 'keyval')
331 if os.path.exists(keyval2):
332 self.version = open(keyval2, 'r').readline().split('=')[1]
mblighde7335d2007-09-26 16:53:20 +0000333 else:
334 self.keyval = None
mblighe9cf9d42007-08-31 08:56:00 +0000335 self.iterations = []
mbligh237bed32007-09-05 13:05:57 +0000336 self.kernel = kernel
mbligh8e1ab172007-09-13 17:29:56 +0000337 self.machine = job.machine
mblighc2514542008-02-19 15:54:26 +0000338 self.finished_time = finished_time
mblighe9cf9d42007-08-31 08:56:00 +0000339
mblighde7335d2007-09-26 16:53:20 +0000340 dprint("PARSING TEST %s %s %s" % (subdir, testname, self.keyval))
mbligh994a23d2007-10-25 15:28:58 +0000341
mblighde7335d2007-09-26 16:53:20 +0000342 if not self.keyval:
mblighe9cf9d42007-08-31 08:56:00 +0000343 return
344 count = 1
345 lines = []
346 for line in open(self.keyval, 'r').readlines():
mbligh2bd48872007-09-20 18:32:25 +0000347 if not re.search('\S', line): # blank line
mblighe9cf9d42007-08-31 08:56:00 +0000348 self.iterations.append(iteration(count, lines))
349 lines = []
350 count += 1
mblighe9cf9d42007-08-31 08:56:00 +0000351 else:
352 lines.append(line)
353 if lines:
354 self.iterations.append(iteration(count, lines))
355
356
357class iteration:
358 def __init__(self, index, lines):
359 self.index = index
360 self.keyval = {}
361
mbligh2bd48872007-09-20 18:32:25 +0000362 dprint("ADDING ITERATION %d" % index)
mblighe9cf9d42007-08-31 08:56:00 +0000363 for line in lines:
mbligh4921b982007-12-03 17:47:45 +0000364 line = line.rstrip();
mblighe9cf9d42007-08-31 08:56:00 +0000365 (key, value) = line.split('=', 1)
366 self.keyval[key] = value