Changeset - 71bc6c4991f8
[Not reviewed]
0 3 0
Branko Majic (branko) - 7 years ago 2018-08-05 14:13:04
branko@majic.rs
MAR-132: Fix virtual environment set-up in wsgi_website role:

- Install more up-to-date version of pip. This fixes some issues
related to pip freeze detecting argparse and wsgiref in virtualenv
as separate packages.
- Remove the pkg-resources package from virtualenv. Workaround for
Debian-specific behaviour. More details at:
- https://github.com/pypa/pip/issues/4022
- https://bugs.launchpad.net/ubuntu/+source/python-pip/+bug/1635463
- https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=871790
- Deploy Gunicorn requirements file without switching to website admin
user (otherwise Ansible fails to template the file due to
permissions restrictions).
- Updated test for checking packages installed in the virtualenv.
3 files changed with 21 insertions and 6 deletions:
0 comments (0 inline, 0 general)
roles/wsgi_website/molecule/default/tests/test_default.py
Show inline comments
 
@@ -111,417 +111,413 @@ def test_environment_profile_configuration(host, profile_file, expected_group, e
 
    Tests if profile configuration file for setting-up environment variables has
 
    been deployed correctly.
 
    """
 

	
 
    with host.sudo():
 

	
 
        config = host.file(profile_file)
 
        assert config.is_file
 
        assert config.user == 'root'
 
        assert config.group == expected_group
 
        assert config.mode == 0o640
 
        assert config.content == expected_content
 

	
 

	
 
@pytest.mark.parametrize("admin_user, expected_virtualenv_path", [
 
    ('admin-parameters-mandatory', '/var/www/parameters-mandatory/virtualenv'),
 
    ('admin-parameters-optional_local', '/var/www/parameters-optional.local/virtualenv\nMy environment variable'),
 
    ('admin-parameters-paste-req', '/var/www/parameters-paste-req/virtualenv'),
 
])
 
def test_profile_configuration(host, admin_user, expected_virtualenv_path):
 
    """
 
    Tests if profile configuration is behaving correctly (setting appropriate
 
    vars via login shell).
 
    """
 

	
 
    env = host.run("sudo -i -u " + admin_user + " printenv VIRTUAL_ENV MY_ENV_VAR")
 
    assert env.stdout == expected_virtualenv_path
 

	
 

	
 
@pytest.mark.parametrize("app_user, expected_uid, expected_group, expected_home", [
 
    ('web-parameters-mandatory', 999, 'web-parameters-mandatory', '/var/www/parameters-mandatory'),
 
    ('web-parameters-optional_local', 5001, 'web-parameters-optional_local', '/var/www/parameters-optional.local'),
 
    ('web-parameters-paste-req', 998, 'web-parameters-paste-req', '/var/www/parameters-paste-req'),
 
])
 
def test_website_application_user(host, app_user, expected_uid, expected_group, expected_home):
 
    """
 
    Tests if website application user has been created correctly.
 
    """
 

	
 
    user = host.user(app_user)
 

	
 
    assert user.exists
 
    assert user.uid == expected_uid
 
    assert user.group == expected_group
 
    assert user.groups == [expected_group]
 
    assert user.shell == '/bin/sh'
 
    assert user.home == expected_home
 

	
 
    with host.sudo():
 
        umask = host.run("su -l " + app_user + " -c 'bash -c umask'")
 
        assert umask.stdout == '0007'
 

	
 

	
 
@pytest.mark.parametrize("expected_group", [
 
    'web-parameters-mandatory',
 
    'web-parameters-optional_local',
 
    'web-parameters-paste-req'
 
])
 
def test_nginx_user(host, expected_group):
 
    """
 
    Tests if web server user has been added to website group.
 
    """
 

	
 
    user = host.user('www-data')
 
    assert expected_group in user.groups
 

	
 

	
 
@pytest.mark.parametrize("forward_file, expected_group, expected_content", [
 
    ('/var/www/parameters-mandatory/.forward', 'web-parameters-mandatory', 'root'),
 
    ('/var/www/parameters-optional.local/.forward', 'web-parameters-optional_local', 'user'),
 
    ('/var/www/parameters-paste-req/.forward', 'web-parameters-paste-req', 'root'),
 
])
 
def test_forward_file(host, forward_file, expected_group, expected_content):
 
    """
 
    Tests if the forward file has correct permissions and content.
 
    """
 

	
 
    with host.sudo():
 

	
 
        config = host.file(forward_file)
 

	
 
        assert config.is_file
 
        assert config.user == 'root'
 
        assert config.group == expected_group
 
        assert config.mode == 0o640
 
        assert config.content == expected_content
 

	
 

	
 
@pytest.mark.parametrize("original_destination, expected_destination_user", [
 
    ('web-parameters-mandatory@localhost', 'vagrant'),
 
    ('web-parameters-optional_local@localhost', 'user'),
 
    ('web-parameters-paste-req@localhost', 'vagrant'),
 
])
 
def test_mail_forwarding(host, original_destination, expected_destination_user):
 
    """
 
    Tests if mail forwarding works as expected.
 
    """
 

	
 
    hostname = host.run('hostname').stdout
 

	
 
    send = host.run('swaks --suppress-data --to ' + original_destination)
 
    assert send.rc == 0
 
    message_id = re.search('Ok: queued as (.*)', send.stdout).group(1)
 

	
 
    # Sleep for a couple of seconds so the mail can get delivered.
 
    time.sleep(5)
 

	
 
    with host.sudo():
 
        mail_log = host.file('/var/log/mail.log')
 

	
 
        # First extract message ID of forwarded mail.
 
        pattern = "%s: to=<%s>.*status=sent \(forwarded as ([^)]*)\)" % (message_id, original_destination)
 
        message_id = re.search(pattern, mail_log.content).group(1)
 

	
 
        # Now try to determine where the forward ended-up at.
 
        pattern = "%s: to=<%s@%s>, orig_to=<%s>.*status=sent" % (message_id, expected_destination_user, hostname, original_destination)
 
        assert re.search(pattern, mail_log.content) is not None
 

	
 

	
 
@pytest.mark.parametrize("virtualenv_dir, expected_owner, expected_group", [
 
    ('/var/www/parameters-mandatory/virtualenv', 'admin-parameters-mandatory', 'web-parameters-mandatory'),
 
    ('/var/www/parameters-optional.local/virtualenv', 'admin-parameters-optional_local', 'web-parameters-optional_local'),
 
    ('/var/www/parameters-paste-req/virtualenv', 'admin-parameters-paste-req', 'web-parameters-paste-req'),
 
])
 
def test_python_virtualenv_created(host, virtualenv_dir, expected_owner, expected_group):
 
    """
 
    Tests if Python virtual environment has been created correctly.
 
    """
 

	
 
    with host.sudo():
 

	
 
        virtualenv = host.file(virtualenv_dir)
 
        assert virtualenv.is_directory
 
        assert virtualenv.user == expected_owner
 
        assert virtualenv.group == expected_group
 
        assert virtualenv.mode == 0o2750
 

	
 
        virtualenv_activate = host.file(virtualenv_dir + "/bin/activate")
 
        assert virtualenv_activate.is_file
 
        assert virtualenv_activate.user == expected_owner
 
        assert virtualenv_activate.group == expected_group
 
        # @TODO: Possibly due to some timing issues, this file might
 
        # end-up being 0640, particularly when switching Python
 
        # version in virtualenv.
 
        # assert virtualenv_activate.mode == 0o644
 

	
 

	
 
@pytest.mark.parametrize("project_file, expected_owner, expected_group", [
 
    ('/var/www/parameters-mandatory/virtualenv/.project', 'admin-parameters-mandatory', 'web-parameters-mandatory'),
 
    ('/var/www/parameters-optional.local/virtualenv/.project', 'admin-parameters-optional_local', 'web-parameters-optional_local'),
 
    ('/var/www/parameters-paste-req/virtualenv/.project', 'admin-parameters-paste-req', 'web-parameters-paste-req'),
 
])
 
def test_python_virtualenv_project_directory_config(host, project_file, expected_owner, expected_group):
 
    """
 
    Tests if project directory configuration within virtualenv is set-up
 
    correctly.
 
    """
 

	
 
    with host.sudo():
 

	
 
        project = host.file(project_file)
 

	
 
        assert project.is_file
 
        assert project.user == expected_owner
 
        assert project.group == expected_group
 
        assert project.mode == 0o640
 

	
 

	
 
@pytest.mark.parametrize("wrapper_script, expected_owner, expected_group", [
 
    ('/var/www/parameters-mandatory/virtualenv/bin/exec', 'admin-parameters-mandatory', 'web-parameters-mandatory'),
 
    ('/var/www/parameters-optional.local/virtualenv/bin/exec', 'admin-parameters-optional_local', 'web-parameters-optional_local'),
 
    ('/var/www/parameters-paste-req/virtualenv/bin/exec', 'admin-parameters-paste-req', 'web-parameters-paste-req'),
 
])
 
def test_python_virtualenv_wrapper_script(host, wrapper_script, expected_owner, expected_group):
 
    """
 
    Tests if Python virtualenv wrapper script is functioning correctly.
 
    """
 

	
 
    with host.sudo():
 

	
 
        wrapper = host.file(wrapper_script)
 
        assert wrapper.is_file
 
        assert wrapper.user == expected_owner
 
        assert wrapper.group == expected_group
 
        assert wrapper.mode == 0o750
 

	
 
        command = host.run("sudo -u %s %s python -c 'import gunicorn'" % (expected_owner, wrapper_script))
 
        assert command.rc == 0
 

	
 

	
 
@pytest.mark.parametrize("admin_user, pip_path, expected_packages",  [
 
    ('admin-parameters-mandatory', '/var/www/parameters-mandatory/virtualenv/bin/pip', [
 
        "argparse==1.2.1",
 
        "futures==3.2.0",
 
        "gunicorn==19.9.0",
 
        "wsgiref==0.1.2"
 
    ]),
 
    ('admin-parameters-optional_local', '/var/www/parameters-optional.local/virtualenv/bin/pip', [
 
        "Pygments==2.2.0",
 
        "dnspython==1.15.0",
 
        "docopt==0.6.2",
 
        "futures==3.1.0",
 
        "gunicorn==19.7.0",
 
        "jedi==0.12.1",
 
        "parso==0.3.1",
 
        "prompt-toolkit==1.0.15",
 
        "ptpython==0.41",
 
        "six==1.11.0",
 
        "wcwidth==0.1.7",
 
    ]),
 
    ('admin-parameters-paste-req', '/var/www/parameters-paste-req/virtualenv/bin/pip', [
 
        "Flask==0.12.2",
 
        "Jinja2==2.9.6",
 
        "MarkupSafe==1.0",
 
        "Paste==2.0.3",
 
        "PasteDeploy==1.5.2",
 
        "PasteScript==2.0.2",
 
        "Werkzeug==0.12.2",
 
        "argparse==1.2.1",
 
        "click==6.7",
 
        "futures==3.1.0",
 
        "gunicorn==19.7.0",
 
        "itsdangerous==0.24",
 
        "six==1.10.0",
 
        "wsgiref==0.1.2",
 
    ]),
 
])
 
def test_virtualenv_packages(host, admin_user, pip_path, expected_packages):
 
    """
 
    Tests if correct packages are installed in virtualenv.
 
    """
 

	
 
    packages = host.run("sudo -u %s %s freeze" % (admin_user, pip_path))
 

	
 
    # Normalise package names and order.
 
    expected_packages = sorted([p.lower() for p in expected_packages])
 
    actual_packages = sorted(packages.stdout.lower().split("\n"))
 

	
 
    assert actual_packages == expected_packages
 

	
 

	
 
@pytest.mark.parametrize('check_config_dir', [
 
    '/etc/pip_check_requirements_upgrades/parameters-mandatory',
 
    '/etc/pip_check_requirements_upgrades/parameters-optional.local',
 
])
 
def test_wsgi_requirements_upgrade_checks(host, check_config_dir):
 
    """
 
    Tests if Python requirements files for upgrade checks are set-up
 
    correctly (absent when not configured).
 
    """
 

	
 
    with host.sudo():
 
        directory = host.file(check_config_dir)
 
        assert not directory.exists
 

	
 

	
 
@pytest.mark.parametrize("config_file, expected_website_name, expected_socket_file_path", [
 
    ('/etc/systemd/system/parameters-mandatory.socket', 'parameters-mandatory', '/run/wsgi/parameters-mandatory.sock'),
 
    ('/etc/systemd/system/parameters-optional.local.socket', 'parameters-optional.local', '/run/wsgi/parameters-optional.local.sock'),
 
    ('/etc/systemd/system/parameters-paste-req.socket', 'parameters-paste-req', '/run/wsgi/parameters-paste-req.sock'),
 
])
 
def test_systemd_socket_configuration_file(host, config_file, expected_website_name, expected_socket_file_path):
 
    """
 
    Tests if systemd socket configuration file has been set-up correctly.
 
    """
 

	
 
    config = host.file(config_file)
 
    assert config.is_file
 
    assert config.user == 'root'
 
    assert config.group == 'root'
 
    assert config.mode == 0o644
 
    assert "Socket for website %s" % expected_website_name in config.content
 
    assert "ListenStream=%s" % expected_socket_file_path in config.content
 

	
 

	
 
@pytest.mark.parametrize("socket_file_path", [
 
    '/run/wsgi/parameters-mandatory.sock',
 
    '/run/wsgi/parameters-optional.local.sock',
 
    '/run/wsgi/parameters-paste-req.sock',
 
])
 
def test_systemd_socket(host, socket_file_path):
 
    """
 
    Tests if systemd socket has correct permissions and is available.
 
    """
 

	
 
    with host.sudo():
 

	
 
        socket_file = host.file(socket_file_path)
 
        assert socket_file.is_socket
 
        assert socket_file.user == 'www-data'
 
        assert socket_file.group == 'www-data'
 
        assert socket_file.mode == 0o660
 

	
 
        socket = host.socket("unix://%s" % socket_file_path)
 
        assert socket.is_listening
 

	
 

	
 
@pytest.mark.parametrize("service_file, expected_fqdn", [
 
    ('/etc/systemd/system/parameters-mandatory.service', 'parameters-mandatory'),
 
    ('/etc/systemd/system/parameters-optional.local.service', 'parameters-optional.local'),
 
    ('/etc/systemd/system/parameters-paste-req.service', 'parameters-paste-req'),
 
])
 
def test_systemd_service_configuration_file(host, service_file, expected_fqdn):
 
    """
 
    Tests if systemd service configuration file has been set-up correctly.
 
    """
 

	
 
    config = host.file(service_file)
 
    assert config.is_file
 
    assert config.user == 'root'
 
    assert config.group == 'root'
 
    assert config.mode == 0o644
 
    assert expected_fqdn in config.content
 

	
 

	
 
@pytest.mark.parametrize("service_name", [
 
    'parameters-mandatory',
 
    'parameters-optional.local',
 
    'parameters-paste-req',
 
])
 
def test_systemd_service(host, service_name):
 
    """
 
    Tests if the systemd service is enabled at boot and running.
 
    """
 

	
 
    service = host.service(service_name)
 

	
 
    assert service.is_enabled
 
    assert service.is_running
 

	
 

	
 
@pytest.mark.parametrize("directory_path, expected_owner, expected_group", [
 
    ('/var/www/parameters-mandatory/htdocs', 'admin-parameters-mandatory', 'web-parameters-mandatory'),
 
    ('/var/www/parameters-optional.local/htdocs', 'admin-parameters-optional_local', 'web-parameters-optional_local'),
 
    ('/var/www/parameters-paste-req/htdocs', 'admin-parameters-paste-req', 'web-parameters-paste-req'),
 
])
 
def test_static_file_directory(host, directory_path, expected_owner, expected_group):
 
    """
 
    Tests if directory for serving static files has been created correctly.
 
    """
 

	
 
    with host.sudo():
 

	
 
        directory = host.file(directory_path)
 
        assert directory.is_directory
 
        assert directory.user == expected_owner
 
        assert directory.group == expected_group
 
        assert directory.mode == 0o2750
 

	
 

	
 
@pytest.mark.parametrize("private_key_path, certificate_path, expected_private_key, expected_certificate", [
 
    ('/etc/ssl/private/parameters-mandatory_https.key', '/etc/ssl/certs/parameters-mandatory_https.pem',
 
     'tests/data/x509/parameters-mandatory_https.key', 'tests/data/x509/parameters-mandatory_https.pem'),
 
    ('/etc/ssl/private/parameters-optional.local_https.key', '/etc/ssl/certs/parameters-optional.local_https.pem',
 
     'tests/data/x509/parameters-optional.local_https.key.pem', 'tests/data/x509/parameters-optional.local_https.cert.pem'),
 
    ('/etc/ssl/private/parameters-paste-req_https.key', '/etc/ssl/certs/parameters-paste-req_https.pem',
 
     'tests/data/x509/parameters-paste-req_https.key.pem', 'tests/data/x509/parameters-paste-req_https.cert.pem'),
 
])
 
def test_nginx_tls_files(host, private_key_path, certificate_path, expected_private_key, expected_certificate):
 
    """
 
    Tests if TLS private key and certificate have been deployed correctly.
 
    """
 

	
 
    with host.sudo():
 

	
 
        tls_file = host.file(private_key_path)
 
        assert tls_file.is_file
 
        assert tls_file.user == 'root'
 
        assert tls_file.group == 'root'
 
        assert tls_file.mode == 0o640
 
        assert tls_file.content == open(expected_private_key, "r").read().rstrip()
 

	
 
        tls_file = host.file(certificate_path)
 
        assert tls_file.is_file
 
        assert tls_file.user == 'root'
 
        assert tls_file.group == 'root'
 
        assert tls_file.mode == 0o644
 
        assert tls_file.content == open(expected_certificate, "r").read().rstrip()
 

	
 

	
 
@pytest.mark.parametrize("config_file_path, expected_content", [
 
    ('/etc/check_certificate/parameters-mandatory_https.conf', '/etc/ssl/certs/parameters-mandatory_https.pem'),
 
    ('/etc/check_certificate/parameters-optional.local_https.conf', '/etc/ssl/certs/parameters-optional.local_https.pem'),
 
    ('/etc/check_certificate/parameters-paste-req_https.conf', '/etc/ssl/certs/parameters-paste-req_https.pem'),
 
])
 
def test_certificate_validity_check_configuration(host, config_file_path, expected_content):
 
    """
 
    Tests if certificate validity check configuration file has been deployed
 
    correctly.
 
    """
 

	
 
    config = host.file(config_file_path)
 
    assert config.is_file
 
    assert config.user == 'root'
 
    assert config.group == 'root'
 
    assert config.mode == 0o644
 
    assert config.content == expected_content
 

	
 

	
 
@pytest.mark.parametrize("config_file", [
 
    '/etc/nginx/sites-available/parameters-mandatory',
 
    '/etc/nginx/sites-available/parameters-optional.local',
 
    '/etc/nginx/sites-available/parameters-paste-req',
 
])
 
def test_vhost_file(host, config_file):
 
    """
 
    Tests permissions of vhost configuration file.
 
    """
 

	
 
    config = host.file(config_file)
 

	
 
    assert config.is_file
 
    assert config.user == 'root'
 
    assert config.group == 'root'
 
    assert config.mode == 0o640
 

	
 

	
roles/wsgi_website/tasks/main.yml
Show inline comments
 
---
 

	
 
- name: Create WSGI website group
 
  group:
 
    name: "{{ user }}"
 
    gid: "{{ uid | default(omit) }}"
 
    state: present
 

	
 
- name: Create WSGI website admin user
 
  user:
 
    name: "{{ admin }}"
 
    uid: "{{ admin_uid | default(omit) }}"
 
    group: "{{ user }}"
 
    shell: /bin/bash
 
    createhome: true
 
    home: "{{ home }}"
 
    state: present
 

	
 
- name: Set-up directory for storing user profile configuration files
 
  file:
 
    path: "{{ home }}/.profile.d"
 
    state: directory
 
    owner: "{{ admin }}"
 
    group: "{{ user }}"
 
    mode: 0750
 

	
 
- name: Deploy profile configuration file for auto-activating the virtual environment
 
  copy:
 
    src: "profile_virtualenv.sh"
 
    dest: "{{ home }}/.profile.d/virtualenv.sh"
 
    owner: root
 
    group: "{{ user }}"
 
    mode: 0640
 

	
 
- name: Deploy profile configuration file for setting environment variables
 
  template:
 
    src: "environment.sh.j2"
 
    dest: "{{ home }}/.profile.d/environment.sh"
 
    owner: root
 
    group: "{{ user }}"
 
    mode: 0640
 

	
 
- name: Create WSGI website user
 
  user:
 
    name: "{{ user }}"
 
    uid: "{{ uid | default(omit) }}"
 
    group: "{{ user }}"
 
    comment: "umask=0007"
 
    system: true
 
    createhome: false
 
    state: present
 
    home: "{{ home }}"
 

	
 
- name: Add nginx user to website group
 
  user:
 
    name: www-data
 
    groups: "{{ user }}"
 
    append: true
 
  notify:
 
    - Restart nginx
 

	
 
# Ownership set to root so Postfix would not check if correct user owns the
 
# file.
 
- name: Set-up forwarding for mails delivered to local application user/admin
 
  template:
 
    src: "forward.j2"
 
    dest: "{{ home }}/.forward"
 
    owner: root
 
    group: "{{ user }}"
 
    mode: 0640
 

	
 
- name: Install extra packages for website
 
  apt:
 
    name: "{{ item }}"
 
    state: present
 
  with_items: "{{ packages }}"
 
  register: install_extra_packages
 
  notify:
 
    - Restart WSGI services
 

	
 
- name: Set-up MariaDB mysql_config symbolic link for compatibility (workaround for Debian bug 766996)
 
  file:
 
    src: "/usr/bin/mariadb_config"
 
    dest: "/usr/bin/mysql_config"
 
    state: link
 
  when: "'libmariadb-client-lgpl-dev-compat' in packages"
 

	
 
# Ignore failures - the virtual environment might not have been
 
# created yet. Don't use --version because Python 2 outputs to stderr,
 
# and Python 3 outputs to stdout.
 
- name: Check current version of Python used in virtual environment (if any)
 
  command: "{{ home }}/virtualenv/bin/python -c \"import sys; print(sys.version.split(' ')[0])\""
 
  failed_when: false
 
  changed_when: false
 
  register: current_python_version
 

	
 
- name: Remove existing Python virtual environment (wrong Python version)
 
  file:
 
    path: "{{ home }}/virtualenv"
 
    state: absent
 
  when: "current_python_version.rc == 0 and not current_python_version.stdout.startswith(python_version | string)"
 
  notify:
 
    - Restart WSGI services
 

	
 
- name: Create directory for storing the Python virtual environment
 
  file:
 
    path: "{{ home }}/virtualenv"
 
    state: directory
 
    owner: "{{ admin }}"
 
    group: "{{ user }}"
 
    mode: 02750
 

	
 
- name: Create Python virtual environment
 
  command: '/usr/bin/virtualenv --python "{{ python_interpreter }}" --prompt "({{ fqdn }})" "{{ home }}/virtualenv"'
 
  args:
 
    creates: "{{ home }}/virtualenv/bin/{{ python_interpreter | basename }}"
 
  become: true
 
  become_user: "{{ admin }}"
 
  tags:
 
    # [ANSIBLE0012] Commands should not change things if nothing needs doing
 
    #   This task will not fire if the virtual environment has already bene
 
    #   created (thanks to 'creates' parameter).
 
    - skip_ansible_lint
 

	
 
- name: Install latest pip in virtual environment
 
  pip:
 
    name:
 
      - "pip>=18.0.0,<19.0.0"
 
    virtualenv: "{{ home }}/virtualenv"
 
  become: true
 
  become_user: "{{ admin }}"
 

	
 
# Workaround for:
 
#
 
# - https://github.com/pypa/pip/issues/4022
 
# - https://bugs.launchpad.net/ubuntu/+source/python-pip/+bug/1635463
 
# - https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=871790
 
- name: Remove the pkg-resources package from virtual environment (see comments above for details)
 
  pip:
 
    name: pkg-resources
 
    virtualenv: "{{ home }}/virtualenv"
 
    state: absent
 
  become: true
 
  become_user: "{{ admin }}"
 

	
 
- name: Configure project directory for the Python virtual environment
 
  template:
 
    src: "venv_project.j2"
 
    dest: "{{ home }}/virtualenv/.project"
 
    owner: "{{ admin }}"
 
    group: "{{ user }}"
 
    mode: 0640
 

	
 
- name: Deploy virtualenv wrapper
 
  template:
 
    src: "venv_exec.j2"
 
    dest: "{{ home }}/virtualenv/bin/exec"
 
    owner: "{{ admin }}"
 
    group: "{{ user }}"
 
    mode: 0750
 

	
 
- name: Install WSGI server
 
  become: true
 
  become_user: "{{ admin }}"
 
  pip:
 
    name: "{{ item.package }}"
 
    version: "{{ item.version }}"
 
    state: present
 
    virtualenv: "{{ home }}/virtualenv"
 
  with_items:
 
    - package: gunicorn
 
      version: "{{ gunicorn_version }}"
 
    - package: futures
 
      version: "{{ futures_version }}"
 
  when: "not wsgi_requirements"
 
  register: install_wsgi_server
 
  notify:
 
    - Restart WSGI services
 

	
 
- include: requirements.yml
 
  when: "wsgi_requirements"
 

	
 
- name: Install additional packages in Python virtual environment
 
  become: true
 
  become_user: "{{ admin }}"
 
  pip:
 
    name: "{{ virtualenv_packages }}"
 
    state: present
 
    virtualenv: "{{ home }}/virtualenv"
 
  register: install_additional_packages_in_virtualenv
 
  when: "virtualenv_packages"
 
  notify:
 
    - Restart WSGI services
 

	
 
- name: Deploy systemd socket configuration for website
 
  template:
 
    src: "systemd_wsgi_website.socket.j2"
 
    dest: "/etc/systemd/system/{{ fqdn }}.socket"
 
    owner: root
 
    group: root
 
    mode: 0644
 
  register: deploy_systemd_socket_configuration
 
  notify:
 
    - Reload systemd
 
    - Restart WSGI services
 

	
 
- name: Deploy systemd service configuration for website
 
  template:
 
    src: "systemd_wsgi_website.service.j2"
 
    dest: "/etc/systemd/system/{{ fqdn }}.service"
 
    owner: root
 
    group: root
 
    mode: 0644
 
  register: deploy_systemd_service_configuration
 
  notify:
 
    - Reload systemd
 
    - Restart WSGI services
 

	
 
- name: Enable the website service
 
  service:
 
    name: "{{ fqdn }}"
 
    enabled: true
 
    state: started
 

	
 
- name: Create directory where static files can be served from
 
  file:
 
    path: "{{ home }}/htdocs/"
 
    state: directory
 
    owner: "{{ admin }}"
 
    group: "{{ user }}"
 
    mode: 02750
 

	
 
- name: Deploy nginx TLS private key for website
 
  copy:
 
    dest: "/etc/ssl/private/{{ fqdn }}_https.key"
 
    content: "{{ https_tls_key }}"
 
    owner: root
 
    group: root
 
    mode: 0640
 
  notify:
 
    - Restart nginx
 

	
 
- name: Deploy nginx TLS certificate for website
 
  copy:
 
    dest: "/etc/ssl/certs/{{ fqdn }}_https.pem"
 
    content: "{{ https_tls_certificate }}"
 
    owner: root
 
    group: root
 
    mode: 0644
 
  notify:
 
    - Restart nginx
 

	
 
- name: Deploy configuration file for checking certificate validity via cron
 
  copy:
 
    content: "/etc/ssl/certs/{{ fqdn }}_https.pem"
 
    dest: "/etc/check_certificate/{{ fqdn }}_https.conf"
 
    owner: root
 
    group: root
 
    mode: 0644
 

	
 
- name: Deploy nginx configuration file for website
 
  template:
 
    src: "nginx_site.j2"
 
    dest: "/etc/nginx/sites-available/{{ fqdn }}"
 
    owner: root
 
    group: root
 
    mode: 0640
 
    validate: "/usr/local/bin/nginx_verify_site.sh -n '{{ fqdn }}' %s"
 
  notify:
 
    - Restart nginx
 

	
 
- name: Enable nginx website
 
  file:
 
    src: "/etc/nginx/sites-available/{{ fqdn }}"
 
    dest: "/etc/nginx/sites-enabled/{{ fqdn }}"
 
    state: link
 
  notify:
 
    - Restart nginx
 

	
 
- name: Set-up empty list of WSGI services to restart
 
  set_fact:
 
    wsgi_services_to_restart: []
 
  when: "wsgi_services_to_restart is not defined"
 
  tags:
 
    - handlers
 

	
 
- name: Add service to list of WSGI services to restart
 
  set_fact:
 
    wsgi_services_to_restart: "{{ wsgi_services_to_restart + [ fqdn ] }}"
 
  when: |
 
    fqdn not in wsgi_services_to_restart and
 
    ((install_extra_packages is defined and install_extra_packages.changed) or
 
    (install_wsgi_server is defined and install_wsgi_server.changed) or
 
    (install_additional_packages_in_virtualenv is defined and install_additional_packages_in_virtualenv.changed) or
 
    (deploy_systemd_socket_configuration is defined and deploy_systemd_socket_configuration.changed) or
 
    (deploy_systemd_service_configuration is defined and deploy_systemd_service_configuration.changed) or
 
    (install_gunciron_via_requirements is defined and install_gunciron_via_requirements.changed) or
 
    (handlers | default(False) | bool() == True))
 
  tags:
 
    - handlers
 
    # [ANSIBLE0016] Tasks that run when changed should likely be handlers
 
    #   This specific task is used in order to work around inability of Ansible
 
    #   to provide properly parametrised handlers for reusable roles.
 
    - skip_ansible_lint
 

	
 
- name: Explicitly run all handlers
 
  include: ../handlers/main.yml
 
  when: "handlers | default(False) | bool() == True"
 
  tags:
 
    - handlers
roles/wsgi_website/tasks/requirements.yml
Show inline comments
 
---
 

	
 
- name: Set-up directory for storing requirements file for upgrade checks
 
  file:
 
    path: "/etc/pip_check_requirements_upgrades/{{ fqdn }}"
 
    state: directory
 
    owner: root
 
    group: pipreqcheck
 
    mode: 0750
 

	
 
- name: Deploy WSGI requirements files for upgrade checks
 
  template:
 
    src: "{{ item }}.j2"
 
    dest: "/etc/pip_check_requirements_upgrades/{{ fqdn }}/{{ item }}"
 
    owner: root
 
    group: pipreqcheck
 
    mode: 0640
 
  with_items:
 
    - wsgi_requirements.in
 
    - wsgi_requirements.txt
 

	
 
- name: Deploy Gunicorn requirements file for installation purposes
 
  become: true
 
  become_user: "{{ admin }}"
 
  template:
 
    src: "wsgi_requirements.txt.j2"
 
    dest: "{{ home }}/.wsgi_requirements.txt"
 
    owner: "{{ admin }}"
 
    group: "{{ user }}"
 
    mode: 0640
 

	
 
- name: Install Gunicorn via requirements file
 
  become: true
 
  become_user: "{{ admin }}"
 
  pip:
 
    requirements: "{{ home }}/.wsgi_requirements.txt"
 
    state: present
 
    virtualenv: "{{ home }}/virtualenv"
 
  register: install_gunciron_via_requirements
 
  notify:
 
    - Restart WSGI services
0 comments (0 inline, 0 general)