merge 44634d19db32
authorymh <ymh.work@gmail.com>
Thu, 10 Apr 2014 17:32:23 +0200
changeset 634 fc13092973c2
parent 630 36ef50b63372 (diff)
parent 633 44634d19db32 (current diff)
child 639 7fd9232d4c88
merge 44634d19db32
--- a/.hgignore	Wed Apr 09 18:38:55 2014 +0200
+++ b/.hgignore	Thu Apr 10 17:32:23 2014 +0200
@@ -9,10 +9,18 @@
 develop-eggs
 downloads
 .settings
-
 src/comt.egg-info
 .installed.cfg
 recreate
 .pydevproject
 settings_local.py
 urls_local.py
+dev/.vagrant
+dev/custom.yaml
+test-suite/node_modules
+test-suite/workspace.info*.js
+test-suite/clean-testserver.sh
+test-suite/karma.conf.full.js
+test-suite/start-test-suite-full.sh
+test-suite/start-testserver.sh
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgsub	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,6 @@
+dev/modules/nginx = [git]https://github.com/jfryman/puppet-nginx.git
+dev/modules/stdlib = [git]https://github.com/puppetlabs/puppetlabs-stdlib.git
+dev/modules/apt = [git]https://github.com/puppetlabs/puppetlabs-apt.git
+dev/modules/postgresql = [git]https://github.com/puppetlabs/puppetlabs-postgresql.git
+dev/modules/supervisord = [git]https://github.com/adedommelin/puppet-supervisord.git
+dev/modules/concat = [git]https://github.com/puppetlabs/puppetlabs-concat.git
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgsubstate	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,6 @@
+6691c2faded01d273672b4db36f5a8651d3a934f dev/modules/apt
+cd2e1d97e94da67c184a3a121b4493898fabe4a8 dev/modules/concat
+5c36913dcda630f5244e0ecc885e3b436973d45a dev/modules/nginx
+400a82d7e0f7374b61962364cb95315d0b5ee0d0 dev/modules/postgresql
+ab981422a67636441f1bfebaaade36aa690f1f25 dev/modules/stdlib
+743e2a3facfd7b9596983bca0f5afef8336ea525 dev/modules/supervisord
--- a/README.txt	Wed Apr 09 18:38:55 2014 +0200
+++ b/README.txt	Thu Apr 10 17:32:23 2014 +0200
@@ -42,7 +42,7 @@
 (all other python dependencies will be downloaded by buildout)
 
 Installation (development install)
-============
+==================================
 1. Install python2.5+ and all required libraries
 	(ubuntu users : 'sudo apt-get install python python-magic python-setuptools python-uno libyaml-0-1 python-yaml python-dev git-core python-utidylib python-pexpect python-cssutils')
 2. Install pandoc
@@ -85,8 +85,50 @@
    - `./bin/django runserver --settings=settings`
 11. Access your Comt instance by pointing your browser to http://127.0.0.1:8000/
 
