Merge lp:~cprov/charms/trusty/adt-cloud-service/gunicorn-app into lp:~canonical-ci-engineering/charms/trusty/adt-cloud-service/trunk

Proposed by Celso Providelo
Status: Merged
Approved by: Celso Providelo
Approved revision: 8
Merged at revision: 2
Proposed branch: lp:~cprov/charms/trusty/adt-cloud-service/gunicorn-app
Merge into: lp:~canonical-ci-engineering/charms/trusty/adt-cloud-service/trunk
Diff against target: 272 lines (+83/-59)
8 files modified
README (+3/-2)
adt.conf (+0/-17)
config.yaml (+3/-4)
hooks/actions.py (+63/-11)
hooks/services.py (+5/-2)
hooks/wsgi-relation-joined (+3/-0)
metadata.yaml (+6/-2)
templates/upstart.conf (+0/-21)
To merge this branch: bzr merge lp:~cprov/charms/trusty/adt-cloud-service/gunicorn-app
Reviewer Review Type Date Requested Status
Joe Talbott (community) Approve
Review via email: mp+252855@code.launchpad.net

Commit message

Restoring upstart template capabilities and running web_app with gunicorn from the venv (py3 support).

Description of the change

Restoring upstart template capabilities and running web_app with gunicorn from the venv (py3 support).

Also providing website relation for HA | Apache

To post a comment you must log in.
Revision history for this message
Joe Talbott (joetalbott) wrote :

