A charm layer for serving a Python 3 application as a WSGI service.
To implement this layer, add layer:wsgi
in your layer.yaml
:
includes: ['layer:wsgi', ...]
By default the layer will look for the WSGI application in /srv
, and will run the WSGI service as the wsgi
user. These settings can be overridden by including a wsgi.yaml
in the root of your charm:
application_root: '{path}'
username: '{username}'
The layer will add the following config options to the charm:
port: 80 # The port where the WSGI service should listen
provision_command: "" # A command to run in the application directory before running the WSGI application - e.g. for provisioning the database
pip_cache_dir: "" # The name of a folder within the application from which to install pip dependencies
wsgi_module: "wsgi:application" # The python path to the WSGI module and application
wsgi_logfile_path: "/var/log/wsgi.service.log" # Where to store logs for the WSGI service
apt_dependencies: "" # A space-separated list of apt dependencies for the WSGI application
environment_variables: "" # A space-separated list of environment variables to pass to the application. E.g.: 'VAR1=val1 VAR2=val2'
You can override the defaults by including these config options in your charm's config.yaml
explicitly, with a new default settings. E.g. to set a new location for the wsgi_module
:
options:
# Defaults for WSGI layer config options
wsgi_module:
default: "webapp.wsgi:application"
The WSGI application source code must be provided in application_root
(/srv
by default). This folder should contain the WSGI function, at the location specified in the wsgi_module
setting (wsgi:application
by default). If this folder contains a requirements.txt
file specifying python dependencies, then these dependencies will be installed.
You must then tell the WSGI layer when the WSGI application is in place by triggering the wsgi.source.available
reactive state, e.g.:
from charms.reactive import remove_state, set_state
@when('resources.build.available')
def update():
set_state('wsgi.source.available')
Once the service has been started, the wsgi.active
state will be set, which you can then use to do any final actions, e.g.:
from charmhelpers.core.hookenv import status_set
@when('wsgi.available')
def wsgi_running():
status_set('active', 'WSGI service running')
The WSGI layer adds the following relations to the charm:
website
: An implementation of thehttp
interface. This could be used attaching an HAProxy load-balancer, for example.
postgres
: An implementation of thepgsql
interface, for attaching a PostgreSQL database.mongo
: An implementation of themongodb
interface, for attaching a Mongo database.
Attaching either database type will result in the WSGI application being run with a DATABASE_URL
environment variables, which will contain information about the database, for use by the WSGI application:
DATABASE_URL="[postgresql|mongodb]://{db_user}:{db_password}@{db_host}:{db_port}/{database_name}"
The WSGI application is run with Gunicorn. The service is run with systemd, and the configuration will be installed into /etc/systemd/system/gunicorn3.service
. Logs from the gunicorn service are sent to the syslog and can be inspected with journalctl, e.g.:
journalctl -u gunicorn3.service