Use whitenoise for serving static files

The usage of static files in the ARA API server is very limited.
They are used for displaying the API browser from django-rest-framework
and the Django admin interface.

By using whitenoise, Django can serve static files through "manage.py
runserver" and through the WSGI application without needing to enable
debug mode or adding specific routes.

This allows us to simplify the deployment a bit because we no longer
need to collect static files.
We're also taking this opportunity to simplify configuration a bit by no
longer exposing the following configuration options:

- STATIC_ROOT
- STATIC_URL
- MEDIA_ROOT
- MEDIA_URL

They'll still be loaded but there is no longer a use case for being able
to change the defaults -- at least for the time being.

Change-Id: I9fc853e84b3739fca574afcd2da799dc8c1fbad6
This commit is contained in:
David Moreau Simard 2019-03-06 09:43:56 -05:00
parent 63d0120ae2
commit 3b6b291967
No known key found for this signature in database
GPG Key ID: CBEB466764A9E621
11 changed files with 17 additions and 79 deletions

View File

@ -114,6 +114,7 @@ if EXTERNAL_AUTH:
# fmt: off
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
@ -155,9 +156,16 @@ USE_I18N = True
USE_L10N = True
LANGUAGE_CODE = "en-us"
# whitenoise serves static files without needing to use "collectstatic"
WHITENOISE_USE_FINDERS = True
STATIC_URL = settings.get("STATIC_URL", "/static/")
STATIC_ROOT = settings.get("STATIC_ROOT", os.path.join(BASE_DIR, "www", "static"))
# Create STATIC_ROOT if it doesn't exist to avoid a warning from whitenoise
# https://github.com/evansd/whitenoise/issues/215
if not os.path.isdir(STATIC_ROOT):
os.makedirs(STATIC_ROOT, mode=0o755)
MEDIA_URL = settings.get("MEDIA_URL", "/media/")
MEDIA_ROOT = settings.get("MEDIA_ROOT", os.path.join(BASE_DIR, "www", "media"))
@ -201,10 +209,6 @@ if not os.path.exists(DEFAULT_SETTINGS) and "ARA_SETTINGS" not in os.environ:
CORS_ORIGIN_ALLOW_ALL=CORS_ORIGIN_ALLOW_ALL,
SECRET_KEY=SECRET_KEY,
DATABASES=DATABASES,
STATIC_URL=STATIC_URL,
STATIC_ROOT=STATIC_ROOT,
MEDIA_URL=MEDIA_URL,
MEDIA_ROOT=MEDIA_ROOT,
DEBUG=DEBUG,
LOG_LEVEL=LOG_LEVEL,
LOGGING=LOGGING,

View File

@ -42,8 +42,6 @@ For more details, click on the configuration parameters.
+--------------------------------+------------------------------------------------------+------------------------------------------+
| ARA_ALLOWED_HOSTS_ | Django's ALLOWED_HOSTS_ setting | ``["127.0.0.1", "localhost", "::1"]`` |
+--------------------------------+------------------------------------------------------+------------------------------------------+
| ARA_STATIC_ROOT_ | Django's STATIC_ROOT_ setting | ``~/.ara/server/www/static`` |
+--------------------------------+------------------------------------------------------+------------------------------------------+
| ARA_DEBUG_ | Django's DEBUG_ setting | ``false`` |
+--------------------------------+------------------------------------------------------+------------------------------------------+
| ARA_SECRET_KEY_ | Django's SECRET_KEY_ setting | Randomized token, see ARA_SECRET_KEY_ |
@ -315,21 +313,6 @@ cryptographic signing, and should be set to a unique, unpredictable value.
If it is not set, a random token will be generated and persisted in the
default configuration file.
ARA_STATIC_ROOT
~~~~~~~~~~~~~~~
- **Environment variable**: ``ARA_STATIC_ROOT``
- **Configuration file variable**: ``STATIC_ROOT``
- **Provided by**: Django's STATIC_ROOT_
- **Type**: ``string``
- **Default**: ``~/.ara/server/www/static``
The absolute path to the directory where Django's collectstatic command will
collect static files for deployment.
The static files are required for the built-in API browser by
django-rest-framework.
ARA_DATABASE_ENGINE
~~~~~~~~~~~~~~~~~~~

View File

@ -6,3 +6,4 @@ django-cors-headers
django-filter
dynaconf[yaml]
requests>=2.14.2
whitenoise

View File

@ -36,7 +36,6 @@ What the role ends up doing by default:
- Generates a random secret key if none are already configured or provided
- Sets up API configuration in ``~/.ara/server/settings.yaml``
- Runs the API SQL migrations (``ara-manage migrate``)
- Collects static files (``ara-manage collectstatic``) into ``~/.ara/www``
About deployment topologies
---------------------------
@ -88,7 +87,6 @@ Install ARA and set up the API to be served by nginx in front of gunicorn::
ansible_python_interpreter: /usr/bin/python3
ara_web_server: nginx
ara_wsgi_server: gunicorn
ara_www_dir: /var/www/ara
ara_api_fqdn: api.ara.example.org
ara_allowed_hosts:
- api.ara.example.org

