blob: 31291108ad71096ff4d4092f5709d7b1fdbfcaea [file] [log] [blame]
mbligh65acae52008-04-24 20:21:55 +00001import re, os, sys, types, time, random
Jakob Jueliche2bf3962014-10-02 11:33:17 -07002from django.conf import settings
mbligh96cf0512008-04-17 15:25:38 +00003
4import common
5from autotest_lib.client.common_lib import global_config
jamesrena12b8a02010-06-16 23:28:23 +00006from autotest_lib.tko import utils
mbligh96cf0512008-04-17 15:25:38 +00007
mblighed4d6dd2008-02-27 16:49:43 +00008
mblighaea09602008-04-16 22:59:37 +00009class MySQLTooManyRows(Exception):
jadmanski0afbb632008-06-06 21:10:57 +000010 pass
mblighaea09602008-04-16 22:59:37 +000011
mblighd5c33db2006-10-08 21:34:16 +000012
mbligh7636b3a2008-06-11 15:44:01 +000013class db_sql(object):
jadmanski0afbb632008-06-06 21:10:57 +000014 def __init__(self, debug=False, autocommit=True, host=None,
15 database=None, user=None, password=None):
16 self.debug = debug
17 self.autocommit = autocommit
18 self._load_config(host, database, user, password)
mbligh96cf0512008-04-17 15:25:38 +000019
jadmanski0afbb632008-06-06 21:10:57 +000020 self.con = None
21 self._init_db()
mblighd5c33db2006-10-08 21:34:16 +000022
jadmanski0afbb632008-06-06 21:10:57 +000023 # if not present, insert statuses
24 self.status_idx = {}
25 self.status_word = {}
showardeab66ce2009-12-23 00:03:56 +000026 status_rows = self.select('status_idx, word', 'tko_status', None)
jadmanski0afbb632008-06-06 21:10:57 +000027 for s in status_rows:
28 self.status_idx[s[1]] = s[0]
29 self.status_word[s[0]] = s[1]
mbligh048e1c92007-10-07 00:10:33 +000030
jadmanski0afbb632008-06-06 21:10:57 +000031 machine_map = os.path.join(os.path.dirname(__file__),
32 'machines')
33 if os.path.exists(machine_map):
34 self.machine_map = machine_map
35 else:
36 self.machine_map = None
37 self.machine_group = {}
mbligh048e1c92007-10-07 00:10:33 +000038
mbligh8e1ab172007-09-13 17:29:56 +000039
jadmanski0afbb632008-06-06 21:10:57 +000040 def _load_config(self, host, database, user, password):
Jakob Jueliche2bf3962014-10-02 11:33:17 -070041 """Loads configuration settings required to connect to the database.
42
43 This will try to connect to use the settings prefixed with global_db_.
44 If they do not exist, they un-prefixed settings will be used.
45
46 If parameters are supplied, these will be taken instead of the values
47 in global_config.
48
49 @param host: If set, this host will be used, if not, the host will be
50 retrieved from global_config.
51 @param database: If set, this database will be used, if not, the
52 database will be retrieved from global_config.
53 @param user: If set, this user will be used, if not, the
54 user will be retrieved from global_config.
55 @param password: If set, this password will be used, if not, the
56 password will be retrieved from global_config.
57 """
58 DATABASE_SETTINGS = settings.DATABASES['global']
mbligh65acae52008-04-24 20:21:55 +000059
jadmanski0afbb632008-06-06 21:10:57 +000060 # grab the host, database
61 if host:
62 self.host = host
63 else:
Jakob Jueliche2bf3962014-10-02 11:33:17 -070064 self.host = DATABASE_SETTINGS['HOST']
jadmanski0afbb632008-06-06 21:10:57 +000065 if database:
66 self.database = database
67 else:
Jakob Jueliche2bf3962014-10-02 11:33:17 -070068 self.database = DATABASE_SETTINGS['NAME']
mbligh65acae52008-04-24 20:21:55 +000069
jadmanski0afbb632008-06-06 21:10:57 +000070 # grab the user and password
71 if user:
72 self.user = user
73 else:
Jakob Jueliche2bf3962014-10-02 11:33:17 -070074 self.user = DATABASE_SETTINGS['USER']
mblighdc2c9bb2008-12-22 14:47:35 +000075 if password is not None:
jadmanski0afbb632008-06-06 21:10:57 +000076 self.password = password
77 else:
Jakob Jueliche2bf3962014-10-02 11:33:17 -070078 self.password = DATABASE_SETTINGS['PASSWORD']
mbligh65acae52008-04-24 20:21:55 +000079
Michael Spang7a273472014-10-08 12:08:13 -040080 # grab the timeout configuration
81 self.query_timeout =(
82 DATABASE_SETTINGS.get('OPTIONS', {}).get('timeout', 3600))
83
Jakob Jueliche2bf3962014-10-02 11:33:17 -070084 # Using fallback to non-global in order to work without configuration
85 # overhead on non-shard instances.
86 get_value = global_config.global_config.get_config_value_with_fallback
Jakob Juelich475b82b2014-09-30 11:17:07 -070087 self.min_delay = get_value("AUTOTEST_WEB", "global_db_min_retry_delay",
Jakob Jueliche2bf3962014-10-02 11:33:17 -070088 "min_retry_delay", type=int, default=20)
Jakob Juelich475b82b2014-09-30 11:17:07 -070089 self.max_delay = get_value("AUTOTEST_WEB", "global_db_max_retry_delay",
Jakob Jueliche2bf3962014-10-02 11:33:17 -070090 "max_retry_delay", type=int, default=60)
mbligh65acae52008-04-24 20:21:55 +000091
92
jadmanski0afbb632008-06-06 21:10:57 +000093 def _init_db(self):
94 # make sure we clean up any existing connection
95 if self.con:
96 self.con.close()
97 self.con = None
mbligh65acae52008-04-24 20:21:55 +000098
jadmanski0afbb632008-06-06 21:10:57 +000099 # create the db connection and cursor
100 self.con = self.connect(self.host, self.database,
101 self.user, self.password)
102 self.cur = self.con.cursor()
mbligh96cf0512008-04-17 15:25:38 +0000103
104
jadmanski0afbb632008-06-06 21:10:57 +0000105 def _random_delay(self):
106 delay = random.randint(self.min_delay, self.max_delay)
107 time.sleep(delay)
mbligh65acae52008-04-24 20:21:55 +0000108
109
jadmanski0afbb632008-06-06 21:10:57 +0000110 def run_with_retry(self, function, *args, **dargs):
111 """Call function(*args, **dargs) until either it passes
112 without an operational error, or a timeout is reached.
113 This will re-connect to the database, so it is NOT safe
114 to use this inside of a database transaction.
jadmanskie7a69092008-05-29 21:03:13 +0000115
jadmanski0afbb632008-06-06 21:10:57 +0000116 It can be safely used with transactions, but the
117 transaction start & end must be completely contained
118 within the call to 'function'."""
119 OperationalError = _get_error_class("OperationalError")
mbligh65acae52008-04-24 20:21:55 +0000120
jadmanski0afbb632008-06-06 21:10:57 +0000121 success = False
122 start_time = time.time()
123 while not success:
124 try:
125 result = function(*args, **dargs)
126 except OperationalError, e:
127 self._log_operational_error(e)
128 stop_time = time.time()
129 elapsed_time = stop_time - start_time
130 if elapsed_time > self.query_timeout:
131 raise
132 else:
133 try:
134 self._random_delay()
135 self._init_db()
136 except OperationalError, e:
137 self._log_operational_error(e)
138 else:
139 success = True
140 return result
mbligh96cf0512008-04-17 15:25:38 +0000141
142
jadmanski0afbb632008-06-06 21:10:57 +0000143 def _log_operational_error(self, e):
mbligh097407d2009-02-17 15:49:37 +0000144 msg = ("%s: An operational error occured during a database "
jadmanski5d4c27e2009-03-02 16:45:42 +0000145 "operation: %s" % (time.strftime("%X %x"), str(e)))
jadmanski0afbb632008-06-06 21:10:57 +0000146 print >> sys.stderr, msg
147 sys.stderr.flush() # we want these msgs to show up immediately
jadmanski60d4fa62008-05-06 22:49:41 +0000148
149
jadmanski0afbb632008-06-06 21:10:57 +0000150 def dprint(self, value):
151 if self.debug:
152 sys.stdout.write('SQL: ' + str(value) + '\n')
mbligh8e1ab172007-09-13 17:29:56 +0000153
mblighd5c33db2006-10-08 21:34:16 +0000154
jadmanski0afbb632008-06-06 21:10:57 +0000155 def commit(self):
156 self.con.commit()
mbligh432bad42007-10-09 19:56:07 +0000157
158
Simran Basie129a962012-08-31 13:03:53 -0700159 def rollback(self):
160 self.con.rollback()
161
162
jadmanski0afbb632008-06-06 21:10:57 +0000163 def get_last_autonumber_value(self):
164 self.cur.execute('SELECT LAST_INSERT_ID()', [])
165 return self.cur.fetchall()[0][0]
mblighe12b8612008-02-12 20:58:14 +0000166
167
showardc1a98d12010-01-15 00:22:22 +0000168 def _quote(self, field):
169 return '`%s`' % field
170
171
172 def _where_clause(self, where):
173 if not where:
174 return '', []
175
176 if isinstance(where, dict):
177 # key/value pairs (which should be equal, or None for null)
178 keys, values = [], []
179 for field, value in where.iteritems():
180 quoted_field = self._quote(field)
181 if value is None:
182 keys.append(quoted_field + ' is null')
183 else:
184 keys.append(quoted_field + '=%s')
185 values.append(value)
186 where_clause = ' and '.join(keys)
187 elif isinstance(where, basestring):
188 # the exact string
189 where_clause = where
190 values = []
191 elif isinstance(where, tuple):
192 # preformatted where clause + values
193 where_clause, values = where
194 assert where_clause
195 else:
196 raise ValueError('Invalid "where" value: %r' % where)
197
198 return ' WHERE ' + where_clause, values
199
200
201
202 def select(self, fields, table, where, distinct=False, group_by=None,
203 max_rows=None):
jadmanski0afbb632008-06-06 21:10:57 +0000204 """\
205 This selects all the fields requested from a
206 specific table with a particular where clause.
207 The where clause can either be a dictionary of
208 field=value pairs, a string, or a tuple of (string,
209 a list of values). The last option is what you
210 should use when accepting user input as it'll
211 protect you against sql injection attacks (if
212 all user data is placed in the array rather than
213 the raw SQL).
mbligh12eebfa2008-01-03 02:01:53 +0000214
jadmanski0afbb632008-06-06 21:10:57 +0000215 For example:
216 where = ("a = %s AND b = %s", ['val', 'val'])
217 is better than
218 where = "a = 'val' AND b = 'val'"
219 """
220 cmd = ['select']
221 if distinct:
222 cmd.append('distinct')
223 cmd += [fields, 'from', table]
mbligh608c3252007-08-31 13:53:00 +0000224
showardc1a98d12010-01-15 00:22:22 +0000225 where_clause, values = self._where_clause(where)
226 cmd.append(where_clause)
mbligh96cf0512008-04-17 15:25:38 +0000227
jadmanski0afbb632008-06-06 21:10:57 +0000228 if group_by:
229 cmd.append(' GROUP BY ' + group_by)
mbligh83f63a02007-12-12 19:13:04 +0000230
jadmanski0afbb632008-06-06 21:10:57 +0000231 self.dprint('%s %s' % (' '.join(cmd), values))
mbligh96cf0512008-04-17 15:25:38 +0000232
jadmanski0afbb632008-06-06 21:10:57 +0000233 # create a re-runable function for executing the query
234 def exec_sql():
235 sql = ' '.join(cmd)
236 numRec = self.cur.execute(sql, values)
mblighd876f452008-12-03 15:09:17 +0000237 if max_rows is not None and numRec > max_rows:
jadmanski0afbb632008-06-06 21:10:57 +0000238 msg = 'Exceeded allowed number of records'
239 raise MySQLTooManyRows(msg)
240 return self.cur.fetchall()
mbligh96cf0512008-04-17 15:25:38 +0000241
jadmanski0afbb632008-06-06 21:10:57 +0000242 # run the query, re-trying after operational errors
243 if self.autocommit:
244 return self.run_with_retry(exec_sql)
245 else:
246 return exec_sql()
mblighd5c33db2006-10-08 21:34:16 +0000247
mbligh056d0d32006-10-08 22:31:10 +0000248
jadmanski0afbb632008-06-06 21:10:57 +0000249 def select_sql(self, fields, table, sql, values):
250 """\
251 select fields from table "sql"
252 """
253 cmd = 'select %s from %s %s' % (fields, table, sql)
254 self.dprint(cmd)
mbligh414c69e2007-10-05 15:13:06 +0000255
jadmanski0afbb632008-06-06 21:10:57 +0000256 # create a -re-runable function for executing the query
257 def exec_sql():
258 self.cur.execute(cmd, values)
259 return self.cur.fetchall()
mbligh96b9a5a2007-11-24 19:32:20 +0000260
jadmanski0afbb632008-06-06 21:10:57 +0000261 # run the query, re-trying after operational errors
262 if self.autocommit:
263 return self.run_with_retry(exec_sql)
264 else:
265 return exec_sql()
mbligh96b9a5a2007-11-24 19:32:20 +0000266
mbligh608c3252007-08-31 13:53:00 +0000267
jadmanski0afbb632008-06-06 21:10:57 +0000268 def _exec_sql_with_commit(self, sql, values, commit):
269 if self.autocommit:
270 # re-run the query until it succeeds
271 def exec_sql():
272 self.cur.execute(sql, values)
273 self.con.commit()
274 self.run_with_retry(exec_sql)
275 else:
276 # take one shot at running the query
277 self.cur.execute(sql, values)
278 if commit:
279 self.con.commit()
mbligh96b9a5a2007-11-24 19:32:20 +0000280
mbligh2bd48872007-09-20 18:32:25 +0000281
jadmanskib591fba2008-09-10 16:19:22 +0000282 def insert(self, table, data, commit=None):
jadmanski0afbb632008-06-06 21:10:57 +0000283 """\
284 'insert into table (keys) values (%s ... %s)', values
mbligh96cf0512008-04-17 15:25:38 +0000285
jadmanski0afbb632008-06-06 21:10:57 +0000286 data:
287 dictionary of fields and data
288 """
289 fields = data.keys()
290 refs = ['%s' for field in fields]
291 values = [data[field] for field in fields]
showardc1a98d12010-01-15 00:22:22 +0000292 cmd = ('insert into %s (%s) values (%s)' %
293 (table, ','.join(self._quote(field) for field in fields),
294 ','.join(refs)))
jadmanski0afbb632008-06-06 21:10:57 +0000295 self.dprint('%s %s' % (cmd, values))
mblighe9cf9d42007-08-31 08:56:00 +0000296
jadmanski0afbb632008-06-06 21:10:57 +0000297 self._exec_sql_with_commit(cmd, values, commit)
mblighe9cf9d42007-08-31 08:56:00 +0000298
mbligh048e1c92007-10-07 00:10:33 +0000299
jadmanski0afbb632008-06-06 21:10:57 +0000300 def delete(self, table, where, commit = None):
301 cmd = ['delete from', table]
mblighd876f452008-12-03 15:09:17 +0000302 if commit is None:
jadmanski0afbb632008-06-06 21:10:57 +0000303 commit = self.autocommit
showardc1a98d12010-01-15 00:22:22 +0000304 where_clause, values = self._where_clause(where)
305 cmd.append(where_clause)
jadmanski0afbb632008-06-06 21:10:57 +0000306 sql = ' '.join(cmd)
307 self.dprint('%s %s' % (sql, values))
mbligh048e1c92007-10-07 00:10:33 +0000308
jadmanski0afbb632008-06-06 21:10:57 +0000309 self._exec_sql_with_commit(sql, values, commit)
mbligh048e1c92007-10-07 00:10:33 +0000310
mbligh7a41a862007-11-30 17:44:24 +0000311
jadmanski0afbb632008-06-06 21:10:57 +0000312 def update(self, table, data, where, commit = None):
313 """\
314 'update table set data values (%s ... %s) where ...'
mbligh2aaeb672007-10-01 14:54:18 +0000315
jadmanski0afbb632008-06-06 21:10:57 +0000316 data:
317 dictionary of fields and data
318 """
mblighd876f452008-12-03 15:09:17 +0000319 if commit is None:
jadmanski0afbb632008-06-06 21:10:57 +0000320 commit = self.autocommit
321 cmd = 'update %s ' % table
322 fields = data.keys()
showardc1a98d12010-01-15 00:22:22 +0000323 data_refs = [self._quote(field) + '=%s' for field in fields]
jadmanski0afbb632008-06-06 21:10:57 +0000324 data_values = [data[field] for field in fields]
jadmanski74eebf32008-07-15 20:04:42 +0000325 cmd += ' set ' + ', '.join(data_refs)
mbligh2aaeb672007-10-01 14:54:18 +0000326
showardc1a98d12010-01-15 00:22:22 +0000327 where_clause, where_values = self._where_clause(where)
328 cmd += where_clause
mbligh2aaeb672007-10-01 14:54:18 +0000329
jadmanski0afbb632008-06-06 21:10:57 +0000330 values = data_values + where_values
jadmanski74eebf32008-07-15 20:04:42 +0000331 self.dprint('%s %s' % (cmd, values))
mbligh2aaeb672007-10-01 14:54:18 +0000332
jadmanski0afbb632008-06-06 21:10:57 +0000333 self._exec_sql_with_commit(cmd, values, commit)
mblighe9cf9d42007-08-31 08:56:00 +0000334
335
jadmanski0afbb632008-06-06 21:10:57 +0000336 def delete_job(self, tag, commit = None):
337 job_idx = self.find_job(tag)
338 for test_idx in self.find_tests(job_idx):
339 where = {'test_idx' : test_idx}
showardeab66ce2009-12-23 00:03:56 +0000340 self.delete('tko_iteration_result', where)
Dennis Jeffrey368c54b2013-07-24 11:19:03 -0700341 self.delete('tko_iteration_perf_value', where)
showardeab66ce2009-12-23 00:03:56 +0000342 self.delete('tko_iteration_attributes', where)
343 self.delete('tko_test_attributes', where)
344 self.delete('tko_test_labels_tests', {'test_id': test_idx})
jadmanski0afbb632008-06-06 21:10:57 +0000345 where = {'job_idx' : job_idx}
showardeab66ce2009-12-23 00:03:56 +0000346 self.delete('tko_tests', where)
347 self.delete('tko_jobs', where)
apw7a7316b2008-02-21 17:42:05 +0000348
apw7a7316b2008-02-21 17:42:05 +0000349
jadmanski0afbb632008-06-06 21:10:57 +0000350 def insert_job(self, tag, job, commit = None):
351 job.machine_idx = self.lookup_machine(job.machine)
352 if not job.machine_idx:
showard71b94312009-08-20 23:40:02 +0000353 job.machine_idx = self.insert_machine(job, commit=commit)
354 else:
355 self.update_machine_information(job, commit=commit)
356
jamesrena12b8a02010-06-16 23:28:23 +0000357 afe_job_id = utils.get_afe_job_id(tag)
showardc1c1caf2009-09-08 16:26:50 +0000358
showard0fec8a02009-12-04 01:19:54 +0000359 data = {'tag':tag,
360 'label': job.label,
361 'username': job.user,
362 'machine_idx': job.machine_idx,
363 'queued_time': job.queued_time,
364 'started_time': job.started_time,
365 'finished_time': job.finished_time,
366 'afe_job_id': afe_job_id}
367 is_update = hasattr(job, 'index')
368 if is_update:
showardeab66ce2009-12-23 00:03:56 +0000369 self.update('tko_jobs', data, {'job_idx': job.index}, commit=commit)
showard0fec8a02009-12-04 01:19:54 +0000370 else:
showardeab66ce2009-12-23 00:03:56 +0000371 self.insert('tko_jobs', data, commit=commit)
showard0fec8a02009-12-04 01:19:54 +0000372 job.index = self.get_last_autonumber_value()
showardc1a98d12010-01-15 00:22:22 +0000373 self.update_job_keyvals(job, commit=commit)
jadmanski0afbb632008-06-06 21:10:57 +0000374 for test in job.tests:
375 self.insert_test(job, test, commit=commit)
apw7a7316b2008-02-21 17:42:05 +0000376
mbligh237bed32007-09-05 13:05:57 +0000377
showardc1a98d12010-01-15 00:22:22 +0000378 def update_job_keyvals(self, job, commit=None):
379 for key, value in job.keyval_dict.iteritems():
380 where = {'job_id': job.index, 'key': key}
381 data = dict(where, value=value)
382 exists = self.select('id', 'tko_job_keyvals', where=where)
383
384 if exists:
385 self.update('tko_job_keyvals', data, where=where, commit=commit)
386 else:
387 self.insert('tko_job_keyvals', data, commit=commit)
388
389
jadmanski0afbb632008-06-06 21:10:57 +0000390 def insert_test(self, job, test, commit = None):
391 kver = self.insert_kernel(test.kernel, commit=commit)
392 data = {'job_idx':job.index, 'test':test.testname,
393 'subdir':test.subdir, 'kernel_idx':kver,
394 'status':self.status_idx[test.status],
395 'reason':test.reason, 'machine_idx':job.machine_idx,
396 'started_time': test.started_time,
397 'finished_time':test.finished_time}
jadmanski9b6babf2009-04-21 17:57:40 +0000398 is_update = hasattr(test, "test_idx")
399 if is_update:
jadmanski74eebf32008-07-15 20:04:42 +0000400 test_idx = test.test_idx
showardeab66ce2009-12-23 00:03:56 +0000401 self.update('tko_tests', data,
402 {'test_idx': test_idx}, commit=commit)
jadmanskib591fba2008-09-10 16:19:22 +0000403 where = {'test_idx': test_idx}
showardeab66ce2009-12-23 00:03:56 +0000404 self.delete('tko_iteration_result', where)
Dennis Jeffrey368c54b2013-07-24 11:19:03 -0700405 self.delete('tko_iteration_perf_value', where)
showardeab66ce2009-12-23 00:03:56 +0000406 self.delete('tko_iteration_attributes', where)
showard0fec8a02009-12-04 01:19:54 +0000407 where['user_created'] = 0
showardeab66ce2009-12-23 00:03:56 +0000408 self.delete('tko_test_attributes', where)
jadmanski74eebf32008-07-15 20:04:42 +0000409 else:
showardeab66ce2009-12-23 00:03:56 +0000410 self.insert('tko_tests', data, commit=commit)
jadmanski74eebf32008-07-15 20:04:42 +0000411 test_idx = test.test_idx = self.get_last_autonumber_value()
412 data = {'test_idx': test_idx}
mbligh237bed32007-09-05 13:05:57 +0000413
jadmanski0afbb632008-06-06 21:10:57 +0000414 for i in test.iterations:
415 data['iteration'] = i.index
416 for key, value in i.attr_keyval.iteritems():
417 data['attribute'] = key
418 data['value'] = value
showardeab66ce2009-12-23 00:03:56 +0000419 self.insert('tko_iteration_attributes', data,
jadmanski0afbb632008-06-06 21:10:57 +0000420 commit=commit)
421 for key, value in i.perf_keyval.iteritems():
422 data['attribute'] = key
423 data['value'] = value
showardeab66ce2009-12-23 00:03:56 +0000424 self.insert('tko_iteration_result', data,
mbligh432bad42007-10-09 19:56:07 +0000425 commit=commit)
mbligh056d0d32006-10-08 22:31:10 +0000426
Dennis Jeffrey368c54b2013-07-24 11:19:03 -0700427 data = {'test_idx': test_idx}
428 for i in test.perf_values:
429 data['iteration'] = i.index
430 for perf_dict in i.perf_measurements:
431 data['description'] = perf_dict['description']
432 data['value'] = perf_dict['value']
433 data['stddev'] = perf_dict['stddev']
434 data['units'] = perf_dict['units']
435 data['higher_is_better'] = perf_dict['higher_is_better']
Fang Deng7f24f0b2013-11-12 11:22:16 -0800436 data['graph'] = perf_dict['graph']
Dennis Jeffrey368c54b2013-07-24 11:19:03 -0700437 self.insert('tko_iteration_perf_value', data, commit=commit)
438
jadmanski0afbb632008-06-06 21:10:57 +0000439 for key, value in test.attributes.iteritems():
440 data = {'test_idx': test_idx, 'attribute': key,
441 'value': value}
showardeab66ce2009-12-23 00:03:56 +0000442 self.insert('tko_test_attributes', data, commit=commit)
mbligh2bd48872007-09-20 18:32:25 +0000443
jadmanski9b6babf2009-04-21 17:57:40 +0000444 if not is_update:
445 for label_index in test.labels:
446 data = {'test_id': test_idx, 'testlabel_id': label_index}
showardeab66ce2009-12-23 00:03:56 +0000447 self.insert('tko_test_labels_tests', data, commit=commit)
jadmanski9b6babf2009-04-21 17:57:40 +0000448
mbligh056d0d32006-10-08 22:31:10 +0000449
jadmanski0afbb632008-06-06 21:10:57 +0000450 def read_machine_map(self):
showard71b94312009-08-20 23:40:02 +0000451 if self.machine_group or not self.machine_map:
452 return
jadmanski0afbb632008-06-06 21:10:57 +0000453 for line in open(self.machine_map, 'r').readlines():
454 (machine, group) = line.split()
455 self.machine_group[machine] = group
mbligh96b9a5a2007-11-24 19:32:20 +0000456
457
showard71b94312009-08-20 23:40:02 +0000458 def machine_info_dict(self, job):
jadmanski0afbb632008-06-06 21:10:57 +0000459 hostname = job.machine
showard71b94312009-08-20 23:40:02 +0000460 group = job.machine_group
461 owner = job.machine_owner
jadmanski0afbb632008-06-06 21:10:57 +0000462
463 if not group:
showard71b94312009-08-20 23:40:02 +0000464 self.read_machine_map()
jadmanski0afbb632008-06-06 21:10:57 +0000465 group = self.machine_group.get(hostname, hostname)
showard71b94312009-08-20 23:40:02 +0000466 if group == hostname and owner:
467 group = owner + '/' + hostname
jadmanski0afbb632008-06-06 21:10:57 +0000468
showard71b94312009-08-20 23:40:02 +0000469 return {'hostname': hostname, 'machine_group': group, 'owner': owner}
470
471
472 def insert_machine(self, job, commit = None):
473 machine_info = self.machine_info_dict(job)
showardeab66ce2009-12-23 00:03:56 +0000474 self.insert('tko_machines', machine_info, commit=commit)
jadmanski0afbb632008-06-06 21:10:57 +0000475 return self.get_last_autonumber_value()
476
477
showard71b94312009-08-20 23:40:02 +0000478 def update_machine_information(self, job, commit = None):
479 machine_info = self.machine_info_dict(job)
showardeab66ce2009-12-23 00:03:56 +0000480 self.update('tko_machines', machine_info,
showard71b94312009-08-20 23:40:02 +0000481 where={'hostname': machine_info['hostname']},
482 commit=commit)
483
484
jadmanski0afbb632008-06-06 21:10:57 +0000485 def lookup_machine(self, hostname):
486 where = { 'hostname' : hostname }
showardeab66ce2009-12-23 00:03:56 +0000487 rows = self.select('machine_idx', 'tko_machines', where)
jadmanski0afbb632008-06-06 21:10:57 +0000488 if rows:
489 return rows[0][0]
490 else:
491 return None
492
493
494 def lookup_kernel(self, kernel):
showardeab66ce2009-12-23 00:03:56 +0000495 rows = self.select('kernel_idx', 'tko_kernels',
jadmanski0afbb632008-06-06 21:10:57 +0000496 {'kernel_hash':kernel.kernel_hash})
497 if rows:
498 return rows[0][0]
499 else:
500 return None
501
502
503 def insert_kernel(self, kernel, commit = None):
504 kver = self.lookup_kernel(kernel)
505 if kver:
506 return kver
507
508 # If this kernel has any significant patches, append their hash
509 # as diferentiator.
510 printable = kernel.base
511 patch_count = 0
512 for patch in kernel.patches:
513 match = re.match(r'.*(-mm[0-9]+|-git[0-9]+)\.(bz2|gz)$',
514 patch.reference)
515 if not match:
516 patch_count += 1
517
showardeab66ce2009-12-23 00:03:56 +0000518 self.insert('tko_kernels',
jadmanski0afbb632008-06-06 21:10:57 +0000519 {'base':kernel.base,
520 'kernel_hash':kernel.kernel_hash,
521 'printable':printable},
522 commit=commit)
523 kver = self.get_last_autonumber_value()
524
525 if patch_count > 0:
526 printable += ' p%d' % (kver)
showardeab66ce2009-12-23 00:03:56 +0000527 self.update('tko_kernels',
jadmanski0afbb632008-06-06 21:10:57 +0000528 {'printable':printable},
529 {'kernel_idx':kver})
530
531 for patch in kernel.patches:
532 self.insert_patch(kver, patch, commit=commit)
533 return kver
534
535
536 def insert_patch(self, kver, patch, commit = None):
537 print patch.reference
538 name = os.path.basename(patch.reference)[:80]
showardeab66ce2009-12-23 00:03:56 +0000539 self.insert('tko_patches',
jadmanski0afbb632008-06-06 21:10:57 +0000540 {'kernel_idx': kver,
541 'name':name,
542 'url':patch.reference,
543 'hash':patch.hash},
544 commit=commit)
545
546
jadmanski74eebf32008-07-15 20:04:42 +0000547 def find_test(self, job_idx, testname, subdir):
548 where = {'job_idx': job_idx , 'test': testname, 'subdir': subdir}
showardeab66ce2009-12-23 00:03:56 +0000549 rows = self.select('test_idx', 'tko_tests', where)
jadmanski0afbb632008-06-06 21:10:57 +0000550 if rows:
551 return rows[0][0]
552 else:
553 return None
554
555
556 def find_tests(self, job_idx):
557 where = { 'job_idx':job_idx }
showardeab66ce2009-12-23 00:03:56 +0000558 rows = self.select('test_idx', 'tko_tests', where)
jadmanski0afbb632008-06-06 21:10:57 +0000559 if rows:
560 return [row[0] for row in rows]
561 else:
562 return []
563
564
565 def find_job(self, tag):
showardeab66ce2009-12-23 00:03:56 +0000566 rows = self.select('job_idx', 'tko_jobs', {'tag': tag})
jadmanski0afbb632008-06-06 21:10:57 +0000567 if rows:
568 return rows[0][0]
569 else:
570 return None
mblighaf25f062007-12-03 17:48:35 +0000571
572
mbligh96cf0512008-04-17 15:25:38 +0000573def _get_db_type():
jadmanski0afbb632008-06-06 21:10:57 +0000574 """Get the database type name to use from the global config."""
Jakob Jueliche2bf3962014-10-02 11:33:17 -0700575 get_value = global_config.global_config.get_config_value_with_fallback
576 return "db_" + get_value("AUTOTEST_WEB", "global_db_type", "db_type",
577 default="mysql")
mblighaf25f062007-12-03 17:48:35 +0000578
mbligh96cf0512008-04-17 15:25:38 +0000579
580def _get_error_class(class_name):
jadmanski0afbb632008-06-06 21:10:57 +0000581 """Retrieves the appropriate error class by name from the database
582 module."""
583 db_module = __import__("autotest_lib.tko." + _get_db_type(),
584 globals(), locals(), ["driver"])
585 return getattr(db_module.driver, class_name)
mbligh96cf0512008-04-17 15:25:38 +0000586
587
588def db(*args, **dargs):
jadmanski0afbb632008-06-06 21:10:57 +0000589 """Creates an instance of the database class with the arguments
590 provided in args and dargs, using the database type specified by
591 the global configuration (defaulting to mysql)."""
592 db_type = _get_db_type()
593 db_module = __import__("autotest_lib.tko." + db_type, globals(),
594 locals(), [db_type])
595 db = getattr(db_module, db_type)(*args, **dargs)
596 return db