Ответ 1
ENV var представляется наиболее очевидным способом сделать это. Либо найдите ENV var, который вы знаете, либо установите свой собственный:
on_heroku = False
if 'YOUR_ENV_VAR' in os.environ:
on_heroku = True
У меня есть Django webapp, и я хочу проверить, работает ли он в стеке Heroku (для условного включения отладки и т.д.) Есть ли простой способ сделать это? Возможно, переменная среды?
Я знаю, что, возможно, я тоже могу сделать это наоборот - то есть, обнаружил ли он, что он работает на машине разработчика, но это просто не "правильно звучит".
ENV var представляется наиболее очевидным способом сделать это. Либо найдите ENV var, который вы знаете, либо установите свой собственный:
on_heroku = False
if 'YOUR_ENV_VAR' in os.environ:
on_heroku = True
Подобно тому, что предложил Нейл, я бы сделал следующее:
debug = True
if 'SOME_ENV_VAR' in os.environ:
debug = False
Я видел, как некоторые люди используют if 'PORT' in os.environ:
. Но, к сожалению, переменная PORT присутствует при локальном запуске foreman start
, поэтому нет возможности различать локальное тестирование с мастером и развертыванием на Heroku.
Я также рекомендую использовать один из env vars, который:
В момент публикации Heroku имеет следующие переменные окружения:
['PATH', 'PS1', 'COLUMNS', 'TERM', 'PORT', 'LINES', 'LANG', 'SHLVL', 'LIBRARY_PATH', 'PWD', 'LD_LIBRARY_PATH', 'PYTHONPATH', 'DYNO', 'PYTHONHASHSEED', 'PYTHONUNBUFFERED', 'PYTHONHOME', 'HOME', '_']
Обычно я использую if 'DYNO' in os.environ:
, потому что это, по-видимому, самый специфичный для Heroku (кто еще будет использовать термин dyno, верно?).
И я также предпочитаю форматировать его как оператор if-else, потому что он более явный:
if 'DYNO' in os.environ:
debug = False
else:
debug = True
Сначала установите переменную окружения ON_HEROKU
на герою:
$ heroku config:set ON_HEROKU=1
Тогда в settings.py
import os
# define if on heroku environment
ON_HEROKU = 'ON_HEROKU' in os.environ
Подробнее об этом читайте здесь: https://devcenter.heroku.com/articles/config-vars
Мое решение:
$ heroku config:set HEROKU=1
Эти переменные среды постоянны - они останутся на месте во всех развертываниях и перезагрузках приложений, поэтому, если вам не нужно изменять значения, вам нужно только установить их один раз.
Затем вы можете проверить его присутствие в своем приложении.:
>>> 'HEROKU' in os.environ
True
Самый надежный способ - установить переменную среды, как указано выше. Если это невозможно, есть несколько знаков, которые вы можете найти в файловой системе, но они не могут быть/не защищены.
У всех экземпляров Heroku есть путь /app
- файлы и скрипты, которые будут запущены, также находятся под этим, поэтому вы можете проверить наличие каталога и/или сценарии, запускаемые из он.
Существует пустая директория /etc/heroku
/etc/hosts
может быть добавлен ряд связанных с героем доменов
~ $ cat /etc/hosts
<snip>.dyno.rt.heroku.com
Любое из них может и может измениться в любой момент.
Ваше перемещение может варьироваться
Краткая версия: проверьте, что часовой пояс UTC/GMT:
if not 'ORIGINAL_TIMEZONE' in os.environ:
f = os.popen('date +%Z')
tz = f.read().upper()
os.environ['ORIGINAL_TIMEZONE']=tz
tz = os.environ['ORIGINAL_TIMEZONE']
if tz != '' and (not 'utc' in tz.lower()) and (not 'gmt' in tz.lower()):
print 'Definitely not running on Heroku (or in production in general)'
else:
print 'Assume that we are running on Heroku (or in production in general)'
Это более консервативно, чем if tz=='UTC\n'
: если сомневаетесь, предположите, что мы в производстве. Обратите внимание, что мы сохраняем часовой пояс для переменной среды, поскольку settings.py
может выполняться более одного раза. На самом деле сервер разработки выполняет его дважды, а во второй раз системный часовой пояс уже "UTC" (или что-то еще в settings.TIMEZONE
).
Длинная версия:
абсолютно уверен, что мы никогда не запускаем Heroku с DEBUG=True
, и что мы никогда не запускаем сервер разработки на Heroku даже с DEBUG=False
. Из settings.py
:
RUNNING_DEV_SERVER = (len(sys.argv) > 1) and (sys.argv[1] == 'runserver')
DEBUG = RUNNING_DEV_SERVER
TEMPLATE_DEBUG = DEBUG
# Detect the timezone
if not 'ORIGINAL_TIMEZONE' in os.environ:
f = os.popen('date +%Z')
tz = f.read().upper()
os.environ['ORIGINAL_TIMEZONE']=tz
print ('DEBUG: %d, RUNNING_DEV_SERVER: %d, system timezone: %s ' % (DEBUG, RUNNING_DEV_SERVER, tz))
if not (DEBUG or RUNNING_DEV_SERVER):
SECRET_KEY = os.environ['SECRET_KEY']
else:
print 'Running in DEBUG MODE! Hope this is not in production!'
SECRET_KEY = 'DEBUG_INSECURE_SECRET_KEY_ae$kh(7b%$+a fcw_bdnzl#)$t88x7h2-p%eg_ei5m=w&2p-)1+'
# But what if we are idiots and are still somehow running with DEBUG=True in production?!
# 1. Make sure SECRET_KEY is not set
assert not SECRET_KEY in os.environ
# 2. Make sure the timezone is not UTC or GMT (indicating production)
tz = os.environ['ORIGINAL_TIMEZONE']
assert tz != '' and (not 'UTC' in tz) and (not 'GMT' in tz)
# 3. Look for environment variables suggesting we are in PROD
for key in os.environ:
for red_flag in ['heroku', 'amazon', 'aws', 'prod', 'gondor']:
assert not red_flag in key.lower()
assert not red_flag in os.environ[key].lower()
Если вы действительно хотите запустить сервер разработки на Heroku, я предлагаю вам добавить переменную среды, указав дату, когда вы сможете это сделать. Тогда продолжайте, если эта дата сегодня. Таким образом вам придется изменить эту переменную до начала разработки, но если вы забудете ее отменить, на следующий день вы все равно будете защищены от случайного запуска ее в процессе производства. Конечно, если вы хотите быть суперконсервативным, вы также можете указать, скажем, 1-часовое окно, когда применяются исключения.
Наконец, если вы решили применить предложенный выше подход, пока вы на нем, установите django-security, добавьте djangosecurity
в INSTALLED_APPS
и добавьте в конец своего settings.py
:
if not (DEBUG or RUNNING_DEV_SERVER):
### Security
SECURE_SSL_REDIRECT = True
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_HSTS_SECONDS = 86400000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_BROWSER_XSS_FILTER = True
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
CSRF_COOKIE_HTTPONLY = True # May have problems with Ajax
CSRF_COOKIE_SECURE = True
DATABASE_URL
переменная окружения
in_heroku = False
if 'DATABASE_URL' in os.environ:
in_heroku = True
Я думаю, вам нужно включить базу данных для вашего приложения с помощью:
heroku addons:create heroku-postgresql:hobby-dev
но он свободен и вероятен, что вы собираетесь делать в любом случае.
Heroku делает эту переменную среды доступной при запуске своих приложений, в частности для использования в качестве:
import dj_database_url
if in_heroku:
DATABASES = {'default': dj_database_url.config()}
else:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
Не является надежным, поскольку эта переменная может быть определена локально, но удобна для простых случаев.
heroku run env
может также показать другие возможные переменные, например:
DYNO_RAM
WEB_CONCURRENCY
но я не уверен, что они документированы как DATABASE_URL
.