diff options
author | Lars Wirzenius <liw@liw.fi> | 2017-11-05 20:15:58 +0100 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2017-11-05 20:15:58 +0100 |
commit | ce63c337d6f8357367efd730c373cd033a568181 (patch) | |
tree | f352e647de4bab9006c7ff2a1a47a2136b715ca1 | |
parent | 30508ca876f00d5aae004ca0588258767e345480 (diff) | |
download | ick2-ce63c337d6f8357367efd730c373cd033a568181.tar.gz |
Add: advance to next step in pipeline automatically
-rw-r--r-- | ick2/controllerapi.py | 61 | ||||
-rw-r--r-- | ick2/controllerapi_tests.py | 59 | ||||
-rw-r--r-- | yarns/400-build.yarn | 2 |
3 files changed, 120 insertions, 2 deletions
diff --git a/ick2/controllerapi.py b/ick2/controllerapi.py index a7d4026..b140ce5 100644 --- a/ick2/controllerapi.py +++ b/ick2/controllerapi.py @@ -323,11 +323,13 @@ class WorkAPI(APIbase): pipeline['status'] = 'building' self._update_project(project) + index = 0 doing = { + 'worker': worker, 'project': project['project'], 'pipeline': pipeline['name'], - 'step': pipeline['actions'][0], - 'step_index': 0, + 'step': pipeline['actions'][index], + 'step_index': index, } worker_state = { @@ -364,6 +366,55 @@ class WorkAPI(APIbase): def _update_project(self, project): self._state.update_resource('projects', project['project'], project) + def update_work(self, update): + if 'worker' not in update: # pragma: no cover + raise BadUpdate('no worker specified') + + worker_state = self._get_worker(update['worker']) + doing = worker_state.get('doing', {}) + self._check_work_update(doing, update) + + project, pipeline = self._get_pipeline( + update['project'], update['pipeline']) + + if update.get('exit_code') == 0: + index = doing['step_index'] + 1 + actions = pipeline['actions'] + if index >= len(actions): + self._finish_pipeline(project, pipeline) + doing = {} + else: + doing['step_index'] = index + doing['step'] = actions[index] + + worker_state = { + 'worker': update['worker'], + 'doing': doing, + } + self._update_worker(worker_state) + + def _check_work_update(self, doing, update): # pragma: no cover + must_match = ['worker', 'project', 'pipeline'] + for name in must_match: + if name not in update: + raise BadUpdate('{} not specified'.format(name)) + if doing.get(name) != update[name]: + raise BadUpdate( + '{} differs from current work: {} vs {}'.format( + name, doing.get(name), update[name])) + + def _get_pipeline(self, project, pipeline): # pragma: no cover + projects = self._get_projects() + for p in projects: + for pl in p['pipelines']: + if pl.get('name') == pipeline: + return p, pl + raise ick2.NotFound() + + def _finish_pipeline(self, project, pipeline): + pipeline['status'] = 'idle' + self._update_project(project) + def create(self, *args, **kwargs): # pragma: no cover pass @@ -380,6 +431,12 @@ class WorkAPI(APIbase): pass +class BadUpdate(Exception): # pragma: no cover + + def __init__(self, how): + super().__init__('Work update is BAD: {}'.format(how)) + + def response(status_code, body, headers): # pragma: no cover obj = { 'status': status_code, diff --git a/ick2/controllerapi_tests.py b/ick2/controllerapi_tests.py index 6b31117..efada2a 100644 --- a/ick2/controllerapi_tests.py +++ b/ick2/controllerapi_tests.py @@ -252,6 +252,9 @@ class WorkAPITests(unittest.TestCase): { 'shell': 'step-1', }, + { + 'shell': 'step-2', + }, ], }, ], @@ -283,6 +286,7 @@ class WorkAPITests(unittest.TestCase): self.create_worker_api() work = self.create_work_api() expected = { + 'worker': 'asterix', 'project': 'foo', 'pipeline': 'build', 'step': { @@ -294,3 +298,58 @@ class WorkAPITests(unittest.TestCase): # Check we get the same thing twice. self.assertEqual(work.get_work('asterix'), expected) + + def test_worker_manager_posts_work_updates(self): + projects = self.create_project_api() + projects.set_pipeline('triggered', 'foo', 'build') + self.create_worker_api() + work = self.create_work_api() + + # Ask for some work. + expected = { + 'worker': 'asterix', + 'project': 'foo', + 'pipeline': 'build', + 'step': { + 'shell': 'step-1', + }, + 'step_index': 0, + } + self.assertEqual(work.get_work('asterix'), expected) + + # Post a partial update. + done = { + 'worker': 'asterix', + 'project': 'foo', + 'pipeline': 'build', + 'exit_code': None, + 'stdout': None, + 'stderr': None, + 'timestamp': '2000-01-01T00:00:00', + } + work.update_work(done) + + # Ask for work again. We didn't finish the previous step, so + # should get same thing. + self.assertEqual(work.get_work('asterix'), expected) + + # Finish the step. + done['exit_code'] = 0 + work.update_work(done) + + # We should get the next step now. + expected['step'] = {'shell': 'step-2'} + expected['step_index'] = 1 + self.assertEqual(work.get_work('asterix'), expected) + + # Finish the step. + done['exit_code'] = 0 + work.update_work(done) + + # We now get nothing further to do. + self.assertEqual(work.get_work('asterix'), {}) + + # An pipeline status has changed. + self.assertEqual( + projects.get_pipeline('foo', 'build'), + {'status': 'idle'}) diff --git a/yarns/400-build.yarn b/yarns/400-build.yarn index 719ef05..7632f00 100644 --- a/yarns/400-build.yarn +++ b/yarns/400-build.yarn @@ -90,6 +90,7 @@ be in the path or can we get it in the access token?** THEN result has status code 200 AND body matches ... { + ... "worker": "obelix", ... "project": "rome", ... "pipeline": "construct", ... "step": { @@ -102,6 +103,7 @@ be in the path or can we get it in the access token?** THEN result has status code 200 AND body matches ... { + ... "worker": "obelix", ... "project": "rome", ... "pipeline": "construct", ... "step": { |