blob: 22d05b81cad33c1efb82f49825fb517dd5a3c53e [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,
mblighb10a60f2007-10-17 00:03:32 +0000221 'machine_idx':job.machine_idx},
222 commit=commit)
mblighe12b8612008-02-12 20:58:14 +0000223 job.index = self.get_last_autonumber_value()
mbligh608c3252007-08-31 13:53:00 +0000224 for test in job.tests:
mbligh432bad42007-10-09 19:56:07 +0000225 self.insert_test(job, test, commit=commit)
mbligh608c3252007-08-31 13:53:00 +0000226
mbligh96b9a5a2007-11-24 19:32:20 +0000227
mbligh432bad42007-10-09 19:56:07 +0000228 def insert_test(self, job, test, commit = None):
229 kver = self.insert_kernel(test.kernel, commit=commit)
mbligh608c3252007-08-31 13:53:00 +0000230 data = {'job_idx':job.index, 'test':test.testname,
mbligh2bd48872007-09-20 18:32:25 +0000231 'subdir':test.subdir, 'kernel_idx':kver,
mbligh8e1ab172007-09-13 17:29:56 +0000232 'status':self.status_idx[test.status],
mbligh2aaeb672007-10-01 14:54:18 +0000233 'reason':test.reason, 'machine_idx':job.machine_idx }
mbligh432bad42007-10-09 19:56:07 +0000234 self.insert('tests', data, commit=commit)
mblighe12b8612008-02-12 20:58:14 +0000235 test_idx = self.get_last_autonumber_value()
mbligh2bd48872007-09-20 18:32:25 +0000236 data = { 'test_idx':test_idx }
237
238 for i in test.iterations:
239 data['iteration'] = i.index
240 for key in i.keyval:
241 data['attribute'] = key
242 data['value'] = i.keyval[key]
mbligh432bad42007-10-09 19:56:07 +0000243 self.insert('iteration_result',
244 data,
245 commit=commit)
mbligh994a23d2007-10-25 15:28:58 +0000246 data = {'test_idx':test_idx, 'attribute':'version', 'value':test.version}
247 self.insert('test_attributes', data, commit=commit)
mblighe9cf9d42007-08-31 08:56:00 +0000248
249
mbligh048e1c92007-10-07 00:10:33 +0000250 def read_machine_map(self):
251 self.machine_group = {}
252 for line in open(self.machine_map, 'r').readlines():
253 (machine, group) = line.split()
254 self.machine_group[machine] = group
255
256
mbligh7a41a862007-11-30 17:44:24 +0000257 def insert_machine(self, job, group = None, commit = None):
258 hostname = job.machine
mbligh048e1c92007-10-07 00:10:33 +0000259 if self.machine_map and not self.machine_group:
260 self.read_machine_map()
261
262 if not group:
263 group = self.machine_group.get(hostname, hostname)
mbligh7a41a862007-11-30 17:44:24 +0000264 if group == hostname and job.machine_owner:
265 group = job.machine_owner + '/' + hostname
266
mbligh432bad42007-10-09 19:56:07 +0000267 self.insert('machines',
268 { 'hostname' : hostname ,
mbligh7a41a862007-11-30 17:44:24 +0000269 'machine_group' : group ,
270 'owner' : job.machine_owner },
mbligh432bad42007-10-09 19:56:07 +0000271 commit=commit)
mblighe12b8612008-02-12 20:58:14 +0000272 return self.get_last_autonumber_value()
mbligh2aaeb672007-10-01 14:54:18 +0000273
274
275 def lookup_machine(self, hostname):
276 where = { 'hostname' : hostname }
277 rows = self.select('machine_idx', 'machines', where)
278 if rows:
279 return rows[0][0]
280 else:
281 return None
282
283
mbligh9bb92fe2007-09-12 15:54:23 +0000284 def lookup_kernel(self, kernel):
285 rows = self.select('kernel_idx', 'kernels',
mbligh048e1c92007-10-07 00:10:33 +0000286 {'kernel_hash':kernel.kernel_hash})
mbligh237bed32007-09-05 13:05:57 +0000287 if rows:
288 return rows[0][0]
289 else:
290 return None
mblighe9cf9d42007-08-31 08:56:00 +0000291
292
mbligh432bad42007-10-09 19:56:07 +0000293 def insert_kernel(self, kernel, commit = None):
mbligh9bb92fe2007-09-12 15:54:23 +0000294 kver = self.lookup_kernel(kernel)
mbligh237bed32007-09-05 13:05:57 +0000295 if kver:
296 return kver
mbligh432bad42007-10-09 19:56:07 +0000297 self.insert('kernels',
298 {'base':kernel.base,
299 'kernel_hash':kernel.kernel_hash,
300 'printable':kernel.base},
301 commit=commit)
mbligh9bb92fe2007-09-12 15:54:23 +0000302 # WARNING - incorrectly shoving base into printable here.
mblighe12b8612008-02-12 20:58:14 +0000303 kver = self.get_last_autonumber_value()
mbligh237bed32007-09-05 13:05:57 +0000304 for patch in kernel.patches:
mbligh432bad42007-10-09 19:56:07 +0000305 self.insert_patch(kver, patch, commit=commit)
mbligh237bed32007-09-05 13:05:57 +0000306 return kver
307
308
mbligh432bad42007-10-09 19:56:07 +0000309 def insert_patch(self, kver, patch, commit = None):
mbligh237bed32007-09-05 13:05:57 +0000310 print patch.reference
311 name = os.path.basename(patch.reference)[:80]
mbligh432bad42007-10-09 19:56:07 +0000312 self.insert('patches',
313 {'kernel_idx': kver,
314 'name':name,
315 'url':patch.reference,
316 'hash':patch.hash},
317 commit=commit)
mbligh056d0d32006-10-08 22:31:10 +0000318
mbligh048e1c92007-10-07 00:10:33 +0000319
mbligh2bd48872007-09-20 18:32:25 +0000320 def find_test(self, job_idx, subdir):
321 where = { 'job_idx':job_idx , 'subdir':subdir }
322 rows = self.select('test_idx', 'tests', where)
323 if rows:
324 return rows[0][0]
325 else:
326 return None
327
mbligh056d0d32006-10-08 22:31:10 +0000328
mbligh96b9a5a2007-11-24 19:32:20 +0000329 def find_tests(self, job_idx):
330 where = { 'job_idx':job_idx }
331 rows = self.select('test_idx', 'tests', where)
332 if rows:
333 return [row[0] for row in rows]
334 else:
mbligh2e57e7b2007-11-29 16:10:50 +0000335 return []
mbligh96b9a5a2007-11-24 19:32:20 +0000336
337
mbligh056d0d32006-10-08 22:31:10 +0000338 def find_job(self, tag):
mbligh608c3252007-08-31 13:53:00 +0000339 rows = self.select('job_idx', 'jobs', {'tag': tag})
340 if rows:
341 return rows[0][0]
342 else:
343 return None
mblighaf25f062007-12-03 17:48:35 +0000344
345
346# Use a class method as a class factory, generating a relevant database object.
347def db(*args, **dargs):
mbligh6f075f02008-01-25 16:36:16 +0000348 path = os.path.dirname(__file__)
mbligha044e562007-12-07 16:26:13 +0000349 db_type = None
mblighaf25f062007-12-03 17:48:35 +0000350 try:
mbligha044e562007-12-07 16:26:13 +0000351 db_file = os.path.join(path, '.database')
352 db_prefs = open(db_file, 'r')
mblighaf25f062007-12-03 17:48:35 +0000353 host = db_prefs.readline().rstrip()
354 database = db_prefs.readline().rstrip()
mbligha044e562007-12-07 16:26:13 +0000355 db_type = db_prefs.readline().rstrip()
356 except:
357 pass
mblighaf25f062007-12-03 17:48:35 +0000358
mbligha044e562007-12-07 16:26:13 +0000359 if not db_type:
360 db_type = 'mysql'
361
362 db_type = 'db_' + db_type
363 exec 'import %s; db = %s.%s(*args, **dargs)' % (db_type, db_type, db_type)
mblighaf25f062007-12-03 17:48:35 +0000364
365 return db