Changeset - 2b3af82bc50e
[Not reviewed]
0 3 5
Branko Majic (branko) - 9 years ago 2017-04-19 23:03:15
branko@majic.rs
MAR-98: Updated testsite to include another WSGI hello world role that utilises wsgi_requirements in wsgi_website role, as well as pip-tools. Purposefully installs some outdated packages for testing the upgrade checks.
8 files changed with 104 insertions and 0 deletions:
0 comments (0 inline, 0 general)
docs/testsite.rst
Show inline comments
 
.. _testsite:
 

	
 
Test Site
 
=========
 

	
 
*Majic Ansible Roles* comes with a small sample test site configuration which
 
demonstrates use of every role. This test site also serves as starting point for
 
developing new roles etc, and can be used for testing regressions/breakages.
 

	
 
The test site covers everything, starting from generating the Debian preseed
 
files, through bootstrap process for new nodes, and onto deployment of all
 
remaining roles.
 

	
 
By default, the test site uses domain ``example.com``, but it has been designed
 
so it is easy to set your own domain (see below in step-by-step
 
instructions). Some changes may be necessary to listed commands in that case
 
(i.e. replace every occurance of ``example.com`` with your own domain).
 

	
 
All example commands listed within this section should be ran from within the
 
``testsite`` directory in order to have proper environment available for
 
playbook runs.
 

	
 
A number of playbooks is provided out of the box:
 

	
 
bootstrap.yml (for bootstrapping fresh nodes)
 
  This playbook can be used for bootstrapping fresh nodes. By default, the
 
  entire test site will be included in the bootstrap. If you wish to limit
 
  bootstrap to a single server, just run the playbook with (for example):
 

	
 
  .. code-block:: shell
 

	
 
    ansible-playbook -l ldap.example.com playbooks/bootstrap.yml
 

	
 
ldap.yml
 
  This playbook sets-up the LDAP servers. It is included in ``site.yml``.
 

	
 
mail.yml
 
  This playbook sets-up the mail server. It is included in ``site.yml``.
 

	
 
preseed.yml
 
  This playbook sets-up the Debian preseed files. It is included in
 
  ``site.yml``.
 

	
 
site.yml
 
  This playbook sets-up all servers, including preseed files on local host.
 

	
 
web.yml
 
  This playbook sets-up the web server. It is included in ``site.yml``.
 

	
 
xmpp.yml
 
  This playbook sets-up the XMPP server. It is included in ``site.yml``.
 

	
 
backup.yml
 
  This playbook sets-up the backup server. It is included in ``site.yml``.
 

	
 
In order to deploy the test site, the following steps would normally be taken:
 

	
 
1. As mentioned in introduction, default domain used by test site is
 
   ``example.com``. To change it, perform the following steps (otherwise, just
 
   skip to step 2):
 

	
 
   a. Update the file ``hosts``. Simply replace all occurances of
 
      ``example.com`` with your chosen domain.
 
   b. Update the file ``group_vars/all.yml``, changing the value of variable
 
      ``testsite_domain``. This value will then be used to calculate some of
 
      derived values, like LDAP base DN (which will be set to something along
 
      the lines of ``dc=example,dc=com`` or
 
      ``dc=your,dc=domain,dc=components``).
 

	
 
2. If you do not wish to have the hassle of creating the private keys and
 
   issuing certificates, there is a small playbook that can help you with
 
   this. Just run the ``tls.yml`` playbook, and skip to step 6 (otherwise follow
 
   steps 3 through 5):
 

	
 
   .. code-block:: shell
 

	
 
     ansible-playbook playbooks/tls.yml
 

	
 
3. Create TLS private keys (relative to top level directory), making sure to
 
   change domain in filenames if necessary:
 

	
 
   - ``testsite/tls/mail.example.com_imap.key``
 
   - ``testsite/tls/mail.example.com_smtp.key``
 
   - ``testsite/tls/xmpp.example.com_xmpp.key``
 
   - ``testsite/tls/ldap.example.com_ldap.key``
 
   - ``testsite/tls/web.example.com_https.key``
 
   - ``testsite/tls/phpfino.example.com_https.key``
 
   - ``testsite/tls/wsgi.example.com_https.key``
 
   - ``testsite/tls/wsgireq.example.com_https.key``
 

	
 
