Changeset - 67dd87d59abb
[Not reviewed]
0 6 0
Branko Majic (branko) - 9 years ago 2016-11-28 22:39:12
branko@majic.rs
MAR-83: Added support to wsgi_website role for specifying headers that should be passed on to Gunicorn by Nginx. Updated hello.wsgi app to demonstrate the feature.
6 files changed with 24 insertions and 3 deletions:
0 comments (0 inline, 0 general)
docs/rolereference.rst
Show inline comments
 
@@ -1561,24 +1561,31 @@ Parameters
 
  X.509 certificate used for TLS for HTTPS service. The file will be stored in
 
  directory ``/etc/ssl/certs/`` under name ``{{ fqdn }}_https.pem``.
 

	
 
**https_tls_key** (string, optional, ``{{ lookup('file', tls_private_key_dir + '/' + fqdn + '_https.key') }}``)
 
  Private key used for TLS for HTTPS service. The file will be stored in
 
  directory ``/etc/ssl/private/`` under name ``{{ fqdn }}_https.key``.
 

	
 
**packages** (list, optional, ``[]``)
 
  A list of additional packages to install for this particular WSGI
 
  website. This is usually going to be development libraries for building Python
 
  packages.
 

	
 
**proxy_headers** (dictionary, optional, ``{}``)
 
  Additional headers to set when proxying request to Gunicorn. Keys are header
 
  names, values are header values. Both should be compatible with Nginx
 
  ``proxy_set_header``. If you need to provide an empty value, use quotes (don't
 
  forget to surround them by another set of quotes for YAML syntax, for example
 
  ``"\"\""`` or ``'""'``).
 

	
 
**rewrites** (list, optional, ``[]``)
 
  A list of rewrite rules that are applied to incoming requests. Each element of
 
  the list should be a string value compatible with the format of ``nginx``
 
  option ``rewrite``. The keyword ``rewrite`` itself should be omitted, as well
 
  as trailing semi-colon (``;``).
 

	
 
**static_locations** (list, optional, ``[]``)
 
  List of locations that should be treated as static-only, and not processed by
 
  the WSGI application at all. This is normally used for designating serving of
 
  static/media files by Nginx (for example, in case of Django projects for
 
  ``/static/`` and ``/media/``).
 

	
 
@@ -1632,24 +1639,26 @@ running a bare Django project):
 
      futures_version: 3.0.5
 
      gunicorn_version: 19.6.0
 
      additional_nginx_config:
 
        - comment: Use custom page for forbidden files.
 
          value: error_page 403 /static/403.html;
 
        - comment: Use custom page for non-existing locations/files.
 
          value: error_page 404 /static/404.html;
 
      website_mail_recipients: "root john.doe@example.com"
 
      environment_indicator:
 
        background_colour: "green"
 
        text_colour: "black"
 
        text: "TEST ENVIRONMENT"
 
      proxy_headers:
 
        Accept-Encoding: '""'
 

	
 

	
 
Database Server
 
---------------
 

	
 
The ``database_server`` role can be used for setting-up a MariaDB database
 
server on destination machine.
 

	
 
The role implements the following:
 

	
 
* Installs MariaDB server and client.
 
* Configures MariaDB server and client to use *UTF-8* encoding by default.
docs/usage.rst
Show inline comments
 
@@ -1476,24 +1476,26 @@ on the safe side:
 
* An administrative user is created as well, and this user should be used when
 
  running maintenance and installation commands. Similar to application user,
 
  the name is also derived from the FQDN of website, for example
 
  ``admin-wiki_example_com``. Administrative user does not have a dedicated
 
  group, and instead belongs to same group as the application user. As
 
  convenience, whenever you switch to this user the Python virtual environment
 
  will be automatically activated for you.
 
* WSGI applications are executed via *Gunicorn*. The WSGI server listens on a
 
  Unix socket, making the socket accessible by *Nginx*.
 
* If you ever need to set some environment variables, this can easily be done
 
  via the ``environment_variables`` role parameter. This particular example does
 
  not set any, though.
 
* You can also specify headers to be passed on via Nginx ``proxy_set_header``
 
  directive to Gunicorn running the application.
 
