Merge lp:~ricardokirkner/locolander/django-supervisor into lp:locolander

Proposed by Ricardo Kirkner
Status: Needs review
Proposed branch: lp:~ricardokirkner/locolander/django-supervisor
Merge into: lp:locolander
Prerequisite: lp:~ricardokirkner/locolander/lean-output
Diff against target: 534 lines (+137/-127)
12 files modified
.locolander.yml (+7/-3)
config/supervisord.conf (+0/-37)
docker/Dockerfile (+5/-4)
docker/scripts/locolander (+5/-6)
fabfile.py (+8/-22)
locolander/locolander/settings.py (+3/-2)
locolander/locolanderweb/models.py (+9/-0)
locolander/locolanderweb/tasks.py (+11/-18)
locolander/locolanderweb/tests/test_models.py (+15/-1)
locolander/locolanderweb/tests/test_tasks.py (+28/-31)
locolander/supervisord.conf (+38/-0)
requirements.txt (+8/-3)
To merge this branch: bzr merge lp:~ricardokirkner/locolander/django-supervisor
Reviewer Review Type Date Requested Status
LocoLanderos Pending
Review via email: mp+177407@code.launchpad.net

Commit message

simplified fabfile for supervisor tasks

To post a comment you must log in.
34. By Ricardo Kirkner

better output from script

35. By Ricardo Kirkner

added config for docker process

36. By Ricardo Kirkner

merged trunk

Unmerged revisions

36. By Ricardo Kirkner

merged trunk

35. By Ricardo Kirkner

added config for docker process

34. By Ricardo Kirkner

better output from script

33. By Ricardo Kirkner

replace subprocess with envoy

use envoy instead of subprocess, because the latter fails to run properly
when celeryd is started under supervisor.

32. By Ricardo Kirkner

customized model repr strings

31. By Ricardo Kirkner

use absolute path for database file

30. By Ricardo Kirkner

better output handling

29. By Ricardo Kirkner

disable autoreload

28. By Ricardo Kirkner

added envoy and django-supervisor as dependencies

27. By Ricardo Kirkner

