diff options
author | Lars Wirzenius <liw@liw.fi> | 2018-01-13 11:10:22 +0200 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2018-01-14 22:23:44 +0200 |
commit | 2fb35dbf240323ba5391937bc6c4fba895750029 (patch) | |
tree | 37e328900c42d9ecf35ae39dca011285c2396f44 | |
parent | 769f03d7ff1709a43c0b82c131fae494f67cf08f (diff) | |
download | ick2-2fb35dbf240323ba5391937bc6c4fba895750029.tar.gz |
Add: move actions for a build into build resource
This way the list is known later even if the pipeline spec is changed.
-rw-r--r-- | ick2/__init__.py | 1 | ||||
-rw-r--r-- | ick2/state.py | 25 | ||||
-rw-r--r-- | ick2/workapi.py | 38 | ||||
-rw-r--r-- | ick2/workapi_tests.py | 4 | ||||
-rw-r--r-- | yarns/400-build.yarn | 85 | ||||
-rw-r--r-- | yarns/500-build-fail.yarn | 13 |
6 files changed, 131 insertions, 35 deletions
diff --git a/ick2/__init__.py b/ick2/__init__.py index 9af0521..1715e62 100644 --- a/ick2/__init__.py +++ b/ick2/__init__.py @@ -22,6 +22,7 @@ from .state import ( Workers, Projects, PipelineInstances, + Builds, ) from .exceptions import ( BadUpdate, diff --git a/ick2/state.py b/ick2/state.py index 806b2a7..3a985a8 100644 --- a/ick2/state.py +++ b/ick2/state.py @@ -40,9 +40,9 @@ class ControllerState: def get_resource_directory(self, type_name): return os.path.join(self.get_state_directory(), type_name) - def get_resource_filename(self, type_name, project_name): - return os.path.join( - self.get_resource_directory(type_name), project_name + '.yaml') + def get_resource_filename(self, type_name, resource_name): + dirname = self.get_resource_directory(type_name) + return os.path.join(dirname, resource_name + '.yaml') def load_resources(self, type_name): assert self._statedir is not None @@ -107,10 +107,14 @@ class ResourceStore: # pragma: no cover self._category = category self._name_field = name_field + def get_resource_name(self, name): + return str(name) + def list(self): return self._state.get_resources(self._category) def get(self, name): + name = self.get_resource_name(name) try: return self._state.get_resource(self._category, name) except ick2.NotFound: @@ -119,10 +123,11 @@ class ResourceStore: # pragma: no cover } def add(self, name, resource): + name = self.get_resource_name(name) self._state.add_resource(self._category, name, resource) def update(self, resource): - name = resource[self._name_field] + name = self.get_resource_name(resource[self._name_field]) try: self._state.get_resource(self._category, name) except ick2.NotFound: @@ -155,6 +160,18 @@ class Projects(ResourceStore): # pragma: no cover self.update(project) +class Builds(ResourceStore): # pragma: no cover + + def __init__(self, state): + super().__init__(state, 'builds', 'build_id') + + def get_builds(self): + return self.list() + + def update_build(self, build): + self.update(build) + + class PipelineInstances(ResourceStore): # pragma: no cover def __init__(self, state): diff --git a/ick2/workapi.py b/ick2/workapi.py index f4c76a7..7edafe0 100644 --- a/ick2/workapi.py +++ b/ick2/workapi.py @@ -23,6 +23,7 @@ class WorkAPI(ick2.APIbase): self._workers = ick2.Workers(state) self._projects = ick2.Projects(state) self._pinstances = ick2.PipelineInstances(state) + self._builds = ick2.Builds(state) self._type_name = 'work' def get_routes(self, path): # pragma: no cover @@ -55,8 +56,10 @@ class WorkAPI(ick2.APIbase): self._start_build(project, pipeline, worker, build_id) self._start_log(build_id) + build = self._get_build(build_id) + actions = build['actions'] + current_action = build['current_action'] - index = 0 doing = { 'build_id': build_id, 'worker': worker, @@ -64,8 +67,7 @@ class WorkAPI(ick2.APIbase): 'pipeline': pipeline['name'], 'parameters': project.get('parameters', {}), 'fresh_workspace': True, - 'step': pipeline['actions'][index], - 'step_index': index, + 'step': actions[current_action], 'log': '/logs/{}'.format(build_id), } @@ -108,10 +110,15 @@ class WorkAPI(ick2.APIbase): 'pipeline': pipeline['name'], 'parameters': parameters, 'status': 'building', + 'actions': pipeline['actions'], + 'current_action': 0, } - self._state.add_resource('builds', str(build_id), build) + self._builds.add(build_id, build) return build_id + def _get_build(self, build_id): + return self._builds.get(build_id) + def _start_log(self, build_id): ick2.log.log('info', msg_text='Starting new log', build_id=build_id) log = { @@ -134,16 +141,20 @@ class WorkAPI(ick2.APIbase): exit_code = update.get('exit_code') if exit_code == 0: - index = doing['step_index'] + 1 - actions = pipeline['actions'] - if index >= len(actions): + build_id = doing['build_id'] + build = self._get_build(build_id) + actions = build['actions'] + current_action = build['current_action'] + if current_action + 1 >= len(actions): pipeline['status'] = 'idle' self._update_pipeline(project, pipeline) doing = {} self._finish_build(update) else: - doing['step_index'] = index - doing['step'] = dict(actions[index]) + index = current_action + 1 + build['current_action'] = index + self._update_build(build) + doing['step'] = actions[index] doing['fresh_workspace'] = False worker_state = { @@ -197,10 +208,15 @@ class WorkAPI(ick2.APIbase): log['log'] += text self._state.update_resource('log', str(build_id), log) + def _update_build(self, build): + self._builds.update_build(build) + def _finish_build(self, update): - build = self._state.get_resource('builds', str(update['build_id'])) + build_id = update['build_id'] + build = self._get_build(build_id) build['status'] = update['exit_code'] - self._state.update_resource('builds', str(update['build_id']), build) + build['current_action'] = None + self._update_build(build) def create(self, body, **kwargs): # pragma: no cover pass diff --git a/ick2/workapi_tests.py b/ick2/workapi_tests.py index d7ebfa9..51ac604 100644 --- a/ick2/workapi_tests.py +++ b/ick2/workapi_tests.py @@ -90,7 +90,6 @@ class WorkAPITests(unittest.TestCase): 'step': { 'shell': 'step-1', }, - 'step_index': 0, 'log': '/logs/1', } self.assertEqual(work.get_work('asterix'), expected) @@ -117,7 +116,6 @@ class WorkAPITests(unittest.TestCase): 'step': { 'shell': 'step-1', }, - 'step_index': 0, 'log': '/logs/1', } self.assertEqual(work.get_work('asterix'), expected) @@ -145,7 +143,6 @@ class WorkAPITests(unittest.TestCase): # We should get the next step now. expected['step'] = {'shell': 'step-2'} - expected['step_index'] = 1 expected['fresh_workspace'] = False self.assertEqual(work.get_work('asterix'), expected) @@ -180,7 +177,6 @@ class WorkAPITests(unittest.TestCase): 'step': { 'shell': 'step-1', }, - 'step_index': 0, 'log': '/logs/1', } self.assertEqual(work.get_work('asterix'), expected) diff --git a/yarns/400-build.yarn b/yarns/400-build.yarn index c8746b4..225bc3b 100644 --- a/yarns/400-build.yarn +++ b/yarns/400-build.yarn @@ -123,8 +123,7 @@ be in the path or can we get it in the access token?** ... "fresh_workspace": true, ... "step": { ... "shell": "day 1" - ... }, - ... "step_index": 0 + ... } ... } WHEN worker-manager makes request GET /work/obelix @@ -142,8 +141,7 @@ be in the path or can we get it in the access token?** ... "fresh_workspace": true, ... "step": { ... "shell": "day 1" - ... }, - ... "step_index": 0 + ... } ... } User can now see pipeline is running and which worker is building it. @@ -170,7 +168,6 @@ User can now see pipeline is running and which worker is building it. ... "foo": "bar" ... }, ... "fresh_workspace": true, - ... "step_index": 0, ... "step": { ... "shell": "day 1" ... } @@ -188,6 +185,11 @@ User can now see pipeline is running and which worker is building it. ... "worker": "obelix", ... "project": "rome", ... "pipeline": "construct", + ... "actions": [ + ... { "shell": "day 1" }, + ... { "shell": "day 2" } + ... ], + ... "current_action": 0, ... "parameters": { ... "foo": "bar" ... }, @@ -217,7 +219,8 @@ Worker reports some build output. Note the null exit code. ... } THEN result has status code 201 -Still the same job, since the first build step didnt't finish. +Worker-manager still gets the same step, since the first build step +didnt't finish. WHEN worker-manager makes request GET /work/obelix THEN result has status code 200 @@ -234,8 +237,7 @@ Still the same job, since the first build step didnt't finish. ... "fresh_workspace": true, ... "step": { ... "shell": "day 1" - ... }, - ... "step_index": 0 + ... } ... } The build log is immediately accessible. @@ -265,6 +267,33 @@ Report the step is done, and successfully. AND result has header Content-Type: text/plain AND body text is "hey ho, hey ho\n" +The build status now shows the next step as the active one. + + WHEN user makes request GET /builds + THEN result has status code 200 + AND body matches + ... { + ... "builds": [ + ... { + ... "build_id": 1, + ... "log": "/logs/1", + ... "worker": "obelix", + ... "project": "rome", + ... "pipeline": "construct", + ... "actions": [ + ... { "shell": "day 1" }, + ... { "shell": "day 2" } + ... ], + ... "current_action": 1, + ... "parameters": { + ... "foo": "bar" + ... }, + ... "status": "building", + ... "log": "/logs/1" + ... } + ... ] + ... } + Now there's another step to do. WHEN worker-manager makes request GET /work/obelix @@ -282,8 +311,7 @@ Now there's another step to do. ... "fresh_workspace": false, ... "step": { ... "shell": "day 2" - ... }, - ... "step_index": 1 + ... } ... } User sees changed status. @@ -302,7 +330,6 @@ User sees changed status. ... "foo": "bar" ... }, ... "fresh_workspace": false, - ... "step_index": 1, ... "step": { ... "shell": "day 2" ... }, @@ -337,7 +364,8 @@ The pipeline status indicates success. THEN result has status code 200 AND body matches { "status": "idle" } -Also, there's a build with a log. +Also, there's a build with a log. Also, the build status shows there's +no current action. WHEN user makes request GET /builds THEN result has status code 200 @@ -350,6 +378,11 @@ Also, there's a build with a log. ... "worker": "obelix", ... "project": "rome", ... "pipeline": "construct", + ... "actions": [ + ... { "shell": "day 1" }, + ... { "shell": "day 2" } + ... ], + ... "current_action": null, ... "parameters": { ... "foo": "bar" ... }, @@ -368,6 +401,11 @@ Also, there's a build with a log. ... "worker": "obelix", ... "project": "rome", ... "pipeline": "construct", + ... "actions": [ + ... { "shell": "day 1" }, + ... { "shell": "day 2" } + ... ], + ... "current_action": null, ... "parameters": { ... "foo": "bar" ... }, @@ -401,8 +439,7 @@ Start build again. This should become build number 2. ... "fresh_workspace": true, ... "step": { ... "shell": "day 1" - ... }, - ... "step_index": 0 + ... } ... } WHEN user makes request GET /builds @@ -416,6 +453,11 @@ Start build again. This should become build number 2. ... "worker": "obelix", ... "project": "rome", ... "pipeline": "construct", + ... "actions": [ + ... { "shell": "day 1" }, + ... { "shell": "day 2" } + ... ], + ... "current_action": null, ... "parameters": { ... "foo": "bar" ... }, @@ -427,6 +469,11 @@ Start build again. This should become build number 2. ... "worker": "obelix", ... "project": "rome", ... "pipeline": "construct", + ... "actions": [ + ... { "shell": "day 1" }, + ... { "shell": "day 2" } + ... ], + ... "current_action": 0, ... "parameters": { ... "foo": "bar" ... }, @@ -475,6 +522,11 @@ Start build again. This should become build number 2. ... "worker": "obelix", ... "project": "rome", ... "pipeline": "construct", + ... "actions": [ + ... { "shell": "day 1" }, + ... { "shell": "day 2" } + ... ], + ... "current_action": null, ... "parameters": { ... "foo": "bar" ... }, @@ -486,6 +538,11 @@ Start build again. This should become build number 2. ... "worker": "obelix", ... "project": "rome", ... "pipeline": "construct", + ... "actions": [ + ... { "shell": "day 1" }, + ... { "shell": "day 2" } + ... ], + ... "current_action": null, ... "parameters": { ... "foo": "bar" ... }, diff --git a/yarns/500-build-fail.yarn b/yarns/500-build-fail.yarn index bc0a5ab..a88108c 100644 --- a/yarns/500-build-fail.yarn +++ b/yarns/500-build-fail.yarn @@ -91,8 +91,7 @@ Worker wants work and gets the first step to run. ... "fresh_workspace": true, ... "step": { ... "shell": "day 1" - ... }, - ... "step_index": 0 + ... } ... } Worker reports some build output. Note the exit code indicating @@ -147,6 +146,11 @@ Also, there's a build with a log. ... "worker": "obelix", ... "project": "rome", ... "pipeline": "construct", + ... "actions": [ + ... { "shell": "day 1" }, + ... { "shell": "day 2" } + ... ], + ... "current_action": null, ... "parameters": {}, ... "status": 1, ... "log": "/logs/1" @@ -163,6 +167,11 @@ Also, there's a build with a log. ... "worker": "obelix", ... "project": "rome", ... "pipeline": "construct", + ... "actions": [ + ... { "shell": "day 1" }, + ... { "shell": "day 2" } + ... ], + ... "current_action": null, ... "parameters": {}, ... "status": 1, ... "log": "/logs/1" |