blob: 35efbc1ec748b67a5baf641e0efd4388a32cd975 [file] [log] [blame]
Jakob Juelich934f0dc2014-10-14 18:21:13 -07001# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
mbligh65acae52008-04-24 20:21:55 +00005import re, os, sys, types, time, random
mbligh96cf0512008-04-17 15:25:38 +00006
7import common
8from autotest_lib.client.common_lib import global_config
Jakob Juelich934f0dc2014-10-14 18:21:13 -07009from autotest_lib.frontend import database_settings_helper
jamesrena12b8a02010-06-16 23:28:23 +000010from autotest_lib.tko import utils
mbligh96cf0512008-04-17 15:25:38 +000011
mblighed4d6dd2008-02-27 16:49:43 +000012
mblighaea09602008-04-16 22:59:37 +000013class MySQLTooManyRows(Exception):
jadmanski0afbb632008-06-06 21:10:57 +000014 pass
mblighaea09602008-04-16 22:59:37 +000015
mblighd5c33db2006-10-08 21:34:16 +000016
mbligh7636b3a2008-06-11 15:44:01 +000017class db_sql(object):
jadmanski0afbb632008-06-06 21:10:57 +000018 def __init__(self, debug=False, autocommit=True, host=None,
19 database=None, user=None, password=None):
20 self.debug = debug
21 self.autocommit = autocommit
22 self._load_config(host, database, user, password)
mbligh96cf0512008-04-17 15:25:38 +000023
jadmanski0afbb632008-06-06 21:10:57 +000024 self.con = None
25 self._init_db()
mblighd5c33db2006-10-08 21:34:16 +000026
jadmanski0afbb632008-06-06 21:10:57 +000027 # if not present, insert statuses
28 self.status_idx = {}
29 self.status_word = {}
showardeab66ce2009-12-23 00:03:56 +000030 status_rows = self.select('status_idx, word', 'tko_status', None)
jadmanski0afbb632008-06-06 21:10:57 +000031 for s in status_rows:
32 self.status_idx[s[1]] = s[0]
33 self.status_word[s[0]] = s[1]
mbligh048e1c92007-10-07 00:10:33 +000034
jadmanski0afbb632008-06-06 21:10:57 +000035 machine_map = os.path.join(os.path.dirname(__file__),
36 'machines')
37 if os.path.exists(machine_map):
38 self.machine_map = machine_map
39 else:
40 self.machine_map = None
41 self.machine_group = {}
mbligh048e1c92007-10-07 00:10:33 +000042
mbligh8e1ab172007-09-13 17:29:56 +000043
jadmanski0afbb632008-06-06 21:10:57 +000044 def _load_config(self, host, database, user, password):
Jakob Juelich934f0dc2014-10-14 18:21:13 -070045 """Loads configuration settings required to connect to the database.
46
47 This will try to connect to use the settings prefixed with global_db_.
48 If they do not exist, they un-prefixed settings will be used.
49
50 If parameters are supplied, these will be taken instead of the values
51 in global_config.
52
53 @param host: If set, this host will be used, if not, the host will be
54 retrieved from global_config.
55 @param database: If set, this database will be used, if not, the
56 database will be retrieved from global_config.
57 @param user: If set, this user will be used, if not, the
58 user will be retrieved from global_config.
59 @param password: If set, this password will be used, if not, the
60 password will be retrieved from global_config.
61 """
62 database_settings = database_settings_helper.get_global_db_config()
mbligh65acae52008-04-24 20:21:55 +000063
jadmanski0afbb632008-06-06 21:10:57 +000064 # grab the host, database
Jakob Juelich934f0dc2014-10-14 18:21:13 -070065 self.host = host or database_settings['HOST']
66 self.database = database or database_settings['NAME']
mbligh65acae52008-04-24 20:21:55 +000067
jadmanski0afbb632008-06-06 21:10:57 +000068 # grab the user and password
Jakob Juelich934f0dc2014-10-14 18:21:13 -070069 self.user = user or database_settings['USER']
70 self.password = password or database_settings['PASSWORD']
mbligh65acae52008-04-24 20:21:55 +000071
Michael Spang7a273472014-10-08 12:08:13 -040072 # grab the timeout configuration
Jakob Juelich934f0dc2014-10-14 18:21:13 -070073 self.query_timeout =(
74 database_settings.get('OPTIONS', {}).get('timeout', 3600))
75
76 # Using fallback to non-global in order to work without configuration
77 # overhead on non-shard instances.
78 get_value = global_config.global_config.get_config_value_with_fallback
Jakob Juelich475b82b2014-09-30 11:17:07 -070079 self.min_delay = get_value("AUTOTEST_WEB", "global_db_min_retry_delay",
Jakob Juelich934f0dc2014-10-14 18:21:13 -070080 "min_retry_delay", type=int, default=20)
Jakob Juelich475b82b2014-09-30 11:17:07 -070081 self.max_delay = get_value("AUTOTEST_WEB", "global_db_max_retry_delay",
Jakob Juelich934f0dc2014-10-14 18:21:13 -070082 "max_retry_delay", type=int, default=60)
mbligh65acae52008-04-24 20:21:55 +000083
84
jadmanski0afbb632008-06-06 21:10:57 +000085 def _init_db(self):
86 # make sure we clean up any existing connection
87 if self.con:
88 self.con.close()
89 self.con = None
mbligh65acae52008-04-24 20:21:55 +000090
jadmanski0afbb632008-06-06 21:10:57 +000091 # create the db connection and cursor
92 self.con = self.connect(self.host, self.database,
93 self.user, self.password)
94 self.cur = self.con.cursor()
mbligh96cf0512008-04-17 15:25:38 +000095
96
jadmanski0afbb632008-06-06 21:10:57 +000097 def _random_delay(self):
98 delay = random.randint(self.min_delay, self.max_delay)
99 time.sleep(delay)
mbligh65acae52008-04-24 20:21:55 +0000100
101
jadmanski0afbb632008-06-06 21:10:57 +0000102 def run_with_retry(self, function, *args, **dargs):
103 """Call function(*args, **dargs) until either it passes
104 without an operational error, or a timeout is reached.
105 This will re-connect to the database, so it is NOT safe
106 to use this inside of a database transaction.
jadmanskie7a69092008-05-29 21:03:13 +0000107
jadmanski0afbb632008-06-06 21:10:57 +0000108 It can be safely used with transactions, but the
109 transaction start & end must be completely contained
110 within the call to 'function'."""
111 OperationalError = _get_error_class("OperationalError")
mbligh65acae52008-04-24 20:21:55 +0000112
jadmanski0afbb632008-06-06 21:10:57 +0000113 success = False
114 start_time = time.time()
115 while not success:
116 try:
117 result = function(*args, **dargs)
118 except OperationalError, e:
119 self._log_operational_error(e)
120 stop_time = time.time()
121 elapsed_time = stop_time - start_time
122 if elapsed_time > self.query_timeout:
123 raise
124 else:
125 try:
126 self._random_delay()
127 self._init_db()
128 except OperationalError, e:
129 self._log_operational_error(e)
130 else:
131 success = True
132 return result
mbligh96cf0512008-04-17 15:25:38 +0000133
134
jadmanski0afbb632008-06-06 21:10:57 +0000135 def _log_operational_error(self, e):
mbligh097407d2009-02-17 15:49:37 +0000136 msg = ("%s: An operational error occured during a database "
jadmanski5d4c27e2009-03-02 16:45:42 +0000137 "operation: %s" % (time.strftime("%X %x"), str(e)))
jadmanski0afbb632008-06-06 21:10:57 +0000138 print >> sys.stderr, msg
139 sys.stderr.flush() # we want these msgs to show up immediately
jadmanski60d4fa62008-05-06 22:49:41 +0000140
141
jadmanski0afbb632008-06-06 21:10:57 +0000142 def dprint(self, value):
143 if self.debug:
144 sys.stdout.write('SQL: ' + str(value) + '\n')
mbligh8e1ab172007-09-13 17:29:56 +0000145
mblighd5c33db2006-10-08 21:34:16 +0000146
jadmanski0afbb632008-06-06 21:10:57 +0000147 def commit(self):
148 self.con.commit()
mbligh432bad42007-10-09 19:56:07 +0000149
150
Simran Basie129a962012-08-31 13:03:53 -0700151 def rollback(self):
152 self.con.rollback()
153
154
jadmanski0afbb632008-06-06 21:10:57 +0000155 def get_last_autonumber_value(self):
156 self.cur.execute('SELECT LAST_INSERT_ID()', [])
157 return self.cur.fetchall()[0][0]
mblighe12b8612008-02-12 20:58:14 +0000158
159
showardc1a98d12010-01-15 00:22:22 +0000160 def _quote(self, field):
161 return '`%s`' % field
162
163
164 def _where_clause(self, where):
165 if not where:
166 return '', []
167
168 if isinstance(where, dict):
169 # key/value pairs (which should be equal, or None for null)
170 keys, values = [], []
171 for field, value in where.iteritems():
172 quoted_field = self._quote(field)
173 if value is None:
174 keys.append(quoted_field + ' is null')
175 else:
176 keys.append(quoted_field + '=%s')
177 values.append(value)
178 where_clause = ' and '.join(keys)
179 elif isinstance(where, basestring):
180 # the exact string
181 where_clause = where
182 values = []
183 elif isinstance(where, tuple):
184 # preformatted where clause + values
185 where_clause, values = where
186 assert where_clause
187 else:
188 raise ValueError('Invalid "where" value: %r' % where)
189
190 return ' WHERE ' + where_clause, values
191
192
193
194 def select(self, fields, table, where, distinct=False, group_by=None,
195 max_rows=None):
jadmanski0afbb632008-06-06 21:10:57 +0000196 """\
197 This selects all the fields requested from a
198 specific table with a particular where clause.
199 The where clause can either be a dictionary of
200 field=value pairs, a string, or a tuple of (string,
201 a list of values). The last option is what you
202 should use when accepting user input as it'll
203 protect you against sql injection attacks (if
204 all user data is placed in the array rather than
205 the raw SQL).
mbligh12eebfa2008-01-03 02:01:53 +0000206
jadmanski0afbb632008-06-06 21:10:57 +0000207 For example:
208 where = ("a = %s AND b = %s", ['val', 'val'])
209 is better than
210 where = "a = 'val' AND b = 'val'"
211 """
212 cmd = ['select']
213 if distinct:
214 cmd.append('distinct')
215 cmd += [fields, 'from', table]
mbligh608c3252007-08-31 13:53:00 +0000216
showardc1a98d12010-01-15 00:22:22 +0000217 where_clause, values = self._where_clause(where)
218 cmd.append(where_clause)
mbligh96cf0512008-04-17 15:25:38 +0000219
jadmanski0afbb632008-06-06 21:10:57 +0000220 if group_by:
221 cmd.append(' GROUP BY ' + group_by)
mbligh83f63a02007-12-12 19:13:04 +0000222
jadmanski0afbb632008-06-06 21:10:57 +0000223 self.dprint('%s %s' % (' '.join(cmd), values))
mbligh96cf0512008-04-17 15:25:38 +0000224
jadmanski0afbb632008-06-06 21:10:57 +0000225 # create a re-runable function for executing the query
226 def exec_sql():
227 sql = ' '.join(cmd)
228 numRec = self.cur.execute(sql, values)
mblighd876f452008-12-03 15:09:17 +0000229 if max_rows is not None and numRec > max_rows:
jadmanski0afbb632008-06-06 21:10:57 +0000230 msg = 'Exceeded allowed number of records'
231 raise MySQLTooManyRows(msg)
232 return self.cur.fetchall()
mbligh96cf0512008-04-17 15:25:38 +0000233
jadmanski0afbb632008-06-06 21:10:57 +0000234 # run the query, re-trying after operational errors
235 if self.autocommit:
236 return self.run_with_retry(exec_sql)
237 else:
238 return exec_sql()
mblighd5c33db2006-10-08 21:34:16 +0000239
mbligh056d0d32006-10-08 22:31:10 +0000240
jadmanski0afbb632008-06-06 21:10:57 +0000241 def select_sql(self, fields, table, sql, values):
242 """\
243 select fields from table "sql"
244 """
245 cmd = 'select %s from %s %s' % (fields, table, sql)
246 self.dprint(cmd)
mbligh414c69e2007-10-05 15:13:06 +0000247
jadmanski0afbb632008-06-06 21:10:57 +0000248 # create a -re-runable function for executing the query
249 def exec_sql():
250 self.cur.execute(cmd, values)
251 return self.cur.fetchall()
mbligh96b9a5a2007-11-24 19:32:20 +0000252
jadmanski0afbb632008-06-06 21:10:57 +0000253 # run the query, re-trying after operational errors
254 if self.autocommit:
255 return self.run_with_retry(exec_sql)
256 else:
257 return exec_sql()
mbligh96b9a5a2007-11-24 19:32:20 +0000258
mbligh608c3252007-08-31 13:53:00 +0000259
jadmanski0afbb632008-06-06 21:10:57 +0000260 def _exec_sql_with_commit(self, sql, values, commit):
261 if self.autocommit:
262 # re-run the query until it succeeds
263 def exec_sql():
264 self.cur.execute(sql, values)
265 self.con.commit()
266 self.run_with_retry(exec_sql)
267 else:
268 # take one shot at running the query
269 self.cur.execute(sql, values)
270 if commit:
271 self.con.commit()
mbligh96b9a5a2007-11-24 19:32:20 +0000272
mbligh2bd48872007-09-20 18:32:25 +0000273
jadmanskib591fba2008-09-10 16:19:22 +0000274 def insert(self, table, data, commit=None):
jadmanski0afbb632008-06-06 21:10:57 +0000275 """\
276 'insert into table (keys) values (%s ... %s)', values
mbligh96cf0512008-04-17 15:25:38 +0000277
jadmanski0afbb632008-06-06 21:10:57 +0000278 data:
279 dictionary of fields and data
280 """
281 fields = data.keys()
282 refs = ['%s' for field in fields]
283 values = [data[field] for field in fields]
showardc1a98d12010-01-15 00:22:22 +0000284 cmd = ('insert into %s (%s) values (%s)' %
285 (table, ','.join(self._quote(field) for field in fields),
286 ','.join(refs)))
jadmanski0afbb632008-06-06 21:10:57 +0000287 self.dprint('%s %s' % (cmd, values))
mblighe9cf9d42007-08-31 08:56:00 +0000288
jadmanski0afbb632008-06-06 21:10:57 +0000289 self._exec_sql_with_commit(cmd, values, commit)
mblighe9cf9d42007-08-31 08:56:00 +0000290
mbligh048e1c92007-10-07 00:10:33 +0000291
jadmanski0afbb632008-06-06 21:10:57 +0000292 def delete(self, table, where, commit = None):
293 cmd = ['delete from', table]
mblighd876f452008-12-03 15:09:17 +0000294 if commit is None:
jadmanski0afbb632008-06-06 21:10:57 +0000295 commit = self.autocommit
showardc1a98d12010-01-15 00:22:22 +0000296 where_clause, values = self._where_clause(where)
297 cmd.append(where_clause)
jadmanski0afbb632008-06-06 21:10:57 +0000298 sql = ' '.join(cmd)
299 self.dprint('%s %s' % (sql, values))
mbligh048e1c92007-10-07 00:10:33 +0000300
jadmanski0afbb632008-06-06 21:10:57 +0000301 self._exec_sql_with_commit(sql, values, commit)
mbligh048e1c92007-10-07 00:10:33 +0000302
mbligh7a41a862007-11-30 17:44:24 +0000303
jadmanski0afbb632008-06-06 21:10:57 +0000304 def update(self, table, data, where, commit = None):
305 """\
306 'update table set data values (%s ... %s) where ...'
mbligh2aaeb672007-10-01 14:54:18 +0000307
jadmanski0afbb632008-06-06 21:10:57 +0000308 data:
309 dictionary of fields and data
310 """
mblighd876f452008-12-03 15:09:17 +0000311 if commit is None:
jadmanski0afbb632008-06-06 21:10:57 +0000312 commit = self.autocommit
313 cmd = 'update %s ' % table
314 fields = data.keys()
showardc1a98d12010-01-15 00:22:22 +0000315 data_refs = [self._quote(field) + '=%s' for field in fields]
jadmanski0afbb632008-06-06 21:10:57 +0000316 data_values = [data[field] for field in fields]
jadmanski74eebf32008-07-15 20:04:42 +0000317 cmd += ' set ' + ', '.join(data_refs)
mbligh2aaeb672007-10-01 14:54:18 +0000318
showardc1a98d12010-01-15 00:22:22 +0000319 where_clause, where_values = self._where_clause(where)
320 cmd += where_clause
mbligh2aaeb672007-10-01 14:54:18 +0000321
jadmanski0afbb632008-06-06 21:10:57 +0000322 values = data_values + where_values
jadmanski74eebf32008-07-15 20:04:42 +0000323 self.dprint('%s %s' % (cmd, values))
mbligh2aaeb672007-10-01 14:54:18 +0000324
jadmanski0afbb632008-06-06 21:10:57 +0000325 self._exec_sql_with_commit(cmd, values, commit)
mblighe9cf9d42007-08-31 08:56:00 +0000326
327
jadmanski0afbb632008-06-06 21:10:57 +0000328 def delete_job(self, tag, commit = None):
329 job_idx = self.find_job(tag)
330 for test_idx in self.find_tests(job_idx):
331 where = {'test_idx' : test_idx}
showardeab66ce2009-12-23 00:03:56 +0000332 self.delete('tko_iteration_result', where)
Dennis Jeffrey368c54b2013-07-24 11:19:03 -0700333 self.delete('tko_iteration_perf_value', where)
showardeab66ce2009-12-23 00:03:56 +0000334 self.delete('tko_iteration_attributes', where)
335 self.delete('tko_test_attributes', where)
336 self.delete('tko_test_labels_tests', {'test_id': test_idx})
jadmanski0afbb632008-06-06 21:10:57 +0000337 where = {'job_idx' : job_idx}
showardeab66ce2009-12-23 00:03:56 +0000338 self.delete('tko_tests', where)
339 self.delete('tko_jobs', where)
apw7a7316b2008-02-21 17:42:05 +0000340
apw7a7316b2008-02-21 17:42:05 +0000341
jadmanski0afbb632008-06-06 21:10:57 +0000342 def insert_job(self, tag, job, commit = None):
343 job.machine_idx = self.lookup_machine(job.machine)
344 if not job.machine_idx:
showard71b94312009-08-20 23:40:02 +0000345 job.machine_idx = self.insert_machine(job, commit=commit)
346 else:
347 self.update_machine_information(job, commit=commit)
348
jamesrena12b8a02010-06-16 23:28:23 +0000349 afe_job_id = utils.get_afe_job_id(tag)
showardc1c1caf2009-09-08 16:26:50 +0000350
showard0fec8a02009-12-04 01:19:54 +0000351 data = {'tag':tag,
352 'label': job.label,
353 'username': job.user,
354 'machine_idx': job.machine_idx,
355 'queued_time': job.queued_time,
356 'started_time': job.started_time,
357 'finished_time': job.finished_time,
358 'afe_job_id': afe_job_id}
359 is_update = hasattr(job, 'index')
360 if is_update:
showardeab66ce2009-12-23 00:03:56 +0000361 self.update('tko_jobs', data, {'job_idx': job.index}, commit=commit)
showard0fec8a02009-12-04 01:19:54 +0000362 else:
showardeab66ce2009-12-23 00:03:56 +0000363 self.insert('tko_jobs', data, commit=commit)
showard0fec8a02009-12-04 01:19:54 +0000364 job.index = self.get_last_autonumber_value()
showardc1a98d12010-01-15 00:22:22 +0000365 self.update_job_keyvals(job, commit=commit)
jadmanski0afbb632008-06-06 21:10:57 +0000366 for test in job.tests:
367 self.insert_test(job, test, commit=commit)
apw7a7316b2008-02-21 17:42:05 +0000368
mbligh237bed32007-09-05 13:05:57 +0000369
showardc1a98d12010-01-15 00:22:22 +0000370 def update_job_keyvals(self, job, commit=None):
371 for key, value in job.keyval_dict.iteritems():
372 where = {'job_id': job.index, 'key': key}
373 data = dict(where, value=value)
374 exists = self.select('id', 'tko_job_keyvals', where=where)
375
376 if exists:
377 self.update('tko_job_keyvals', data, where=where, commit=commit)
378 else:
379 self.insert('tko_job_keyvals', data, commit=commit)
380
381
jadmanski0afbb632008-06-06 21:10:57 +0000382 def insert_test(self, job, test, commit = None):
383 kver = self.insert_kernel(test.kernel, commit=commit)
384 data = {'job_idx':job.index, 'test':test.testname,
385 'subdir':test.subdir, 'kernel_idx':kver,
386 'status':self.status_idx[test.status],
387 'reason':test.reason, 'machine_idx':job.machine_idx,
388 'started_time': test.started_time,
389 'finished_time':test.finished_time}
jadmanski9b6babf2009-04-21 17:57:40 +0000390 is_update = hasattr(test, "test_idx")
391 if is_update:
jadmanski74eebf32008-07-15 20:04:42 +0000392 test_idx = test.test_idx
showardeab66ce2009-12-23 00:03:56 +0000393 self.update('tko_tests', data,
394 {'test_idx': test_idx}, commit=commit)
jadmanskib591fba2008-09-10 16:19:22 +0000395 where = {'test_idx': test_idx}
showardeab66ce2009-12-23 00:03:56 +0000396 self.delete('tko_iteration_result', where)
Dennis Jeffrey368c54b2013-07-24 11:19:03 -0700397 self.delete('tko_iteration_perf_value', where)
showardeab66ce2009-12-23 00:03:56 +0000398 self.delete('tko_iteration_attributes', where)
showard0fec8a02009-12-04 01:19:54 +0000399 where['user_created'] = 0
showardeab66ce2009-12-23 00:03:56 +0000400 self.delete('tko_test_attributes', where)
jadmanski74eebf32008-07-15 20:04:42 +0000401 else:
showardeab66ce2009-12-23 00:03:56 +0000402 self.insert('tko_tests', data, commit=commit)
jadmanski74eebf32008-07-15 20:04:42 +0000403 test_idx = test.test_idx = self.get_last_autonumber_value()
404 data = {'test_idx': test_idx}
mbligh237bed32007-09-05 13:05:57 +0000405
jadmanski0afbb632008-06-06 21:10:57 +0000406 for i in test.iterations:
407 data['iteration'] = i.index
408 for key, value in i.attr_keyval.iteritems():
409 data['attribute'] = key
410 data['value'] = value
showardeab66ce2009-12-23 00:03:56 +0000411 self.insert('tko_iteration_attributes', data,
jadmanski0afbb632008-06-06 21:10:57 +0000412 commit=commit)
413 for key, value in i.perf_keyval.iteritems():
414 data['attribute'] = key
415 data['value'] = value
showardeab66ce2009-12-23 00:03:56 +0000416 self.insert('tko_iteration_result', data,
mbligh432bad42007-10-09 19:56:07 +0000417 commit=commit)
mbligh056d0d32006-10-08 22:31:10 +0000418
Dennis Jeffrey368c54b2013-07-24 11:19:03 -0700419 data = {'test_idx': test_idx}
420 for i in test.perf_values:
421 data['iteration'] = i.index
422 for perf_dict in i.perf_measurements:
423 data['description'] = perf_dict['description']
424 data['value'] = perf_dict['value']
425 data['stddev'] = perf_dict['stddev']
426 data['units'] = perf_dict['units']
427 data['higher_is_better'] = perf_dict['higher_is_better']
Fang Deng7f24f0b2013-11-12 11:22:16 -0800428 data['graph'] = perf_dict['graph']
Dennis Jeffrey368c54b2013-07-24 11:19:03 -0700429 self.insert('tko_iteration_perf_value', data, commit=commit)
430
jadmanski0afbb632008-06-06 21:10:57 +0000431 for key, value in test.attributes.iteritems():
432 data = {'test_idx': test_idx, 'attribute': key,
433 'value': value}
showardeab66ce2009-12-23 00:03:56 +0000434 self.insert('tko_test_attributes', data, commit=commit)
mbligh2bd48872007-09-20 18:32:25 +0000435
jadmanski9b6babf2009-04-21 17:57:40 +0000436 if not is_update:
437 for label_index in test.labels:
438 data = {'test_id': test_idx, 'testlabel_id': label_index}
showardeab66ce2009-12-23 00:03:56 +0000439 self.insert('tko_test_labels_tests', data, commit=commit)
jadmanski9b6babf2009-04-21 17:57:40 +0000440
mbligh056d0d32006-10-08 22:31:10 +0000441
jadmanski0afbb632008-06-06 21:10:57 +0000442 def read_machine_map(self):
showard71b94312009-08-20 23:40:02 +0000443 if self.machine_group or not self.machine_map:
444 return
jadmanski0afbb632008-06-06 21:10:57 +0000445 for line in open(self.machine_map, 'r').readlines():
446 (machine, group) = line.split()
447 self.machine_group[machine] = group
mbligh96b9a5a2007-11-24 19:32:20 +0000448
449
showard71b94312009-08-20 23:40:02 +0000450 def machine_info_dict(self, job):
jadmanski0afbb632008-06-06 21:10:57 +0000451 hostname = job.machine
showard71b94312009-08-20 23:40:02 +0000452 group = job.machine_group
453 owner = job.machine_owner
jadmanski0afbb632008-06-06 21:10:57 +0000454
455 if not group:
showard71b94312009-08-20 23:40:02 +0000456 self.read_machine_map()
jadmanski0afbb632008-06-06 21:10:57 +0000457 group = self.machine_group.get(hostname, hostname)
showard71b94312009-08-20 23:40:02 +0000458 if group == hostname and owner:
459 group = owner + '/' + hostname
jadmanski0afbb632008-06-06 21:10:57 +0000460
showard71b94312009-08-20 23:40:02 +0000461 return {'hostname': hostname, 'machine_group': group, 'owner': owner}
462
463
464 def insert_machine(self, job, commit = None):
465 machine_info = self.machine_info_dict(job)
showardeab66ce2009-12-23 00:03:56 +0000466 self.insert('tko_machines', machine_info, commit=commit)
jadmanski0afbb632008-06-06 21:10:57 +0000467 return self.get_last_autonumber_value()
468
469
showard71b94312009-08-20 23:40:02 +0000470 def update_machine_information(self, job, commit = None):
471 machine_info = self.machine_info_dict(job)
showardeab66ce2009-12-23 00:03:56 +0000472 self.update('tko_machines', machine_info,
showard71b94312009-08-20 23:40:02 +0000473 where={'hostname': machine_info['hostname']},
474 commit=commit)
475
476
jadmanski0afbb632008-06-06 21:10:57 +0000477 def lookup_machine(self, hostname):
478 where = { 'hostname' : hostname }
showardeab66ce2009-12-23 00:03:56 +0000479 rows = self.select('machine_idx', 'tko_machines', where)
jadmanski0afbb632008-06-06 21:10:57 +0000480 if rows:
481 return rows[0][0]
482 else:
483 return None
484
485
486 def lookup_kernel(self, kernel):
showardeab66ce2009-12-23 00:03:56 +0000487 rows = self.select('kernel_idx', 'tko_kernels',
jadmanski0afbb632008-06-06 21:10:57 +0000488 {'kernel_hash':kernel.kernel_hash})
489 if rows:
490 return rows[0][0]
491 else:
492 return None
493
494
495 def insert_kernel(self, kernel, commit = None):
496 kver = self.lookup_kernel(kernel)
497 if kver:
498 return kver
499
500 # If this kernel has any significant patches, append their hash
501 # as diferentiator.
502 printable = kernel.base
503 patch_count = 0
504 for patch in kernel.patches:
505 match = re.match(r'.*(-mm[0-9]+|-git[0-9]+)\.(bz2|gz)$',
506 patch.reference)
507 if not match:
508 patch_count += 1
509
showardeab66ce2009-12-23 00:03:56 +0000510 self.insert('tko_kernels',
jadmanski0afbb632008-06-06 21:10:57 +0000511 {'base':kernel.base,
512 'kernel_hash':kernel.kernel_hash,
513 'printable':printable},
514 commit=commit)
515 kver = self.get_last_autonumber_value()
516
517 if patch_count > 0:
518 printable += ' p%d' % (kver)
showardeab66ce2009-12-23 00:03:56 +0000519 self.update('tko_kernels',
jadmanski0afbb632008-06-06 21:10:57 +0000520 {'printable':printable},
521 {'kernel_idx':kver})
522
523 for patch in kernel.patches:
524 self.insert_patch(kver, patch, commit=commit)
525 return kver
526
527
528 def insert_patch(self, kver, patch, commit = None):
529 print patch.reference
530 name = os.path.basename(patch.reference)[:80]
showardeab66ce2009-12-23 00:03:56 +0000531 self.insert('tko_patches',
jadmanski0afbb632008-06-06 21:10:57 +0000532 {'kernel_idx': kver,
533 'name':name,
534 'url':patch.reference,
535 'hash':patch.hash},
536 commit=commit)
537
538
jadmanski74eebf32008-07-15 20:04:42 +0000539 def find_test(self, job_idx, testname, subdir):
540 where = {'job_idx': job_idx , 'test': testname, 'subdir': subdir}
showardeab66ce2009-12-23 00:03:56 +0000541 rows = self.select('test_idx', 'tko_tests', where)
jadmanski0afbb632008-06-06 21:10:57 +0000542 if rows:
543 return rows[0][0]
544 else:
545 return None
546
547
548 def find_tests(self, job_idx):
549 where = { 'job_idx':job_idx }
showardeab66ce2009-12-23 00:03:56 +0000550 rows = self.select('test_idx', 'tko_tests', where)
jadmanski0afbb632008-06-06 21:10:57 +0000551 if rows:
552 return [row[0] for row in rows]
553 else:
554 return []
555
556
557 def find_job(self, tag):
showardeab66ce2009-12-23 00:03:56 +0000558 rows = self.select('job_idx', 'tko_jobs', {'tag': tag})
jadmanski0afbb632008-06-06 21:10:57 +0000559 if rows:
560 return rows[0][0]
561 else:
562 return None
mblighaf25f062007-12-03 17:48:35 +0000563
564
mbligh96cf0512008-04-17 15:25:38 +0000565def _get_db_type():
jadmanski0afbb632008-06-06 21:10:57 +0000566 """Get the database type name to use from the global config."""
Jakob Juelich934f0dc2014-10-14 18:21:13 -0700567 get_value = global_config.global_config.get_config_value_with_fallback
568 return "db_" + get_value("AUTOTEST_WEB", "global_db_type", "db_type",
569 default="mysql")
mblighaf25f062007-12-03 17:48:35 +0000570
mbligh96cf0512008-04-17 15:25:38 +0000571
572def _get_error_class(class_name):
jadmanski0afbb632008-06-06 21:10:57 +0000573 """Retrieves the appropriate error class by name from the database
574 module."""
575 db_module = __import__("autotest_lib.tko." + _get_db_type(),
576 globals(), locals(), ["driver"])
577 return getattr(db_module.driver, class_name)
mbligh96cf0512008-04-17 15:25:38 +0000578
579
580def db(*args, **dargs):
jadmanski0afbb632008-06-06 21:10:57 +0000581 """Creates an instance of the database class with the arguments
582 provided in args and dargs, using the database type specified by
583 the global configuration (defaulting to mysql)."""
584 db_type = _get_db_type()
585 db_module = __import__("autotest_lib.tko." + db_type, globals(),
586 locals(), [db_type])
587 db = getattr(db_module, db_type)(*args, **dargs)
588 return db