blob: 789517a13e657ae41db22698be2a035812833342 [file] [log] [blame]
mblighaf25f062007-12-03 17:48:35 +00001import re, os, sys, types
mblighed4d6dd2008-02-27 16:49:43 +00002from common import global_config
3
mblighd5c33db2006-10-08 21:34:16 +00004
mblighaf25f062007-12-03 17:48:35 +00005class db_sql:
mbligh2bb6dfd2008-01-10 16:38:30 +00006 def __init__(self, debug = False, autocommit=True, host = None,
7 database = None, user = None, password = None):
mbligh8e1ab172007-09-13 17:29:56 +00008 self.debug = debug
mbligh432bad42007-10-09 19:56:07 +00009 self.autocommit = autocommit
mblighed4d6dd2008-02-27 16:49:43 +000010
mbligh6f075f02008-01-25 16:36:16 +000011 path = os.path.dirname(__file__)
mblighed4d6dd2008-02-27 16:49:43 +000012
13 # grab the global config
14 c = global_config.global_config
15
16 # grab the host, database
17 if not host:
18 host = c.get_config_value("TKO", "host", 'localhost')
19 if not database:
20 database = c.get_config_value("TKO", "database", 'tko')
21
22 # grab the user and password
23 if not user:
24 user = c.get_config_value("TKO", "user", 'nobody')
25 if not password:
26 password = c.get_config_value("TKO", "password", '')
27
mblighaf25f062007-12-03 17:48:35 +000028 self.con = self.connect(host, database, user, password)
mblighd5c33db2006-10-08 21:34:16 +000029 self.cur = self.con.cursor()
30
mbligh8e1ab172007-09-13 17:29:56 +000031 # if not present, insert statuses
32 self.status_idx = {}
33 self.status_word = {}
mblighc82f2462007-10-02 19:19:17 +000034 status_rows = self.select('status_idx, word', 'status', None)
35 for s in status_rows:
mbligh97894452007-10-05 15:10:33 +000036 self.status_idx[s[1]] = s[0]
mblighc82f2462007-10-02 19:19:17 +000037 self.status_word[s[0]] = s[1]
mbligh048e1c92007-10-07 00:10:33 +000038
mbligh6f075f02008-01-25 16:36:16 +000039 dir = os.path.dirname(__file__)
mbligh048e1c92007-10-07 00:10:33 +000040 machine_map = os.path.join(dir, 'machines')
41 if os.path.exists(machine_map):
42 self.machine_map = machine_map
mblighba9c54c2007-10-26 16:41:26 +000043 else:
44 self.machine_map = None
mbligh048e1c92007-10-07 00:10:33 +000045 self.machine_group = {}
46
mbligh8e1ab172007-09-13 17:29:56 +000047
mbligh8e1ab172007-09-13 17:29:56 +000048 def dprint(self, value):
49 if self.debug:
mbligh83f63a02007-12-12 19:13:04 +000050 sys.stdout.write('SQL: ' + str(value) + '\n')
mbligh8e1ab172007-09-13 17:29:56 +000051
mblighd5c33db2006-10-08 21:34:16 +000052
mbligh432bad42007-10-09 19:56:07 +000053 def commit(self):
54 self.con.commit()
55
56
mblighe12b8612008-02-12 20:58:14 +000057 def get_last_autonumber_value(self):
58 self.cur.execute('SELECT LAST_INSERT_ID()', [])
59 return self.cur.fetchall()[0][0]
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,
mbligh26b992b2008-02-19 15:46:21 +0000205 'machine_idx': job.machine_idx,
206 'queued_time': job.queued_time,
207 'started_time': job.started_time,
208 'finished_time': job.finished_time},
mblighb10a60f2007-10-17 00:03:32 +0000209 commit=commit)
mblighe12b8612008-02-12 20:58:14 +0000210 job.index = self.get_last_autonumber_value()
mbligh608c3252007-08-31 13:53:00 +0000211 for test in job.tests:
mbligh432bad42007-10-09 19:56:07 +0000212 self.insert_test(job, test, commit=commit)
mbligh608c3252007-08-31 13:53:00 +0000213
mbligh96b9a5a2007-11-24 19:32:20 +0000214
mbligh432bad42007-10-09 19:56:07 +0000215 def insert_test(self, job, test, commit = None):
216 kver = self.insert_kernel(test.kernel, commit=commit)
mbligh608c3252007-08-31 13:53:00 +0000217 data = {'job_idx':job.index, 'test':test.testname,
mbligh2bd48872007-09-20 18:32:25 +0000218 'subdir':test.subdir, 'kernel_idx':kver,
mbligh8e1ab172007-09-13 17:29:56 +0000219 'status':self.status_idx[test.status],
mblighc2514542008-02-19 15:54:26 +0000220 'reason':test.reason, 'machine_idx':job.machine_idx,
221 'finished_time':test.finished_time}
mbligh432bad42007-10-09 19:56:07 +0000222 self.insert('tests', data, commit=commit)
mblighe12b8612008-02-12 20:58:14 +0000223 test_idx = self.get_last_autonumber_value()
mbligh2bd48872007-09-20 18:32:25 +0000224 data = { 'test_idx':test_idx }
225
226 for i in test.iterations:
227 data['iteration'] = i.index
228 for key in i.keyval:
229 data['attribute'] = key
230 data['value'] = i.keyval[key]
mbligh432bad42007-10-09 19:56:07 +0000231 self.insert('iteration_result',
232 data,
233 commit=commit)
mbligh994a23d2007-10-25 15:28:58 +0000234 data = {'test_idx':test_idx, 'attribute':'version', 'value':test.version}
235 self.insert('test_attributes', data, commit=commit)
mblighe9cf9d42007-08-31 08:56:00 +0000236
237
mbligh048e1c92007-10-07 00:10:33 +0000238 def read_machine_map(self):
239 self.machine_group = {}
240 for line in open(self.machine_map, 'r').readlines():
241 (machine, group) = line.split()
242 self.machine_group[machine] = group
243
244
mbligh7a41a862007-11-30 17:44:24 +0000245 def insert_machine(self, job, group = None, commit = None):
246 hostname = job.machine
mbligh048e1c92007-10-07 00:10:33 +0000247 if self.machine_map and not self.machine_group:
248 self.read_machine_map()
249
250 if not group:
251 group = self.machine_group.get(hostname, hostname)
mbligh7a41a862007-11-30 17:44:24 +0000252 if group == hostname and job.machine_owner:
253 group = job.machine_owner + '/' + hostname
254
mbligh432bad42007-10-09 19:56:07 +0000255 self.insert('machines',
256 { 'hostname' : hostname ,
mbligh7a41a862007-11-30 17:44:24 +0000257 'machine_group' : group ,
258 'owner' : job.machine_owner },
mbligh432bad42007-10-09 19:56:07 +0000259 commit=commit)
mblighe12b8612008-02-12 20:58:14 +0000260 return self.get_last_autonumber_value()
mbligh2aaeb672007-10-01 14:54:18 +0000261
262
263 def lookup_machine(self, hostname):
264 where = { 'hostname' : hostname }
265 rows = self.select('machine_idx', 'machines', where)
266 if rows:
267 return rows[0][0]
268 else:
269 return None
270
271
mbligh9bb92fe2007-09-12 15:54:23 +0000272 def lookup_kernel(self, kernel):
273 rows = self.select('kernel_idx', 'kernels',
mbligh048e1c92007-10-07 00:10:33 +0000274 {'kernel_hash':kernel.kernel_hash})
mbligh237bed32007-09-05 13:05:57 +0000275 if rows:
276 return rows[0][0]
277 else:
278 return None
mblighe9cf9d42007-08-31 08:56:00 +0000279
280
mbligh432bad42007-10-09 19:56:07 +0000281 def insert_kernel(self, kernel, commit = None):
mbligh9bb92fe2007-09-12 15:54:23 +0000282 kver = self.lookup_kernel(kernel)
mbligh237bed32007-09-05 13:05:57 +0000283 if kver:
284 return kver
apw7a7316b2008-02-21 17:42:05 +0000285
286 # If this kernel has any significant patches, append their hash
287 # as diferentiator.
288 printable = kernel.base
289 patch_count = 0
290 for patch in kernel.patches:
291 match = re.match(r'.*(-mm[0-9]+|-git[0-9]+)\.(bz2|gz)$',
292 patch.reference)
293 if not match:
294 patch_count += 1
295
mbligh432bad42007-10-09 19:56:07 +0000296 self.insert('kernels',
297 {'base':kernel.base,
298 'kernel_hash':kernel.kernel_hash,
apw7a7316b2008-02-21 17:42:05 +0000299 'printable':printable},
mbligh432bad42007-10-09 19:56:07 +0000300 commit=commit)
mblighe12b8612008-02-12 20:58:14 +0000301 kver = self.get_last_autonumber_value()
apw7a7316b2008-02-21 17:42:05 +0000302
303 if patch_count > 0:
304 printable += ' p%d' % (kver)
305 self.update('kernels',
306 {'printable':printable},
307 {'kernel_idx':kver})
308
mbligh237bed32007-09-05 13:05:57 +0000309 for patch in kernel.patches:
mbligh432bad42007-10-09 19:56:07 +0000310 self.insert_patch(kver, patch, commit=commit)
mbligh237bed32007-09-05 13:05:57 +0000311 return kver
312
313
mbligh432bad42007-10-09 19:56:07 +0000314 def insert_patch(self, kver, patch, commit = None):
mbligh237bed32007-09-05 13:05:57 +0000315 print patch.reference
316 name = os.path.basename(patch.reference)[:80]
mbligh432bad42007-10-09 19:56:07 +0000317 self.insert('patches',
318 {'kernel_idx': kver,
319 'name':name,
320 'url':patch.reference,
321 'hash':patch.hash},
322 commit=commit)
mbligh056d0d32006-10-08 22:31:10 +0000323
mbligh048e1c92007-10-07 00:10:33 +0000324
mbligh2bd48872007-09-20 18:32:25 +0000325 def find_test(self, job_idx, subdir):
326 where = { 'job_idx':job_idx , 'subdir':subdir }
327 rows = self.select('test_idx', 'tests', where)
328 if rows:
329 return rows[0][0]
330 else:
331 return None
332
mbligh056d0d32006-10-08 22:31:10 +0000333
mbligh96b9a5a2007-11-24 19:32:20 +0000334 def find_tests(self, job_idx):
335 where = { 'job_idx':job_idx }
336 rows = self.select('test_idx', 'tests', where)
337 if rows:
338 return [row[0] for row in rows]
339 else:
mbligh2e57e7b2007-11-29 16:10:50 +0000340 return []
mbligh96b9a5a2007-11-24 19:32:20 +0000341
342
mbligh056d0d32006-10-08 22:31:10 +0000343 def find_job(self, tag):
mbligh608c3252007-08-31 13:53:00 +0000344 rows = self.select('job_idx', 'jobs', {'tag': tag})
345 if rows:
346 return rows[0][0]
347 else:
348 return None
mblighaf25f062007-12-03 17:48:35 +0000349
350
351# Use a class method as a class factory, generating a relevant database object.
352def db(*args, **dargs):
mbligh6f075f02008-01-25 16:36:16 +0000353 path = os.path.dirname(__file__)
mbligha044e562007-12-07 16:26:13 +0000354 db_type = None
mblighed4d6dd2008-02-27 16:49:43 +0000355
356 # read db_type from global config
357 c = global_config.global_config
358 db_type = c.get_config_value("TKO", "db_type", 'mysql')
mbligha044e562007-12-07 16:26:13 +0000359 db_type = 'db_' + db_type
mblighed4d6dd2008-02-27 16:49:43 +0000360 exec ('import %s; db = %s.%s(*args, **dargs)'
361 % (db_type, db_type, db_type))
mblighaf25f062007-12-03 17:48:35 +0000362
363 return db