summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ick2/controllerapi.py54
-rw-r--r--ick2/controllerapi_tests.py6
-rw-r--r--yarns/400-build.yarn46
3 files changed, 94 insertions, 12 deletions
diff --git a/ick2/controllerapi.py b/ick2/controllerapi.py
index 5cf5d64..c72c300 100644
--- a/ick2/controllerapi.py
+++ b/ick2/controllerapi.py
@@ -34,6 +34,7 @@ class ControllerAPI:
apis = {
'/version': VersionAPI,
'/builds': BuildsAPI,
+ '/log': LogAPI,
'/projects': ProjectAPI,
'/work': WorkAPI,
'/workers': WorkerAPI,
@@ -93,7 +94,11 @@ class APIbase: # pragma: no cover
body = callback(**kwargs)
except ick2.NotFound as e:
return not_found(e)
- return OK(body)
+ if isinstance(body, dict):
+ return OK(body)
+ elif isinstance(body, str):
+ return text_plain(body)
+ raise Exception('this must not happen')
return wrapper
def POST(self, callback):
@@ -242,6 +247,26 @@ class BuildsAPI(ResourceApiBase): # pragma: no cover
raise MethodNotAllowed('Updating builds directly is not allowed')
+class LogAPI(ResourceApiBase): # pragma: no cover
+
+ def __init__(self, state):
+ super().__init__('log', state)
+
+ def get_resource_name(self, resource):
+ return resource['log']
+
+ def create(self, body): # pragma: no cover
+ raise MethodNotAllowed('Creating builds directly is not allowed')
+
+ def update(self, body, name): # pragma: no cover
+ raise MethodNotAllowed('Updating builds directly is not allowed')
+
+ def show(self, name):
+ log = self._state.get_resource('log', str(name))
+ ick2.log.log('info', msg_text='Returning log', log=log)
+ return log['log']
+
+
class ProjectAPI(ResourceApiBase):
def __init__(self, state):
@@ -343,6 +368,7 @@ class WorkAPI(APIbase):
self._update_project(project)
build_id = self._start_build(project, pipeline, worker)
+ self._start_log(build_id)
index = 0
doing = {
@@ -352,6 +378,7 @@ class WorkAPI(APIbase):
'pipeline': pipeline['name'],
'step': pipeline['actions'][index],
'step_index': index,
+ 'log': '/log/{}'.format(build_id),
}
worker_state = {
@@ -450,6 +477,7 @@ class WorkAPI(APIbase):
build_id = 1
build = {
'build_id': build_id,
+ 'log': '/log/{}'.format(build_id),
'worker': worker,
'project': project['project'],
'pipeline': pipeline['name'],
@@ -458,8 +486,23 @@ class WorkAPI(APIbase):
self._state.add_resource('builds', str(build_id), build)
return build_id
+ def _start_log(self, build_id):
+ ick2.log.log('info', msg_text='Starting new log', build_id=build_id)
+ log = {
+ 'build_id': build_id,
+ 'log': '',
+ }
+ self._state.add_resource('log', str(build_id), log)
+ return build_id
+
def _append_to_build_log(self, update):
- pass
+ build_id = update['build_id']
+ log = self._state.get_resource('log', str(build_id))
+ for kind in ['stdout', 'stderr']:
+ text = update.get(kind, '')
+ if text is not None:
+ log['log'] += text
+ self._state.update_resource('log', str(build_id), log)
def _finish_build(self, update):
build = self._state.get_resource('builds', str(update['build_id']))
@@ -510,6 +553,13 @@ def OK(body): # pragma: no cover
return response(apifw.HTTP_OK, body, headers)
+def text_plain(body): # pragma: no cover
+ headers = {
+ 'Content-Type': 'text/plain',
+ }
+ return response(apifw.HTTP_OK, body, headers)
+
+
def not_found(error): # pragma: no cover
headers = {
'Content-Type': 'text/plain',
diff --git a/ick2/controllerapi_tests.py b/ick2/controllerapi_tests.py
index ce1e1d5..709f184 100644
--- a/ick2/controllerapi_tests.py
+++ b/ick2/controllerapi_tests.py
@@ -294,6 +294,7 @@ class WorkAPITests(unittest.TestCase):
'shell': 'step-1',
},
'step_index': 0,
+ 'log': '/log/1',
}
self.assertEqual(work.get_work('asterix'), expected)
@@ -316,6 +317,7 @@ class WorkAPITests(unittest.TestCase):
'shell': 'step-1',
},
'step_index': 0,
+ 'log': '/log/1',
}
self.assertEqual(work.get_work('asterix'), expected)
@@ -326,8 +328,8 @@ class WorkAPITests(unittest.TestCase):
'project': 'foo',
'pipeline': 'build',
'exit_code': None,
- 'stdout': None,
- 'stderr': None,
+ 'stdout': 'out',
+ 'stderr': 'err',
'timestamp': '2000-01-01T00:00:00',
}
work.update_work(done)
diff --git a/yarns/400-build.yarn b/yarns/400-build.yarn
index b544695..c57fd07 100644
--- a/yarns/400-build.yarn
+++ b/yarns/400-build.yarn
@@ -35,6 +35,7 @@ Set up the controller.
... uapi_workers_id_get
... uapi_builds_get
... uapi_builds_id_get
+ ... uapi_log_id_get
AND a running ick controller
Add up a project.
@@ -94,6 +95,7 @@ be in the path or can we get it in the access token?**
AND body matches
... {
... "build_id": 1,
+ ... "log": "/log/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -108,6 +110,7 @@ be in the path or can we get it in the access token?**
AND body matches
... {
... "build_id": 1,
+ ... "log": "/log/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -133,6 +136,7 @@ User can now see pipeline is running and which worker is building it.
... "worker": "obelix",
... "doing": {
... "build_id": 1,
+ ... "log": "/log/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -150,14 +154,21 @@ User can now see pipeline is running and which worker is building it.
... "builds": [
... {
... "build_id": 1,
+ ... "log": "/log/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
- ... "status": "building"
+ ... "status": "building",
+ ... "log": "/log/1"
... }
... ]
... }
+ WHEN user makes request GET /log/1
+ THEN result has status code 200
+ AND result has header Content-Type: text/plain
+ AND body text is ""
+
Worker reports some build output. Note the null exit code.
WHEN worker-manager makes request POST /work
@@ -167,7 +178,7 @@ Worker reports some build output. Note the null exit code.
... "project": "rome",
... "pipeline": "construct",
... "exit_code": null,
- ... "stdout": "hey ho hey ho",
+ ... "stdout": "hey ho",
... "stderr": "",
... "timestamp": "2017-10-27T17:08:49"
... }
@@ -180,6 +191,7 @@ Still the same job, since the first build step didnt't finish.
AND body matches
... {
... "build_id": 1,
+ ... "log": "/log/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -189,6 +201,13 @@ Still the same job, since the first build step didnt't finish.
... "step_index": 0
... }
+The build log is immediately accessible.
+
+ WHEN user makes request GET /log/1
+ THEN result has status code 200
+ AND result has header Content-Type: text/plain
+ AND body text is "hey ho"
+
Report the step is done, and successfully.
WHEN worker-manager makes request POST /work
@@ -198,12 +217,17 @@ Report the step is done, and successfully.
... "project": "rome",
... "pipeline": "construct",
... "exit_code": 0,
- ... "stdout": "hey ho, hey ho\n",
+ ... "stdout": ", hey ho\n",
... "stderr": "",
... "timestamp": "2017-10-27T17:08:49"
... }
THEN result has status code 201
+ WHEN user makes request GET /log/1
+ THEN result has status code 200
+ AND result has header Content-Type: text/plain
+ AND body text is "hey ho, hey ho\n"
+
Now there's another step to do.
WHEN worker-manager makes request GET /work/obelix
@@ -211,6 +235,7 @@ Now there's another step to do.
AND body matches
... {
... "build_id": 1,
+ ... "log": "/log/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -235,7 +260,8 @@ User sees changed status.
... "step_index": 1,
... "step": {
... "shell": "day 2"
- ... }
+ ... },
+ ... "log": "/log/1"
... }
... }
@@ -275,10 +301,12 @@ Also, there's a build with a log.
... "builds": [
... {
... "build_id": 1,
+ ... "log": "/log/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
- ... "status": 0
+ ... "status": 0,
+ ... "log": "/log/1"
... }
... ]
... }
@@ -288,15 +316,17 @@ Also, there's a build with a log.
AND body matches
... {
... "build_id": 1,
+ ... "log": "/log/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
- ... "status": 0
+ ... "status": 0,
+ ... "log": "/log/1"
... }
- WHEN user makes request GET /builds/1/log
+ WHEN user makes request GET /log/1
THEN result has status code 200
AND result has header Content-Type: text/plain
- AND body matches "hey ho, hey ho\nto the gold mine we go!\n"
+ AND body text is "hey ho, hey ho\nto the gold mine we go!\n"
FINALLY stop ick controller