LGTM, Thanks for doing this.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'README'
2--- README 2015-03-10 20:17:05 +0000
3+++ README 2015-03-13 03:40:39 +0000
4@@ -7,7 +7,8 @@
5 -------------
6
7 There are only two config options for this charm:
8- * branch: The bzr branch to pull for adt-cloud-service (default:
9- lp:adt-cloud-service)
10 * config-file: A base64 encoded string with the config file to use for
11 adt-cloud-service.
12+
13+NOTE: This expects the payload code in the form of adt-cloud-service.tgz
14+to exist with the snapshot of lp:adt-cloud-service that needs deploying
15
16=== removed file 'adt.conf'
17--- adt.conf 2015-03-10 20:17:05 +0000
18+++ adt.conf 1970-01-01 00:00:00 +0000
19@@ -1,17 +0,0 @@
20-# `adt-cloud-worker` configuration file.
21-[adt]
22-name = foo
23-# <arch>.<platform>[ ...]
24-tags = i386.nova amd64.nova
25-
26-[amqp]
27-uris = amqp://guest:guest@localhost:5672//
28-
29-[nova]
30-# Matching OS_ env_vars.
31-os_username = foo
32-os_tenant_name = foo_project
33-os_password = <redacted>
34-os_auth_url = http://172.20.161.138:5000/v2.0/
35-os_region_name = bot-prototype
36-extra_args = --net-id=415a0839-eb05-4e7a-907c-413c657f4bf5
37
38=== modified file 'config.yaml'
39--- config.yaml 2015-03-10 20:17:05 +0000
40+++ config.yaml 2015-03-13 03:40:39 +0000
41@@ -1,6 +1,5 @@
42 options:
43- branch:
44+ config-file:
45 type: string
46- default: "lp:adt-cloud-service"
47- description: "Branch to use for adt-cloud-service"
48-
49+ description: |
50+ base64 encoded string with the config file for adt-cloud-worker
51
52=== added directory 'files'
53=== modified file 'hooks/actions.py'
54--- hooks/actions.py 2015-03-10 20:17:05 +0000
55+++ hooks/actions.py 2015-03-13 03:40:39 +0000
56@@ -1,38 +1,90 @@
57 import base64
58 import os
59-import shutil
60 import subprocess
61
62 from charmhelpers import fetch
63-from charmhelpers.core import hookenv
64+from charmhelpers.core import (
65+ hookenv,
66+ host,
67+)
68+from charmhelpers.core.services import helpers
69+from charmhelpers.payload.archive import extract_tarfile
70
71
72 REQUIRED_PACKAGES = [
73- 'bzr',
74- # py2 dependencies as a temporary hack-to-production.
75- 'python-kombu',
76- 'python-configparser',
77- 'python-swiftclient',
78+ 'python-virtualenv', 'python3-dev',
79 ]
80 SERVICE_DIR = '/srv/adt-cloud-service'
81+LOG_DIR = os.path.join(SERVICE_DIR, 'logs')
82+WSGI_USER = 'www-data'
83+WSGI_GROUP = 'www-data'
84
85 config = hookenv.config()
86
87+
88 def log_start(service_name):
89 hookenv.log('adt-cloud-service starting')
90
91+
92 def install_packages(service_name):
93 hookenv.log('Installing dependencies...')
94+ fetch.add_source('ppa:canonical-ci-engineering/ci-airline-phase-0')
95 fetch.configure_sources(update=True)
96 fetch.apt_install(REQUIRED_PACKAGES, fatal=True)
97
98-def get_cloud_service_branch(service_name):
99- branch = config['branch']
100- shutil.rmtree(SERVICE_DIR, ignore_errors=True)
101- subprocess.call(['bzr', 'branch', branch, SERVICE_DIR])
102+
103+def get_cloud_service_from_tarball(service_name):
104+ files_dir = os.path.join(hookenv.charm_dir(), 'files')
105+ tarball = os.path.join(files_dir, 'adt-cloud-service.tgz')
106+ if not os.path.exists(SERVICE_DIR):
107+ hookenv.log('Installing the code for the first time from tarball')
108+ extract_tarfile(tarball, '/srv/')
109+
110
111 def get_config_file(service_name):
112 config_file = config.get('config-file')
113 if config_file is not None:
114 with open(os.path.join(SERVICE_DIR, '.adt-service.conf'), 'w') as f:
115 f.write(base64.b64decode(config_file))
116+
117+
118+def install_python_packages(service_name):
119+ env_dir = os.path.join(SERVICE_DIR, 've')
120+ if os.path.exists(env_dir):
121+ hookenv.log('Service venv already exists, nothing to do ...')
122+ return
123+
124+ hookenv.log('Installing python packages into the venv ...')
125+ subprocess.check_call(['virtualenv', '-p', 'python3', env_dir])
126+
127+ pip_cache = os.path.join(hookenv.charm_dir(), 'files', 'pip-cache')
128+ requirements = os.path.join(SERVICE_DIR, 'requirements.txt')
129+
130+ hookenv.log('Installing from download cache.')
131+ subprocess.check_call(['%s/bin/pip' % env_dir,
132+ 'install',
133+ '--no-index',
134+ '--find-links={}'.format(pip_cache),
135+ '-r', requirements])
136+
137+ subprocess.check_call(['%s/bin/pip' % env_dir,
138+ 'install', '--no-deps', '-e', SERVICE_DIR])
139+
140+def prepare_for_wsgi(service_name):
141+ host.adduser(WSGI_USER)
142+ host.add_group(WSGI_GROUP)
143+ host.add_user_to_group(WSGI_USER, WSGI_GROUP)
144+ if not os.path.exists(LOG_DIR):
145+ host.mkdir(LOG_DIR, WSGI_USER, WSGI_GROUP, perms=0755)
146+
147+
148+class WebsiteRelation(helpers.RelationContext):
149+ name = 'website'
150+ interface = 'http'
151+
152+ def provide_data(self):
153+ data = {
154+ 'hostname': hookenv.unit_private_ip(),
155+ 'port': 8000,
156+ }
157+ return data
158
159=== modified file 'hooks/services.py'
160--- hooks/services.py 2015-03-10 20:17:05 +0000
161+++ hooks/services.py 2015-03-13 03:40:39 +0000
162@@ -1,8 +1,8 @@
163 #!/usr/bin/python
164
165 from charmhelpers.core import hookenv
166+from charmhelpers.core.services import helpers
167 from charmhelpers.core.services.base import ServiceManager
168-from charmhelpers.core.services import helpers
169
170 import actions
171
172@@ -12,11 +12,14 @@
173 manager = ServiceManager([
174 {
175 'service': 'adt-cloud-service',
176+ 'provided_data': [actions.WebsiteRelation()],
177 'required_data': [config],
178 'data_ready': [
179 actions.install_packages,
180- actions.get_cloud_service_branch,
181+ actions.get_cloud_service_from_tarball,
182+ actions.install_python_packages,
183 actions.get_config_file,
184+ actions.prepare_for_wsgi,
185 helpers.render_template(
186 source='upstart.conf',
187 target='/etc/init/adt-cloud-service.conf'),
188
189=== added file 'hooks/wsgi-relation-joined'
190--- hooks/wsgi-relation-joined 1970-01-01 00:00:00 +0000
191+++ hooks/wsgi-relation-joined 2015-03-13 03:40:39 +0000
192@@ -0,0 +1,3 @@
193+#!/usr/bin/python
194+import services
195+services.manage()
196
197=== modified file 'metadata.yaml'
198--- metadata.yaml 2015-03-10 20:17:05 +0000
199+++ metadata.yaml 2015-03-13 03:40:39 +0000
200@@ -1,5 +1,9 @@
201 name: adt-cloud-service
202-summary: Deploy a service to handle adt jobs dispatched to a rabbit queue
203+summary: Deploys a web_app to handle adt jobs dispatched to a rabbit queue
204 maintainer: Canonical CI Engineering <canonical-ci-engineering@lists.launchpad.net>
205 description: |
206- Runs adt-cloud-service from a specified bzr branch
207+ Runs adt-cloud-service using gunicorn from given code tarball
208+provides:
209+ website:
210+ interface: http
211+ optional: true
212
213=== added directory 'templates'
214=== removed directory 'templates'
215=== added file 'templates/upstart.conf'
216--- templates/upstart.conf 1970-01-01 00:00:00 +0000
217+++ templates/upstart.conf 2015-03-13 03:40:39 +0000
218@@ -0,0 +1,28 @@
219+description "Starts the adt-cloud-service with gunicorn"
220+
221+start on (local-filesystems and net-device-up IFACE=eth0)
222+stop on runlevel [!12345]
223+
224+# use sigint so python code just needs to catch KeyboardInterrupt
225+kill signal SIGINT
226+
227+# If the process quits unexpectedly trigger respawn it
228+respawn
229+# unless it fails 15 times within 5 seconds
230+respawn limit 15 5
231+
232+env SERVICE_DIR=/srv/adt-cloud-service
233+
234+script
235+
236+ chdir ${SERVICE_DIR}
237+
238+ exec sudo -u www-data ./ve/bin/gunicorn \
239+ --name=adt-cloud-service \
240+ --bind=0.0.0.0 \
241+ --log-file=${SERVICE_DIR}/logs/gunicorn.log \
242+ --log-level=INFO \
243+ --access-logfile=${SERVICE_DIR}/logs/access.log \
244+ adt_cloud_service:app
245+
246+end script
247
248=== removed file 'templates/upstart.conf'
249--- templates/upstart.conf 2015-03-10 20:17:05 +0000
250+++ templates/upstart.conf 1970-01-01 00:00:00 +0000
251@@ -1,21 +0,0 @@
252-description "Starts a adt-cloud-worker process"
253-
254-start on (local-filesystems and net-device-up IFACE=eth0)
255-stop on runlevel [!12345]
256-
257-# use sigint so python code just needs to catch KeyboardInterrupt
258-kill signal SIGINT
259-
260-# If the process quits unexpectedly trigger respawn it
261-respawn
262-# unless it fails 15 times within 5 seconds
263-respawn limit 15 5
264-
265-env SERVICE_DIR=/srv/adt-cloud-worker
266-
267-script
268- mkdir -p ${SERVICE_DIR}/logs
269- # XXX cprov: respect py3 project choice once we have proper dependencies
270- # available.
271- exec python ${SERVICE_DIR}/adt-cloud-worker.py -c ${SERVICE_DIR}/.adt-service.conf >> ${SERVICE_DIR}/logs/adt-cloud-worker.log 2>&1
272-end script

Subscribers

People subscribed via source and target branches