Skip to content

Commit aabb08f

Browse files
author
Matthew Fisher
committed
fix(controller): return proper json messages on error
1 parent 2359596 commit aabb08f

7 files changed

Lines changed: 40 additions & 22 deletions

File tree

controller/api/tests/test_app.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,8 @@ def test_run_without_auth(self):
248248
response = self.client.post(url, json.dumps(body), content_type='application/json',
249249
HTTP_AUTHORIZATION='token {}'.format(self.token))
250250
self.assertEquals(response.status_code, 400)
251-
self.assertEquals(response.data, 'Support for admin commands is not configured')
251+
self.assertEquals(response.data, {'detail': 'Support for admin commands '
252+
'is not configured'})
252253

253254
def test_run_without_release_should_error(self):
254255
"""
@@ -265,8 +266,8 @@ def test_run_without_release_should_error(self):
265266
response = self.client.post(url, json.dumps(body), content_type='application/json',
266267
HTTP_AUTHORIZATION='token {}'.format(self.token))
267268
self.assertEqual(response.status_code, 400)
268-
self.assertEqual(response.data, "No build associated with this release "
269-
"to run this command")
269+
self.assertEqual(response.data, {'detail': 'No build associated with this '
270+
'release to run this command'})
270271

271272
@unittest.expectedFailure
272273
def test_unauthorized_user_cannot_see_app(self):

controller/api/tests/test_auth.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ def test_passwd(self):
133133
response = self.client.post(url, json.dumps(submit), content_type='application/json',
134134
HTTP_AUTHORIZATION='token {}'.format(token))
135135
self.assertEqual(response.status_code, 400)
136+
self.assertEqual(response.data, {'detail': 'Current password does not match'})
137+
self.assertEqual(response.get('content-type'), 'application/json')
136138
submit = {
137139
'password': password,
138140
'new_password': 'password2',

controller/api/tests/test_container.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,8 @@ def test_container_errors(self):
304304
body = {'web': 'not_an_int'}
305305
response = self.client.post(url, json.dumps(body), content_type='application/json',
306306
HTTP_AUTHORIZATION='token {}'.format(self.token))
307-
self.assertContains(response, 'Invalid scaling format', status_code=400)
307+
self.assertEqual(response.status_code, 400)
308+
self.assertEqual(response.data, {'detail': 'Invalid scaling format'})
308309
body = {'invalid': 1}
309310
response = self.client.post(url, json.dumps(body), content_type='application/json',
310311
HTTP_AUTHORIZATION='token {}'.format(self.token))
@@ -447,7 +448,7 @@ def test_scale_without_build_should_error(self):
447448
response = self.client.post(url, json.dumps(body), content_type='application/json',
448449
HTTP_AUTHORIZATION='token {}'.format(self.token))
449450
self.assertEqual(response.status_code, 400)
450-
self.assertEqual(response.data, "No build associated with this release")
451+
self.assertEqual(response.data, {'detail': 'No build associated with this release'})
451452

452453
def test_command_good(self):
453454
"""Test the default command for each container workflow"""

controller/api/tests/test_release.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ def test_release_rollback(self):
147147
response = self.client.post(url, content_type='application/json',
148148
HTTP_AUTHORIZATION='token {}'.format(self.token))
149149
self.assertEqual(response.status_code, 400)
150+
self.assertEqual(response.data, {'detail': 'version cannot be below 0'})
151+
self.assertEqual(response.get('content-type'), 'application/json')
150152
# update config to roll a new release
151153
url = '/v1/apps/{app_id}/config'.format(**locals())
152154
body = {'values': json.dumps({'NEW_URL1': 'http://localhost:8080/'})}

controller/api/tests/test_scheduler.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ def test_create_chaos(self):
6969
response = self.client.post(url, json.dumps(body), content_type='application/json',
7070
HTTP_AUTHORIZATION='token {}'.format(self.token))
7171
self.assertEqual(response.status_code, 503)
72+
self.assertEqual(response.data, {'detail': 'aborting, failed to create some containers'})
73+
self.assertEqual(response.get('content-type'), 'application/json')
7274
# inspect broken containers
7375
url = "/v1/apps/{app_id}/containers".format(**locals())
7476
response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
@@ -151,6 +153,8 @@ def test_destroy_chaos(self):
151153
response = self.client.post(url, json.dumps(body), content_type='application/json',
152154
HTTP_AUTHORIZATION='token {}'.format(self.token))
153155
self.assertEqual(response.status_code, 503)
156+
self.assertEqual(response.data, {'detail': 'aborting, failed to destroy some containers'})
157+
self.assertEqual(response.get('content-type'), 'application/json')
154158
# inspect broken containers
155159
url = "/v1/apps/{app_id}/containers".format(**locals())
156160
response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
@@ -167,7 +171,10 @@ def test_destroy_chaos(self):
167171
# break if we destroyed successfully
168172
if response.status_code == 204:
169173
break
170-
self.assertEquals(response.status_code, 503)
174+
self.assertEqual(response.status_code, 503)
175+
self.assertEqual(response.data, {'detail': 'aborting, failed to '
176+
'destroy some containers'})
177+
self.assertEqual(response.get('content-type'), 'application/json')
171178
# inspect broken containers
172179
url = "/v1/apps/{app_id}/containers".format(**locals())
173180
response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
@@ -216,6 +223,8 @@ def test_build_chaos(self):
216223
response = self.client.post(url, json.dumps(body), content_type='application/json',
217224
HTTP_AUTHORIZATION='token {}'.format(self.token))
218225
self.assertEqual(response.status_code, 503)
226+
self.assertEqual(response.data, {'detail': 'aborting, failed to create some containers'})
227+
self.assertEqual(response.get('content-type'), 'application/json')
219228
# inspect releases
220229
url = "/v1/apps/{app_id}/releases".format(**locals())
221230
response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
@@ -267,6 +276,8 @@ def test_config_chaos(self):
267276
response = self.client.post(url, json.dumps(body), content_type='application/json',
268277
HTTP_AUTHORIZATION='token {}'.format(self.token))
269278
self.assertEqual(response.status_code, 503)
279+
self.assertEqual(response.data, {'detail': 'aborting, failed to create some containers'})
280+
self.assertEqual(response.get('content-type'), 'application/json')
270281
# inspect releases
271282
url = "/v1/apps/{app_id}/releases".format(**locals())
272283
response = self.client.get(url, HTTP_AUTHORIZATION='token {}'.format(self.token))
@@ -315,3 +326,5 @@ def test_run_chaos(self):
315326
response = self.client.post(url, json.dumps(body), content_type='application/json',
316327
HTTP_AUTHORIZATION='token {}'.format(self.token))
317328
self.assertEqual(response.status_code, 503)
329+
self.assertEqual(response.data, {'detail': 'exit code 1'})
330+
self.assertEqual(response.get('content-type'), 'application/json')

controller/api/views.py

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ def get_object(self):
3838
def passwd(self, request, **kwargs):
3939
obj = self.get_object()
4040
if not obj.check_password(request.DATA['password']):
41-
return Response("Current password did not match", status=status.HTTP_400_BAD_REQUEST)
41+
return Response({'detail': 'Current password does not match'},
42+
status=status.HTTP_400_BAD_REQUEST)
4243
obj.set_password(request.DATA['new_password'])
4344
obj.save()
4445
return Response({'status': 'password set'})
@@ -60,7 +61,7 @@ def create(self, request, *args, **kwargs):
6061
return super(BaseDeisViewSet, self).create(request, *args, **kwargs)
6162
# If the scheduler oopsie'd
6263
except RuntimeError as e:
63-
return Response(str(e), status=status.HTTP_503_SERVICE_UNAVAILABLE)
64+
return Response({'detail': str(e)}, status=status.HTTP_503_SERVICE_UNAVAILABLE)
6465

6566

6667
class AppResourceViewSet(BaseDeisViewSet):
@@ -116,22 +117,20 @@ def post_save(self, app):
116117

117118
def scale(self, request, **kwargs):
118119
new_structure = {}
120+
app = self.get_object()
119121
try:
120122
for target, count in request.DATA.items():
121123
new_structure[target] = int(count)
122-
except (TypeError, ValueError):
123-
return Response('Invalid scaling format',
124-
status=status.HTTP_400_BAD_REQUEST)
125-
app = self.get_object()
126-
try:
127124
models.validate_app_structure(new_structure)
128125
app.scale(request.user, new_structure)
129-
except (EnvironmentError, ValidationError) as e:
130-
return Response(str(e), status=status.HTTP_400_BAD_REQUEST)
126+
except (TypeError, ValueError):
127+
return Response({'detail': 'Invalid scaling format'},
128+
status=status.HTTP_400_BAD_REQUEST)
129+
except (ValidationError, EnvironmentError) as e:
130+
return Response({'detail': str(e)}, status=status.HTTP_400_BAD_REQUEST)
131131
except RuntimeError as e:
132-
return Response(str(e), status=status.HTTP_503_SERVICE_UNAVAILABLE)
133-
return Response(status=status.HTTP_204_NO_CONTENT,
134-
content_type='application/json')
132+
return Response({'detail': str(e)}, status=status.HTTP_503_SERVICE_UNAVAILABLE)
133+
return Response(status=status.HTTP_204_NO_CONTENT)
135134

136135
def logs(self, request, **kwargs):
137136
app = self.get_object()
@@ -150,9 +149,9 @@ def run(self, request, **kwargs):
150149
try:
151150
output_and_rc = app.run(self.request.user, command)
152151
except EnvironmentError as e:
153-
return Response(str(e), status=status.HTTP_400_BAD_REQUEST)
152+
return Response({'detail': str(e)}, status=status.HTTP_400_BAD_REQUEST)
154153
except RuntimeError as e:
155-
return Response(str(e), status=status.HTTP_503_SERVICE_UNAVAILABLE)
154+
return Response({'detail': str(e)}, status=status.HTTP_503_SERVICE_UNAVAILABLE)
156155
return Response(output_and_rc, status=status.HTTP_200_OK,
157156
content_type='text/plain')
158157

@@ -237,7 +236,7 @@ def rollback(self, request, **kwargs):
237236
response = {'version': new_release.version}
238237
return Response(response, status=status.HTTP_201_CREATED)
239238
except EnvironmentError as e:
240-
return Response(str(e), status=status.HTTP_400_BAD_REQUEST)
239+
return Response({'detail': str(e)}, status=status.HTTP_400_BAD_REQUEST)
241240
except RuntimeError:
242241
new_release.delete()
243242
raise

controller/scheduler/chaos.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def run(self, name, image, entrypoint, command):
5050
Run a one-off command
5151
"""
5252
if random.random() < CREATE_ERROR_RATE:
53-
raise RuntimeError
53+
raise RuntimeError('exit code 1')
5454
return 0, ''
5555

5656
SchedulerClient = ChaosSchedulerClient

0 commit comments

Comments
 (0)