Support for virtualenv environments

The role can be used to run WSGI applications deployed in a virtualenv environment. To do this, you need to install a gunicorn Python module inside the environment at the same version as the Debian package. Below you can find instructions for doing that with Ansible.

The debops.gunicorn role deploys an Ansible local facts script which returns the version of the system gunicorn package. This fact can be accessed as:

ansible_local.gunicorn.version

In your role, you can define a YAML list which specifies what Python modules should be present in the virtualenv environment:

---

application__virtualenv_pip_packages:

  # Install compatible 'gunicorn' module inside the virtualenv
  - name: 'gunicorn'
    version: '{{ ansible_local.gunicorn.version|d(omit) }}'

  # Install 'setproctitle' for nice process names
  # (You'll need gcc and the python-dev or python3-dev package for this)
  - 'setproctitle'

Next, in your role task list, include set of tasks that will create the virtualenv environment and install the required modules inside:

---
- name: Install additional Python modules for gunicorn support
  pip:
    name:    '{{ item.name    | d(item) }}'
    version: '{{ item.version | d(omit) }}'
    virtualenv: '/path/to/virtualenv'
  with_flattened: '{{ application__virtualenv_pip_packages }}'
  become_user: 'app-user'

The above steps should ensure that the application deployed in the virtualenv environment can be started by the gunicorn service installed from the Debian packages. To do that, you can define the application using the role dependent variables in your role's defaults/main.yml file, like this:

---

application__gunicorn__dependent_applications:

  - name: 'virtualenv-app'
    working_dir: '/path/to/virtualenv/app/src'
    python: '/path/to/virtualenv/bin/python'
    mode: 'wsgi'
    user: 'app-user'
    group: 'app-group'
    args: [ '--bind=unix:/run/gunicorn/virtualenv-app.sock',
            '--workers={{ ansible_processor_vcpus|int + 1 }}',
            '--timeout=10' 'virtualenv-app.wsgi' ]

And the corresponding playbook which uses debops.gunicorn as a dependent role:

---

- name: Deploy the application
  hosts: [ 'application-hosts' ]
  become: True

  roles:

    - role: gunicorn
      gunicorn__dependent_applications:
        - '{{ application__gunicorn__dependent_applications }}'

    - role: application-role

Currently there's no way to request that the gunicorn service should be restarted apart from specifying the Restart gunicorn Ansible handler directly in your role, for example like this:

---

- name: Generate the application configuration
  template:
    src: 'path/to/virtualenv/app/src/config.j2'
    dest: '/path/to/virtualenv/app/src/config.j2'
    owner: 'app-user'
    group: 'app-group'
    mode: '0644'
  notify: [ 'Restart gunicorn' ]

This requires that the debops.gunicorn role is included in the playbook that manages your application. This restriction will be changed in the future, when Ansible handlers will be able to listen for notifications.