--- a/.hgignore Tue Nov 27 15:45:45 2018 +0100
+++ b/.hgignore Wed Nov 28 15:45:37 2018 +0100
@@ -47,3 +47,6 @@
^deploy/group_vars/.*\.yml$
^deploy/hosts/hosts\.prod$
^deploy/hosts/hosts\.test$
+^deploy/.*\.retry$
+
+^.vscode/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/deploy/README.md Wed Nov 28 15:45:37 2018 +0100
@@ -0,0 +1,21 @@
+# build and deployment
+
+- install Ansible
+- Create a new deployment profile:
+ - add a new deplyment host list by creating a `hosts/hosts.<profile>` file:
+ - `cp hosts/hosts.tmpl hosts/hosts.<profile>`
+ - define the profile vars: `cp group_vars/group_vars.yml.tmpl group_vars/<profile>.yml`, customize it
+ - create the necessary host vars in `host_vars/<machine>/base.yml`. Use ansible vaults to edit them and do not expose any secret.
+ - deploy with the command `deploy.sh`: `./deploy.sh <profile> <version>`
+
+## Create new version
+Launch the command:
+- `set-version.sh <version>`
+- commit, tag and push as needed.
+
+## Launch local django command on the managed host
+
+```
+DJANGO_SETTINGS_MODULE=irinotes.settings IRINOTES_CONFIG_BASE=/etc/www/irinotes django-admin <command>
+```
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/deploy/Vagrantfile Wed Nov 28 15:45:37 2018 +0100
@@ -0,0 +1,34 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+Vagrant.configure("2") do |config|
+# config.vm.box = "maier/alpine-3.6-x86_64"
+ config.vm.box = "generic/alpine38"
+ config.vm.provider "virtualbox" do |v|
+ # v.default_nic_type = "Am79C973"
+ v.default_nic_type = "virtio"
+ end
+ config.vm.network "private_network", ip: "172.16.1.7", auto_config: false
+ config.vbguest.auto_update = false
+
+ # config.vm.provider :virtualbox do |vb|
+ # vb.gui = true
+ # end
+
+ # Enable provisioning with a shell script. Additional provisioners such as
+ # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
+ # documentation for more information about their specific syntax and use.
+ # config.vm.provision "shell", inline: <<-SHELL
+ # apt-get update
+ # apt-get install -y python python3
+ # SHELL
+ config.vm.provision "shell", inline: <<-SHELL
+ apk update
+ apk upgrade
+ apk add python python3
+ SHELL
+ config.vm.provision "ansible" do |ansible|
+ ansible.playbook = "test_playbook.yml"
+ ansible.compatibility_mode = "2.0"
+ end
+end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/deploy/deploy.sh Wed Nov 28 15:45:37 2018 +0100
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+
+SCRIPTPATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+SCRIPTNAME=`basename "$0"`
+
+usage() {
+ echo -n "${SCRIPTNAME} [CONFIG] [VERSION]
+
+Deploy the <config> using ansible.
+config must be in the following list : test, prod
+"
+}
+
+if [[ "$#" -ne 2 ]]; then
+ usage
+ exit 1
+fi
+
+config=${1}
+VERSION=${2}
+
+case $config in
+ test) configOK=true;;
+ prod) configOK=true;;
+ *) configOK=false;;
+esac
+
+if [[ "$configOK" = false ]]; then
+ usage
+ exit 1
+fi
+
+pushd "$SCRIPTPATH"
+
+ANSIBLE_SSH_PIPELINING=1 ANSIBLE_STDOUT_CALLBACK=debug ansible-playbook -v -i "./hosts/hosts.$config" -l "$config" ./deploy.yml --extra-vars "irinotes_version=${VERSION}" --ask-vault-pass
+
+popd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/deploy/deploy.yml Wed Nov 28 15:45:37 2018 +0100
@@ -0,0 +1,341 @@
+---
+# - hosts: all
+# tasks:
+# - name: Print some debug information
+# vars:
+# msg: |
+# Module Variables ("vars"):
+# --------------------------------
+# {{ vars | to_nice_json }}
+
+# Environment Variables ("environment"):
+# --------------------------------
+# {{ environment | to_nice_json }}
+
+# GROUP NAMES Variables ("group_names"):
+# --------------------------------
+# {{ group_names | to_nice_json }}
+
+# GROUPS Variables ("groups"):
+# --------------------------------
+# {{ groups | to_nice_json }}
+
+# HOST Variables ("hostvars"):
+# --------------------------------
+# {{ hostvars | to_nice_json }}
+
+# debug:
+# msg: "{{ msg.split('\n') }}"
+# tags: debug_info
+#
+# Localhost actions
+#
+- hosts: localhost
+ connection: local
+ vars:
+ irinotes_build_dir: "{{playbook_dir}}/build/tmp/irinotes/"
+ backend_build_dir: "{{playbook_dir}}/build/tmp/irinotes/src"
+ client_dir: "{{playbook_dir}}/build/tmp/irinotes/client"
+ tasks:
+
+ - name: mkdir build folder
+ file:
+ path: "{{playbook_dir}}/build/tmp"
+ state: directory
+
+ - name: clear irinotes checkout dir if exists
+ file:
+ path: "{{irinotes_build_dir}}"
+ state: absent
+
+ - name: checkout irinotes
+ hg:
+ repo: "{{irinotes_repo}}"
+ version: "{{irinotes_version}}"
+ force: yes
+ dest: "{{irinotes_build_dir}}"
+
+ - name: make irinotes py package
+ command: python setup.py sdist chdir="{{backend_build_dir}}"
+
+#
+# all actions
+#
+- hosts: remote_backend
+ vars:
+ backend_build_dir: "{{playbook_dir}}/build/tmp/irinotes/src"
+ client_dir: "{{playbook_dir}}/build/tmp/irinotes/client"
+ tasks:
+
+ - name: get backend version
+ local_action: command python setup.py -V chdir="{{backend_build_dir}}"
+ register: backend_version
+
+ - name: get discussion package version
+ set_fact:
+ backend_pkg_version: "{{backend_version.stdout}}"
+
+#
+# Localhost actions
+#
+- hosts: localhost
+ connection: local
+ vars:
+ backend_build_dir: "{{playbook_dir}}/build/tmp/irinotes/src"
+ client_dir: "{{playbook_dir}}/build/tmp/irinotes/client"
+ tasks:
+
+# build client js
+ - name: remove build
+ file: path="{{client_dir}}/build" state=absent
+
+ - name: client yarn install
+ command: npm install --no-save yarn
+ args:
+ chdir: "{{client_dir}}"
+
+ - name: client dependencies install
+ command: npx yarn install
+ args:
+ chdir: "{{client_dir}}"
+
+ - name: client build
+ command: npx yarn build
+ args:
+ chdir: "{{client_dir}}"
+ environment:
+ REACT_APP_API_ROOT_URL: "{{api_root_url}}"
+ REACT_APP_BASENAME: "{{api_root_url}}"
+ REACT_APP_NETWORK_STATUS_INTERVAL: "{{network_status_interval}}"
+ REACT_APP_NETWORK_STATUS_TIMEOUT: "{{network_status_timeout}}"
+ REACT_APP_SYNC_INTERVAL: "{{sync_interval}}"
+
+#
+# Static server
+#
+- hosts: remote_static
+ become: yes
+ vars:
+ backend_build_dir: "{{playbook_dir}}/build/tmp/irinotes/src"
+ client_dir: "{{playbook_dir}}/build/tmp/irinotes/client"
+ tasks:
+
+ - name: create dest static directory content
+ file:
+ path: "{{remote_static_path}}"
+ state: directory
+ owner: "{{static_http_user}}"
+ group: "{{static_http_group}}"
+
+ - name: remove dest static directory content
+ command: /bin/rm -fr "{{remote_static_path}}/*" warn=False
+ when: remote_static_path != ""
+
+ - name: transfert static dist to remote
+ copy:
+ src: "{{client_dir}}/build/"
+ dest: "{{remote_static_path}}/"
+ owner: "{{static_http_user}}"
+ group: "{{static_http_group}}"
+ notify:
+ - restart static nginx
+
+ - name: create refresh nginx config
+ template:
+ src: "{{static_nginx_use_ssl | ternary('nginx.static.ssl.conf.j2', 'nginx.static.conf.j2')}}"
+ dest: "{{static_nginx_config | default('/etc/nginx/site-available/'+static_server_name, true)}}"
+ notify:
+ - restart static nginx
+
+ handlers:
+ - name: restart static nginx
+ service:
+ name: "{{static_http_service}}"
+ state: restarted
+ ignore_errors: yes
+
+#
+# backend servers
+#
+- hosts: remote_backend
+ become: yes
+ vars:
+ backend_build_dir: "{{playbook_dir}}/build/tmp/irinotes/src"
+ tasks:
+
+ - name: add iri group
+ group:
+ name: iri
+
+ - name: add uwsgi user
+ user:
+ name: uwsgi
+ group: iri
+ home: /var/www
+ create_home: no
+ system: yes
+ shell: /bin/false
+
+ - name: create log dir
+ file:
+ path: "{{log_base_path}}"
+ state: directory
+ owner: uwsgi
+ group: iri
+ mode: 0755
+
+ - name: create config dir
+ file:
+ path: "{{backend_config_base}}"
+ state: directory
+ owner: uwsgi
+ group: iri
+ mode: 0755
+
+ - name: create config dir requirements
+ file:
+ path: "{{backend_config_base}}/requirements"
+ state: directory
+ owner: uwsgi
+ group: iri
+ mode: 0755
+
+ - name: create static folder
+ file:
+ path: "{{backend_static_root}}"
+ state: directory
+ owner: uwsgi
+ group: iri
+ mode: 0755
+
+ - name: create media folder
+ file:
+ path: "{{backend_media_root}}"
+ state: directory
+ owner: uwsgi
+ group: iri
+ mode: 0755
+
+ - name: install backend venv
+ block:
+ - name: register backend virtualenv stats
+ stat: path="{{backend_venv}}"
+ register: backend_venv_stats
+
+ - name: copy backend base requirement file
+ copy:
+ src: "{{backend_build_dir}}/requirements/base.txt"
+ dest: "{{backend_config_base}}/requirements/base.txt"
+ register: copy_backend_requirements_base
+
+ - name: copy backend prod requirement file
+ copy:
+ src: "{{backend_build_dir}}/requirements/prod.txt"
+ dest: "{{backend_config_base}}/requirements/prod.txt"
+ register: copy_backend_requirements_prod
+
+
+ - name: remove annotation api venv
+ file:
+ path: "{{backend_venv}}"
+ state: absent
+ when: copy_backend_requirements_base.changed or copy_backend_requirements_prod.changed
+
+ - name: create backend virtualenv
+ pip:
+ virtualenv_command: /usr/bin/python3 -m venv
+ virtualenv: "{{backend_venv}}"
+ name: pip
+ state: latest
+ when: (copy_backend_requirements_base.changed or copy_backend_requirements_prod.changed) or (not backend_venv_stats.stat.exists)
+
+ - name: virtualenv install requirements
+ pip:
+ virtualenv: "{{backend_venv}}"
+ requirements: "{{backend_config_base}}/requirements/prod.txt"
+ when: (copy_backend_requirements_base.changed or copy_backend_requirements_prod.changed) or (not backend_venv_stats.stat.exists)
+ notify: restart irinotes backend service
+
+ - name: copy backend config
+ template:
+ src: "backend_settings.ini.j2"
+ dest: "{{backend_config_base}}/settings.ini"
+ notify: restart irinotes backend service
+
+ # install irinotes
+ - name: create temporary install directory
+ tempfile:
+ state: directory
+ suffix: build
+ register: backend_temp_folder
+
+ - name: copy irinotes backend build
+ copy:
+ src: "{{backend_build_dir}}/dist/irinotes-{{backend_pkg_version}}.tar.gz"
+ dest: "{{backend_temp_folder.path}}/irinotes-{{backend_pkg_version}}.tar.gz"
+
+ - name: virtualenv remove irinotes
+ pip:
+ virtualenv: "{{backend_venv}}"
+ name: irinotes
+ state: absent
+ notify: restart irinotes backend service
+
+ - name: virtualenv install irinotes
+ pip:
+ virtualenv: "{{backend_venv}}"
+ name: "file://{{backend_temp_folder.path}}/irinotes-{{backend_pkg_version}}.tar.gz"
+ notify: restart irinotes backend service
+
+ - name: irinotes migrate
+ command: "{{backend_venv}}/bin/django-admin migrate --noinput"
+ args:
+ chdir: "{{backend_venv}}"
+ environment:
+ DJANGO_SETTINGS_MODULE: "irinotes.settings"
+ IRINOTES_CONFIG_BASE: "{{backend_config_base}}"
+ become: yes
+ become_user: uwsgi
+ notify: restart irinotes backend service
+
+ - name: irinotes collectstatic
+ command: "{{backend_venv}}/bin/django-admin collectstatic --noinput -c"
+ args:
+ chdir: "{{backend_venv}}"
+ environment:
+ DJANGO_SETTINGS_MODULE: "irinotes.settings"
+ IRINOTES_CONFIG_BASE: "{{backend_config_base}}"
+ become: yes
+ become_user: uwsgi
+ notify: restart irinotes backend service
+
+ always:
+ - name: remove temp folder
+ file:
+ state: absent
+ path: "{{backend_temp_folder.path}}"
+ when: backend_temp_folder is defined
+
+
+ - name: copy backend uwsgi config
+ template:
+ src: "uwsgi_irinotes.yml.j2"
+ dest: "{{backend_config_base}}/uwsgi_irinotes.yml"
+ notify: restart irinotes backend service
+
+ - name: copy annotations api supervisor config
+ template:
+ src: "supervisord_irinotes_backend.ini.j2"
+ dest: "{{backend_supervisor_conf_path}}/irinotes_backend.ini"
+ notify: restart irinotes backend service
+
+ - name: Add uwsgi app (reread + add)
+ supervisorctl: name=irinotes_backend state=present
+
+ handlers:
+ - name: reload backend service supervisorctl
+ listen: "restart irinotes backend service"
+ supervisorctl:
+ name: irinotes_backend
+ state: restarted
+ ignore_errors: yes
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/deploy/group_vars/group_vars.yml.tmpl Wed Nov 28 15:45:37 2018 +0100
@@ -0,0 +1,102 @@
+---
+# irinotes repository url
+irinotes_repo: "https://www.iri.centrepompidou.fr/dev/hg/irinotes"
+
+# irinites version, should be overriden from command line
+irinotes_version: "HEAD"
+
+# remote path for static files
+# note : must not end with /
+remote_static_path: ""
+
+# remote path for nginx static file config
+static_nginx_config: ""
+
+# use the nginx ssl config template for static webserver of not
+static_nginx_use_ssl: true
+
+# static file domain
+static_server_name: ""
+
+# Remote static nginx service
+static_http_service: "nginx"
+
+# Static server nginx user
+static_http_user: "www-data"
+# Static server nginx group
+static_http_group: "www-data"
+
+# NGINX config
+backend_upstream_name: "irinotes_backend"
+backend_host: 127.0.0.1
+backend_port: 8081
+backend_url: ""
+
+
+# dashboard log base path
+log_base_path: ""
+
+# backend config base path, i.e. the path where all configuration files are stored. (no slash)
+backend_config_base: ""
+
+# backend virtualenv path
+backend_venv: ""
+
+# backend application base url
+backend_base_url: ""
+
+# base url for static resources (ends with "/")
+# default : /static/
+backend_static_url: "{{backend_base_url}}/backend/static/"
+
+# The absolute path to the directory where collectstatic will collect static files for deployment. (https://docs.djangoproject.com/en/1.11/ref/settings/#std:setting-STATIC_ROOT)
+backend_static_root: ""
+
+# The absolute path to the directory from where nginx will serve the backend static files
+backend_nginx_static_root: "{{backend_static_root}}"
+
+
+# base url for media (ends with "/")
+# default : /media/
+backend_media_url: "{{backend_base_url}}/backend/media/"
+
+# Absolute filesystem path to the directory that will hold user-uploaded files (https://docs.djangoproject.com/en/1.11/ref/settings/#media-root)
+backend_media_root: ""
+
+# Absolute filesystem path to the directory from where nginx will serve the backend media files
+backend_nginx_media_root: "{{backend_media_root}}"
+
+# Secret key for the application. cf. https://docs.djangoproject.com/en/1.11/ref/settings/#secret-key
+backend_secret_key: "REPLACE_SECRET_KEY"
+
+# Debug the application. Default True
+# DEBUG=<true|False>
+backend_debug: "True"
+
+# Comma separated values of authorized host. cf. https://docs.djangoproject.com/en/1.11/ref/settings/#allowed-hosts
+# default: empty
+backend_allowed_hosts: "{{static_server_name}}"
+
+# 12factor inspired DATABASE_URL environment variable cf.https://github.com/kennethreitz/dj-database-url
+# examples: postgres://<user>:<password>@<host>:<port>/<db_name>
+# examples: sqlite:////full/path/to/your/database/file.sqlite
+backend_database_url: ""
+
+# path for the log file
+backend_log_file: "{{log_base_path}}/backend.log"
+
+# log level one of CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET. Default: ERROR
+backend_log_level: "DEBUG"
+
+# expiration delta for JWT tokens (in seconds)
+# default: 3600
+backend_jwt_expiration_delta: 3600
+
+# expiration refresh delta for JWT tokens (in seconds)
+# default: 3600*24*7 = 604800
+backend_jwt_refresh_expiration_delta: 604800
+
+# annotations api supervisor configuration base path
+backend_supervisor_conf_path: "/etc/supervisor.d"
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/deploy/hosts/hosts.tmpl Wed Nov 28 15:45:37 2018 +0100
@@ -0,0 +1,12 @@
+[test]
+localhost
+
+[test:children]
+remote_static
+remote_backend
+
+[remote_static]
+172.16.1.7 ansible_user=vagrant
+
+[remote_backend]
+172.16.1.7 ansible_user=vagrant
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/deploy/templates/backend_settings.ini.j2 Wed Nov 28 15:45:37 2018 +0100
@@ -0,0 +1,45 @@
+[settings]
+# Base url for the application. default=''
+BASE_URL={{backend_base_url}}
+
+# base url for static resources (ends with "/")
+# default : /static/
+STATIC_URL={{backend_static_url}}
+
+# The absolute path to the directory where collectstatic will collect static files for deployment. (https://docs.djangoproject.com/en/1.11/ref/settings/#std:setting-STATIC_ROOT)
+# default: <path to irinotes repository clone>/run/web/static
+STATIC_ROOT={{backend_static_root}}
+
+# base url for static resources (ends with "/")
+# default : /media/
+MEDIA_URL={{backend_media_url}}
+
+# Absolute filesystem path to the directory that will hold user-uploaded files (https://docs.djangoproject.com/en/1.11/ref/settings/#media-root)
+# default: <path to irinotes repository clone>/run/web/media
+MEDIA_ROOT={{backend_media_root}}
+
+# Secret key for the application. cf. https://docs.djangoproject.com/en/1.11/ref/settings/#secret-key
+SECRET_KEY={{backend_secret_key}}
+
+# Debug the application. Default True
+DEBUG={{backend_debug}}
+
+# Comma separated values of authorized host. cf. https://docs.djangoproject.com/en/1.11/ref/settings/#allowed-hosts
+# default: empty
+ALLOWED_HOSTS={{backend_allowed_hosts}}
+
+# 12factor inspired DATABASE_URL environment variable cf.https://github.com/kennethreitz/dj-database-url
+# examples: postgres://<user>:<password>@<host>:<port>/<db_name>
+# examples: sqlite:////full/path/to/your/database/file.sqlite
+# default: sqlite:///<path to irinotes repository clone>/run/db/db.sqlite3
+DATABASE_URL={{backend_database_url}}
+
+# path for the log file
+# default: <path to irinotes repository clone>/run/log/log.txt
+LOG_FILE={{backend_log_file}}
+
+# log level one of CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET. Default: ERROR
+LOG_LEVEL={{backend_log_level}}
+
+JWT_EXPIRATION_DELTA={{backend_jwt_expiration_delta}}
+JWT_REFRESH_EXPIRATION_DELTA={{backend_jwt_refresh_expiration_delta}}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/deploy/templates/nginx.static.conf.j2 Wed Nov 28 15:45:37 2018 +0100
@@ -0,0 +1,46 @@
+upstream {{backend_upstream_name}} {
+ server {{backend_host}}:{{backend_port}};
+ server 127.0.0.1 backup;
+}
+
+
+server {
+ listen 80;
+ listen [::]:80;
+
+ server_name {{static_server_name}};
+
+ access_log /var/log/nginx/{{static_server_name}}-access.log;
+ error_log /var/log/nginx/{{static_server_name}}-error.log;
+
+ root {{remote_static_path}}/;
+ index index.html index.htm;
+
+
+ location {{backend_url}}/api {
+ uwsgi_pass {{backend_upstream_name}};
+ include /etc/nginx/uwsgi_params;
+ }
+ location {{backend_url}}/admin {
+ uwsgi_pass {{backend_upstream_name}};
+ include /etc/nginx/uwsgi_params;
+ }
+ location {{backend_url}}/auth {
+ uwsgi_pass {{backend_upstream_name}};
+ include /etc/nginx/uwsgi_params;
+ }
+
+ location /backend/static {
+ alias {{backend_nginx_static_root}}; # backend static files
+ }
+
+ location /backend/media {
+ alias {{backend_nginx_media_root}}; # backend media files
+ }
+
+ location / {
+ # First attempt to serve request as file, then
+ # as directory, then fall back to displaying a 404.
+ try_files $uri $uri/ /index.html;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/deploy/templates/nginx.static.ssl.conf.j2 Wed Nov 28 15:45:37 2018 +0100
@@ -0,0 +1,68 @@
+upstream {{backend_upstream_name}} {
+ server {{backend_host}}:{{backend_port}};
+ server 127.0.0.1 backup;
+}
+
+server {
+ listen 80;
+ listen [::]:80;
+
+ server_name {{static_server_name}};
+ return 301 https://$host$request_uri;
+}
+
+server {
+ listen 443 ssl http2;
+ listen [::]:443 ssl http2;
+
+ server_name {{static_server_name}};
+
+ access_log /var/log/nginx/{{static_server_name}}-access.log;
+ error_log /var/log/nginx/{{static_server_name}}-error.log;
+
+ ssl_certificate /etc/letsencrypt/live/{{static_server_name}}/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/{{static_server_name}}/privkey.pem;
+
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+ ssl_prefer_server_ciphers on;
+ ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
+
+ root {{remote_static_path}}/;
+ index index.html index.htm;
+
+ location /.well-known/acme-challenge {
+ alias /var/lib/letsencrypt/.well-known/acme-challenge;
+ default_type "text/plain";
+ try_files $uri =404;
+ }
+
+ location {{backend_url}}/api {
+ uwsgi_pass {{backend_upstream_name}};
+ include /etc/nginx/uwsgi_params;
+ }
+
+ location {{backend_url}}/admin {
+ uwsgi_pass {{backend_upstream_name}};
+ include /etc/nginx/uwsgi_params;
+ }
+
+ location {{backend_url}}/auth {
+ uwsgi_pass {{backend_upstream_name}};
+ include /etc/nginx/uwsgi_params;
+ }
+
+ location /backend/static {
+ alias {{backend_nginx_static_root}}; # backend static files
+ }
+
+ location /backend/media {
+ alias {{backend_nginx_media_root}}; # backend media files
+ }
+
+ location / {
+ # First attempt to serve request as file, then
+ # as directory, then fall back to displaying a 404.
+ try_files $uri $uri/ /index.html;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/deploy/templates/supervisord_irinotes_backend.ini.j2 Wed Nov 28 15:45:37 2018 +0100
@@ -0,0 +1,10 @@
+[program:irinotes_backend]
+command={{backend_venv}}/bin/uwsgi --yaml {{backend_config_base}}/uwsgi_irinotes.yml
+stdout_logfile={{log_base_path}}/supervisor_stdout.log
+stderr_logfile={{log_base_path}}/supervisor_stderr.log
+autostart=true
+autorestart=true
+stopsignal=QUIT
+user=uwsgi
+redirect_stderr=true
+directory={{backend_venv}}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/deploy/templates/uwsgi_irinotes.yml.j2 Wed Nov 28 15:45:37 2018 +0100
@@ -0,0 +1,13 @@
+uwsgi:
+ uwsgi-socket: :{{backend_port}}
+ virtualenv: {{backend_venv}}
+ chdir: {{backend_venv}}/bin
+ master: true
+ module: irinotes.wsgi
+ processes: 1
+ buffer-size: 65535
+ logto: {{log_base_path}}/backend_wsgi.log
+ env: IRINOTES_CONFIG_BASE={{backend_config_base}}
+ manage-script-name : true
+ uid = uwsgi
+ gid = uwsgi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/deploy/test_playbook.yml Wed Nov 28 15:45:37 2018 +0100
@@ -0,0 +1,38 @@
+---
+#
+# all actions
+#
+- hosts: all
+ become: true
+ tasks:
+ - name: set eth1 interface
+ blockinfile:
+ path: /etc/network/interfaces
+ block: |
+ auto eth1
+ iface eth1 inet static
+ address 172.16.1.7
+ netmask 255.255.255.0
+ register: eth1_added
+ - name: restart network service
+ service:
+ name: networking
+ state: restarted
+ when: eth1_added.changed
+ - name: install deps
+ apk:
+ name: python-dev,python3-dev,py-virtualenv,nginx,supervisor,build-base,musl-dev,gcc,linux-headers,libffi,libffi-dev, shadow, git, postgresql-dev, postgresql-client, libmemcached-dev, zlib-dev
+ update_cache: yes
+ - name: create etc supervisor.d folder
+ file:
+ path: /etc/supervisor.d
+ state: directory
+ - name: starts supervisord
+ service:
+ name: supervisord
+ state: started
+ - name: Set authorized key for user vagrant copying it from current user
+ authorized_key:
+ user: vagrant
+ state: present
+ key: "{{ lookup('file', lookup('env','HOME') + '/.ssh/id_rsa.pub') }}"