4. Issue TLS certificates corresponding to the generated TLS private keys
 
   (correct FQDN for DNS subject alternative name **must** be used), making sure
 
   to change domain in filenames if necessary:
 

	
 
   - ``testsite/tls/mail.example.com_imap.pem`` (subject alternative name should
 
     be ``mail.example.com``)
 
   - ``testsite/tls/mail.example.com_smtp.pem`` (subject alternative name should
 
     be ``mail.example.com``)
 
   - ``testsite/tls/xmpp.example.com_xmpp.pem`` (subject alternative name should
 
     be ``xmpp.example.com``)
 
   - ``testsite/tls/ldap.example.com_ldap.pem`` (subject alternative name should
 
     be ``ldap.example.com``)
 
   - ``testsite/tls/web.example.com_https.pem`` (subject alternative name should
 
     be ``web.example.com``)
 
   - ``testsite/tls/web.example.com_https.pem`` (subject alternative name should
 
     be ``web.example.com``)
 
   - ``testsite/tls/phpinfo.example.com_https.pem`` (subject alternative name
 
     should be ``phpinfo.example.com``)
 
   - ``testsite/tls/wsgi.example.com_https.pem`` (subject alternative name
 
     should be ``wsgi.example.com``)
 
   - ``testsite/tls/wsgireq.example.com_https.pem`` (subject alternative name
 
     should be ``wsgireq.example.com``)
 

	
 
5. Create ``PEM`` truststore file which contains all CA certificates that form
 
   CA chain for the issued end entity certificates from previous step at
 
   location ``testsite/tls/ca.pem``. It is very important to
 
   include the full CA chain used for LDAP server.
 

	
 
6. Generate SSH keys to be used by the backup server and backup clients:
 

	
 
  .. code-block:: shell
 

	
 
     mkdir ssh
 
     ssh-keygen -f ssh/backup_server_dsa_key -N '' -t dsa
 
     ssh-keygen -f ssh/backup_server_rsa_key -N '' -t rsa
 
     ssh-keygen -f ssh/backup_server_ed25519_key -N '' -t ed25519
 
     ssh-keygen -f ssh/backup_server_ecdsa_key -N '' -t ecdsa
 
     ssh-keygen -f ssh/mail.example.com -N ''
 
     ssh-keygen -f ssh/ldap.example.com -N ''
 
     ssh-keygen -f ssh/xmpp.example.com -N ''
 
     ssh-keygen -f ssh/web.example.com -N ''
 
     ssh-keygen -f ssh/backup.example.com -N ''
 
     ssh-keygen -f ssh/ws01.example.com -N ''
 

	
 
7. Set-up a local GnuPG keyring that will contain the necessary encryption and
 
   signing keys for the backup clients::
 

	
 
     mkdir ./backup_keyring
 
     chmod 700 ./backup_keyring
 
     cat << EOF | gpg2 --homedir ./backup_keyring --batch --gen-key
 
     Key-Type:RSA
 
     Key-Length:1024
 
     Name-Real:ldap.example.com
 
     Expire-Date:0
 
     %commit
 

	
 
     Key-Type:RSA
 
     Key-Length:1024
 
     Name-Real:mail.example.com
 
     Expire-Date:0
 
     %commit
 

	
 
     Key-Type:RSA
 
     Key-Length:1024
 
     Name-Real:web.example.com
 
     Expire-Date:0
 
     %commit
 

	
 
     Key-Type:RSA
 
     Key-Length:1024
 
     Name-Real:xmpp.example.com
 
     Expire-Date:0
 
     %commit
 

	
 
     Key-Type:RSA
 
     Key-Length:1024
 
     Name-Real:backup.example.com
 
     Expire-Date:0
 
     %commit
 

	
 
     Key-Type:RSA
 
     Key-Length:1024
 
     Name-Real:ws01.example.com
 
     Expire-Date:0
 
     %commit
 
     EOF
 

	
 
8. Generate the preseed files:
 

	
 
  .. code-block:: shell
 

	
 
     ansible-playbook playbooks/preseed.yml
 

	
 
9. Install all servers using the generated preseed files. All servers except
 
   ``ws01.example.com`` are supposed to be running *Debian 8 Jessie*. The server
 
   ``ws01.example.com`` is meant to run *Debian 9 Stretch* (althogh, Debian
 
   Jessie should function as well).
 

	
 
