From 09ba06020d8564ecc76a07090fd021d486a2c68d Mon Sep 17 00:00:00 2001 From: David Moreau Simard Date: Fri, 1 Feb 2019 14:29:10 -0500 Subject: [PATCH] Import Ansible roles for setting up ara-server This commits imports two bootstrapped Ansible roles: - ara_server for installing and configuring ara-server - ara_frontend_nginx for setting up vhosts with nginx The roles are integration tested by new Zuul jobs on Fedora and Ubuntu. Change-Id: I06c7a2e9fb3f61fa451053543971de89d438fef4 --- .zuul.yaml => .zuul.d/zuul.yaml | 32 ++++ playbooks/ara-server.yaml | 7 + roles/ara_frontend_nginx/README.rst | 30 +++ roles/ara_frontend_nginx/handlers/main.yaml | 24 +++ roles/ara_frontend_nginx/meta/main.yaml | 36 ++++ roles/ara_frontend_nginx/tasks/main.yaml | 65 +++++++ .../templates/ara-server.conf.j2 | 41 +++++ roles/ara_frontend_nginx/vars/Fedora.yaml | 21 +++ roles/ara_frontend_nginx/vars/Ubuntu.yaml | 21 +++ roles/ara_server/README.rst | 73 ++++++++ roles/ara_server/defaults/main.yaml | 171 ++++++++++++++++++ roles/ara_server/files/ara-gunicorn.te | 14 ++ roles/ara_server/handlers/main.yaml | 30 +++ roles/ara_server/meta/main.yaml | 36 ++++ roles/ara_server/tasks/config.yaml | 104 +++++++++++ .../django.db.backends.sqlite3.yaml | 34 ++++ roles/ara_server/tasks/install/source.yaml | 55 ++++++ roles/ara_server/tasks/main.yaml | 55 ++++++ roles/ara_server/tasks/pre-requirements.yaml | 63 +++++++ .../tasks/wsgi_server/gunicorn.yaml | 64 +++++++ .../templates/ara-server.service.j2 | 22 +++ roles/ara_server/vars/Fedora.yaml | 22 +++ roles/ara_server/vars/Ubuntu.yaml | 21 +++ 23 files changed, 1041 insertions(+) rename .zuul.yaml => .zuul.d/zuul.yaml (68%) create mode 100644 playbooks/ara-server.yaml create mode 100644 roles/ara_frontend_nginx/README.rst create mode 100644 roles/ara_frontend_nginx/handlers/main.yaml create mode 100644 roles/ara_frontend_nginx/meta/main.yaml create mode 100644 roles/ara_frontend_nginx/tasks/main.yaml create mode 100644 roles/ara_frontend_nginx/templates/ara-server.conf.j2 create mode 100644 roles/ara_frontend_nginx/vars/Fedora.yaml create mode 100644 roles/ara_frontend_nginx/vars/Ubuntu.yaml create mode 100644 roles/ara_server/README.rst create mode 100644 roles/ara_server/defaults/main.yaml create mode 100644 roles/ara_server/files/ara-gunicorn.te create mode 100644 roles/ara_server/handlers/main.yaml create mode 100644 roles/ara_server/meta/main.yaml create mode 100644 roles/ara_server/tasks/config.yaml create mode 100644 roles/ara_server/tasks/database_engine/django.db.backends.sqlite3.yaml create mode 100644 roles/ara_server/tasks/install/source.yaml create mode 100644 roles/ara_server/tasks/main.yaml create mode 100644 roles/ara_server/tasks/pre-requirements.yaml create mode 100644 roles/ara_server/tasks/wsgi_server/gunicorn.yaml create mode 100644 roles/ara_server/templates/ara-server.service.j2 create mode 100644 roles/ara_server/vars/Fedora.yaml create mode 100644 roles/ara_server/vars/Ubuntu.yaml diff --git a/.zuul.yaml b/.zuul.d/zuul.yaml similarity index 68% rename from .zuul.yaml rename to .zuul.d/zuul.yaml index 8aadcf2..d17ecf2 100644 --- a/.zuul.yaml +++ b/.zuul.d/zuul.yaml @@ -51,6 +51,34 @@ - name: github.com/ansible/ansible override-checkout: stable-2.6 +- job: + name: ara-server-role-integration-base + parent: base + files: + - playbooks/* + - roles/ara_frontend_nginx/* + - roles/ara_server/* + - ara/* + - tests/* + - .zuul.d/* + - setup.py + - setup.cfg + - requirements.txt + - test-requirements.txt + required-projects: + - openstack/ara-server + run: playbooks/ara-server.yaml + +- job: + name: ara-server-role-integration-ubuntu + parent: ara-server-role-integration-base + nodeset: ubuntu-bionic + +- job: + name: ara-server-role-integration-fedora + parent: ara-server-role-integration-base + nodeset: fedora-latest + - project: check: jobs: @@ -59,8 +87,12 @@ - ara-integration-fedora-devel: voting: false - ara-integration-ubuntu-2.6 + - ara-server-role-integration-ubuntu + - ara-server-role-integration-fedora gate: jobs: - ara-infra-website - ara-integration-fedora-2.7 - ara-integration-ubuntu-2.6 + - ara-server-role-integration-ubuntu + - ara-server-role-integration-fedora diff --git a/playbooks/ara-server.yaml b/playbooks/ara-server.yaml new file mode 100644 index 0000000..15aaa87 --- /dev/null +++ b/playbooks/ara-server.yaml @@ -0,0 +1,7 @@ +- name: Deploy ara-server + hosts: all + gather_facts: yes + vars: + ansible_python_interpreter: /usr/bin/python3 + roles: + - ara_server diff --git a/roles/ara_frontend_nginx/README.rst b/roles/ara_frontend_nginx/README.rst new file mode 100644 index 0000000..cc7617f --- /dev/null +++ b/roles/ara_frontend_nginx/README.rst @@ -0,0 +1,30 @@ +ansible-role-ara-frontend-nginx +=============================== + +Ansible role to install and configure nginx to serve instances of ara-server +and ara-web. + +While this role can be used by itself, it is meant to be used alongside the +Ansible roles for ara-server and ara-web. + +It is currently tested and supported against Ubuntu 18.04 and Fedora 29. + +Copyright +========= + +:: + + Copyright (c) 2019 Red Hat, Inc. + + ARA Records Ansible is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ARA Records Ansible is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ARA Records Ansible. If not, see . diff --git a/roles/ara_frontend_nginx/handlers/main.yaml b/roles/ara_frontend_nginx/handlers/main.yaml new file mode 100644 index 0000000..b0b485a --- /dev/null +++ b/roles/ara_frontend_nginx/handlers/main.yaml @@ -0,0 +1,24 @@ +--- +# Copyright (c) 2019 Red Hat, Inc. +# +# This file is part of ARA Records Ansible. +# +# ARA Records Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ARA Records Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with ARA Records Ansible. If not, see . + +- name: restart nginx + become: true + service: + name: nginx + state: restarted + when: ara_nginx_enabled is not changed diff --git a/roles/ara_frontend_nginx/meta/main.yaml b/roles/ara_frontend_nginx/meta/main.yaml new file mode 100644 index 0000000..46b9a08 --- /dev/null +++ b/roles/ara_frontend_nginx/meta/main.yaml @@ -0,0 +1,36 @@ +--- +# Copyright (c) 2019 Red Hat, Inc. +# +# This file is part of ARA Records Ansible. +# +# ARA Records Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ARA Records Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with ARA Records Ansible. If not, see . + +galaxy_info: + author: David Moreau-Simard + description: Role to set up nginx for ara-server and ara-web + license: GPLv3 + min_ansible_version: 2.7 + platforms: + - name: Fedora + versions: + - 29 + - name: Ubuntu + versions: + - bionic + galaxy_tags: + - ansible + - ara + - ara-server + +dependencies: [] diff --git a/roles/ara_frontend_nginx/tasks/main.yaml b/roles/ara_frontend_nginx/tasks/main.yaml new file mode 100644 index 0000000..ddf4f43 --- /dev/null +++ b/roles/ara_frontend_nginx/tasks/main.yaml @@ -0,0 +1,65 @@ +--- +# Copyright (c) 2019 Red Hat, Inc. +# +# This file is part of ARA Records Ansible. +# +# ARA Records Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ARA Records Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with ARA Records Ansible. If not, see . + +- name: Include OS family/distribution specific variables + include_vars: "{{ item }}" + with_first_found: + - "{{ ansible_distribution }}.yaml" + - "{{ ansible_os_family }}.yaml" + +- become: yes + block: + - name: Install nginx + package: + name: nginx + state: present + + - name: Set selinux boolean to allow nginx to reverse proxy + seboolean: + name: httpd_can_network_connect + state: yes + persistent: yes + when: ansible_os_family == "RedHat" + + - when: + - ara_server_frontend_fqdn is defined + - ara_server_wsgi_bind is defined + - ara_server_www_dir is defined + block: + - name: Set up the ara-server nginx vhost + template: + src: "{{ ara_nginx_server_vhost | default('ara-server.conf.j2') }}" + dest: "{{ ara_nginx_config_path }}/ara-server.conf" + notify: + - restart nginx + + - name: Enable the nginx configuration on Debian-like systems + file: + src: "{{ ara_nginx_config_path }}/ara-server.conf" + dest: /etc/nginx/sites-enabled/ara-server.conf + state: link + when: ansible_os_family == 'Debian' + notify: + - restart nginx + + - name: Enable and start nginx + service: + name: nginx + state: started + enabled: yes + register: ara_nginx_enabled diff --git a/roles/ara_frontend_nginx/templates/ara-server.conf.j2 b/roles/ara_frontend_nginx/templates/ara-server.conf.j2 new file mode 100644 index 0000000..1f591d4 --- /dev/null +++ b/roles/ara_frontend_nginx/templates/ara-server.conf.j2 @@ -0,0 +1,41 @@ +upstream ara_server { + # fail_timeout=0 means we always retry an upstream even if it failed + # to return a good HTTP response + server {{ ara_server_wsgi_bind }} fail_timeout=0; +} + +server { + listen 80; + keepalive_timeout 5; + server_name {{ ara_server_frontend_fqdn }}; + + access_log /var/log/nginx/{{ ara_server_frontend_fqdn }}_access.log; + error_log /var/log/nginx/{{ ara_server_frontend_fqdn }}_error.log; + + # /static contains files from "ara-manage collectstatic" + location /static { + alias {{ ara_server_www_dir }}/static; + expires 1; + access_log off; + add_header Cache-Control "public"; + } + + # There's nothing at /, redirect it to the actual API for convenience + location / { + return 301 http://{{ ara_server_frontend_fqdn }}/api/v1/; + } + + location /api/v1/ { + # checks if the file exists, if not found proxy to app + try_files $uri @proxy_to_app; + } + + location @proxy_to_app { + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Host $http_host; + + proxy_redirect off; + proxy_pass http://ara_server; + } +} diff --git a/roles/ara_frontend_nginx/vars/Fedora.yaml b/roles/ara_frontend_nginx/vars/Fedora.yaml new file mode 100644 index 0000000..164743e --- /dev/null +++ b/roles/ara_frontend_nginx/vars/Fedora.yaml @@ -0,0 +1,21 @@ +--- +# Copyright (c) 2019 Red Hat, Inc. +# +# This file is part of ARA Records Ansible. +# +# ARA Records Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ARA Records Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with ARA Records Ansible. If not, see . + +ara_nginx_user: nginx +ara_nginx_group: nginx +ara_nginx_config_path: /etc/nginx/conf.d diff --git a/roles/ara_frontend_nginx/vars/Ubuntu.yaml b/roles/ara_frontend_nginx/vars/Ubuntu.yaml new file mode 100644 index 0000000..6f0120e --- /dev/null +++ b/roles/ara_frontend_nginx/vars/Ubuntu.yaml @@ -0,0 +1,21 @@ +--- +# Copyright (c) 2019 Red Hat, Inc. +# +# This file is part of ARA Records Ansible. +# +# ARA Records Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ARA Records Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with ARA Records Ansible. If not, see . + +ara_nginx_user: www-data +ara_nginx_group: www-data +ara_nginx_config_path: /etc/nginx/sites-available diff --git a/roles/ara_server/README.rst b/roles/ara_server/README.rst new file mode 100644 index 0000000..0d3f476 --- /dev/null +++ b/roles/ara_server/README.rst @@ -0,0 +1,73 @@ +ansible-role-ara-server +======================= + +This Ansible role provides a framework for installing one or many instances of +`ara-server `_ in a variety of +opinionated deployment topologies. + +It is currently tested and supported against Ubuntu 18.04 and Fedora 29. + +Role Variables +============== + +See ``defaults/main.yaml``. + +TL;DR +===== + +This is what the role does by default out of the box: + +- Installs required packages +- Creates a user for running ara-server +- Creates standard directories (``/var/lib/ara``, ``/etc/ara``, ``/var/log/ara``, ``/var/www/ara-server``) +- Retrieves ara-server from source +- Installs ara-server in a virtualenv +- Generates a random secret key if none are provided or already configured +- Configures ``/etc/ara/settings.yaml`` +- Runs SQL migrations (``ara-manage migrate``) +- Installs gunicorn in the same virtualenv as ara-server +- Sets up a systemd unit file for running ara-server with gunicorn +- Collects static files (``ara-manage collectstatic``) into ``/var/www/ara-server`` +- Includes the ``ara_frontend_nginx`` role to install and configure nginx as a reverse proxy to gunicorn + +About deployment topologies +=========================== + +This Ansible role is designed to support different opinionated topologies that +can be selected with role variables. + +For example, the following role variables are used to provide the topology from +the ``TL;DR`` above: + +- ``ara_server_install_method: source`` +- ``ara_server_wsgi_server: gunicorn`` +- ``ara_server_database_engine: django.db.backends.sqlite3`` +- ``ara_server_frontend_server: nginx`` + +The intent is that as the role gains support for other install methods, +wsgi servers, frontend servers or database engines, it will be possible to +mix and match according to preference or requirements. + +Perhaps ara-server could be installed from pypi and run with uwsgi, nginx and mysql. +Or maybe it could be installed from distribution packages and set up to run with apache, mod_wsgi and postgresql. +Or any combination of any of those. + +Copyright +========= + +:: + + Copyright (c) 2019 Red Hat, Inc. + + ARA Records Ansible is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ARA Records Ansible is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ARA Records Ansible. If not, see . diff --git a/roles/ara_server/defaults/main.yaml b/roles/ara_server/defaults/main.yaml new file mode 100644 index 0000000..f060513 --- /dev/null +++ b/roles/ara_server/defaults/main.yaml @@ -0,0 +1,171 @@ +--- +# Copyright (c) 2019 Red Hat, Inc. +# +# This file is part of ARA Records Ansible. +# +# ARA Records Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ARA Records Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with ARA Records Ansible. If not, see . + +#################################### +# ara-server installation settings +#################################### +# User that runs the ara-server process and owns the files for the installation. +ara_server_user: ara + +# Group for that user +ara_server_group: ara + +# Root directories in which data, configuration and logs will be stored +ara_server_home_dir: /var/lib/ara # git repos, virtualenvs, sqlite db +ara_server_config_dir: /etc/ara # settings.yaml +ara_server_log_dir: /var/log/ara # logs +ara_server_www_dir: /var/www/ara-server # django collectstatic assets (html/css/js) + +# Whether or not ara-server should be installed in a virtual environment. +# Running ara-server in a virtualenv is recommended to avoid conflicting with +# system-wide python packages. +ara_server_venv: true + +# Location where the virtualenv will be stored +ara_server_venv_path: "{{ ara_server_home_dir }}/venv/ara-server" + +# How ara-server will be installed +# source (default): installs from a local or remote git repository specified by ara_server_source +# pypi (planned): installs from pypi +ara_server_install_method: source + +# Version of ara-server to install +# This can be a git ref (tag, branch, commit) when installing from source or +# it can be a version number released to PyPi. +# When using "latest" as the source version, HEAD will be used +# When using "latest" as the pypi version, the latest release will be used +ara_server_install_version: latest + +# The source where the git repository can be cloned from. +# Can be an URL to a git repository or the path to a local repository on disk. +ara_server_source: "https://git.openstack.org/openstack/ara-server" + +# Location where ara-server will be checked out when installing from source +ara_server_source_checkout: "{{ ara_server_home_dir }}/git/ara-server" + +# The WSGI server for running ara-server's django application +# - gunicorn (default) +# - uwsgi (planned) +# - mod_wsgi (planned) +ara_server_wsgi_server: gunicorn + +# Address and port on which the wsgi server will bind +ara_server_wsgi_bind: "127.0.0.1:8000" + +# The frontend server for serving the ara-server wsgi +# - nginx (default) +# - apache (planned) +ara_server_frontend_server: nginx + +# The domain the frontend server will be listening on +ara_server_frontend_fqdn: api.ara.example.org + +#################################### +# ara-server configuration settings +# For more information, see documentation: https://ara-server.readthedocs.io/en/latest/configuring.html +#################################### + +# ARA_BASE_DIR - Default directory for storing data and configuration +ara_server_base_dir: "{{ ara_server_home_dir }}/server" + +# ARA_SETTINGS - Path to an ara-server configuration file +ara_server_settings: "{{ ara_server_config_dir }}/settings.yaml" + +# ARA_ENV - Environment to load configuration for +ara_server_env: default + +# ARA_LOG_LEVEL - Log level of the different components +ara_server_log_level: INFO + +# ARA_LOGGING - Python logging configuration +ara_server_logging: + disable_existing_loggers: false + formatters: + normal: + format: '%(asctime)s %(levelname)s %(name)s: %(message)s' + handlers: + console: + class: logging.handlers.TimedRotatingFileHandler + formatter: normal + level: "{{ ara_server_log_level }}" + filename: "{{ ara_server_log_dir }}/server.log" + when: 'midnight' + interval: 1 + backupCount: 30 + loggers: + ara: + handlers: + - console + level: "{{ ara_server_log_level }}" + propagate: 0 + root: + handlers: + - console + level: "{{ ara_server_log_level }}" + version: 1 + +# ARA_CORS_ORIGIN_ALLOW_ALL - django-cors-headers’s CORS_ORIGIN_WHITELIST_ALLOW_ALL setting +ara_server_cors_origin_allow_all: false + +# ARA_CORS_ORIGIN_WHITELIST - django-cors-headers’s CORS_ORIGIN_WHITELIST setting +ara_server_cors_origin_whitelist: + - "127.0.0.1:8000" + - "localhost:3000" + +# ARA_SERVER_ALLOWED_HOSTS - Django’s ALLOWED_HOSTS setting +ara_server_allowed_hosts: + - "127.0.0.1" + - "localhost" + - "::1" + +# ARA_DEBUG - Django's DEBUG setting +ara_server_debug: false + +# ARA_SECRET_KEY - Django's SECRET_KEY setting +# Note: If no key is provided, a random one will be generated once and persisted +ara_server_secret_key: null + +# ARA_STATIC_ROOT - Django’s STATIC_ROOT setting +ara_server_static_root: "{{ ara_server_www_dir }}/static" + +# ARA_STATIC_URL - Django's STATIC_URL setting +ara_server_static_url: "/static/" + +# ARA_MEDIA_ROOT - Django's MEDIA_ROOT setting +ara_server_media_root: "{{ ara_server_www_dir }}/media" + +# ARA_MEDIA_URL - Django's MEDIA_URL setting +ara_server_media_url: "/media/" + +# ARA_DATABASE_ENGINE - Django’s ENGINE database setting +ara_server_database_engine: django.db.backends.sqlite3 + +# ARA_DATABASE_NAME - Django’s NAME database setting +ara_server_database_name: "{{ ara_server_home_dir }}/server/ansible.sqlite" + +# ARA_DATABASE_USER - Django’s USER database setting +ara_server_database_user: null + +# ARA_DATABASE_PASSWORD - Django’s PASSWORD database setting +ara_server_database_password: null + +# ARA_DATABASE_HOST - Django’s HOST database setting +ara_server_database_host: null + +# ARA_DATABASE_PORT - Django’s PORT database setting +ara_server_database_port: null diff --git a/roles/ara_server/files/ara-gunicorn.te b/roles/ara_server/files/ara-gunicorn.te new file mode 100644 index 0000000..8fda81e --- /dev/null +++ b/roles/ara_server/files/ara-gunicorn.te @@ -0,0 +1,14 @@ +module ara-gunicorn 1.0; + +require { + type var_lib_t; + type postgresql_db_t; + type init_t; + class file { execute execute_no_trans getattr open read }; + class lnk_file { getattr read }; +} + +#============= init_t ============== +allow init_t postgresql_db_t:file { getattr open read }; +allow init_t var_lib_t:file { execute execute_no_trans }; +allow init_t var_lib_t:lnk_file { getattr read }; diff --git a/roles/ara_server/handlers/main.yaml b/roles/ara_server/handlers/main.yaml new file mode 100644 index 0000000..d15ffb8 --- /dev/null +++ b/roles/ara_server/handlers/main.yaml @@ -0,0 +1,30 @@ +--- +# Copyright (c) 2019 Red Hat, Inc. +# +# This file is part of ARA Records Ansible. +# +# ARA Records Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ARA Records Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with ARA Records Ansible. If not, see . + +- name: restart ara-server + become: true + service: + name: ara-server + state: restarted + when: ara_server_service_enabled is not changed + +# Is there a better way ? Static files are not created with the httpd context +- name: restore selinux context for static files + become: true + command: "restorecon -Rv {{ ara_server_www_dir }}" + when: ansible_os_family == "RedHat" diff --git a/roles/ara_server/meta/main.yaml b/roles/ara_server/meta/main.yaml new file mode 100644 index 0000000..fc8dbc1 --- /dev/null +++ b/roles/ara_server/meta/main.yaml @@ -0,0 +1,36 @@ +--- +# Copyright (c) 2019 Red Hat, Inc. +# +# This file is part of ARA Records Ansible. +# +# ARA Records Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ARA Records Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with ARA Records Ansible. If not, see . + +galaxy_info: + author: David Moreau-Simard + description: Role to set up ara-server + license: GPLv3 + min_ansible_version: 2.7 + platforms: + - name: Fedora + versions: + - 29 + - name: Ubuntu + versions: + - bionic + galaxy_tags: + - ansible + - ara + - ara-server + +dependencies: [] diff --git a/roles/ara_server/tasks/config.yaml b/roles/ara_server/tasks/config.yaml new file mode 100644 index 0000000..ef7b341 --- /dev/null +++ b/roles/ara_server/tasks/config.yaml @@ -0,0 +1,104 @@ +--- +# Copyright (c) 2019 Red Hat, Inc. +# +# This file is part of ARA Records Ansible. +# +# ARA Records Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ARA Records Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with ARA Records Ansible. If not, see . + +- become: yes + become_user: "{{ ara_server_user }}" + block: + - name: Verify if a configuration file exists + stat: + path: "{{ ara_server_settings }}" + register: settings_stat + + # If no secret key has been provided and this isn't the first time we are + # running, recover the secret key from the existing configuration file. + - when: + - ara_server_secret_key is none + - settings_stat.stat.exists + block: + - name: Read the configuration file + command: cat "{{ ara_server_settings }}" + changed_when: false + no_log: yes + register: settings_contents + + - name: Recover existing secret key + vars: + config: "{{ settings_contents.stdout | from_yaml }}" + set_fact: + ara_server_secret_key: "{{ config[ara_server_env]['SECRET_KEY'] }}" + no_log: yes + + # If no secret key has been provided and this is the first time we are + # running, generate a new random secret key that will be persisted in the + # configuration file. + - when: + - ara_server_secret_key is none + - not settings_stat.stat.exists + block: + - name: Generate a random secret key + environment: + PATH: "{{ path_with_virtualenv | default(omit) }}" + command: python3 -c "from django.utils.crypto import get_random_string; print(get_random_string(length=50))" + no_log: yes + register: generated_key + + - name: Set ara_server_secret_key + set_fact: + ara_server_secret_key: "{{ generated_key.stdout }}" + no_log: yes + + - name: Reconcile configuration + vars: + reconciled_configuration: + ALLOWED_HOSTS: "{{ ara_server_allowed_hosts }}" + BASE_DIR: "{{ ara_server_base_dir }}" + CORS_ORIGIN_ALLOW_ALL: "{{ ara_server_cors_origin_allow_all }}" + CORS_ORIGIN_WHITELIST: "{{ ara_server_cors_origin_whitelist }}" + DATABASES: + default: + ENGINE: "{{ ara_server_database_engine }}" + NAME: "{{ ara_server_database_name }}" + USER: "{{ ara_server_database_user }}" + PASSWORD: "{{ ara_server_database_password }}" + HOST: "{{ ara_server_database_host }}" + PORT: "{{ ara_server_database_port }}" + DEBUG: "{{ ara_server_debug }}" + LOGGING: "{{ ara_server_logging }}" + LOG_LEVEL: "{{ ara_server_log_level }}" + MEDIA_ROOT: "{{ ara_server_media_root }}" + MEDIA_URL: "{{ ara_server_media_url }}" + STATIC_ROOT: "{{ ara_server_static_root }}" + STATIC_URL: "{{ ara_server_static_url }}" + SECRET_KEY: "{{ ara_server_secret_key }}" + set_fact: + ara_server_configuration: "{'{{ ara_server_env }}': {{ reconciled_configuration }} }" + +- name: Configure ara-server + become: yes + copy: + content: | + --- + # Managed by the ara_server Ansible role + {{ ara_server_configuration | to_nice_yaml(indent=2) }} + dest: "{{ ara_server_settings }}" + owner: "{{ ara_server_user }}" + group: "{{ ara_server_group }}" + mode: 0750 + notify: + - restart ara-server + no_log: yes diff --git a/roles/ara_server/tasks/database_engine/django.db.backends.sqlite3.yaml b/roles/ara_server/tasks/database_engine/django.db.backends.sqlite3.yaml new file mode 100644 index 0000000..8690b7b --- /dev/null +++ b/roles/ara_server/tasks/database_engine/django.db.backends.sqlite3.yaml @@ -0,0 +1,34 @@ +--- +# Copyright (c) 2019 Red Hat, Inc. +# +# This file is part of ARA Records Ansible. +# +# ARA Records Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ARA Records Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with ARA Records Ansible. If not, see . + +- become: yes + become_user: "{{ ara_server_user }}" + block: + - name: Ensure the database directory exists + file: + path: "{{ ara_server_database_name | dirname }}" + state: directory + owner: "{{ ara_server_user }}" + group: "{{ ara_server_group }}" + mode: 0750 + + - name: Run SQL migrations + environment: + ARA_SETTINGS: "{{ ara_server_settings }}" + PATH: "{{ path_with_virtualenv | default(omit) }}" + command: ara-manage migrate diff --git a/roles/ara_server/tasks/install/source.yaml b/roles/ara_server/tasks/install/source.yaml new file mode 100644 index 0000000..f2fc4d0 --- /dev/null +++ b/roles/ara_server/tasks/install/source.yaml @@ -0,0 +1,55 @@ +--- +# Copyright (c) 2019 Red Hat, Inc. +# +# This file is part of ARA Records Ansible. +# +# ARA Records Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ARA Records Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with ARA Records Ansible. If not, see . + +# Zuul takes care of preparing the source repository but we need to make it +# available to the ara user. +- when: zuul is defined + become: yes + block: + - name: Ensure git checkout directory exists + become_user: "{{ ara_server_user }}" + file: + path: "{{ ara_server_source_checkout | dirname }}" + state: directory + + # Files will be owned by the Zuul user but allow for reading, we don't need + # to adjust permissions for this. + - name: Copy Zuul git repository for ara-server + command: "cp -r {{ ansible_user_dir }}/src/git.openstack.org/openstack/ara-server {{ ara_server_source_checkout }}" + +- become: yes + become_user: "{{ ara_server_user }}" + block: + - name: Prepare git repository for ara-server + git: + repo: "{{ ara_server_source }}" + dest: "{{ ara_server_source_checkout }}" + version: "{{ (ara_server_install_version == 'latest') | ternary('HEAD', ara_server_install_version) }}" + when: zuul is not defined + + - name: Install ara-server + pip: + name: "{{ ara_server_source_checkout }}" + state: present + virtualenv: "{{ ara_server_venv | bool | ternary(ara_server_venv_path, omit) }}" + virtualenv_python: python3 + +- name: Prefix the virtualenv bin directory to PATH + set_fact: + path_with_virtualenv: "{{ ara_server_venv_path }}/bin:{{ ansible_env.PATH }}" + when: ara_server_venv | bool diff --git a/roles/ara_server/tasks/main.yaml b/roles/ara_server/tasks/main.yaml new file mode 100644 index 0000000..f5b19ea --- /dev/null +++ b/roles/ara_server/tasks/main.yaml @@ -0,0 +1,55 @@ +--- +# Copyright (c) 2019 Red Hat, Inc. +# +# This file is part of ARA Records Ansible. +# +# ARA Records Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ARA Records Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with ARA Records Ansible. If not, see . + +- name: Set up pre-requirements + include_tasks: pre-requirements.yaml + +- name: Include ara-server installation + include_tasks: "install/{{ ara_server_install_method }}.yaml" + +- name: Include ara-server configuration + include_tasks: config.yaml + +- name: Include database engine configuration + include_tasks: "database_engine/{{ ara_server_database_engine }}.yaml" + +- name: Include backend server installation + include_tasks: "wsgi_server/{{ ara_server_wsgi_server }}.yaml" + +- name: Create web asset directory + become: yes + file: + path: "{{ ara_server_www_dir }}" + state: directory + owner: "{{ ara_server_user }}" + group: "{{ ara_server_group }}" + mode: 0755 + +- name: Collect static files + become: yes + become_user: "{{ ara_server_user }}" + environment: + ARA_SETTINGS: "{{ ara_server_settings }}" + PATH: "{{ path_with_virtualenv | default(omit) }}" + command: ara-manage collectstatic --clear --no-input + notify: + - restore selinux context for static files + +- name: Include frontend server installation + include_role: + name: "ara_frontend_{{ ara_server_frontend_server }}" diff --git a/roles/ara_server/tasks/pre-requirements.yaml b/roles/ara_server/tasks/pre-requirements.yaml new file mode 100644 index 0000000..b38ae07 --- /dev/null +++ b/roles/ara_server/tasks/pre-requirements.yaml @@ -0,0 +1,63 @@ +--- +# Copyright (c) 2019 Red Hat, Inc. +# +# This file is part of ARA Records Ansible. +# +# ARA Records Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ARA Records Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with ARA Records Ansible. If not, see . + +# The ansible_python_version fact might end up retrieving the version of +# python2 so we need to explicitely get the version of python 3 available. +- name: Validate availability of Python 3.6 + command: /usr/bin/python3 -c 'import sys; print(".".join(map(str, sys.version_info[:2])))' + changed_when: false + failed_when: false + register: python_version + +- name: Fail pre-emptively if running Python <3.6 + fail: + msg: "Python >=3.6 is required to run ara-server" + when: python_version.stdout is version('3.6', '<') or python_version.rc != 0 + +- name: Include OS family/distribution specific variables + include_vars: "{{ item }}" + with_first_found: + - "{{ ansible_distribution }}.yaml" + - "{{ ansible_os_family }}.yaml" + +- become: true + block: + - name: Install required packages + package: + name: "{{ ara_server_required_packages }}" + state: present + + - name: Create user for ara-server + user: + name: "{{ ara_server_user }}" + comment: User for ARA Records Ansible + shell: /sbin/nologin + home: "{{ ara_server_home_dir }}" + + - name: Ensure required directories are created with the right permissions + file: + path: "{{ item }}" + state: directory + owner: "{{ ara_server_user }}" + group: "{{ ara_server_group }}" + mode: 0750 + loop: + - "{{ ara_server_home_dir }}" + - "{{ ara_server_base_dir }}" + - "{{ ara_server_config_dir }}" + - "{{ ara_server_log_dir }}" diff --git a/roles/ara_server/tasks/wsgi_server/gunicorn.yaml b/roles/ara_server/tasks/wsgi_server/gunicorn.yaml new file mode 100644 index 0000000..53f3b68 --- /dev/null +++ b/roles/ara_server/tasks/wsgi_server/gunicorn.yaml @@ -0,0 +1,64 @@ +--- +# Copyright (c) 2019 Red Hat, Inc. +# +# This file is part of ARA Records Ansible. +# +# ARA Records Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ARA Records Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with ARA Records Ansible. If not, see . + +- become: yes + become_user: "{{ ara_server_user }}" + block: + - name: Install gunicorn + pip: + name: gunicorn + state: present + virtualenv: "{{ ara_server_venv | bool | ternary(ara_server_venv_path, omit) }}" + virtualenv_python: python3 + + - when: ansible_os_family == "RedHat" + block: + - name: Transfer gunicorn selinux type enforcement file + copy: + src: ara-gunicorn.te + dest: "{{ ara_server_home_dir }}/ara-gunicorn.te" + + - name: Compile ara-gunicorn selinux module + command: "checkmodule -M -m -o {{ ara_server_home_dir }}/ara-gunicorn.mod {{ ara_server_home_dir }}/ara-gunicorn.te" + + - name: Compile ara-gunicorn selinux policy package + command: "semodule_package -o {{ ara_server_home_dir }}/ara-gunicorn.pp -m {{ ara_server_home_dir }}/ara-gunicorn.mod" + +- become: yes + block: + - name: Install selinux policy package + command: "semodule -i {{ ara_server_home_dir }}/ara-gunicorn.pp" + when: ansible_os_family == "RedHat" + + - name: Set up systemd unit file for gunicorn + template: + src: ara-server.service.j2 + dest: /etc/systemd/system/ara-server.service + owner: root + group: root + mode: 0644 + notify: + - restart ara-server + + - name: Enable and start ara-server with gunicorn + service: + name: ara-server + state: started + enabled: yes + daemon_reload: yes + register: ara_server_service_enabled diff --git a/roles/ara_server/templates/ara-server.service.j2 b/roles/ara_server/templates/ara-server.service.j2 new file mode 100644 index 0000000..a565b5e --- /dev/null +++ b/roles/ara_server/templates/ara-server.service.j2 @@ -0,0 +1,22 @@ +[Unit] +Description=ARA Records Ansible API server with gunicorn +After=network.target + +[Service] +PIDFile=/run/ara-server/pid +User={{ ara_server_user }} +Group={{ ara_server_group }} +RuntimeDirectory=ara-server +WorkingDirectory={{ ara_server_home_dir }} +Environment=ARA_SETTINGS={{ ara_server_settings }} +{% if ara_server_venv %} +ExecStart={{ ara_server_venv_path }}/bin/gunicorn --pid /run/ara-server/pid --workers=4 --bind {{ ara_server_wsgi_bind }} ara.server.wsgi +{% else %} +ExecStart=gunicorn --pid /run/ara-server/pid --workers=4 --bind {{ ara_server_wsgi_bind }} ara.server.wsgi +{% endif %} +ExecReload=/bin/kill -s HUP $MAINPID +ExecStop=/bin/kill -s TERM $MAINPID +PrivateTmp=true + +[Install] +WantedBy=multi-user.target diff --git a/roles/ara_server/vars/Fedora.yaml b/roles/ara_server/vars/Fedora.yaml new file mode 100644 index 0000000..f6ac069 --- /dev/null +++ b/roles/ara_server/vars/Fedora.yaml @@ -0,0 +1,22 @@ +--- +# Copyright (c) 2019 Red Hat, Inc. +# +# This file is part of ARA Records Ansible. +# +# ARA Records Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ARA Records Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with ARA Records Ansible. If not, see . + +ara_server_required_packages: + - git + - libselinux-python + - policycoreutils-python-utils diff --git a/roles/ara_server/vars/Ubuntu.yaml b/roles/ara_server/vars/Ubuntu.yaml new file mode 100644 index 0000000..071046d --- /dev/null +++ b/roles/ara_server/vars/Ubuntu.yaml @@ -0,0 +1,21 @@ +--- +# Copyright (c) 2019 Red Hat, Inc. +# +# This file is part of ARA Records Ansible. +# +# ARA Records Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ARA Records Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with ARA Records Ansible. If not, see . + +ara_server_required_packages: + - git + - python3-venv