blob: 08fcb687722757146c42613279fec6a280fc94c5 [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
mbligh532cb272007-11-26 18:54:20 +00003client_bin = os.path.join(os.path.dirname(__file__), '../client/bin')
4sys.path.insert(0, os.path.abspath(client_bin))
5from autotest_utils import read_keyval
mblighbb7b8912006-10-08 03:59:02 +00006
mblighb10a60f2007-10-17 00:03:32 +00007user = re.compile(r'user(\s*)=')
8label = re.compile(r'label(\s*)=')
mblighb85e6b02006-10-08 17:20:56 +00009
mbligh006f2302007-09-13 20:46:46 +000010debug = True
11
mbligh74fc0462007-11-05 20:24:17 +000012# XXX: these mail bits came almost verbatim from mirror/mirror and this should
13# probably be refactored into another file and used by both.
14def mail(from_address, to_addresses, cc_addresses, subject, message_text):
mbligh08415d82007-11-24 19:23:34 +000015 # if passed a string for the to_addresses convert it to a tuple
16 if type(to_addresses) is str:
17 to_addresses = (to_addresses,)
mbligh74fc0462007-11-05 20:24:17 +000018
mbligh08415d82007-11-24 19:23:34 +000019 message = email.Message.Message()
20 message["To"] = ", ".join(to_addresses)
21 message["Cc"] = ", ".join(cc_addresses)
22 message["From"] = from_address
23 message["Subject"] = subject
24 message.set_payload(message_text)
mbligh74fc0462007-11-05 20:24:17 +000025
mbligh08415d82007-11-24 19:23:34 +000026 try:
27 sendmail(message.as_string())
28 except SendmailException, e:
29 server = smtplib.SMTP("localhost")
30 server.sendmail(from_address, to_addresses, cc_addresses, message.as_string())
31 server.quit()
mbligh74fc0462007-11-05 20:24:17 +000032
33
34MAIL = "sendmail"
35
36class SendmailException(Exception):
mbligh08415d82007-11-24 19:23:34 +000037 pass
mbligh74fc0462007-11-05 20:24:17 +000038
39def sendmail(message):
mbligh08415d82007-11-24 19:23:34 +000040 """Send an email using sendmail"""
41 # open a pipe to the mail program and
42 # write the data to the pipe
43 p = os.popen("%s -t" % MAIL, 'w')
44 p.write(message)
45 exitcode = p.close()
46 if exitcode:
47 raise SendmailException("Exit code: %s" % exitcode)
mbligh74fc0462007-11-05 20:24:17 +000048
49# XXX: End of code from mirror/mirror
50
51
mblighb85e6b02006-10-08 17:20:56 +000052def shorten_patch(long):
mbligh340c9682006-10-08 18:26:08 +000053 short = os.path.basename(long)
mblighb85e6b02006-10-08 17:20:56 +000054 short = re.sub(r'^patch-', '', short)
55 short = re.sub(r'\.(bz2|gz)$', '', short)
56 short = re.sub(r'\.patch$', '', short)
57 short = re.sub(r'\+', '_', short)
58 return short
59
mblighbb7b8912006-10-08 03:59:02 +000060
mbligh006f2302007-09-13 20:46:46 +000061def dprint(info):
62 if debug:
63 sys.stderr.write(str(info) + '\n')
64
65
mbligh26b992b2008-02-19 15:46:21 +000066def keyval_timestamp(keyval, field):
67 val = keyval.get(field, None)
68 if val is not None:
69 val = datetime.datetime.fromtimestamp(int(val))
70 return val
71
72
mblighe9cf9d42007-08-31 08:56:00 +000073class job:
mbligh532cb272007-11-26 18:54:20 +000074 def __init__(self, dir):
mblighe9cf9d42007-08-31 08:56:00 +000075 self.dir = dir
mblighe9cf9d42007-08-31 08:56:00 +000076 self.control = os.path.join(dir, "control")
mblighe8b37a92007-12-19 15:54:11 +000077 self.status = os.path.join(dir, "status.log")
78 if not os.path.exists(self.status):
79 self.status = os.path.join(dir, "status")
mblighbb7b8912006-10-08 03:59:02 +000080 self.variables = {}
mblighe9cf9d42007-08-31 08:56:00 +000081 self.tests = []
mblighbb7b8912006-10-08 03:59:02 +000082 self.kernel = None
83
mblighb10a60f2007-10-17 00:03:32 +000084 # Get the user + tag info from the keyval file.
mbligh8e1ab172007-09-13 17:29:56 +000085 try:
mbligh532cb272007-11-26 18:54:20 +000086 keyval = read_keyval(dir)
87 print keyval
mbligh8e1ab172007-09-13 17:29:56 +000088 except:
mbligh532cb272007-11-26 18:54:20 +000089 keyval = {}
90 self.user = keyval.get('user', None)
91 self.label = keyval.get('label', None)
92 self.machine = keyval.get('hostname', None)
mblighe8b37a92007-12-19 15:54:11 +000093 if self.machine:
94 assert ',' not in self.machine
mbligh26b992b2008-02-19 15:46:21 +000095 self.queued_time = keyval_timestamp(keyval, 'job_queued')
96 self.started_time = keyval_timestamp(keyval, 'job_started')
97 self.finished_time = keyval_timestamp(keyval, 'job_finished')
mbligh7a41a862007-11-30 17:44:24 +000098 self.machine_owner = keyval.get('owner', None)
mbligh532cb272007-11-26 18:54:20 +000099
100 if not self.machine:
101 self.get_machine()
102
103 print 'MACHINE NAME: ' + self.machine
104 if not os.path.exists(self.status):
mbligh8e1ab172007-09-13 17:29:56 +0000105 return None
106
mbligh529f2f32007-08-30 11:22:50 +0000107 self.grope_status()
mblighbb7b8912006-10-08 03:59:02 +0000108
109
mbligh532cb272007-11-26 18:54:20 +0000110 def get_machine(self):
111 try:
mbligh7a41a862007-11-30 17:44:24 +0000112 hostname = os.path.join(self.dir, "sysinfo/hostname")
mbligh532cb272007-11-26 18:54:20 +0000113 self.machine = open(hostname, 'r').readline().rstrip()
114 return
115 except:
116 pass
117 try:
mbligh7a41a862007-11-30 17:44:24 +0000118 uname = os.path.join(self.dir, "sysinfo/uname_-a")
mbligh532cb272007-11-26 18:54:20 +0000119 self.machine = open(uname, 'r').readline().split()[1]
120 return
121 except:
122 pass
mbligh215a1662007-11-29 19:16:58 +0000123 raise "Could not figure out machine name"
mbligh532cb272007-11-26 18:54:20 +0000124
125
mblighd5c33db2006-10-08 21:34:16 +0000126 def grope_status(self):
mbligh215a1662007-11-29 19:16:58 +0000127 """
128 Note that what we're looking for here is level 1 groups
129 (ie end markers with 1 tab in front)
130
131 For back-compatiblity, we also count level 0 groups that
132 are not job-level events, if there's no start/end job level
133 markers: "START ---- ----"
134 """
mblighde7335d2007-09-26 16:53:20 +0000135 dprint('=====================================================')
136 dprint(self.dir)
137 dprint('=====================================================')
mbligh049f5e62007-09-30 02:00:14 +0000138 self.kernel = kernel(self.dir)
mbligh237bed32007-09-05 13:05:57 +0000139
mbligh05d81212008-01-10 16:37:35 +0000140 statuses = ['NOSTATUS', 'ERROR', 'ABORT', 'FAIL', 'WARN',
141 'GOOD', 'ALERT']
mbligh40d021b2007-12-03 17:35:51 +0000142 reboot_inprogress = 0 # Saw reboot start and not finish
mbligh9bcfef72008-02-12 20:55:34 +0000143 boot_count = 0
apw569f4782007-12-13 19:32:53 +0000144 alert_pending = None # Saw an ALERT for this test
mblighde7335d2007-09-26 16:53:20 +0000145 group_subdir = None
mbligh215a1662007-11-29 19:16:58 +0000146 sought_level = 0 # we log events at indent level 0
mbligh237bed32007-09-05 13:05:57 +0000147 for line in open(self.status, 'r').readlines():
mbligh215a1662007-11-29 19:16:58 +0000148 dprint('\nSTATUS: ' + line.rstrip())
149 if not re.search(r'^\t*\S', line):
150 dprint('Continuation line, ignoring')
mblighde7335d2007-09-26 16:53:20 +0000151 continue # ignore continuation lines
mbligh215a1662007-11-29 19:16:58 +0000152 if re.search(r'^START\t----\t----', line):
153 sought_level = 1
154 # we now log events at indent level 1
155 dprint('Found job level start marker. Looking for level 1 groups now')
156 continue
157 indent = re.search('^(\t*)', line).group(0).count('\t')
158 line = line.strip()
159 if line.startswith('START\t'):
mblighde7335d2007-09-26 16:53:20 +0000160 group_subdir = None
mbligh215a1662007-11-29 19:16:58 +0000161 dprint('start line, ignoring')
mblighde7335d2007-09-26 16:53:20 +0000162 continue # ignore start lines
163 reason = None
164 if line.startswith('END'):
165 elements = line.split(None, 4)[1:]
mblighbafa6ef2008-01-10 16:36:52 +0000166 end = True
mblighde7335d2007-09-26 16:53:20 +0000167 else:
168 elements = line.split(None, 3)
mblighbafa6ef2008-01-10 16:36:52 +0000169 end = False
mblighde7335d2007-09-26 16:53:20 +0000170 elements.append(None) # in case no reason specified
171 (status, subdir, testname, reason) = elements[0:4]
mbligh215a1662007-11-29 19:16:58 +0000172 dprint('GROPE_STATUS: ' + str(elements[0:4]))
apw569f4782007-12-13 19:32:53 +0000173 if status == 'ALERT':
174 dprint('job level alert, recording')
175 alert_pending = reason
176 continue
mblighbafa6ef2008-01-10 16:36:52 +0000177 if testname == 'Autotest.install' and status == 'GOOD':
178 dprint('Sucessful autotest install, ignoring')
mbligh59a479f2007-11-24 19:24:05 +0000179 continue
mblighbafa6ef2008-01-10 16:36:52 +0000180 if testname == '----':
181 if status == 'ABORT' and not end:
182 testname = 'JOB'
183 else:
184 dprint('job level event, ignoring')
185 # This is a job level event, not a test
186 continue
mblighde7335d2007-09-26 16:53:20 +0000187 ################################################
188 # REMOVE THIS SECTION ONCE OLD FORMAT JOBS ARE GONE
189 ################################################
mbligh215a1662007-11-29 19:16:58 +0000190 if re.search(r'^(GOOD|FAIL|WARN) ', line):
mblighde7335d2007-09-26 16:53:20 +0000191 (status, testname, reason) = line.split(None, 2)
192 if testname.startswith('kernel.'):
193 subdir = 'build'
194 else:
195 subdir = testname
196 if testname.startswith('completed'):
197 raise 'testname is crap'
198 ################################################
199 if subdir == '----':
200 subdir = None
201 if line.startswith('END'):
202 subdir = group_subdir
mblighbafa6ef2008-01-10 16:36:52 +0000203 if indent != sought_level and status != 'ABORT':
204 # we're in a block group
mblighde7335d2007-09-26 16:53:20 +0000205 if subdir:
mbligh215a1662007-11-29 19:16:58 +0000206 dprint('set group_subdir: %s' % subdir)
mblighde7335d2007-09-26 16:53:20 +0000207 group_subdir = subdir
mbligh215a1662007-11-29 19:16:58 +0000208 dprint('incorrect indent level %d != %d, ignoring' % (indent, sought_level))
mblighde7335d2007-09-26 16:53:20 +0000209 continue
mbligh215a1662007-11-29 19:16:58 +0000210 if not re.search(r'^(boot$|kernel\.)', testname):
mblighde7335d2007-09-26 16:53:20 +0000211 # This is a real test
212 if subdir and subdir.count('.'):
213 # eg dbench.ext3
214 testname = subdir
mbligh0e21c872008-01-03 16:36:56 +0000215 if testname == 'reboot.start':
216 dprint('reboot start event, ignoring')
217 reboot_inprogress = 1
218 continue
mbligh215a1662007-11-29 19:16:58 +0000219 if testname == 'reboot.verify':
mbligh9bcfef72008-02-12 20:55:34 +0000220 testname = 'boot.%d' % boot_count
mbligh0e21c872008-01-03 16:36:56 +0000221 dprint('reboot verified')
mbligh40d021b2007-12-03 17:35:51 +0000222 reboot_inprogress = 0
mbligh9bcfef72008-02-12 20:55:34 +0000223 boot_count += 1
apw569f4782007-12-13 19:32:53 +0000224 if alert_pending:
225 status = 'ALERT'
226 reason = alert_pending
227 alert_pending = None
mbligh05d81212008-01-10 16:37:35 +0000228 if status in statuses:
229 dprint('Adding: %s\nSubdir:%s\nTestname:%s\n%s'%
230 (status, subdir, testname, reason))
231 else:
232 dprint('WARNING: Invalid status code. Ignoring')
233 continue
mblighde7335d2007-09-26 16:53:20 +0000234 self.tests.append(test(subdir, testname, status, reason, self.kernel, self))
235 dprint('')
mbligh05d81212008-01-10 16:37:35 +0000236
mbligh40d021b2007-12-03 17:35:51 +0000237 if reboot_inprogress:
238 dprint('Adding: %s\nSubdir:%s\nTestname:%s\n%s' %
239 (status, subdir, testname, reason))
240 self.tests.append(test('----', 'boot', 'ABORT',
241 'machine did not return from reboot',
242 self.kernel, self))
243 dprint('')
mblighe9cf9d42007-08-31 08:56:00 +0000244
245
246class kernel:
mbligh049f5e62007-09-30 02:00:14 +0000247 def __init__(self, topdir):
mblighe8b37a92007-12-19 15:54:11 +0000248 self.base = 'UNKNOWN'
mblighe9cf9d42007-08-31 08:56:00 +0000249 self.patches = []
mblighe9cf9d42007-08-31 08:56:00 +0000250 patch_hashes = []
mbligh049f5e62007-09-30 02:00:14 +0000251 # HACK. we don't have proper build tags in the status file yet
252 # so we hardcode build/ and do it at the start of the job
mbligh9c39d152007-11-24 19:11:58 +0000253 build_log = os.path.join(topdir, 'build/debug/build_log')
mbligh049f5e62007-09-30 02:00:14 +0000254
mbligh9c39d152007-11-24 19:11:58 +0000255 if os.path.exists(build_log):
256 for line in open(build_log, 'r'):
mbligh049f5e62007-09-30 02:00:14 +0000257 print line
258 (type, rest) = line.split(': ', 1)
259 words = rest.split()
260 if type == 'BASE':
261 self.base = words[0]
262 if type == 'PATCH':
263 print words
264 self.patches.append(patch(*words[0:]))
265 # patch_hashes.append(words[2])
mbligh9c39d152007-11-24 19:11:58 +0000266 else:
267 for sysinfo in ['sysinfo/reboot1', 'sysinfo']:
268 uname_file = os.path.join(topdir, sysinfo, 'uname_-a')
269 if not os.path.exists(uname_file):
270 continue
271 uname = open(uname_file, 'r').readline().split()
272 self.base = uname[2]
mbligh215a1662007-11-29 19:16:58 +0000273 re.sub(r'-autotest$', '', self.base)
mbligh9c39d152007-11-24 19:11:58 +0000274 break
275 print 'kernel.__init__() found kernel version %s' % self.base
mblighe8b37a92007-12-19 15:54:11 +0000276 if self.base == 'UNKNOWN':
277 self.kernel_hash = 'UNKNOWN'
278 else:
mbligh52f97442007-09-14 17:43:28 +0000279 self.kernel_hash = self.get_kver_hash(self.base, patch_hashes)
mblighe9cf9d42007-08-31 08:56:00 +0000280
281
mbligh237bed32007-09-05 13:05:57 +0000282 def get_kver_hash(self, base, patch_hashes):
mblighe9cf9d42007-08-31 08:56:00 +0000283 """\
284 Calculate a hash representing the unique combination of
285 the kernel base version plus
286 """
287 key_string = ','.join([base] + patch_hashes)
288 return md5.new(key_string).hexdigest()
289
290
mbligh237bed32007-09-05 13:05:57 +0000291class patch:
292 def __init__(self, spec, reference=None, hash=None):
293 # NEITHER OF THE ABOVE SHOULD HAVE DEFAULTS!!!! HACK HACK
294 if not reference:
295 reference = spec
296 print 'PATCH::%s %s %s' % (spec, reference, hash)
297 self.spec = spec
298 self.reference = reference
299 self.hash = hash
300
301
mblighe9cf9d42007-08-31 08:56:00 +0000302class test:
mblighde7335d2007-09-26 16:53:20 +0000303 def __init__(self, subdir, testname, status, reason, kernel, job):
mblighde940942007-11-05 17:25:56 +0000304 # NOTE: subdir may be none here for lines that aren't an
305 # actual test
mbligh2bd48872007-09-20 18:32:25 +0000306 self.subdir = subdir
mblighde7335d2007-09-26 16:53:20 +0000307 self.testname = testname
mblighe9cf9d42007-08-31 08:56:00 +0000308 self.status = status
309 self.reason = reason
mblighde940942007-11-05 17:25:56 +0000310 self.version = None
311 self.keyval = None
mbligh994a23d2007-10-25 15:28:58 +0000312
mblighde7335d2007-09-26 16:53:20 +0000313 if subdir:
mblighde940942007-11-05 17:25:56 +0000314 keyval = os.path.join(job.dir, subdir, 'results/keyval')
315 if os.path.exists(keyval):
316 self.keyval = keyval
317 keyval2 = os.path.join(job.dir, subdir, 'keyval')
318 if os.path.exists(keyval2):
319 self.version = open(keyval2, 'r').readline().split('=')[1]
mblighde7335d2007-09-26 16:53:20 +0000320 else:
321 self.keyval = None
mblighe9cf9d42007-08-31 08:56:00 +0000322 self.iterations = []
mbligh237bed32007-09-05 13:05:57 +0000323 self.kernel = kernel
mbligh8e1ab172007-09-13 17:29:56 +0000324 self.machine = job.machine
mblighe9cf9d42007-08-31 08:56:00 +0000325
mblighde7335d2007-09-26 16:53:20 +0000326 dprint("PARSING TEST %s %s %s" % (subdir, testname, self.keyval))
mbligh994a23d2007-10-25 15:28:58 +0000327
mblighde7335d2007-09-26 16:53:20 +0000328 if not self.keyval:
mblighe9cf9d42007-08-31 08:56:00 +0000329 return
330 count = 1
331 lines = []
332 for line in open(self.keyval, 'r').readlines():
mbligh2bd48872007-09-20 18:32:25 +0000333 if not re.search('\S', line): # blank line
mblighe9cf9d42007-08-31 08:56:00 +0000334 self.iterations.append(iteration(count, lines))
335 lines = []
336 count += 1
mblighe9cf9d42007-08-31 08:56:00 +0000337 else:
338 lines.append(line)
339 if lines:
340 self.iterations.append(iteration(count, lines))
341
342
343class iteration:
344 def __init__(self, index, lines):
345 self.index = index
346 self.keyval = {}
347
mbligh2bd48872007-09-20 18:32:25 +0000348 dprint("ADDING ITERATION %d" % index)
mblighe9cf9d42007-08-31 08:56:00 +0000349 for line in lines:
mbligh4921b982007-12-03 17:47:45 +0000350 line = line.rstrip();
mblighe9cf9d42007-08-31 08:56:00 +0000351 (key, value) = line.split('=', 1)
352 self.keyval[key] = value