From 0cfbf58cdb890f5eaec3b93a0dfbff8824ef8f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Tue, 16 May 2017 11:42:53 +0100 Subject: [PATCH 01/13] Upgrade to Django 1.11 --- evenementiel/settings_dev.py | 2 +- requirements-devel.txt | 1 + requirements.txt | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/evenementiel/settings_dev.py b/evenementiel/settings_dev.py index 54f17a8..3d0f63d 100644 --- a/evenementiel/settings_dev.py +++ b/evenementiel/settings_dev.py @@ -99,7 +99,7 @@ WSGI_APPLICATION = 'evenementiel.wsgi.application' # PostGreSQL DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'ENGINE': 'django.db.backends.postgresql', 'NAME': os.environ['DBNAME'], 'USER': os.environ['DBUSER'], 'PASSWORD': os.environ['DBPASSWD'], diff --git a/requirements-devel.txt b/requirements-devel.txt index dc8dbc4..425dfc3 100644 --- a/requirements-devel.txt +++ b/requirements-devel.txt @@ -1,2 +1,3 @@ +-r requirements.txt django-debug-toolbar ipython diff --git a/requirements.txt b/requirements.txt index 73d7caa..15bac7c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ -Django==1.10.* -Pillow==3.3.0 -psycopg2==2.6.2 +Django==1.11.* +psycopg2 +Pillow django-bootstrap-form==3.2.1 django-widget-tweaks From 981c5cade576d5613eb55fa899b9d1283debd8d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Tue, 16 May 2017 11:43:40 +0100 Subject: [PATCH 02/13] Use the Debian Stretch box in Vagrant --- Vagrantfile | 2 +- provisioning/bootstrap.sh | 35 +++++++++++++++++++++++++---------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/Vagrantfile b/Vagrantfile index c84c3dd..874b923 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -10,7 +10,7 @@ Vagrant.configure(2) do |config| # For a complete reference, please see the online documentation at # https://docs.vagrantup.com. - config.vm.box = "ubuntu/trusty64" + config.vm.box = "debian/stretch64" # On associe le port 80 dans la machine virtuelle avec le port 8080 de notre # ordinateur, et le port 8000 avec le port 8000. diff --git a/provisioning/bootstrap.sh b/provisioning/bootstrap.sh index f0bab20..3acd68f 100644 --- a/provisioning/bootstrap.sh +++ b/provisioning/bootstrap.sh @@ -8,8 +8,9 @@ DBNAME="event_gestion" DBPASSWD="4KZt3nGPLVeWSvtBZPsd9jdssdJMds78" # Installation de paquets utiles -apt-get update && apt-get install -y python3-pip python3-dev \ - libpq-dev postgresql postgresql-contrib libjpeg-dev +apt-get update && apt-get upgrade +apt-get install -y python3-pip python3-dev python3-venv libpq-dev postgresql \ + postgresql-contrib libjpeg-dev # Setup Database and User sudo -u postgres createdb $DBNAME @@ -19,27 +20,41 @@ sudo -u postgres psql -c "ALTER USER $DBUSER CREATEDB;" sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE $DBNAME TO $DBUSER;" # Mise en place du .bash_profile pour tout configurer lors du `vagrant ssh` -cat > ~vagrant/.bash_profile <> ~vagrant/.bashrc < Date: Tue, 16 May 2017 16:13:31 +0100 Subject: [PATCH 03/13] Setup a production-like environment in vagrant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - We already use Daphne and channels to prepare the future use of websockets. - The app is served behind an nginx reverse-proxy - The services we need are managed by systemctl The production-like running instance of GestionÉvénementiel can be accessed on localhost:8080 outside vagrant. --- evenementiel/asgi.py | 7 +++ evenementiel/routing.py | 2 + evenementiel/settings_dev.py | 30 ++++----- provisioning/bootstrap.sh | 114 ++++++++++++++++++++++++++--------- provisioning/daphne.service | 19 ++++++ provisioning/nginx.conf | 40 ++++++++++++ provisioning/worker.service | 19 ++++++ requirements.txt | 5 ++ 8 files changed, 193 insertions(+), 43 deletions(-) create mode 100644 evenementiel/asgi.py create mode 100644 evenementiel/routing.py create mode 100644 provisioning/daphne.service create mode 100644 provisioning/nginx.conf create mode 100644 provisioning/worker.service diff --git a/evenementiel/asgi.py b/evenementiel/asgi.py new file mode 100644 index 0000000..59c5d58 --- /dev/null +++ b/evenementiel/asgi.py @@ -0,0 +1,7 @@ +import os +from channels.asgi import get_channel_layer + +if "DJANGO_SETTINGS_MODULE" not in os.environ: + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "evenementiel.settings") + +channel_layer = get_channel_layer() diff --git a/evenementiel/routing.py b/evenementiel/routing.py new file mode 100644 index 0000000..8f9af19 --- /dev/null +++ b/evenementiel/routing.py @@ -0,0 +1,2 @@ +# Nothing yet +channel_routing = [] diff --git a/evenementiel/settings_dev.py b/evenementiel/settings_dev.py index 3d0f63d..535c6c2 100644 --- a/evenementiel/settings_dev.py +++ b/evenementiel/settings_dev.py @@ -43,6 +43,7 @@ INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'channels', 'bootstrapform', 'debug_toolbar', 'widget_tweaks', @@ -82,21 +83,19 @@ TEMPLATES = [ }, ] -WSGI_APPLICATION = 'evenementiel.wsgi.application' +CHANNEL_LAYERS = { + "default": { + "BACKEND": "asgi_redis.RedisChannelLayer", + "CONFIG": { + "hosts": [( + "redis://:{passwd}@{host}:{port}/{db}" + .format(passwd="dummy", host="localhost", port=6379, db=0) + )], + }, + "ROUTING": "evenementiel.routing.channel_routing", + } +} - -# Database -# https://docs.djangoproject.com/en/1.9/ref/settings/#databases - -# # MySQL -# DATABASES = { -# 'default': { -# 'ENGINE': 'django.db.backends.sqlite3', -# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), -# } -# } - -# PostGreSQL DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', @@ -108,6 +107,9 @@ DATABASES = { } } +STATIC_ROOT = "/srv/GE/static/" +MEDIA_ROOT = "/srv/GE/media/" + # Password validation # https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators diff --git a/provisioning/bootstrap.sh b/provisioning/bootstrap.sh index 3acd68f..2986efe 100644 --- a/provisioning/bootstrap.sh +++ b/provisioning/bootstrap.sh @@ -1,25 +1,102 @@ -#!/bin/sh +#!/bin/bash -# Configuration de la base de données. Le mot de passe est constant car c'est -# pour une installation de dév locale qui ne sera accessible que depuis la -# machine virtuelle. +# The credentials of the database. Can be public since they will only be used in +# the local development environment DBUSER="event_gestion" DBNAME="event_gestion" DBPASSWD="4KZt3nGPLVeWSvtBZPsd9jdssdJMds78" -# Installation de paquets utiles +# Not critical either +REDIS_PASSWD="dummy" + +# It is used in quite a few places +SETTINGS="evenementiel.settings_dev" + +# --- +# Installs the dependencies +# --- + +# System packages apt-get update && apt-get upgrade apt-get install -y python3-pip python3-dev python3-venv libpq-dev postgresql \ - postgresql-contrib libjpeg-dev + postgresql-contrib libjpeg-dev nginx redis-server -# Setup Database and User +# Python packages, in a virtual environment +sudo -H -u vagrant python3 -m venv ~vagrant/venv +sudo -H -u vagrant ~vagrant/venv/bin/pip install -U pip wheel +sudo -H -u vagrant ~vagrant/venv/bin/pip install -U -r /vagrant/requirements-devel.txt + + +# --- +# Setup the production-like environment +# --- + +# Database and User 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 "ALTER USER $DBUSER CREATEDB;" sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE $DBNAME TO $DBUSER;" -# Mise en place du .bash_profile pour tout configurer lors du `vagrant ssh` +# The working directory for Daphne and cie +mkdir -p /srv/GE/{media,static} +chown -R vagrant:vagrant /srv/GE + +# Nginx +cp /vagrant/provisioning/nginx.conf /etc/nginx/sites-available/ge.conf +if [ ! -h /etc/nginx/sites-enabled/ge.conf ] +then + # If the configuration file is not activated yet, activates it + ln -s /etc/nginx/sites-available/ge.conf /etc/nginx/sites-enabled/ge.conf +fi +rm -f /etc/nginx/sites-enabled/default # We do not need this +service nginx restart + +# Daphne and the worker(s) +for service in {daphne,worker}.service +do + cp /vagrant/provisioning/$service /etc/systemd/system/$service + sed "s/{{DBUSER}}/$DBUSER/" -i /etc/systemd/system/$service + sed "s/{{DBNAME}}/$DBNAME/" -i /etc/systemd/system/$service + sed "s/{{DBPASSWD}}/$DBPASSWD/" -i /etc/systemd/system/$service + sed "s/{{SETTINGS}}/$SETTINGS/" -i /etc/systemd/system/$service + systemctl enable $service + systemctl start $service +done + +# Redis +redis-cli CONFIG SET requirepass $REDIS_PASSWD +if [ ! $? ] +then + # In case the requirepass command failed, checks that it was because the + # password was already set *to the right value*. + redis-cli AUTH $REDIS_PASSWD +fi +redis-cli -a $REDIS_PASSWD CONFIG REWRITE + + +# --- +# Prepare Django +# --- + +function venv_python { + sudo -H -u vagrant DJANGO_SETTINGS_MODULE=$SETTINGS \ + DBUSER=$DBUSER DBNAME=$DBNAME DBPASSWD=$DBPASSWD \ + ~vagrant/venv/bin/python \ + $@ +} + +cd /vagrant +venv_python manage.py collectstatic --noinput +venv_python manage.py migrate + +unset venv_python + + +# --- +# Setup a friendly environment for the user +# --- + cat >> ~vagrant/.bashrc < Date: Tue, 16 May 2017 19:52:59 +0100 Subject: [PATCH 04/13] Split the settings in two files, secrets system --- evenementiel/settings/.gitignore | 1 + .../{settings_dev.py => settings/common.py} | 122 ++++++++---------- evenementiel/settings/dev.py | 44 +++++++ evenementiel/settings/secret_example.py | 13 ++ provisioning/bootstrap.sh | 29 +++-- requirements-devel.txt | 1 + 6 files changed, 131 insertions(+), 79 deletions(-) create mode 100644 evenementiel/settings/.gitignore rename evenementiel/{settings_dev.py => settings/common.py} (58%) create mode 100644 evenementiel/settings/dev.py create mode 100644 evenementiel/settings/secret_example.py diff --git a/evenementiel/settings/.gitignore b/evenementiel/settings/.gitignore new file mode 100644 index 0000000..2142506 --- /dev/null +++ b/evenementiel/settings/.gitignore @@ -0,0 +1 @@ +secret.py diff --git a/evenementiel/settings_dev.py b/evenementiel/settings/common.py similarity index 58% rename from evenementiel/settings_dev.py rename to evenementiel/settings/common.py index 535c6c2..6519497 100644 --- a/evenementiel/settings_dev.py +++ b/evenementiel/settings/common.py @@ -1,36 +1,45 @@ +# -*- coding: utf-8 -*- """ -Django settings for evenementiel project. +Django common settings for GestionÉvénementiel -Generated by 'django-admin startproject' using Django 1.9.9. +Everything which is supposed to be identical between the production server and +the local development server should be here. -For more information on this file, see -https://docs.djangoproject.com/en/1.9/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/1.9/ref/settings/ +We also load the secrets in this file. """ import os -from django.core.urlresolvers import reverse_lazy - -# Build paths inside the project like this: os.path.join(BASE_DIR, ...) -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +from . import secret -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = '0@=@$0*2x)x=$6qzf*1a(07she(33zr9vi0+=(yd%3i=i9gp+_' -CREATE_USER_KEY = 'lolilol' # Do not use this one on prod !! - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -ALLOWED_HOSTS = [] +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)) -# Application definition +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") + + +BASE_DIR = os.path.dirname( + os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +) + INSTALLED_APPS = [ 'equipment.apps.EquipmentConfig', @@ -45,12 +54,10 @@ INSTALLED_APPS = [ 'django.contrib.staticfiles', 'channels', 'bootstrapform', - 'debug_toolbar', 'widget_tweaks', ] MIDDLEWARE_CLASSES = [ - 'debug_toolbar.middleware.DebugToolbarMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', @@ -63,8 +70,11 @@ MIDDLEWARE_CLASSES = [ ROOT_URLCONF = 'evenementiel.urls' -LOGIN_REDIRECT_URL = reverse_lazy('shared:home') -LOGOUT_REDIRECT_URL = reverse_lazy('shared:home') +STATIC_URL = "/static/" +MEDIA_URL = "/media/" + +LOGIN_REDIRECT_URL = 'shared:home' +LOGOUT_REDIRECT_URL = 'shared:home' TEMPLATES = [ { @@ -83,19 +93,6 @@ TEMPLATES = [ }, ] -CHANNEL_LAYERS = { - "default": { - "BACKEND": "asgi_redis.RedisChannelLayer", - "CONFIG": { - "hosts": [( - "redis://:{passwd}@{host}:{port}/{db}" - .format(passwd="dummy", host="localhost", port=6379, db=0) - )], - }, - "ROUTING": "evenementiel.routing.channel_routing", - } -} - DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', @@ -107,13 +104,22 @@ DATABASES = { } } -STATIC_ROOT = "/srv/GE/static/" -MEDIA_ROOT = "/srv/GE/media/" - +CHANNEL_LAYERS = { + "default": { + "BACKEND": "asgi_redis.RedisChannelLayer", + "CONFIG": { + "hosts": [( + "redis://:{passwd}@{host}:{port}/{db}" + .format(passwd=REDIS_PASSWD, host=REDIS_HOST, + port=REDIS_PORT, db=REDIS_DB) + )], + }, + "ROUTING": "evenementiel.routing.channel_routing", + } +} # Password validation # https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators - AUTH_PASSWORD_VALIDATORS = [ {'NAME': 'django.contrib.auth.password_validation' '.UserAttributeSimilarityValidator'}, @@ -124,9 +130,8 @@ AUTH_PASSWORD_VALIDATORS = [ '.NumericPasswordValidator'}, ] - # Internationalization -# https://docs.djangoproject.com/en/1.9/topics/i18n/ +# https://docs.djangoproject.com/en/1.8/topics/i18n/ LANGUAGE_CODE = 'en-us' @@ -137,28 +142,3 @@ USE_I18N = True USE_L10N = True USE_TZ = True - - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/1.9/howto/static-files/ - -STATIC_URL = '/static/' - - -def show_toolbar(request): - """ - On ne veut pas la vérification de INTERNAL_IPS faite par la debug-toolbar - car cela interfère avec l'utilisation de Vagrant. En effet, l'adresse de la - machine physique n'est pas forcément connue, et peut difficilement être - mise dans les INTERNAL_IPS. - """ - if not DEBUG: - return False - if request.is_ajax(): - return False - return True - - -DEBUG_TOOLBAR_CONFIG = { - 'SHOW_TOOLBAR_CALLBACK': show_toolbar, -} diff --git a/evenementiel/settings/dev.py b/evenementiel/settings/dev.py new file mode 100644 index 0000000..f65a54c --- /dev/null +++ b/evenementiel/settings/dev.py @@ -0,0 +1,44 @@ +""" +Django development settings for GestionÉvénementiel +The settings that are not listed here are imported from .common +""" + +from .common import * # NOQA + + +EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' + +DEBUG = True + +# Add some debugging tools +INSTALLED_APPS += ["debug_toolbar", "debug_panel"] # NOQA +MIDDLEWARE_CLASSES = ( + ["debug_panel.middleware.DebugPanelMiddleware"] + + MIDDLEWARE_CLASSES # NOQA +) + + +# --- +# Nginx static/media config +# --- + +STATIC_ROOT = "/srv/GE/static/" +MEDIA_ROOT = "/srv/GE/media/" + + +# --- +# Debug tool bar +# --- + +def show_toolbar(request): + """ + On ne veut pas la vérification de INTERNAL_IPS faite par la debug-toolbar + car cela interfère avec l'utilisation de Vagrant. En effet, l'adresse de la + machine physique n'est pas forcément connue, et peut difficilement être + mise dans les INTERNAL_IPS. + """ + return DEBUG # True + +DEBUG_TOOLBAR_CONFIG = { + 'SHOW_TOOLBAR_CALLBACK': show_toolbar, +} diff --git a/evenementiel/settings/secret_example.py b/evenementiel/settings/secret_example.py new file mode 100644 index 0000000..5c1aa0e --- /dev/null +++ b/evenementiel/settings/secret_example.py @@ -0,0 +1,13 @@ +SECRET_KEY = 'dummy_key3i%5cp4)f+ww4-28_w+ly3q9=6imw2ciu&_(5_4ah' +ADMINS = None + +# Postgres +DBNAME = "{{DBNAME}}" +DBUSER = "{{DBUSER}}" +DBPASSWD = "{{DBPASSWD}}" + +# Redis +REDIS_PASSWD = "{{REDIS_PASSWD}}" +REDIS_PORT = 6379 +REDIS_DB = 0 +REDIS_HOST = "127.0.0.1" diff --git a/provisioning/bootstrap.sh b/provisioning/bootstrap.sh index 2986efe..6483f30 100644 --- a/provisioning/bootstrap.sh +++ b/provisioning/bootstrap.sh @@ -10,7 +10,18 @@ DBPASSWD="4KZt3nGPLVeWSvtBZPsd9jdssdJMds78" REDIS_PASSWD="dummy" # It is used in quite a few places -SETTINGS="evenementiel.settings_dev" +SETTINGS="evenementiel.settings.dev" + +# Fills a "templated file" with the information specified in the variables above +# e.g. every occurrence of {{DBUSER}} in the file will be replaced by the value +# of the variable $DBUSER +function fill_template { + sed "s/{{DBUSER}}/$DBUSER/" -i $1 + sed "s/{{DBNAME}}/$DBNAME/" -i $1 + sed "s/{{DBPASSWD}}/$DBPASSWD/" -i $1 + sed "s/{{REDIS_PASSWD}}/$REDIS_PASSWD/" -i $1 + sed "s/{{SETTINGS}}/$SETTINGS/" -i $1 +} # --- # Installs the dependencies @@ -56,10 +67,7 @@ service nginx restart for service in {daphne,worker}.service do cp /vagrant/provisioning/$service /etc/systemd/system/$service - sed "s/{{DBUSER}}/$DBUSER/" -i /etc/systemd/system/$service - sed "s/{{DBNAME}}/$DBNAME/" -i /etc/systemd/system/$service - sed "s/{{DBPASSWD}}/$DBPASSWD/" -i /etc/systemd/system/$service - sed "s/{{SETTINGS}}/$SETTINGS/" -i /etc/systemd/system/$service + fill_template /etc/systemd/system/$service systemctl enable $service systemctl start $service done @@ -79,6 +87,14 @@ redis-cli -a $REDIS_PASSWD CONFIG REWRITE # Prepare Django # --- +cd /vagrant + +# Setup the secrets +sudo -H -u vagrant cp evenementiel/settings/secret_example.py \ + evenementiel/settings/secret.py +fill_template evenementiel/settings/secret.py + +# Run the usual django admin commands function venv_python { sudo -H -u vagrant DJANGO_SETTINGS_MODULE=$SETTINGS \ DBUSER=$DBUSER DBNAME=$DBNAME DBPASSWD=$DBPASSWD \ @@ -86,12 +102,9 @@ function venv_python { $@ } -cd /vagrant venv_python manage.py collectstatic --noinput venv_python manage.py migrate -unset venv_python - # --- # Setup a friendly environment for the user diff --git a/requirements-devel.txt b/requirements-devel.txt index 425dfc3..83053f7 100644 --- a/requirements-devel.txt +++ b/requirements-devel.txt @@ -1,3 +1,4 @@ -r requirements.txt django-debug-toolbar +django-debug-panel ipython From 5dc43b2ac6888f380ac70f2ba9697d1e37775a34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Tue, 16 May 2017 21:43:30 +0100 Subject: [PATCH 05/13] Remove irrelevant environment variables --- evenementiel/settings/common.py | 6 +++--- provisioning/bootstrap.sh | 14 ++++---------- provisioning/daphne.service | 3 --- provisioning/worker.service | 3 --- 4 files changed, 7 insertions(+), 19 deletions(-) diff --git a/evenementiel/settings/common.py b/evenementiel/settings/common.py index 6519497..691730d 100644 --- a/evenementiel/settings/common.py +++ b/evenementiel/settings/common.py @@ -96,9 +96,9 @@ TEMPLATES = [ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', - 'NAME': os.environ['DBNAME'], - 'USER': os.environ['DBUSER'], - 'PASSWORD': os.environ['DBPASSWD'], + 'NAME': DBNAME, + 'USER': DBUSER, + 'PASSWORD': DBPASSWD, 'PORT': 5432, 'HOST': 'localhost', } diff --git a/provisioning/bootstrap.sh b/provisioning/bootstrap.sh index 6483f30..2cbda4b 100644 --- a/provisioning/bootstrap.sh +++ b/provisioning/bootstrap.sh @@ -97,7 +97,6 @@ fill_template evenementiel/settings/secret.py # Run the usual django admin commands function venv_python { sudo -H -u vagrant DJANGO_SETTINGS_MODULE=$SETTINGS \ - DBUSER=$DBUSER DBNAME=$DBNAME DBPASSWD=$DBPASSWD \ ~vagrant/venv/bin/python \ $@ } @@ -112,18 +111,13 @@ venv_python manage.py migrate cat >> ~vagrant/.bashrc < Date: Tue, 16 May 2017 22:00:00 +0100 Subject: [PATCH 06/13] Avoid duplicate lines in .bash{rc,_profile} --- provisioning/bootstrap.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/provisioning/bootstrap.sh b/provisioning/bootstrap.sh index 2cbda4b..15f76d6 100644 --- a/provisioning/bootstrap.sh +++ b/provisioning/bootstrap.sh @@ -109,7 +109,9 @@ venv_python manage.py migrate # Setup a friendly environment for the user # --- -cat >> ~vagrant/.bashrc < ~vagrant/.bash_profile < Date: Wed, 17 May 2017 02:07:06 +0100 Subject: [PATCH 07/13] Some docs about the dev environment in README.md --- README.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/README.md b/README.md index e69de29..92c7cb2 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,41 @@ +# Gestion Événementiel + +## Vagrant + +### Production-like environment + +Our Vagrant setup provides two ways of running GestionEvenementiel: + +1. You can run the usual development server with: + + python manage.py runserver 0.0.0.0:8000 + + Please note that we specify the interface `0.0.0.0` to make the server + reachable outside the VM at address `localhost:8000` + +2. A second instance, more similar to the production environment, runs with + Daphne and nginx in the VM. It runs permanently by default but is not + reloaded when you update the code. To restart this server, type: + + python manage.py collectstatic --noinput + sudo systemctl restart daphne.service worker.service + + To query this instance from the host, you have to use the address + `localhost:8080`. It is a good practice to ensure that this instance works + before submitting a merge request (although it might break sometimes). + + +### About synced folders + +Due to a limitation related to the Debian boxes, VirtualBox synced folders +cannot be enabled. Vagrant uses `rsync` instead to upload the current folder +into the VM at `/vagrant`. But this only occurs once each time you run +`vagrant up` or `vagrant reload`. However you can ask Vagrant to automatically +resync when changes occur in the host with the `vagrant rsync-auto` command. +Please note that this is a **one-way** synchronization. + +For more information: + +- https://wiki.debian.org/Teams/Cloud/VagrantBaseBoxes#Shared_folders +- https://www.vagrantup.com/docs/synced-folders/rsync.html + From 21de45b42a183440d84d0c2f0ddcb4e43e6f8e86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Wed, 17 May 2017 09:55:26 +0100 Subject: [PATCH 08/13] Prevent secret.py from being removed by rsync --- Vagrantfile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Vagrantfile b/Vagrantfile index 874b923..715b1f9 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -17,6 +17,11 @@ Vagrant.configure(2) do |config| config.vm.network :forwarded_port, guest: 80, host: 8080 config.vm.network :forwarded_port, guest: 8000, host: 8000 + # Override the synced folder configuration to prevent the secret file from + # being removed. + config.vm.synced_folder ".", "/vagrant", + rsync__exclude: [".git/", ".vagrant/", "evenementiel/settings/secret.py"] + # 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" From a35148f7be58b31620cea35c89360ce3f8ea3268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Wed, 17 May 2017 16:18:13 +0100 Subject: [PATCH 09/13] Restore the USER_CREATE_KEY --- evenementiel/settings/common.py | 2 ++ evenementiel/settings/secret_example.py | 3 +++ 2 files changed, 5 insertions(+) diff --git a/evenementiel/settings/common.py b/evenementiel/settings/common.py index b5620bb..61bf2d6 100644 --- a/evenementiel/settings/common.py +++ b/evenementiel/settings/common.py @@ -35,6 +35,8 @@ REDIS_DB = import_secret("REDIS_DB") REDIS_HOST = import_secret("REDIS_HOST") REDIS_PORT = import_secret("REDIS_PORT") +CREATE_USER_KEY = import_secret("CREATE_USER_KEY") + BASE_DIR = os.path.dirname( os.path.dirname(os.path.dirname(os.path.abspath(__file__))) diff --git a/evenementiel/settings/secret_example.py b/evenementiel/settings/secret_example.py index 5c1aa0e..1bd3a29 100644 --- a/evenementiel/settings/secret_example.py +++ b/evenementiel/settings/secret_example.py @@ -11,3 +11,6 @@ REDIS_PASSWD = "{{REDIS_PASSWD}}" REDIS_PORT = 6379 REDIS_DB = 0 REDIS_HOST = "127.0.0.1" + +# An other secret key used for user creation +CREATE_USER_KEY = "lolilol" From 27fc3560454ff5383fec5226e3d07106d2555a35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Wed, 17 May 2017 17:19:42 +0100 Subject: [PATCH 10/13] Add a test for the user creation view --- users/tests.py | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/users/tests.py b/users/tests.py index 7ce503c..4d439ba 100644 --- a/users/tests.py +++ b/users/tests.py @@ -1,3 +1,34 @@ -from django.test import TestCase +from django.test import TestCase, Client +from django.conf import settings +from django.contrib.auth.models import User -# Create your tests here. + +class TestUserCreation(TestCase): + def test_create_view(self): + """Create a user using the user creation form""" + user_data = { + "username": "MrsFoobar", + "first_name": "Baz", + "last_name": "Foobar", + "email": "baz@foobar.net", + } + + data = user_data.copy() + data["password1"] = "4zwY5jdI" + data["password2"] = "4zwY5jdI" + data["key"] = settings.CREATE_USER_KEY + + client = Client() + resp = client.post("/user/create/", data) + + # The user redirection means successful form validation + self.assertRedirects(resp, "/") + + # The user should know exist + user = ( + User.objects + .filter(username=data["username"]) + .values(*user_data.keys()) + [0] + ) + self.assertEqual(user_data, user) From a43b7ba9142f4816d6c1de688fa26a6494acde90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Thu, 18 May 2017 14:19:37 +0100 Subject: [PATCH 11/13] Roll back to Debian8 for the vagrant VM --- README.md | 16 ---------------- Vagrantfile | 7 +------ 2 files changed, 1 insertion(+), 22 deletions(-) diff --git a/README.md b/README.md index 92c7cb2..57fcf2b 100644 --- a/README.md +++ b/README.md @@ -23,19 +23,3 @@ Our Vagrant setup provides two ways of running GestionEvenementiel: To query this instance from the host, you have to use the address `localhost:8080`. It is a good practice to ensure that this instance works before submitting a merge request (although it might break sometimes). - - -### About synced folders - -Due to a limitation related to the Debian boxes, VirtualBox synced folders -cannot be enabled. Vagrant uses `rsync` instead to upload the current folder -into the VM at `/vagrant`. But this only occurs once each time you run -`vagrant up` or `vagrant reload`. However you can ask Vagrant to automatically -resync when changes occur in the host with the `vagrant rsync-auto` command. -Please note that this is a **one-way** synchronization. - -For more information: - -- https://wiki.debian.org/Teams/Cloud/VagrantBaseBoxes#Shared_folders -- https://www.vagrantup.com/docs/synced-folders/rsync.html - diff --git a/Vagrantfile b/Vagrantfile index 715b1f9..b853e43 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -10,18 +10,13 @@ Vagrant.configure(2) do |config| # For a complete reference, please see the online documentation at # https://docs.vagrantup.com. - config.vm.box = "debian/stretch64" + config.vm.box = "debian/contrib-jessie64" # 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 - # Override the synced folder configuration to prevent the secret file from - # being removed. - config.vm.synced_folder ".", "/vagrant", - rsync__exclude: [".git/", ".vagrant/", "evenementiel/settings/secret.py"] - # 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" From f105b17e3f8757c3dbd0c2314d677563825117d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Thu, 18 May 2017 16:53:29 +0100 Subject: [PATCH 12/13] replace `[0]` by `.get()` for a more robust test --- users/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/users/tests.py b/users/tests.py index 4d439ba..b0ef62b 100644 --- a/users/tests.py +++ b/users/tests.py @@ -29,6 +29,6 @@ class TestUserCreation(TestCase): User.objects .filter(username=data["username"]) .values(*user_data.keys()) - [0] + .get() ) self.assertEqual(user_data, user) From a53a9249ef6c6b7f30bfe2274efa878970da13b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Thu, 18 May 2017 17:15:14 +0100 Subject: [PATCH 13/13] typo --- users/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/users/tests.py b/users/tests.py index b0ef62b..adf62a8 100644 --- a/users/tests.py +++ b/users/tests.py @@ -24,7 +24,7 @@ class TestUserCreation(TestCase): # The user redirection means successful form validation self.assertRedirects(resp, "/") - # The user should know exist + # The user should now exist user = ( User.objects .filter(username=data["username"])