blob: 23364901a2aecbf2cf6de62d52b11049ac587c8a [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
Richard Barnette2468fbd2014-11-07 01:12:46 +000084 # TODO(beeps): Move this to django settings once we have routers.
85 # On test instances mysql connects through a different port. No point
86 # piping this through our entire infrastructure when it is only really
87 # used for testing; Ideally we would specify this through django
88 # settings and default it to the empty string so django will figure out
89 # the default based on the database backend (eg: mysql, 3306), but until
90 # we have database routers in place any django settings will apply to
91 # both tko and afe.
92 # The intended use of this port is to allow a testing shard vm to
93 # update the master vm's database with test results. Specifying
94 # and empty string will fallback to not even specifying the port
95 # to the backend in tko/db.py. Unfortunately this means retries
96 # won't work on the test cluster till we've migrated to routers.
97 self.port = global_config.global_config.get_config_value(
98 "AUTOTEST_WEB", "global_db_port", type=str, default='')
99
mbligh65acae52008-04-24 20:21:55 +0000100
jadmanski0afbb632008-06-06 21:10:57 +0000101 def _init_db(self):
102 # make sure we clean up any existing connection
103 if self.con:
104 self.con.close()
105 self.con = None
mbligh65acae52008-04-24 20:21:55 +0000106
jadmanski0afbb632008-06-06 21:10:57 +0000107 # create the db connection and cursor
108 self.con = self.connect(self.host, self.database,
Richard Barnette2468fbd2014-11-07 01:12:46 +0000109 self.user, self.password, self.port)
jadmanski0afbb632008-06-06 21:10:57 +0000110 self.cur = self.con.cursor()
mbligh96cf0512008-04-17 15:25:38 +0000111
112
jadmanski0afbb632008-06-06 21:10:57 +0000113 def _random_delay(self):
114 delay = random.randint(self.min_delay, self.max_delay)
115 time.sleep(delay)
mbligh65acae52008-04-24 20:21:55 +0000116
117
jadmanski0afbb632008-06-06 21:10:57 +0000118 def run_with_retry(self, function, *args, **dargs):
119 """Call function(*args, **dargs) until either it passes
120 without an operational error, or a timeout is reached.
121 This will re-connect to the database, so it is NOT safe
122 to use this inside of a database transaction.
jadmanskie7a69092008-05-29 21:03:13 +0000123
jadmanski0afbb632008-06-06 21:10:57 +0000124 It can be safely used with transactions, but the
125 transaction start & end must be completely contained
126 within the call to 'function'."""
127 OperationalError = _get_error_class("OperationalError")
mbligh65acae52008-04-24 20:21:55 +0000128
jadmanski0afbb632008-06-06 21:10:57 +0000129 success = False
130 start_time = time.time()
131 while not success:
132 try:
133 result = function(*args, **dargs)
134 except OperationalError, e:
135 self._log_operational_error(e)
136 stop_time = time.time()
137 elapsed_time = stop_time - start_time
138 if elapsed_time > self.query_timeout:
139 raise
140 else:
141 try:
142 self._random_delay()
143 self._init_db()
144 except OperationalError, e:
145 self._log_operational_error(e)
146 else:
147 success = True
148 return result
mbligh96cf0512008-04-17 15:25:38 +0000149
150
jadmanski0afbb632008-06-06 21:10:57 +0000151 def _log_operational_error(self, e):
mbligh097407d2009-02-17 15:49:37 +0000152 msg = ("%s: An operational error occured during a database "
jadmanski5d4c27e2009-03-02 16:45:42 +0000153 "operation: %s" % (time.strftime("%X %x"), str(e)))
jadmanski0afbb632008-06-06 21:10:57 +0000154 print >> sys.stderr, msg
155 sys.stderr.flush() # we want these msgs to show up immediately
jadmanski60d4fa62008-05-06 22:49:41 +0000156
157
jadmanski0afbb632008-06-06 21:10:57 +0000158 def dprint(self, value):
159 if self.debug:
160 sys.stdout.write('SQL: ' + str(value) + '\n')
mbligh8e1ab172007-09-13 17:29:56 +0000161
mblighd5c33db2006-10-08 21:34:16 +0000162
jadmanski0afbb632008-06-06 21:10:57 +0000163 def commit(self):
164 self.con.commit()
mbligh432bad42007-10-09 19:56:07 +0000165
166
Simran Basie129a962012-08-31 13:03:53 -0700167 def rollback(self):
168 self.con.rollback()
169
170
jadmanski0afbb632008-06-06 21:10:57 +0000171 def get_last_autonumber_value(self):
172 self.cur.execute('SELECT LAST_INSERT_ID()', [])
173 return self.cur.fetchall()[0][0]
mblighe12b8612008-02-12 20:58:14 +0000174
175
showardc1a98d12010-01-15 00:22:22 +0000176 def _quote(self, field):
177 return '`%s`' % field
178
179
180 def _where_clause(self, where):
181 if not where:
182 return '', []
183
184 if isinstance(where, dict):
185 # key/value pairs (which should be equal, or None for null)
186 keys, values = [], []
187 for field, value in where.iteritems():
188 quoted_field = self._quote(field)
189 if value is None:
190 keys.append(quoted_field + ' is null')
191 else:
192 keys.append(quoted_field + '=%s')
193 values.append(value)
194 where_clause = ' and '.join(keys)
195 elif isinstance(where, basestring):
196 # the exact string
197 where_clause = where
198 values = []
199 elif isinstance(where, tuple):
200 # preformatted where clause + values
201 where_clause, values = where
202 assert where_clause
203 else:
204 raise ValueError('Invalid "where" value: %r' % where)
205
206 return ' WHERE ' + where_clause, values
207
208
209
210 def select(self, fields, table, where, distinct=False, group_by=None,
211 max_rows=None):
jadmanski0afbb632008-06-06 21:10:57 +0000212 """\
213 This selects all the fields requested from a
214 specific table with a particular where clause.
215 The where clause can either be a dictionary of
216 field=value pairs, a string, or a tuple of (string,
217 a list of values). The last option is what you
218 should use when accepting user input as it'll
219 protect you against sql injection attacks (if
220 all user data is placed in the array rather than
221 the raw SQL).
mbligh12eebfa2008-01-03 02:01:53 +0000222
jadmanski0afbb632008-06-06 21:10:57 +0000223 For example:
224 where = ("a = %s AND b = %s", ['val', 'val'])
225 is better than
226 where = "a = 'val' AND b = 'val'"
227 """
228 cmd = ['select']
229 if distinct:
230 cmd.append('distinct')
231 cmd += [fields, 'from', table]
mbligh608c3252007-08-31 13:53:00 +0000232
showardc1a98d12010-01-15 00:22:22 +0000233 where_clause, values = self._where_clause(where)
234 cmd.append(where_clause)
mbligh96cf0512008-04-17 15:25:38 +0000235
jadmanski0afbb632008-06-06 21:10:57 +0000236 if group_by:
237 cmd.append(' GROUP BY ' + group_by)
mbligh83f63a02007-12-12 19:13:04 +0000238
jadmanski0afbb632008-06-06 21:10:57 +0000239 self.dprint('%s %s' % (' '.join(cmd), values))
mbligh96cf0512008-04-17 15:25:38 +0000240
jadmanski0afbb632008-06-06 21:10:57 +0000241 # create a re-runable function for executing the query
242 def exec_sql():
243 sql = ' '.join(cmd)
244 numRec = self.cur.execute(sql, values)
mblighd876f452008-12-03 15:09:17 +0000245 if max_rows is not None and numRec > max_rows:
jadmanski0afbb632008-06-06 21:10:57 +0000246 msg = 'Exceeded allowed number of records'
247 raise MySQLTooManyRows(msg)
248 return self.cur.fetchall()
mbligh96cf0512008-04-17 15:25:38 +0000249
jadmanski0afbb632008-06-06 21:10:57 +0000250 # run the query, re-trying after operational errors
251 if self.autocommit:
252 return self.run_with_retry(exec_sql)
253 else:
254 return exec_sql()
mblighd5c33db2006-10-08 21:34:16 +0000255
mbligh056d0d32006-10-08 22:31:10 +0000256
jadmanski0afbb632008-06-06 21:10:57 +0000257 def select_sql(self, fields, table, sql, values):
258 """\
259 select fields from table "sql"
260 """
261 cmd = 'select %s from %s %s' % (fields, table, sql)
262 self.dprint(cmd)
mbligh414c69e2007-10-05 15:13:06 +0000263
jadmanski0afbb632008-06-06 21:10:57 +0000264 # create a -re-runable function for executing the query
265 def exec_sql():
266 self.cur.execute(cmd, values)
267 return self.cur.fetchall()
mbligh96b9a5a2007-11-24 19:32:20 +0000268
jadmanski0afbb632008-06-06 21:10:57 +0000269 # run the query, re-trying after operational errors
270 if self.autocommit:
271 return self.run_with_retry(exec_sql)
272 else:
273 return exec_sql()
mbligh96b9a5a2007-11-24 19:32:20 +0000274
mbligh608c3252007-08-31 13:53:00 +0000275
jadmanski0afbb632008-06-06 21:10:57 +0000276 def _exec_sql_with_commit(self, sql, values, commit):
277 if self.autocommit:
278 # re-run the query until it succeeds
279 def exec_sql():
280 self.cur.execute(sql, values)
281 self.con.commit()
282 self.run_with_retry(exec_sql)
283 else:
284 # take one shot at running the query
285 self.cur.execute(sql, values)
286 if commit:
287 self.con.commit()
mbligh96b9a5a2007-11-24 19:32:20 +0000288
mbligh2bd48872007-09-20 18:32:25 +0000289
jadmanskib591fba2008-09-10 16:19:22 +0000290 def insert(self, table, data, commit=None):
jadmanski0afbb632008-06-06 21:10:57 +0000291 """\
292 'insert into table (keys) values (%s ... %s)', values
mbligh96cf0512008-04-17 15:25:38 +0000293
jadmanski0afbb632008-06-06 21:10:57 +0000294 data:
295 dictionary of fields and data
296 """
297 fields = data.keys()
298 refs = ['%s' for field in fields]
299 values = [data[field] for field in fields]
showardc1a98d12010-01-15 00:22:22 +0000300 cmd = ('insert into %s (%s) values (%s)' %
301 (table, ','.join(self._quote(field) for field in fields),
302 ','.join(refs)))
jadmanski0afbb632008-06-06 21:10:57 +0000303 self.dprint('%s %s' % (cmd, values))
mblighe9cf9d42007-08-31 08:56:00 +0000304
jadmanski0afbb632008-06-06 21:10:57 +0000305 self._exec_sql_with_commit(cmd, values, commit)
mblighe9cf9d42007-08-31 08:56:00 +0000306
mbligh048e1c92007-10-07 00:10:33 +0000307
jadmanski0afbb632008-06-06 21:10:57 +0000308 def delete(self, table, where, commit = None):
309 cmd = ['delete from', table]
mblighd876f452008-12-03 15:09:17 +0000310 if commit is None:
jadmanski0afbb632008-06-06 21:10:57 +0000311 commit = self.autocommit
showardc1a98d12010-01-15 00:22:22 +0000312 where_clause, values = self._where_clause(where)
313 cmd.append(where_clause)
jadmanski0afbb632008-06-06 21:10:57 +0000314 sql = ' '.join(cmd)
315 self.dprint('%s %s' % (sql, values))
mbligh048e1c92007-10-07 00:10:33 +0000316
jadmanski0afbb632008-06-06 21:10:57 +0000317 self._exec_sql_with_commit(sql, values, commit)
mbligh048e1c92007-10-07 00:10:33 +0000318
mbligh7a41a862007-11-30 17:44:24 +0000319
jadmanski0afbb632008-06-06 21:10:57 +0000320 def update(self, table, data, where, commit = None):
321 """\
322 'update table set data values (%s ... %s) where ...'
mbligh2aaeb672007-10-01 14:54:18 +0000323
jadmanski0afbb632008-06-06 21:10:57 +0000324 data:
325 dictionary of fields and data
326 """
mblighd876f452008-12-03 15:09:17 +0000327 if commit is None:
jadmanski0afbb632008-06-06 21:10:57 +0000328 commit = self.autocommit
329 cmd = 'update %s ' % table
330 fields = data.keys()
showardc1a98d12010-01-15 00:22:22 +0000331 data_refs = [self._quote(field) + '=%s' for field in fields]
jadmanski0afbb632008-06-06 21:10:57 +0000332 data_values = [data[field] for field in fields]
jadmanski74eebf32008-07-15 20:04:42 +0000333 cmd += ' set ' + ', '.join(data_refs)
mbligh2aaeb672007-10-01 14:54:18 +0000334
showardc1a98d12010-01-15 00:22:22 +0000335 where_clause, where_values = self._where_clause(where)
336 cmd += where_clause
mbligh2aaeb672007-10-01 14:54:18 +0000337
jadmanski0afbb632008-06-06 21:10:57 +0000338 values = data_values + where_values
jadmanski74eebf32008-07-15 20:04:42 +0000339 self.dprint('%s %s' % (cmd, values))
mbligh2aaeb672007-10-01 14:54:18 +0000340
jadmanski0afbb632008-06-06 21:10:57 +0000341 self._exec_sql_with_commit(cmd, values, commit)
mblighe9cf9d42007-08-31 08:56:00 +0000342
343
jadmanski0afbb632008-06-06 21:10:57 +0000344 def delete_job(self, tag, commit = None):
345 job_idx = self.find_job(tag)
346 for test_idx in self.find_tests(job_idx):
347 where = {'test_idx' : test_idx}
showardeab66ce2009-12-23 00:03:56 +0000348 self.delete('tko_iteration_result', where)
Dennis Jeffrey368c54b2013-07-24 11:19:03 -0700349 self.delete('tko_iteration_perf_value', where)
showardeab66ce2009-12-23 00:03:56 +0000350 self.delete('tko_iteration_attributes', where)
351 self.delete('tko_test_attributes', where)
352 self.delete('tko_test_labels_tests', {'test_id': test_idx})
jadmanski0afbb632008-06-06 21:10:57 +0000353 where = {'job_idx' : job_idx}
showardeab66ce2009-12-23 00:03:56 +0000354 self.delete('tko_tests', where)
355 self.delete('tko_jobs', where)
apw7a7316b2008-02-21 17:42:05 +0000356
apw7a7316b2008-02-21 17:42:05 +0000357
jadmanski0afbb632008-06-06 21:10:57 +0000358 def insert_job(self, tag, job, commit = None):
359 job.machine_idx = self.lookup_machine(job.machine)
360 if not job.machine_idx:
showard71b94312009-08-20 23:40:02 +0000361 job.machine_idx = self.insert_machine(job, commit=commit)
362 else:
363 self.update_machine_information(job, commit=commit)
364
jamesrena12b8a02010-06-16 23:28:23 +0000365 afe_job_id = utils.get_afe_job_id(tag)
showardc1c1caf2009-09-08 16:26:50 +0000366
showard0fec8a02009-12-04 01:19:54 +0000367 data = {'tag':tag,
368 'label': job.label,
369 'username': job.user,
370 'machine_idx': job.machine_idx,
371 'queued_time': job.queued_time,
372 'started_time': job.started_time,
373 'finished_time': job.finished_time,
374 'afe_job_id': afe_job_id}
375 is_update = hasattr(job, 'index')
376 if is_update:
showardeab66ce2009-12-23 00:03:56 +0000377 self.update('tko_jobs', data, {'job_idx': job.index}, commit=commit)
showard0fec8a02009-12-04 01:19:54 +0000378 else:
showardeab66ce2009-12-23 00:03:56 +0000379 self.insert('tko_jobs', data, commit=commit)
showard0fec8a02009-12-04 01:19:54 +0000380 job.index = self.get_last_autonumber_value()
showardc1a98d12010-01-15 00:22:22 +0000381 self.update_job_keyvals(job, commit=commit)
jadmanski0afbb632008-06-06 21:10:57 +0000382 for test in job.tests:
383 self.insert_test(job, test, commit=commit)
apw7a7316b2008-02-21 17:42:05 +0000384
mbligh237bed32007-09-05 13:05:57 +0000385
showardc1a98d12010-01-15 00:22:22 +0000386 def update_job_keyvals(self, job, commit=None):
387 for key, value in job.keyval_dict.iteritems():
388 where = {'job_id': job.index, 'key': key}
389 data = dict(where, value=value)
390 exists = self.select('id', 'tko_job_keyvals', where=where)
391
392 if exists:
393 self.update('tko_job_keyvals', data, where=where, commit=commit)
394 else:
395 self.insert('tko_job_keyvals', data, commit=commit)
396
397
jadmanski0afbb632008-06-06 21:10:57 +0000398 def insert_test(self, job, test, commit = None):
399 kver = self.insert_kernel(test.kernel, commit=commit)
400 data = {'job_idx':job.index, 'test':test.testname,
401 'subdir':test.subdir, 'kernel_idx':kver,
402 'status':self.status_idx[test.status],
403 'reason':test.reason, 'machine_idx':job.machine_idx,
404 'started_time': test.started_time,
405 'finished_time':test.finished_time}
jadmanski9b6babf2009-04-21 17:57:40 +0000406 is_update = hasattr(test, "test_idx")
407 if is_update:
jadmanski74eebf32008-07-15 20:04:42 +0000408 test_idx = test.test_idx
showardeab66ce2009-12-23 00:03:56 +0000409 self.update('tko_tests', data,
410 {'test_idx': test_idx}, commit=commit)
jadmanskib591fba2008-09-10 16:19:22 +0000411 where = {'test_idx': test_idx}
showardeab66ce2009-12-23 00:03:56 +0000412 self.delete('tko_iteration_result', where)
Dennis Jeffrey368c54b2013-07-24 11:19:03 -0700413 self.delete('tko_iteration_perf_value', where)
showardeab66ce2009-12-23 00:03:56 +0000414 self.delete('tko_iteration_attributes', where)
showard0fec8a02009-12-04 01:19:54 +0000415 where['user_created'] = 0
showardeab66ce2009-12-23 00:03:56 +0000416 self.delete('tko_test_attributes', where)
jadmanski74eebf32008-07-15 20:04:42 +0000417 else:
showardeab66ce2009-12-23 00:03:56 +0000418 self.insert('tko_tests', data, commit=commit)
jadmanski74eebf32008-07-15 20:04:42 +0000419 test_idx = test.test_idx = self.get_last_autonumber_value()
420 data = {'test_idx': test_idx}
mbligh237bed32007-09-05 13:05:57 +0000421
jadmanski0afbb632008-06-06 21:10:57 +0000422 for i in test.iterations:
423 data['iteration'] = i.index
424 for key, value in i.attr_keyval.iteritems():
425 data['attribute'] = key
426 data['value'] = value
showardeab66ce2009-12-23 00:03:56 +0000427 self.insert('tko_iteration_attributes', data,
jadmanski0afbb632008-06-06 21:10:57 +0000428 commit=commit)
429 for key, value in i.perf_keyval.iteritems():
430 data['attribute'] = key
431 data['value'] = value
showardeab66ce2009-12-23 00:03:56 +0000432 self.insert('tko_iteration_result', data,
mbligh432bad42007-10-09 19:56:07 +0000433 commit=commit)
mbligh056d0d32006-10-08 22:31:10 +0000434
Dennis Jeffrey368c54b2013-07-24 11:19:03 -0700435 data = {'test_idx': test_idx}
436 for i in test.perf_values:
437 data['iteration'] = i.index
438 for perf_dict in i.perf_measurements:
439 data['description'] = perf_dict['description']
440 data['value'] = perf_dict['value']
441 data['stddev'] = perf_dict['stddev']
442 data['units'] = perf_dict['units']
443 data['higher_is_better'] = perf_dict['higher_is_better']
Fang Deng7f24f0b2013-11-12 11:22:16 -0800444 data['graph'] = perf_dict['graph']
Dennis Jeffrey368c54b2013-07-24 11:19:03 -0700445 self.insert('tko_iteration_perf_value', data, commit=commit)
446
jadmanski0afbb632008-06-06 21:10:57 +0000447 for key, value in test.attributes.iteritems():
448 data = {'test_idx': test_idx, 'attribute': key,
449 'value': value}
showardeab66ce2009-12-23 00:03:56 +0000450 self.insert('tko_test_attributes', data, commit=commit)
mbligh2bd48872007-09-20 18:32:25 +0000451
jadmanski9b6babf2009-04-21 17:57:40 +0000452 if not is_update:
453 for label_index in test.labels:
454 data = {'test_id': test_idx, 'testlabel_id': label_index}
showardeab66ce2009-12-23 00:03:56 +0000455 self.insert('tko_test_labels_tests', data, commit=commit)
jadmanski9b6babf2009-04-21 17:57:40 +0000456
mbligh056d0d32006-10-08 22:31:10 +0000457
jadmanski0afbb632008-06-06 21:10:57 +0000458 def read_machine_map(self):
showard71b94312009-08-20 23:40:02 +0000459 if self.machine_group or not self.machine_map:
460 return
jadmanski0afbb632008-06-06 21:10:57 +0000461 for line in open(self.machine_map, 'r').readlines():
462 (machine, group) = line.split()
463 self.machine_group[machine] = group
mbligh96b9a5a2007-11-24 19:32:20 +0000464
465
showard71b94312009-08-20 23:40:02 +0000466 def machine_info_dict(self, job):
jadmanski0afbb632008-06-06 21:10:57 +0000467 hostname = job.machine
showard71b94312009-08-20 23:40:02 +0000468 group = job.machine_group
469 owner = job.machine_owner
jadmanski0afbb632008-06-06 21:10:57 +0000470
471 if not group:
showard71b94312009-08-20 23:40:02 +0000472 self.read_machine_map()
jadmanski0afbb632008-06-06 21:10:57 +0000473 group = self.machine_group.get(hostname, hostname)
showard71b94312009-08-20 23:40:02 +0000474 if group == hostname and owner:
475 group = owner + '/' + hostname
jadmanski0afbb632008-06-06 21:10:57 +0000476
showard71b94312009-08-20 23:40:02 +0000477 return {'hostname': hostname, 'machine_group': group, 'owner': owner}
478
479
480 def insert_machine(self, job, commit = None):
481 machine_info = self.machine_info_dict(job)
showardeab66ce2009-12-23 00:03:56 +0000482 self.insert('tko_machines', machine_info, commit=commit)
jadmanski0afbb632008-06-06 21:10:57 +0000483 return self.get_last_autonumber_value()
484
485
showard71b94312009-08-20 23:40:02 +0000486 def update_machine_information(self, job, commit = None):
487 machine_info = self.machine_info_dict(job)
showardeab66ce2009-12-23 00:03:56 +0000488 self.update('tko_machines', machine_info,
showard71b94312009-08-20 23:40:02 +0000489 where={'hostname': machine_info['hostname']},
490 commit=commit)
491
492
jadmanski0afbb632008-06-06 21:10:57 +0000493 def lookup_machine(self, hostname):
494 where = { 'hostname' : hostname }
showardeab66ce2009-12-23 00:03:56 +0000495 rows = self.select('machine_idx', 'tko_machines', where)
jadmanski0afbb632008-06-06 21:10:57 +0000496 if rows:
497 return rows[0][0]
498 else:
499 return None
500
501
502 def lookup_kernel(self, kernel):
showardeab66ce2009-12-23 00:03:56 +0000503 rows = self.select('kernel_idx', 'tko_kernels',
jadmanski0afbb632008-06-06 21:10:57 +0000504 {'kernel_hash':kernel.kernel_hash})
505 if rows:
506 return rows[0][0]
507 else:
508 return None
509
510
511 def insert_kernel(self, kernel, commit = None):
512 kver = self.lookup_kernel(kernel)
513 if kver:
514 return kver
515
516 # If this kernel has any significant patches, append their hash
517 # as diferentiator.
518 printable = kernel.base
519 patch_count = 0
520 for patch in kernel.patches:
521 match = re.match(r'.*(-mm[0-9]+|-git[0-9]+)\.(bz2|gz)$',
522 patch.reference)
523 if not match:
524 patch_count += 1
525
showardeab66ce2009-12-23 00:03:56 +0000526 self.insert('tko_kernels',
jadmanski0afbb632008-06-06 21:10:57 +0000527 {'base':kernel.base,
528 'kernel_hash':kernel.kernel_hash,
529 'printable':printable},
530 commit=commit)
531 kver = self.get_last_autonumber_value()
532
533 if patch_count > 0:
534 printable += ' p%d' % (kver)
showardeab66ce2009-12-23 00:03:56 +0000535 self.update('tko_kernels',
jadmanski0afbb632008-06-06 21:10:57 +0000536 {'printable':printable},
537 {'kernel_idx':kver})
538
539 for patch in kernel.patches:
540 self.insert_patch(kver, patch, commit=commit)
541 return kver
542
543
544 def insert_patch(self, kver, patch, commit = None):
545 print patch.reference
546 name = os.path.basename(patch.reference)[:80]
showardeab66ce2009-12-23 00:03:56 +0000547 self.insert('tko_patches',
jadmanski0afbb632008-06-06 21:10:57 +0000548 {'kernel_idx': kver,
549 'name':name,
550 'url':patch.reference,
551 'hash':patch.hash},
552 commit=commit)
553
554
jadmanski74eebf32008-07-15 20:04:42 +0000555 def find_test(self, job_idx, testname, subdir):
556 where = {'job_idx': job_idx , 'test': testname, 'subdir': subdir}
showardeab66ce2009-12-23 00:03:56 +0000557 rows = self.select('test_idx', 'tko_tests', where)
jadmanski0afbb632008-06-06 21:10:57 +0000558 if rows:
559 return rows[0][0]
560 else:
561 return None
562
563
564 def find_tests(self, job_idx):
565 where = { 'job_idx':job_idx }
showardeab66ce2009-12-23 00:03:56 +0000566 rows = self.select('test_idx', 'tko_tests', where)
jadmanski0afbb632008-06-06 21:10:57 +0000567 if rows:
568 return [row[0] for row in rows]
569 else:
570 return []
571
572
573 def find_job(self, tag):
showardeab66ce2009-12-23 00:03:56 +0000574 rows = self.select('job_idx', 'tko_jobs', {'tag': tag})
jadmanski0afbb632008-06-06 21:10:57 +0000575 if rows:
576 return rows[0][0]
577 else:
578 return None
mblighaf25f062007-12-03 17:48:35 +0000579
580
mbligh96cf0512008-04-17 15:25:38 +0000581def _get_db_type():
jadmanski0afbb632008-06-06 21:10:57 +0000582 """Get the database type name to use from the global config."""
Jakob Juelich934f0dc2014-10-14 18:21:13 -0700583 get_value = global_config.global_config.get_config_value_with_fallback
584 return "db_" + get_value("AUTOTEST_WEB", "global_db_type", "db_type",
585 default="mysql")
mblighaf25f062007-12-03 17:48:35 +0000586
mbligh96cf0512008-04-17 15:25:38 +0000587
588def _get_error_class(class_name):
jadmanski0afbb632008-06-06 21:10:57 +0000589 """Retrieves the appropriate error class by name from the database
590 module."""
591 db_module = __import__("autotest_lib.tko." + _get_db_type(),
592 globals(), locals(), ["driver"])
593 return getattr(db_module.driver, class_name)
mbligh96cf0512008-04-17 15:25:38 +0000594
595
596def db(*args, **dargs):
jadmanski0afbb632008-06-06 21:10:57 +0000597 """Creates an instance of the database class with the arguments
598 provided in args and dargs, using the database type specified by
599 the global configuration (defaulting to mysql)."""
600 db_type = _get_db_type()
601 db_module = __import__("autotest_lib.tko." + db_type, globals(),
602 locals(), [db_type])
603 db = getattr(db_module, db_type)(*args, **dargs)
604 return db