Merge lp:~ricardokirkner/isitdeployable/docker into lp:isitdeployable

Proposed by Ricardo Kirkner
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
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

To post a comment you must log in.
Revision history for this message
Guillermo Gonzalez (verterok) wrote :

besides the weird missing modules errors, it worked!

review: Approve
Revision history for this message
Otto Co-Pilot (otto-copilot) wrote :
Revision history for this message
Otto Co-Pilot (otto-copilot) wrote :
Revision history for this message
Otto Co-Pilot (otto-copilot) wrote :
Revision history for this message
Otto Co-Pilot (otto-copilot) wrote :
Revision history for this message
Otto Co-Pilot (otto-copilot) wrote :
Revision history for this message
Otto Co-Pilot (otto-copilot) wrote :
Revision history for this message
Otto Co-Pilot (otto-copilot) wrote :
225. By Ricardo Kirkner

do not override default $(ENV) target in docker Makefile

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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

Subscribers

People subscribed via source and target branches