blob: 1cce50f81461be323594f39458f65c92ce24d56c [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:
mbligh432bad42007-10-09 19:56:07 +00004 def __init__(self, debug = False, autocommit=True):
mbligh8e1ab172007-09-13 17:29:56 +00005 self.debug = debug
mbligh432bad42007-10-09 19:56:07 +00006 self.autocommit = autocommit
mbligha218d112007-10-03 20:15:09 +00007
8 path = os.path.dirname(os.path.abspath(sys.argv[0]))
mblighb32cd432007-09-25 18:20:04 +00009 try:
mbligha218d112007-10-03 20:15:09 +000010 file = os.path.join(path, '.database')
mbligh432bad42007-10-09 19:56:07 +000011 db_prefs = open(file, 'r')
mbligh728ff0a2007-09-27 17:05:12 +000012 host = db_prefs.readline().rstrip()
13 database = db_prefs.readline().rstrip()
14 except:
15 host = 'localhost'
16 database = 'tko'
17
18 try:
mbligha218d112007-10-03 20:15:09 +000019 file = os.path.join(path, '.priv_login')
20 login = open(file, 'r')
mblighb32cd432007-09-25 18:20:04 +000021 user = login.readline().rstrip()
22 password = login.readline().rstrip()
mbligh95fca572007-09-27 17:11:00 +000023 except:
24 try:
mbligha218d112007-10-03 20:15:09 +000025 file = os.path.join(path, '.unpriv_login')
mbligh432bad42007-10-09 19:56:07 +000026 login = open(file, 'r')
mbligh95fca572007-09-27 17:11:00 +000027 user = login.readline().rstrip()
28 password = login.readline().rstrip()
29 except:
30 user = 'nobody'
31 password = ''
mblighb32cd432007-09-25 18:20:04 +000032
mblighaf25f062007-12-03 17:48:35 +000033 self.con = self.connect(host, database, user, password)
mblighd5c33db2006-10-08 21:34:16 +000034 self.cur = self.con.cursor()
35
mbligh8e1ab172007-09-13 17:29:56 +000036 # if not present, insert statuses
37 self.status_idx = {}
38 self.status_word = {}
mblighc82f2462007-10-02 19:19:17 +000039 status_rows = self.select('status_idx, word', 'status', None)
40 for s in status_rows:
mbligh97894452007-10-05 15:10:33 +000041 self.status_idx[s[1]] = s[0]
mblighc82f2462007-10-02 19:19:17 +000042 self.status_word[s[0]] = s[1]
mbligh048e1c92007-10-07 00:10:33 +000043
44 dir = os.path.abspath(os.path.dirname(sys.argv[0]))
45 machine_map = os.path.join(dir, 'machines')
46 if os.path.exists(machine_map):
47 self.machine_map = machine_map
mblighba9c54c2007-10-26 16:41:26 +000048 else:
49 self.machine_map = None
mbligh048e1c92007-10-07 00:10:33 +000050 self.machine_group = {}
51
mbligh8e1ab172007-09-13 17:29:56 +000052
mbligh8e1ab172007-09-13 17:29:56 +000053 def dprint(self, value):
54 if self.debug:
mbligh83f63a02007-12-12 19:13:04 +000055 sys.stdout.write('SQL: ' + str(value) + '\n')
mbligh8e1ab172007-09-13 17:29:56 +000056
mblighd5c33db2006-10-08 21:34:16 +000057
mbligh432bad42007-10-09 19:56:07 +000058 def commit(self):
59 self.con.commit()
60
61
mbligh83f63a02007-12-12 19:13:04 +000062 def select(self, fields, table, where, wherein={}, distinct = False,
63 group_by = None):
mbligh608c3252007-08-31 13:53:00 +000064 """\
mbligh12eebfa2008-01-03 02:01:53 +000065 This selects all the fields requested from a
66 specific table with a particular where clause.
67 The where clause can either be a dictionary of
68 field=value pairs, a string, or a tuple of (string,
69 a list of values). The last option is what you
70 should use when accepting user input as it'll
71 protect you against sql injection attacks (if
72 all user data is placed in the array rather than
73 the raw SQL).
74
75 For example:
76 where = ("a = %s AND b = %s", ['val', 'val'])
77 is better than
78 where = "a = 'val' AND b = 'val'"
mbligh608c3252007-08-31 13:53:00 +000079 """
mbligh31d29c42007-09-27 00:51:33 +000080 cmd = ['select']
81 if distinct:
82 cmd.append('distinct')
83 cmd += [fields, 'from', table]
mbligh608c3252007-08-31 13:53:00 +000084
mbligh31d29c42007-09-27 00:51:33 +000085 values = []
mbligh414c69e2007-10-05 15:13:06 +000086 if where and isinstance(where, types.DictionaryType):
mbligh12eebfa2008-01-03 02:01:53 +000087 # key/value pairs (which should be equal)
mbligh53d14252007-09-12 16:33:14 +000088 keys = [field + '=%s' for field in where.keys()]
89 values = [where[field] for field in where.keys()]
90
mbligh31d29c42007-09-27 00:51:33 +000091 cmd.append(' where ' + ' and '.join(keys))
mbligh414c69e2007-10-05 15:13:06 +000092 elif where and isinstance(where, types.StringTypes):
mbligh12eebfa2008-01-03 02:01:53 +000093 # the exact string
mbligh414c69e2007-10-05 15:13:06 +000094 cmd.append(' where ' + where)
mbligh12eebfa2008-01-03 02:01:53 +000095 elif where and isinstance(where, types.TupleType):
96 # preformatted where clause + values
97 (sql, vals) = where
98 values = vals
99 cmd.append(' where (%s) ' % sql)
mbligh53d14252007-09-12 16:33:14 +0000100
mbligh12eebfa2008-01-03 02:01:53 +0000101 # TODO: this assumes there's a where clause...bad
mbligh85952b42007-12-07 16:28:33 +0000102 if wherein and isinstance(wherein, types.DictionaryType):
103 keys_in = []
104 for field_in in wherein.keys():
105 keys_in += [field_in + ' in (' + ','.join(wherein[field_in])+') ']
106
107 cmd.append(' and '+' and '.join(keys_in))
mbligh83f63a02007-12-12 19:13:04 +0000108 if group_by:
109 cmd.append(' GROUP BY ' + group_by)
110
111 self.dprint('%s %s' % (' '.join(cmd), values))
mbligh31d29c42007-09-27 00:51:33 +0000112 self.cur.execute(' '.join(cmd), values)
mblighd5c33db2006-10-08 21:34:16 +0000113 return self.cur.fetchall()
114
mbligh056d0d32006-10-08 22:31:10 +0000115
mbligh414c69e2007-10-05 15:13:06 +0000116 def select_sql(self, fields, table, sql, values):
117 """\
118 select fields from table "sql"
119 """
120 cmd = 'select %s from %s %s' % (fields, table, sql)
121 self.dprint(cmd)
122 self.cur.execute(cmd, values)
123 return self.cur.fetchall()
124
125
mbligh432bad42007-10-09 19:56:07 +0000126 def insert(self, table, data, commit = None):
mbligh608c3252007-08-31 13:53:00 +0000127 """\
128 'insert into table (keys) values (%s ... %s)', values
129
130 data:
131 dictionary of fields and data
132 """
mbligh432bad42007-10-09 19:56:07 +0000133 if commit == None:
134 commit = self.autocommit
mbligh608c3252007-08-31 13:53:00 +0000135 fields = data.keys()
136 refs = ['%s' for field in fields]
137 values = [data[field] for field in fields]
138 cmd = 'insert into %s (%s) values (%s)' % \
139 (table, ','.join(fields), ','.join(refs))
mbligh53d14252007-09-12 16:33:14 +0000140
mbligh8e1ab172007-09-13 17:29:56 +0000141 self.dprint('%s %s' % (cmd,values))
mbligh608c3252007-08-31 13:53:00 +0000142 self.cur.execute(cmd, values)
mbligh432bad42007-10-09 19:56:07 +0000143 if commit:
144 self.con.commit()
mbligh608c3252007-08-31 13:53:00 +0000145
146
mbligh96b9a5a2007-11-24 19:32:20 +0000147 def delete(self, table, where, commit = None):
148 cmd = ['delete from', table]
149 if commit == None:
150 commit = self.autocommit
151 if where and isinstance(where, types.DictionaryType):
152 keys = [field + '=%s' for field in where.keys()]
153 values = [where[field] for field in where.keys()]
154 cmd += ['where', ' and '.join(keys)]
155 self.dprint('%s %s' % (' '.join(cmd),values))
156 self.cur.execute(' '.join(cmd), values)
157 if commit:
158 self.con.commit()
159
160
mbligh432bad42007-10-09 19:56:07 +0000161 def update(self, table, data, where, commit = None):
mbligh414c69e2007-10-05 15:13:06 +0000162 """\
163 'update table set data values (%s ... %s) where ...'
164
165 data:
166 dictionary of fields and data
167 """
mbligh432bad42007-10-09 19:56:07 +0000168 if commit == None:
169 commit = self.autocommit
mbligh414c69e2007-10-05 15:13:06 +0000170 cmd = 'update %s ' % table
171 fields = data.keys()
172 data_refs = [field + '=%s' for field in fields]
173 data_values = [data[field] for field in fields]
174 cmd += ' set ' + ' and '.join(data_refs)
175
176 where_keys = [field + '=%s' for field in where.keys()]
177 where_values = [where[field] for field in where.keys()]
178 cmd += ' where ' + ' and '.join(where_keys)
179
180 print '%s %s' % (cmd, data_values + where_values)
181 self.cur.execute(cmd, data_values + where_values)
mbligh432bad42007-10-09 19:56:07 +0000182 if commit:
183 self.con.commit()
mbligh414c69e2007-10-05 15:13:06 +0000184
185
mbligh96b9a5a2007-11-24 19:32:20 +0000186 def delete_job(self, tag, commit = None):
187 job_idx = self.find_job(tag)
188 for test_idx in self.find_tests(job_idx):
189 where = {'test_idx' : test_idx}
190 self.delete('iteration_result', where)
191 self.delete('test_attributes', where)
192 where = {'job_idx' : job_idx}
193 self.delete('tests', where)
194 self.delete('jobs', where)
195
196
mbligh432bad42007-10-09 19:56:07 +0000197 def insert_job(self, tag, job, commit = None):
mbligh2aaeb672007-10-01 14:54:18 +0000198 job.machine_idx = self.lookup_machine(job.machine)
199 if not job.machine_idx:
mbligh7a41a862007-11-30 17:44:24 +0000200 job.machine_idx = self.insert_machine(job,
mbligh432bad42007-10-09 19:56:07 +0000201 commit=commit)
mblighb10a60f2007-10-17 00:03:32 +0000202 self.insert('jobs', {'tag':tag,
203 'label': job.label,
mbligh05067a32007-12-03 17:48:04 +0000204 'username': job.user,
mblighb10a60f2007-10-17 00:03:32 +0000205 'machine_idx':job.machine_idx},
206 commit=commit)
mbligh608c3252007-08-31 13:53:00 +0000207 job.index = self.find_job(tag)
208 for test in job.tests:
mbligh432bad42007-10-09 19:56:07 +0000209 self.insert_test(job, test, commit=commit)
mbligh608c3252007-08-31 13:53:00 +0000210
mbligh96b9a5a2007-11-24 19:32:20 +0000211
mbligh432bad42007-10-09 19:56:07 +0000212 def insert_test(self, job, test, commit = None):
213 kver = self.insert_kernel(test.kernel, commit=commit)
mbligh608c3252007-08-31 13:53:00 +0000214 data = {'job_idx':job.index, 'test':test.testname,
mbligh2bd48872007-09-20 18:32:25 +0000215 'subdir':test.subdir, 'kernel_idx':kver,
mbligh8e1ab172007-09-13 17:29:56 +0000216 'status':self.status_idx[test.status],
mbligh2aaeb672007-10-01 14:54:18 +0000217 'reason':test.reason, 'machine_idx':job.machine_idx }
mbligh432bad42007-10-09 19:56:07 +0000218 self.insert('tests', data, commit=commit)
mbligh2bd48872007-09-20 18:32:25 +0000219 test_idx = self.find_test(job.index, test.subdir)
220 data = { 'test_idx':test_idx }
221
222 for i in test.iterations:
223 data['iteration'] = i.index
224 for key in i.keyval:
225 data['attribute'] = key
226 data['value'] = i.keyval[key]
mbligh432bad42007-10-09 19:56:07 +0000227 self.insert('iteration_result',
228 data,
229 commit=commit)
mbligh994a23d2007-10-25 15:28:58 +0000230 data = {'test_idx':test_idx, 'attribute':'version', 'value':test.version}
231 self.insert('test_attributes', data, commit=commit)
mblighe9cf9d42007-08-31 08:56:00 +0000232
233
mbligh048e1c92007-10-07 00:10:33 +0000234 def read_machine_map(self):
235 self.machine_group = {}
236 for line in open(self.machine_map, 'r').readlines():
237 (machine, group) = line.split()
238 self.machine_group[machine] = group
239
240
mbligh7a41a862007-11-30 17:44:24 +0000241 def insert_machine(self, job, group = None, commit = None):
242 hostname = job.machine
mbligh048e1c92007-10-07 00:10:33 +0000243 if self.machine_map and not self.machine_group:
244 self.read_machine_map()
245
246 if not group:
247 group = self.machine_group.get(hostname, hostname)
mbligh7a41a862007-11-30 17:44:24 +0000248 if group == hostname and job.machine_owner:
249 group = job.machine_owner + '/' + hostname
250
mbligh432bad42007-10-09 19:56:07 +0000251 self.insert('machines',
252 { 'hostname' : hostname ,
mbligh7a41a862007-11-30 17:44:24 +0000253 'machine_group' : group ,
254 'owner' : job.machine_owner },
mbligh432bad42007-10-09 19:56:07 +0000255 commit=commit)
mbligh2aaeb672007-10-01 14:54:18 +0000256 return self.lookup_machine(hostname)
257
258
259 def lookup_machine(self, hostname):
260 where = { 'hostname' : hostname }
261 rows = self.select('machine_idx', 'machines', where)
262 if rows:
263 return rows[0][0]
264 else:
265 return None
266
267
mbligh9bb92fe2007-09-12 15:54:23 +0000268 def lookup_kernel(self, kernel):
269 rows = self.select('kernel_idx', 'kernels',
mbligh048e1c92007-10-07 00:10:33 +0000270 {'kernel_hash':kernel.kernel_hash})
mbligh237bed32007-09-05 13:05:57 +0000271 if rows:
272 return rows[0][0]
273 else:
274 return None
mblighe9cf9d42007-08-31 08:56:00 +0000275
276
mbligh432bad42007-10-09 19:56:07 +0000277 def insert_kernel(self, kernel, commit = None):
mbligh9bb92fe2007-09-12 15:54:23 +0000278 kver = self.lookup_kernel(kernel)
mbligh237bed32007-09-05 13:05:57 +0000279 if kver:
280 return kver
mbligh432bad42007-10-09 19:56:07 +0000281 self.insert('kernels',
282 {'base':kernel.base,
283 'kernel_hash':kernel.kernel_hash,
284 'printable':kernel.base},
285 commit=commit)
mbligh9bb92fe2007-09-12 15:54:23 +0000286 # WARNING - incorrectly shoving base into printable here.
287 kver = self.lookup_kernel(kernel)
mbligh237bed32007-09-05 13:05:57 +0000288 for patch in kernel.patches:
mbligh432bad42007-10-09 19:56:07 +0000289 self.insert_patch(kver, patch, commit=commit)
mbligh237bed32007-09-05 13:05:57 +0000290 return kver
291
292
mbligh432bad42007-10-09 19:56:07 +0000293 def insert_patch(self, kver, patch, commit = None):
mbligh237bed32007-09-05 13:05:57 +0000294 print patch.reference
295 name = os.path.basename(patch.reference)[:80]
mbligh432bad42007-10-09 19:56:07 +0000296 self.insert('patches',
297 {'kernel_idx': kver,
298 'name':name,
299 'url':patch.reference,
300 'hash':patch.hash},
301 commit=commit)
mbligh056d0d32006-10-08 22:31:10 +0000302
mbligh048e1c92007-10-07 00:10:33 +0000303
mbligh2bd48872007-09-20 18:32:25 +0000304 def find_test(self, job_idx, subdir):
305 where = { 'job_idx':job_idx , 'subdir':subdir }
306 rows = self.select('test_idx', 'tests', where)
307 if rows:
308 return rows[0][0]
309 else:
310 return None
311
mbligh056d0d32006-10-08 22:31:10 +0000312
mbligh96b9a5a2007-11-24 19:32:20 +0000313 def find_tests(self, job_idx):
314 where = { 'job_idx':job_idx }
315 rows = self.select('test_idx', 'tests', where)
316 if rows:
317 return [row[0] for row in rows]
318 else:
mbligh2e57e7b2007-11-29 16:10:50 +0000319 return []
mbligh96b9a5a2007-11-24 19:32:20 +0000320
321
mbligh056d0d32006-10-08 22:31:10 +0000322 def find_job(self, tag):
mbligh608c3252007-08-31 13:53:00 +0000323 rows = self.select('job_idx', 'jobs', {'tag': tag})
324 if rows:
325 return rows[0][0]
326 else:
327 return None
mblighaf25f062007-12-03 17:48:35 +0000328
329
330# Use a class method as a class factory, generating a relevant database object.
331def db(*args, **dargs):
332 path = os.path.dirname(os.path.abspath(sys.argv[0]))
mbligha044e562007-12-07 16:26:13 +0000333 db_type = None
mblighaf25f062007-12-03 17:48:35 +0000334 try:
mbligha044e562007-12-07 16:26:13 +0000335 db_file = os.path.join(path, '.database')
336 db_prefs = open(db_file, 'r')
mblighaf25f062007-12-03 17:48:35 +0000337 host = db_prefs.readline().rstrip()
338 database = db_prefs.readline().rstrip()
mbligha044e562007-12-07 16:26:13 +0000339 db_type = db_prefs.readline().rstrip()
340 except:
341 pass
mblighaf25f062007-12-03 17:48:35 +0000342
mbligha044e562007-12-07 16:26:13 +0000343 if not db_type:
344 db_type = 'mysql'
345
346 db_type = 'db_' + db_type
347 exec 'import %s; db = %s.%s(*args, **dargs)' % (db_type, db_type, db_type)
mblighaf25f062007-12-03 17:48:35 +0000348
349 return db