blob: 409d086ee9ba61535ebb01cc9603c8ce19e5ecc8 [file] [log] [blame]
mblighaf25f062007-12-03 17:48:35 +00001import re, os, sys, types
mblighd5c33db2006-10-08 21:34:16 +00002
mblighaf25f062007-12-03 17:48:35 +00003class db_sql:
mbligh2bb6dfd2008-01-10 16:38:30 +00004 def __init__(self, debug = False, autocommit=True, host = None,
5 database = None, user = None, password = None):
mbligh8e1ab172007-09-13 17:29:56 +00006 self.debug = debug
mbligh432bad42007-10-09 19:56:07 +00007 self.autocommit = autocommit
mbligha218d112007-10-03 20:15:09 +00008
mbligh6f075f02008-01-25 16:36:16 +00009 path = os.path.dirname(__file__)
mblighb32cd432007-09-25 18:20:04 +000010 try:
mbligha218d112007-10-03 20:15:09 +000011 file = os.path.join(path, '.database')
mbligh432bad42007-10-09 19:56:07 +000012 db_prefs = open(file, 'r')
mbligh2bb6dfd2008-01-10 16:38:30 +000013 if not host:
14 host = db_prefs.readline().rstrip()
15 if not database:
16 database = db_prefs.readline().rstrip()
mbligh728ff0a2007-09-27 17:05:12 +000017 except:
mbligh2bb6dfd2008-01-10 16:38:30 +000018 if not host:
19 host = 'localhost'
20 if not database:
21 database = 'tko'
mbligh728ff0a2007-09-27 17:05:12 +000022
23 try:
mbligha218d112007-10-03 20:15:09 +000024 file = os.path.join(path, '.priv_login')
25 login = open(file, 'r')
mbligh2bb6dfd2008-01-10 16:38:30 +000026 if not user:
27 user = login.readline().rstrip()
28 if not password:
29 password = login.readline().rstrip()
mbligh95fca572007-09-27 17:11:00 +000030 except:
31 try:
mbligha218d112007-10-03 20:15:09 +000032 file = os.path.join(path, '.unpriv_login')
mbligh432bad42007-10-09 19:56:07 +000033 login = open(file, 'r')
mbligh2bb6dfd2008-01-10 16:38:30 +000034 if not user:
35 user = login.readline().rstrip()
36 if not password:
37 password = login.readline().rstrip()
mbligh95fca572007-09-27 17:11:00 +000038 except:
mbligh2bb6dfd2008-01-10 16:38:30 +000039 if not user:
40 user = 'nobody'
41 if not password:
42 password = ''
mblighb32cd432007-09-25 18:20:04 +000043
mblighaf25f062007-12-03 17:48:35 +000044 self.con = self.connect(host, database, user, password)
mblighd5c33db2006-10-08 21:34:16 +000045 self.cur = self.con.cursor()
46
mbligh8e1ab172007-09-13 17:29:56 +000047 # if not present, insert statuses
48 self.status_idx = {}
49 self.status_word = {}
mblighc82f2462007-10-02 19:19:17 +000050 status_rows = self.select('status_idx, word', 'status', None)
51 for s in status_rows:
mbligh97894452007-10-05 15:10:33 +000052 self.status_idx[s[1]] = s[0]
mblighc82f2462007-10-02 19:19:17 +000053 self.status_word[s[0]] = s[1]
mbligh048e1c92007-10-07 00:10:33 +000054
mbligh6f075f02008-01-25 16:36:16 +000055 dir = os.path.dirname(__file__)
mbligh048e1c92007-10-07 00:10:33 +000056 machine_map = os.path.join(dir, 'machines')
57 if os.path.exists(machine_map):
58 self.machine_map = machine_map
mblighba9c54c2007-10-26 16:41:26 +000059 else:
60 self.machine_map = None
mbligh048e1c92007-10-07 00:10:33 +000061 self.machine_group = {}
62
mbligh8e1ab172007-09-13 17:29:56 +000063
mbligh8e1ab172007-09-13 17:29:56 +000064 def dprint(self, value):
65 if self.debug:
mbligh83f63a02007-12-12 19:13:04 +000066 sys.stdout.write('SQL: ' + str(value) + '\n')
mbligh8e1ab172007-09-13 17:29:56 +000067
mblighd5c33db2006-10-08 21:34:16 +000068
mbligh432bad42007-10-09 19:56:07 +000069 def commit(self):
70 self.con.commit()
71
72
mblighe12b8612008-02-12 20:58:14 +000073 def get_last_autonumber_value(self):
74 self.cur.execute('SELECT LAST_INSERT_ID()', [])
75 return self.cur.fetchall()[0][0]
76
77
mbligh83f63a02007-12-12 19:13:04 +000078 def select(self, fields, table, where, wherein={}, distinct = False,
79 group_by = None):
mbligh608c3252007-08-31 13:53:00 +000080 """\
mbligh12eebfa2008-01-03 02:01:53 +000081 This selects all the fields requested from a
82 specific table with a particular where clause.
83 The where clause can either be a dictionary of
84 field=value pairs, a string, or a tuple of (string,
85 a list of values). The last option is what you
86 should use when accepting user input as it'll
87 protect you against sql injection attacks (if
88 all user data is placed in the array rather than
89 the raw SQL).
90
91 For example:
92 where = ("a = %s AND b = %s", ['val', 'val'])
93 is better than
94 where = "a = 'val' AND b = 'val'"
mbligh608c3252007-08-31 13:53:00 +000095 """
mbligh31d29c42007-09-27 00:51:33 +000096 cmd = ['select']
97 if distinct:
98 cmd.append('distinct')
99 cmd += [fields, 'from', table]
mbligh608c3252007-08-31 13:53:00 +0000100
mbligh31d29c42007-09-27 00:51:33 +0000101 values = []
mbligh414c69e2007-10-05 15:13:06 +0000102 if where and isinstance(where, types.DictionaryType):
mbligh12eebfa2008-01-03 02:01:53 +0000103 # key/value pairs (which should be equal)
mbligh53d14252007-09-12 16:33:14 +0000104 keys = [field + '=%s' for field in where.keys()]
105 values = [where[field] for field in where.keys()]
106
mbligh31d29c42007-09-27 00:51:33 +0000107 cmd.append(' where ' + ' and '.join(keys))
mbligh414c69e2007-10-05 15:13:06 +0000108 elif where and isinstance(where, types.StringTypes):
mbligh12eebfa2008-01-03 02:01:53 +0000109 # the exact string
mbligh414c69e2007-10-05 15:13:06 +0000110 cmd.append(' where ' + where)
mbligh12eebfa2008-01-03 02:01:53 +0000111 elif where and isinstance(where, types.TupleType):
112 # preformatted where clause + values
113 (sql, vals) = where
114 values = vals
115 cmd.append(' where (%s) ' % sql)
mbligh53d14252007-09-12 16:33:14 +0000116
mbligh12eebfa2008-01-03 02:01:53 +0000117 # TODO: this assumes there's a where clause...bad
mbligh85952b42007-12-07 16:28:33 +0000118 if wherein and isinstance(wherein, types.DictionaryType):
119 keys_in = []
120 for field_in in wherein.keys():
121 keys_in += [field_in + ' in (' + ','.join(wherein[field_in])+') ']
122
123 cmd.append(' and '+' and '.join(keys_in))
mbligh83f63a02007-12-12 19:13:04 +0000124 if group_by:
125 cmd.append(' GROUP BY ' + group_by)
126
127 self.dprint('%s %s' % (' '.join(cmd), values))
mbligh31d29c42007-09-27 00:51:33 +0000128 self.cur.execute(' '.join(cmd), values)
mblighd5c33db2006-10-08 21:34:16 +0000129 return self.cur.fetchall()
130
mbligh056d0d32006-10-08 22:31:10 +0000131
mbligh414c69e2007-10-05 15:13:06 +0000132 def select_sql(self, fields, table, sql, values):
133 """\
134 select fields from table "sql"
135 """
136 cmd = 'select %s from %s %s' % (fields, table, sql)
137 self.dprint(cmd)
138 self.cur.execute(cmd, values)
139 return self.cur.fetchall()
140
141
mbligh432bad42007-10-09 19:56:07 +0000142 def insert(self, table, data, commit = None):
mbligh608c3252007-08-31 13:53:00 +0000143 """\
144 'insert into table (keys) values (%s ... %s)', values
145
146 data:
147 dictionary of fields and data
148 """
mbligh432bad42007-10-09 19:56:07 +0000149 if commit == None:
150 commit = self.autocommit
mbligh608c3252007-08-31 13:53:00 +0000151 fields = data.keys()
152 refs = ['%s' for field in fields]
153 values = [data[field] for field in fields]
154 cmd = 'insert into %s (%s) values (%s)' % \
155 (table, ','.join(fields), ','.join(refs))
mbligh53d14252007-09-12 16:33:14 +0000156
mbligh8e1ab172007-09-13 17:29:56 +0000157 self.dprint('%s %s' % (cmd,values))
mbligh608c3252007-08-31 13:53:00 +0000158 self.cur.execute(cmd, values)
mbligh432bad42007-10-09 19:56:07 +0000159 if commit:
160 self.con.commit()
mbligh608c3252007-08-31 13:53:00 +0000161
162
mbligh96b9a5a2007-11-24 19:32:20 +0000163 def delete(self, table, where, commit = None):
164 cmd = ['delete from', table]
165 if commit == None:
166 commit = self.autocommit
167 if where and isinstance(where, types.DictionaryType):
168 keys = [field + '=%s' for field in where.keys()]
169 values = [where[field] for field in where.keys()]
170 cmd += ['where', ' and '.join(keys)]
171 self.dprint('%s %s' % (' '.join(cmd),values))
172 self.cur.execute(' '.join(cmd), values)
173 if commit:
174 self.con.commit()
175
176
mbligh432bad42007-10-09 19:56:07 +0000177 def update(self, table, data, where, commit = None):
mbligh414c69e2007-10-05 15:13:06 +0000178 """\
179 'update table set data values (%s ... %s) where ...'
180
181 data:
182 dictionary of fields and data
183 """
mbligh432bad42007-10-09 19:56:07 +0000184 if commit == None:
185 commit = self.autocommit
mbligh414c69e2007-10-05 15:13:06 +0000186 cmd = 'update %s ' % table
187 fields = data.keys()
188 data_refs = [field + '=%s' for field in fields]
189 data_values = [data[field] for field in fields]
190 cmd += ' set ' + ' and '.join(data_refs)
191
192 where_keys = [field + '=%s' for field in where.keys()]
193 where_values = [where[field] for field in where.keys()]
194 cmd += ' where ' + ' and '.join(where_keys)
195
196 print '%s %s' % (cmd, data_values + where_values)
197 self.cur.execute(cmd, data_values + where_values)
mbligh432bad42007-10-09 19:56:07 +0000198 if commit:
199 self.con.commit()
mbligh414c69e2007-10-05 15:13:06 +0000200
201
mbligh96b9a5a2007-11-24 19:32:20 +0000202 def delete_job(self, tag, commit = None):
203 job_idx = self.find_job(tag)
204 for test_idx in self.find_tests(job_idx):
205 where = {'test_idx' : test_idx}
206 self.delete('iteration_result', where)
207 self.delete('test_attributes', where)
208 where = {'job_idx' : job_idx}
209 self.delete('tests', where)
210 self.delete('jobs', where)
211
212
mbligh432bad42007-10-09 19:56:07 +0000213 def insert_job(self, tag, job, commit = None):
mbligh2aaeb672007-10-01 14:54:18 +0000214 job.machine_idx = self.lookup_machine(job.machine)
215 if not job.machine_idx:
mbligh7a41a862007-11-30 17:44:24 +0000216 job.machine_idx = self.insert_machine(job,
mbligh432bad42007-10-09 19:56:07 +0000217 commit=commit)
mblighb10a60f2007-10-17 00:03:32 +0000218 self.insert('jobs', {'tag':tag,
219 'label': job.label,
mbligh05067a32007-12-03 17:48:04 +0000220 'username': job.user,
mbligh26b992b2008-02-19 15:46:21 +0000221 'machine_idx': job.machine_idx,
222 'queued_time': job.queued_time,
223 'started_time': job.started_time,
224 'finished_time': job.finished_time},
mblighb10a60f2007-10-17 00:03:32 +0000225 commit=commit)
mblighe12b8612008-02-12 20:58:14 +0000226 job.index = self.get_last_autonumber_value()
mbligh608c3252007-08-31 13:53:00 +0000227 for test in job.tests:
mbligh432bad42007-10-09 19:56:07 +0000228 self.insert_test(job, test, commit=commit)
mbligh608c3252007-08-31 13:53:00 +0000229
mbligh96b9a5a2007-11-24 19:32:20 +0000230
mbligh432bad42007-10-09 19:56:07 +0000231 def insert_test(self, job, test, commit = None):
232 kver = self.insert_kernel(test.kernel, commit=commit)
mbligh608c3252007-08-31 13:53:00 +0000233 data = {'job_idx':job.index, 'test':test.testname,
mbligh2bd48872007-09-20 18:32:25 +0000234 'subdir':test.subdir, 'kernel_idx':kver,
mbligh8e1ab172007-09-13 17:29:56 +0000235 'status':self.status_idx[test.status],
mbligh2aaeb672007-10-01 14:54:18 +0000236 'reason':test.reason, 'machine_idx':job.machine_idx }
mbligh432bad42007-10-09 19:56:07 +0000237 self.insert('tests', data, commit=commit)
mblighe12b8612008-02-12 20:58:14 +0000238 test_idx = self.get_last_autonumber_value()
mbligh2bd48872007-09-20 18:32:25 +0000239 data = { 'test_idx':test_idx }
240
241 for i in test.iterations:
242 data['iteration'] = i.index
243 for key in i.keyval:
244 data['attribute'] = key
245 data['value'] = i.keyval[key]
mbligh432bad42007-10-09 19:56:07 +0000246 self.insert('iteration_result',
247 data,
248 commit=commit)
mbligh994a23d2007-10-25 15:28:58 +0000249 data = {'test_idx':test_idx, 'attribute':'version', 'value':test.version}
250 self.insert('test_attributes', data, commit=commit)
mblighe9cf9d42007-08-31 08:56:00 +0000251
252
mbligh048e1c92007-10-07 00:10:33 +0000253 def read_machine_map(self):
254 self.machine_group = {}
255 for line in open(self.machine_map, 'r').readlines():
256 (machine, group) = line.split()
257 self.machine_group[machine] = group
258
259
mbligh7a41a862007-11-30 17:44:24 +0000260 def insert_machine(self, job, group = None, commit = None):
261 hostname = job.machine
mbligh048e1c92007-10-07 00:10:33 +0000262 if self.machine_map and not self.machine_group:
263 self.read_machine_map()
264
265 if not group:
266 group = self.machine_group.get(hostname, hostname)
mbligh7a41a862007-11-30 17:44:24 +0000267 if group == hostname and job.machine_owner:
268 group = job.machine_owner + '/' + hostname
269
mbligh432bad42007-10-09 19:56:07 +0000270 self.insert('machines',
271 { 'hostname' : hostname ,
mbligh7a41a862007-11-30 17:44:24 +0000272 'machine_group' : group ,
273 'owner' : job.machine_owner },
mbligh432bad42007-10-09 19:56:07 +0000274 commit=commit)
mblighe12b8612008-02-12 20:58:14 +0000275 return self.get_last_autonumber_value()
mbligh2aaeb672007-10-01 14:54:18 +0000276
277
278 def lookup_machine(self, hostname):
279 where = { 'hostname' : hostname }
280 rows = self.select('machine_idx', 'machines', where)
281 if rows:
282 return rows[0][0]
283 else:
284 return None
285
286
mbligh9bb92fe2007-09-12 15:54:23 +0000287 def lookup_kernel(self, kernel):
288 rows = self.select('kernel_idx', 'kernels',
mbligh048e1c92007-10-07 00:10:33 +0000289 {'kernel_hash':kernel.kernel_hash})
mbligh237bed32007-09-05 13:05:57 +0000290 if rows:
291 return rows[0][0]
292 else:
293 return None
mblighe9cf9d42007-08-31 08:56:00 +0000294
295
mbligh432bad42007-10-09 19:56:07 +0000296 def insert_kernel(self, kernel, commit = None):
mbligh9bb92fe2007-09-12 15:54:23 +0000297 kver = self.lookup_kernel(kernel)
mbligh237bed32007-09-05 13:05:57 +0000298 if kver:
299 return kver
mbligh432bad42007-10-09 19:56:07 +0000300 self.insert('kernels',
301 {'base':kernel.base,
302 'kernel_hash':kernel.kernel_hash,
303 'printable':kernel.base},
304 commit=commit)
mbligh9bb92fe2007-09-12 15:54:23 +0000305 # WARNING - incorrectly shoving base into printable here.
mblighe12b8612008-02-12 20:58:14 +0000306 kver = self.get_last_autonumber_value()
mbligh237bed32007-09-05 13:05:57 +0000307 for patch in kernel.patches:
mbligh432bad42007-10-09 19:56:07 +0000308 self.insert_patch(kver, patch, commit=commit)
mbligh237bed32007-09-05 13:05:57 +0000309 return kver
310
311
mbligh432bad42007-10-09 19:56:07 +0000312 def insert_patch(self, kver, patch, commit = None):
mbligh237bed32007-09-05 13:05:57 +0000313 print patch.reference
314 name = os.path.basename(patch.reference)[:80]
mbligh432bad42007-10-09 19:56:07 +0000315 self.insert('patches',
316 {'kernel_idx': kver,
317 'name':name,
318 'url':patch.reference,
319 'hash':patch.hash},
320 commit=commit)
mbligh056d0d32006-10-08 22:31:10 +0000321
mbligh048e1c92007-10-07 00:10:33 +0000322
mbligh2bd48872007-09-20 18:32:25 +0000323 def find_test(self, job_idx, subdir):
324 where = { 'job_idx':job_idx , 'subdir':subdir }
325 rows = self.select('test_idx', 'tests', where)
326 if rows:
327 return rows[0][0]
328 else:
329 return None
330
mbligh056d0d32006-10-08 22:31:10 +0000331
mbligh96b9a5a2007-11-24 19:32:20 +0000332 def find_tests(self, job_idx):
333 where = { 'job_idx':job_idx }
334 rows = self.select('test_idx', 'tests', where)
335 if rows:
336 return [row[0] for row in rows]
337 else:
mbligh2e57e7b2007-11-29 16:10:50 +0000338 return []
mbligh96b9a5a2007-11-24 19:32:20 +0000339
340
mbligh056d0d32006-10-08 22:31:10 +0000341 def find_job(self, tag):
mbligh608c3252007-08-31 13:53:00 +0000342 rows = self.select('job_idx', 'jobs', {'tag': tag})
343 if rows:
344 return rows[0][0]
345 else:
346 return None
mblighaf25f062007-12-03 17:48:35 +0000347
348
349# Use a class method as a class factory, generating a relevant database object.
350def db(*args, **dargs):
mbligh6f075f02008-01-25 16:36:16 +0000351 path = os.path.dirname(__file__)
mbligha044e562007-12-07 16:26:13 +0000352 db_type = None
mblighaf25f062007-12-03 17:48:35 +0000353 try:
mbligha044e562007-12-07 16:26:13 +0000354 db_file = os.path.join(path, '.database')
355 db_prefs = open(db_file, 'r')
mblighaf25f062007-12-03 17:48:35 +0000356 host = db_prefs.readline().rstrip()
357 database = db_prefs.readline().rstrip()
mbligha044e562007-12-07 16:26:13 +0000358 db_type = db_prefs.readline().rstrip()
359 except:
360 pass
mblighaf25f062007-12-03 17:48:35 +0000361
mbligha044e562007-12-07 16:26:13 +0000362 if not db_type:
363 db_type = 'mysql'
364
365 db_type = 'db_' + db_type
366 exec 'import %s; db = %s.%s(*args, **dargs)' % (db_type, db_type, db_type)
mblighaf25f062007-12-03 17:48:35 +0000367
368 return db