summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2017-11-25 18:43:36 +0100
committerLars Wirzenius <liw@liw.fi>2017-11-25 18:43:36 +0100
commit2d4733f446dd4e62a554bfe637b1d595571842f8 (patch)
tree8cd3e25939ddf7acf703a863b21f498a28804cad
parentbdadf8cf1acddcbec060a529bedafd0abb5913f2 (diff)
downloadick2-2d4733f446dd4e62a554bfe637b1d595571842f8.tar.gz
Fix: POST /project with an existing project name fails
-rw-r--r--NEWS3
-rw-r--r--ick2/__init__.py2
-rw-r--r--ick2/apibase.py16
-rw-r--r--ick2/exceptions.py6
-rw-r--r--ick2/responses.py7
-rw-r--r--yarns/100-projects.yarn9
6 files changed, 39 insertions, 4 deletions
diff --git a/NEWS b/NEWS
index 91e2186..a6cec8f 100644
--- a/NEWS
+++ b/NEWS
@@ -23,6 +23,9 @@ Version 0.17+git, not yet released
* Add subommand `icktool status` which shows current status of every
pipeline in every project.
+* `POST /projects` (or `icktool create-project`) with a project
+ description that names an already existing project fails.
+
Version 0.17, released 2017-11-19
----------------------------------
diff --git a/ick2/__init__.py b/ick2/__init__.py
index abbde96..13912fe 100644
--- a/ick2/__init__.py
+++ b/ick2/__init__.py
@@ -18,12 +18,14 @@ from .logging import setup_logging, log
from .state import ControllerState, NotFound, WrongPipelineStatus
from .exceptions import (
BadUpdate,
+ ExistsAlready,
IckException,
MethodNotAllowed,
)
from .responses import (
OK,
bad_request,
+ conflict,
created,
not_found,
text_plain,
diff --git a/ick2/apibase.py b/ick2/apibase.py
index 7694b47..9795178 100644
--- a/ick2/apibase.py
+++ b/ick2/apibase.py
@@ -73,8 +73,11 @@ class APIbase:
ick2.log.log(
'trace', msg_text='POST called', kwargs=kwargs,
content_type=content_type, body=body)
- body = callback(body)
- ick2.log.log('trace', msg_text='returned body', body=repr(body))
+ try:
+ body = callback(body)
+ except ick2.ExistsAlready as e:
+ ick2.log.log('error', msg_text=str(e))
+ return ick2.conflict(str(e))
return ick2.created(body)
return wrapper
@@ -144,8 +147,13 @@ class ResourceApiBase(APIbase):
return self._state.get_resource(self._type_name, name)
def create(self, body, **kwargs):
- return self._state.add_resource(
- self._type_name, self.get_resource_name(body), body)
+ name = self.get_resource_name(body)
+ try:
+ self._state.get_resource(self._type_name, name)
+ except ick2.NotFound:
+ return self._state.add_resource(self._type_name, name, body)
+ else:
+ raise ick2.ExistsAlready(name)
def get_resource_name(self, resource): # pragma: no cover
raise NotImplementedError()
diff --git a/ick2/exceptions.py b/ick2/exceptions.py
index c99c3e5..124b207 100644
--- a/ick2/exceptions.py
+++ b/ick2/exceptions.py
@@ -18,6 +18,12 @@ class IckException(Exception):
pass
+class ExistsAlready(IckException):
+
+ def __init__(self, name):
+ super().__init__('Resource {} already exists'.format(name))
+
+
class BadUpdate(IckException):
def __init__(self, how):
diff --git a/ick2/responses.py b/ick2/responses.py
index ef68783..1ceae52 100644
--- a/ick2/responses.py
+++ b/ick2/responses.py
@@ -58,3 +58,10 @@ def created(body): # pragma: no cover
'Content-Type': 'application/json',
}
return response(apifw.HTTP_CREATED, body, headers)
+
+
+def conflict(body): # pragma: no cover
+ headers = {
+ 'Content-Type': 'text/plain',
+ }
+ return response(apifw.HTTP_CONFLICT, body, headers)
diff --git a/yarns/100-projects.yarn b/yarns/100-projects.yarn
index 0aa57b0..de7f9c7 100644
--- a/yarns/100-projects.yarn
+++ b/yarns/100-projects.yarn
@@ -106,6 +106,15 @@ building them. We start by starting an instance of the controller.
... }
AND controller state directory contains project website
+Creating a new project with the same name is forbidden.
+
+ WHEN user makes request POST /projects with a valid token and body
+ ... {
+ ... "project": "website",
+ ... "pipelines": []
+ ... }
+ THEN result has status code 409
+
WHEN user makes request GET /projects
THEN result has status code 200
AND body matches