From 251611803f6e5e38dd1b4d6d890bcd2d0f4d35e4 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Thu, 7 Mar 2019 13:26:15 -0600 Subject: [PATCH] roles/taiga: Deploy Taiga project management app The *taiga* role installs the three components of Taiga: * taiga-back * taiga-events * taiga-front *taiga-back* is a Python application. Its dependencies are installed via `pip` in the *taiga* user's site-packages, and the application itself is installed by unpacking the archive. *taiga-events* is a Node.js application. Its dependencies are installed by `npm`, and is itself installed by unpacking the archive. Finally, *taiga-front* is a single-page browser application that is installed by unpacking the archive, and served by Apache. Taiga requires PostgreSQL and RabbitMQ. --- roles/taiga/defaults/main.yml | 2 + roles/taiga/files/taiga-back.sh | 7 ++ roles/taiga/files/taiga-events.service | 13 ++++ roles/taiga/files/taiga.httpd.conf | 33 +++++++++ roles/taiga/files/taiga.service | 11 +++ roles/taiga/handlers/main.yml | 34 +++++++++ roles/taiga/tasks/main.yml | 19 +++++ roles/taiga/tasks/postgresql.yml | 19 +++++ roles/taiga/tasks/rabbitmq.yml | 14 ++++ roles/taiga/tasks/taiga-back.yml | 73 +++++++++++++++++++ roles/taiga/tasks/taiga-events.yml | 52 +++++++++++++ roles/taiga/tasks/taiga-front.yml | 11 +++ roles/taiga/templates/settings.py.j2 | 26 +++++++ .../templates/taiga-events.config.json.j2 | 7 ++ .../taiga/templates/taiga-front.conf.json.j2 | 10 +++ roles/taiga/vars/main.yml | 3 + 16 files changed, 334 insertions(+) create mode 100644 roles/taiga/defaults/main.yml create mode 100644 roles/taiga/files/taiga-back.sh create mode 100644 roles/taiga/files/taiga-events.service create mode 100644 roles/taiga/files/taiga.httpd.conf create mode 100644 roles/taiga/files/taiga.service create mode 100644 roles/taiga/handlers/main.yml create mode 100644 roles/taiga/tasks/main.yml create mode 100644 roles/taiga/tasks/postgresql.yml create mode 100644 roles/taiga/tasks/rabbitmq.yml create mode 100644 roles/taiga/tasks/taiga-back.yml create mode 100644 roles/taiga/tasks/taiga-events.yml create mode 100644 roles/taiga/tasks/taiga-front.yml create mode 100644 roles/taiga/templates/settings.py.j2 create mode 100644 roles/taiga/templates/taiga-events.config.json.j2 create mode 100644 roles/taiga/templates/taiga-front.conf.json.j2 create mode 100644 roles/taiga/vars/main.yml diff --git a/roles/taiga/defaults/main.yml b/roles/taiga/defaults/main.yml new file mode 100644 index 0000000..4e08f7d --- /dev/null +++ b/roles/taiga/defaults/main.yml @@ -0,0 +1,2 @@ +taiga_media_url: /media/ +taiga_static_url: /static/ diff --git a/roles/taiga/files/taiga-back.sh b/roles/taiga/files/taiga-back.sh new file mode 100644 index 0000000..bee6589 --- /dev/null +++ b/roles/taiga/files/taiga-back.sh @@ -0,0 +1,7 @@ +#!/bin/sh +export PYTHONUNBUFFERED=1 +cd /usr/local/lib/taiga/taiga-back +exec /usr/local/lib/taiga/venv/bin/gunicorn \ + --workers 4 \ + -b [::1]:8001 \ + taiga.wsgi diff --git a/roles/taiga/files/taiga-events.service b/roles/taiga/files/taiga-events.service new file mode 100644 index 0000000..e771e0a --- /dev/null +++ b/roles/taiga/files/taiga-events.service @@ -0,0 +1,13 @@ +# vim: set ft=systemd : +[Unit] +Description=Taiga Events Server + +[Service] +Type=simple +WorkingDirectory=/usr/local/lib/taiga/taiga-events +ExecStart=/usr/local/lib/taiga/taiga-events/node_modules/coffeescript/bin/coffee \ + index.coffee +User=taiga + +[Install] +WantedBy=multi-user.target diff --git a/roles/taiga/files/taiga.httpd.conf b/roles/taiga/files/taiga.httpd.conf new file mode 100644 index 0000000..ca8a9be --- /dev/null +++ b/roles/taiga/files/taiga.httpd.conf @@ -0,0 +1,33 @@ +# vim: set ft=apache : +ProxyRequests off +ProxyPreserveHost on + +ProxyPass /api http://localhost:8001/api +ProxyPassReverse /api http://localhost:8001/api +ProxyPass /admin http://localhost:8001/admin +ProxyPassReverse /admin http://localhost:8001/admin +ProxyPass /events ws://localhost:8888/events + +Alias /static /usr/local/lib/taiga/taiga-back/static + + Require all granted + + +Alias /media /usr/local/lib/taiga/taiga-back/media + + Require all granted + + +DocumentRoot /usr/local/lib/taiga/taiga-front-dist/dist + + Require all granted + + RewriteEngine On + + RewriteCond %{HTTPS} !on + RewriteRule /.* https://%{SERVER_NAME}$0 + + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.html [L] + diff --git a/roles/taiga/files/taiga.service b/roles/taiga/files/taiga.service new file mode 100644 index 0000000..836ad46 --- /dev/null +++ b/roles/taiga/files/taiga.service @@ -0,0 +1,11 @@ +# vim: set ft=systemd : +[Unit] +Description=Taiga Backend Server + +[Service] +Type=simple +User=taiga +ExecStart=/usr/local/libexec/taiga-back.sh + +[Install] +WantedBy=multi-user.target diff --git a/roles/taiga/handlers/main.yml b/roles/taiga/handlers/main.yml new file mode 100644 index 0000000..aedf0f1 --- /dev/null +++ b/roles/taiga/handlers/main.yml @@ -0,0 +1,34 @@ +- name: reload systemd + command: systemctl daemon-reload + +- name: migrate taiga data + become: true + become_user: taiga + command: + /usr/local/lib/taiga/venv/bin/python manage.py migrate + chdir=/usr/local/lib/taiga/taiga-back +- name: compile taiga messages +# become: true +# become_user: taiga + command: + /usr/local/lib/taiga/venv/bin/python manage.py compilemessages + chdir=/usr/local/lib/taiga/taiga-back +- name: collect taiga static data +# become: true +# become_user: taiga + command: + /usr/local/lib/taiga/venv/bin/python manage.py collectstatic --noinput + chdir=/usr/local/lib/taiga/taiga-back + +- name: reload httpd + service: + name: httpd + state: reloaded +- name: restart taiga-events + service: + name: taiga-events + state: restarted +- name: restart taiga + service: + name: taiga + state: restarted diff --git a/roles/taiga/tasks/main.yml b/roles/taiga/tasks/main.yml new file mode 100644 index 0000000..5a2bba7 --- /dev/null +++ b/roles/taiga/tasks/main.yml @@ -0,0 +1,19 @@ +- import_tasks: postgresql.yml +- import_tasks: rabbitmq.yml + +- import_tasks: taiga-back.yml +- import_tasks: taiga-front.yml +- import_tasks: taiga-events.yml + +- name: ensure apache is configured to serve taiga + copy: + src: taiga.httpd.conf + dest: /etc/httpd/conf.d/taiga.conf + mode: '0644' + notify: + - reload httpd +- name: ensure selinux allows apache to proxy for taiga + seboolean: + name: httpd_can_network_connect + state: true + persistent: true diff --git a/roles/taiga/tasks/postgresql.yml b/roles/taiga/tasks/postgresql.yml new file mode 100644 index 0000000..a013f21 --- /dev/null +++ b/roles/taiga/tasks/postgresql.yml @@ -0,0 +1,19 @@ +- name: ensure taiga postgresql user exists + become: true + become_user: postgres + postgresql_user: + name=taiga + state=present + +- name: ensure taiga postgresql database exists + become: true + become_user: postgres + postgresql_db: + name=taiga + owner=taiga + encoding=utf-8 + lc_collate=en_US.UTF-8 + lc_ctype=en_US.UTF-8 + state=present + notify: + - migrate taiga data diff --git a/roles/taiga/tasks/rabbitmq.yml b/roles/taiga/tasks/rabbitmq.yml new file mode 100644 index 0000000..4a3cd44 --- /dev/null +++ b/roles/taiga/tasks/rabbitmq.yml @@ -0,0 +1,14 @@ +- name: ensure taiga rabbitmq vhost exists + rabbitmq_vhost: + name=taiga + state=present +- name: ensure taiga rabbitmq user exists + rabbitmq_user: + name: taiga + password: '{{ taiga_events_password }}' + permissions: + - vhost: taiga + configure_priv: .* + read_priv: .* + write_priv: .* + state: present diff --git a/roles/taiga/tasks/taiga-back.yml b/roles/taiga/tasks/taiga-back.yml new file mode 100644 index 0000000..c654e8d --- /dev/null +++ b/roles/taiga/tasks/taiga-back.yml @@ -0,0 +1,73 @@ +- name: ensure system dependencies are installed + package: + name: + - gzip + - libjpeg + - python3-psycopg2 + - '{{ taiga_python_package }}' + - sudo + - tar + - zlib + state: present + tags: + - install + +- name: ensure taiga user exists + user: + name: taiga + system: yes + home: /var/lib/taiga + state: present + +- name: ensure taiga dependencies are installed + environment: + PIP_NO_INDEX: t + PIP_FIND_LINKS: '{{ taiga_pip_url }}' + PIP_TRUSTED_HOST: '{{ taiga_pip_url|urlsplit("hostname") }}' + pip: + requirements: '{{ taiga_pip_url }}/requirements.txt' + virtualenv: /usr/local/lib/taiga/venv + virtualenv_command: '{{ taiga_python_exe }} -m venv' + state: present +- name: ensure taiga-back is installed + unarchive: + src: '{{ taiga_back_url }}' + dest: /usr/local/lib/taiga/ + remote_src: true + notify: + - migrate taiga data + - compile taiga messages + - collect taiga static data + +- name: ensure taiga media directory exists + file: + path: /usr/local/lib/taiga/taiga-back/media + owner: taiga + group: taiga + mode: '0755' + state: directory + +- name: ensure taiga-back is configured + template: + src: settings.py.j2 + dest: /usr/local/lib/taiga/taiga-back/settings/local.py + +- name: ensure taiga-back entry point script is installed + copy: + src: taiga-back.sh + dest: /usr/local/libexec/taiga-back.sh + mode: '0755' + notify: + - restart taiga +- name: ensure taiga systemd unit is installed + copy: + src: taiga.service + dest: /etc/systemd/system/taiga.service + mode: '0644' + notify: + - reload systemd + - restart taiga +- name: ensure taiga starts at boot + service: + name: taiga + enabled: yes diff --git a/roles/taiga/tasks/taiga-events.yml b/roles/taiga/tasks/taiga-events.yml new file mode 100644 index 0000000..426622d --- /dev/null +++ b/roles/taiga/tasks/taiga-events.yml @@ -0,0 +1,52 @@ +- name: ensure nodejs is installed + package: + name: + - nodejs + - npm + state: present + tags: + - install + +- name: ensure taiga-events directory exists + file: + path: /usr/local/lib/taiga/taiga-events + owner: taiga + group: taiga + mode: '0755' + state: directory +- name: ensure taiga-events is installed + become: true + become_user: taiga + unarchive: + src: '{{ taiga_events_url }}' + dest: /usr/local/lib/taiga/ + remote_src: true + +- name: ensure taiga-events dependencies are installed + become: true + become_user: taiga + npm: + path: /usr/local/lib/taiga/taiga-events + +- name: ensure taiga-events is configured + template: + src: taiga-events.config.json.j2 + dest: /usr/local/lib/taiga/taiga-events/config.json + owner: root + group: taiga + mode: '0750' + notify: + - restart taiga-events + +- name: ensure taiga-events systemd unit is installed + copy: + src: taiga-events.service + dest: /etc/systemd/system/taiga-events.service + mode: '0644' + notify: + - reload systemd + - restart taiga-events +- name: ensure taiga-events starts at boot + service: + name: taiga-events + enabled: yes diff --git a/roles/taiga/tasks/taiga-front.yml b/roles/taiga/tasks/taiga-front.yml new file mode 100644 index 0000000..fd00a1a --- /dev/null +++ b/roles/taiga/tasks/taiga-front.yml @@ -0,0 +1,11 @@ +- name: ensure taiga-front is installed + unarchive: + src: '{{ taiga_front_url }}' + dest: /usr/local/lib/taiga/ + remote_src: true + +- name: ensure taiga-front is configured + template: + src: taiga-front.conf.json.j2 + dest: /usr/local/lib/taiga/taiga-front-dist/dist/conf.json + mode: '0644' diff --git a/roles/taiga/templates/settings.py.j2 b/roles/taiga/templates/settings.py.j2 new file mode 100644 index 0000000..be00580 --- /dev/null +++ b/roles/taiga/templates/settings.py.j2 @@ -0,0 +1,26 @@ +from .common import * + +MEDIA_URL = "{{ taiga_media_url }}" +STATIC_URL = "{{ taiga_static_url }}" +SITES["front"]["scheme"] = "http" +SITES["front"]["domain"] = "example.com" + +SECRET_KEY = "{{ taiga_back_secret_key }}" + +DEBUG = False +PUBLIC_REGISTER_ENABLED = True + +DEFAULT_FROM_EMAIL = "no-reply@example.com" +SERVER_EMAIL = DEFAULT_FROM_EMAIL + +#CELERY_ENABLED = True + +EVENTS_PUSH_BACKEND = "taiga.events.backends.rabbitmq.EventsPushBackend" +EVENTS_PUSH_BACKEND_OPTIONS = {"url": "amqp://taiga:{{ taiga_events_password }}@localhost:5672/taiga"} + +EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" +EMAIL_USE_TLS = False +EMAIL_HOST = "{{ taiga_email_host }}" +#EMAIL_HOST_USER = "" +#EMAIL_HOST_PASSWORD = "" +#EMAIL_PORT = 25 diff --git a/roles/taiga/templates/taiga-events.config.json.j2 b/roles/taiga/templates/taiga-events.config.json.j2 new file mode 100644 index 0000000..c818787 --- /dev/null +++ b/roles/taiga/templates/taiga-events.config.json.j2 @@ -0,0 +1,7 @@ +{ + "url": "amqp://taiga:{{ taiga_events_password }}", + "Secret": "{{ taiga_back_secret_key }}", + "webSocketServer": { + "port": 8888 + } +} diff --git a/roles/taiga/templates/taiga-front.conf.json.j2 b/roles/taiga/templates/taiga-front.conf.json.j2 new file mode 100644 index 0000000..1cdf0c3 --- /dev/null +++ b/roles/taiga/templates/taiga-front.conf.json.j2 @@ -0,0 +1,10 @@ +{ + "api": "/api/v1/", + "publicRegisterEnabled": false, + "feedbackEnabled": false, + "privacyPolicyUrl": null, + "termsOfServiceUrl": null, + "GDPRUrl": null, + "maxUploadFileSize": null, + "contribPlugins": [] +} diff --git a/roles/taiga/vars/main.yml b/roles/taiga/vars/main.yml new file mode 100644 index 0000000..c47ef8d --- /dev/null +++ b/roles/taiga/vars/main.yml @@ -0,0 +1,3 @@ +taiga_python_version: 3.6 +taiga_python_exe: /usr/bin/python{{ taiga_python_version }} +taiga_python_package: python{{ taiga_python_version|replace('.', '') }}