diff --git a/.dockerignore b/.dockerignore index 33957286..88f752a0 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,4 @@ virtual-env .vscode db.sqlite -postgres_data \ No newline at end of file +postgres_data diff --git a/.gitignore b/.gitignore index 8813a2d2..6a185cea 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ dist/ .python-version .mypy_cache/ +env \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..686e319b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,51 @@ +# Stage 1 - Install Python Requirement and Response +FROM python:3.7-slim as builder + +WORKDIR /src + +RUN apt-get update && apt-get install -y gcc libpq-dev + +RUN pip install uwsgi + +COPY ./response/ /src/response/ +COPY ./setup.py /src/ +COPY ./README.md /src/ +COPY ./MANIFEST.in /src/ +COPY ./LICENSE /src/ + +RUN pip install . + +# Stage 2 - Install/Obtain supercronic for cron +FROM python:3.7-slim as supercronic + +RUN apt-get update && apt-get install -y curl + +ENV SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/v0.1.11/supercronic-linux-amd64 \ + SUPERCRONIC=supercronic-linux-amd64 \ + SUPERCRONIC_SHA1SUM=a2e2d47078a8dafc5949491e5ea7267cc721d67c + +RUN curl -fsSLO "$SUPERCRONIC_URL" \ + && echo "${SUPERCRONIC_SHA1SUM} ${SUPERCRONIC}" | sha1sum -c - \ + && chmod +x "$SUPERCRONIC" \ + && mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}" \ + && ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic + +# Stage 3 - FINAL - Put the pieces together +FROM python:3.7-slim + +WORKDIR /app +ENTRYPOINT ["/app/entrypoint.sh"] + +RUN apt-get update && apt-get install -y wget netcat postgresql-client && apt-get clean && rm -rf /var/lib/apt/lists/* + +COPY --from=supercronic /usr/local/bin/supercronic /usr/local/bin/supercronic +COPY --from=builder /usr/local/lib/python3.7/site-packages/ /usr/local/lib/python3.7/site-packages/ +COPY --from=builder /usr/local/bin/ /usr/local/bin/ + +COPY ./app/ /app/ +COPY ./entrypoint.sh /app/entrypoint.sh +COPY ./crontab /app/crontab + +RUN mkdir -p /app/static && chown -R nobody /app/static + +USER nobody \ No newline at end of file diff --git a/demo/demo/__init__.py b/app/__init__.py similarity index 100% rename from demo/demo/__init__.py rename to app/__init__.py diff --git a/demo/manage.py b/app/manage.py similarity index 88% rename from demo/manage.py rename to app/manage.py index c98d68ed..6af94a0b 100755 --- a/demo/manage.py +++ b/app/manage.py @@ -5,7 +5,7 @@ def main(): - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "demo.settings") + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings.prod") try: from django.core.management import execute_from_command_line except ImportError as exc: diff --git a/demo/demo/settings/base.py b/app/settings/base.py similarity index 97% rename from demo/demo/settings/base.py rename to app/settings/base.py index ebeb8deb..da7eeaa2 100644 --- a/demo/demo/settings/base.py +++ b/app/settings/base.py @@ -1,5 +1,5 @@ """ -Django settings for demo project. +Django settings for response project. Generated by 'django-admin startproject' using Django 2.2.3. @@ -22,7 +22,6 @@ # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ @@ -47,7 +46,7 @@ "after_response", "rest_framework", "bootstrap4", - "response.apps.ResponseConfig", + "response.apps.ResponseConfig" ] MIDDLEWARE = [ @@ -60,7 +59,7 @@ "django.middleware.clickjacking.XFrameOptionsMiddleware", ] -ROOT_URLCONF = "demo.urls" +ROOT_URLCONF = "urls" TEMPLATES = [ { @@ -78,7 +77,7 @@ } ] -WSGI_APPLICATION = "demo.wsgi.application" +WSGI_APPLICATION = "wsgi.application" # Database @@ -125,7 +124,6 @@ STATIC_URL = "/static/" STATIC_ROOT = "static" - # Django Rest Framework # https://www.django-rest-framework.org/ diff --git a/demo/demo/settings/prod.py b/app/settings/prod.py similarity index 97% rename from demo/demo/settings/prod.py rename to app/settings/prod.py index a27184d3..a86d638b 100644 --- a/demo/demo/settings/prod.py +++ b/app/settings/prod.py @@ -60,3 +60,5 @@ INCIDENT_REPORT_CHANNEL_ID = os.getenv( "INCIDENT_REPORT_CHANNEL_ID" ) or SLACK_CLIENT.get_channel_id(INCIDENT_REPORT_CHANNEL_NAME) + +SECRET_KEY = os.getenv("SECRET_KEY") diff --git a/demo/demo/urls.py b/app/urls.py similarity index 79% rename from demo/demo/urls.py rename to app/urls.py index d201422e..ff0b704c 100644 --- a/demo/demo/urls.py +++ b/app/urls.py @@ -1,4 +1,4 @@ -"""demo URL Configuration +"""response app URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/2.2/topics/http/urls/ @@ -15,10 +15,12 @@ """ from django.contrib import admin from django.urls import include, path +from django.conf import settings +from django.conf.urls.static import static urlpatterns = [ path("admin/", admin.site.urls), path("slack/", include("response.slack.urls")), path("core/", include("response.core.urls")), - path("", include("response.ui.urls")), -] + path("", include("response.ui.urls")) +] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) diff --git a/demo/demo/wsgi.py b/app/wsgi.py similarity index 73% rename from demo/demo/wsgi.py rename to app/wsgi.py index f3d69374..5d0b4623 100644 --- a/demo/demo/wsgi.py +++ b/app/wsgi.py @@ -1,5 +1,5 @@ """ -WSGI config for demo project. +WSGI config for response app project. It exposes the WSGI callable as a module-level variable named ``application``. @@ -11,6 +11,6 @@ from django.core.wsgi import get_wsgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "demo.settings.dev") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings.prod") application = get_wsgi_application() diff --git a/crontab b/crontab new file mode 100644 index 00000000..87ffe888 --- /dev/null +++ b/crontab @@ -0,0 +1 @@ +* * * * * wget -qO- $RESPONSE_URL/slack/cron_minute \ No newline at end of file diff --git a/demo/Dockerfile.cron b/demo/Dockerfile.cron deleted file mode 100644 index d94bb359..00000000 --- a/demo/Dockerfile.cron +++ /dev/null @@ -1,7 +0,0 @@ -FROM alpine - -# Run every minute -RUN echo '* * * * * wget -qO- response:8000/slack/cron_minute' > /etc/crontabs/root - -# Run crond in the foreground -CMD ["crond", "-f"] \ No newline at end of file diff --git a/demo/Dockerfile.response b/demo/Dockerfile.response deleted file mode 100644 index 2fff54a1..00000000 --- a/demo/Dockerfile.response +++ /dev/null @@ -1,14 +0,0 @@ -FROM python:3.7-slim - -RUN apt-get update && apt-get install -y --no-install-recommends \ - netcat \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /app -COPY requirements.txt /app -RUN pip install -r requirements.txt - -COPY . /app/ - -ENTRYPOINT ["python", "manage.py"] -CMD ["runserver", "0.0.0.0:8000"] diff --git a/demo/README.md b/demo/README.md index 5c91876a..d0913254 100644 --- a/demo/README.md +++ b/demo/README.md @@ -1,25 +1,12 @@ -# Response Demo App +# Response -This is an example Django project using the django-incident-response package that you can use to test drive Response locally. You'll need access to be able to add and configure apps in a Slack workspace of your choosing - you can sign up for a free account, if necessary. - -All commands should be run from this directory (`demo`). - ---- - -# Quick Start - -The following steps explain how to create a Slack app, run Response locally, and configure everything to develop and test locally. - -Broadly speaking, this sets things up as below: -
- -
+The easiest way to get started is with docker! ## 1. Create a Slack App Follow [these instructions](../docs/slack_app_create.md) to create a new Slack App. -## 2. Configure the demo app +## 2. Configure Response! The demo app is configured using environment variables in a `.env` file. Create your own: ``` @@ -34,47 +21,23 @@ and update the variables in it: | `INCIDENT_CHANNEL_NAME` | When an incident is declared, a 'headline' post is sent to a central channel.