* Mails deliverd to local admin/application users are forwarded to ``root``
 
  account instead (this can be configured via ``website_mail_recipients`` role
 
  parameter.
 
* If you ever find yourself mixing-up test and production websites, have a look
 
  at ``environment_indicator`` role parameter. It lets you insert small strip at
 
  bottom of each HTML page automatically.
 
* Static content is served directly by *Nginx*.
 
* Each web application gets distinct sub-directory under ``/var/www``, named
 
  after the FQDN. All sub-directories created under there are created with
 
  ``2750`` permissions, with ownership set to admin user, and group set to the
 
  application's group. In other words, all directories will have ``SGID`` bit
 
  set-up, allowing you to create files/directories that will have their group
roles/wsgi_website/defaults/main.yml
Show inline comments
 
@@ -5,13 +5,14 @@ enforce_https: True
 
packages: []
 
rewrites: []
 
static_locations: []
 
use_paste: False
 
virtualenv_packages: []
 
environment_variables: {}
 
admin: "web-{{ fqdn | replace('.', '_') }}"
 
https_tls_certificate: "{{ lookup('file', tls_certificate_dir + '/' + fqdn + '_https.pem') }}"
 
https_tls_key: "{{ lookup('file', tls_private_key_dir + '/' + fqdn + '_https.key') }}"
 
gunicorn_version: "19.6.0"
 
futures_version: "3.0.5"
 
website_mail_recipients: "root"
 
environment_indicator: null
 
\ No newline at end of file
 
environment_indicator: null
 
proxy_headers: {}
roles/wsgi_website/templates/nginx_site.j2
Show inline comments
 
@@ -54,24 +54,28 @@ server {
 

	
 
    # Pass remaining requests to the WSGI server.
 
    location / {
 
        try_files $uri @proxy_to_app;
 
    }
 

	
 
    location @proxy_to_app {
 
        proxy_set_header X-Forwarded-Proto $scheme;
 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 
        proxy_set_header Host $http_host;
 
        proxy_redirect off;
 

	
 
    {% for header, value in proxy_headers.iteritems() -%}
 
    proxy_set_header {{ header }} {{ value }};
 
    {% endfor -%}
 

	
 
        proxy_pass http://unix:/run/wsgi/{{ fqdn }}.sock;
 
    }
 

	
 
    {% if environment_indicator -%}
 
    # Show environment indicator on HTML pages.
 
    sub_filter_types text/html;
 
    sub_filter_once on;
 
    sub_filter "</body>" "<div id='website-environment' style='background-color: {{ environment_indicator.background_colour }}; width: 100%; text-align: center; position: fixed; bottom: 5px; color: {{ environment_indicator.text_colour }}; font-weight: bold;'>{{ environment_indicator.text }}</div></body>";
 
    {% endif -%}
 

	
 
    access_log /var/log/nginx/{{ fqdn }}-access.log;
 
    error_log /var/log/nginx/{{ fqdn }}-error.log;
testsite/group_vars/web.yml
Show inline comments
 
@@ -11,13 +11,16 @@ default_https_tls_key: "{{ lookup('file', inventory_dir + '/tls/web.' + testsite
 
default_https_tls_certificate: "{{ lookup('file', inventory_dir + '/tls/web.' + testsite_domain + '_https.pem') }}"
 

	
 
web_default_title: "Welcome to Example Inc."
 
web_default_message: "You are attempting to access the web server using a wrong name or an IP address. Please check your URL."
 

	
 
db_root_password: "root"
 

	
 
website_mail_recipients: "john.doe@example.com"
 

	
 
environment_indicator:
 
  background_colour: "purple"
 
  text_colour: "white"
 
  text: "Majic Ansible Roles Test Site"
 
\ No newline at end of file
 
  text: "Majic Ansible Roles Test Site"
 

	
 
proxy_headers:
 
  Accept-Encoding: '"gzip"'
testsite/playbooks/roles/wsgihello/files/hello.wsgi
Show inline comments
 
@@ -5,22 +5,24 @@ import os
 
def application(environ, start_response):
 
    status = '200 OK'
 

	
 
    template = """<!DOCTYPE html>
 
<html lang="en">
 
  <head>
 
    <meta charset="utf-8">
 
    <title>{title}</title>
 
  </head>
 
  <body>
 
    <h1>Hello, world!</h1>
 
    <p>I am website {title}</p>
 
    <p>Accept-Encoding header was set to {acceptencoding}</p>
 
  </body>
 
</html>
 
"""
 
    output = template.format(title=os.environ.get("WEBSITE_NAME", "that nobody set a name for :("))
 
    output = template.format(title=os.environ.get("WEBSITE_NAME", "that nobody set a name for :("),
 
                             acceptencoding=environ.get("HTTP_ACCEPT_ENCODING"))
 

	
 
    response_headers = [('Content-type', 'text/html'),
 
                        ('Content-Length', str(len(output)))]
 
    start_response(status, response_headers)
 

	
 
    return [output]
0 comments (0 inline, 0 general)