wsgi app #2
Description
This charm should be able to serve most simple WSGI applications. It can hook into postgresql or mongodb databases (whose locations will be available to the app as DATABASE_URL and MONGO_URL environment variables), provides HTTP interfaces for load-balancing, and you can pass any extra environment variables for your application through the environment_variables config option.
- Tags:
- app-servers ›
charm-bootstrap-wsgi
This repo is a template charm for any juju deployed wsgi service. As is, this charm deploys an example wsgi service with nagios checks and simple rolling upgrades.
You can re-use this charm to deploy any wsgi service by updating the playbook.yaml file. All of the wsgi functionality is provided by a reusable wsgi-app ansible role (see roles/wsgi-app) together with the gunicorn charm.
Disclaimer: this template does not try to explain what's possible with either ansible or juju - but if you know a bit about both, it will show you how you can easily use them together.
Deploying the charm
Make sure you've got a bootstrapped juju environment ready, and then:
$ mkdir -p ~/charms/precise && cd ~/charms/precise
$ git clone https://github.com/absoludity/charm-bootstrap-wsgi
$ cd charm-bootstrap-wsgi
$ make deploy
You should now be able to curl your service to see it working:
$ make curl
juju run --service wsgi-example "curl -s http://localhost:8080"
- MachineId: "1"
Stdout: 'It works! Revision 1'
UnitId: charm-bootstrap-wsgi/0
- MachineId: "2"
Stdout: 'It works! Revision 1'
UnitId: charm-bootstrap-wsgi/1
You can also see the output of all the configured nagios checks, including the check_http added by the playbook, by running:
$ make nagios
Your custom deployment code
To deploy your own custom wsgi application, open up the playbook.yml In addition to the wsgi-app reusable role and the optional nagios reusable role (nrpe-external-master), it only has two tasks:
- installing any package dependencies
- Re-rendering the app's config file (and triggering a wsgi restart)
If you find yourself needing to do more than this, let me know :-)
For simplicity, the default example app is deployed from the charm itself with the archived code in the charm's files directory. But the wsgi-app role also allows you to define a code_assets_uri, which if set, will be used instead of the charm's files directory.
The nagios check used for your app can be updated by adjusting the check_params passed to the role in playbook.yml (or you can additionally add further nagios checks depending on your needs).
A rolling upgrade example
Assuming you've already deployed the example service, we first update the configuration so that the units continue to run the 'r1' build (current_symlink), while simultaneously ensuring that the 'r2' build is installed and ready to run:
$ juju set wsgi-example current_symlink=r1 build_label=r2
Next, manually set just one unit to use the r2 build:
$ juju run --unit wsgi-example/0 "CURRENT_SYMLINK=r2 actions/set-current-symlink"
PLAY [localhost] **************************************************************
GATHERING FACTS ***************************************************************
ok: [localhost]
TASK: [wsgi-app | Manually set current symlink.] ******************************
changed: [localhost]
NOTIFIED: [wsgi-app | Restart wsgi] *******************************************
changed: ...
PLAY RECAP ********************************************************************
localhost : ok=3 changed=2 unreachable=0 failed=0
Verify that the new revision is working correctly on the one instance:
$ make curl
juju run --service wsgi-example "curl -s http://localhost:8080"
- MachineId: "1"
Stdout: 'It works! Revision 2'
UnitId: wsgi-example/0
- MachineId: "2"
Stdout: 'It works! Revision 1'
UnitId: wsgi-example/1
Update any others, or when you're confident, update the full set with:
$ juju set wsgi-example current_symlink=r2
and then verify that all units are service the latest with make curl
again.
Note about test Dependencies
The makefile to run tests requires the following dependencies
- python-nose
- python-mock
- python-flake8
installable via:
$ sudo apt-get install python-nose python-mock python-flake8
Configuration
- apt_dependencies
- (string) A space-separated list of apt dependencies to install
- archive_filename
- (string) The filename for the archive - e.g. "code_archive.tgz"
- build_label
- (string) The build label given to the code archive and corresponding to the path from which the archived code should be installed. For example, a value of 'r2' tells the charm to use the archive at 'r2/code_archive.tgz'.
- code_assets_uri
- (string) An optional URI to download the archive from This shouldn't be the whole URI but the earlier part (e.g.: 'https://example.com/AUTH/container') for this format: {{ code_assets_uri }}/{{ build_label }}/{{ archive_filename }} NB: The URI should *not* include a trailing slash
- current_symlink
- (string) The symlink of the code to run. The default of 'latest' will use the most recently added build on the instance. Specifying a differnt label (eg. "r235") will symlink to that directory assuming it has been previously added to the instance.
- latest
- environment_variables
- (string) A space separated list of environment variables for the app - in Bash variable syntax
- http_protocol
- (string) The protocol of the manager-service interface.
- http
- nagios_http_status
- (int) The expected HTTP status of the nagios check
- 200
- nagios_index_content
- (string) A string to check for inside the index page response - for nagios to test
- nagios_index_path
- (string) The path within the URI to the index page of the website - for nagios to test
- /
- pip_cache_path
- (string) The location of the pip-cache to install requirements from. If pip-cache is present, pip will not attempt to connect to PyPi, and instead look for requirements in the specified cache folder.
- requirements_path
- (string) The location of the requirements file within the archive. Requirements in this file will be installed with `pip install`
- update_make_target
- (string) After the code is extracted, the charm will run: $ make <update_make_target> in the project directory. You can define this make target in your project to run any commands necessary to update your app
- wsgi_application
- (string) The WSGI application within the archive, in Python notation E.g.: my_app.wsgi:application