+Installation (Vagrant development box)
+======================================
+
+The second option is to use the vagrant virtual machine defined in the `dev` folder.
+For this you need first to install Vagrant for your platform (c.f. http://www.vagrantup.com/), open a terminal in the `dev` folder and launch the command
+<code>
+$ vagrant up
+</code>
+This will create a virtual box, using the private address 172.16.1.2. An instance of comt can be reached at the following url http://172.16.1.2.
+
+The installation have the following parameters:
+  - The root of the project is mapped on `/srv/comt` on the dev box.
+  - The web server is nginx (http://nginx.org/).
+  - The web pages are served as a wsgi application with gunicorn (http://gunicorn.org/).
+  - The gunicorn processes are monitored by supervisor (http://supervisord.org/).
+  - Openoffice is installed but is not launched as an headless instance (althought it could be easily setup with supervisor).
+  - The dev box uses a virtual network with the ip 172.16.1.2 (this can be changed in the Vagrant config).
+  - The box is provisioned using puppet (http://puppetlabs.com/).
+  - Most of the configuration is don in the sysconfig module found in `dev/modules/sysconfig`.
+  - All the other subdirectories of `dev/modules` are puppet modules used during the box provisioning. All the folders are sub-repositories and are checked-out using git.
+
+Moreover, the following parameters are set :
+
+  | var name       | default     |
+  |----------------|-------------|
+  | db_name        | coment      |
+  | db_user        | coment_user |
+  | db_pw          | coment      |
+  | db_host        | 127.0.0.1   |
+  | db_port        | 5432        |
+  | superuser_name | admin       |
+  | superuser_pw   | dev@co-ment |
+
+These values can be overriden by creating a `custom.yaml` file in the `dev` folder. The file `custom.yaml.tmpl` gives a template for the format of this file.
+if the db_host is empty or 'localhost', or '127.0.0.1', the database is considered local to the box and a postgresql server is installed in the virtual server.
+Otherwise, the server is considered remote and only the postgresql client libraries are installed on the dev box.
+Also in this case, the database (db_name) and user (db_user) are not created automatically.
+You must ensure that they are already created on the postgresql server with the adequate authorizations, and that the user can connect on the 'remote' server from the dev box.
+
+Please refer to the available online documentation for more details on the various tools used here.
+
+
 Installation (production environment)
-=============
+=====================================
 This README.txt does not cover in details a production environment because this kind of setup is too platform dependant for us to provide a guide.
 A few tips thought:
 - recommended way to install it is using apache and wsgi, check out django installation guide at http://www.djangoproject.com/documentation/modpython/
@@ -116,7 +158,7 @@
 To use openoffice, on a development setup, you should make sure no openoffice process is left and launch `soffice -headless "-accept=socket,port=2002;urp;"` to start openoffice in background mode.
 
 Comt uses
-============
+=========
 
 Javascript libs used (and license) / shipped with the distribution
 ------------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/buildout-prod.cfg	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,11 @@
+[buildout]
+extends = buildout.cfg
+parts += gunicorn
+
+[gunicorn]
+recipe = zc.recipe.egg:scripts
+dependent-scripts = true
+eggs =
+    ${python:eggs}
+    eventlet
+    gunicorn
--- a/buildout.cfg	Wed Apr 09 18:38:55 2014 +0200
+++ b/buildout.cfg	Thu Apr 10 17:32:23 2014 +0200
@@ -1,16 +1,20 @@
 [buildout]
 newest=false
+find-links = http://download.berlios.de/utidylib/uTidylib-0.2.zip
 parts = 
 	django
 	python
 	django-extensions
-	django-piston
+	utidylib
 	omelette
 unzip = true
 develop = .
 
 [versions]
 django = 1.3
+utidylib = 0.2
+django-tagging = 0.3.1
+psycopg2 = 2.4.1
 
 [python]
 recipe = zc.recipe.egg
@@ -27,36 +31,40 @@
 #test = cm
 pythonpath = src
 	src/cm
+	extras
 	${django-extensions:location}
-	${django-piston:location}
 eggs = 
 	django-flash
 	django-tagging
-#	django-piston
+	django-piston
 # api dependency
 #	django-css	
-#	chardet
+	chardet
 	feedparser
-	PIL
+	Pillow
 	BeautifulSoup
 	html5lib
 	pytz
 	simplejson
 	pyyaml
 	south
-# psycopg2/mysql should be optional dependencies ... possible with buildout ???
-#	magic ???????? http://www.jsnp.net/code/magic.py ??? impossible to include this dependency
-#	utidylib ?????? http://download.berlios.de/utidylib/uTidylib-0.2.zip
+	psycopg2
+	utidylib
+        cssutils
+        pexpect
 
 [django-extensions]
 recipe=zerokspot.recipe.git
 repository=git://github.com/django-extensions/django-extensions.git
 #rev=7c73978b55fcadbe2cd6f2abbefbedb5a85c2c8c
 
-[django-piston]
-recipe = mercurialrecipe
-repository = http://bitbucket.org/jespern/django-piston
+
+[utidylib]
+recipe = zc.recipe.egg
+eggs = uTidylib
+
 
 [omelette]
 recipe = collective.recipe.omelette
 eggs = ${django:eggs}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/Vagrantfile	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,138 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+require 'yaml'
+
+custom_file_path = File.join(__dir__, (ENV['SYSCONFIG'] || 'custom.yaml'))
+
+context = (File.exist?(custom_file_path)?YAML::load_file(custom_file_path):{}) || {}
+
+ROOT_PATH = context.fetch("root_path","../")
+
+# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
+VAGRANTFILE_API_VERSION = "2"
+
+Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
+  # All Vagrant configuration is done here. The most common configuration
+  # options are documented and commented below. For a complete reference,
+  # please see the online documentation at vagrantup.com.
+
+  # Every Vagrant virtual environment requires a box to build off of.
+  config.vm.box = context.fetch("vm_box","wheezy-73-x64")
+
+  # The url from where the 'config.vm.box' box will be fetched if it
+  # doesn't already exist on the user's system.
+  config.vm.box_url = context.fetch("vm_box_url","http://puppet-vagrant-boxes.puppetlabs.com/debian-73-x64-virtualbox-puppet.box")
+
+  # Create a forwarded port mapping which allows access to a specific port
+  # within the machine from a port on the host machine. In the example below,
+  # accessing "localhost:8080" will access port 80 on the guest machine.
+  # config.vm.network :forwarded_port, guest: 80, host: 8080
+
+  # Create a private network, which allows host-only access to the machine
+  # using a specific IP.
+  config.vm.network :private_network, ip: (ENV['VM_IP'] || context['vm_ip'] || "172.16.1.2")
+
+  # Create a public network, which generally matched to bridged network.
+  # Bridged networks make the machine appear as another physical device on
+  # your network.
+  # config.vm.network :public_network
+
+  # If true, then any SSH connections made will enable agent forwarding.
+  # Default value: false
+  # config.ssh.forward_agent = true
+
+  # Share an additional folder to the guest VM. The first argument is
+  # the path on the host to the actual folder. The second argument is
+  # the path on the guest to mount the folder. And the optional third
+  # argument is a set of non-required options.
+  config.vm.synced_folder ROOT_PATH, "/srv/comt"
+
+  vmname = (ENV['VM_NAME'] || context['vm_name'] || "coment_dev")
+
+  config.vm.define :"#{vmname}" do |coment_dev|
+  end
+
+  # Provider-specific configuration so you can fine-tune various
+  # backing providers for Vagrant. These expose provider-specific options.
+  # Example for VirtualBox:
+  #
+  config.vm.provider :virtualbox do |vb|
+      vb.name = vmname
+  #   # Don't boot with headless mode
+  #   vb.gui = true
+  #
+  #   # Use VBoxManage to customize the VM. For example to change memory:
+  #   vb.customize ["modifyvm", :id, "--memory", "1024"]
+  end
+  #
+  # View the documentation for the provider you're using for more
+  # information on available options.
+
+  # Enable provisioning with Puppet stand alone.  Puppet manifests
+  # are contained in a directory path relative to this Vagrantfile.
+  # You will need to create the manifests directory and a manifest in
+  # the file base.pp in the manifests_path directory.
+  #
+  # An example Puppet manifest to provision the message of the day:
+  #
+  # # group { "puppet":
+  # #   ensure => "present",
+  # # }
+  # #
+  # # File { owner => 0, group => 0, mode => 0644 }
+  # #
+  # # file { '/etc/motd':
+  # #   content => "Welcome to your Vagrant-built virtual machine!
+  # #               Managed by Puppet.\n"
+  # # }
+  #
+  config.vm.provision :puppet do |puppet|
+    puppet.manifests_path = "manifests"
+    puppet.manifest_file  = "site.pp"
+    puppet.module_path    = "modules"
+    puppet.options        = "--hiera_config /vagrant/hiera.yaml "
+    puppet.facter = {
+      "vagrant_base_path" => File.dirname(__FILE__)
+    }
+  #  puppet.options        = "--debug --verbose --hiera_config /vagrant/hiera.yaml "
+  end
+
+  # Enable provisioning with chef solo, specifying a cookbooks path, roles
+  # path, and data_bags path (all relative to this Vagrantfile), and adding
+  # some recipes and/or roles.
+  #
+  # config.vm.provision :chef_solo do |chef|
+  #   chef.cookbooks_path = "../my-recipes/cookbooks"
+  #   chef.roles_path = "../my-recipes/roles"
+  #   chef.data_bags_path = "../my-recipes/data_bags"
+  #   chef.add_recipe "mysql"
+  #   chef.add_role "web"
+  #
+  #   # You may also specify custom JSON attributes:
+  #   chef.json = { :mysql_password => "foo" }
+  # end
+
+  # Enable provisioning with chef server, specifying the chef server URL,
+  # and the path to the validation key (relative to this Vagrantfile).
+  #
+  # The Opscode Platform uses HTTPS. Substitute your organization for
+  # ORGNAME in the URL and validation key.
+  #
+  # If you have your own Chef Server, use the appropriate URL, which may be
+  # HTTP instead of HTTPS depending on your configuration. Also change the
+  # validation key to validation.pem.
+  #
+  # config.vm.provision :chef_client do |chef|
+  #   chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
+  #   chef.validation_key_path = "ORGNAME-validator.pem"
+  # end
+  #
+  # If you're using the Opscode platform, your validator client is
+  # ORGNAME-validator, replacing ORGNAME with your organization name.
+  #
+  # If you have your own Chef Server, the default validation client name is
+  # chef-validator, unless you changed the configuration.
+  #
+  #   chef.validation_client_name = "ORGNAME-validator"
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/clean_dev.sh	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+pushd `dirname $0` > /dev/null
+SCRIPTPATH=`pwd -P`
+popd > /dev/null
+
+ROOTPATH="$SCRIPTPATH/.."
+
+pushd "$ROOTPATH" > /dev/null
+
+rm -rfv .installed.cfg .mr.developer.cfg parts/ eggs/ develop-eggs/ bin/ \
+    src/cm/settings_local.py test-suite/workspace.info*.js \
+    test-suite/{clean-testserver.sh,karma.conf.full.js} \
+    test-suite/{start-test-suite-full.sh,start-testserver.sh}
+
+find . -name '*.pyc' -or -name '*.egg-info' | xargs rm -rvf
+
+popd > /dev/null
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/custom.yaml.tmpl	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,24 @@
+---
+#root_path  : ../
+#vm_box     : wheezy-73-x64
+#vm_box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-73-x64-virtualbox-puppet.box
+#vm_ip      : 172.16.1.2
+#vm_name    : coment_dev
+
+#sysconfig::params::db_name : coment_custom
+#sysconfig::params::db_user : coment_user_cutom
+#sysconfig::params::db_pw   : coment_pw_custom
+#sysconfig::params::db_host : 127.0.0.1_custom
+#sysconfig::params::db_port : 5433
+
+#sysconfig::params::testserver_port : 8001
+
+#sysconfig::params::superuser_name   : admin_custom
+#sysconfig::params::superuser_pw     : dev@co-ment_custom
+#sysconfig::params::user_edit_name   : user-edit
+#sysconfig::params::user_edit_pw     : user-edit@co-ment
+#sysconfig::params::user_com_name    : user-com
+#sysconfig::params::user_com_pw      : user-com@co-ment
+#sysconfig::params::user_observ_name : user-observ
+#sysconfig::params::user_observ_pw   : user-observ@co-ment
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/hiera.yaml	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,7 @@
+---
+:hierarchy:
+  - custom
+:backends:
+  - yaml
+:yaml:
+  :datadir: '/vagrant/'
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/manifests/site.pp	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,26 @@
+# upgrade system
+class { 'sysconfig::sys_upgrade': }
+
+# install packages
+class { 'sysconfig::packages': require => Class['sysconfig::sys_upgrade'] }
+
+# install postgres
+class { 'sysconfig::postgresql': require => Class['sysconfig::sys_upgrade'] }
+
+# install nginx
+class { 'sysconfig::nginx': require => Class['sysconfig::sys_upgrade'] }
+
+# create python
+class { 'sysconfig::buildout': require => [Class['sysconfig::packages'], Class['sysconfig::postgresql']] }
+
+# write config
+class { 'sysconfig::config': require => Class['sysconfig::buildout'] }
+
+# write django_init
+class { 'sysconfig::django_init': require => Class['sysconfig::config'] }
+
+# config testserver_init
+class { 'sysconfig::testserver_init': vagrant_base_path => $vagrant_base_path, require => Class['sysconfig::config'] }
+
+# deploy
+class { 'sysconfig::deploy': require => [ Class['sysconfig::django_init'], Class['sysconfig::nginx'], Class['sysconfig::postgresql'] ] }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/modules/sysconfig/files/clean-testserver.sh	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+PID=$(cat /tmp/testserver.pid|cut -d"|" -f1)
+OUTFILE=$(cat /tmp/testserver.pid|cut -d"|" -f2)
+
+echo "Kill test server pid $PID"
+kill $PID
+
+echo "Test server log:"
+echo "================================================================================"
+cat "$OUTFILE"
+echo "================================================================================"
+
+echo "Clean testserver output"
+rm "$OUTFILE"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/modules/sysconfig/files/karma.conf.full.js	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,50 @@
+// Karma configuration
+// Generated on Wed Jan 29 2014 15:32:16 GMT+0100 (CET)
+
+
+// SID: get WORKSPACE_URL configuration from one single file to customize
+var w = require ('./workspace.info.full.js');
+
+module.exports = function(config) {
+	config.set({
+		// list of files or patterns to load in the browser, from current directory
+		files: [
+			{pattern: 'tests/**/*.js', included: true}
+		],
+		// list of files to exclude
+		exclude: [ ],
+		// Start these browsers, currently available:
+		// - Firefox	; Safari	(only Mac; run `npm install karma-safari-launcher` first)
+		// - Chrome		; ChromeCanary ; Opera (run `npm install karma-opera-launcher` first)
+		// - PhantomJS	; IE		(only Windows; run `npm install karma-ie-launcher` first)
+		browsers: w.BROWSERS,
+		// frameworks to use. SID: choosen mocha, added karma-e2e-dsl (end-to-end testing)
+		frameworks: ['mocha', 'karma-e2e-dsl'],
+		// SID: Karma will start and run somewhere else than '/', to allow proxying '/'
+		urlRoot: '/karma/',
+		// SID: directive added on karma-e2e-dsl purpose. Map of path-proxy pairs.
+		proxies: {
+			'/': w.WORKSPACE_URL
+		},
+		client: {
+			mocha: {
+				ui: 'tdd'
+			},
+			w: w // SID: exports the variable in the test execution browser window
+		},
+		// test results reporter to use : 'dots', 'progress', 'junit', 'growl', 'coverage'
+		reporters: ['progress'],
+		// web server port
+		port: 9876,
+		// enable / disable colors in the output (reporters and logs)
+		colors: true,
+		// level of logging : config.LOG_DISABLE || _ERROR || _WARN || _INFO || _DEBUG
+		logLevel: config.LOG_INFO,
+		// If browser does not capture in given timeout [ms], kill it
+		captureTimeout: 20000,
+		// enable / disable watching file and executing tests whenever any file changes
+		autoWatch: false,
+		// Continuous Integration mode : if true, it capture browsers, run tests and exit
+		singleRun: true,
+	});
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/modules/sysconfig/manifests/buildout.pp	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,18 @@
+class sysconfig::buildout {
+
+  exec {
+    'bootstrap':
+      command => '/usr/bin/python bootstrap.py',
+      cwd     => '/srv/comt',
+      creates => '/srv/comt/bin',
+      user    => 'vagrant';
+    'buildout':
+      command => '/srv/comt/bin/buildout -c /srv/comt/buildout-prod.cfg',
+      cwd     => '/srv/comt',
+      timeout => 0,
+      creates => '/srv/comt/bin/gunicorn';
+  }
+
+  Exec['bootstrap'] -> Exec['buildout']
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/modules/sysconfig/manifests/config.pp	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,29 @@
+class sysconfig::config(
+  $db_name = hiera('sysconfig::params::db_name',$sysconfig::params::db_name),
+  $db_user = hiera('sysconfig::params::db_user',$sysconfig::params::db_user),
+  $db_pw   = hiera('sysconfig::params::db_pw',$sysconfig::params::db_pw),
+  $db_host = hiera('sysconfig::params::db_host',$sysconfig::params::db_host),
+  $db_port = hiera('sysconfig::params::db_port',$sysconfig::params::db_port)
+) inherits sysconfig::params {
+
+  notify {'config': name => "config -> \$db_host: ${db_host}, \$db_port: ${db_port}, \$db_name: ${db_name}, \$db_user: ${db_user}, \$db_pw: ${db_pw}", withpath => true }
+
+  file { 'local-settings':
+     ensure  => 'present',
+     path    => "/srv/comt/src/cm/settings_local.py",
+     replace => 'no',
+     owner   => 'vagrant',
+     group   => 'vagrant',
+     mode    => 644,
+     content => template('sysconfig/settings_local.erb'),
+   }
+ 
+   file { 'media-root':
+     ensure => 'directory',
+     path   => '/srv/comt/web',
+     owner  => 'www-data',
+     group  => 'www-data',
+     mode   => '0775'
+   }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/modules/sysconfig/manifests/deploy.pp	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,65 @@
+class sysconfig::deploy {
+    
+    # create /var/run/gunicorn folder and insert entry in /etc/rc.local
+    file { 'run-folder':
+        path    => '/var/run/gunicorn',
+        ensure  => 'directory',
+        owner   => 'www-data',
+        group   => 'www-data',
+        mode    => '0775',
+    }
+
+    #create run folder for gunicorn
+    file { 'rc.local':
+        path    => '/etc/rc.local',
+        ensure  => 'present',
+        mode    => 755,
+        owner   => 'root',
+        group   => 'root',
+        content => template('sysconfig/rc.local.erb')
+    }
+
+    # install supervidsord
+    class { 'supervisord': }
+    
+    supervisord::program { 'coment' :
+        command      => '/srv/comt/bin/gunicorn -b unix:/var/run/gunicorn/comt.socket cm.wsgi:app',
+        user         => 'www-data',
+        directory    => '/srv/comt',
+        environment  => "PYTHONPATH='/srv/comt/src',PROJECT_PATH='/srv/comt/src/cm'",
+        require      => Class['supervisord']
+    }
+
+    supervisord::program { 'soffice' :
+        command      => '/usr/bin/soffice --headless "--accept=socket,port=2002;urp;"',
+        user         => 'vagrant',
+        directory    => '/srv/comt',
+        autostart    => false,
+        numprocs     => 1,
+        require      => Class['supervisord']
+    }
+
+    exec { 'reload_supervisor' :
+        command  => '/usr/bin/supervisorctl update',
+        require  => Supervisord::Program['coment']
+    }
+
+    #add site
+    nginx::resource::upstream { 'coment_app':
+        ensure                => present,
+        members               => [ 'unix:/var/run/gunicorn/comt.socket' ],
+        upstream_fail_timeout => 0,
+        require               => Exec['reload_supervisor']
+    }
+
+    nginx::resource::vhost { $ipaddress_eth1:
+        ensure           => present,
+        proxy            => 'http://coment_app',
+        proxy_set_header => ['Host $http_host'],
+        vhost_cfg_append => {
+            'proxy_redirect' => 'off'
+        },
+        require          => Nginx::Resource::Upstream['coment_app']
+    }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/modules/sysconfig/manifests/django_init.pp	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,27 @@
+class sysconfig::django_init (
+    $superuser_name = hiera('sysconfig::params::superuser_name', $sysconfig::params::superuser_name ),
+    $superuser_pw   = hiera('sysconfig::params::superuser_pw'  , $sysconfig::params::superuser_pw   )
+) inherits sysconfig::params {
+    
+    notify {'django_init': name => "django init \$superuser_name : ${superuser_name}, \$superuser_pw : ${superuser_pw}", withpath => true }->
+
+    exec { 'syncdb':
+        command => '/srv/comt/bin/django syncdb --noinput --migrate',
+        user    => 'vagrant' 
+    }
+
+    exec { 'loaddata':
+        command => '/srv/comt/bin/django loaddata roles_generic',
+        user    => 'vagrant',
+        require => Exec['syncdb']
+    }
+
+    exec { 'createsuperuser':
+        command => "/bin/echo \"from django.contrib.auth.models import User; User.objects.create_superuser('${superuser_name}', 'admin@example.com', '${superuser_pw}')\" | /srv/comt/bin/django shell",
+        cwd     => '/srv/comt',
+        user    => 'vagrant',
+        onlyif  => "/bin/echo \"from django.contrib.auth.models import User; exit(User.objects.filter(username='${superuser_name}').count())\" | /srv/comt/bin/django shell",
+       require => Exec['syncdb']
+    }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/modules/sysconfig/manifests/init.pp	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,4 @@
+
+class sysconfig {
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/modules/sysconfig/manifests/nginx.pp	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,6 @@
+class sysconfig::nginx {
+  # install nginx
+  class { '::nginx':}
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/modules/sysconfig/manifests/packages.pp	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,52 @@
+class sysconfig::packages {
+
+  $coment_pkgs = [
+      'vim',
+      'python-setuptools',
+      'libpq-dev',
+      'python-dev',
+      'python-virtualenv',
+      'libjpeg8-dev',
+      'zlib1g-dev',
+      'libtiff5-dev',
+      'libfreetype6-dev',
+      'liblcms2-dev',
+      'libwebp-dev',
+      'tcl-dev',
+      'tk-dev',
+      'python-magic',
+      'mercurial',
+      'libtidy-dev',
+      'libyaml-dev',
+      'git-core',
+      'pandoc',
+      'abiword',
+      'libreoffice',
+      'libreoffice-script-provider-python',
+      'python-uno'
+  ]
+  
+  package { $coment_pkgs: ensure => "installed" }
+
+  #upgrade setuptools
+  exec { '/usr/bin/easy_install --upgrade setuptools': require => Package[$coment_pkgs]}
+
+  augeas { "sshd_config":
+    context => "/files/etc/ssh/sshd_config",
+    changes => [
+      "set UseDNS no",
+      "set GSSAPIAuthentication no",
+    ],
+    notify  => Service["sshd"],
+  }
+
+  service { "sshd":
+    name    => $operatingsystem ? {
+      Debian  => "ssh",
+      default => "sshd",
+    },
+    require => Augeas["sshd_config"],
+    enable  => true,
+    ensure  => running,
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/modules/sysconfig/manifests/params.pp	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,23 @@
+class sysconfig::params {
+
+  $db_name = 'coment'
+  $db_user = 'coment_user'
+  $db_pw   = 'coment'
+  $db_host = '127.0.0.1'
+  $db_port = '5432'
+
+  $db_host_real = hiera('sysconfig::params::db_host',$db_host)
+  $db_is_local = ($db_host_real == undef or !$db_host_real or $db_host_real=='127.0.0.1' or $db_host_real=='localhost')
+
+  $testserver_port = 8001
+
+  $superuser_name   = 'admin'
+  $superuser_pw     = 'dev@co-ment'
+  $user_edit_name   = 'user-edit'
+  $user_edit_pw     = 'user-edit@co-ment'
+  $user_com_name    = 'user-com'
+  $user_com_pw      = 'user-com@co-ment'
+  $user_observ_name = 'user-observ'
+  $user_observ_pw   = 'user-observ@co-ment'
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/modules/sysconfig/manifests/postgresql.pp	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,35 @@
+
+class sysconfig::postgresql (
+    $db_host    = hiera('sysconfig::params::db_host', $sysconfig::params::db_host),
+    $db_port    = hiera('sysconfig::params::db_port', $sysconfig::params::db_port),
+    $db_name    = hiera('sysconfig::params::db_name', $sysconfig::params::db_name),
+    $db_user    = hiera('sysconfig::params::db_user', $sysconfig::params::db_user),
+    $db_pw      = hiera('sysconfig::params::db_pw', $sysconfig::params::db_pw),
+) inherits sysconfig::params {
+
+    notify {'postgresql': name => "\$db_host : ${db_host}, \$db_port : ${db_port}, \$db_name : ${db_name}, \$db_user : ${db_user}, \$db_pw : ${db_pw}", withpath => true }
+
+    if $sysconfig::params::db_is_local {
+        class { 'postgresql::server': }
+
+        postgresql::server::role {"${db_user}_createdb":
+            username      => $db_user,
+            createdb      => true,
+            password_hash => postgresql_password($db_user, $db_pw)
+        }->
+        postgresql::server::database { $db_name:
+            owner    => $db_user,            
+            encoding => 'UTF8',
+        }
+    }
+    else {
+        class { 'postgresql::client': }->
+        postgresql::validate_db_connection { 'validate_postgres_connection':
+            database_host           => $db_host,
+            database_port           => $db_port,
+            database_username       => $db_user,
+            database_password       => $db_pw,
+            database_name           => $db_name,
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/modules/sysconfig/manifests/sys_upgrade.pp	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,21 @@
+class sysconfig::sys_upgrade {
+
+  exec {
+    'apt_get_update_sysconfig':
+      command     => '/usr/bin/apt-get update',
+      timeout     => 2400,
+      returns     => [ 0, 100 ];
+#      refreshonly => true;
+    'sys-upgrade':
+      command   => '/usr/bin/apt-get upgrade -y',
+      timeout => 0,
+      require   => Exec['apt_get_update_sysconfig'];
+    'sys-dist-upgrade':
+      command   => '/usr/bin/apt-get dist-upgrade -y',
+      timeout => 0,
+      require   => Exec['apt_get_update_sysconfig'];
+  }
+
+  Exec['sys-upgrade'] -> Exec['sys-dist-upgrade']
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/modules/sysconfig/manifests/testserver_init.pp	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,77 @@
+class sysconfig::testserver_init (
+    $superuser_name    = hiera('sysconfig::params::superuser_name'   ,$sysconfig::params::superuser_name   ),
+    $superuser_pw      = hiera('sysconfig::params::superuser_pw'     ,$sysconfig::params::superuser_pw     ),
+    $user_edit_name    = hiera('sysconfig::params::user_edit_name'   ,$sysconfig::params::user_edit_name   ),
+    $user_edit_pw      = hiera('sysconfig::params::user_edit_pw'     ,$sysconfig::params::user_edit_pw     ),
+    $user_com_name     = hiera('sysconfig::params::user_com_name'    ,$sysconfig::params::user_com_name    ),
+    $user_com_pw       = hiera('sysconfig::params::user_com_pw'      ,$sysconfig::params::user_com_pw      ),
+    $user_observ_name  = hiera('sysconfig::params::user_observ_name' ,$sysconfig::params::user_observ_name ),
+    $user_observ_pw    = hiera('sysconfig::params::user_observ_pw'   ,$sysconfig::params::user_observ_pw   ),
+    $testserver_port   = hiera('sysconfig::params::testserver_port'  ,$sysconfig::params::testserver_port  ),
+    $vagrant_base_path
+
+) inherits sysconfig::params {
+
+    notify {'testserver_init': name => "testserver init : \$superuser_name : ${superuser_name}, \$superuser_pw : ${superuser_pw}", withpath => true }->
+
+    file { 'karma_workspace_info':
+        ensure  => 'present',
+        path    => "/srv/comt/test-suite/workspace.info.js",
+        replace => 'no',
+        owner   => 'vagrant',
+        group   => 'vagrant',
+        mode    => 644,
+        content => template('sysconfig/workspace.info.js.erb','sysconfig/url.workspace.info.js.erb'),
+    }
+
+    file { 'karma_workspace_info_full':
+        ensure  => 'present',
+        path    => "/srv/comt/test-suite/workspace.info.full.js",
+        replace => 'no',
+        owner   => 'vagrant',
+        group   => 'vagrant',
+        mode    => 644,
+        content => template('sysconfig/workspace.info.js.erb','sysconfig/url.test.workspace.info.js.erb'),
+    }
+
+    file { 'clean-testserver.sh':
+        ensure  => 'present',
+        path    => "/srv/comt/test-suite/clean-testserver.sh",
+        replace => 'no',
+        owner   => 'vagrant',
+        group   => 'vagrant',
+        mode    => 755,
+        source  => 'puppet:///modules/sysconfig/clean-testserver.sh'
+    }
+
+    file { 'karma.conf.full.js':
+        ensure  => 'present',
+        path    => "/srv/comt/test-suite/karma.conf.full.js",
+        replace => 'no',
+        owner   => 'vagrant',
+        group   => 'vagrant',
+        mode    => 644,
+        source  => 'puppet:///modules/sysconfig/karma.conf.full.js'
+    }
+
+    file { 'start-test-suite-full.sh':
+        ensure  => 'present',
+        path    => "/srv/comt/test-suite/start-test-suite-full.sh",
+        replace => 'no',
+        owner   => 'vagrant',
+        group   => 'vagrant',
+        mode    => 755,
+        content => template('sysconfig/start-test-suite-full.sh.erb'),
+    }
+
+    file { 'start-testserver.sh':
+        ensure  => 'present',
+        path    => "/srv/comt/test-suite/start-testserver.sh",
+        replace => 'no',
+        owner   => 'vagrant',
+        group   => 'vagrant',
+        mode    => 755,
+        content => template('sysconfig/start-testserver.sh.erb'),
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/modules/sysconfig/templates/rc.local.erb	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,19 @@
+#!/bin/sh -e
+#
+# rc.local
+#
+# This script is executed at the end of each multiuser runlevel.
+# Make sure that the script will "exit 0" on success or any other
+# value on error.
+#
+# In order to enable or disable this script just change the execution
+# bits.
+#
+# By default this script does nothing.
+
+if [ ! -d /var/run/gunicorn ]; then
+  mkdir /var/run/gunicorn/
+  chown www-data:www-data /var/run/gunicorn/
+fi
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/modules/sysconfig/templates/settings_local.erb	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,87 @@
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+CLIENT_DEBUG = DEBUG
+
+YUI_DEBUG = DEBUG # use expanded yui version (i.e. not -min)
+YUI_DISTANT = False
+
+DATABASES = {
+  'default': {
+    'ENGINE': 'postgresql_psycopg2', # YOUR_SETTINGS # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
+    'NAME': '<%= @db_name %>',               # YOUR_SETTINGS # Or path to database file if using sqlite3.
+    'USER': '<%= @db_user %>',               # YOUR_SETTINGS # Not used with sqlite3.
+    'PASSWORD': '<%= @db_pw %>',             # YOUR_SETTINGS # Not used with sqlite3.
+    'HOST': '<%= @db_host %>',                      # YOUR_SETTINGS # Set to empty string for localhost. Not used with sqlite3.
+    'PORT': '<%= @db_port %>',                      # YOUR_SETTINGS # Set to empty string for default. Not used with sqlite3.
+   }
+}
+
+SITE_URL = "http://<%= @ipaddress_eth1 %>/" # YOUR_SETTINGS
+
+DEFAULT_FROM_EMAIL = "me@example.com" # YOUR_SETTINGS
+
+# destination email for the contact page
+CONTACT_DEST = DEFAULT_FROM_EMAIL
+
+# smtp host
+EMAIL_HOST = "localhost" # YOUR_SETTINGS
+
+TEMPLATE_STRING_IF_INVALID = "NNNNNNNNNOOOOOOOOOOOOOOO" if DEBUG else ''
+
+# web server writable directory to store Comt uploaded content (text images etc.)
+MEDIA_ROOT = '/srv/comt/web' # YOUR_SETTINGS
+
+# Insert some random text here, 
+# it will be used to add some randomness to every crypto operation Comt does
+SECRET_KEY = '<%= Array.new(50){"abcdefghijklmnopqrstuvwxyz0123456789!@#\$%^&*(-_=+)".split("").sample}.join %>' # YOUR_SETTINGS
+
+MEDIA_URL = '/site_media/'
+
+INSTALLED_APPS = (
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.sites',
+    'django.contrib.admin',
+    'cm',
+#    'django_extensions',
+    'tagging',
+    'south',
+)
+
+CM_MEDIA_PREFIX = '/cmmedia/'
+
+ADMIN_MEDIA_PREFIX = '/media/'
+
+ADMINS = (
+    ('Comt admin', CONTACT_DEST),
+)
+
+MANAGERS = ADMINS
+SEND_BROKEN_LINK_EMAILS = False
+
+SERVER_EMAIL = DEFAULT_FROM_EMAIL
+
+# 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.
+# If running in a Windows environment this must be set to the same as your
+# system time zone.
+DEFAULT_TIME_ZONE = "Europe/Paris"
+
+# Do not use name/email of co-ment users but rather
+# those passed in the request.
+# Set this parameter to True when using co-ment from
+# a third-party CMS throuch co-ment API.
+DECORATED_CREATORS = False
+
+# Set to TRUE to use Abiword for convertion form and to legacy formats.
+# Set to False to use LibreOffice for convertion form and to legacy formats.
+USE_ABI = True
+
+# Set to True if you don't want to appear in Sopinspace Piwik statistics
+DISABLE_TRACKING = True
+
+#disable email reporting by piston
+PISTON_EMAIL_ERRORS = False
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/modules/sysconfig/templates/start-test-suite-full.sh.erb	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,56 @@
+#!/bin/bash
+
+echo "---------------------"
+echo "Starting test server"
+
+DEV_FOLDER="<%= @vagrant_base_path %>"
+
+pushd "$DEV_FOLDER" > /dev/null
+vagrant ssh -c "/srv/comt/test-suite/start-testserver.sh"
+popd > /dev/null
+
+CONNECTION_TIMEOUT=10
+TESTSERVER_START_TIMEOUT=15
+TESTSERVER_LOOP_WAIT=5
+TESTSERVER_WAIT_LOOP_NB=10
+
+SERVER_IP=`grep WORKSPACE_URL workspace.info.full.js | tail -n -1 | cut -d: -f2 | tr -d " //"`
+SERVER_PORT=`grep WORKSPACE_URL ./workspace.info.full.js | tail -n -1 | cut -d: -f3 | tr -d " ');"`
+
+if [[ -x `which nc` ]]; then
+    SERVER_TEST_CMD="nc -G $CONNECTION_TIMEOUT -z $SERVER_IP $SERVER_PORT"
+elif [[ -x `which curl` ]]; then
+    SERVER_TEST_CMD="curl -m $CONNECTION_TIMEOUT --output /dev/null --silent --head --fail http://$SERVER_IP:$SERVER_PORT"
+elif [[ -x `which wget` ]]; then
+    SERVER_TEST_CMD="wget --timeout=$CONNECTION_TIMEOUT -q --spider http://$SERVER_IP:$SERVER_PORT"
+fi
+echo "$SERVER_TEST_CMD"
+
+echo "---------------------"
+if [[ -z "$SERVER_TEST_CMD" ]]; then
+    echo "Waiting $TESTSERVER_START_TIMEOUT seconds to let test server start"
+    sleep $TESTSERVER_START_TIMEOUT
+else
+    for i in $(seq 1 $TESTSERVER_WAIT_LOOP_NB); do
+        echo "waiting $TESTSERVER_LOOP_WAIT seconds to let the test server $SERVER_IP:$SERVER_PORT start"
+        sleep $TESTSERVER_LOOP_WAIT
+	if $SERVER_TEST_CMD; then
+            break
+        fi
+    done
+    if [ $i -eq $TESTSERVER_WAIT_LOOP_NB ]; then
+         echo "could not start test server $SERVER_IP:$SERVER_PORT"
+         exit 1
+    fi
+fi
+
+echo "---------------------"
+echo "Starting karma tests"
+. ./start-test-suite.sh ./karma.conf.full.js $@
+
+echo "---------------------"
+echo "stopping test server + output test server logs"
+
+pushd "$DEV_FOLDER" > /dev/null
+vagrant ssh -c "/srv/comt/test-suite/clean-testserver.sh"
+popd /dev/null
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/modules/sysconfig/templates/start-testserver.sh.erb	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+
+ROOTPATH="/srv/comt"
+TMPFILE=`mktemp`
+
+pushd "$ROOTPATH" > /dev/null
+
+nohup bin/django testserver --noinput --addrport=0.0.0.0:<%= @testserver_port %> initial_data roles_generic test_content > $TMPFILE 2>&1 &
+echo "$!|$TMPFILE" > /tmp/testserver.pid
+
+cat  /tmp/testserver.pid
+
+popd > /dev/null
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/modules/sysconfig/templates/url.test.workspace.info.js.erb	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,4 @@
+
+
+define ("WORKSPACE_URL", 'http://<%= @ipaddress_eth1 %>:<%= @testserver_port %>');
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/modules/sysconfig/templates/url.workspace.info.js.erb	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,4 @@
+
+
+define ("WORKSPACE_URL", 'http://<%= @ipaddress_eth1 %>');
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/modules/sysconfig/templates/workspace.info.js.erb	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,26 @@
+
+function define (name, value) {
+    Object.defineProperty (exports, name, {
+        value:      value,
+        enumerable: true
+    });
+}
+
+define ("DEBUG", false);
+
+define ("USER_ADMIN", '<%= @superuser_name %>');
+define ("PASS_ADMIN", '<%= @superuser_pw %>');
+
+define ("BROWSERS", ['PhantomJS']);
+
+// TODO: decide wether we should populate workspaces with standard users or
+// create them on the fly ?
+
+define ("USER_EDIT", '<%= @user_edit_name %>');
+define ("PASS_EDIT", '<%= @user_edit_pw %>');
+
+define ("USER_COM", '<%= @user_com_name %>');
+define ("PASS_COM", '<%= @user_com_pw %>');
+
+define ("USER_OBSERV", '<%= @user_observ_name %>');
+define ("PASS_OBSERV", '<%= @user_observ_pw %>');
--- a/src/cm/tests/test_security.py	Wed Apr 09 18:38:55 2014 +0200
+++ b/src/cm/tests/test_security.py	Thu Apr 10 17:32:23 2014 +0200
@@ -1,7 +1,7 @@
 from django.test import TestCase
 from django.test.client import Client
 from django.core import management
-from django.core.cache import cache
+
 
 from cm.models import *
 from cm.security import *
@@ -12,7 +12,7 @@
         self.user = user
 
 class SecurityTest(TestCase):
-    fixtures = ['initial_data', 'roles_generic','test_content']
+    fixtures = ['initial_data','roles_generic','test_content']
     
     def test_access_rights(self):
         # anon user sees no text
@@ -53,7 +53,6 @@
         c2.save()
         c3.state = 'approved'
         c3.save()
-        cache.clear()
 
         self.assertFalse(has_own_perm(FalseRequest(user3), "can_edit_comment" + "_own", text2, c3),'CANNOT edit own comment (there is a reply)')
         self.assertTrue(has_own_perm(FalseRequest(user2), "can_edit_comment" + "_own", text2, c2),"CAN edit own comment (is moderator)")
@@ -78,4 +77,4 @@
                 
         self.assertFalse(has_own_perm(FalseRequest(user3), "can_edit_comment" + "_own", text2, c3),'CANNOT edit own comment (there is a reply)')
         self.assertTrue(has_perm(FalseRequest(user2), "can_edit_comment", text2),"CAN edit other's comment (moderator)")
-        
+        
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cm/wsgi.py	Thu Apr 10 17:32:23 2014 +0200
@@ -0,0 +1,11 @@
+import os
+import sys
+
+os.environ['DJANGO_SETTINGS_MODULE'] = 'cm.settings'
+
+path = os.environ['PROJECT_PATH']
+if path not in sys.path:
+    sys.path.append(path)
+
+import django.core.handlers.wsgi
+app = django.core.handlers.wsgi.WSGIHandler()