From e13d68a127eb9c88710a9d195eb815f41390f477 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Tue, 8 Aug 2017 00:03:08 +0100 Subject: [PATCH 01/18] Ignore PyCharm's files --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index f12190af..9e139df9 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,7 @@ venv/ /src media/ *.log + +# PyCharm +.idea +.cache From 88597e62f116fcfa9aa10b53e1de78f0c3bdea14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Tue, 8 Aug 2017 00:06:03 +0100 Subject: [PATCH 02/18] More verbose secret error reporting --- cof/settings/common.py | 50 ++++++++++++++++++++++------------ cof/settings/secret_example.py | 12 ++++++-- 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/cof/settings/common.py b/cof/settings/common.py index ffcb8ee5..73959c71 100644 --- a/cof/settings/common.py +++ b/cof/settings/common.py @@ -8,26 +8,42 @@ the local development server should be here. import os -# Database credentials try: - from .secret import DBNAME, DBUSER, DBPASSWD + from . import secret except ImportError: - # On the local development VM, theses credentials are in the environment - DBNAME = os.environ["DBNAME"] - DBUSER = os.environ["DBUSER"] - DBPASSWD = os.environ["DBPASSWD"] -except KeyError: - raise RuntimeError("Secrets missing") - - -# Other secrets -try: - from .secret import ( - SECRET_KEY, RECAPTCHA_PUBLIC_KEY, RECAPTCHA_PRIVATE_KEY, ADMINS, - REDIS_PASSWD, REDIS_DB, REDIS_HOST, REDIS_PORT, KFETOPEN_TOKEN, + raise ImportError( + "The secret.py file is missing.\n" + "For a development environment, simply copy secret_example.py" ) -except ImportError: - raise RuntimeError("Secrets missing") + + +def import_secret(name): + """ + Shorthand for importing a value from the secret module and raising an + informative exception if a secret is missing. + """ + try: + return getattr(secret, name) + except AttributeError: + raise RuntimeError("Secret missing: {}".format(name)) + + +SECRET_KEY = import_secret("SECRET_KEY") +ADMINS = import_secret("ADMINS") + +DBNAME = import_secret("DBNAME") +DBUSER = import_secret("DBUSER") +DBPASSWD = import_secret("DBPASSWD") + +REDIS_PASSWD = import_secret("REDIS_PASSWD") +REDIS_DB = import_secret("REDIS_DB") +REDIS_HOST = import_secret("REDIS_HOST") +REDIS_PORT = import_secret("REDIS_PORT") + +RECAPTCHA_PUBLIC_KEY = import_secret("RECAPTCHA_PUBLIC_KEY") +RECAPTCHA_PRIVATE_KEY = import_secret("RECAPTCHA_PRIVATE_KEY") + +KFETOPEN_TOKEN = import_secret("KFETOPEN_TOKEN") BASE_DIR = os.path.dirname( diff --git a/cof/settings/secret_example.py b/cof/settings/secret_example.py index a1d35b68..0dbc91dc 100644 --- a/cof/settings/secret_example.py +++ b/cof/settings/secret_example.py @@ -1,10 +1,16 @@ SECRET_KEY = 'q()(zn4m63i%5cp4)f+ww4-28_w+ly3q9=6imw2ciu&_(5_4ah' -RECAPTCHA_PUBLIC_KEY = "DUMMY" -RECAPTCHA_PRIVATE_KEY = "DUMMY" +ADMINS = None + +DBUSER = "cof_gestion" +DBNAME = "cof_gestion" +DBPASSWD = "4KZt3nGPLVeWSvtBZPSM3fSzXpzEU4" + REDIS_PASSWD = "dummy" REDIS_PORT = 6379 REDIS_DB = 0 REDIS_HOST = "127.0.0.1" -ADMINS = None + +RECAPTCHA_PUBLIC_KEY = "DUMMY" +RECAPTCHA_PRIVATE_KEY = "DUMMY" KFETOPEN_TOKEN = "plop" From 784513b3ccee0e2dfd5a2be891e2f17db14facaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Tue, 8 Aug 2017 00:12:09 +0100 Subject: [PATCH 03/18] Use utf8 encoding for the mysql database --- provisioning/bootstrap.sh | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/provisioning/bootstrap.sh b/provisioning/bootstrap.sh index e35af45a..9d210fe8 100644 --- a/provisioning/bootstrap.sh +++ b/provisioning/bootstrap.sh @@ -22,6 +22,7 @@ apt-get install -y mysql-server mysql -uroot -p$DBPASSWD -e "CREATE DATABASE $DBNAME; GRANT ALL PRIVILEGES ON $DBNAME.* TO '$DBUSER'@'localhost' IDENTIFIED BY '$DBPASSWD'" mysql -uroot -p$DBPASSWD -e "GRANT ALL PRIVILEGES ON test_$DBNAME.* TO '$DBUSER'@'localhost'" +mysql -uroot -p$DBPASSWD -e "ALTER DATABASE databasename CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" # Configuration de redis REDIS_PASSWD="dummy" @@ -43,11 +44,6 @@ cat >> ~ubuntu/.bashrc < Date: Tue, 8 Aug 2017 00:19:47 +0100 Subject: [PATCH 04/18] Use the right python interpreter in the cron tasks --- provisioning/cron.dev | 4 ++-- provisioning/cron.md | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/provisioning/cron.dev b/provisioning/cron.dev index 0dab871f..896b5125 100644 --- a/provisioning/cron.dev +++ b/provisioning/cron.dev @@ -6,5 +6,5 @@ DBUSER="cof_gestion" DBNAME="cof_gestion" DBPASSWD="4KZt3nGPLVeWSvtBZPSM3fSzXpzEU4" -19 */12 * * * date >> /vagrant/rappels.log ; python /vagrant/manage.py sendrappels >> /vagrant/rappels.log 2>&1 -*/5 * * * * python /vagrant/manage.py manage_revente >> /vagrant/reventes.log 2>&1 +19 */12 * * * date >> /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/cron.md b/provisioning/cron.md index 840a8716..7aff775b 100644 --- a/provisioning/cron.md +++ b/provisioning/cron.md @@ -9,9 +9,9 @@ envoie les mails de rappels des spectacles à venir (sauf s'ils ont déjà été envoyés). - Un fois toutes les 12 heures me semble bien. -- Penser à utiliser le bon executable python (virtualenvs) et les bonnes - variables d'environnement si besoin. -- Garde les logs peut être une bonne idée. +- Penser à utiliser le bon executable python (virtualenvs) et le bon fichier de + settings pour Django. +- Garder les logs peut être une bonne idée. Exemple : voir le fichier `provisioning/cron.dev`. From 81f3d6ab81dbc0894666b2f99b03e9b2bcadf507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Tue, 8 Aug 2017 00:24:00 +0100 Subject: [PATCH 05/18] Move STATIC_ROOT in production --- cof/settings/prod.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/cof/settings/prod.py b/cof/settings/prod.py index 5fae5651..f6953479 100644 --- a/cof/settings/prod.py +++ b/cof/settings/prod.py @@ -5,7 +5,8 @@ The settings that are not listed here are imported from .common import os -from .common import * +from .common import * # NOQA +from .common import BASE_DIR DEBUG = False @@ -16,7 +17,13 @@ ALLOWED_HOSTS = [ "dev.cof.ens.fr" ] -STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), "static") + +STATIC_ROOT = os.path.join( + os.path.dirname(os.path.dirname(BASE_DIR)), + "public", + "static", +) + STATIC_URL = "/gestion/static/" MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), "media") MEDIA_URL = "/gestion/media/" From a6b0c51d394ee04c6e0c789585146444b74a4aac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Tue, 8 Aug 2017 00:25:13 +0100 Subject: [PATCH 06/18] Add SERVER_EMAIL to the secrets --- cof/settings/common.py | 1 + cof/settings/secret_example.py | 1 + 2 files changed, 2 insertions(+) diff --git a/cof/settings/common.py b/cof/settings/common.py index 73959c71..bdbf179f 100644 --- a/cof/settings/common.py +++ b/cof/settings/common.py @@ -30,6 +30,7 @@ def import_secret(name): SECRET_KEY = import_secret("SECRET_KEY") ADMINS = import_secret("ADMINS") +SERVER_EMAIL = import_secret("SERVER_EMAIL") DBNAME = import_secret("DBNAME") DBUSER = import_secret("DBUSER") diff --git a/cof/settings/secret_example.py b/cof/settings/secret_example.py index 0dbc91dc..5e9bc5ca 100644 --- a/cof/settings/secret_example.py +++ b/cof/settings/secret_example.py @@ -1,5 +1,6 @@ SECRET_KEY = 'q()(zn4m63i%5cp4)f+ww4-28_w+ly3q9=6imw2ciu&_(5_4ah' ADMINS = None +SERVER_EMAIL = "root@vagrant" DBUSER = "cof_gestion" DBNAME = "cof_gestion" From cb1d2535175850acbae13d127d0c1c7114e4d939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Wed, 9 Aug 2017 20:48:20 +0100 Subject: [PATCH 07/18] Local development settings - Add a new settings file for local development - Update README.md according to the new setup --- .gitignore | 1 + README.md | 79 ++++++++---------------------------------- cof/settings/dev.py | 23 ++---------- cof/settings/local.py | 33 ++++++++++++++++++ manage.py | 2 +- requirements-devel.txt | 2 +- 6 files changed, 53 insertions(+), 87 deletions(-) create mode 100644 cof/settings/local.py diff --git a/.gitignore b/.gitignore index 9e139df9..ab791b2e 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ venv/ /src media/ *.log +*.sqlite3 # PyCharm .idea diff --git a/README.md b/README.md index b6017577..f5e93302 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ car par défaut Django n'écoute que sur l'adresse locale de la machine virtuell or vous voudrez accéder à GestioCOF depuis votre machine physique. L'url à entrer dans le navigateur est `localhost:8000`. + #### Serveur de développement type production Sur la VM Vagrant, un serveur apache est configuré pour servir GestioCOF de @@ -79,26 +80,25 @@ Ce serveur se lance tout seul et est accessible en dehors de la VM à l'url change, il faut relancer le worker avec `sudo supervisorctl restart worker` pour visualiser la dernière version du code. + ### Installation manuelle -Si vous optez pour une installation manuelle plutôt que d'utiliser Vagrant, il -est fortement conseillé d'utiliser un environnement virtuel pour Python. +Vous pouvez opter pour une installation manuelle plutôt que d'utiliser Vagrant, +il est fortement conseillé d'utiliser un environnement virtuel pour Python. -Il vous faudra installer pip, les librairies de développement de python, un -client et un serveur MySQL ainsi qu'un serveur redis ; sous Debian et dérivées -(Ubuntu, ...) : +Il vous faudra installer pip, les librairies de développement de python ainsi +que sqlite3, un moteur de base de données léger et simple d'utilisation ; sous +Debian et dérivées (Ubuntu, ...) : - sudo apt-get install python-pip python-dev libmysqlclient-dev redis-server + sudo apt-get install python3-pip python3-dev sqlite3 Si vous décidez d'utiliser un environnement virtuel Python (virtualenv; fortement conseillé), déplacez-vous dans le dossier où est installé GestioCOF (le dossier où se trouve ce README), et créez-le maintenant : - virtualenv env -p $(which python3) + python3 -m venv venv -L'option `-p` sert à préciser l'exécutable python à utiliser. Vous devez choisir -python3, si c'est la version de python par défaut sur votre système, ceci n'est -pas nécessaire. Pour l'activer, il faut faire +Pour l'activer, il faut faire . env/bin/activate @@ -109,61 +109,12 @@ Vous pouvez maintenant installer les dépendances Python depuis le fichier pip install -r requirements-devel.txt -Copiez le fichier `cof/settings_dev.py` dans `cof/settings.py`. +Pour terminer, copier le fichier `cof/settings/secret_example.py` vers +`cof/settings/secret.py`. Sous Linux ou Mac, préférez plutôt un lien symbolique +pour profiter de faon transparent des mises à jour du fichier d'exemple: -#### Installation avec MySQL + ln -s cof/settngs/secret_example.py cof/settings/secret.py -Il faut maintenant installer MySQL. Si vous n'avez pas déjà MySQL installé sur -votre serveur, il faut l'installer ; sous Debian et dérivées (Ubuntu, ...) : - - sudo apt-get install mysql-server - -Il vous demandera un mot de passe pour le compte d'administration MySQL, -notez-le quelque part (ou n'en mettez pas, le serveur n'est accessible que -localement par défaut). Si vous utilisez une autre distribution, consultez la -documentation de votre distribution pour savoir comment changer ce mot de passe -et démarrer le serveur MySQL (c'est automatique sous Ubuntu). - -Vous devez alors créer un utilisateur local et une base `cof_gestion`, avec le -mot de passe de votre choix (remplacez `mot_de_passe`) : - - mysql -uroot -e "CREATE DATABASE cof_gestion; GRANT ALL PRIVILEGES ON cof_gestion.* TO 'cof_gestion'@'localhost' IDENTIFIER BY 'mot_de_passe'" - -Éditez maintenant le fichier `cof/settings.py` pour y intégrer ces changements ; -la définition de `DATABASES` doit ressembler à (à nouveau, remplacez -`mot_de_passe` de façon appropriée) : - - DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'cof_gestion', - 'USER': 'cof_gestion', - 'PASSWORD': 'mot_de_passe', - } - } - -#### Installation avec SQLite - -GestioCOF est installé avec MySQL sur la VM COF, et afin d'avoir un -environnement de développement aussi proche que possible de ce qui tourne en -vrai pour éviter les mauvaises surprises, il est conseillé d'utiliser MySQL sur -votre machine de développement également. Toutefois, GestioCOF devrait -fonctionner avec d'autres moteurs SQL, et certains préfèrent utiliser SQLite -pour sa légèreté et facilité d'installation. - -Si vous décidez d'utiliser SQLite, il faut l'installer ; sous Debian et dérivées : - - sudo apt-get install sqlite3 - -puis éditer le fichier `cof/settings.py` pour que la définition de `DATABASES` -ressemble à : - - DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), - } - } #### Fin d'installation @@ -188,7 +139,7 @@ Vous êtes prêts à développer ! Lancer GestioCOF en faisant Pour mettre à jour les paquets Python, utiliser la commande suivante : - pip install --upgrade -r requirements.txt -r requirements-devel.txt + pip install --upgrade -r requirements-devel.txt Pour mettre à jour les modèles après une migration, il faut ensuite faire : diff --git a/cof/settings/dev.py b/cof/settings/dev.py index ffd34c7d..61201ea5 100644 --- a/cof/settings/dev.py +++ b/cof/settings/dev.py @@ -5,7 +5,8 @@ The settings that are not listed here are imported from .common import os -from .common import * +from .common import * # NOQA +from .common import BASE_DIR, INSTALLED_APPS, MIDDLEWARE_CLASSES EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' @@ -28,26 +29,6 @@ MEDIA_URL = '/media/' # Debug tool bar # --- -# "Versions" panel of django-debug-toolbar <=1.8 is not compatible with -# wagtailmenus. -# See https://github.com/jazzband/django-debug-toolbar/issues/922 -# TODO: Bug should be fixed in ddt 1.9 (not released yet). When fixed, this -# declaration may be removed. -DEBUG_TOOLBAR_PANELS = [ - 'debug_toolbar.panels.timer.TimerPanel', - 'debug_toolbar.panels.settings.SettingsPanel', - 'debug_toolbar.panels.headers.HeadersPanel', - 'debug_toolbar.panels.request.RequestPanel', - 'debug_toolbar.panels.sql.SQLPanel', - 'debug_toolbar.panels.staticfiles.StaticFilesPanel', - 'debug_toolbar.panels.templates.TemplatesPanel', - 'debug_toolbar.panels.cache.CachePanel', - 'debug_toolbar.panels.signals.SignalsPanel', - 'debug_toolbar.panels.logging.LoggingPanel', - 'debug_toolbar.panels.redirects.RedirectsPanel', -] - - def show_toolbar(request): """ On ne veut pas la vérification de INTERNAL_IPS faite par la debug-toolbar diff --git a/cof/settings/local.py b/cof/settings/local.py new file mode 100644 index 00000000..a7ecbe39 --- /dev/null +++ b/cof/settings/local.py @@ -0,0 +1,33 @@ +""" +Django local settings for the cof project. +The settings that are not listed here are imported from .common +""" + +from .dev import * # NOQA + + +# Use sqlite for local development +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": "db.sqlite3", + } +} + +# Use the default cache backend for local development +CACHES = { + "default": { + "BACKEND": "django.core.cache.backends.locmem.LocMemCache" + } +} + +# Use the default in memory asgi backend for local development +CHANNEL_LAYERS = { + "default": { + "BACKEND": "asgiref.inmemory.ChannelLayer", + "ROUTING": "cof.routing.routing", + } +} + +# No need to run collectstatic -> unset STATIC_ROOT +STATIC_ROOT = None diff --git a/manage.py b/manage.py index 7f4e79f6..094ec16f 100644 --- a/manage.py +++ b/manage.py @@ -3,7 +3,7 @@ import os import sys if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cof.settings") + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cof.settings.local") from django.core.management import execute_from_command_line diff --git a/requirements-devel.txt b/requirements-devel.txt index 83053f76..de272491 100644 --- a/requirements-devel.txt +++ b/requirements-devel.txt @@ -1,4 +1,4 @@ -r requirements.txt -django-debug-toolbar +-e git://github.com/jazzband/django-debug-toolbar.git@88ddc7bdf39c7ff660eac054eab225ac22926754#egg=django-debug-toolbar django-debug-panel ipython From ad15c452375ce7cd9b027e89e96b7fe55a682946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Wed, 9 Aug 2017 22:07:49 +0100 Subject: [PATCH 08/18] Switch to nginx + postgres in vagrant --- cof/settings/common.py | 2 +- cof/settings/dev.py | 4 +- provisioning/apache.conf | 39 ------------------- provisioning/bootstrap.sh | 73 +++++++++++++++--------------------- provisioning/daphne.service | 16 ++++++++ provisioning/nginx.conf | 40 ++++++++++++++++++++ provisioning/supervisor.conf | 20 ---------- provisioning/worker.service | 16 ++++++++ requirements.txt | 2 +- 9 files changed, 107 insertions(+), 105 deletions(-) delete mode 100644 provisioning/apache.conf create mode 100644 provisioning/daphne.service create mode 100644 provisioning/nginx.conf delete mode 100644 provisioning/supervisor.conf create mode 100644 provisioning/worker.service diff --git a/cof/settings/common.py b/cof/settings/common.py index bdbf179f..ba0b6044 100644 --- a/cof/settings/common.py +++ b/cof/settings/common.py @@ -136,7 +136,7 @@ TEMPLATES = [ DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.mysql', + 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': DBNAME, 'USER': DBUSER, 'PASSWORD': DBPASSWD, diff --git a/cof/settings/dev.py b/cof/settings/dev.py index 61201ea5..01651bba 100644 --- a/cof/settings/dev.py +++ b/cof/settings/dev.py @@ -19,9 +19,9 @@ DEBUG = True # --- STATIC_URL = '/static/' -STATIC_ROOT = '/var/www/static/' +STATIC_ROOT = '/srv/gestiocof/static/' -MEDIA_ROOT = os.path.join(BASE_DIR, 'media/') +MEDIA_ROOT = '/srv/gestiocof/media/' MEDIA_URL = '/media/' diff --git a/provisioning/apache.conf b/provisioning/apache.conf deleted file mode 100644 index db5bd602..00000000 --- a/provisioning/apache.conf +++ /dev/null @@ -1,39 +0,0 @@ - - ServerName default - DocumentRoot /var/www/html - - ProxyPreserveHost On - ProxyRequests Off - ProxyPass /static/ ! - ProxyPass /media/ ! - # Pour utiliser un sous-dossier (typiquement /gestion/), il faut faire a la - # place des lignes suivantes: - # - # RequestHeader set Daphne-Root-Path /gestion - # ProxyPass /gestion/ws/ ws://127.0.0.1:8001/ws/ - # ProxyPass /gestion http://127.0.0.1:8001/gestion - # ProxyPassReverse /gestion http://127.0.0.1:8001/gestion - # - # Penser egalement a changer les /static/ et /media/ dans la config apache - # ainsi que dans les settings django. - ProxyPass /ws/ ws://127.0.0.1:8001/ws/ - ProxyPass / http://127.0.0.1:8001/ - ProxyPassReverse / http://127.0.0.1:8001/ - - Alias /media /vagrant/media - Alias /static /var/www/static - - Order deny,allow - Allow from all - - - Order deny,allow - Allow from all - - - ErrorLog ${APACHE_LOG_DIR}/error.log - CustomLog ${APACHE_LOG_DIR}/access.log combined - - - -# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/provisioning/bootstrap.sh b/provisioning/bootstrap.sh index 9d210fe8..dd4f1634 100644 --- a/provisioning/bootstrap.sh +++ b/provisioning/bootstrap.sh @@ -9,44 +9,48 @@ DBPASSWD="4KZt3nGPLVeWSvtBZPSM3fSzXpzEU4" # Installation de paquets utiles apt-get update && apt-get upgrade -y -apt-get install -y python3-pip python3-dev python3-venv libmysqlclient-dev \ - libjpeg-dev git redis-server +apt-get install -y python3-pip python3-dev python3-venv libpq-dev postgresql \ + postgresql-contrib libjpeg-dev nginx git redis-server -# Configuration et installation de mysql. Le mot de passe root est le même que -# le mot de passe pour l'utilisateur local - pour rappel, ceci est une instance -# locale de développement. -echo "mysql-server mysql-server/root_password password $DBPASSWD" | debconf-set-selections -echo "mysql-server mysql-server/root_password_again password $DBPASSWD" | debconf-set-selections +# Postgresql +sudo -u postgres createdb $DBNAME +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;" -apt-get install -y mysql-server -mysql -uroot -p$DBPASSWD -e "CREATE DATABASE $DBNAME; GRANT ALL PRIVILEGES ON $DBNAME.* TO '$DBUSER'@'localhost' IDENTIFIED BY '$DBPASSWD'" -mysql -uroot -p$DBPASSWD -e "GRANT ALL PRIVILEGES ON test_$DBNAME.* TO '$DBUSER'@'localhost'" -mysql -uroot -p$DBPASSWD -e "ALTER DATABASE databasename CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" - -# Configuration de redis +# Redis REDIS_PASSWD="dummy" redis-cli CONFIG SET requirepass $REDIS_PASSWD redis-cli -a $REDIS_PASSWD CONFIG REWRITE -# Installation et configuration d'Apache -apt-get install -y apache2 -a2enmod proxy proxy_http proxy_wstunnel headers -cp /vagrant/provisioning/apache.conf /etc/apache2/sites-available/gestiocof.conf -a2ensite gestiocof -a2dissite 000-default -service apache2 restart -mkdir /var/www/static -chown -R ubuntu:www-data /var/www/static +# Contenu static +mkdir -p /srv/gestiocof/{media,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 + +# 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 + +# 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 # Mise en place du .bash_profile pour tout configurer lors du `vagrant ssh` cat >> ~ubuntu/.bashrc < Date: Thu, 10 Aug 2017 16:31:09 +0100 Subject: [PATCH 09/18] Fix symlink for secret.py --- README.md | 2 +- provisioning/bootstrap.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f5e93302..9ba4642b 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ Pour terminer, copier le fichier `cof/settings/secret_example.py` vers `cof/settings/secret.py`. Sous Linux ou Mac, préférez plutôt un lien symbolique pour profiter de faon transparent des mises à jour du fichier d'exemple: - ln -s cof/settngs/secret_example.py cof/settings/secret.py + ln -s secret_example.py cof/settings/secret.py #### Fin d'installation diff --git a/provisioning/bootstrap.sh b/provisioning/bootstrap.sh index dd4f1634..f604cad0 100644 --- a/provisioning/bootstrap.sh +++ b/provisioning/bootstrap.sh @@ -61,7 +61,7 @@ EOF cd /vagrant # Préparation de Django -ln -s -f cof/settings/secret_example.py cof/settings/secret.py +ln -s -f secret_example.py cof/settings/secret.py sudo -H -u ubuntu DJANGO_SETTINGS_MODULE='cof.settings.dev' bash provisioning/prepare_django.sh # Installation du cron pour les mails de rappels From 4075fcaa643a14d21a350db79a987bed4852e2e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Thu, 10 Aug 2017 16:35:41 +0100 Subject: [PATCH 10/18] typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9ba4642b..982f69fd 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ Vous pouvez maintenant installer les dépendances Python depuis le fichier Pour terminer, copier le fichier `cof/settings/secret_example.py` vers `cof/settings/secret.py`. Sous Linux ou Mac, préférez plutôt un lien symbolique -pour profiter de faon transparent des mises à jour du fichier d'exemple: +pour profiter de façon transparente des mises à jour du fichier d'exemple: ln -s secret_example.py cof/settings/secret.py From 73296ea251b14725f97ec9a7629c8d27f362324a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Thu, 10 Aug 2017 16:55:36 +0100 Subject: [PATCH 11/18] Setup django before launching daphne + Django --- provisioning/bootstrap.sh | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/provisioning/bootstrap.sh b/provisioning/bootstrap.sh index f604cad0..827db06d 100644 --- a/provisioning/bootstrap.sh +++ b/provisioning/bootstrap.sh @@ -38,6 +38,14 @@ 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 +# 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 provisioning/prepare_django.sh + +# 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 @@ -57,12 +65,3 @@ source ~/venv/bin/activate # On va dans /vagrant où se trouve le code de gestioCOF cd /vagrant EOF - -cd /vagrant - -# Préparation de Django -ln -s -f secret_example.py cof/settings/secret.py -sudo -H -u ubuntu DJANGO_SETTINGS_MODULE='cof.settings.dev' bash provisioning/prepare_django.sh - -# Installation du cron pour les mails de rappels -sudo -H -u ubuntu crontab provisioning/cron.dev From dae418af3d89105ecc54a74a14dc82b7eabba30b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Thu, 10 Aug 2017 16:56:03 +0100 Subject: [PATCH 12/18] Handle websockets in nginx.conf --- provisioning/nginx.conf | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/provisioning/nginx.conf b/provisioning/nginx.conf index 07f290f3..d2f55bd0 100644 --- a/provisioning/nginx.conf +++ b/provisioning/nginx.conf @@ -9,7 +9,7 @@ server { server_name localhost; # All the trafic is routed to Daphne - location ~ ^/ { + location / { # A copy-paste of what we have in production proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; @@ -18,21 +18,42 @@ server { 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; + # Reverse-proxy proxy_pass http://gestiocof; } + # Upgrading the connection when handling websockets + location /ws/ { + # 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; + + # 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; + } + # Static files - location ~ ^/static/ { - root /srv/gestiocof/static/; + location /static/ { + root /srv/gestiocof/; access_log off; add_header Cache-Control "public"; expires 7d; } # Uploaded media - location ~ ^/media/ { - root /srv/gestiocof/static/; + location /media/ { + root /srv/gestiocof/; access_log off; add_header Cache-Control "public"; expires 7d; From 522acafb2ee68645af72eafa3c48dcd21b1dbf57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Thu, 10 Aug 2017 16:56:20 +0100 Subject: [PATCH 13/18] Add python dependency for Debian9 --- requirements.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/requirements.txt b/requirements.txt index c12798dc..f3964212 100644 --- a/requirements.txt +++ b/requirements.txt @@ -25,3 +25,6 @@ channels==1.1.5 python-dateutil wagtail==1.10.* wagtailmenus==2.2.* + +# Production tools +wheel From 853fa57ce4945abfd3541844430a4b1ab0954c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Fri, 11 Aug 2017 15:45:19 +0100 Subject: [PATCH 14/18] In README.md: typo env -> venv --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 982f69fd..e5ac882f 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ fortement conseillé), déplacez-vous dans le dossier où est installé GestioCO Pour l'activer, il faut faire - . env/bin/activate + . venv/bin/activate dans le même dossier. From 59231661968b0435add613edf5c5c0ebc30d3e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Fri, 11 Aug 2017 17:24:09 +0100 Subject: [PATCH 15/18] Specify the full path of the sqlite database --- cof/settings/local.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cof/settings/local.py b/cof/settings/local.py index a7ecbe39..6e1f0802 100644 --- a/cof/settings/local.py +++ b/cof/settings/local.py @@ -3,14 +3,17 @@ Django local settings for the cof project. The settings that are not listed here are imported from .common """ +import os + from .dev import * # NOQA +from .dev import BASE_DIR # Use sqlite for local development DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", - "NAME": "db.sqlite3", + "NAME": os.path.join(BASE_DIR, "db.sqlite3") } } From 4d026407d104ebc260c051b340540a9e14be038b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Fri, 11 Aug 2017 23:56:02 +0100 Subject: [PATCH 16/18] Quicker setup for local development --- README.md | 39 +++++++++++++++------------------- provisioning/bootstrap.sh | 5 ++++- provisioning/prepare_django.sh | 3 --- 3 files changed, 21 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index e5ac882f..0e84146b 100644 --- a/README.md +++ b/README.md @@ -69,16 +69,17 @@ entrer dans le navigateur est `localhost:8000`. #### Serveur de développement type production -Sur la VM Vagrant, un serveur apache est configuré pour servir GestioCOF de -façon similaire à la version en production : on utilise +Juste histoire de jouer, pas indispensable pour développer : + +La VM Vagrant héberge en plus un serveur nginx configuré pour servir GestioCOF +comme en production : on utilise [Daphne](https://github.com/django/daphne/) et `python manage.py runworker` -derrière un reverse-proxy apache. Le tout est monitoré par -[supervisor](http://supervisord.org/). +derrière un reverse-proxy nginx. Ce serveur se lance tout seul et est accessible en dehors de la VM à l'url `localhost:8080`. Toutefois il ne se recharge pas tout seul lorsque le code -change, il faut relancer le worker avec `sudo supervisorctl restart worker` pour -visualiser la dernière version du code. +change, il faut relancer le worker avec `sudo systemctl restart worker.service` +pour visualiser la dernière version du code. ### Installation manuelle @@ -87,7 +88,7 @@ Vous pouvez opter pour une installation manuelle plutôt que d'utiliser Vagrant, il est fortement conseillé d'utiliser un environnement virtuel pour Python. Il vous faudra installer pip, les librairies de développement de python ainsi -que sqlite3, un moteur de base de données léger et simple d'utilisation ; sous +que sqlite3, un moteur de base de données léger et simple d'utilisation. Sous Debian et dérivées (Ubuntu, ...) : sudo apt-get install python3-pip python3-dev sqlite3 @@ -107,29 +108,23 @@ dans le même dossier. Vous pouvez maintenant installer les dépendances Python depuis le fichier `requirements-devel.txt` : + pip install -U pip pip install -r requirements-devel.txt Pour terminer, copier le fichier `cof/settings/secret_example.py` vers `cof/settings/secret.py`. Sous Linux ou Mac, préférez plutôt un lien symbolique -pour profiter de façon transparente des mises à jour du fichier d'exemple: +pour profiter de façon transparente des mises à jour du fichier: ln -s secret_example.py cof/settings/secret.py #### Fin d'installation -Il ne vous reste plus qu'à initialiser les modèles de Django avec la commande suivante : +Il ne vous reste plus qu'à initialiser les modèles de Django et peupler la base +de donnée avec les données nécessaires au bon fonctionnement de GestioCOF + des +données bidons bien pratiques pour développer avec la commande suivante : - python manage.py migrate - -Charger les mails indispensables au bon fonctionnement de GestioCOF : - - python manage.py syncmails - -Une base de donnée pré-remplie est disponible en lançant les commandes : - - python manage.py loaddata gestion sites articles - python manage.py loaddevdata + bash provisioning/prepare_django.sh Vous êtes prêts à développer ! Lancer GestioCOF en faisant @@ -148,6 +143,6 @@ Pour mettre à jour les modèles après une migration, il faut ensuite faire : ## Documentation utilisateur -Une brève documentation utilisateur pour se familiariser plus vite avec l'outil -est accessible sur le -[wiki](https://git.eleves.ens.fr/cof-geek/gestioCOF/wikis/home). +Une brève documentation utilisateur est accessible sur le +[wiki](https://git.eleves.ens.fr/cof-geek/gestioCOF/wikis/home) pour avoir une +idée de la façon dont le COF utilise GestioCOF. diff --git a/provisioning/bootstrap.sh b/provisioning/bootstrap.sh index 827db06d..4505db3f 100644 --- a/provisioning/bootstrap.sh +++ b/provisioning/bootstrap.sh @@ -41,7 +41,10 @@ sudo -H -u ubuntu ~ubuntu/venv/bin/pip install -r /vagrant/requirements-devel.tx # 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 provisioning/prepare_django.sh +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 # Installation du cron pour les mails de rappels sudo -H -u ubuntu crontab provisioning/cron.dev diff --git a/provisioning/prepare_django.sh b/provisioning/prepare_django.sh index 4ec1a70f..1818a0cd 100644 --- a/provisioning/prepare_django.sh +++ b/provisioning/prepare_django.sh @@ -1,9 +1,6 @@ #!/bin/bash -# Doit être lancé par bootstrap.sh -source ~/venv/bin/activate python manage.py migrate python manage.py loaddata gestion sites articles python manage.py loaddevdata python manage.py syncmails -python manage.py collectstatic --noinput From 4c08962e093f31b65ad8a154887912685d99f9ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 13 Aug 2017 13:39:13 +0100 Subject: [PATCH 17/18] Hide more stuff in secret.py --- cof/settings/prod.py | 4 ---- cof/settings/secret_example.py | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cof/settings/prod.py b/cof/settings/prod.py index f6953479..286b5547 100644 --- a/cof/settings/prod.py +++ b/cof/settings/prod.py @@ -27,7 +27,3 @@ STATIC_ROOT = os.path.join( STATIC_URL = "/gestion/static/" MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), "media") MEDIA_URL = "/gestion/media/" - -LDAP_SERVER_URL = "ldaps://ldap.spi.ens.fr:636" - -EMAIL_HOST = "nef.ens.fr" diff --git a/cof/settings/secret_example.py b/cof/settings/secret_example.py index 5e9bc5ca..e9c0e63c 100644 --- a/cof/settings/secret_example.py +++ b/cof/settings/secret_example.py @@ -14,4 +14,7 @@ REDIS_HOST = "127.0.0.1" RECAPTCHA_PUBLIC_KEY = "DUMMY" RECAPTCHA_PRIVATE_KEY = "DUMMY" +EMAIL_HOST = None + KFETOPEN_TOKEN = "plop" +LDAP_SERVER_URL = None From 2a519bfedf1c650453cafa84d61cc79e90f892e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 13 Aug 2017 14:36:45 +0100 Subject: [PATCH 18/18] Add SCRIPT_NAME to the production-like server --- README.md | 6 ++-- cof/settings/dev.py | 4 +-- provisioning/bootstrap.sh | 5 +-- provisioning/nginx.conf | 67 ++++++++++++++++++--------------------- 4 files changed, 38 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 0e84146b..01f4ead2 100644 --- a/README.md +++ b/README.md @@ -77,9 +77,9 @@ comme en production : on utilise derrière un reverse-proxy nginx. Ce serveur se lance tout seul et est accessible en dehors de la VM à l'url -`localhost:8080`. Toutefois il ne se recharge pas tout seul lorsque le code -change, il faut relancer le worker avec `sudo systemctl restart worker.service` -pour visualiser la dernière version du code. +`localhost:8080/gestion/`. Toutefois il ne se recharge pas tout seul lorsque le +code change, il faut relancer le worker avec `sudo systemctl restart +worker.service` pour visualiser la dernière version du code. ### Installation manuelle diff --git a/cof/settings/dev.py b/cof/settings/dev.py index 01651bba..9c622063 100644 --- a/cof/settings/dev.py +++ b/cof/settings/dev.py @@ -3,10 +3,8 @@ Django development settings for the cof project. The settings that are not listed here are imported from .common """ -import os - from .common import * # NOQA -from .common import BASE_DIR, INSTALLED_APPS, MIDDLEWARE_CLASSES +from .common import INSTALLED_APPS, MIDDLEWARE_CLASSES EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' diff --git a/provisioning/bootstrap.sh b/provisioning/bootstrap.sh index 4505db3f..69bbcf4c 100644 --- a/provisioning/bootstrap.sh +++ b/provisioning/bootstrap.sh @@ -24,8 +24,9 @@ REDIS_PASSWD="dummy" redis-cli CONFIG SET requirepass $REDIS_PASSWD redis-cli -a $REDIS_PASSWD CONFIG REWRITE -# Contenu static -mkdir -p /srv/gestiocof/{media,static} +# Contenu statique +mkdir -p /srv/gestiocof/media +mkdir -p /srv/gestiocof/static chown -R ubuntu:www-data /srv/gestiocof # Nginx diff --git a/provisioning/nginx.conf b/provisioning/nginx.conf index d2f55bd0..015e1712 100644 --- a/provisioning/nginx.conf +++ b/provisioning/nginx.conf @@ -7,45 +7,15 @@ server { listen 80; server_name localhost; + root /srv/gestiocof/; - # All the trafic is routed to Daphne - location / { - # 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; - - # Reverse-proxy - proxy_pass http://gestiocof; - } - - # Upgrading the connection when handling websockets - location /ws/ { - # 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; - - # 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; - } + # / → /gestion/ + # /gestion → /gestion/ + rewrite ^/$ /gestion/; + rewrite ^/gestion$ /gestion/; # Static files location /static/ { - root /srv/gestiocof/; access_log off; add_header Cache-Control "public"; expires 7d; @@ -53,9 +23,34 @@ server { # Uploaded media location /media/ { - root /srv/gestiocof/; 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; + } + } }