diff --git a/Vagrantfile b/Vagrantfile index e12a45ed..f34653a5 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -1,47 +1,19 @@ # -*- mode: ruby -*- # vi: set ft=ruby : -# All Vagrant configuration is done below. The "2" in Vagrant.configure -# configures the configuration version (we support older styles for -# backwards compatibility). Please don't change it unless you know what -# you're doing. +# Configuration de base pour GestioCOF. +# Voir https://docs.vagrantup.com pour plus d'informations. Vagrant.configure(2) do |config| - # The most common configuration options are documented and commented below. - # For a complete reference, please see the online documentation at - # https://docs.vagrantup.com. - - config.vm.box = "ubuntu/xenial64" + # On se base sur Debian 10 (Buster) pour avoir le même environnement qu'en + # production. + config.vm.box = "debian/contrib-buster64" # On associe le port 80 dans la machine virtuelle avec le port 8080 de notre # ordinateur, et le port 8000 avec le port 8000. config.vm.network :forwarded_port, guest: 80, host: 8080 config.vm.network :forwarded_port, guest: 8000, host: 8000 - # Create a private network, which allows host-only access to the machine - # using a specific IP. - # config.vm.network "private_network", ip: "192.168.33.10" - - # Provider-specific configuration so you can fine-tune various - # backing providers for Vagrant. These expose provider-specific options. - # Example for VirtualBox: - # - # config.vm.provider "virtualbox" do |vb| - # # Display the VirtualBox GUI when booting the machine - # vb.gui = true - # - # # Customize the amount of memory on the VM: - # vb.memory = "1024" - # end - # - # View the documentation for the provider you are using for more - # information on available options. - - # 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 - # sudo apt-get update - # sudo apt-get install -y apache2 - # SHELL + # Le restes de la configuration (installation de paquets, etc) est géré un + # script shell. config.vm.provision :shell, path: "provisioning/bootstrap.sh" end diff --git a/cof/settings/dev.py b/cof/settings/dev.py new file mode 100644 index 00000000..7e1a63a8 --- /dev/null +++ b/cof/settings/dev.py @@ -0,0 +1,58 @@ +"""Django local development settings.""" +import os + +from . import bds_prod +from .cof_prod import * # NOQA +from .cof_prod import INSTALLED_APPS, MIDDLEWARE, TESTING + +# --- +# Merge COF and BDS configs +# --- + +for app in bds_prod.INSTALLED_APPS: + if app not in INSTALLED_APPS: + INSTALLED_APPS.append(app) + +# --- +# Tweaks for debug/local development +# --- + +ALLOWED_HOSTS = [] + +DEBUG = True +EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" + +if TESTING: + PASSWORD_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"] + +STATIC_URL = "/static/" +STATIC_ROOT = "/srv/gestiocof/static" +MEDIA_URL = "/media/" +MEDIA_ROOT = "/srv/gestiocof/media" + + +# --- +# Debug tool bar +# --- + + +def show_toolbar(request): + """ + On active la debug-toolbar en mode développement local sauf : + - dans l'admin où ça ne sert pas à grand chose; + - si la variable d'environnement DJANGO_NO_DDT est à 1 → ça permet de la désactiver + sans modifier ce fichier en exécutant `export DJANGO_NO_DDT=1` dans le terminal + qui lance `./manage.py runserver`. + + Autre side effect de cette fonction : on ne fait pas la vérification de INTERNAL_IPS + que ferait la debug-toolbar par défaut, ce qui la fait fonctionner aussi à + l'intérieur de Vagrant (comportement non testé depuis un moment…) + """ + env_no_ddt = bool(os.environ.get("DJANGO_NO_DDT", None)) + return DEBUG and not env_no_ddt and not request.path.startswith("/admin/") + + +if not TESTING: + INSTALLED_APPS += ["debug_toolbar"] + MIDDLEWARE = ["debug_toolbar.middleware.DebugToolbarMiddleware"] + MIDDLEWARE + DEBUG_TOOLBAR_CONFIG = {"SHOW_TOOLBAR_CALLBACK": show_toolbar} diff --git a/provisioning/bootstrap.sh b/provisioning/bootstrap.sh index cb6917a7..d6b8f914 100644 --- a/provisioning/bootstrap.sh +++ b/provisioning/bootstrap.sh @@ -1,74 +1,141 @@ #!/bin/sh -# Stop if an error is encountered -set -e +# Arête le script quand : +# - une erreur survient +# - on essaie d'utiliser une variable non définie +# - on essaie d'écraser un fichier avec une redirection (>). +set -euC -# Configuration de la base de données. Le mot de passe est constant car c'est +# Configuration de la base de données, redis, Django, etc. +# Tous les mots de passe sont constant et en clair dans le fichier car c'est # pour une installation de dév locale qui ne sera accessible que depuis la # machine virtuelle. -DBUSER="cof_gestion" -DBNAME="cof_gestion" -DBPASSWD="4KZt3nGPLVeWSvtBZPSM3fSzXpzEU4" +readonly DBUSER="cof_gestion" +readonly DBNAME="cof_gestion" +readonly DBPASSWD="4KZt3nGPLVeWSvtBZPSM3fSzXpzEU4" +readonly REDIS_PASSWD="dummy" +readonly DJANGO_SETTINGS_MODULE="cof.settings.dev" -# Installation de paquets utiles -apt-get update && apt-get upgrade -y -apt-get install -y python3-pip python3-dev python3-venv libpq-dev postgresql \ - postgresql-contrib libjpeg-dev nginx git redis-server + +# --- +# Installation des paquets systèmes +# --- + +get_packages_list () { + sed 's/#.*$//' /vagrant/provisioning/packages.list | grep -v '^ *$' +} + +# https://github.com/chef/bento/issues/661 +export DEBIAN_FRONTEND=noninteractive + +apt-get update +apt-get -y upgrade +get_packages_list | xargs apt-get install -y + + +# --- +# Configuration de la base de données +# --- # Postgresql -sudo -u postgres createdb $DBNAME -sudo -u postgres createuser -SdR $DBUSER +pg_user_exists () { + sudo -u postgres psql postgres -tAc \ + "SELECT 1 FROM pg_roles WHERE rolname='$1'" \ + | grep -q '^1$' +} + +pg_db_exists () { + sudo -u postgres psql postgres -tAc \ + "SELECT 1 FROM pg_database WHERE datname='$1'" \ + | grep -q '^1$' +} + +pg_db_exists "$DBNAME" || sudo -u postgres createdb "$DBNAME" +pg_user_exists "$DBUSER" || sudo -u postgres createuser -SdR "$DBUSER" sudo -u postgres psql -c "ALTER USER $DBUSER WITH PASSWORD '$DBPASSWD';" sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE $DBNAME TO $DBUSER;" -# Redis -REDIS_PASSWD="dummy" -redis-cli CONFIG SET requirepass $REDIS_PASSWD -redis-cli -a $REDIS_PASSWD CONFIG REWRITE +# --- +# Configuration de redis (pour django-channels) +# --- -# Contenu statique +# Redis +redis-cli CONFIG SET requirepass "$REDIS_PASSWD" +redis-cli -a "$REDIS_PASSWD" CONFIG REWRITE + + +# --- +# Préparation de Django +# --- + +# Dossiers pour le contenu statique mkdir -p /srv/gestiocof/media mkdir -p /srv/gestiocof/static -chown -R ubuntu:www-data /srv/gestiocof - -# Nginx -ln -s -f /vagrant/provisioning/nginx.conf /etc/nginx/sites-enabled/gestiocof.conf -rm -f /etc/nginx/sites-enabled/default -systemctl reload nginx +chown -R vagrant:www-data /srv/gestiocof # Environnement virtuel python -sudo -H -u ubuntu python3 -m venv ~ubuntu/venv -sudo -H -u ubuntu ~ubuntu/venv/bin/pip install -U pip -sudo -H -u ubuntu ~ubuntu/venv/bin/pip install -r /vagrant/requirements-devel.txt +sudo -H -u vagrant python3 -m venv ~vagrant/venv +sudo -H -u vagrant ~vagrant/venv/bin/pip install -U pip +sudo -H -u vagrant ~vagrant/venv/bin/pip install \ + -r /vagrant/requirements-prod.txt \ + -r /vagrant/requirements-devel.txt \ # Préparation de Django cd /vagrant ln -s -f secret_example.py cof/settings/secret.py -sudo -H -u ubuntu \ - DJANGO_SETTINGS_MODULE='cof.settings.dev' \ - bash -c ". ~/venv/bin/activate && bash provisioning/prepare_django.sh" -/home/ubuntu/venv/bin/python manage.py collectstatic --noinput --settings cof.settings.dev +sudo -H -u vagrant \ + DJANGO_SETTINGS_MODULE="$DJANGO_SETTINGS_MODULE"\ + /bin/sh -c ". ~vagrant/venv/bin/activate && /bin/sh provisioning/prepare_django.sh" +~vagrant/venv/bin/python manage.py collectstatic \ + --noinput \ + --settings "$DJANGO_SETTINGS_MODULE" -# Installation du cron pour les mails de rappels -sudo -H -u ubuntu crontab provisioning/cron.dev -# Daphne + runworker -cp /vagrant/provisioning/daphne.service /etc/systemd/system/daphne.service -cp /vagrant/provisioning/worker.service /etc/systemd/system/worker.service -systemctl enable daphne.service -systemctl enable worker.service -systemctl start daphne.service -systemctl start worker.service +# --- +# Units systemd +# --- -# Mise en place du .bash_profile pour tout configurer lors du `vagrant ssh` -cat >> ~ubuntu/.bashrc < ~vagrant/.bash_aliases <> /vagrant/rappels.log ; /ubuntu/home/venv/bin/python /vagrant/manage.py sendrappels >> /vagrant/rappels.log 2>&1 -*/5 * * * * /ubuntu/home/venv/bin/python /vagrant/manage.py manage_revente >> /vagrant/reventes.log 2>&1 diff --git a/provisioning/nginx.conf b/provisioning/nginx.conf deleted file mode 100644 index 015e1712..00000000 --- a/provisioning/nginx.conf +++ /dev/null @@ -1,56 +0,0 @@ -upstream gestiocof { - # Daphne listens on a unix socket - server unix:/srv/gestiocof/gestiocof.sock; -} - -server { - listen 80; - - server_name localhost; - root /srv/gestiocof/; - - # / → /gestion/ - # /gestion → /gestion/ - rewrite ^/$ /gestion/; - rewrite ^/gestion$ /gestion/; - - # Static files - location /static/ { - access_log off; - add_header Cache-Control "public"; - expires 7d; - } - - # Uploaded media - location /media/ { - access_log off; - add_header Cache-Control "public"; - expires 7d; - } - - location /gestion/ { - # A copy-paste of what we have in production - proxy_set_header Host $http_host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-SSL-Client-Serial $ssl_client_serial; - proxy_set_header X-SSL-Client-Verify $ssl_client_verify; - proxy_set_header X-SSL-Client-S-DN $ssl_client_s_dn; - proxy_set_header Daphne-Root-Path /gestion; - - location /gestion/ws/ { - # See http://nginx.org/en/docs/http/websocket.html - proxy_buffering off; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - - proxy_pass http://gestiocof/ws/; - } - - location /gestion/ { - proxy_pass http://gestiocof; - } - } -} diff --git a/provisioning/nginx/gestiocof.conf b/provisioning/nginx/gestiocof.conf new file mode 100644 index 00000000..f623bcf9 --- /dev/null +++ b/provisioning/nginx/gestiocof.conf @@ -0,0 +1,42 @@ +upstream gestiocof { + # Daphne listens on a unix socket + server unix:/srv/gestiocof/gestiocof.sock; +} + +server { + listen 80; + listen [::]:80; + + server_name _; + root /srv/gestiocof/; + + # Redirection: + rewrite ^/$ http://localhost:8080/gestion/ redirect; + rewrite ^/gestion$ http://localhost:8080/gestion/ redirect; + + # Les pages statiques sont servies à part. + location /gestion/static { try_files $uri $uri/ =404; } + location /gestion/media { try_files $uri $uri/ =404; } + + # On proxy-pass les requêtes vers les pages dynamiques à daphne + location / { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-SSL-Client-Serial $ssl_client_serial; + proxy_set_header X-SSL-Client-Verify $ssl_client_verify; + proxy_set_header X-SSL-Client-S-DN $ssl_client_s_dn; + proxy_pass http://gestiocof; + } + + # Pour les websockets : + # See http://nginx.org/en/docs/http/websocket.html. + location /ws/ { + proxy_buffering off; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_pass http://gestiocof/ws/; + } +} diff --git a/provisioning/packages.list b/provisioning/packages.list new file mode 100644 index 00000000..34714442 --- /dev/null +++ b/provisioning/packages.list @@ -0,0 +1,25 @@ +# Python +python3-pip +python3-dev +python3-venv + +# Pour installer authens depuis git.eleves +git + +# Postgres +libpq-dev +postgresql +postgresql-contrib + +# Pour Pillow +libjpeg-dev + +# Outils de prod +nginx # Test +redis-server + +# Le LDAP +libldap2-dev +libsasl2-dev +slapd +ldap-utils diff --git a/provisioning/prepare_django.sh b/provisioning/prepare_django.sh index 73745544..87cc70b3 100644 --- a/provisioning/prepare_django.sh +++ b/provisioning/prepare_django.sh @@ -1,9 +1,8 @@ -#!/bin/bash +#!/bin/sh -# Stop if an error is encountered. -set -e +set -euC -python manage.py migrate +python manage.py migrate --noinput python manage.py sync_page_translation_fields python manage.py update_translation_fields python manage.py loaddata gestion sites articles diff --git a/provisioning/daphne.service b/provisioning/systemd/daphne.service similarity index 51% rename from provisioning/daphne.service rename to provisioning/systemd/daphne.service index 41327ce5..a9c30008 100644 --- a/provisioning/daphne.service +++ b/provisioning/systemd/daphne.service @@ -1,16 +1,17 @@ -Description="GestioCOF" +Description="GestioCOF - Daphne" After=syslog.target After=network.target [Service] Type=simple -User=ubuntu -Group=ubuntu +User=vagrant +Group=vagrant TimeoutSec=300 WorkingDirectory=/vagrant Environment="DJANGO_SETTINGS_MODULE=cof.settings.dev" -ExecStart=/home/ubuntu/venv/bin/daphne -u /srv/gestiocof/gestiocof.sock \ - cof.asgi:channel_layer +ExecStart=/home/vagrant/venv/bin/daphne \ + -u /srv/gestiocof/gestiocof.sock \ + cof.asgi:channel_layer [Install] WantedBy=multi-user.target diff --git a/provisioning/systemd/rappels.service b/provisioning/systemd/rappels.service new file mode 100644 index 00000000..2d407d53 --- /dev/null +++ b/provisioning/systemd/rappels.service @@ -0,0 +1,8 @@ +[Unit] +Description=Envoi des mails de rappel des spectales BdA + +[Service] +Type=oneshot +User=vagrant +Environment="DJANGO_SETTINGS_MODULE=cof.settings.dev" +ExecStart=/home/vagrant/venv/bin/python /vagrant/manage.py sendrappels diff --git a/provisioning/systemd/rappels.timer b/provisioning/systemd/rappels.timer new file mode 100644 index 00000000..f05c54e0 --- /dev/null +++ b/provisioning/systemd/rappels.timer @@ -0,0 +1,9 @@ +[Unit] +Description=Envoi des mails de rappel des spectales BdA + +[Timer] +OnBootSec=10min +OnUnitActiveSec=3h + +[Install] +WantedBy=timers.target diff --git a/provisioning/systemd/reventes.service b/provisioning/systemd/reventes.service new file mode 100644 index 00000000..bd1992f8 --- /dev/null +++ b/provisioning/systemd/reventes.service @@ -0,0 +1,8 @@ +[Unit] +Description=Envoi des mails de BdA-Revente + +[Service] +Type=oneshot +User=vagrant +Environment="DJANGO_SETTINGS_MODULE=cof.settings.dev" +ExecStart=/home/vagrant/venv/bin/python /vagrant/manage.py manage_reventes diff --git a/provisioning/systemd/reventes.timer b/provisioning/systemd/reventes.timer new file mode 100644 index 00000000..2ccaf7bf --- /dev/null +++ b/provisioning/systemd/reventes.timer @@ -0,0 +1,9 @@ +[Unit] +Description=Envoi des mails de BdA-Revente + +[Timer] +OnBootSec=15min +OnUnitActiveSec=15min + +[Install] +WantedBy=timers.target diff --git a/provisioning/worker.service b/provisioning/systemd/worker.service similarity index 72% rename from provisioning/worker.service rename to provisioning/systemd/worker.service index 42836cfe..69d742dc 100644 --- a/provisioning/worker.service +++ b/provisioning/systemd/worker.service @@ -5,12 +5,12 @@ After=network.target [Service] Type=simple -User=ubuntu -Group=ubuntu +User=vagrant +Group=vagrant TimeoutSec=300 WorkingDirectory=/vagrant Environment="DJANGO_SETTINGS_MODULE=cof.settings.dev" -ExecStart=/home/ubuntu/venv/bin/python manage.py runworker +ExecStart=/home/vagrant/venv/bin/python manage.py runworker [Install] WantedBy=multi-user.target