merged branch lp:~ricardokirkner/locolander/lean-output

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.locolander.yml'
--- .locolander.yml 2013-07-23 23:55:56 +0000
+++ .locolander.yml 2013-08-17 00:46:15 +0000
@@ -5,9 +5,6 @@
5 libxml2-dev:5 libxml2-dev:
6 libxslt1-dev:6 libxslt1-dev:
7 pip:7 pip:
8 Django: 1.5.1
9 PyYAML: 3.10.0
10 South: 0.8.1
11 amqp: 1.0.128 amqp: 1.0.12
12 anyjson: 0.3.39 anyjson: 0.3.3
13 argparse: 1.2.110 argparse: 1.2.1
@@ -16,8 +13,11 @@
16 celery: 3.0.2113 celery: 3.0.21
17 cssselect: 0.814 cssselect: 0.8
18 distribute: 0.6.3415 distribute: 0.6.34
16 Django: 1.5.1
19 django-allauth: 0.12.017 django-allauth: 0.12.0
20 django-celery: 3.0.1718 django-celery: 3.0.17
19 django-supervisor: 0.3.1
20 envoy: 0.0.2
21 flower: 0.5.221 flower: 0.5.2
22 github3.py: 0.7.022 github3.py: 0.7.0
23 gunicorn: 17.523 gunicorn: 17.5
@@ -33,6 +33,7 @@
33 mock: 1.0.133 mock: 1.0.1
34 oauth: 1.0.134 oauth: 1.0.1
35 oauthlib: 0.5.035 oauthlib: 0.5.0
36 pathtools: 0.1.2
36 pep8: 1.4.637 pep8: 1.4.6
37 psycopg2: 2.5.138 psycopg2: 2.5.1
38 pyflakes: 0.7.339 pyflakes: 0.7.3
@@ -40,15 +41,18 @@
40 python-dateutil: 2.141 python-dateutil: 2.1
41 python-openid: 2.2.542 python-openid: 2.2.5
42 pytz: 2013b43 pytz: 2013b
44 PyYAML: 3.10.0
43 redis: 2.7.645 redis: 2.7.6
44 requests: 1.2.346 requests: 1.2.3
45 requests-oauthlib: 0.3.247 requests-oauthlib: 0.3.2
46 simplejson: 3.3.048 simplejson: 3.3.0
47 six: 1.3.049 six: 1.3.0
50 South: 0.8.1
48 supervisor: 3.0b251 supervisor: 3.0b2
49 testresources: 0.2.752 testresources: 0.2.7
50 tornado: 3.153 tornado: 3.1
51 wadllib: 1.3.254 wadllib: 1.3.2
55 watchdog: 0.6.0
52 wsgi-intercept: 0.5.156 wsgi-intercept: 0.5.1
53 wsgiref: 0.1.257 wsgiref: 0.1.2
54 zope.interface: 4.0.558 zope.interface: 4.0.5
5559
=== removed file 'config/supervisord.conf'
--- config/supervisord.conf 2013-07-13 17:01:27 +0000
+++ config/supervisord.conf 1970-01-01 00:00:00 +0000
@@ -1,37 +0,0 @@
1; Sample supervisor config file.
2
3[supervisord]
4nodaemon = true
5loglevel = info
6logfile = supervisord.log
7
8
9; service configuration sections
10
11[program:gunicorn]
12command = gunicorn_django locolander/locolander/settings.py
13autostart = true
14autorestart = true
15stdout_logfile = supervisord.log
16redirect_stderr = true
17
18[program:redis]
19command = redis-server
20autostart = true
21autorestart = true
22stdout_logfile = supervisord.log
23redirect_stderr = true
24
25[program:celeryd]
26command = python locolander/manage.py celeryd
27autostart = true
28autorestart = true
29stdout_logfile = supervisord.log
30redirect_stderr = true
31
32[program:flower]
33command = python locolander/manage.py celery flower
34autostart = true
35autorestart = true
36stdout_logfile = supervisord.log
37redirect_stderr = true
380
=== modified file 'docker/Dockerfile'
--- docker/Dockerfile 2013-06-21 21:48:36 +0000
+++ docker/Dockerfile 2013-08-17 00:46:15 +0000
@@ -24,10 +24,6 @@
24# add locolander user24# add locolander user
25run adduser locolander25run adduser locolander
2626
27# install main locolander script
28add ./scripts/run_tests.sh /usr/local/bin/run_tests.sh
29run chown locolander.locolander /usr/local/bin/run_tests.sh
30
31# configure ssh27# configure ssh
32run mkdir /home/locolander/.ssh28run mkdir /home/locolander/.ssh
33add ./files/ssh/id_rsa /home/locolander/.ssh/id_rsa29add ./files/ssh/id_rsa /home/locolander/.ssh/id_rsa
@@ -40,3 +36,8 @@
4036
41# ensure proper ownership37# ensure proper ownership
42run chown -R locolander.locolander /home/locolander/38run chown -R locolander.locolander /home/locolander/
39
40# install main locolander script
41add ./scripts/locolander /usr/local/bin/locolander
42run chown locolander.locolander /usr/local/bin/locolander
43
4344
=== modified file 'docker/scripts/locolander'
--- docker/scripts/locolander 2013-07-27 00:04:40 +0000
+++ docker/scripts/locolander 2013-08-17 00:46:15 +0000
@@ -56,8 +56,8 @@
56OUTPUT=$(python ns2df.py $PROJECT .locolander.yml Dockerfile 2>&1)56OUTPUT=$(python ns2df.py $PROJECT .locolander.yml Dockerfile 2>&1)
57OUTPUT=$(docker build -t $PROJECT . 2>&1)57OUTPUT=$(docker build -t $PROJECT . 2>&1)
58if [ -z $? -o "`echo $OUTPUT | grep 'Error'`" != "" ]; then58if [ -z $? -o "`echo $OUTPUT | grep 'Error'`" != "" ]; then
59 echo "FAILURE - Build failed:"
60 echo $OUTPUT59 echo $OUTPUT
60 echo "FAILURE - Build failed"
61 exit 161 exit 1
62fi62fi
6363
@@ -67,9 +67,8 @@
6767
68# 4. run test script using image68# 4. run test script using image
69echo "Running tests ..."69echo "Running tests ..."
70docker run $PROJECT70docker run $PROJECT 2>&1
7171if [ -z $? ]; then
72if [ -z $? -o "`echo $OUTPUT | grep 'Error'`" != "" ]; then
73 echo "FAILURE - Tests failed"72 echo "FAILURE - Tests failed"
74 exit 173 exit 1
75fi74fi
@@ -87,7 +86,7 @@
87echo "Pushing merge ..."86echo "Pushing merge ..."
88OUTPUT=$(bzr push $TARGET 2>&1)87OUTPUT=$(bzr push $TARGET 2>&1)
8988
90echo "SUCCESS"
91
92# cleanup89# cleanup
93rm -rf $TMPFOLDER90rm -rf $TMPFOLDER
91
92echo "SUCCESS"
9493
=== modified file 'fabfile.py'
--- fabfile.py 2013-07-17 13:33:49 +0000
+++ fabfile.py 2013-08-17 00:46:15 +0000
@@ -23,30 +23,16 @@
2323
2424
25@virtualenv25@virtualenv
26def run():
27 manage('supervisor')
28
29
30@virtualenv
26def test():31def test():
27 local('./run_tests.sh')32 local('./run_tests.sh')
2833
2934
30@virtualenv35@virtualenv
31def start_redis():36def docker_build():
32 local('redis-server')37 local('python ns2df.py locolander .locolander.yml Dockerfile')
3338 local('docker build -t locolander .')
34
35@virtualenv
36def start_gunicorn():
37 local('gunicorn_django locolander/locolander/settings.py')
38
39
40@virtualenv
41def start_celery():
42 manage('celeryd')
43
44
45@virtualenv
46def start_flower():
47 manage('celery flower')
48
49
50@virtualenv
51def start_supervisor():
52 local('supervisord -c config/supervisord.conf -n')
5339
=== modified file 'locolander/locolander/settings.py'
--- locolander/locolander/settings.py 2013-07-21 03:05:23 +0000
+++ locolander/locolander/settings.py 2013-08-17 00:46:15 +0000
@@ -16,7 +16,7 @@
16DATABASES = {16DATABASES = {
17 'default': {17 'default': {
18 'ENGINE': 'django.db.backends.sqlite3',18 'ENGINE': 'django.db.backends.sqlite3',
19 'NAME': 'locolander.db',19 'NAME': os.path.abspath(os.path.join(os.curdir, 'locolander.db')),
20 # The following settings are not used with sqlite3:20 # The following settings are not used with sqlite3:
21 'USER': '',21 'USER': '',
22 'PASSWORD': '',22 'PASSWORD': '',
@@ -126,9 +126,10 @@
126 'django.contrib.messages',126 'django.contrib.messages',
127 'django.contrib.staticfiles',127 'django.contrib.staticfiles',
128 'django.contrib.admin',128 'django.contrib.admin',
129 'djcelery',
130 'locolanderweb',129 'locolanderweb',
131 'south',130 'south',
131 'djcelery',
132 'djsupervisor',
132 'allauth',133 'allauth',
133 'allauth.account',134 'allauth.account',
134 'allauth.socialaccount',135 'allauth.socialaccount',
135136
=== modified file 'locolander/locolanderweb/models.py'
--- locolander/locolanderweb/models.py 2013-07-13 18:44:18 +0000
+++ locolander/locolanderweb/models.py 2013-08-17 00:46:15 +0000
@@ -33,6 +33,9 @@
33 name = models.TextField()33 name = models.TextField()
34 url = models.CharField(max_length=256, validators=[service_url_validator])34 url = models.CharField(max_length=256, validators=[service_url_validator])
3535
36 def __repr__(self):
37 return u"<Project: %s>" % self.name
38
36 @property39 @property
37 def service(self):40 def service(self):
38 return get_service_from_url(self.url)41 return get_service_from_url(self.url)
@@ -56,6 +59,9 @@
56 date_created = models.DateTimeField()59 date_created = models.DateTimeField()
57 date_completed = models.DateTimeField(null=True, blank=True)60 date_completed = models.DateTimeField(null=True, blank=True)
5861
62 def __repr__(self):
63 return u"<MergeRequest: %s -> %s>" % (self.source, self.target)
64
59 def complete(self, error=False):65 def complete(self, error=False):
60 self.date_completed = datetime.utcnow()66 self.date_completed = datetime.utcnow()
61 self.status = STATUS_MERGED if not error else STATUS_ERROR67 self.status = STATUS_MERGED if not error else STATUS_ERROR
@@ -71,3 +77,6 @@
7177
72 class Meta:78 class Meta:
73 get_latest_by = 'timestamp'79 get_latest_by = 'timestamp'
80
81 def __repr__(self):
82 return u"<RunLog: %r at %s>" % (self.merge_request, self.timestamp)
7483
=== modified file 'locolander/locolanderweb/tasks.py'
--- locolander/locolanderweb/tasks.py 2013-08-03 17:06:41 +0000
+++ locolander/locolanderweb/tasks.py 2013-08-17 00:46:15 +0000
@@ -1,7 +1,7 @@
1import os1import os
2import subprocess
3from datetime import datetime2from datetime import datetime
43
4import envoy
5from celery import task5from celery import task
66
7from locolanderweb.models import MergeRequest, RunLog7from locolanderweb.models import MergeRequest, RunLog
@@ -21,23 +21,16 @@
21 author = request.author21 author = request.author
22 message = request.commit_message22 message = request.commit_message
2323
24 cmd = [24 cmd = '{script} {project} {source} {target} "{message}" "{author}"'.format(
25 os.path.realpath(os.path.join(25 script=os.path.join(os.path.abspath(os.curdir),
26 os.path.abspath('.'), 'docker/scripts/locolander')),26 'docker', 'scripts', 'locolander'),
27 project.name,27 project=project.name, source=source, target=target, message=message,
28 source,28 author=author)
29 target,29
30 message,30 r = envoy.run(cmd)
31 author,31 output = r.std_out
32 ]32 return_code = r.status_code
33 try:33 error = return_code != 0
34 output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
35 return_code = 0
36 error = False
37 except subprocess.CalledProcessError as err:
38 output = err.output
39 return_code = err.returncode
40 error = True
4134
42 RunLog.objects.create(merge_request=request, raw=output,35 RunLog.objects.create(merge_request=request, raw=output,
43 return_code=return_code)36 return_code=return_code)
4437
=== modified file 'locolander/locolanderweb/tests/test_models.py'
--- locolander/locolanderweb/tests/test_models.py 2013-07-20 21:10:37 +0000
+++ locolander/locolanderweb/tests/test_models.py 2013-08-17 00:46:15 +0000
@@ -96,6 +96,10 @@
96 result = self.obj.approved_requests()96 result = self.obj.approved_requests()
97 self.assertEqual(len(result), 1)97 self.assertEqual(len(result), 1)
9898
99 def test_repr(self):
100 expected = u'<Project: foo>'
101 self.assertEqual(repr(self.obj), expected)
102
99103
100class MergeRequestTestCase(BaseTestCase):104class MergeRequestTestCase(BaseTestCase):
101105
@@ -156,14 +160,20 @@
156 self.assertEqual(self.obj.status, STATUS_ERROR)160 self.assertEqual(self.obj.status, STATUS_ERROR)
157 self.assertEqual(self.obj.date_completed, completed)161 self.assertEqual(self.obj.date_completed, completed)
158162
163 def test_repr(self):
164 expected = u'<MergeRequest: source -> target>'
165 self.assertEqual(repr(self.obj), expected)
166
159167
160class RunLogTestCase(BaseTestCase):168class RunLogTestCase(BaseTestCase):
161169
162 def setUp(self):170 def setUp(self):
163 super(RunLogTestCase, self).setUp()171 super(RunLogTestCase, self).setUp()
164 self.merge_request = self.factory.make_merge_request()172 self.merge_request = self.factory.make_merge_request()
173 self.timestamp = datetime.utcnow()
165 self.obj = RunLog.objects.create(174 self.obj = RunLog.objects.create(
166 merge_request=self.merge_request, return_code=0)175 merge_request=self.merge_request, return_code=0,
176 timestamp=self.timestamp)
167177
168 def test_merge_request(self):178 def test_merge_request(self):
169 self.assertEqual(self.obj.merge_request, self.merge_request)179 self.assertEqual(self.obj.merge_request, self.merge_request)
@@ -187,3 +197,7 @@
187 merge_request=self.merge_request, return_code=0,197 merge_request=self.merge_request, return_code=0,
188 timestamp=self.obj.timestamp + timedelta(seconds=1))198 timestamp=self.obj.timestamp + timedelta(seconds=1))
189 self.assertEqual(RunLog.objects.latest(), other)199 self.assertEqual(RunLog.objects.latest(), other)
200
201 def test_repr(self):
202 expected = u"<RunLog: %r at %s>" % (self.merge_request, self.timestamp)
203 self.assertEqual(repr(self.obj), expected)
190204
=== modified file 'locolander/locolanderweb/tests/test_tasks.py'
--- locolander/locolanderweb/tests/test_tasks.py 2013-07-20 21:07:18 +0000
+++ locolander/locolanderweb/tests/test_tasks.py 2013-08-17 00:46:15 +0000
@@ -1,7 +1,7 @@
1import subprocess1import os
2from datetime import datetime2from datetime import datetime
33
4from mock import ANY, patch4from mock import patch
55
6from locolanderweb.models import (6from locolanderweb.models import (
7 STATUS_ERROR,7 STATUS_ERROR,
@@ -55,29 +55,28 @@
5555
56 def setUp(self):56 def setUp(self):
57 super(RunRequestTestCase, self).setUp()57 super(RunRequestTestCase, self).setUp()
58 patcher = patch('locolanderweb.tasks.subprocess.check_output')58 patcher = patch('locolanderweb.tasks.envoy.run')
59 self.mock_check_output = patcher.start()59 self.mock_run = patcher.start()
60 self.addCleanup(patcher.stop)60 self.addCleanup(patcher.stop)
6161
62 def test_run_request(self):62 def test_run_request(self):
63 self.mock_check_output.return_value = 'SUCCESS'63 self.mock_run.return_value.std_out = 'SUCCESS'
64 self.mock_run.return_value.status_code = 0
6465
65 merge_request = self.factory.make_merge_request()66 merge_request = self.factory.make_merge_request()
6667
67 run_request(merge_request)68 run_request(merge_request)
6869
69 cmd = [70 cmd = ('{script} {project} {source} {target} '
70 ANY,71 '"{message}" "{author}"').format(
71 merge_request.project.name,72 script=os.path.abspath('./docker/scripts/locolander'),
72 merge_request.source,73 project=merge_request.project.name,
73 merge_request.target,74 source=merge_request.source,
74 merge_request.commit_message,75 target=merge_request.target,
75 merge_request.author,76 message=merge_request.commit_message,
76 ]77 author=merge_request.author
77 self.mock_check_output.assert_called_once_with(78 )
78 cmd, stderr=subprocess.STDOUT)79 self.mock_run.assert_called_once_with(cmd)
79 real_cmd = self.mock_check_output.call_args[0][0][0]
80 self.assertTrue(real_cmd.endswith('docker/scripts/locolander'))
8180
82 self.assertEqual(RunLog.objects.all().count(), 1)81 self.assertEqual(RunLog.objects.all().count(), 1)
83 run_log = RunLog.objects.get(merge_request=merge_request)82 run_log = RunLog.objects.get(merge_request=merge_request)
@@ -91,23 +90,21 @@
91 def test_run_request_with_error(self):90 def test_run_request_with_error(self):
92 merge_request = self.factory.make_merge_request()91 merge_request = self.factory.make_merge_request()
9392
94 cmd = [93 cmd = ('{script} {project} {source} {target} '
95 ANY,94 '"{message}" "{author}"').format(
96 merge_request.project.name,95 script=os.path.abspath('./docker/scripts/locolander'),
97 merge_request.source,96 project=merge_request.project.name,
98 merge_request.target,97 source=merge_request.source,
99 merge_request.commit_message,98 target=merge_request.target,
100 merge_request.author,99 message=merge_request.commit_message,
101 ]100 author=merge_request.author
102 error = subprocess.CalledProcessError(1, cmd, output='FAILURE')101 )
103 self.mock_check_output.side_effect = error102 self.mock_run.return_value.std_out = 'FAILURE'
103 self.mock_run.return_value.status_code = 1
104104
105 run_request(merge_request)105 run_request(merge_request)
106106
107 self.mock_check_output.assert_called_once_with(107 self.mock_run.assert_called_once_with(cmd)
108 cmd, stderr=subprocess.STDOUT)
109 real_cmd = self.mock_check_output.call_args[0][0][0]
110 self.assertTrue(real_cmd.endswith('docker/scripts/locolander'))
111108
112 self.assertEqual(RunLog.objects.all().count(), 1)109 self.assertEqual(RunLog.objects.all().count(), 1)
113 run_log = RunLog.objects.get(merge_request=merge_request)110 run_log = RunLog.objects.get(merge_request=merge_request)
114111
=== added file 'locolander/supervisord.conf'
--- locolander/supervisord.conf 1970-01-01 00:00:00 +0000
+++ locolander/supervisord.conf 2013-08-17 00:46:15 +0000
@@ -0,0 +1,38 @@
1[program:gunicorn]
2command = gunicorn -b 0.0.0.0:8000 locolander.wsgi:application
3directory = {{ PROJECT_DIR }}
4autostart = true
5autorestart = true
6stdout_logfile = supervisord.log
7redirect_stderr = true
8
9[program:redis]
10command = redis-server
11autostart = true
12autorestart = true
13stdout_logfile = supervisord.log
14redirect_stderr = true
15
16[program:docker]
17command = /usr/bin/docker
18autostart = false
19autorestart = true
20stdout_logfile = supervisord.log
21redirect_stderr = true
22
23[program:celeryd]
24command = {{ PYTHON }} {{ PROJECT_DIR }}/manage.py celeryd
25autostart = true
26autorestart = true
27stdout_logfile = supervisord.log
28redirect_stderr = true
29
30[program:flower]
31command = {{ PYTHON }} {{ PROJECT_DIR }}/manage.py celery flower
32autostart = true
33autorestart = true
34stdout_logfile = supervisord.log
35redirect_stderr = true
36
37[program:autoreload]
38exclude = true
039
=== modified file 'requirements.txt'
--- requirements.txt 2013-07-20 23:52:03 +0000
+++ requirements.txt 2013-08-17 00:46:15 +0000
@@ -1,16 +1,17 @@
1Django==1.5.1
2PyYAML==3.10
3South==0.8.1
4amqp==1.0.121amqp==1.0.12
5anyjson==0.3.32anyjson==0.3.3
3argh==0.23.2
6argparse==1.2.14argparse==1.2.1
7billiard==2.7.3.315billiard==2.7.3.31
8bzr==2.6b26bzr==2.6b2
9celery==3.0.217celery==3.0.21
10cssselect==0.88cssselect==0.8
11distribute==0.6.349distribute==0.6.34
10Django==1.5.1
12django-allauth==0.12.011django-allauth==0.12.0
13django-celery==3.0.1712django-celery==3.0.17
13django-supervisor==0.3.1
14envoy==0.0.2
14flower==0.5.215flower==0.5.2
15github3.py==0.7.016github3.py==0.7.0
16gunicorn==17.517gunicorn==17.5
@@ -26,6 +27,7 @@
26mock==1.0.127mock==1.0.1
27oauth==1.0.128oauth==1.0.1
28oauthlib==0.5.029oauthlib==0.5.0
30pathtools==0.1.2
29pep8==1.4.631pep8==1.4.6
30psycopg2==2.5.132psycopg2==2.5.1
31pyflakes==0.7.333pyflakes==0.7.3
@@ -33,15 +35,18 @@
33python-dateutil==2.135python-dateutil==2.1
34python-openid==2.2.536python-openid==2.2.5
35pytz==2013b37pytz==2013b
38PyYAML==3.10
36redis==2.7.639redis==2.7.6
37requests==1.2.340requests==1.2.3
38requests-oauthlib==0.3.241requests-oauthlib==0.3.2
39simplejson==3.3.042simplejson==3.3.0
40six==1.3.043six==1.3.0
44South==0.8.1
41supervisor==3.0b245supervisor==3.0b2
42testresources==0.2.746testresources==0.2.7
43tornado==3.147tornado==3.1
44wadllib==1.3.248wadllib==1.3.2
49watchdog==0.6.0
45wsgi-intercept==0.5.150wsgi-intercept==0.5.1
46wsgiref==0.1.251wsgiref==0.1.2
47zope.interface==4.0.552zope.interface==4.0.5

Subscribers

People subscribed via source and target branches

to all changes: