Merge lp:~ricardokirkner/isitdeployable/docker into lp:isitdeployable
- docker
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Ricardo Kirkner |
Approved revision: | 225 |
Merge reported by: | Otto Co-Pilot |
Merged at revision: | not available |
Proposed branch: | lp:~ricardokirkner/isitdeployable/docker |
Merge into: | lp:isitdeployable |
Diff against target: |
1016 lines (+609/-176) 19 files modified
.bzrignore (+1/-1) .dockerignore (+2/-0) Dockerfile (+26/-0) Dockerfile.test (+4/-0) Makefile (+24/-21) Makefile.docker (+62/-0) README.docker (+35/-0) branches/wait-for-it/LICENSE (+20/-0) branches/wait-for-it/README.md (+69/-0) branches/wait-for-it/wait-for-it.sh (+161/-0) django_project/settings_base.py (+98/-149) django_project/settings_build.py (+12/-0) django_project/settings_devel.py (+17/-5) docker-compose.dev.yml (+24/-0) docker-compose.secrets.yml (+5/-0) docker-compose.test.yml (+9/-0) docker-compose.yml (+19/-0) requirements-docker.txt (+19/-0) requirements.txt (+2/-0) |
To merge this branch: | bzr merge lp:~ricardokirkner/isitdeployable/docker |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Guillermo Gonzalez | Approve | ||
Review via email: mp+327809@code.launchpad.net |
Commit message
added tooling to build and run application using docker
Description of the change
Otto Co-Pilot (otto-copilot) wrote : | # |
Project setup failed
https:/
Otto Co-Pilot (otto-copilot) wrote : | # |
Project setup failed
https:/
Otto Co-Pilot (otto-copilot) wrote : | # |
Project setup failed
https:/
Otto Co-Pilot (otto-copilot) wrote : | # |
Project setup failed
https:/
Otto Co-Pilot (otto-copilot) wrote : | # |
Project setup failed
https:/
Otto Co-Pilot (otto-copilot) wrote : | # |
Project setup failed
https:/
Otto Co-Pilot (otto-copilot) wrote : | # |
Project setup failed
https:/
- 225. By Ricardo Kirkner
-
do not override default $(ENV) target in docker Makefile
Preview Diff
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2016-07-14 21:54:18 +0000 |
3 | +++ .bzrignore 2017-08-01 11:41:20 +0000 |
4 | @@ -15,7 +15,7 @@ |
5 | ./tmp/supervisor-childlogs/* |
6 | ./.sass-cache |
7 | ./revtracker/static/css/* |
8 | -./virtualenv |
9 | +./env |
10 | ./lib/versioninfo.py |
11 | ./static |
12 | ./logs/* |
13 | |
14 | === added file '.dockerignore' |
15 | --- .dockerignore 1970-01-01 00:00:00 +0000 |
16 | +++ .dockerignore 2017-08-01 11:41:20 +0000 |
17 | @@ -0,0 +1,2 @@ |
18 | +.bzr |
19 | +env |
20 | |
21 | === added file 'Dockerfile' |
22 | --- Dockerfile 1970-01-01 00:00:00 +0000 |
23 | +++ Dockerfile 2017-08-01 11:41:20 +0000 |
24 | @@ -0,0 +1,26 @@ |
25 | +FROM ubuntu:trusty |
26 | + |
27 | +RUN mkdir -p /usr/src/app |
28 | +WORKDIR /usr/src/app |
29 | + |
30 | +# install system dependencies (debs) |
31 | +COPY dependencies.txt dependencies-devel.txt /usr/src/app/ |
32 | +RUN apt-get update && apt-get upgrade -y \ |
33 | + && apt-get install -y software-properties-common \ |
34 | + && apt-add-repository --yes ppa:mojo-maintainers \ |
35 | + && apt-add-repository --yes ppa:ubuntuone/isitdeployable-dependencies \ |
36 | + && apt-get update \ |
37 | + && cat dependencies.txt dependencies-devel.txt | xargs apt-get install -y --no-install-recommends \ |
38 | + && apt-get install -y python-pip \ |
39 | + && rm -rf /var/lib/apt/lists/* |
40 | + |
41 | +# install python dependencies (wheels) |
42 | +COPY branches/wheels branches/wheels |
43 | +COPY requirements.txt /usr/src/app |
44 | +RUN pip install --find-links=branches/wheels --no-index -r requirements.txt |
45 | + |
46 | +# add app source code |
47 | +COPY . /usr/src/app |
48 | + |
49 | +# start container |
50 | +CMD ["make", "app-start"] |
51 | |
52 | === added file 'Dockerfile.test' |
53 | --- Dockerfile.test 1970-01-01 00:00:00 +0000 |
54 | +++ Dockerfile.test 2017-08-01 11:41:20 +0000 |
55 | @@ -0,0 +1,4 @@ |
56 | +FROM deployable:dev |
57 | + |
58 | +COPY requirements-devel.txt /usr/src/app |
59 | +RUN pip install --find-links=branches/wheels --no-index -r requirements-devel.txt |
60 | |
61 | === modified file 'Makefile' |
62 | --- Makefile 2016-07-27 14:51:28 +0000 |
63 | +++ Makefile 2017-08-01 11:41:20 +0000 |
64 | @@ -17,28 +17,20 @@ |
65 | LOCAL_SETTINGS_DIR ?= ../local_config |
66 | LOCAL_SETTINGS_PATH = $(LOCAL_SETTINGS_DIR)/settings.py |
67 | |
68 | -HERE := $(shell pwd) |
69 | -VIRTUALENV_DIR ?= ${HERE}/virtualenv |
70 | -VIRTUALENV_BIN := ${VIRTUALENV_DIR}/bin |
71 | +ENV = $(CURDIR)/env |
72 | PYTHONPATH := ${HERE}/revtracker:${HERE}/lib:${HERE}:${PYTHONPATH} |
73 | |
74 | CM ?= /usr/lib/config-manager/cm.py |
75 | CONFIGMANAGER = config-manager.txt |
76 | -PYTHON = $(VIRTUALENV_DIR)/bin/python |
77 | -# use env's python to run pip in order to overcome shebang's max line length limitation |
78 | -PIP = $(PYTHON) $(VIRTUALENV_DIR)/bin/pip |
79 | +GUNICORN ?= $(ENV)/bin/gunicorn |
80 | +PYTHON ?= $(ENV)/bin/python |
81 | +PIP ?= $(ENV)/bin/pip |
82 | |
83 | # Several targets assume (wrongly) that $(ENV) already exists. As a stop-gap |
84 | # we ifdef them with ENV_CREATED to avoid spurious |
85 | # '/bin/sh: 1: /.../env/bin/python: not found' errors |
86 | ENV_CREATED = $(shell test -e $(PYTHON) && echo "yes" || echo "no") |
87 | |
88 | -include makefiles/css.mk |
89 | -include makefiles/gem.mk |
90 | -include makefiles/js.mk |
91 | -ifeq (yes,$(ENV_CREATED)) |
92 | -include Makefile.db |
93 | -endif |
94 | WHEELS_BRANCH_URL ?= lp:isitdeployable-dependencies |
95 | WHEELS_DIR = branches/wheels |
96 | |
97 | @@ -78,13 +70,13 @@ |
98 | cp django_project/settings.py.example $(LOCAL_SETTINGS_PATH) |
99 | |
100 | |
101 | -$(VIRTUALENV_DIR): |
102 | +$(ENV): |
103 | echo 'creating new virtualenv...' |
104 | - virtualenv --clear --system-site-packages $(VIRTUALENV_DIR) |
105 | + virtualenv --clear --system-site-packages $(ENV) |
106 | |
107 | clean-virtualenv: |
108 | echo 'cleaning virtualenv...' |
109 | - rm -rf $(VIRTUALENV_DIR) |
110 | + rm -rf $(ENV) |
111 | |
112 | version: |
113 | bzr version-info --format=python > lib/versioninfo.py |
114 | @@ -101,7 +93,7 @@ |
115 | |
116 | sourcedeps: fetch-sourcedeps install-wheels |
117 | |
118 | -bootstrap: $(LOCAL_SETTINGS_PATH) $(VIRTUALENV_DIR) sourcedeps install-wheels-dev |
119 | +bootstrap: $(LOCAL_SETTINGS_PATH) $(ENV) sourcedeps install-wheels-dev |
120 | |
121 | |
122 | # Management |
123 | @@ -115,7 +107,7 @@ |
124 | run: ARGS=0.0.0.0:8000 |
125 | run: collectstatic |
126 | $(MAKE) manage ARGS="loaddata fixtures/group.json" |
127 | - $(VIRTUALENV_DIR)/bin/gunicorn django_project.wsgi:application --workers=2 --reload --pid=logs/gunicorn.pid --bind=$(ARGS) --timeout=99999 |
128 | + $(GUNICORN) django_project.wsgi:application --workers=2 --reload --pid=logs/gunicorn.pid --bind=$(ARGS) --timeout=99999 |
129 | |
130 | start-supervisor: logs |
131 | @echo Starting supervised processes |
132 | @@ -141,14 +133,14 @@ |
133 | [ -d $(WHEELS_DIR) ] && (cd $(WHEELS_DIR) && bzr pull) || (bzr branch $(WHEELS_BRANCH_URL) $(WHEELS_DIR)) |
134 | |
135 | update-wheels: ARGS=-r requirements-devel.txt |
136 | -update-wheels: $(VIRTUALENV_DIR) |
137 | +update-wheels: $(ENV) |
138 | $(PIP) wheel -w $(WHEELS_DIR) -f $(WHEELS_DIR) $(ARGS) |
139 | |
140 | install-wheels: ARGS=-r requirements.txt |
141 | -install-wheels: $(VIRTUALENV_DIR) |
142 | +install-wheels: $(ENV) |
143 | $(PIP) install --find-links=$(WHEELS_DIR) --no-index $(ARGS) |
144 | |
145 | -install-wheels-dev: $(VIRTUALENV_DIR) install-wheels |
146 | +install-wheels-dev: $(ENV) install-wheels |
147 | $(MAKE) install-wheels ARGS="-r requirements-devel.txt --pre" |
148 | |
149 | |
150 | @@ -162,7 +154,7 @@ |
151 | REV_DIR=$(STATIC_ROOT)/combo/rev-r$$(cat $(STATIC_ROOT)/combo/revno) |
152 | |
153 | collectstatic: js css |
154 | - DJANGO_SETTINGS_MODULE=django_project.settings_base $(DJANGO_MANAGE) collectstatic --noinput \ |
155 | + DJANGO_SETTINGS_MODULE=django_project.settings_build $(DJANGO_MANAGE) collectstatic --noinput \ |
156 | > logs/collectstatic.log 2>&1 || (cat logs/collectstatic.log && false) |
157 | cd $(STATIC_ROOT)/combo |
158 | [ -L $(REV_DIR) ] && (echo 'existing rev symbolink, removing' && rm $(REV_DIR)) \ |
159 | @@ -187,4 +179,15 @@ |
160 | conn-check $(CONN_CHECK_CONFIG_PATH) |
161 | |
162 | |
163 | +# static assets related targets |
164 | +include makefiles/css.mk |
165 | +include makefiles/gem.mk |
166 | +include makefiles/js.mk |
167 | +# database related targets |
168 | +ifeq (yes,$(ENV_CREATED)) |
169 | +include Makefile.db |
170 | +endif |
171 | +# deployment related targets |
172 | +include Makefile.docker |
173 | + |
174 | .PHONY: build-tarball install-wheels |
175 | |
176 | === added file 'Makefile.docker' |
177 | --- Makefile.docker 1970-01-01 00:00:00 +0000 |
178 | +++ Makefile.docker 2017-08-01 11:41:20 +0000 |
179 | @@ -0,0 +1,62 @@ |
180 | + |
181 | +PROJECT_NAME = django_project |
182 | + |
183 | +# define docker related variables |
184 | +DOCKER_COMPOSE_FILES ?= -f docker-compose.yml -f docker-compose.dev.yml |
185 | +DOCKER_COMPOSE ?= $(ENV)/bin/docker-compose |
186 | +TAG ?= deployable:dev |
187 | + |
188 | +# pre-process arguments |
189 | +# if the first argument is "special" (docker-compose, docker-test)... |
190 | +ifneq (,$(filter $(firstword $(MAKECMDGOALS)),docker-compose docker-test)) |
191 | +# use the rest as sub-arguments |
192 | +ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS)) |
193 | +# ...and turn them into do-nothing targets |
194 | +$(eval $(ARGS):;@:) |
195 | +endif |
196 | + |
197 | + |
198 | +docker-bootstrap: $(ENV) fetch-sourcedeps |
199 | + $(ENV)/bin/pip install --find-links=$(WHEELS_DIR) --no-index -r requirements-docker.txt |
200 | + |
201 | +docker-build: version ## Build images |
202 | + $(MAKE) docker-compose ARGS="build" |
203 | + |
204 | +docker-run: ## Run stack in foreground |
205 | + DOCKER_COMPOSE_FILES="$(DOCKER_COMPOSE_FILES) -f docker-compose.secrets.yml" $(MAKE) docker-compose ARGS="up" |
206 | + |
207 | +docker-start: ## Run stack in background |
208 | + DOCKER_COMPOSE_FILES="$(DOCKER_COMPOSE_FILES) -f docker-compose.secrets.yml" $(MAKE) docker-compose ARGS="up -d" |
209 | + |
210 | +docker-stop: ## Stop containers |
211 | + DOCKER_COMPOSE_FILES="$(DOCKER_COMPOSE_FILES) -f docker-compose.secrets.yml" $(MAKE) docker-compose ARGS="down" |
212 | + |
213 | +docker-clean: docker-stop ## Remove images |
214 | + docker rmi $(TAG) |
215 | + |
216 | +docker-compose: $(ENV) |
217 | + $(DOCKER_COMPOSE) $(DOCKER_COMPOSE_FILES) $(ARGS) |
218 | + |
219 | +docker-test: ## Run tests using containers |
220 | + DOCKER_COMPOSE_FILES='-f docker-compose.yml -f docker-compose.test.yml' $(MAKE) docker-compose ARGS="up --build -d" |
221 | + DOCKER_COMPOSE_FILES='-f docker-compose.yml -f docker-compose.test.yml' $(MAKE) docker-compose ARGS="run app make test $(ARGS)" |
222 | + DOCKER_COMPOSE_FILES='-f docker-compose.yml -f docker-compose.test.yml' $(MAKE) docker-compose ARGS="down" |
223 | + docker rmi deployable:test |
224 | + |
225 | +### targets for in-container use |
226 | + |
227 | +app-update-db: |
228 | + $(MAKE) manage ARGS='syncdb --noinput' PYTHON=python |
229 | + $(MAKE) manage ARGS='migrate --noinput' PYTHON=python |
230 | + |
231 | +app-start: BIND=0.0.0.0:8000 |
232 | +app-start: WORKERS=3 |
233 | +app-start: app-update-db collectstatic |
234 | + $(MAKE) manage ARGS="loaddata fixtures/group.json" |
235 | + gunicorn --workers=$(WORKERS) --bind=$(BIND) $(PROJECT_NAME).wsgi:application |
236 | + |
237 | +worker-worker: |
238 | + python $(PROJECT_NAME)/celeryapp.py worker |
239 | + |
240 | +worker-beat: |
241 | + python $(PROJECT_NAME)/celeryapp.py beat |
242 | |
243 | === added file 'README.docker' |
244 | --- README.docker 1970-01-01 00:00:00 +0000 |
245 | +++ README.docker 2017-08-01 11:41:20 +0000 |
246 | @@ -0,0 +1,35 @@ |
247 | +------ |
248 | +Docker |
249 | +------ |
250 | + |
251 | +It's as simple as: |
252 | + |
253 | + $ sudo apt install docker.io config-manager |
254 | + $ make docker-bootstrap |
255 | + $ make docker-build |
256 | + $ make docker-run |
257 | + |
258 | +.. important: |
259 | + |
260 | + Notice that docker.io can't be run inside a container easily, thus the suggested way to run it is to |
261 | + install it on your host and run it from there directly (or run everything inside a virtual machine like VirtualBox or KVM). |
262 | + |
263 | +.. important: |
264 | + |
265 | + Before running any docker commands you'll need to add yourself to the `docker` group. Otherwise all docker commands will |
266 | + have to be run as root. |
267 | + |
268 | + sudo groupadd -a -G docker $USER |
269 | + sg docker bash |
270 | + |
271 | +.. note: |
272 | + |
273 | + You only need to run the `sg` command in the current terminal. The next time you login with your user, you should |
274 | + already be a part of the docker group. |
275 | + |
276 | +You can now interact with the service by opening http://localhost:8000 in your browser of choice. |
277 | + |
278 | +To run the tests simply do: |
279 | + |
280 | + $ make docker-test |
281 | + |
282 | |
283 | === added directory 'branches/wait-for-it' |
284 | === added file 'branches/wait-for-it/LICENSE' |
285 | --- branches/wait-for-it/LICENSE 1970-01-01 00:00:00 +0000 |
286 | +++ branches/wait-for-it/LICENSE 2017-08-01 11:41:20 +0000 |
287 | @@ -0,0 +1,20 @@ |
288 | +The MIT License (MIT) |
289 | +Copyright (c) 2016 Giles Hall |
290 | + |
291 | +Permission is hereby granted, free of charge, to any person obtaining a copy of |
292 | +this software and associated documentation files (the "Software"), to deal in |
293 | +the Software without restriction, including without limitation the rights to |
294 | +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
295 | +of the Software, and to permit persons to whom the Software is furnished to do |
296 | +so, subject to the following conditions: |
297 | + |
298 | +The above copyright notice and this permission notice shall be included in all |
299 | +copies or substantial portions of the Software. |
300 | + |
301 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
302 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
303 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
304 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
305 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
306 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
307 | +SOFTWARE. |
308 | |
309 | === added file 'branches/wait-for-it/README.md' |
310 | --- branches/wait-for-it/README.md 1970-01-01 00:00:00 +0000 |
311 | +++ branches/wait-for-it/README.md 2017-08-01 11:41:20 +0000 |
312 | @@ -0,0 +1,69 @@ |
313 | +# HELP NEEDED |
314 | + |
315 | +Hi there! I wrote `wait-for-it` in order to help me orchestrate containers I operate at my day job. I thought it was a neat little script, so I published it. I assumed I would be its only user, but that's not what happened! `wait-for-it` has received more stars then all of my other public repositories put together. I had no idea this tool would solicit such an audience, and I was equally unprepared to carve out the time required to address my user's issues and patches. I would like to solicit a volunteer from the community who would be willing to be a co-maintainer of this repository. If this is something you might be interested in, please email me at `waitforit@polymerase.org`. Thanks! |
316 | + |
317 | +## wait-for-it |
318 | + |
319 | +`wait-for-it.sh` is a pure bash script that will wait on the availability of a host and TCP port. It is useful for synchronizing the spin-up of interdependent services, such as linked docker containers. Since it is a pure bash script, it does not have any external dependencies. |
320 | + |
321 | +## Usage |
322 | + |
323 | +``` |
324 | +wait-for-it.sh host:port [-s] [-t timeout] [-- command args] |
325 | +-h HOST | --host=HOST Host or IP under test |
326 | +-p PORT | --port=PORT TCP port under test |
327 | + Alternatively, you specify the host and port as host:port |
328 | +-s | --strict Only execute subcommand if the test succeeds |
329 | +-q | --quiet Don't output any status messages |
330 | +-t TIMEOUT | --timeout=TIMEOUT |
331 | + Timeout in seconds, zero for no timeout |
332 | +-- COMMAND ARGS Execute command with args after the test finishes |
333 | +``` |
334 | + |
335 | +## Examples |
336 | + |
337 | +For example, let's test to see if we can access port 80 on www.google.com, and if it is available, echo the message `google is up`. |
338 | + |
339 | +``` |
340 | +$ ./wait-for-it.sh www.google.com:80 -- echo "google is up" |
341 | +wait-for-it.sh: waiting 15 seconds for www.google.com:80 |
342 | +wait-for-it.sh: www.google.com:80 is available after 0 seconds |
343 | +google is up |
344 | +``` |
345 | + |
346 | +You can set your own timeout with the `-t` or `--timeout=` option. Setting the timeout value to 0 will disable the timeout: |
347 | + |
348 | +``` |
349 | +$ ./wait-for-it.sh -t 0 www.google.com:80 -- echo "google is up" |
350 | +wait-for-it.sh: waiting for www.google.com:80 without a timeout |
351 | +wait-for-it.sh: www.google.com:80 is available after 0 seconds |
352 | +google is up |
353 | +``` |
354 | + |
355 | +The subcommand will be executed regardless if the service is up or not. If you wish to execute the subcommand only if the service is up, add the `--strict` argument. In this example, we will test port 81 on www.google.com which will fail: |
356 | + |
357 | +``` |
358 | +$ ./wait-for-it.sh www.google.com:81 --timeout=1 --strict -- echo "google is up" |
359 | +wait-for-it.sh: waiting 1 seconds for www.google.com:81 |
360 | +wait-for-it.sh: timeout occurred after waiting 1 seconds for www.google.com:81 |
361 | +wait-for-it.sh: strict mode, refusing to execute subprocess |
362 | +``` |
363 | + |
364 | +If you don't want to execute a subcommand, leave off the `--` argument. This way, you can test the exit condition of `wait-for-it.sh` in your own scripts, and determine how to proceed: |
365 | + |
366 | +``` |
367 | +$ ./wait-for-it.sh www.google.com:80 |
368 | +wait-for-it.sh: waiting 15 seconds for www.google.com:80 |
369 | +wait-for-it.sh: www.google.com:80 is available after 0 seconds |
370 | +$ echo $? |
371 | +0 |
372 | +$ ./wait-for-it.sh www.google.com:81 |
373 | +wait-for-it.sh: waiting 15 seconds for www.google.com:81 |
374 | +wait-for-it.sh: timeout occurred after waiting 15 seconds for www.google.com:81 |
375 | +$ echo $? |
376 | +124 |
377 | +``` |
378 | + |
379 | +## Thanks |
380 | + |
381 | +I wrote this script for my employer, [Ginkgo Bioworks](http://www.ginkgobioworks.com/), who was kind enough to let me release it as an open source tool. We are always looking to [hire](https://jobs.lever.co/ginkgobioworks) talented folks who are interested in working in the field of synthetic biology. |
382 | |
383 | === added file 'branches/wait-for-it/wait-for-it.sh' |
384 | --- branches/wait-for-it/wait-for-it.sh 1970-01-01 00:00:00 +0000 |
385 | +++ branches/wait-for-it/wait-for-it.sh 2017-08-01 11:41:20 +0000 |
386 | @@ -0,0 +1,161 @@ |
387 | +#!/usr/bin/env bash |
388 | +# Use this script to test if a given TCP host/port are available |
389 | + |
390 | +cmdname=$(basename $0) |
391 | + |
392 | +echoerr() { if [[ $QUIET -ne 1 ]]; then echo "$@" 1>&2; fi } |
393 | + |
394 | +usage() |
395 | +{ |
396 | + cat << USAGE >&2 |
397 | +Usage: |
398 | + $cmdname host:port [-s] [-t timeout] [-- command args] |
399 | + -h HOST | --host=HOST Host or IP under test |
400 | + -p PORT | --port=PORT TCP port under test |
401 | + Alternatively, you specify the host and port as host:port |
402 | + -s | --strict Only execute subcommand if the test succeeds |
403 | + -q | --quiet Don't output any status messages |
404 | + -t TIMEOUT | --timeout=TIMEOUT |
405 | + Timeout in seconds, zero for no timeout |
406 | + -- COMMAND ARGS Execute command with args after the test finishes |
407 | +USAGE |
408 | + exit 1 |
409 | +} |
410 | + |
411 | +wait_for() |
412 | +{ |
413 | + if [[ $TIMEOUT -gt 0 ]]; then |
414 | + echoerr "$cmdname: waiting $TIMEOUT seconds for $HOST:$PORT" |
415 | + else |
416 | + echoerr "$cmdname: waiting for $HOST:$PORT without a timeout" |
417 | + fi |
418 | + start_ts=$(date +%s) |
419 | + while : |
420 | + do |
421 | + (echo > /dev/tcp/$HOST/$PORT) >/dev/null 2>&1 |
422 | + result=$? |
423 | + if [[ $result -eq 0 ]]; then |
424 | + end_ts=$(date +%s) |
425 | + echoerr "$cmdname: $HOST:$PORT is available after $((end_ts - start_ts)) seconds" |
426 | + break |
427 | + fi |
428 | + sleep 1 |
429 | + done |
430 | + return $result |
431 | +} |
432 | + |
433 | +wait_for_wrapper() |
434 | +{ |
435 | + # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 |
436 | + if [[ $QUIET -eq 1 ]]; then |
437 | + timeout $TIMEOUT $0 --quiet --child --host=$HOST --port=$PORT --timeout=$TIMEOUT & |
438 | + else |
439 | + timeout $TIMEOUT $0 --child --host=$HOST --port=$PORT --timeout=$TIMEOUT & |
440 | + fi |
441 | + PID=$! |
442 | + trap "kill -INT -$PID" INT |
443 | + wait $PID |
444 | + RESULT=$? |
445 | + if [[ $RESULT -ne 0 ]]; then |
446 | + echoerr "$cmdname: timeout occurred after waiting $TIMEOUT seconds for $HOST:$PORT" |
447 | + fi |
448 | + return $RESULT |
449 | +} |
450 | + |
451 | +# process arguments |
452 | +while [[ $# -gt 0 ]] |
453 | +do |
454 | + case "$1" in |
455 | + *:* ) |
456 | + hostport=(${1//:/ }) |
457 | + HOST=${hostport[0]} |
458 | + PORT=${hostport[1]} |
459 | + shift 1 |
460 | + ;; |
461 | + --child) |
462 | + CHILD=1 |
463 | + shift 1 |
464 | + ;; |
465 | + -q | --quiet) |
466 | + QUIET=1 |
467 | + shift 1 |
468 | + ;; |
469 | + -s | --strict) |
470 | + STRICT=1 |
471 | + shift 1 |
472 | + ;; |
473 | + -h) |
474 | + HOST="$2" |
475 | + if [[ $HOST == "" ]]; then break; fi |
476 | + shift 2 |
477 | + ;; |
478 | + --host=*) |
479 | + HOST="${1#*=}" |
480 | + shift 1 |
481 | + ;; |
482 | + -p) |
483 | + PORT="$2" |
484 | + if [[ $PORT == "" ]]; then break; fi |
485 | + shift 2 |
486 | + ;; |
487 | + --port=*) |
488 | + PORT="${1#*=}" |
489 | + shift 1 |
490 | + ;; |
491 | + -t) |
492 | + TIMEOUT="$2" |
493 | + if [[ $TIMEOUT == "" ]]; then break; fi |
494 | + shift 2 |
495 | + ;; |
496 | + --timeout=*) |
497 | + TIMEOUT="${1#*=}" |
498 | + shift 1 |
499 | + ;; |
500 | + --) |
501 | + shift |
502 | + CLI="$@" |
503 | + break |
504 | + ;; |
505 | + --help) |
506 | + usage |
507 | + ;; |
508 | + *) |
509 | + echoerr "Unknown argument: $1" |
510 | + usage |
511 | + ;; |
512 | + esac |
513 | +done |
514 | + |
515 | +if [[ "$HOST" == "" || "$PORT" == "" ]]; then |
516 | + echoerr "Error: you need to provide a host and port to test." |
517 | + usage |
518 | +fi |
519 | + |
520 | +TIMEOUT=${TIMEOUT:-15} |
521 | +STRICT=${STRICT:-0} |
522 | +CHILD=${CHILD:-0} |
523 | +QUIET=${QUIET:-0} |
524 | + |
525 | +if [[ $CHILD -gt 0 ]]; then |
526 | + wait_for |
527 | + RESULT=$? |
528 | + exit $RESULT |
529 | +else |
530 | + if [[ $TIMEOUT -gt 0 ]]; then |
531 | + wait_for_wrapper |
532 | + RESULT=$? |
533 | + else |
534 | + wait_for |
535 | + RESULT=$? |
536 | + fi |
537 | +fi |
538 | + |
539 | +if [[ $CLI != "" ]]; then |
540 | + if [[ $RESULT -ne 0 && $STRICT -eq 1 ]]; then |
541 | + echoerr "$cmdname: strict mode, refusing to execute subprocess" |
542 | + exit $RESULT |
543 | + fi |
544 | + exec $CLI |
545 | +else |
546 | + exit $RESULT |
547 | +fi |
548 | |
549 | === modified file 'django_project/settings_base.py' |
550 | --- django_project/settings_base.py 2016-11-03 21:48:25 +0000 |
551 | +++ django_project/settings_base.py 2017-08-01 11:41:20 +0000 |
552 | @@ -2,120 +2,47 @@ |
553 | |
554 | import os |
555 | import pwd |
556 | -import sys |
557 | +from datetime import timedelta |
558 | + |
559 | +import dj_database_url |
560 | +import djcelery |
561 | +from getenv import env |
562 | |
563 | # Needed to have celery work from management commands |
564 | -import djcelery |
565 | djcelery.setup_loader() |
566 | |
567 | -from datetime import timedelta |
568 | - |
569 | -DEBUG = True |
570 | -TEMPLATE_DEBUG = DEBUG |
571 | - |
572 | - |
573 | -BASE_DIR = os.path.dirname(os.path.dirname(__file__)) |
574 | -SRC_DIR = os.path.join(BASE_DIR, 'revtracker') |
575 | + |
576 | +# base directories |
577 | + |
578 | +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
579 | +_LOGS_DIR = os.path.abspath( |
580 | + os.path.join(BASE_DIR, os.pardir, os.pardir, 'logs')) |
581 | +LOGS_DIR = os.path.abspath(os.getenv('DPA_LOGS_DIR', _LOGS_DIR)) |
582 | HOST_DIR = os.path.abspath( |
583 | os.getenv('DPA_LP_CACHE_HOST_DIR', os.path.abspath( |
584 | os.path.join(BASE_DIR, os.path.pardir, os.path.pardir)))) |
585 | -LOGS_DIR = os.path.abspath( |
586 | - os.getenv('DPA_LOGS_DIR', os.path.join(BASE_DIR, 'logs'))) |
587 | OOPS_DIR = os.path.join(LOGS_DIR, 'www-oops') |
588 | - |
589 | - |
590 | -ADMINS = ( |
591 | - # ('Your Name', 'your_email@example.com'), |
592 | +SRC_DIR = os.path.join(BASE_DIR, 'revtracker') |
593 | + |
594 | +# django settings |
595 | + |
596 | +ADMIN_MEDIA_PREFIX = '/static/admin/' |
597 | +ALLOWED_HOSTS = env('ALLOWED_HOSTS', '[]') |
598 | +AUTHENTICATION_BACKENDS = ( |
599 | + 'django_openid_auth.auth.OpenIDBackend', |
600 | + 'django.contrib.auth.backends.ModelBackend', |
601 | ) |
602 | - |
603 | -MANAGERS = ADMINS |
604 | - |
605 | +CSRF_COOKIE_DOMAIN = None |
606 | +CSRF_COOKIE_HTTPONLY = False |
607 | +CSRF_COOKIE_NAME = 'csrftoken' |
608 | +CSRF_COOKIE_PATH = '/' |
609 | +CSRF_COOKIE_SECURE = False |
610 | +CSRF_FAILURE_VIEW = 'django.views.csrf.csrf_failure' |
611 | DATABASES = { |
612 | - 'default': { |
613 | - 'ENGINE': 'django.db.backends.postgresql_psycopg2', |
614 | - 'ATOMIC_REQUESTS': False, |
615 | - 'AUTOCOMMIT': True, |
616 | - 'CONN_MAX_AGE': 600, |
617 | - 'HOST': 'localhost', |
618 | - 'NAME': 'revtracker', |
619 | - 'OPTIONS': {}, |
620 | - 'PORT': '', |
621 | - 'TEST': { |
622 | - 'NAME': None, |
623 | - 'MIRROR': None, |
624 | - 'CHARSET': None, |
625 | - 'COLLATION': None, |
626 | - }, |
627 | - 'TIME_ZONE': 'UTC', |
628 | - 'USER': 'postgres', |
629 | - }, |
630 | + 'default': dj_database_url.config( |
631 | + default='postgres://postgres@localhost/revtracker') |
632 | } |
633 | - |
634 | -TIME_ZONE = 'UTC' |
635 | - |
636 | -LANGUAGE_CODE = 'en-us' |
637 | - |
638 | -SITE_ID = 1 |
639 | - |
640 | -USE_I18N = True |
641 | - |
642 | -USE_L10N = True |
643 | - |
644 | -MEDIA_ROOT = '' |
645 | - |
646 | -MEDIA_URL = '' |
647 | - |
648 | -STATIC_ROOT = 'static' |
649 | - |
650 | -STATIC_URL = '/static/' |
651 | - |
652 | -ADMIN_MEDIA_PREFIX = '/static/admin/' |
653 | - |
654 | -STATICFILES_DIRS = ( |
655 | - os.path.join(BASE_DIR, 'build/revtracker/js'), |
656 | -) |
657 | - |
658 | -STATICFILES_FINDERS = ( |
659 | - 'django.contrib.staticfiles.finders.FileSystemFinder', |
660 | - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', |
661 | -# 'django.contrib.staticfiles.finders.DefaultStorageFinder', |
662 | -) |
663 | - |
664 | -SECRET_KEY = '6s!*-&#t8mks^8+7_2w%!oh8wh9uzzm-vzh5)l+7r2403+tm^!' |
665 | - |
666 | -TEMPLATE_LOADERS = ( |
667 | - 'django.template.loaders.filesystem.Loader', |
668 | - 'django.template.loaders.app_directories.Loader', |
669 | - 'django.template.loaders.eggs.Loader', |
670 | -) |
671 | - |
672 | -MIDDLEWARE_CLASSES = ( |
673 | - 'django.middleware.common.CommonMiddleware', |
674 | - 'django.contrib.sessions.middleware.SessionMiddleware', |
675 | - 'django.middleware.csrf.CsrfViewMiddleware', |
676 | - 'django.contrib.auth.middleware.AuthenticationMiddleware', |
677 | - 'django.contrib.messages.middleware.MessageMiddleware', |
678 | - 'waffle.middleware.WaffleMiddleware', |
679 | - #'debug_toolbar.middleware.DebugToolbarMiddleware', |
680 | -) |
681 | - |
682 | -INTERNAL_IPS = ('127.0.0.1',) |
683 | - |
684 | -ROOT_URLCONF = 'django_project.urls' |
685 | - |
686 | -TEMPLATE_DIRS = ( |
687 | - # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". |
688 | - # Always use forward slashes, even on Windows. |
689 | - # Don't forget to use absolute paths, not relative paths. |
690 | -) |
691 | - |
692 | -TEMPLATE_CONTEXT_PROCESSORS = ( |
693 | - "django.contrib.auth.context_processors.auth", |
694 | - "django.core.context_processors.csrf", |
695 | - "django.core.context_processors.static", |
696 | - "django.core.context_processors.request", |
697 | -) |
698 | - |
699 | +DEBUG = env('DEBUG', '').lower() == 'true' |
700 | INSTALLED_APPS = ( |
701 | 'django.contrib.auth', |
702 | 'django.contrib.contenttypes', |
703 | @@ -135,7 +62,8 @@ |
704 | 'pgtools', |
705 | #'debug_toolbar', |
706 | ) |
707 | - |
708 | +INTERNAL_IPS = ('127.0.0.1',) |
709 | +LANGUAGE_CODE = 'en-us' |
710 | LOGGING = { |
711 | 'version': 1, |
712 | 'disable_existing_loggers': False, |
713 | @@ -174,13 +102,57 @@ |
714 | }, |
715 | } |
716 | } |
717 | +LOGIN_URL = '/openid/login' |
718 | +LOGIN_REDIRECT_URL = '/' |
719 | +MIDDLEWARE_CLASSES = ( |
720 | + 'django.middleware.common.CommonMiddleware', |
721 | + 'django.contrib.sessions.middleware.SessionMiddleware', |
722 | + 'django.middleware.csrf.CsrfViewMiddleware', |
723 | + 'django.contrib.auth.middleware.AuthenticationMiddleware', |
724 | + 'django.contrib.messages.middleware.MessageMiddleware', |
725 | + 'waffle.middleware.WaffleMiddleware', |
726 | + #'debug_toolbar.middleware.DebugToolbarMiddleware', |
727 | +) |
728 | +ROOT_URLCONF = 'django_project.urls' |
729 | +SECRET_KEY = env('SECRET_KEY', '') |
730 | +SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer' |
731 | +STATIC_ROOT = 'static' |
732 | +STATIC_URL = '/static/' |
733 | +STATICFILES_DIRS = ( |
734 | + os.path.join(BASE_DIR, 'build/revtracker/js'), |
735 | +) |
736 | +STATICFILES_FINDERS = ( |
737 | + 'django.contrib.staticfiles.finders.FileSystemFinder', |
738 | + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', |
739 | +) |
740 | +TEMPLATE_CONTEXT_PROCESSORS = ( |
741 | + "django.contrib.auth.context_processors.auth", |
742 | + "django.core.context_processors.csrf", |
743 | + "django.core.context_processors.static", |
744 | + "django.core.context_processors.request", |
745 | +) |
746 | +TEMPLATE_LOADERS = ( |
747 | + 'django.template.loaders.filesystem.Loader', |
748 | + 'django.template.loaders.app_directories.Loader', |
749 | + 'django.template.loaders.eggs.Loader', |
750 | +) |
751 | +TEST_RUNNER = 'django.test.runner.DiscoverRunner' |
752 | +TIME_ZONE = 'UTC' |
753 | +USE_I18N = True |
754 | +USE_L10N = True |
755 | + |
756 | +# debug-toolbar settings |
757 | |
758 | DEBUG_TOOLBAR_CONFIG = { |
759 | 'INTERCEPT_REDIRECTS': False, |
760 | } |
761 | |
762 | -BRANCH_CACHE_DIR = "branches" |
763 | +# celery settings |
764 | |
765 | +CELERY_BROKER_URL = os.getenv('CELERY_BROKER_URL', 'amqp://') |
766 | +CELERY_ACCEPT_CONTENT = ['json'] |
767 | +CELERY_TASK_SERIALIZER = 'json' |
768 | +CELERY_RESULT_SERIALIZER = 'json' |
769 | CELERYBEAT_SCHEDULE = { |
770 | "update_all_projects": { |
771 | "task": "revtracker.tasks.update_all_projects", |
772 | @@ -192,14 +164,25 @@ |
773 | CELERYD_PREFETCH_MULTIPLIER = 1 |
774 | CELERYBEAT_SCHEDULE_FILENAME = 'tmp/celerybeat-schedule' |
775 | |
776 | -LOGIN_URL = '/openid/login' |
777 | -LOGIN_REDIRECT_URL = '/' |
778 | - |
779 | -AUTHENTICATION_BACKENDS = ( |
780 | - 'django_openid_auth.auth.OpenIDBackend', |
781 | - 'django.contrib.auth.backends.ModelBackend', |
782 | - ) |
783 | - |
784 | +# django-openid-auth settings |
785 | + |
786 | +OPENID_CREATE_USERS = True |
787 | +OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO = True |
788 | +OPENID_UPDATE_DETAILS_FROM_SREG = True |
789 | +OPENID_SREG_REQUIRED_FIELDS = ['nickname'] |
790 | +OPENID_SSO_SERVER_URL = 'https://login.ubuntu.com/' |
791 | + |
792 | +# revtracker settings |
793 | + |
794 | +BRANCH_CACHE_DIR = "branches" |
795 | +COMBO_URL = env('COMBO_URL', 'http://127.0.0.1:8001/') |
796 | +CONVOY_ROOT = os.path.join(STATIC_ROOT, 'combo') |
797 | +GIT_SSH_DEFAULT_USERNAME = pwd.getpwuid(os.getuid()).pw_name |
798 | +GIT_SSH_DEFAULT_PORT = None |
799 | +GIT_SSH_PRIVATE_KEY = os.path.expanduser('~/.ssh/id_rsa') |
800 | +GIT_SSH_PUBLIC_KEY = os.path.expanduser('~/.ssh/id_rsa.pub') |
801 | +LP_INSTANCE = 'production' |
802 | +MULTILANG_OP_ENDPOINTS = False |
803 | OOPSES = { |
804 | 'publishers': [{ |
805 | 'inherit_id': False, |
806 | @@ -209,40 +192,6 @@ |
807 | }], |
808 | 'template': {'reporter': 'DEFAULT'}, |
809 | } |
810 | - |
811 | -USE_HTTPS = True |
812 | - |
813 | -OPENID_SSO_SERVER_URL = 'https://login.ubuntu.com/' |
814 | -OPENID_CREATE_USERS = True |
815 | -OPENID_UPDATE_DETAILS_FROM_SREG = True |
816 | -OPENID_SREG_REQUIRED_FIELDS = ['nickname'] |
817 | -OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO = True |
818 | - |
819 | -MULTILANG_OP_ENDPOINTS = False |
820 | - |
821 | -COMBO_URL = 'http://127.0.0.1:8001/' |
822 | - |
823 | -CONVOY_ROOT = os.path.join(STATIC_ROOT, 'combo') |
824 | - |
825 | +SOFT_TIMEOUT_MILLISECONDS = 10000 |
826 | +USE_HTTPS = env('USE_HTTPS', 'true').lower() == 'true' |
827 | WAFFLE_OVERRIDE = True |
828 | -SOFT_TIMEOUT_MILLISECONDS = 10000 |
829 | - |
830 | -CSRF_COOKIE_DOMAIN = None |
831 | -CSRF_COOKIE_HTTPONLY = False |
832 | -CSRF_COOKIE_NAME = 'csrftoken' |
833 | -CSRF_COOKIE_PATH = '/' |
834 | -CSRF_COOKIE_SECURE = False |
835 | -CSRF_FAILURE_VIEW = 'django.views.csrf.csrf_failure' |
836 | - |
837 | -TEST_RUNNER = 'django.test.runner.DiscoverRunner' |
838 | -SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer' |
839 | - |
840 | -LP_INSTANCE = 'production' |
841 | - |
842 | -GIT_SSH_DEFAULT_USERNAME = pwd.getpwuid(os.getuid()).pw_name |
843 | -GIT_SSH_DEFAULT_PORT = None |
844 | -GIT_SSH_PRIVATE_KEY = os.path.expanduser('~/.ssh/id_rsa') |
845 | -GIT_SSH_PUBLIC_KEY = os.path.expanduser('~/.ssh/id_rsa.pub') |
846 | - |
847 | - |
848 | -sys.path.insert(0, os.path.dirname(__file__)) |
849 | |
850 | === added file 'django_project/settings_build.py' |
851 | --- django_project/settings_build.py 1970-01-01 00:00:00 +0000 |
852 | +++ django_project/settings_build.py 2017-08-01 11:41:20 +0000 |
853 | @@ -0,0 +1,12 @@ |
854 | +import os |
855 | + |
856 | +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
857 | + |
858 | +os.environ.setdefault( |
859 | + 'DPA_LOGS_DIR', |
860 | + os.path.abspath(os.path.join(BASE_DIR, 'logs'))) |
861 | + |
862 | +from django_project.settings_base import * # noqa |
863 | + |
864 | +DATABASES = {} |
865 | +SECRET_KEY = 'build-secret-key' |
866 | |
867 | === modified file 'django_project/settings_devel.py' |
868 | --- django_project/settings_devel.py 2016-07-25 20:52:24 +0000 |
869 | +++ django_project/settings_devel.py 2017-08-01 11:41:20 +0000 |
870 | @@ -1,8 +1,20 @@ |
871 | -from django_project.settings_base import * # noqa |
872 | - |
873 | -DATABASES['default']['HOST'] = '/dev/shm/pg_deployable' |
874 | -USE_HTTPS = False |
875 | +import os |
876 | + |
877 | +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
878 | + |
879 | +os.environ.setdefault('ALLOWED_HOSTS', "['*']") |
880 | # Serve combo data from a relative url - served by project's gunicorn |
881 | # directly. |
882 | -COMBO_URL = '/combo/' |
883 | +os.environ.setdefault('COMBO_URL', '/combo/') |
884 | +os.environ.setdefault( |
885 | + 'DATABASE_URL', |
886 | + 'postgres://postgres@%2Fdev%2Fshm%2Fpg_deployable/revtracker') |
887 | +os.environ.setdefault('DEBUG', 'true') |
888 | +os.environ.setdefault( |
889 | + 'DPA_LOGS_DIR', |
890 | + os.path.abspath(os.path.join(BASE_DIR, 'logs'))) |
891 | +os.environ.setdefault( |
892 | + 'SECRET_KEY', '6s!*-&#t8mks^8+7_2w%!oh8wh9uzzm-vzh5)l+7r2403+tm^!') |
893 | +os.environ.setdefault('USE_HTTPS', 'false') |
894 | |
895 | +from django_project.settings_base import * # noqa |
896 | |
897 | === added file 'docker-compose.dev.yml' |
898 | --- docker-compose.dev.yml 1970-01-01 00:00:00 +0000 |
899 | +++ docker-compose.dev.yml 2017-08-01 11:41:20 +0000 |
900 | @@ -0,0 +1,24 @@ |
901 | +version: '2' |
902 | +services: |
903 | + app: |
904 | + restart: always |
905 | + build: . |
906 | + image: deployable:dev |
907 | + command: ["./branches/wait-for-it/wait-for-it.sh", "db:5432", "--", "make", "app-start"] |
908 | + volumes: |
909 | + - .:/usr/src/app |
910 | + ports: |
911 | + - "8000:8000" |
912 | + environment: |
913 | + CELERY_BROKER_URL: amqp://amqp |
914 | + DATABASE_URL: postgres://postgres@db/postgres |
915 | + DJANGO_SETTINGS_MODULE: "django_project.settings_devel" |
916 | + worker: |
917 | + restart: always |
918 | + image: deployable:dev |
919 | + volumes: |
920 | + - .:/usr/src/app |
921 | + environment: |
922 | + CELERY_BROKER_URL: amqp://amqp |
923 | + DATABASE_URL: postgres://postgres@db/postgres |
924 | + DJANGO_SETTINGS_MODULE: "django_project.settings_devel" |
925 | |
926 | === added file 'docker-compose.secrets.yml' |
927 | --- docker-compose.secrets.yml 1970-01-01 00:00:00 +0000 |
928 | +++ docker-compose.secrets.yml 2017-08-01 11:41:20 +0000 |
929 | @@ -0,0 +1,5 @@ |
930 | +version: '2' |
931 | +services: |
932 | + app: |
933 | +# environment: |
934 | +# SECRET_KEY: 'changeme' |
935 | |
936 | === added file 'docker-compose.test.yml' |
937 | --- docker-compose.test.yml 1970-01-01 00:00:00 +0000 |
938 | +++ docker-compose.test.yml 2017-08-01 11:41:20 +0000 |
939 | @@ -0,0 +1,9 @@ |
940 | +version: '2' |
941 | +services: |
942 | + app: |
943 | + extends: |
944 | + file: docker-compose.dev.yml |
945 | + service: app |
946 | + build: |
947 | + dockerfile: Dockerfile.test |
948 | + image: deployable:test |
949 | |
950 | === added file 'docker-compose.yml' |
951 | --- docker-compose.yml 1970-01-01 00:00:00 +0000 |
952 | +++ docker-compose.yml 2017-08-01 11:41:20 +0000 |
953 | @@ -0,0 +1,19 @@ |
954 | +version: '2' |
955 | +services: |
956 | + db: |
957 | + image: postgres |
958 | + expose: |
959 | + - "5432" |
960 | + amqp: |
961 | + image: rabbitmq |
962 | + app: |
963 | + build: . |
964 | + image: deployable |
965 | + expose: |
966 | + - "8000" |
967 | + depends_on: |
968 | + - db |
969 | + - amqp |
970 | + worker: |
971 | + image: deployable |
972 | + command: ["make", "worker-worker", "worker-beat"] |
973 | |
974 | === added file 'requirements-docker.txt' |
975 | --- requirements-docker.txt 1970-01-01 00:00:00 +0000 |
976 | +++ requirements-docker.txt 2017-08-01 11:41:20 +0000 |
977 | @@ -0,0 +1,19 @@ |
978 | +# direct dependencies |
979 | +docker_compose==1.14.0 |
980 | + |
981 | +# indirect dependencies |
982 | +PyYAML==3.12 |
983 | +backports.ssl_match_hostname==3.5.0.1 |
984 | +cached_property==1.3.0 |
985 | +colorama==0.3.9 |
986 | +docker==2.4.2 |
987 | +docker_pycreds==0.2.1 |
988 | +dockerpty==0.4.1 |
989 | +docopt==0.6.2 |
990 | +enum34==1.1.6 |
991 | +functools32==3.2.3-2 |
992 | +ipaddress==1.0.18 |
993 | +jsonschema==2.6.0 |
994 | +requests==2.11.1 |
995 | +texttable==0.8.8 |
996 | +websocket_client==0.44.0 |
997 | |
998 | === modified file 'requirements.txt' |
999 | --- requirements.txt 2016-09-02 22:32:27 +0000 |
1000 | +++ requirements.txt 2017-08-01 11:41:20 +0000 |
1001 | @@ -11,6 +11,7 @@ |
1002 | django-debug-toolbar==0.10.0 |
1003 | django-devserver==0.7.0 |
1004 | django-factory==0.10 |
1005 | +django-getenv==1.3.1 |
1006 | django-kombu==0.9.4 |
1007 | django-openid-auth==0.9 |
1008 | # A checkout of https://github.com/bfirsh/django-ordered-model at 2998740eeda348473d8a8965b40b2292c31efd85 |
1009 | @@ -18,6 +19,7 @@ |
1010 | django-picklefield==0.2.1 |
1011 | django-pgtools==0.2 |
1012 | django-waffle==0.10.1 |
1013 | +dj-database-url==0.4.2 |
1014 | gorun==1.7 |
1015 | gunicorn==19.3.0 |
1016 | html5lib==0.9999999 |
besides the weird missing modules errors, it worked!