Skip to content

Commit 99729b1

Browse files
author
Gabriel Monroy
committed
add logs endpoint, views and tests along with deis logs cli command re #20
1 parent 16cfd8d commit 99729b1

7 files changed

Lines changed: 58 additions & 0 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ nosetests.xml
4040
# Deis' config file
4141
deis/local_settings.py
4242

43+
# deis application logs
44+
logs/
45+
4346
# Misc.
4447
.DS_Store
4548
htmlcov/

api/models.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import importlib
1111
import json
1212
import os
13+
import subprocess
1314
import yaml
1415

1516
from celery.canvas import group
@@ -436,6 +437,14 @@ def converge(self, databag):
436437
job.apply_async().join()
437438
return databag
438439

440+
def logs(self):
441+
"""Return aggregated log data for this formation."""
442+
path = os.path.join(settings.DEIS_LOG_DIR, self.id + '.log')
443+
if not os.path.exists(path):
444+
raise EnvironmentError('Could not locate logs')
445+
data = subprocess.check_output(['tail', '-n', str(settings.LOG_LINES), path])
446+
return data
447+
439448
def destroy(self):
440449
"""Create subtasks to terminate all nodes in parallel."""
441450
all_layers = self.layer_set.all()

api/tests/formation.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
from __future__ import unicode_literals
88

99
import json
10+
import os.path
1011

1112
from django.test import TestCase
13+
from deis import settings
1214

1315

1416
class FormationTest(TestCase):
@@ -130,3 +132,21 @@ def test_formation_actions(self):
130132
self.assertIn('containers', response.data)
131133
self.assertIn('proxy', response.data)
132134
self.assertIn('release', response.data)
135+
# test logs
136+
if not os.path.exists(settings.DEIS_LOG_DIR):
137+
os.mkdir(settings.DEIS_LOG_DIR)
138+
path = os.path.join(settings.DEIS_LOG_DIR, formation_id + '.log')
139+
with open(path, 'w') as f:
140+
f.write(FAKE_LOG_DATA)
141+
url = '/api/formations/{formation_id}/logs'.format(**locals())
142+
response = self.client.post(url)
143+
self.assertEqual(response.status_code, 200)
144+
self.assertEqual(response.data, FAKE_LOG_DATA)
145+
146+
147+
FAKE_LOG_DATA = """
148+
2013-08-15 12:41:25 [33454] [INFO] Starting gunicorn 17.5
149+
2013-08-15 12:41:25 [33454] [INFO] Listening at: http://0.0.0.0:5000 (33454)
150+
2013-08-15 12:41:25 [33454] [INFO] Using worker: sync
151+
2013-08-15 12:41:25 [33457] [INFO] Booting worker with pid 33457
152+
"""

api/urls.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,8 @@
283283
views.FormationViewSet.as_view({'post': 'calculate'})),
284284
url(r'^formations/(?P<id>[a-z0-9-]+)/converge/?',
285285
views.FormationViewSet.as_view({'post': 'converge'})),
286+
url(r'^formations/(?P<id>[a-z0-9-]+)/logs/?',
287+
views.FormationViewSet.as_view({'post': 'logs'})),
286288
# formation base endpoint
287289
url(r'^formations/(?P<id>[a-z0-9-]+)/?',
288290
views.FormationViewSet.as_view({'get': 'retrieve', 'delete': 'destroy'})),

api/views.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,12 @@ def converge(self, request, **kwargs):
223223
return Response(databag, status=status.HTTP_200_OK,
224224
content_type='application/json')
225225

226+
def logs(self, request, **kwargs):
227+
formation = self.get_object()
228+
logs = formation.logs()
229+
return Response(logs, status=status.HTTP_200_OK,
230+
content_type='text/plain')
231+
226232
def destroy(self, request, **kwargs):
227233
formation = self.get_object()
228234
formation.destroy()

client/deis.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,22 @@ def layers_scale(self, args):
10261026
else:
10271027
print('Error!', response.text)
10281028

1029+
def logs(self, args):
1030+
"""
1031+
Retrieve the most recent log events
1032+
1033+
Usage: deis logs
1034+
"""
1035+
formation = args.get('--formation')
1036+
if not formation:
1037+
formation = self._session.formation
1038+
response = self._dispatch('post',
1039+
"/api/formations/{}/logs".format(formation))
1040+
if response.status_code == requests.codes.ok: # @UndefinedVariable
1041+
print(response.json())
1042+
else:
1043+
print('Error!', response.text)
1044+
10291045
def nodes(self, args):
10301046
"""
10311047
Valid commands for nodes:

deis/settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,8 @@
222222

223223
# default deis settings
224224
CONVERGE_ON_PUSH = True
225+
DEIS_LOG_DIR = os.path.abspath(os.path.join(__file__, '..', '..', 'logs'))
226+
LOG_LINES = 1000
225227

226228
# Create a file named "local_settings.py" to contain sensitive settings data
227229
# such as database configuration, admin email, or passwords and keys. It

0 commit comments

Comments
 (0)