blob: 15173da6057c93c9a50a5418dbdf27ae2be467bc [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],
mblighc2514542008-02-19 15:54:26 +0000236 'reason':test.reason, 'machine_idx':job.machine_idx,
237 'finished_time':test.finished_time}
mbligh432bad42007-10-09 19:56:07 +0000238 self.insert('tests', data, commit=commit)
mblighe12b8612008-02-12 20:58:14 +0000239 test_idx = self.get_last_autonumber_value()
mbligh2bd48872007-09-20 18:32:25 +0000240 data = { 'test_idx':test_idx }
241
242 for i in test.iterations:
243 data['iteration'] = i.index
244 for key in i.keyval:
245 data['attribute'] = key
246 data['value'] = i.keyval[key]
mbligh432bad42007-10-09 19:56:07 +0000247 self.insert('iteration_result',
248 data,
249 commit=commit)
mbligh994a23d2007-10-25 15:28:58 +0000250 data = {'test_idx':test_idx, 'attribute':'version', 'value':test.version}
251 self.insert('test_attributes', data, commit=commit)
mblighe9cf9d42007-08-31 08:56:00 +0000252
253
mbligh048e1c92007-10-07 00:10:33 +0000254 def read_machine_map(self):
255 self.machine_group = {}
256 for line in open(self.machine_map, 'r').readlines():
257 (machine, group) = line.split()
258 self.machine_group[machine] = group
259
260
mbligh7a41a862007-11-30 17:44:24 +0000261 def insert_machine(self, job, group = None, commit = None):
262 hostname = job.machine
mbligh048e1c92007-10-07 00:10:33 +0000263 if self.machine_map and not self.machine_group:
264 self.read_machine_map()
265
266 if not group:
267 group = self.machine_group.get(hostname, hostname)
mbligh7a41a862007-11-30 17:44:24 +0000268 if group == hostname and job.machine_owner:
269 group = job.machine_owner + '/' + hostname
270
mbligh432bad42007-10-09 19:56:07 +0000271 self.insert('machines',
272 { 'hostname' : hostname ,
mbligh7a41a862007-11-30 17:44:24 +0000273 'machine_group' : group ,
274 'owner' : job.machine_owner },
mbligh432bad42007-10-09 19:56:07 +0000275 commit=commit)
mblighe12b8612008-02-12 20:58:14 +0000276 return self.get_last_autonumber_value()
mbligh2aaeb672007-10-01 14:54:18 +0000277
278
279 def lookup_machine(self, hostname):
280 where = { 'hostname' : hostname }
281 rows = self.select('machine_idx', 'machines', where)
282 if rows:
283 return rows[0][0]
284 else:
285 return None
286
287
mbligh9bb92fe2007-09-12 15:54:23 +0000288 def lookup_kernel(self, kernel):
289 rows = self.select('kernel_idx', 'kernels',
mbligh048e1c92007-10-07 00:10:33 +0000290 {'kernel_hash':kernel.kernel_hash})
mbligh237bed32007-09-05 13:05:57 +0000291 if rows:
292 return rows[0][0]
293 else:
294 return None
mblighe9cf9d42007-08-31 08:56:00 +0000295
296
mbligh432bad42007-10-09 19:56:07 +0000297 def insert_kernel(self, kernel, commit = None):
mbligh9bb92fe2007-09-12 15:54:23 +0000298 kver = self.lookup_kernel(kernel)
mbligh237bed32007-09-05 13:05:57 +0000299 if kver:
300 return kver
mbligh432bad42007-10-09 19:56:07 +0000301 self.insert('kernels',
302 {'base':kernel.base,
303 'kernel_hash':kernel.kernel_hash,
304 'printable':kernel.base},
305 commit=commit)
mbligh9bb92fe2007-09-12 15:54:23 +0000306 # WARNING - incorrectly shoving base into printable here.
mblighe12b8612008-02-12 20:58:14 +0000307 kver = self.get_last_autonumber_value()
mbligh237bed32007-09-05 13:05:57 +0000308 for patch in kernel.patches:
mbligh432bad42007-10-09 19:56:07 +0000309 self.insert_patch(kver, patch, commit=commit)
mbligh237bed32007-09-05 13:05:57 +0000310 return kver
311
312
mbligh432bad42007-10-09 19:56:07 +0000313 def insert_patch(self, kver, patch, commit = None):
mbligh237bed32007-09-05 13:05:57 +0000314 print patch.reference
315 name = os.path.basename(patch.reference)[:80]
mbligh432bad42007-10-09 19:56:07 +0000316 self.insert('patches',
317 {'kernel_idx': kver,
318 'name':name,
319 'url':patch.reference,
320 'hash':patch.hash},
321 commit=commit)
mbligh056d0d32006-10-08 22:31:10 +0000322
mbligh048e1c92007-10-07 00:10:33 +0000323
mbligh2bd48872007-09-20 18:32:25 +0000324 def find_test(self, job_idx, subdir):
325 where = { 'job_idx':job_idx , 'subdir':subdir }
326 rows = self.select('test_idx', 'tests', where)
327 if rows:
328 return rows[0][0]
329 else:
330 return None
331
mbligh056d0d32006-10-08 22:31:10 +0000332
mbligh96b9a5a2007-11-24 19:32:20 +0000333 def find_tests(self, job_idx):
334 where = { 'job_idx':job_idx }
335 rows = self.select('test_idx', 'tests', where)
336 if rows:
337 return [row[0] for row in rows]
338 else:
mbligh2e57e7b2007-11-29 16:10:50 +0000339 return []
mbligh96b9a5a2007-11-24 19:32:20 +0000340
341
mbligh056d0d32006-10-08 22:31:10 +0000342 def find_job(self, tag):
mbligh608c3252007-08-31 13:53:00 +0000343 rows = self.select('job_idx', 'jobs', {'tag': tag})
344 if rows:
345 return rows[0][0]
346 else:
347 return None
mblighaf25f062007-12-03 17:48:35 +0000348
349
350# Use a class method as a class factory, generating a relevant database object.
351def db(*args, **dargs):
mbligh6f075f02008-01-25 16:36:16 +0000352 path = os.path.dirname(__file__)
mbligha044e562007-12-07 16:26:13 +0000353 db_type = None
mblighaf25f062007-12-03 17:48:35 +0000354 try:
mbligha044e562007-12-07 16:26:13 +0000355 db_file = os.path.join(path, '.database')
356 db_prefs = open(db_file, 'r')
mblighaf25f062007-12-03 17:48:35 +0000357 host = db_prefs.readline().rstrip()
358 database = db_prefs.readline().rstrip()
mbligha044e562007-12-07 16:26:13 +0000359 db_type = db_prefs.readline().rstrip()
360 except:
361 pass
mblighaf25f062007-12-03 17:48:35 +0000362
mbligha044e562007-12-07 16:26:13 +0000363 if not db_type:
364 db_type = 'mysql'
365
366 db_type = 'db_' + db_type
367 exec 'import %s; db = %s.%s(*args, **dargs)' % (db_type, db_type, db_type)
mblighaf25f062007-12-03 17:48:35 +0000368
369 return db