summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2017-11-06 12:02:03 +0100
committerLars Wirzenius <liw@liw.fi>2017-11-06 12:02:03 +0100
commit599e095cda626ff66c789017a752d7f91678d033 (patch)
tree24202f10b62992c5e0c1864c7e796e308b0a3cb8
parent854bf88c1a69666db4aacfe540e9797ba6d6a69e (diff)
downloadick2-599e095cda626ff66c789017a752d7f91678d033.tar.gz
Add: /builds
-rw-r--r--ick2/controllerapi.py50
-rw-r--r--ick2/controllerapi_tests.py3
-rw-r--r--yarns/400-build.yarn52
3 files changed, 96 insertions, 9 deletions
diff --git a/ick2/controllerapi.py b/ick2/controllerapi.py
index a7d5fb5..5cf5d64 100644
--- a/ick2/controllerapi.py
+++ b/ick2/controllerapi.py
@@ -33,6 +33,7 @@ class ControllerAPI:
def find_missing_route(self, missing_path): # pragma: no cover
apis = {
'/version': VersionAPI,
+ '/builds': BuildsAPI,
'/projects': ProjectAPI,
'/work': WorkAPI,
'/workers': WorkerAPI,
@@ -226,6 +227,21 @@ class WorkerAPI(ResourceApiBase): # pragma: no cover
return resource['worker']
+class BuildsAPI(ResourceApiBase): # pragma: no cover
+
+ def __init__(self, state):
+ super().__init__('builds', state)
+
+ def get_resource_name(self, resource):
+ return resource['build']
+
+ 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')
+
+
class ProjectAPI(ResourceApiBase):
def __init__(self, state):
@@ -326,8 +342,11 @@ class WorkAPI(APIbase):
pipeline['status'] = 'building'
self._update_project(project)
+ build_id = self._start_build(project, pipeline, worker)
+
index = 0
doing = {
+ 'build_id': build_id,
'worker': worker,
'project': project['project'],
'pipeline': pipeline['name'],
@@ -379,6 +398,7 @@ class WorkAPI(APIbase):
project, pipeline = self._get_pipeline(
update['project'], update['pipeline'])
+ self._append_to_build_log(update)
ick2.log.log(
'trace',
@@ -395,6 +415,7 @@ class WorkAPI(APIbase):
if index >= len(actions):
pipeline['status'] = 'idle'
doing = {}
+ self._finish_build(update)
else:
doing['step_index'] = index
doing['step'] = actions[index]
@@ -407,7 +428,7 @@ class WorkAPI(APIbase):
self._update_worker(worker_state)
def _check_work_update(self, doing, update): # pragma: no cover
- must_match = ['worker', 'project', 'pipeline']
+ must_match = ['worker', 'project', 'pipeline', 'build_id']
for name in must_match:
if name not in update:
raise BadUpdate('{} not specified'.format(name))
@@ -424,6 +445,27 @@ class WorkAPI(APIbase):
return p, pl
raise ick2.NotFound()
+ def _start_build(self, project, pipeline, worker):
+ ick2.log.log('info', msg_text='Starting new build')
+ build_id = 1
+ build = {
+ 'build_id': build_id,
+ 'worker': worker,
+ 'project': project['project'],
+ 'pipeline': pipeline['name'],
+ 'status': 'building',
+ }
+ self._state.add_resource('builds', str(build_id), build)
+ return build_id
+
+ def _append_to_build_log(self, update):
+ pass
+
+ def _finish_build(self, update):
+ build = self._state.get_resource('builds', str(update['build_id']))
+ build['status'] = update['exit_code']
+ self._state.update_resource('builds', str(update['build_id']), build)
+
def create(self, *args, **kwargs): # pragma: no cover
pass
@@ -446,6 +488,12 @@ class BadUpdate(Exception): # pragma: no cover
super().__init__('Work update is BAD: {}'.format(how))
+class MethodNotAllowed(Exception): # pragma: no cover
+
+ def __init__(self, wat):
+ super().__init__(wat)
+
+
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 efada2a..ce1e1d5 100644
--- a/ick2/controllerapi_tests.py
+++ b/ick2/controllerapi_tests.py
@@ -286,6 +286,7 @@ class WorkAPITests(unittest.TestCase):
self.create_worker_api()
work = self.create_work_api()
expected = {
+ 'build_id': 1,
'worker': 'asterix',
'project': 'foo',
'pipeline': 'build',
@@ -307,6 +308,7 @@ class WorkAPITests(unittest.TestCase):
# Ask for some work.
expected = {
+ 'build_id': 1,
'worker': 'asterix',
'project': 'foo',
'pipeline': 'build',
@@ -319,6 +321,7 @@ class WorkAPITests(unittest.TestCase):
# Post a partial update.
done = {
+ 'build_id': 1,
'worker': 'asterix',
'project': 'foo',
'pipeline': 'build',
diff --git a/yarns/400-build.yarn b/yarns/400-build.yarn
index 81124a4..b544695 100644
--- a/yarns/400-build.yarn
+++ b/yarns/400-build.yarn
@@ -33,6 +33,8 @@ Set up the controller.
... uapi_projects_id_pipeline_id_get
... uapi_projects_id_builds_get
... uapi_workers_id_get
+ ... uapi_builds_get
+ ... uapi_builds_id_get
AND a running ick controller
Add up a project.
@@ -58,9 +60,9 @@ There are no builds for the project yet, and is idle.
THEN result has status code 200
AND body matches { "status": "idle" }
- WHEN user makes request GET /projects/rome/builds
+ WHEN user makes request GET /builds
THEN result has status code 200
- AND body matches { "project": "rome", "builds": []}
+ AND body matches { "builds": [] }
Register a worker.
@@ -91,6 +93,7 @@ be in the path or can we get it in the access token?**
THEN result has status code 200
AND body matches
... {
+ ... "build_id": 1,
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -104,6 +107,7 @@ be in the path or can we get it in the access token?**
THEN result has status code 200
AND body matches
... {
+ ... "build_id": 1,
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -128,6 +132,7 @@ User can now see pipeline is running and which worker is building it.
... {
... "worker": "obelix",
... "doing": {
+ ... "build_id": 1,
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -138,11 +143,26 @@ User can now see pipeline is running and which worker is building it.
... }
... }
+ WHEN user makes request GET /builds
+ THEN result has status code 200
+ AND body matches
+ ... {
+ ... "builds": [
+ ... {
+ ... "build_id": 1,
+ ... "worker": "obelix",
+ ... "project": "rome",
+ ... "pipeline": "construct",
+ ... "status": "building"
+ ... }
+ ... ]
+ ... }
Worker reports some build output. Note the null exit code.
WHEN worker-manager makes request POST /work
... {
+ ... "build_id": 1,
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -159,6 +179,7 @@ Still the same job, since the first build step didnt't finish.
THEN result has status code 200
AND body matches
... {
+ ... "build_id": 1,
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -172,6 +193,7 @@ Report the step is done, and successfully.
WHEN worker-manager makes request POST /work
... {
+ ... "build_id": 1,
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -188,6 +210,7 @@ Now there's another step to do.
THEN result has status code 200
AND body matches
... {
+ ... "build_id": 1,
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -205,6 +228,7 @@ User sees changed status.
... {
... "worker": "obelix",
... "doing": {
+ ... "build_id": 1,
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -219,6 +243,7 @@ Report it done.
WHEN worker-manager makes request POST /work
... {
+ ... "build_id": 1,
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -243,22 +268,33 @@ The pipeline status indicates success.
Also, there's a build with a log.
- WHEN user makes request GET /projects/rome/builds
+ WHEN user makes request GET /builds
THEN result has status code 200
AND body matches
... {
- ... "project": "rome",
... "builds": [
... {
+ ... "build_id": 1,
+ ... "worker": "obelix",
+ ... "project": "rome",
... "pipeline": "construct",
- ... "build_number": 1,
- ... "status": "success",
- ... "log": "/projects/rome/logs/1"
+ ... "status": 0
... }
... ]
... }
- WHEN user makes request GET /projects/rome/logs/1
+ WHEN user makes request GET /builds/1
+ THEN result has status code 200
+ AND body matches
+ ... {
+ ... "build_id": 1,
+ ... "worker": "obelix",
+ ... "project": "rome",
+ ... "pipeline": "construct",
+ ... "status": 0
+ ... }
+
+ WHEN user makes request GET /builds/1/log
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"