View File

@ -19,7 +19,6 @@
# Root directories in which data, configuration and logs will be stored
ara_root_dir: "{{ ansible_user_dir }}/.ara" # git repos, virtualenvs, sqlite db
ara_log_dir: "{{ ara_root_dir }}/logs" # logs
ara_www_dir: "{{ ara_root_dir }}/www" # django collectstatic assets (html/css/js)
# Whether or not ara should be installed in a virtual environment.
# Running ara in a virtualenv is recommended to avoid conflicting with
@ -50,10 +49,6 @@ ara_install_version: feature/1.0
# The web server for serving the ARA API
# It is recommended to specify a web server when deploying a production environment.
# When setting a web server, you'll need to set "ara_www_dir" to a location the
# web server has access to.
# If no web server are specified, the Ansible role will set "ara_debug" to true
# in order to let Django serve the static files for the admin interface and the
# API browser.
# - none (null - default)
# - nginx (recommended)
@ -135,28 +130,13 @@ ara_allowed_hosts:
- "{{ ansible_default_ipv4['address'] }}"
# ARA_DEBUG - Django's DEBUG setting
# If a web server is specified, this will default to false.
# If no web server is specified, this will default to true in order to let
# Django serve a minimum amount of static files.
# It is not recommended to run with debug enabled in production.
ara_debug: "{{ (ara_web_server is none) | ternary(true, false) }}"
ara_debug: false
# ARA_SECRET_KEY - Django's SECRET_KEY setting
# Note: If no key is provided, a random one will be generated once and persisted
ara_secret_key: null
# ARA_STATIC_ROOT - Djangos STATIC_ROOT setting
ara_static_root: "{{ ara_www_dir }}/static"
# ARA_STATIC_URL - Django's STATIC_URL setting
ara_static_url: /static/
# ARA_MEDIA_ROOT - Django's MEDIA_ROOT setting
ara_media_root: "{{ ara_www_dir }}/media"
# ARA_MEDIA_URL - Django's MEDIA_URL setting
ara_media_url: /media/
# ARA_DATABASE_ENGINE - Djangos ENGINE database setting
ara_database_engine: django.db.backends.sqlite3

View File

@ -29,9 +29,3 @@
name: ara-api
state: restarted
when: ara_api_service_enabled is not changed
# Is there a better way ? Static files are not created with the httpd context
- name: restore selinux context for static files
become: "{{ (ansible_user_dir in ara_www_dir) | ternary(false, true) }}"
command: "restorecon -Rv {{ ara_www_dir }}"
when: ansible_os_family == "RedHat"

View File

@ -78,10 +78,6 @@
DEBUG: "{{ ara_debug }}"
LOGGING: "{{ ara_logging }}"
LOG_LEVEL: "{{ ara_log_level }}"
MEDIA_ROOT: "{{ ara_media_root }}"
MEDIA_URL: "{{ ara_media_url }}"
STATIC_ROOT: "{{ ara_static_root }}"
STATIC_URL: "{{ ara_static_url }}"
SECRET_KEY: "{{ ara_secret_key }}"
set_fact:
ara_api_configuration: "{'{{ ara_env }}': {{ reconciled_configuration }} }"

View File

@ -34,15 +34,6 @@
- name: Include configuration of the database engine
include_tasks: "database_engine/{{ ara_database_engine }}.yaml"
- name: Collect static files
become: "{{ (ansible_user_dir in ara_www_dir) | ternary(false, true) }}"
environment:
ARA_SETTINGS: "{{ ara_settings }}"
PATH: "{{ path_with_virtualenv | default(omit) }}"
command: ara-manage collectstatic --clear --no-input
notify:
- restore selinux context for static files
- name: Include installation of the WSGI backend server
include_tasks: "wsgi_server/{{ ara_wsgi_server }}.yaml"

View File

@ -73,10 +73,3 @@
path: "{{ ara_log_dir }}"
state: directory
mode: 0750
- name: Ensure ara_www_dir exists
become: "{{ (ansible_user_dir in ara_www_dir) | ternary(false, true) }}"
file:
path: "{{ ara_www_dir }}"
state: directory
mode: 0755

View File

@ -12,19 +12,18 @@ server {
access_log /var/log/nginx/{{ ara_api_fqdn }}_access.log;
error_log /var/log/nginx/{{ ara_api_fqdn }}_error.log;
# /static contains files from "ara-manage collectstatic"
location /static {
alias {{ ara_www_dir }}/static;
expires 7d;
add_header Cache-Control "public";
}
# There's nothing at /, redirect it to the actual API for convenience
location / {
return 301 http://{{ ara_api_fqdn }}/api/v1/;
}
location /api/v1/ {
location /static {
expires 7d;
add_header Cache-Control "public";
}
# Everything, including static files, is served by the backend
location ~ {
# checks if the file exists, if not found proxy to app
try_files $uri @proxy_to_app;
}

View File

@ -30,7 +30,6 @@ setenv =
[testenv:runserver]
commands =
ara-manage migrate
ara-manage collectstatic --clear --no-input
ara-manage runserver
setenv =
ARA_DEBUG=true