summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <lars.wirzenius@codethink.co.uk>2014-03-25 16:05:04 +0000
committerLars Wirzenius <lars.wirzenius@codethink.co.uk>2014-03-25 16:05:04 +0000
commit1ec5c253fa3e2f2f52bf382326799c801cb8fe1d (patch)
treeb8890d8e3aa89582cc47e640fcac389219c686ca
parent380aa938e91356e137a03ca9f420333abe783ca7 (diff)
downloadlorry-controller-1ec5c253fa3e2f2f52bf382326799c801cb8fe1d.tar.gz
Set project.head and project.description from remote Trove
-rw-r--r--lorrycontroller/givemejob.py61
-rw-r--r--lorrycontroller/lstroves.py1
-rw-r--r--lorrycontroller/readconf.py2
-rw-r--r--lorrycontroller/statedb.py10
4 files changed, 69 insertions, 5 deletions
diff --git a/lorrycontroller/givemejob.py b/lorrycontroller/givemejob.py
index 46e8885..bfad6c5 100644
--- a/lorrycontroller/givemejob.py
+++ b/lorrycontroller/givemejob.py
@@ -23,6 +23,13 @@ import cliapp
import lorrycontroller
+class GitanoCommandFailure(Exception):
+
+ def __init__(self, trovehost, command):
+ Exception.__init__(
+ self, 'Failed to run "%s" on Gitano on %s' % (command, trovehost))
+
+
class GiveMeJob(lorrycontroller.LorryControllerRoute):
http_method = 'POST'
@@ -39,6 +46,8 @@ class GiveMeJob(lorrycontroller.LorryControllerRoute):
for lorry_info in lorry_infos:
if self.ready_to_run(lorry_info):
self.create_repository_in_local_trove(lorry_info)
+ if lorry_info['from_trovehost']:
+ self.copy_repository_metadata(lorry_info)
self.give_job_to_minion(statedb, lorry_info)
logging.info(
'Giving job %s to lorry %s to MINION %s:%s',
@@ -68,6 +77,58 @@ class GiveMeJob(lorrycontroller.LorryControllerRoute):
else:
logging.info('Created %s on local repo', lorry_info['path'])
+ def copy_repository_metadata(self, lorry_info):
+ '''Copy project.head and project.description to the local Trove.'''
+
+ try:
+ remote_config = self.get_gitano_config(
+ lorry_info['from_trovehost'], lorry_info['from_path'])
+ local_config = self.get_gitano_config('localhost', lorry_info['path'])
+
+ if remote_config['project.head'] != local_config['project.head']:
+ self.set_gitano_config(
+ 'localhost', lorry_info['path'],
+ 'project.head', remote_config['project.head'])
+
+ if not local_config['project.description']:
+ desc = '{host}: {desc}'.format(
+ host=lorry_info['from_trovehost'],
+ desc=remote_config['project.description'])
+ self.set_gitano_config(
+ 'localhost', lorry_info['path'],
+ 'project.description', desc)
+ except GitanoCommandFailure as e:
+ logging.error('ERROR: %s' % str(e))
+ bottle.abort(500)
+
+ def get_gitano_config(self, trovehost, repo_path):
+ exit, stdout, stderr = cliapp.runcmd(
+ ['ssh', 'git@%s' % trovehost,
+ 'config', cliapp.shell_quote(repo_path), 'show'])
+
+ if exit:
+ raise GitanoCommandFailure(trovehost, 'config show')
+
+ # "config REPO show" outputs a sequence of lines of the form "key: value".
+ # Extract those into a collections.defaultdict.
+
+ result = collections.defaultdict(str)
+ for line in stdout.splitlines():
+ m = re.match(r'^([^:])+:\s*(.*)$')
+ if m:
+ result[m.group(0)] = m.group(1).strip()
+
+ return result
+
+ def set_gitano_config(self, trovehost, repo_path, key, value):
+ exit, stdout, stderr = cliapp.runcmd(
+ ['ssh', 'git@%s' % trovehost,
+ 'config', cliapp.shell_quote(repo_path),
+ 'set', cliapp.shell_quote(key), cliapp.shell_quote(value)])
+
+ if exit:
+ raise GitanoCommandFailure(trovehost, 'config set')
+
def give_job_to_minion(self, statedb, lorry_info):
path = lorry_info['path']
minion_host = bottle.request.forms.host
diff --git a/lorrycontroller/lstroves.py b/lorrycontroller/lstroves.py
index d80785e..3c37554 100644
--- a/lorrycontroller/lstroves.py
+++ b/lorrycontroller/lstroves.py
@@ -137,6 +137,7 @@ class TroveRepositoryLister(object):
path=local_path,
text=json.dumps(lorry, indent=4),
from_trovehost=trovehost,
+ from_path=remote_path,
interval=trove_info['lorry_interval'])
all_local_paths = set(statedb.get_lorries_for_trove(trovehost))
diff --git a/lorrycontroller/readconf.py b/lorrycontroller/readconf.py
index 9ee1f3d..f4dad65 100644
--- a/lorrycontroller/readconf.py
+++ b/lorrycontroller/readconf.py
@@ -157,7 +157,7 @@ class ReadConfiguration(lorrycontroller.LorryControllerRoute):
old_lorry_info = None
statedb.add_to_lorries(
- path=path, text=text, from_trovehost='',
+ path=path, text=text, from_trovehost='', from_path='',
interval=interval)
added_paths.add(path)
diff --git a/lorrycontroller/statedb.py b/lorrycontroller/statedb.py
index f1da8c9..b49da60 100644
--- a/lorrycontroller/statedb.py
+++ b/lorrycontroller/statedb.py
@@ -59,6 +59,7 @@ class StateDB(object):
('path', 'TEXT PRIMARY KEY'),
('text', 'TEXT'),
('from_trovehost', 'TEXT'),
+ ('from_path', 'TEXT'),
('running_job', 'INT'),
('kill_job', 'INT'),
('last_run', 'INT'),
@@ -290,8 +291,8 @@ class StateDB(object):
'SELECT path FROM lorries WHERE from_trovehost IS ?', (trovehost,))
return [row[0] for row in c.fetchall()]
- def add_to_lorries(self, path=None, text=None, from_trovehost=None,
- interval=None):
+ def add_to_lorries(self, path=None, text=None, from_trovehost=None,
+ from_path=None, interval=None):
logging.debug(
'StateDB.add_to_lorries('
'path=%r, text=%r, from_trovehost=%r, interval=%s called',
@@ -303,6 +304,7 @@ class StateDB(object):
assert path is not None
assert text is not None
assert from_trovehost is not None
+ assert from_path is not None
assert interval is not None
assert self.in_transaction
@@ -320,9 +322,9 @@ class StateDB(object):
c = self.get_cursor()
c.execute(
'UPDATE lorries '
- 'SET text=?, from_trovehost=?, interval=? '
+ 'SET text=?, from_trovehost=?, from_path=?, interval=? '
'WHERE path IS ?',
- (text, from_trovehost, interval, path))
+ (text, from_trovehost, from_path, interval, path))
def remove_lorry(self, path):
logging.debug('StateDB.remove_lorry(%r) called', path)