summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Thursfield <sam.thursfield@codethink.co.uk>2015-06-15 17:25:05 +0100
committerSam Thursfield <sam.thursfield@codethink.co.uk>2015-06-15 17:25:05 +0100
commit8f622bd6b285a840e56e375eb11e7fa8e67caffb (patch)
tree0c56f27bd56ab5328a4b930d247cb44e6e3565a2
parent17b6ea7d5ef8bd86872d9895196b5b79ca9bd079 (diff)
downloadmorph-cache-server-8f622bd6b285a840e56e375eb11e7fa8e67caffb.tar.gz
Track source_repo and source_ref for a given artifact
This is done in a hacky way because right now YBD artifact metadata is pretty lacking. The "proper" approach is to require all of the info that went into the cache key, then recalculate the cache key on the server and check that it matches against the hash in the cache name. But first we need to fix YBD to actually store all that info in the artifact.
-rwxr-xr-xmorph-cache-server10
-rw-r--r--morphcacheserver/artifact_database.py70
-rw-r--r--morphcacheserver/frontend.py16
3 files changed, 77 insertions, 19 deletions
diff --git a/morph-cache-server b/morph-cache-server
index 4cbc20d..5fe6b0f 100755
--- a/morph-cache-server
+++ b/morph-cache-server
@@ -388,6 +388,8 @@ class MorphCacheServer(cliapp.Application):
- builder_name: URL identifying the build worker
- build_datetime: time artifact build was started
- hash_sha1: SHA1 of built artifact
+ - source_repo: (optional): repo this is built from
+ - source_ref: (optional): ref this is built from
'''
cache_name = self._unescape_parameter(request.query.cache_name)
@@ -396,7 +398,13 @@ class MorphCacheServer(cliapp.Application):
request.query.build_datetime)
hash_sha1 = self._unescape_parameter(request.query.hash_sha1)
- db.record_build(cache_name, builder_name, build_datetime, hash_sha1)
+ source_repo = self._unescape_parameter(
+ request.query.get('source_repo'))
+ source_ref = self._unescape_parameter(
+ request.query.get('source_ref'))
+
+ db.record_build(cache_name, builder_name, build_datetime,
+ hash_sha1, source_repo, source_ref)
@app.get('/builds')
def get_builds():
diff --git a/morphcacheserver/artifact_database.py b/morphcacheserver/artifact_database.py
index b9550a1..21d28ef 100644
--- a/morphcacheserver/artifact_database.py
+++ b/morphcacheserver/artifact_database.py
@@ -64,7 +64,24 @@ class ArtifactDatabase(object):
to_apply.apply()
self.db.commit()
- def intern_artifact_file(self, cache_name):
+ def query(self, sql, args=[]):
+ '''Run a SELECT query.'''
+
+ cursor = self.db.cursor()
+ logging.debug('Running: %s with args %s', sql, args)
+ cursor.execute(sql, args)
+ return cursor
+
+ def update(self, sql, args=[]):
+ '''Run an INSERT or UPDATE query.'''
+
+ cursor = self.db.cursor()
+ log.debug('Running %s with args %s', sql, args)
+ cursor.execute(sql, args)
+ self.db.commit()
+ return cursor.lastrowid
+
+ def intern_artifact_file(self, cache_name, source_repo, source_ref):
'''Record that a Baserock artifact file is now in the cache directory.
The 'cache_name' variable is the SHA256 hash of the 'cache key', plus
@@ -87,23 +104,33 @@ class ArtifactDatabase(object):
'''
cursor = self.db.cursor()
- find_artifact_sql = 'SELECT internal_id FROM artifact_files WHERE ' \
- 'cache_name=?'
+ find_artifact_sql = '''
+ SELECT internal_id, source_repo, source_ref
+ FROM artifact_files
+ WHERE cache_name=?
+ '''
row = cursor.execute(find_artifact_sql, [cache_name]).fetchone()
+
if row is None:
- log.debug('Recording new artifact file %s', cache_name)
- cursor.execute(
- 'INSERT INTO artifact_files(cache_name) VALUES(?)',
- [cache_name])
- self.db.commit()
- internal_id = cursor.lastrowid
+ internal_id = self.update(
+ 'INSERT INTO artifact_files(cache_name, source_repo, '
+ ' source_ref) VALUES(?,?,?)',
+ [cache_name, source_repo, source_ref])
else:
- # If the artifact file was already known, no problem.
internal_id = row[0]
+ if row[1] is None and row[2] is None:
+ # Set repo and ref if not set. Currently we take it on trust
+ # that these are correct. Actually, we should take the entire
+ # contents of the cache key, and verify that it matches with
+ # the hash in the cache_name parameter.
+ self.update(
+ 'UPDATE artifact_files SET source_repo=?, source_ref=? '
+ 'WHERE cache_name=?',
+ [source_repo, source_ref, cache_name])
return internal_id
def record_build(self, cache_name, builder_name, build_datetime,
- hash_sha1):
+ hash_sha1, source_repo, source_ref):
'''Record a build of a Baserock artifact.
The artifact file is identified by the 'cache name', which is a hash of
@@ -116,7 +143,7 @@ class ArtifactDatabase(object):
deterministic.
'''
- self.intern_artifact_file(cache_name)
+ self.intern_artifact_file(cache_name, source_repo, source_ref)
cursor = self.db.cursor()
log.debug('Recording new build of %s, %s, %s', cache_name,
@@ -178,12 +205,9 @@ class ArtifactDatabase(object):
# first, they are the most important. Sort order should be configurable,
# really.
sql = n_builds_per_artifact_sql + ' ORDER BY n_different_builds DESC'
-
sql += ' LIMIT %i OFFSET %i' % (page_size, start)
- cursor = self.db.cursor()
- logging.debug('Running: %s', sql)
- cursor.execute(sql)
+ cursor = self.query(sql)
result = []
for row in cursor:
@@ -193,3 +217,17 @@ class ArtifactDatabase(object):
'n_different_builds': row[2],
})
return result
+
+ def view_artifact_info(self, cache_name):
+ sql = '''
+ SELECT source_repo, source_ref FROM artifact_files WHERE cache_name=?
+ '''
+ cursor = self.query(sql, [cache_name])
+
+ row = cursor.fetchone()
+ if row is None:
+ raise KeyError('No artifact with name %s' % cache_name)
+ else:
+ source_repo = row[0]
+ source_ref = row[1]
+ return source_repo, source_ref
diff --git a/morphcacheserver/frontend.py b/morphcacheserver/frontend.py
index 6eb0917..b463c33 100644
--- a/morphcacheserver/frontend.py
+++ b/morphcacheserver/frontend.py
@@ -31,7 +31,7 @@ def make_table(data, heading_ids, heading_titles, row_class_cb=None):
%for row in rows:
<tr class="{{ row_class_cb(row) }}" >
%for col in heading_ids:
- <td>{{row[col]}}</td>
+ <td>{{!row[col]}}</td>
%end
</tr>
%end
@@ -66,9 +66,14 @@ def web_frontend(db):
artifacts = db.view_artifact_statistics(
start=(page-1)*page_size, page_size=page_size)
+
+ for item in artifacts:
+ item['cache_name_with_url'] = '<a href="/artifacts/%s">%s</a>' % (
+ item['cache_name'], item['cache_name'])
+
content += make_table(
artifacts,
- ['cache_name', 'n_builds', 'n_different_builds'],
+ ['cache_name_with_url', 'n_builds', 'n_different_builds'],
['Artifact', 'Total builds', 'Mismatching builds'],
row_class_cb=row_style_class_cb)
@@ -87,6 +92,13 @@ def web_frontend(db):
return template('morphcacheserver/templates/base', base=content)
+ @app.get('/artifacts/<cache_name>')
+ def artifact_info(cache_name):
+ source_repo, source_ref = db.view_artifact_info(cache_name)
+ return template('morphcacheserver/templates/artifact_info',
+ cache_name=cache_name, source_repo=source_repo,
+ source_ref=source_ref)
+
@app.get('/')
def frontpage():
'''A nice frontpage.'''