From ec1f4966b585df5bc94a8aad09893c4ce241d1aa Mon Sep 17 00:00:00 2001 From: Ronald Ip Date: Thu, 23 Feb 2017 01:09:54 +0800 Subject: [PATCH 1/2] Heroku compatibility. --- Procfile | 1 + app.json | 34 ++++++++++++++++++++++++++ bin/post_compile | 36 +++++++++++++++++++++++++++ bin/run_compress | 15 ++++++++++++ hc/heroku_settings.py | 57 +++++++++++++++++++++++++++++++++++++++++++ hc/settings.py | 2 ++ hc/wsgi.py | 5 ++-- requirements.in | 9 +++++++ requirements.txt | 32 ++++++++++++++++++++---- 9 files changed, 184 insertions(+), 7 deletions(-) create mode 100644 Procfile create mode 100644 app.json create mode 100755 bin/post_compile create mode 100755 bin/run_compress create mode 100644 hc/heroku_settings.py create mode 100644 requirements.in diff --git a/Procfile b/Procfile new file mode 100644 index 00000000..e4b26fdc --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: gunicorn hc.wsgi --log-file - diff --git a/app.json b/app.json new file mode 100644 index 00000000..c13272e6 --- /dev/null +++ b/app.json @@ -0,0 +1,34 @@ +{ + "name": "healthchecks", + "website": "https://github.com/healthchecks/healthchecks", + "keywords": ["heroku", "cron", "devops", "python", "monitoring", "cron-jobs"], + "image": "heroku/python", + "addons": [ + "heroku-postgresql:hobby-dev", + "mailgun:starter", + "scheduler:standard" + ], + "scripts": { + "postdeploy": "python manage.py migrate" + }, + "env": { + "SITE_ROOT": { + "description": "Used to build fully qualified URLs for pings, and for use in emails and notifications. Enter your App Name defined above here.", + "value": "https://appname.herokuapp.com/" + }, + "SITE_NAME": { + "description": "Used throughout the templates.", + "value": "My Monitoring Project" + }, + "FROM_EMAIL": { + "description": "Email from address.", + "value": "noreply@example.com" + }, + "SECRET_KEY": { + "generator": "secret" + }, + "ON_HEROKU": { + "value": "yes" + } + } +} diff --git a/bin/post_compile b/bin/post_compile new file mode 100755 index 00000000..f9329570 --- /dev/null +++ b/bin/post_compile @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -eo pipefail + +# The post_compile hook is run by heroku-buildpack-python + +echo "-----> I'm post-compile hook" + +# Work around Heroku bug whereby pylibmc isn't available during +# compile phase. See: https://github.com/heroku/heroku-buildpack-python/issues/57 +export MEMCACHE_SERVERS='' MEMCACHIER_SERVERS='' + +if [ -f bin/install_nodejs ]; then + echo "-----> Running install_nodejs" + chmod +x bin/install_nodejs + bin/install_nodejs + + if [ -f bin/install_less ]; then + echo "-----> Running install_lessc" + chmod +x bin/install_less + bin/install_less + fi +fi + +if [ -f bin/run_collectstatic ]; then + echo "-----> Running run_collectstatic" + chmod +x bin/run_collectstatic + bin/run_collectstatic +fi + +if [ -f bin/run_compress ]; then + echo "-----> Running run_compress" + chmod +x bin/run_compress + bin/run_compress +fi + +echo "-----> Post-compile done" diff --git a/bin/run_compress b/bin/run_compress new file mode 100755 index 00000000..e373071d --- /dev/null +++ b/bin/run_compress @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -eo pipefail + +indent() { + RE="s/^/ /" + [ $(uname) == "Darwin" ] && sed -l "$RE" || sed -u "$RE" +} + +MANAGE_FILE=$(find . -maxdepth 3 -type f -name 'manage.py' | head -1) +MANAGE_FILE=${MANAGE_FILE:2} + +echo "-----> Compressing static files" +python $MANAGE_FILE compress 2>&1 | indent + +echo diff --git a/hc/heroku_settings.py b/hc/heroku_settings.py new file mode 100644 index 00000000..ae04240e --- /dev/null +++ b/hc/heroku_settings.py @@ -0,0 +1,57 @@ +import os +PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +SITE_ROOT = os.getenv('SITE_ROOT', "https://my-monitoring-project.com") +SITE_NAME = os.getenv('SITE_NAME', "My Monitoring Project") +DEFAULT_FROM_EMAIL = os.getenv('FROM_EMAIL', "noreply@my-monitoring-project.com") + +import herokuify +from herokuify.common import * +from herokuify.mail.mailgun import * + +DATABASES = herokuify.get_db_config() + +DEBUG = False +SECRET_KEY = os.getenv('SECRET_KEY', "---") + +# Allow all host headers +ALLOWED_HOSTS = ['*'] + +# Simplified static file serving. +# https://warehouse.python.org/project/whitenoise/ + +STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage' + +import sys +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'formatters': { + 'verbose': { + 'format' : "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s", + 'datefmt' : "%d/%b/%Y %H:%M:%S" + }, + 'simple': { + 'format': '%(levelname)s %(message)s' + }, + }, + 'handlers': { + 'console': { + 'level': 'DEBUG', + 'class': 'logging.StreamHandler', + 'formatter': 'verbose', + 'stream': sys.stdout, + }, + }, + 'loggers': { + 'django': { + 'handlers':['console'], + 'propagate': True, + 'level':'DEBUG', + }, + 'MYAPP': { + 'handlers': ['console'], + 'level': 'DEBUG', + }, + } +} diff --git a/hc/settings.py b/hc/settings.py index e41f24bf..ee29f8b2 100644 --- a/hc/settings.py +++ b/hc/settings.py @@ -153,5 +153,7 @@ PUSHBULLET_CLIENT_SECRET = None if os.path.exists(os.path.join(BASE_DIR, "hc/local_settings.py")): from .local_settings import * +elif ('ON_HEROKU' in os.environ == 'yes' or 'STACK' in os.environ) and os.path.exists(os.path.join(BASE_DIR, "hc/heroku_settings.py")): + from .heroku_settings import * else: warnings.warn("local_settings.py not found, using defaults") diff --git a/hc/wsgi.py b/hc/wsgi.py index 4a9bf892..52fc1384 100644 --- a/hc/wsgi.py +++ b/hc/wsgi.py @@ -8,9 +8,10 @@ https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/ """ import os +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hc.settings") from django.core.wsgi import get_wsgi_application - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hc.settings") +from whitenoise.django import DjangoWhiteNoise application = get_wsgi_application() +application = DjangoWhiteNoise(application) diff --git a/requirements.in b/requirements.in new file mode 100644 index 00000000..dd31d353 --- /dev/null +++ b/requirements.in @@ -0,0 +1,9 @@ +croniter +Django +django_compressor +psycopg2 +pytz +requests +gunicorn +whitenoise +django-herokuify diff --git a/requirements.txt b/requirements.txt index 3d669c09..8bf24d2c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,28 @@ -croniter -Django==1.10.5 -django_compressor==2.1 +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile --output-file requirements.txt requirements.in +# +boto==2.46.1 # via django-herokuify +croniter==0.3.15 +dj-database-url==0.4.2 # via django-heroku-postgresify, django-herokuify +django-appconf==1.0.2 # via django-compressor +django-compressor==2.1.1 +django-heroku-memcacheify==1.0.0 # via django-herokuify +django-heroku-postgresify==0.4 # via django-herokuify +django-herokuify==1.0rc3 +django-pylibmc-sasl==0.2.4 # via django-herokuify +django-pylibmc==0.6.1 # via django-heroku-memcacheify +django-storages==1.5.2 # via django-herokuify +Django==1.10.5 # via django-heroku-postgresify, django-pylibmc-sasl +gunicorn==19.6.0 psycopg2==2.6.2 -pytz==2016.7 -requests==2.9.1 +pylibmc==1.5.1 # via django-herokuify, django-pylibmc, django-pylibmc-sasl +python-dateutil==2.6.0 # via croniter +pytz==2016.10 +rcssmin==1.0.6 # via django-compressor +requests==2.13.0 +rjsmin==1.0.12 # via django-compressor +six==1.10.0 # via python-dateutil +whitenoise==3.3.0 From 4593feda3d4023fb6fbe0daeb2f4464d908fa1df Mon Sep 17 00:00:00 2001 From: Ronald Ip Date: Thu, 23 Feb 2017 02:26:18 +0800 Subject: [PATCH 2/2] Heroku documentation. --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index cd54a777..78bf51d7 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,20 @@ The building blocks are: * Django 1.9 * PostgreSQL or MySQL +## Deploying to Heroku + +[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) + +Upon successful deploy via the Heroku Button, the [Postgresql](https://elements.heroku.com/addons/heroku-postgresql), [Mailgun](https://elements.heroku.com/addons/mailgun), and [Scheduler](https://elements.heroku.com/addons/scheduler) add-ons will be provisioned and configured for use. The initial database migration task will also be run. + +The site should now be running at `https://appname.herokuapp.com/`. + +### Heroku Configuration + +1. Create a superuser manually: `$ heroku run python manage.py createsuperuser --app `. + +2. Refer to [Sending Status Notifications](#sending-status-notifications) and [Database Cleanup](#database-cleanup) sections for tasks that are required to be scheduled via [Heroku's Scheduler add-on](https://devcenter.heroku.com/articles/scheduler#scheduling-jobs): `$ heroku addons:open scheduler`. + ## Setting Up for Development These are instructions for setting up HealthChecks Django app