Compare commits
32 Commits
Author | SHA1 | Date |
---|---|---|
Jérôme Schneider | 20d86da33d | |
Jérôme Schneider | c202c906e9 | |
Jérôme Schneider | d6602f2db5 | |
Jérôme Schneider | 19b4516525 | |
Jérôme Schneider | e31d6413d5 | |
Jérôme Schneider | 1e18e58f34 | |
Jérôme Schneider | 58825e0537 | |
Jérôme Schneider | 24e4a171f6 | |
Benjamin Dauvergne | ed3a95a8b2 | |
Benjamin Dauvergne | 8d6f3993e1 | |
Benjamin Dauvergne | ec65cd8a97 | |
Benjamin Dauvergne | c2e74252d7 | |
Benjamin Dauvergne | 8fc707a0ea | |
Benjamin Dauvergne | b7844f3251 | |
Benjamin Dauvergne | 71865d8aa7 | |
Benjamin Dauvergne | 35d82acd26 | |
Benjamin Dauvergne | 00cbdfeb0a | |
Benjamin Dauvergne | e9a2e2f02d | |
Benjamin Dauvergne | 4023a55b54 | |
Benjamin Dauvergne | e3c7a3b5b8 | |
Benjamin Dauvergne | feacff7e43 | |
Benjamin Dauvergne | fb4de63584 | |
Benjamin Dauvergne | 857bab1aac | |
Benjamin Dauvergne | 337f51d7ee | |
Benjamin Dauvergne | 4748001300 | |
Benjamin Dauvergne | 0fa2179ca0 | |
Benjamin Dauvergne | 7a63397ba0 | |
Benjamin Dauvergne | 1b402d2a7e | |
Benjamin Dauvergne | b6111e6ce2 | |
Benjamin Dauvergne | 7229c9d030 | |
Benjamin Dauvergne | 65b7414813 | |
Benjamin Dauvergne | b4958f4cd4 |
48
README
48
README
|
@ -1,48 +0,0 @@
|
|||
wcsinst
|
||||
=======
|
||||
|
||||
wcsinst is a web application to deploy w.c.s. instances; it is released under
|
||||
the GNU AGPL Licence.
|
||||
|
||||
|
||||
Architecture
|
||||
------------
|
||||
|
||||
This project is composed of two Django applications; wcsinst provides a model
|
||||
and is expected to be installed as part of an administrative portal; wcsinstd
|
||||
provides the web API to deploy w.c.s. instances and should be installed on its
|
||||
own, on the host instances should be deployed.
|
||||
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
If the WCSINSTD_URL environment variable is set, ./manage.py will run itself as
|
||||
a standalone wcsinst (admin) site. Go to /admin/.
|
||||
|
||||
Example: WCSINSTD_URL=http://127.0.0.1:8001/ ./manage.py runserver
|
||||
|
||||
The wcsinstd application expects a WCSINST_WCS_APP_DIR setting, that should
|
||||
point to the w.c.s. application directory (typically /var/lib/wcs/).
|
||||
|
||||
Additionally it expects site skeletons to be made available from the
|
||||
media/skeletons directory; the default skeleton should go in a subdirectory
|
||||
named "default".
|
||||
|
||||
A skeleton directory has the following files:
|
||||
|
||||
- export.wcs: as produced from wcs, admin/export
|
||||
- idff-metadata-template: template file for ID-FF 1.2 metadata (optional)
|
||||
- saml2-metadata-template: template file for SAMLv2 metadata (optional)
|
||||
- private-key.pem & public-key.pem: pair of keys for ID-FF/SAML (optional)
|
||||
- idp-metadata.xml: metadata of the identity provider (optional)
|
||||
- site-options.cfg: template file for the w.c.s. site-options.cfg file
|
||||
- apache-vhost.conf: tempalte file for the Apache virtual host configuration
|
||||
|
||||
The template files contains template strings (cf the Python documentation);
|
||||
there is a single variable made available, named domain (hence ${domain} to
|
||||
use it).
|
||||
|
||||
The wcsinstd application should be able to run "sudo -n /etc/init.d/apache2
|
||||
reload", to reload virtual hosts configuration. Virtual host configuration
|
||||
files are created in $media/vhosts.d
|
|
@ -0,0 +1,5 @@
|
|||
python-wcsinst (0.1-1) unstable; urgency=low
|
||||
|
||||
* Source package initialized manually by looking at python-entrouvert
|
||||
|
||||
-- Benjamin Dauvergne <info@entrouvert.com> Wed, 18 Sep 2013 17:33:52 +0200
|
|
@ -0,0 +1 @@
|
|||
7
|
|
@ -0,0 +1,23 @@
|
|||
Source: python-wcsinst
|
||||
Maintainer: Frédéric Péters <info@entrouvert.com>
|
||||
Section: python
|
||||
Priority: optional
|
||||
Build-Depends: python-setuptools (>= 0.6b3), python-all (>= 2.6), debhelper (>= 7.4.3),
|
||||
python-django (>= 1.5)
|
||||
Standards-Version: 3.9.1
|
||||
X-Python-Version: >= 2.6
|
||||
|
||||
Package: python-wcsinst
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends},
|
||||
python (>= 2.6),
|
||||
python-django (>= 1.5)
|
||||
Description: Remote w.c.s. management framework
|
||||
|
||||
Package: wcsinstd
|
||||
Architecture: all
|
||||
Pre-Depends: python-django (>= 1.5)
|
||||
Depends: ${misc:Depends}, adduser, python-wcsinst, sudo, wcs, python-entrouvert (>= 1.3)
|
||||
Description: Remote w.c.s. instances management daemon
|
||||
wcsinstd allows to create, update and delete w.c.s. instance through a REST API
|
||||
|
|
@ -0,0 +1 @@
|
|||
usr/lib
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/make -f
|
||||
|
||||
%:
|
||||
dh $@ --with python2
|
|
@ -0,0 +1,54 @@
|
|||
[dirs]
|
||||
template_dirs: /var/lib/wcsinstd/templates
|
||||
media_root: /var/lib/wcsinstd/media
|
||||
static_root: /var/lib/wcsinstd/static
|
||||
static_dirs:
|
||||
|
||||
[database]
|
||||
engine: django.db.backends.sqlite3
|
||||
name: /var/lib/wcsinstd/wcsinst.sqlite3
|
||||
host:
|
||||
port:
|
||||
user:
|
||||
password:
|
||||
|
||||
[wcsinstd]
|
||||
url_template: http://%%(domain)s-site.entrouvert.org/
|
||||
wcs_app_dir: /var/lib/wcs-au-quotidien/
|
||||
wcsctl_script: wcsctl -f /etc/wcs/wcs-au-quotidien.cfg
|
||||
|
||||
[cache]
|
||||
memcached: false
|
||||
|
||||
[secrets]
|
||||
secret_key: random-string-of-ascii
|
||||
csrf_secret: random-string-of-ascii
|
||||
|
||||
# all settings in debug section should be false in production
|
||||
# INTERNAL_IPS should be empty in productive environment
|
||||
[debug]
|
||||
general: false
|
||||
template: false
|
||||
toolbar: false
|
||||
internal_ips: 127.0.0.1
|
||||
sentry_dsn:
|
||||
|
||||
[email]
|
||||
server_email: wcsinstd
|
||||
default_from_email: wcsinstd
|
||||
subject_prefix: [wcsinstd]
|
||||
host: localhost
|
||||
port: 25
|
||||
use_tls: no
|
||||
user:
|
||||
password:
|
||||
|
||||
# the [admins] and [managers] sections are special. Just add lines with
|
||||
# full name: email_address@domain.xx
|
||||
# each section must be present but may be empty.
|
||||
[admins]
|
||||
#Entr'ouvert: admin+wcsinstd@entrouvert.com
|
||||
|
||||
[managers]
|
||||
#Entr'ouvert: admin+wcsinstd@entrouvert.com
|
||||
|
|
@ -0,0 +1 @@
|
|||
3.0 (quilt)
|
|
@ -0,0 +1,9 @@
|
|||
etc/wcsinstd
|
||||
usr/lib/wcsinstd
|
||||
var/lib/wcsinstd
|
||||
var/lib/wcsinstd/static
|
||||
var/lib/wcsinstd/extra-static
|
||||
var/lib/wcsinstd/templates
|
||||
var/lib/wcsinstd/media
|
||||
var/run/wcsinstd
|
||||
var/log/wcsinstd
|
|
@ -0,0 +1,171 @@
|
|||
#!/bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: wcsinstd
|
||||
# Required-Start: $network $local_fs
|
||||
# Required-Stop:
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Remote w.c.s. instances management daemon
|
||||
# Description: wcsinstd allows to create, update and delete w.c.s. instances through a REST API
|
||||
### END INIT INFO
|
||||
|
||||
# Author: Jérôme Schneider <jschneider@entrouvert.com>
|
||||
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
||||
DESC=wcsinstd
|
||||
NAME=wcsinstd
|
||||
DAEMON=/usr/bin/gunicorn
|
||||
PIDFILE=/var/run/$NAME/$NAME.pid
|
||||
LOG_DIR=/var/log/$NAME
|
||||
SCRIPTNAME=/etc/init.d/$NAME
|
||||
|
||||
USER=wcs-au-quotidien
|
||||
GROUP=wcs-au-quotidien
|
||||
|
||||
DAEMON_ARGS="--pid $PIDFILE \
|
||||
--user $USER --group $GROUP \
|
||||
--daemon \
|
||||
--access-logfile $LOG_DIR/gunicorn-access.log \
|
||||
--log-file $LOG_DIR/gunicorn-error.log \
|
||||
--bind=127.0.0.1:8092 \
|
||||
--workers=1 \
|
||||
--worker-class=sync \
|
||||
--timeout=60 \
|
||||
wcsinst.wsgi:application"
|
||||
|
||||
export PYTHONPATH=/usr/lib/$NAME
|
||||
|
||||
# Exit if the package is not installed
|
||||
[ -x $DAEMON ] || exit 0
|
||||
|
||||
# Read configuration variable file if it is present
|
||||
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
|
||||
|
||||
# Load the VERBOSE setting and other rcS variables
|
||||
. /lib/init/vars.sh
|
||||
|
||||
# Define LSB log_* functions.
|
||||
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
#
|
||||
# Function that starts the daemon/service
|
||||
#
|
||||
do_start()
|
||||
{
|
||||
# Return
|
||||
# 0 if daemon has been started
|
||||
# 1 if daemon was already running
|
||||
# 2 if daemon could not be started
|
||||
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
|
||||
|| return 1
|
||||
start-stop-daemon --start --quiet --exec $DAEMON -- \
|
||||
$DAEMON_ARGS \
|
||||
|| return 2
|
||||
}
|
||||
|
||||
#
|
||||
# Function that stops the daemon/service
|
||||
#
|
||||
do_stop()
|
||||
{
|
||||
# Return
|
||||
# 0 if daemon has been stopped
|
||||
# 1 if daemon was already stopped
|
||||
# 2 if daemon could not be stopped
|
||||
# other if a failure occurred
|
||||
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE
|
||||
RETVAL="$?"
|
||||
[ "$RETVAL" = 2 ] && return 2
|
||||
# Wait for children to finish too if this is a daemon that forks
|
||||
# and if the daemon is only ever run from this initscript.
|
||||
# If the above conditions are not satisfied then add some other code
|
||||
# that waits for the process to drop all resources that could be
|
||||
# needed by services started subsequently. A last resort is to
|
||||
# sleep for some time.
|
||||
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
|
||||
[ "$?" = 2 ] && return 2
|
||||
# Many daemons don't delete their pidfiles when they exit.
|
||||
rm -f $PIDFILE
|
||||
return "$RETVAL"
|
||||
}
|
||||
|
||||
#
|
||||
# Function that sends a SIGHUP to the daemon/service
|
||||
#
|
||||
do_reload() {
|
||||
#
|
||||
# If the daemon can reload its configuration without
|
||||
# restarting (for example, when it is sent a SIGHUP),
|
||||
# then implement that here.
|
||||
#
|
||||
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
|
||||
return 0
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
log_daemon_msg "Starting $DESC " "$NAME"
|
||||
do_start
|
||||
case "$?" in
|
||||
0|1) log_end_msg 0 ;;
|
||||
2) log_end_msg 1 ;;
|
||||
esac
|
||||
;;
|
||||
stop)
|
||||
log_daemon_msg "Stopping $DESC" "$NAME"
|
||||
do_stop
|
||||
case "$?" in
|
||||
0|1) log_end_msg 0 ;;
|
||||
2) log_end_msg 1 ;;
|
||||
esac
|
||||
;;
|
||||
status)
|
||||
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
|
||||
;;
|
||||
#reload|force-reload)
|
||||
#
|
||||
# If do_reload() is not implemented then leave this commented out
|
||||
# and leave 'force-reload' as an alias for 'restart'.
|
||||
#
|
||||
#log_daemon_msg "Reloading $DESC" "$NAME"
|
||||
#do_reload
|
||||
#log_end_msg $?
|
||||
#;;
|
||||
restart|force-reload)
|
||||
#
|
||||
# If the "reload" option is implemented then remove the
|
||||
# 'force-reload' alias
|
||||
#
|
||||
log_daemon_msg "Restarting $DESC" "$NAME"
|
||||
do_stop
|
||||
case "$?" in
|
||||
0|1)
|
||||
do_start
|
||||
case "$?" in
|
||||
0) log_end_msg 0 ;;
|
||||
1) log_end_msg 1 ;; # Old process is still running
|
||||
*) log_end_msg 1 ;; # Failed to start
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
# Failed to stop
|
||||
log_end_msg 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
manage)
|
||||
shift
|
||||
if [ $(id -un) != $USER ]; then
|
||||
sudo -E -u $USER python /usr/lib/$NAME/manage.py "$@"
|
||||
else
|
||||
python /usr/lib/$NAME/manage.py "$@"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
|
||||
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
|
||||
exit 3
|
||||
;;
|
||||
esac
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
manage.py usr/lib/wcsinstd
|
||||
debian/settings.ini etc/wcsinstd
|
|
@ -0,0 +1,72 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Postinst script for wcsinstd
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
NAME=wcsinstd
|
||||
WCSINSTD_USER=wcs-au-quotidien
|
||||
WCSINSTD_GROUP=wcs-au-quotidien
|
||||
WCSINSTD_HOME=/var/lib/$NAME
|
||||
WCSINSTD_INIT=/etc/init.d/$NAME
|
||||
|
||||
case "$1" in
|
||||
configure)
|
||||
if ! getent group $WCSINSTD_GROUP > /dev/null 2>&1; then
|
||||
echo -n "Adding group $WCSINSTD_GROUP.."
|
||||
addgroup --quiet --system $WCSINSTD_GROUP
|
||||
echo "..done"
|
||||
fi
|
||||
if ! getent passwd $WCSINSTD_USER > /dev/null 2>&1; then
|
||||
echo -n "Adding user $WCSINSTD_USER.."
|
||||
adduser --quiet --system --gecos "wcsinst daemon" \
|
||||
--ingroup $WCSINSTD_GROUP \
|
||||
--no-create-home --home $WCSINSTD_HOME \
|
||||
$WCSINSTD_USER
|
||||
echo "..done"
|
||||
fi
|
||||
|
||||
chown -R $WCSINSTD_USER:$WCSINSTD_GROUP $WCSINSTD_HOME /var/run/$NAME /var/log/$NAME
|
||||
chown -R $WCSINSTD_USER:$WCSINSTD_GROUP $WCSINSTD_HOME/static $WCSINSTD_HOME/extra-static
|
||||
chown -R $WCSINSTD_USER:$WCSINSTD_GROUP $WCSINSTD_HOME/media $WCSINSTD_HOME/templates
|
||||
# echo -n "Initializing sqlite database.."
|
||||
# $WCSINSTD_INIT manage syncdb --migrate
|
||||
echo -n "Generating static files.."
|
||||
$WCSINSTD_INIT manage collectstatic --noinput --link
|
||||
echo "..done"
|
||||
|
||||
;;
|
||||
|
||||
reconfigure)
|
||||
echo -n "Generating static files.."
|
||||
$WCSINSTD_INIT manage collectstatic --noinput --link
|
||||
echo "..done"
|
||||
|
||||
;;
|
||||
|
||||
abort-upgrade|abort-remove|abort-deconfigure)
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "postinst called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$1" in
|
||||
configure)
|
||||
if [ -z "$2" ]; then
|
||||
# echo -n "Initializing sqlite database.."
|
||||
# $WCSINSTD_INIT manage syncdb --migrate
|
||||
true
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# dh_installdeb will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/sh
|
||||
# postrm script for passerelle
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
set -e
|
||||
|
||||
case "$1" in purge)
|
||||
deluser --quiet --system wcsinstd > /dev/null || true
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
exit 0
|
|
@ -1,6 +0,0 @@
|
|||
#!/bin/sh
|
||||
pip install --upgrade pip
|
||||
pip install --upgrade pylint
|
||||
pip install --upgrade -v -r requirements.txt
|
||||
echo Nothing to test for now
|
||||
(pylint -f parseable --rcfile /var/lib/jenkins/pylint.django.rc wcsinst/ | tee pylint.out) || /bin/true
|
10
manage.py
10
manage.py
|
@ -1,10 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
import os
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "wcsinst.settings")
|
||||
|
||||
from django.core.management import execute_from_command_line
|
||||
|
||||
execute_from_command_line(sys.argv)
|
|
@ -1,3 +0,0 @@
|
|||
django < 1.6
|
||||
south>=0.8,<0.9
|
||||
http://pypi.python.org/packages/source/d/django-jsonresponse/django-jsonresponse-0.5.tar.gz
|
33
setup.py
33
setup.py
|
@ -1,33 +0,0 @@
|
|||
#! /usr/bin/python
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
VERSION='0.1'
|
||||
|
||||
def get_version():
|
||||
if os.path.exists('.git'):
|
||||
p = subprocess.Popen(['git','describe','--dirty'], stdout=subprocess.PIPE)
|
||||
result = p.communicate()[0]
|
||||
return result.split()[0].replace('-','.')
|
||||
return VERSION
|
||||
|
||||
setup(name='wcsinst',
|
||||
version=get_version(),
|
||||
license='AGPLv3',
|
||||
description='',
|
||||
url='https://dev.entrouvert.org/projects/wcsinst/',
|
||||
download_url='http://repos.entrouvert.org/wcsinst.git/',
|
||||
author="Entr'ouvert",
|
||||
author_email="info@entrouvert.com",
|
||||
packages=find_packages(os.path.dirname(__file__) or '.'),
|
||||
scripts=['manage.py'],
|
||||
include_package_data = True,
|
||||
install_requires=[
|
||||
'django >= 1.5.1, < 1.6',
|
||||
],
|
||||
dependency_links = [
|
||||
'http://pypi.python.org/packages/source/d/django-jsonresponse/django-jsonresponse-0.5.tar.gz',
|
||||
],
|
||||
)
|
|
@ -1,163 +0,0 @@
|
|||
# Django settings for wcsinst project.
|
||||
|
||||
import os
|
||||
|
||||
DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
|
||||
PROJECT_PATH = os.path.dirname(os.path.dirname(__file__))
|
||||
|
||||
ADMINS = (
|
||||
# ('Your Name', 'your_email@example.com'),
|
||||
)
|
||||
|
||||
MANAGERS = ADMINS
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(PROJECT_PATH, 'wcsinst.sqlite3'),
|
||||
}
|
||||
}
|
||||
|
||||
# Hosts/domain names that are valid for this site; required if DEBUG is False
|
||||
# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
# Local time zone for this installation. Choices can be found here:
|
||||
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
|
||||
# although not all choices may be available on all operating systems.
|
||||
# In a Windows environment this must be set to your system time zone.
|
||||
TIME_ZONE = 'Europe/Brussels'
|
||||
|
||||
# Language code for this installation. All choices can be found here:
|
||||
# http://www.i18nguy.com/unicode/language-identifiers.html
|
||||
LANGUAGE_CODE = 'fr-fr'
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
# If you set this to False, Django will make some optimizations so as not
|
||||
# to load the internationalization machinery.
|
||||
USE_I18N = True
|
||||
|
||||
# If you set this to False, Django will not format dates, numbers and
|
||||
# calendars according to the current locale.
|
||||
USE_L10N = True
|
||||
|
||||
# If you set this to False, Django will not use timezone-aware datetimes.
|
||||
USE_TZ = True
|
||||
|
||||
# Absolute filesystem path to the directory that will hold user-uploaded files.
|
||||
# Example: "/var/www/example.com/media/"
|
||||
MEDIA_ROOT = os.path.join(PROJECT_PATH, 'media')
|
||||
|
||||
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
||||
# trailing slash.
|
||||
# Examples: "http://example.com/media/", "http://media.example.com/"
|
||||
MEDIA_URL = '/media/'
|
||||
|
||||
# Absolute path to the directory static files should be collected to.
|
||||
# Don't put anything in this directory yourself; store your static files
|
||||
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
|
||||
# Example: "/var/www/example.com/static/"
|
||||
STATIC_ROOT = os.path.join(PROJECT_PATH, 'static')
|
||||
|
||||
# URL prefix for static files.
|
||||
# Example: "http://example.com/static/", "http://static.example.com/"
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
# Additional locations of static files
|
||||
STATICFILES_DIRS = (
|
||||
os.path.join(PROJECT_PATH, 'wcsinst', 'static'),
|
||||
)
|
||||
|
||||
# List of finder classes that know how to find static files in
|
||||
# various locations.
|
||||
STATICFILES_FINDERS = (
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
|
||||
)
|
||||
|
||||
# Make this unique, and don't share it with anybody.
|
||||
SECRET_KEY = 'sw-v(^psaet3)44flti-zr!=u64mzfeaodkey(m=&^nz(=43!o'
|
||||
|
||||
# List of callables that know how to import templates from various sources.
|
||||
TEMPLATE_LOADERS = (
|
||||
'django.template.loaders.filesystem.Loader',
|
||||
'django.template.loaders.app_directories.Loader',
|
||||
# 'django.template.loaders.eggs.Loader',
|
||||
)
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
# Uncomment the next line for simple clickjacking protection:
|
||||
# 'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
)
|
||||
|
||||
ROOT_URLCONF = 'wcsinst.urls'
|
||||
|
||||
# Python dotted path to the WSGI application used by Django's runserver.
|
||||
WSGI_APPLICATION = 'wcsinst.wsgi.application'
|
||||
|
||||
TEMPLATE_DIRS = (
|
||||
os.path.join(PROJECT_PATH, 'wcsinst', 'templates'),
|
||||
)
|
||||
|
||||
INSTALLED_APPS = (
|
||||
'south',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.admin',
|
||||
)
|
||||
|
||||
# A sample logging configuration. The only tangible logging
|
||||
# performed by this configuration is to send an email to
|
||||
# the site admins on every HTTP 500 error when DEBUG=False.
|
||||
# See http://docs.djangoproject.com/en/dev/topics/logging for
|
||||
# more details on how to customize your logging configuration.
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'filters': {
|
||||
'require_debug_false': {
|
||||
'()': 'django.utils.log.RequireDebugFalse'
|
||||
}
|
||||
},
|
||||
'handlers': {
|
||||
'mail_admins': {
|
||||
'level': 'ERROR',
|
||||
'filters': ['require_debug_false'],
|
||||
'class': 'django.utils.log.AdminEmailHandler'
|
||||
}
|
||||
},
|
||||
'loggers': {
|
||||
'django.request': {
|
||||
'handlers': ['mail_admins'],
|
||||
'level': 'ERROR',
|
||||
'propagate': True,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
WCSINSTD_URL = os.environ.get('WCSINSTD_URL')
|
||||
|
||||
if WCSINSTD_URL:
|
||||
INSTALLED_APPS += ('wcsinst.wcsinst',)
|
||||
else:
|
||||
INSTALLED_APPS += ('wcsinst.wcsinstd',)
|
||||
|
||||
WCSINST_WCSCTL_SCRIPT = os.environ.get('WCSINST_WCSCTL_SCRIPT', 'wcsctl')
|
||||
|
||||
try:
|
||||
from local_settings import *
|
||||
except ImportError:
|
||||
pass
|
|
@ -1,13 +0,0 @@
|
|||
from django.conf.urls import patterns, include, url
|
||||
from django.conf import settings
|
||||
|
||||
from django.contrib import admin
|
||||
admin.autodiscover()
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
)
|
||||
|
||||
if 'wcsinst.wcsinstd' in settings.INSTALLED_APPS:
|
||||
urlpatterns += patterns('',
|
||||
(r'^wcsinstd/', include('wcsinst.wcsinstd.urls')))
|
|
@ -1,31 +0,0 @@
|
|||
from django.contrib import admin
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from models import WcsInstance, ApiSecret, Variable
|
||||
|
||||
class ApiSecretsInline(admin.TabularInline):
|
||||
model = ApiSecret
|
||||
verbose_name = _('API secret')
|
||||
verbose_name_plural = _('API secrets')
|
||||
|
||||
class VariablesInline(admin.TabularInline):
|
||||
model = Variable
|
||||
verbose_name = _('variable')
|
||||
verbose_name_plural = _('variables')
|
||||
|
||||
class WcsInstanceAdmin(admin.ModelAdmin):
|
||||
prepopulated_fields = {'domain': ('title',)}
|
||||
fieldsets = (
|
||||
(None, {'fields': ('title', 'domain'),}),
|
||||
('site-options.cfg',
|
||||
{'fields': ('postgresql', ('saml2_use_role', 'saml2_role_prefix',), 'backoffice_feed_url' )}
|
||||
),
|
||||
('site-options.cfg au-quotidien',
|
||||
{'fields': ('drupal', 'ezldap', 'strongbox', 'clicrdv', 'domino' )}
|
||||
),
|
||||
)
|
||||
inlines = [VariablesInline, ApiSecretsInline]
|
||||
save_as = True
|
||||
|
||||
|
||||
admin.site.register(WcsInstance, WcsInstanceAdmin)
|
|
@ -1,34 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding model 'WcsInstance'
|
||||
db.create_table(u'wcsinst_wcsinstance', (
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('title', self.gf('django.db.models.fields.CharField')(max_length=50)),
|
||||
('domain', self.gf('django.db.models.fields.CharField')(max_length=100)),
|
||||
))
|
||||
db.send_create_signal(u'wcsinst', ['WcsInstance'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting model 'WcsInstance'
|
||||
db.delete_table(u'wcsinst_wcsinstance')
|
||||
|
||||
|
||||
models = {
|
||||
u'wcsinst.wcsinstance': {
|
||||
'Meta': {'object_name': 'WcsInstance'},
|
||||
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['wcsinst']
|
|
@ -1,142 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding model 'Variable'
|
||||
db.create_table(u'wcsinst_variable', (
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('key', self.gf('django.db.models.fields.CharField')(max_length=128)),
|
||||
('value', self.gf('django.db.models.fields.CharField')(max_length=1024, blank=True)),
|
||||
('wcs_instance', self.gf('django.db.models.fields.related.ForeignKey')(related_name='variables', to=orm['wcsinst.WcsInstance'])),
|
||||
))
|
||||
db.send_create_signal(u'wcsinst', ['Variable'])
|
||||
|
||||
# Adding model 'ApiSecret'
|
||||
db.create_table(u'wcsinst_apisecret', (
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('key', self.gf('django.db.models.fields.CharField')(max_length=128)),
|
||||
('value', self.gf('django.db.models.fields.CharField')(max_length=1024, blank=True)),
|
||||
('wcs_instance', self.gf('django.db.models.fields.related.ForeignKey')(related_name='api_secrets', to=orm['wcsinst.WcsInstance'])),
|
||||
))
|
||||
db.send_create_signal(u'wcsinst', ['ApiSecret'])
|
||||
|
||||
# Adding field 'WcsInstance.postgresql'
|
||||
db.add_column(u'wcsinst_wcsinstance', 'postgresql',
|
||||
self.gf('django.db.models.fields.BooleanField')(default=False),
|
||||
keep_default=False)
|
||||
|
||||
# Adding field 'WcsInstance.saml2_use_role'
|
||||
db.add_column(u'wcsinst_wcsinstance', 'saml2_use_role',
|
||||
self.gf('django.db.models.fields.BooleanField')(default=False),
|
||||
keep_default=False)
|
||||
|
||||
# Adding field 'WcsInstance.saml2_role_prefix'
|
||||
db.add_column(u'wcsinst_wcsinstance', 'saml2_role_prefix',
|
||||
self.gf('django.db.models.fields.CharField')(default='', max_length=128, blank=True),
|
||||
keep_default=False)
|
||||
|
||||
# Adding field 'WcsInstance.backoffice_feed_url'
|
||||
db.add_column(u'wcsinst_wcsinstance', 'backoffice_feed_url',
|
||||
self.gf('django.db.models.fields.URLField')(default='', max_length=128, blank=True),
|
||||
keep_default=False)
|
||||
|
||||
# Adding field 'WcsInstance.drupal'
|
||||
db.add_column(u'wcsinst_wcsinstance', 'drupal',
|
||||
self.gf('django.db.models.fields.BooleanField')(default=False),
|
||||
keep_default=False)
|
||||
|
||||
# Adding field 'WcsInstance.ezldap'
|
||||
db.add_column(u'wcsinst_wcsinstance', 'ezldap',
|
||||
self.gf('django.db.models.fields.BooleanField')(default=False),
|
||||
keep_default=False)
|
||||
|
||||
# Adding field 'WcsInstance.strongbox'
|
||||
db.add_column(u'wcsinst_wcsinstance', 'strongbox',
|
||||
self.gf('django.db.models.fields.BooleanField')(default=False),
|
||||
keep_default=False)
|
||||
|
||||
# Adding field 'WcsInstance.clicrdv'
|
||||
db.add_column(u'wcsinst_wcsinstance', 'clicrdv',
|
||||
self.gf('django.db.models.fields.BooleanField')(default=False),
|
||||
keep_default=False)
|
||||
|
||||
# Adding field 'WcsInstance.domino'
|
||||
db.add_column(u'wcsinst_wcsinstance', 'domino',
|
||||
self.gf('django.db.models.fields.BooleanField')(default=False),
|
||||
keep_default=False)
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting model 'Variable'
|
||||
db.delete_table(u'wcsinst_variable')
|
||||
|
||||
# Deleting model 'ApiSecret'
|
||||
db.delete_table(u'wcsinst_apisecret')
|
||||
|
||||
# Deleting field 'WcsInstance.postgresql'
|
||||
db.delete_column(u'wcsinst_wcsinstance', 'postgresql')
|
||||
|
||||
# Deleting field 'WcsInstance.saml2_use_role'
|
||||
db.delete_column(u'wcsinst_wcsinstance', 'saml2_use_role')
|
||||
|
||||
# Deleting field 'WcsInstance.saml2_role_prefix'
|
||||
db.delete_column(u'wcsinst_wcsinstance', 'saml2_role_prefix')
|
||||
|
||||
# Deleting field 'WcsInstance.backoffice_feed_url'
|
||||
db.delete_column(u'wcsinst_wcsinstance', 'backoffice_feed_url')
|
||||
|
||||
# Deleting field 'WcsInstance.drupal'
|
||||
db.delete_column(u'wcsinst_wcsinstance', 'drupal')
|
||||
|
||||
# Deleting field 'WcsInstance.ezldap'
|
||||
db.delete_column(u'wcsinst_wcsinstance', 'ezldap')
|
||||
|
||||
# Deleting field 'WcsInstance.strongbox'
|
||||
db.delete_column(u'wcsinst_wcsinstance', 'strongbox')
|
||||
|
||||
# Deleting field 'WcsInstance.clicrdv'
|
||||
db.delete_column(u'wcsinst_wcsinstance', 'clicrdv')
|
||||
|
||||
# Deleting field 'WcsInstance.domino'
|
||||
db.delete_column(u'wcsinst_wcsinstance', 'domino')
|
||||
|
||||
|
||||
models = {
|
||||
u'wcsinst.apisecret': {
|
||||
'Meta': {'object_name': 'ApiSecret'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'key': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'value': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'blank': 'True'}),
|
||||
'wcs_instance': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'api_secrets'", 'to': u"orm['wcsinst.WcsInstance']"})
|
||||
},
|
||||
u'wcsinst.variable': {
|
||||
'Meta': {'object_name': 'Variable'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'key': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'value': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'blank': 'True'}),
|
||||
'wcs_instance': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': u"orm['wcsinst.WcsInstance']"})
|
||||
},
|
||||
u'wcsinst.wcsinstance': {
|
||||
'Meta': {'object_name': 'WcsInstance'},
|
||||
'backoffice_feed_url': ('django.db.models.fields.URLField', [], {'max_length': '128', 'blank': 'True'}),
|
||||
'clicrdv': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'domino': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'drupal': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'ezldap': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'postgresql': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'saml2_role_prefix': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
|
||||
'saml2_use_role': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'strongbox': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['wcsinst']
|
|
@ -1,117 +0,0 @@
|
|||
import json
|
||||
import logging
|
||||
import urllib2
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class WcsInstance(models.Model):
|
||||
title = models.CharField(max_length=50)
|
||||
domain = models.CharField(max_length=100)
|
||||
|
||||
# site-options.cfg options
|
||||
postgresql = models.BooleanField(verbose_name=_('postgresql'),
|
||||
blank=True)
|
||||
saml2_use_role = models.BooleanField(verbose_name=_('use saml2 roles'),
|
||||
blank=True)
|
||||
saml2_role_prefix = models.CharField(verbose_name=_('role prefix'),
|
||||
blank=True, max_length=128)
|
||||
backoffice_feed_url = models.URLField(verbose_name=_('backoffice feed url'),
|
||||
blank=True, max_length=128)
|
||||
drupal = models.BooleanField(verbose_name=_('drupal'),
|
||||
blank=True)
|
||||
ezldap = models.BooleanField(verbose_name=_('ezldap'),
|
||||
blank=True)
|
||||
strongbox = models.BooleanField(verbose_name=_('strongbox'),
|
||||
blank=True)
|
||||
clicrdv = models.BooleanField(verbose_name=_('clicrdv'),
|
||||
blank=True)
|
||||
domino = models.BooleanField(verbose_name=_('domino'),
|
||||
blank=True)
|
||||
|
||||
|
||||
def __unicode__(self):
|
||||
return '%s (%s)' % (self.title, self.domain)
|
||||
|
||||
def site_options_cfg(self):
|
||||
d = {
|
||||
'postgresql': self.postgresql,
|
||||
'saml2_use_role': self.saml2_use_role,
|
||||
'saml2_role_prefix': self.saml2_role_prefix,
|
||||
'backoffice_feed_url': self.backoffice_feed_url,
|
||||
'drupal': self.drupal,
|
||||
'ezldap': self.ezldap,
|
||||
'strongbox': self.strongbox,
|
||||
'clicrdv': self.clicrdv,
|
||||
'domino': self.domino,
|
||||
}
|
||||
d['api_secrets'] = dict((kv.key, kv.value) for kv in self.api_secrets.all())
|
||||
d['variables'] = dict((kv.key, kv.value) for kv in self.variables.all())
|
||||
return d
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
'title': self.title,
|
||||
'domain': self.domain,
|
||||
'site_options_cfg': self.site_options_cfg(),
|
||||
}
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
created = (self.id is None)
|
||||
super(WcsInstance, self).save(*args, **kwargs)
|
||||
# notify wcsinstd
|
||||
if not settings.WCSINSTD_URL:
|
||||
return
|
||||
if created:
|
||||
url = settings.WCSINSTD_URL + 'wcsinstd/create'
|
||||
else:
|
||||
url = settings.WCSINSTD_URL + 'wcsinstd/%s/' % self.domain
|
||||
post_data = json.dumps(self.to_json())
|
||||
request = urllib2.Request(url)
|
||||
request.add_header('Accept', 'application/json')
|
||||
request.add_header('Content-Type', 'application/json;charset=UTF-8')
|
||||
request.add_data(post_data)
|
||||
try:
|
||||
p = urllib2.urlopen(request)
|
||||
except urllib2.HTTPError as e:
|
||||
logger.error('wcsinstd HTTP error (%s)', str(e))
|
||||
print e.read()
|
||||
except urllib2.URLError as e:
|
||||
print e
|
||||
logger.error('wcsinstd URL error (%s)', str(e))
|
||||
else:
|
||||
out_data = p.read()
|
||||
p.close()
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('wcs instance')
|
||||
verbose_name_plural = _('wcs instances')
|
||||
|
||||
|
||||
class KeyValue(models.Model):
|
||||
key = models.CharField(max_length=128)
|
||||
value = models.CharField(max_length=1024, blank=True)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class Variable(KeyValue):
|
||||
wcs_instance = models.ForeignKey(WcsInstance, related_name='variables')
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('variable')
|
||||
verbose_name_plural = _('variables')
|
||||
|
||||
|
||||
class ApiSecret(KeyValue):
|
||||
wcs_instance = models.ForeignKey(WcsInstance, related_name='api_secrets')
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('api secret')
|
||||
verbose_name_plural = _('api secrets')
|
||||
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
"""
|
||||
This file demonstrates writing tests using the unittest module. These will pass
|
||||
when you run "manage.py test".
|
||||
|
||||
Replace this with more appropriate tests for your application.
|
||||
"""
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
|
||||
class SimpleTest(TestCase):
|
||||
def test_basic_addition(self):
|
||||
"""
|
||||
Tests that 1 + 1 always equals 2.
|
||||
"""
|
||||
self.assertEqual(1 + 1, 2)
|
|
@ -1 +0,0 @@
|
|||
# Create your views here.
|
|
@ -1,5 +0,0 @@
|
|||
from django.conf import settings
|
||||
|
||||
URL_TEMPLATE = getattr(settings, 'WCSINST_URL_TEMPLATE', 'https://%(domain)s')
|
||||
WCS_APP_DIR = getattr(settings, 'WCSINST_WCS_APP_DIR', None)
|
||||
WCSCTL_SCRIPT = getattr(settings, 'WCSINST_WCSCTL_SCRIPT', 'wcsctl')
|
|
@ -1,226 +0,0 @@
|
|||
import string
|
||||
import cPickle
|
||||
import os
|
||||
import zipfile
|
||||
import subprocess
|
||||
from urlparse import urlparse
|
||||
|
||||
from cStringIO import StringIO
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
import psycopg2
|
||||
|
||||
from . import app_settings
|
||||
|
||||
|
||||
def get_provider_key(provider_id):
|
||||
return provider_id.replace('://', '-').replace('/', '-').replace('?', '-').replace(':', '-')
|
||||
|
||||
|
||||
class DeployInstance(object):
|
||||
skeleton = 'default'
|
||||
|
||||
skel_dir = None
|
||||
collectivity_install_dir = None
|
||||
|
||||
def __init__(self, domain, title, site_options_cfg):
|
||||
self.domain = domain
|
||||
self.title = title
|
||||
self.site_options_cfg = site_options_cfg
|
||||
|
||||
def make(self):
|
||||
self.skel_dir = os.path.join(settings.MEDIA_ROOT, 'skeletons', self.skeleton)
|
||||
|
||||
url_template = app_settings.URL_TEMPLATE
|
||||
self.url = str(url_template % {'domain': self.domain})
|
||||
|
||||
host, path = urlparse(self.url)[1:3]
|
||||
if path.endswith('/'):
|
||||
path = path[:-1]
|
||||
|
||||
coldir = host
|
||||
if path:
|
||||
coldir += path.replace('/', '+')
|
||||
|
||||
self.collectivity_install_dir = os.path.join(app_settings.WCS_APP_DIR, coldir)
|
||||
|
||||
if os.path.exists(self.collectivity_install_dir):
|
||||
# site exists, let's update it
|
||||
pass
|
||||
anew = False
|
||||
else:
|
||||
anew = True
|
||||
os.mkdir(self.collectivity_install_dir)
|
||||
|
||||
z = zipfile.ZipFile(os.path.join(self.skel_dir, 'export.wcs'), 'r')
|
||||
|
||||
for f in z.namelist():
|
||||
path = os.path.join(self.collectivity_install_dir, f)
|
||||
data = z.read(f)
|
||||
if not os.path.exists(os.path.dirname(path)):
|
||||
os.mkdir(os.path.dirname(path))
|
||||
open(path, 'w').write(data)
|
||||
z.close()
|
||||
|
||||
config_file = os.path.join(self.collectivity_install_dir, 'config.pck')
|
||||
if os.path.exists(config_file):
|
||||
wcs_cfg = cPickle.load(file(os.path.join(self.collectivity_install_dir, 'config.pck')))
|
||||
else:
|
||||
wcs_cfg = {}
|
||||
|
||||
has_sql = self.make_sql_config(wcs_cfg)
|
||||
self.make_sso_config(wcs_cfg)
|
||||
self.make_site_options()
|
||||
|
||||
cPickle.dump(wcs_cfg, file(config_file, 'w'))
|
||||
|
||||
if has_sql:
|
||||
self.make_sql_tables(wcs_cfg)
|
||||
|
||||
self.make_apache_vhost()
|
||||
self.reload_apache()
|
||||
|
||||
|
||||
def make_sql_config(self, wcs_cfg):
|
||||
if not wcs_cfg.get('postgresql'):
|
||||
# this is not a site configured to use SQL
|
||||
return False
|
||||
|
||||
database_name = wcs_cfg['postgresql'].get('database', 'wcs')
|
||||
domain_table_name = self.domain.replace('-', '_').replace('.', '_')
|
||||
if '_' in database_name:
|
||||
database_name = '%s_%s' % (database_name.split('_')[0], domain_table_name)
|
||||
else:
|
||||
database_name = '%s_%s' % (database_name, domain_table_name)
|
||||
|
||||
postgresql_cfg = {}
|
||||
for k, v in wcs_cfg['postgresql'].items():
|
||||
if v:
|
||||
postgresql_cfg[k] = v
|
||||
try:
|
||||
pgconn = psycopg2.connect(**postgresql_cfg)
|
||||
except psycopg2.Error:
|
||||
# XXX: log
|
||||
raise
|
||||
|
||||
pgconn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
|
||||
cur = pgconn.cursor()
|
||||
try:
|
||||
cur.execute('''CREATE DATABASE %s''' % database_name)
|
||||
except psycopg2.Error as e:
|
||||
print 'got psycopg2 error:', e
|
||||
cur.close()
|
||||
|
||||
wcs_cfg['postgresql']['database'] = database_name
|
||||
|
||||
return True
|
||||
|
||||
def make_sql_tables(self, wcs_cfg):
|
||||
params = []
|
||||
for param in ('database', 'user', 'password', 'host', 'port'):
|
||||
if wcs_cfg.get('postgresql').get(param):
|
||||
if param == 'database':
|
||||
params.append('--dbname')
|
||||
else:
|
||||
params.append('--' + param)
|
||||
params.append(wcs_cfg.get('postgresql').get(param))
|
||||
os.system('%s convert-to-sql %s %s' % (app_settings.WCSCTL_SCRIPT, ' '.join(params), self.domain))
|
||||
|
||||
def make_sso_config(self, wcs_cfg):
|
||||
has_idff = False
|
||||
has_saml2 = False
|
||||
|
||||
service_provider_configuration = {}
|
||||
|
||||
if self.url.endswith('/'):
|
||||
url_stripped = self.url[:-1]
|
||||
else:
|
||||
url_stripped = self.url
|
||||
|
||||
if os.path.exists(os.path.join(self.skel_dir, 'idff-metadata-template')):
|
||||
# there's a ID-FF metadata template, so we do the ID-FF stuff
|
||||
has_idff = True
|
||||
service_provider_configuration.update({
|
||||
'base_url': '%s/liberty' % url_stripped,
|
||||
'metadata': 'metadata.xml',
|
||||
'providerid': '%s/liberty/metadata' % url_stripped,
|
||||
})
|
||||
|
||||
idff_metadata_template = file(
|
||||
os.path.join(self.skel_dir, 'idff-metadata-template')).read()
|
||||
file(os.path.join(self.collectivity_install_dir, 'metadata.xml'), 'w').write(
|
||||
string.Template(idff_metadata_template).substitute({'url': url_stripped}))
|
||||
|
||||
if os.path.exists(os.path.join(self.skel_dir, 'saml2-metadata-template')):
|
||||
# there's a SAMLv2 metadata template, so we do the SAMLv2 stuff
|
||||
has_saml2 = True
|
||||
service_provider_configuration.update({
|
||||
'saml2_base_url': '%s/saml' % url_stripped,
|
||||
'saml2_metadata': 'saml2-metadata.xml',
|
||||
'saml2_providerid': '%s/saml/metadata' % url_stripped
|
||||
})
|
||||
|
||||
saml2_metadata_template = file(
|
||||
os.path.join(self.skel_dir, 'saml2-metadata-template')).read()
|
||||
file(os.path.join(self.collectivity_install_dir, 'saml2-metadata.xml'), 'w').write(
|
||||
string.Template(saml2_metadata_template).substitute({'url': url_stripped}))
|
||||
|
||||
if has_idff or has_saml2:
|
||||
idp_metadata = ET.parse(file(os.path.join(self.skel_dir, 'idp-metadata.xml')))
|
||||
entity_id = idp_metadata.getroot().attrib['entityID']
|
||||
idp_key = get_provider_key(entity_id)
|
||||
|
||||
wcs_cfg['identification'] = {'methods': ['idp']}
|
||||
wcs_cfg['idp'] = {
|
||||
idp_key: {
|
||||
'metadata': 'provider-%s-metadata.xml' % idp_key,
|
||||
'metadata_url': entity_id,
|
||||
'publickey_url': None,
|
||||
'role': 2}}
|
||||
wcs_cfg['sp'] = {
|
||||
'common_domain': None,
|
||||
'common_domain_getter_url': None,
|
||||
'organization_name': self.title.encode('utf-8'),
|
||||
'privatekey': 'private-key.pem',
|
||||
'publickey': 'public-key.pem'}
|
||||
wcs_cfg['sp'].update(service_provider_configuration)
|
||||
|
||||
file(os.path.join(self.collectivity_install_dir, 'provider-%s-metadata.xml' % idp_key), 'w').write(
|
||||
file(os.path.join(self.skel_dir, 'idp-metadata.xml')).read())
|
||||
file(os.path.join(self.collectivity_install_dir, 'public-key.pem'), 'w').write(
|
||||
file(os.path.join(self.skel_dir, 'public-key.pem')).read())
|
||||
file(os.path.join(self.collectivity_install_dir, 'private-key.pem'), 'w').write(
|
||||
file(os.path.join(self.skel_dir, 'private-key.pem')).read())
|
||||
else:
|
||||
wcs_cfg['identification'] = {'methods': ['password']}
|
||||
|
||||
|
||||
def make_site_options(self):
|
||||
options_template_path = os.path.join(self.skel_dir, 'site-options.cfg')
|
||||
if not os.path.exists(options_template_path):
|
||||
return
|
||||
options_template = file(options_template_path).read()
|
||||
file(os.path.join(self.collectivity_install_dir, 'site-options.cfg'), 'w').write(
|
||||
string.Template(options_template).substitute({
|
||||
'domain': self.domain,
|
||||
'options': self.site_options_cfg
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
def make_apache_vhost(self):
|
||||
apache_vhost_template_path = os.path.join(self.skel_dir, 'apache-vhost.conf')
|
||||
if not os.path.exists(apache_vhost_template_path):
|
||||
return
|
||||
apache_vhost_template = file(apache_vhost_template_path).read()
|
||||
apache_dir = os.path.join(settings.MEDIA_ROOT, 'vhosts.d')
|
||||
if not os.path.exists(apache_dir):
|
||||
os.mkdir(apache_dir)
|
||||
file(os.path.join(apache_dir, '%s.conf' % self.domain), 'w').write(
|
||||
string.Template(apache_vhost_template).substitute({'domain': self.domain}))
|
||||
|
||||
|
||||
def reload_apache(self):
|
||||
os.system('sudo -n /etc/init.d/apache2 reload')
|
|
@ -1,3 +0,0 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
|
@ -1,7 +0,0 @@
|
|||
from django.conf.urls import patterns, url, include
|
||||
|
||||
urlpatterns = patterns('wcsinst.wcsinstd.views',
|
||||
url(r'^create$', 'create'),
|
||||
url(r'^(?P<instance>[\w\.-]+)/$', 'update'),
|
||||
)
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
import json
|
||||
import threading
|
||||
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.decorators.http import require_POST
|
||||
|
||||
from jsonresponse import to_json
|
||||
|
||||
from .deploy import DeployInstance
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
@to_json('api')
|
||||
@require_POST
|
||||
def create(request):
|
||||
data = json.loads(request.body)
|
||||
deploy = DeployInstance(**data)
|
||||
threading.Thread(target=deploy.make).start()
|
||||
return {}
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
@to_json('api')
|
||||
@require_POST
|
||||
def update(request, instance):
|
||||
print 'updating instance:', instance
|
||||
data = json.loads(request.body)
|
||||
if data.get('domain') != instance:
|
||||
raise Exception('domain mismatch') # -> should remove/add ?
|
||||
deploy = DeployInstance(**data)
|
||||
threading.Thread(target=deploy.make).start()
|
||||
return {}
|
|
@ -1,32 +0,0 @@
|
|||
"""
|
||||
WSGI config for wcsinst project.
|
||||
|
||||
This module contains the WSGI application used by Django's development server
|
||||
and any production WSGI deployments. It should expose a module-level variable
|
||||
named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover
|
||||
this application via the ``WSGI_APPLICATION`` setting.
|
||||
|
||||
Usually you will have the standard Django WSGI application here, but it also
|
||||
might make sense to replace the whole Django WSGI application with a custom one
|
||||
that later delegates to the Django one. For example, you could introduce WSGI
|
||||
middleware here, or combine a Django application with an application of another
|
||||
framework.
|
||||
|
||||
"""
|
||||
import os
|
||||
|
||||
# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks
|
||||
# if running multiple sites in the same mod_wsgi process. To fix this, use
|
||||
# mod_wsgi daemon mode with each site in its own daemon process, or use
|
||||
# os.environ["DJANGO_SETTINGS_MODULE"] = "wcsinst.settings"
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "wcsinst.settings")
|
||||
|
||||
# This application object is used by any WSGI server configured to use this
|
||||
# file. This includes Django's development server, if the WSGI_APPLICATION
|
||||
# setting points here.
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
application = get_wsgi_application()
|
||||
|
||||
# Apply WSGI middleware here.
|
||||
# from helloworld.wsgi import HelloWorldApplication
|
||||
# application = HelloWorldApplication(application)
|
Reference in New Issue