diff --git a/.gitignore b/.gitignore index d9e8b03f..15e74fdf 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ # This is the name that the install notes suggest be used for the virtualenv .venv +env/ .DS_Store .vagrant diff --git a/CHECKS b/CHECKS new file mode 100644 index 00000000..037f0ce8 --- /dev/null +++ b/CHECKS @@ -0,0 +1,5 @@ +WAIT=10 +ATTEMPTS=3 + +/ + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..cc58cd37 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,47 @@ +FROM python:2.7-stretch +ENV DEBIAN_FRONTEND noninteractive + +# Upgrade OS Dependencies +RUN apt-get update && apt-get upgrade -y +# Install Postgresql Client +RUN apt-get install postgresql-client -y + +# Upgrade pip + setuptools +RUN pip install -q -U pip setuptools + +# Install gunicorn with gevent +RUN pip install -q -U gunicorn[gevent] + +# GDAL Installs +RUN apt-get install gdal-bin python-gdal libgdal-dev -y +RUN pip install -q GDAL==2.1.3 --global-option=build_ext --global-option="-I/usr/include/gdal" + +# Set env variables used in this Dockerfile +#Django settings +ENV DJANGO_SETTINGS_MODULE=project.settings + +# Local directory with project source +ENV APP_SRC=. +# Directory in container for all project files +ENV APP_SRVHOME=/src +# Directory in container for project source files +ENV APP_SRVPROJ=/src/mapit + +# Create application subdirectories +WORKDIR $APP_SRVHOME +RUN mkdir media static logs +VOLUME ["$APP_SRVHOME/media/", "$APP_SRVHOME/logs/"] + +# Add application source code to SRCDIR +ADD $APP_SRC $APP_SRVPROJ +WORKDIR $APP_SRVPROJ + +# Install dependencies +RUN pip install -q -e . + +# Server +EXPOSE 8000 + +COPY ./docker-entrypoint.sh / +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD [ "--name", "mapit", "--reload", "project.wsgi:application" ] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..4d80efe0 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,39 @@ +version: '3.3' + +services: + db: + image: mdillon/postgis:9.5 + ports: + - "54321:5432" + environment: + - POSTGRES_USER=mapit + - POSTGRES_PASSWORD=mapit + - POSTGRES_DB=mapit + - PGUSER=mapit + - PGPASSWORD=mapit + + web: + build: . + ports: + - "8000:8000" + depends_on: + - db + volumes: + - ./:/src/mapit + environment: + - DJANGO_SETTINGS_MODULE=project.settings + - DATABASE_URL=postgresql://mapit:mapit@db:5432/mapit + - DJANGO_SECRET_KEY=somethingsecret + - MAPIT_DB_HOST=db + - MAPIT_DB_NAME=mapit + - MAPIT_DB_USER=mapit + - MAPIT_DB_PASS=mapit + - AREA_SRID= + - COUNTRY= + - RATE_LIMIT= + - GOOGLE_ANALYTICS= + - DEBUG= + - BUGS_EMAIL= + - EMAIL_SUBJECT_PREFIX= + - PYTHONDONTWRITEBYTECODE="True" + # - DJANGO_DEBUG=False # For testing deploys diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100755 index 00000000..26b2b0a8 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,30 @@ +#!/bin/bash +set -e + +until psql $DATABASE_URL -c '\l'; do + >&2 echo "Postgres is unavailable - sleeping" + sleep 1 +done + +>&2 echo "Postgres is up - continuing" + +./bin/mapit_make_css +python manage.py collectstatic --clear --noinput # Collect static files + +python manage.py migrate --noinput # Apply database migrations + +# Prepare log files and start outputting logs to stdout +touch /src/logs/gunicorn.log +touch /src/logs/access.log +tail -n 0 -f /src/logs/*.log & + +# Start Gunicorn processes +echo Starting Gunicorn. +exec gunicorn \ + --bind 0.0.0.0:8000 \ + --workers 3 \ + --worker-class gevent \ + --log-level=info \ + --log-file=/src/logs/gunicorn.log \ + --access-logfile=/src/logs/access.log \ + project.wsgi:application diff --git a/project/settings.py b/project/settings.py index 45c86219..750fbe94 100644 --- a/project/settings.py +++ b/project/settings.py @@ -20,22 +20,22 @@ # An EPSG code for what the areas are stored as, e.g. 27700 is OSGB, 4326 for # WGS84. Optional, defaults to 4326. -MAPIT_AREA_SRID = int(config.get('AREA_SRID', 4326)) +MAPIT_AREA_SRID = int(config.get('AREA_SRID', os.environ.get('AREA_SRID', 4326))) # Country is currently one of GB, NO, IT, KE, SA, or ZA. # Optional; country specific things won't happen if not set. -MAPIT_COUNTRY = config.get('COUNTRY', '') +MAPIT_COUNTRY = config.get('COUNTRY', os.environ.get('COUNTRY', '')) # A dictionary of IP addresses, User Agents, or functions that should be # excluded from rate limiting. Optional. -MAPIT_RATE_LIMIT = config.get('RATE_LIMIT', {}) +MAPIT_RATE_LIMIT = config.get('RATE_LIMIT', os.environ.get('RATE_LIMIT', {})) # A GA code for analytics -GOOGLE_ANALYTICS = config.get('GOOGLE_ANALYTICS', '') +GOOGLE_ANALYTICS = config.get('GOOGLE_ANALYTICS', os.environ.get('GOOGLE_ANALYTICS', '')) # Django settings for mapit project. -DEBUG = config.get('DEBUG', True) +DEBUG = config.get('DEBUG', os.environ.get('DEBUG', True)) # (Note that even if DEBUG is true, output_json still sets a # Cache-Control header with max-age of 28 days.) @@ -59,30 +59,38 @@ except ImportError: pass CACHE_MIDDLEWARE_SECONDS = 86400 - CACHE_MIDDLEWARE_KEY_PREFIX = config.get('MAPIT_DB_NAME') + CACHE_MIDDLEWARE_KEY_PREFIX = config.get('MAPIT_DB_NAME', os.environ.get('MAPIT_DB_NAME')) if config.get('BUGS_EMAIL'): SERVER_EMAIL = config['BUGS_EMAIL'] ADMINS = ( - ('mySociety bugs', config['BUGS_EMAIL']), + ('mySociety bugs', SERVER_EMAIL), + ) +if os.environ.get('BUGS_EMAIL'): + SERVER_EMAIL = os.environ['BUGS_EMAIL'] + ADMINS = ( + ('mySociety bugs', SERVER_EMAIL), ) if config.get('EMAIL_SUBJECT_PREFIX'): EMAIL_SUBJECT_PREFIX = config['EMAIL_SUBJECT_PREFIX'] +if os.environ.get('EMAIL_SUBJECT_PREFIX'): + EMAIL_SUBJECT_PREFIX = os.environ['EMAIL_SUBJECT_PREFIX'] + DATABASES = { 'default': { 'ENGINE': 'django.contrib.gis.db.backends.postgis', - 'NAME': config.get('MAPIT_DB_NAME', 'mapit'), - 'USER': config.get('MAPIT_DB_USER', 'mapit'), - 'PASSWORD': config.get('MAPIT_DB_PASS', ''), - 'HOST': config.get('MAPIT_DB_HOST', ''), - 'PORT': config.get('MAPIT_DB_PORT', ''), + 'NAME': config.get('MAPIT_DB_NAME', os.environ.get('MAPIT_DB_NAME')), + 'USER': config.get('MAPIT_DB_USER', os.environ.get('MAPIT_DB_USER')), + 'PASSWORD': config.get('MAPIT_DB_PASS', os.environ.get('MAPIT_DB_PASS')), + 'HOST': config.get('MAPIT_DB_HOST', os.environ.get('MAPIT_DB_HOST')), + 'PORT': config.get('MAPIT_DB_PORT', os.environ.get('MAPIT_DB_PORT')), } } # Make this unique, and don't share it with anybody. -SECRET_KEY = config.get('DJANGO_SECRET_KEY', '') +SECRET_KEY = config.get('DJANGO_SECRET_KEY', os.environ.get('DJANGO_SECRET_KEY')) ALLOWED_HOSTS = ['*'] diff --git a/project/urls.py b/project/urls.py index bca42fa9..ef51c2c9 100644 --- a/project/urls.py +++ b/project/urls.py @@ -1,9 +1,11 @@ from django.conf.urls import include, url +from django.conf.urls.static import static from django.contrib import admin +import project.settings as settings handler500 = 'mapit.shortcuts.json_500' urlpatterns = [ url(r'^', include('mapit.urls')), url(r'^admin/', admin.site.urls), -] +] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) diff --git a/runtime.txt b/runtime.txt new file mode 100644 index 00000000..5b664547 --- /dev/null +++ b/runtime.txt @@ -0,0 +1 @@ +python-2.7.15 \ No newline at end of file