10. Add the SSH host fingerprints to your ``known_hosts`` file (don't forget to
 
    remove old entries if you are redoing the process). You can easily obtain all
 
    the necessary fingerprints with command (don't forget to modify domain if you
 
    need to):
 

	
 
    .. code-block:: shell
 

	
 
      ssh-keyscan -t ed25519 mail.example.com ldap.example.com xmpp.example.com web.example.com backup.example.com ws01.example.com $(resolveip -s mail.example.com) $(resolveip -s ldap.example.com) $(resolveip -s xmpp.example.com) $(resolveip -s web.example.com) $(resolveip -s backup.example.com) $(resolveip -s ws01.example.com)
 

	
 
11. Invoke the ``bootstrap.yml`` playbook in order to set-up some basic
 
    environment for Ansible runs on all servers:
 

	
 
    .. code-block:: shell
 

	
 
       ansible-playbook playbooks/bootstrap.yml
 

	
 
12. Finally, apply configuration on all servers:
 

	
 
    .. code-block:: shell
 

	
testsite/playbooks/roles/wsgihello2/files/hello.wsgi
Show inline comments
 
new file 100644
 
#!/usr/bin/env python
 

	
 
import os
 
import ipcalc
 

	
 
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>
 
    <p>Available IP range for subnet {subnet} is from {subnet_first} to {subnet_last}</p>
 
  </body>
 
</html>
 
"""
 
    subnet = ipcalc.Network('10.128.128.0/24')
 

	
 
    output = template.format(title=os.environ.get("WEBSITE_NAME", "that nobody set a name for :("),
 
                             acceptencoding=environ.get("HTTP_ACCEPT_ENCODING"),
 
                             subnet=str(subnet),
 
                             subnet_first=subnet.host_first(),
 
                             subnet_last=subnet.host_last())
 

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

	
 
    return [output]
testsite/playbooks/roles/wsgihello2/files/requirements.in
Show inline comments
 
new file 100644
 
ipcalc
 
\ No newline at end of file
testsite/playbooks/roles/wsgihello2/files/requirements.txt
Show inline comments
 
new file 100644
 
ipcalc==1.1.3
testsite/playbooks/roles/wsgihello2/meta/main.yml
Show inline comments
 
new file 100644
 
---
 

	
 
dependencies:
 
  - role: wsgi_website
 
    fqdn: wsgireq.{{ testsite_domain }}
 
    admin_uid: 3002
 
    uid: 2002
 
    wsgi_application: wsgi:application
 
    static_locations:
 
      - /static/
 
    https_tls_key: "{{ lookup('file', inventory_dir + '/tls/wsgireq.' + testsite_domain + '_https.key') }}"
 
    https_tls_certificate: "{{ lookup('file', inventory_dir + '/tls/wsgireq.' + testsite_domain + '_https.pem') }}"
 
    environment_variables:
 
      WEBSITE_NAME: "Majic Ansible Roles Test Site"
 
    wsgi_requirements:
 
      - futures==3.0.1
 
      - gunicorn==19.6.0
 
  - role: database
 
    db_name: wsgi_{{ testsite_domain_underscores }}
 
    db_password: wsgi_{{ testsite_domain_underscores }}
 
\ No newline at end of file
testsite/playbooks/roles/wsgihello2/tasks/main.yml
Show inline comments
 
new file 100644
 
---
 

	
 
- name: Create directory for storing code
 
  file: dest="/var/www/wsgireq.{{ testsite_domain }}/code/" state=directory
 
        owner="admin-wsgireq_{{ testsite_domain_underscores }}" group="web-wsgireq_{{ testsite_domain_underscores }}" mode=2750
 

	
 
- name: Deploy requirements and its source for upgrade checks
 
  copy: src="{{ item }}" dest="/etc/pip_check_requirements_upgrades/{{ item }}"
 
        owner="root" group="pipreqcheck" mode=640
 
  with_items:
 
    - requirements.in
 
    - requirements.txt
 

	
 
- name: Deploy requirements
 
  copy: src="{{ item }}" dest="/var/www/wsgireq.{{ testsite_domain }}/code/"
 
        owner="admin-wsgireq_{{ testsite_domain_underscores }}" group="web-wsgireq_{{ testsite_domain_underscores }}" mode=640
 
  with_items:
 
    - requirements.txt
 

	
 
- name: Install latest version of pip
 
  become_user: "admin-wsgireq_{{ testsite_domain_underscores }}"
 
  pip: name=pip state=latest virtualenv="/var/www/wsgireq.{{ testsite_domain }}/virtualenv"
 

	
 
- name: Deploy pip-tools
 
  become_user: "admin-wsgireq_{{ testsite_domain_underscores }}"
 
  pip: name=pip-tools state=present virtualenv="/var/www/wsgireq.{{ testsite_domain }}/virtualenv"
 

	
 
- name: Synchronise virtual environment with requirements file
 
  become_user: "admin-wsgireq_{{ testsite_domain_underscores }}"
 
  command: "'/var/www/wsgireq.{{ testsite_domain }}/virtualenv/bin/exec' pip-sync ~/code/requirements.txt ~/.wsgi_requirements.txt"
 
  register: pip_sync_result
 
  changed_when: "pip_sync_result.stdout != 'Everything up-to-date'"
 
  notify:
 
    - Restart website wsgireq.{{ testsite_domain }}
 

	
 
- name: Deploy WSGI application
 
  copy: src="hello.wsgi" dest="/var/www/wsgireq.{{ testsite_domain }}/code/wsgi.py"
 
        owner="admin-wsgireq_{{ testsite_domain_underscores }}" group="web-wsgireq_{{ testsite_domain_underscores }}" mode=640
 
  notify:
 
    - Restart website wsgireq.{{ testsite_domain }}
 
\ No newline at end of file
testsite/playbooks/tls.yml
Show inline comments
 
---
 

	
 
- hosts: preseed
 
  vars:
 
    host_tls_info:
 
      - hostname: ldap
 
        service: ldap
 
        name: LDAP
 
      - hostname: mail
 
        service: imap
 
        name: IMAP
 
      - hostname: mail
 
        service: smtp
 
        name: SMTP
 
      - hostname: phpinfo
 
        service: https
 
        name: PHP Info
 
      - hostname: web
 
        service: https
 
        name: Web
 
      - hostname: wsgi
 
        service: https
 
        name: WSGI Hello World
 
      - hostname: wsgireq
 
        service: https
 
        name: WSGI Hello World
 
      - hostname: xmpp
 
        service: xmpp
 
        name: XMPP
 
  tasks:
 
    - name: Create GnuTLS certificate templates for all hosts
 
      template: src="../tls/gnutls_server_certificate.cfg.j2" dest="../tls/{{ item.hostname }}.{{ testsite_domain }}_{{ item.service }}.cfg"
 
      with_items: host_tls_info
 
    - name: Create the CA key
 
      command: certtool --sec-param high --generate-privkey --outfile ../tls/ca.key
 
      args:
 
        creates: ../tls/ca.key
 
    - name: Create the CA certificate
 
      command: certtool --template ../tls/ca.cfg --generate-self-signed --load-privkey ../tls/ca.key --outfile ../tls/ca.pem
 
      args:
 
        creates: ../tls/ca.pem
 
    - name: Create private keys for all hosts
 
      command: certtool --sec-param normal --generate-privkey --outfile "../tls/{{ item.hostname }}.{{ testsite_domain }}_{{ item.service }}.key"
 
      with_items: host_tls_info
 
      args:
 
        creates: "../tls/{{ item.hostname }}.{{ testsite_domain }}_{{ item.service }}.key"
 
    - name: Issue certificates for all hosts
 
      shell: sleep 1 && certtool --generate-certificate
 
             --load-ca-privkey "../tls/ca.key" --load-ca-certificate "../tls/ca.pem"
 
             --template "../tls/{{ item.hostname }}.{{ testsite_domain }}_{{ item.service }}.cfg"
 
             --load-privkey "../tls/{{ item.hostname }}.{{ testsite_domain }}_{{ item.service }}.key"
 
             --outfile "../tls/{{ item.hostname }}.{{ testsite_domain }}_{{ item.service }}.pem"
 
      with_items: host_tls_info
 
      args:
 
        creates: "../tls/{{ item.hostname }}.{{ testsite_domain }}_{{ item.service }}.pem"
 
\ No newline at end of file
testsite/playbooks/web.yml
Show inline comments
 
---
 

	
 
- hosts: web
 
  remote_user: ansible
 
  become: yes
 
  roles:
 
    - common
 
    - ldap_client
 
    - mail_forwarder
 
    - database_server
 
    - web_server
 
    - phpinfo
 
    - wsgihello
 
    - wsgihello2
 
\ No newline at end of file
0 comments (0 inline, 0 general)