beginning of a cubicweb salt formula
authorDavid Douard <david.douard@logilab.fr>
Tue, 29 Apr 2014 10:02:32 +0200
changeset 0 5106aa7d0a28
child 1 a0f87dba2b8f
beginning of a cubicweb salt formula
README.rst
_modules/cubicweb.py
_states/cubicweb_instance.py
cubicweb/apache/init.sls
cubicweb/apache/reverseproxy.sls
cubicweb/apache/vhost.sls
cubicweb/apache/vhost.tmpl
cubicweb/init.sls
cubicweb/instances.sls
cubicweb/logilab-pinning
cubicweb/logilab.sls
cubicweb/monitor.sls
cubicweb/postgres.sls
cubicweb/twisted.sls
pillar.example
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README.rst	Tue Apr 29 10:02:32 2014 +0200
@@ -0,0 +1,245 @@
+========
+cubicweb
+========
+
+Set up and configure the Cubicweb web application framework.
+
+.. note::
+
+    See the full `Salt Formulas installation and usage instructions
+    <http://docs.saltstack.com/topics/conventions/formulas.html>`_.
+
+Available states
+================
+
+.. contents::
+    :local:
+
+``cubicweb``
+----------
+
+Install Cubicweb from the system package manager. Note, the Cubicweb version
+available varies by platform.
+
+Example usage::
+
+    include:
+      - cubicweb
+
+    mysite:
+      git:
+        - latest
+        - name: git@git.example.com/mysite
+        - target: /var/www/mysite
+        - require:
+            - pkg: cubicweb
+
+
+Full-stack App Deployment
+=========================
+
+This formula also provides an example of how Salt can be used to deploy a
+Cubicweb app in a single command, using the `OverState System`_. It installs
+Cubicweb into a virtualenv, using pip with a requirements.txt.
+
+.. _`OverState System`: http://docs.saltstack.com/ref/states/overstate.html
+
+This example makes use of the following three files:
+
+* `pillar.example`_ - Pillar data
+* `overstate.single`_ - Single-host OverState deployment stages 
+* `overstate.multi`_ - Multi-host OverState deployment stages
+
+.. _pillar.example: https://github.com/saltstack-formulas/cubicweb-formula/blob/master/pillar.example
+.. _overstate.single: https://github.com/saltstack-formulas/cubicweb-formula/blob/master/overstate.single
+.. _overstate.multi: https://github.com/saltstack-formulas/cubicweb-formula/blob/master/overstate.multi
+
+Deploying this example will require that the relevant files from above (the
+Pillar data and appropriate OverState config file) are copied to the Master and
+edited as necessary. The Pillar data will need to be available to all involved
+minions.
+
+Additionally, this example makes use of several other Salt formulae:
+
+* `apache-formula`_
+* `postgres-formula`_
+
+.. _apache-formula: https://github.com/saltstack-formulas/apache-formula.git
+.. _postgres-formula: https://github.com/saltstack-formulas/postgres-formula.git
+
+To deploy the entire stack (Apache, PostgreSQL, Cubicweb, cubes) to a
+single host, run the following command:
+
+.. code-block:: bash
+
+    # salt-run state.over deployment /path/to/overstate.single
+
+To deploy using one database server, one Apache server and one or more
+Cubiweb servers, run the following command:
+
+.. code-block:: bash
+
+    # salt-run state.over deployment /path/to/overstate.multi
+
+.. note::
+
+   If you did not create a separate ``deployment`` branch, then
+   replace ``deployment`` with ``base`` in the above ``salt-run``
+   commands.
+
+
+Other Tips
+==========
+
+Create ``settings.py`` using data from Pillar
+---------------------------------------------
+
+The easiest way to create Cubicweb's ``setttings.py`` file using data from Pillar
+is to simply transform a dictionary in YAML into a dictionary in Python.
+
+``/srv/salt/mysite.sls``::
+
+    include:
+      - cubicweb.pip
+
+    mysite:
+      git:
+        - latest
+        - name: git@git.example.com/mysite
+        - target: /var/www/mysite
+        - require:
+            - pip: cubicweb_pip
+
+    mysite_settings:
+      file:
+        - managed
+        - name: /var/www/mysite/settings.py
+        - contents: |
+            globals().update({{ salt['pillar.get']('mysite:settings') | python() | indent(8) }})
+        - require:
+          - git: mysite
+
+``/srv/pillar/mysite.sls``::
+
+    mysite:
+      settings:
+        ROOT_URLCONF: mysite.urls
+        SECRET_KEY: 'gith!)on!_dq0=2l(otd67%#0urmrk6_d0!zu)i9fn=!8_g5(c'
+        DATABASES:
+          default:
+            ENGINE: cubicweb.db.backends.mysql
+            NAME: mysitedb
+            USER: mysiteuser
+            PASSWORD: mysitepass
+            HOST: localhost
+            PORT: 3306
+        TEMPLATE_DIRS:
+          - /var/www/mysite/cubicweb-tutorial/templates
+        STATICFILES_DIRS:
+          - /var/www/mysite/cubicweb-tutorial/static
+        STATIC_ROOT: /var/www/mysite/cubicweb-tutorial/staticroot
+
+Create ``settings.py`` with a template file
+-------------------------------------------
+
+A more traditional (and flexible) method of creating the ``settings.py`` file
+is to actually create the file as a template.
+
+``/srv/salt/mysite/mysite.sls``::
+
+    include:
+      - cubicweb.pip
+
+    mysite:
+      git:
+        - latest
+        - name: git@git.example.com/mysite
+        - target: /var/www/mysite
+        - require:
+            - pip: cubicweb_pip
+
+    mysite_settings:
+      file:
+        - managed
+        - name: /var/www/mysite/settings.py
+        - source: salt://mysite/files/settings-tmpl.py
+        - template: jinja
+        - require:
+          - git: mysite
+
+``/srv/salt/mysite/files/settings-tmpl.py``::
+
+    {# Data can be defined inline, in Grains, in Pillar, etc #}
+
+    {% set db_settings = {
+        'default': {
+            'ENGINE': 'cubicweb.db.backends.mysql',
+            'HOST': 'localhost',
+            'NAME': 'polldb',
+            'PASSWORD': 'pollpass',
+            'PORT': 3306,
+            'USER': 'polluser',
+        }
+    } %}
+
+    {% set staticfiles_dirs_settings = [
+        '/var/www/poll/cubicweb-tutorial/static',
+    ] %}
+
+    {% set template_dirs_settings = [
+        '/var/www/poll/cubicweb-tutorial/templates',
+    ] %}
+
+    ROOT_URLCONF = mysite.urls
+
+    {# Have Salt automatically generate the SECRET_KEY for this minion #}
+    SECRET_KEY = '{{ salt['grains.get_or_set_hash']('mysite:SECRET_KEY', 50) }}'
+
+    DATABASES = {{ db_settings | python() }}
+
+    TEMPLATE_DIRS = {{ template_dirs_settings | python() }}
+
+    STATICFILES_DIRS = {{ staticfiles_dirs_settings | python() }}
+
+    STATIC_ROOT = /var/www/mysite/cubicweb-tutorial/staticroot
+
+Run ``syncdb`` or ``collectstatic`` automatically
+-------------------------------------------------
+
+A wait state can be used to trigger ``cubicweb-admin.py syncdb`` or
+``cubicweb-admin.py collectstatic`` automatically. The following example runs
+both commands whenever the Git repository containing the "mysite" Cubicweb
+project is updated.
+
+::
+
+    include:
+      - cubicweb.pip
+
+    mysite:
+      git:
+        - latest
+        - name: git@git.example.com/mysite
+        - target: /var/www/mysite
+        - require:
+            - pip: cubicweb_pip
+
+    mysite_syncdb:
+      module:
+        - wait
+        - name: cubicweb.syncdb
+        - settings_module: "mysite.settings"
+        - bin_env: /path/to/virtualenv          # optional
+        - pythonpath: /path/to/mysite_project   # optional
+        - watch:
+          - git: mysite
+
+    mysite_collectstatic:
+      module:
+        - wait
+        - name: cubicweb.collectstatic
+        - settings_module: "mysite.settings"
+        - bin_env: /path/to/virtualenv          # optional
+        - pythonpath: /path/to/mysite_project   # optional
+        - watch:
+          - git: mysite
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/_modules/cubicweb.py	Tue Apr 29 10:02:32 2014 +0200
@@ -0,0 +1,239 @@
+#
+'''
+Module to provide Cubicweb compatibility to salt.
+
+'''
+
+# Import python libs
+import sys
+import pipes
+import logging
+import re
+
+# Import salt libs
+from salt.utils import check_or_die
+from salt.exceptions import CommandNotFoundError
+
+log = logging.getLogger(__name__)
+
+
+def __virtual__():
+    '''
+    Only load this module if cubicweb is available
+    '''
+    try:
+        check_or_die('cubicweb-ctl')
+        return 'cubicweb'
+    except CommandNotFoundError:
+        return False
+
+
+def version():
+    '''
+    Return the version of Cubicweb
+
+    CLI Example::
+
+        salt '*' cubicweb.version
+    '''
+    return __salt__['cmd.run']('cubicweb-ctl version').split("\n")[0]
+
+def start(name):
+    '''
+    Start a Cubicweb instance
+
+    CLI Example::
+
+        salt '*' cubicweb.start myinstance
+    '''
+    return __salt__['cmd.run']('cubicweb-ctl start {0}'.format(name))
+
+
+def list(verbose=False):
+    '''
+    Return the list of available Cubicweb cubes, configurations and instances
+
+    CLI Example::
+
+        salt '*' cubicweb.list
+    '''
+    cmd = 'cubicweb-ctl list'
+    if verbose:
+        cmd += ' -v'
+    return __salt__['cmd.run'](cmd)
+
+def _cwlist(verbose=False):
+    cmd = 'cubicweb-ctl list'
+    if verbose:
+        cmd += ' -v'
+    cwlst = __salt__['cmd.run'](cmd).splitlines()
+    ret = {}
+    section = None
+    item = None
+    regsec = re.compile('^Available (?P<section>\w+)( *\((?P<path>.*)\))?:$')
+    regitem = re.compile('^\* (?P<item>[\w-]+)\s*(\(?(?P<desc>[\w.-]+)?\)?)$')
+    for row in cwlst[1:]:
+        if row.strip() == '':
+            item = None
+            section = None
+            continue
+        m = regsec.match(row)
+        if m:
+            ret[m.group('section')] = section = {}
+            item = None
+        else:
+            m = regitem.match(row)
+            if m:
+                item = m.group('item')
+                desc = m.group('desc')
+                section[item] = []
+                if desc:
+                    section[item].append(desc)
+            else:
+                if item is not None and row.strip():
+                    section[item].append(row.strip())
+    return ret
+
+
+
+def cubes(verbose=False):
+    '''
+    Return the list of available Cubicweb cubes
+
+    CLI Example::
+
+        salt '*' cubicweb.cubes
+    '''
+    return _cwlist(verbose)['cubes']
+
+def configurations(verbose=False):
+    '''
+    Return the list of available Cubicweb configurations
+
+    CLI Example::
+
+        salt '*' cubicweb.configurations
+    '''
+    return _cwlist(verbose)['configurations']
+
+def instances(verbose=False):
+    '''
+    Return the list of existing Cubicweb instances
+
+    CLI Example::
+
+        salt '*' cubicweb.instances
+    '''
+    return _cwlist(verbose)['instances']
+
+def status(instance=None):
+    '''
+    Return the status of Cubicweb instances; if an instance name is given, return
+    the pid of the process or an empty string if not running.
+
+    CLI Example::
+
+        salt '*' cubicweb.status
+    '''
+    cmd = 'cubicweb-ctl status'
+    if instance:
+        cmd += ' ' + instance
+    result = __salt__['cmd.run'](cmd)
+    if not instance:
+        return result
+    reg = re.compile('^[[].*[]] running with pid (?P<pid>[0-9]+)$')
+    for row in result.splitlines():
+        m = reg.match(row)
+        if m:
+            return m.group('pid')
+    return ''
+
+def create(name, cubes, install_type, **kwargs):
+    '''
+    '''
+    log.debug('create {0} ({1}): {2!r}'.format(name,install_type, cubes))
+    if not isinstance(cubes, basestring):
+        cubes = ",".join(cubes)
+    cmd = ('cubicweb-ctl create --automatic --no-db-create --config={0} '
+           '{1} {2}').format(install_type, cubes, name)
+    result1 = __salt__['cmd.run'](cmd)
+    log.debug('creation: {0}: {1} => {2!r}'.format(name, cubes, result1))
+
+    result2 = configure(name, **kwargs)
+    return result1 + result2
+
+def configure(name, **kwargs):
+    '''
+    '''
+    cmd = 'cubicweb-ctl configure '
+    dbcfg = []
+    params = []
+    admin = {}
+    for key, value in kwargs.items():
+        if key.startswith('__'):
+            continue
+        elif key.startswith('admin/'):
+            admin[key[6:]] = value
+        elif key.startswith('db-'):
+            dbcfg.append('{0}:{1}'.format(key, value))
+        else:
+            params.append('{0}:{1}'.format(key, value))
+    # do admin/password config "by hand" sincs cubicweb-ctl configure
+    # cannot handle it yet
+    sources = '/etc/cubicweb.d/{0}/sources'.format(name)
+    for admkey in 'login', 'password':
+        if admin.get(admkey): # ugly
+            __salt__['file.replace'](path=sources,
+                                     pattern=r'^{0} *=.*$'.format(admkey),
+                                     repl='{0}={1}'.format(admkey, admin[admkey]))
+    if params:
+        cmd += ' --param={0}'.format(','.join(params))
+    if dbcfg:
+        cmd += ' --db={0}'.format(','.join(dbcfg))
+    cmd += ' {0}'.format(name)
+    result = __salt__['cmd.run'](cmd)
+    log.debug('configure {0}: {1!r}'.format(name, cmd))
+    log.debug('==> {0!r}'.format(result))
+    return result
+
+def initialize(name, drop=False):
+    '''Initialize the database for an instance
+    '''
+    cmd = ('cubicweb-ctl db-init --config-level 0 {0}').format(name)
+    if drop:
+        cmd += ' --drop'
+    return __salt__['cmd.run'](cmd)
+
+def delete(name):
+    '''Delete an instance
+    '''
+    if status(name):
+        stop(name)
+    cmd = ('cubicweb-ctl delete {0}').format(name)
+    result = __salt__['cmd.run'](cmd)
+    log.debug('delete: {0} => {1!r}'.format(name, result))
+    return result
+
+def start(name):
+    '''Start an instance
+    '''
+    cmd = ('cubicweb-ctl start {0}').format(name)
+    result = __salt__['cmd.run'](cmd)
+    log.debug('start {0}: {1!r}'.format(name, result))
+    return result
+
+def stop(name):
+    '''Stop an instance
+    '''
+    cmd = ('cubicweb-ctl stop {0}').format(name)
+    result = __salt__['cmd.run'](cmd)
+    log.debug('stop {0}: {1!r}'.format(name, result))
+    return result
+
+def restart(name):
+    '''Restart an instance
+    '''
+    cmd = ('cubicweb-ctl restart {0}').format(name)
+    result = __salt__['cmd.run'](cmd)
+    log.debug('restart {0}: {1!r}'.format(name, result))
+    return result
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/_states/cubicweb_instance.py	Tue Apr 29 10:02:32 2014 +0200
@@ -0,0 +1,63 @@
+'''
+Manage Cubicweb instances
+=========================
+
+
+'''
+
+
+import logging
+
+import salt.utils
+
+log = logging.getLogger(__name__)
+
+def __virtual__():
+    '''
+    Only make these states available if a pkg provider has been detected or
+    assigned for this minion
+    '''
+    return 'cubicweb_instance'
+
+def running(name):
+    ret = {'name': name,
+           'comment': 'Instance {0} is already running'.format(name),
+           'changes': {},
+           'result': True}
+    # check if an instance of that name already runs
+    if __salt__['cubicweb.status'](name):
+        # XXX check the instance is the same cube as described
+        ret['comment'] = "Rhoo"
+        return ret
+    if __opts__['test']:
+        ret['result'] = None
+        ret['comment'] = 'Instance {0} is set to be started'.format(name)
+        return ret
+    ret['comment'] = "Dunno what to do"
+    ret['result'] = False
+    return ret
+
+def present(name,
+            cubes,
+            install_type='all-in-one',
+            **kwargs):
+
+    ret = {'name': name,
+           'changes': {},
+           'result': True,
+           'comment': 'Instance {0} is already present'.format(name)}
+
+    # check if an instance of that name already runs
+    if __salt__['cubicweb.status'](name):
+        # XXX check the instance is at leaset the same cubes as
+        # described
+        return ret
+
+    # is the instance does not exists, create it
+    if __opts__['test']:
+        ret['result'] = None
+        ret['comment'] = 'Instance {0} is set to be created'.format(name)
+        return ret
+    __salt__['cubicweb.create'](name, cubes, install_type=install_type, **kwargs)
+    ret['comment'] = 'Instance {0} has been installed'.format(name)
+    return ret
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/apache/init.sls	Tue Apr 29 10:02:32 2014 +0200
@@ -0,0 +1,20 @@
+apache2:
+  pkg:
+    - installed
+    - pkgs:
+      - apache2
+      - apachetop
+      - apache2-utils
+    - require:
+      - pkg: www-packages
+  service.running:
+    - enable: True
+    - require:
+      - pkg: apache2
+
+www-packages:
+  pkg:
+    - installed
+    - names:
+      - logrotate
+      - ssl-cert
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/apache/reverseproxy.sls	Tue Apr 29 10:02:32 2014 +0200
@@ -0,0 +1,16 @@
+include:
+  - cubicweb.apache
+
+proxymod:
+  cmd.run:
+    - name: 'a2enmod proxy_http'
+    - unless: '[ -a /etc/apache2/mods-enabled/proxy_http.load ]'
+    - require:
+      - pkg: apache2
+
+extend:
+  apache2:
+    service:
+      - watch:
+        - cmd: proxymod
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/apache/vhost.sls	Tue Apr 29 10:02:32 2014 +0200
@@ -0,0 +1,37 @@
+include:
+  - cubicweb.apache
+  - cubicweb.apache.reverseproxy
+
+
+{% for vhostname, vhost in pillar['cubicweb_apps'].iteritems() %}
+/etc/apache2/sites-available/{{ vhostname }}:
+  file:
+    - managed
+    - source: salt://cubicweb/apache/vhost.tmpl
+    - template: jinja
+    - vhost: {{ vhost }}
+    - vhostname: {{ vhostname }}
+    - require:
+      - file: /var/www/{{ vhostname }}
+
+/var/www/{{vhostname}}:
+  file.directory:
+    - user: www-data
+    - group: www-data
+    - makedirs: True
+    - mode: 755
+
+site-{{vhostname}}:
+  cmd.run:
+    - name: 'a2ensite {{vhostname}}'
+    - unless: '[ -a /etc/apache2/sites-enabled/{{vhostname}} ]'
+    - require:
+      - pkg: apache2
+
+extend:
+  apache2:
+    service:
+      - watch:
+        - cmd: site-{{vhostname}}
+
+{% endfor %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/apache/vhost.tmpl	Tue Apr 29 10:02:32 2014 +0200
@@ -0,0 +1,27 @@
+<VirtualHost 1.2.3.4:80>
+    ServerName  {{ vhostname }}
+    DocumentRoot /var/www/{{ vhostname }}
+    ServerAdmin sysadmin@logilab.fr
+
+    CustomLog /var/log/apache2/{{ vhostname }}-access.log combined2
+    ErrorLog /var/log/apache2/{{ vhostname }}-error.log
+
+    <Directory /home/logilab/www/{{ vhostname }}>
+        Order allow,deny
+        Allow from all
+        Options MultiViews FollowSymLinks
+    </Directory>
+
+    ProxyRequests Off
+
+    <Proxy *>
+        Order deny,allow
+        Allow from all
+    </Proxy>
+{% for name, config in vhost.iteritems() %}
+    ProxyPass {{ config.cwapp.basepath }} http://{{config.cwapp.backend}}:{{ config.cwapp.port }}/
+    ProxyPassReverse {{ config.cwapp.basepath }} http://{{ config.cwapp.backend }}:{{ config.cwapp.port }}/
+{% endfor %}
+</VirtualHost>
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/init.sls	Tue Apr 29 10:02:32 2014 +0200
@@ -0,0 +1,51 @@
+include:
+  - cubicweb.logilab
+
+cw-logilab-deps:
+  pkg.installed:
+    - pkgs:
+      - python-logilab-common
+      - python-yams
+      - python-rql
+      - python-logilab-database
+      - python-logilab-mtconverter
+    - require:
+      - pkgrepo: logilab-public-production
+      - pkgrepo: logilab-public-acceptance
+    - fromrepo: production
+
+cw-core:
+  pkg.installed:
+    - pkgs:
+      - cubicweb-common
+      - cubicweb-ctl
+      - cubicweb-postgresql-support
+      - cubicweb-server
+    - fromrepo: production
+    - require:
+      - pkg: cw-logilab-deps
+
+cw-basecubes:
+  pkg.installed:
+    - pkgs:
+      - cubicweb-blog
+      - cubicweb-card
+      - cubicweb-comment
+      - cubicweb-email
+      - cubicweb-file
+      - cubicweb-folder
+      - cubicweb-keyword
+      - cubicweb-localperms
+      - cubicweb-tag
+    - fromrepo: production
+    - require:
+      - pkg: cw-core
+
+cw-web:
+  pkg.installed:
+    - pkgs:
+      - cubicweb-web
+      - cubicweb-twisted
+    - fromrepo: production
+    - require:
+      - pkg: cw-core
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/instances.sls	Tue Apr 29 10:02:32 2014 +0200
@@ -0,0 +1,37 @@
+include:
+  - cubicweb
+
+{% for vhostname, vhost in pillar['cubicweb_apps'].iteritems() %}
+ {% for name, config in vhost.iteritems() %}
+
+cw-{{vhostname}}-{{name}}:
+  cubicweb_instance.present:
+    - name: {{name}}
+    - port: {{config.cwapp.port}}
+    - admin/login: {{config.cwapp.adminuser}}
+    - admin/password: {{config.cwapp.adminpass}}
+    - cubes: {{config.cwapp.cubes}}
+    - db-name: postgres
+    - db-host: {{  }}
+    - db-port: {{ who? }}
+    - db-name: {{config.database.name}}
+    - db-user: {{config.database.user}}
+    - db-password: {{config.database.password}}
+    - require:
+      - pkg: cw-{{vhostname}}-{{name}}
+  pkg.installed:
+    - pkgs:
+        {% for cube in config.cwapp.cubes -%}
+        - cubicweb-{{cube}} {% endfor %}
+    - require:
+      - pkg: cw-web
+
+cw-{{vhostname}}-{{name}}-running:
+  cubicweb_instance.running:
+    - name: {{name}}
+    - require:
+      - cubicweb_instance: cw-{{vhostname}}-{{name}}
+ {% endfor %}
+{% endfor %}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/logilab-pinning	Tue Apr 29 10:02:32 2014 +0200
@@ -0,0 +1,11 @@
+Package: *
+Pin: release a=acceptance
+Pin-Priority: 100
+
+Package: *
+Pin: release a=production
+Pin-Priority: 600
+
+Package: *
+Pin: release a=unstable
+Pin-Priority: 1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/logilab.sls	Tue Apr 29 10:02:32 2014 +0200
@@ -0,0 +1,24 @@
+
+/etc/apt/preferences.d/logilab-pinning:
+  file.managed:
+    - source: salt://cubicweb/logilab-pinning
+    - template: jinja
+
+logilab-public-acceptance:
+  pkgrepo.managed:
+    - human_name: Logilab acceptance public Debian repository
+    - name: deb http://download.logilab.org/acceptance {{ grains['oscodename'] }}/
+    - key_url: http://download.logilab.org/logilab-dists-key.asc
+    - gpgcheck: 1
+    - require:
+      - file: /etc/apt/preferences.d/logilab-pinning
+
+logilab-public-production:
+  pkgrepo.managed:
+    - human_name: Logilab production public Debian repository
+    - name: deb http://download.logilab.org/production {{ grains['oscodename'] }}/
+    - key_url: http://download.logilab.org/logilab-dists-key.asc
+    - gpgcheck: 1
+    - require:
+      - file: /etc/apt/preferences.d/logilab-pinning
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/monitor.sls	Tue Apr 29 10:02:32 2014 +0200
@@ -0,0 +1,21 @@
+include: 
+    - monit
+
+# TODO replace by debian package installation
+# cf https://intranet.logilab.fr/jpl/ticket/199142
+/usr/share/munin/plugins/cubicweb_stats:
+    file.managed: 
+        - source: salt://cubicweb/cubicweb_stats
+
+/etc/munin/plugins/cubicweb_stats:
+    file.symlink:
+        - target: /usr/share/munin/plugins/cubicweb_stats
+
+/usr/lib/nagios/plugins/check_cubicweb:
+    file.managed:
+        - source: salt://shinken/scripts/check_cubicweb
+        - mode: 0755
+
+/etc/nagios/nrpe.d/check_cubicweb.cfg:
+    file.managed:
+        - source: salt://shinken/nrpe.d/check_cubicweb.cfg
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/postgres.sls	Tue Apr 29 10:02:32 2014 +0200
@@ -0,0 +1,49 @@
+pg-server:
+  pkg.installed:
+    - pkgs:
+      - postgresql-9.1
+      - postgresql-contrib-9.1
+      - postgresql-plpython-9.1
+  service.running:
+    - name: postgresql
+
+/etc/postgresql/9.1/main/pg_hba.conf:
+  file.append:
+    - text:
+          - host    all             all             0.0.0.0/0            md5
+    - watch_in : pgserver
+
+{% for vhostname, vhost in pillar['cubicweb_apps'].iteritems() %}
+ {% for name, config in vhost.iteritems() %}
+
+pg-{{vhostname}}-{{name}}:
+  postgres_database:
+    - present
+    - name: {{ config.database.name }}
+    - owner: {{ config.database.user }}
+    - encoding: 'UTF8'
+    - template: template0
+    - require:
+      - postgres_user: pg-{{vhostname}}-{{name}}
+      - service: pg-server
+  postgres_user:
+    - present
+    - name: {{ config.database.user }}
+    - password: {{ config.database.password }}
+    - require:
+      - service: pg-server
+  module.run:
+    - name: postgres.create_extension
+    - m_name: plpythonu
+    - require:
+      - service: pg-server
+
+# Not yet available
+#  postgres_extension.present:
+#    - name: plpythonu
+#    - require:
+#      - service: pg-server
+#      - postgres_database: pg-{{vhostname}}-{{name}}
+ {% endfor %}
+{% endfor %}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/twisted.sls	Tue Apr 29 10:02:32 2014 +0200
@@ -0,0 +1,12 @@
+include:
+  - cubicweb
+
+cw-twisted:
+  pkg.installed:
+    - names:
+      - cubicweb-twisted
+      - cubicweb-web
+    - fromrepo: production
+    - require:
+      - pkg: cw-core
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pillar.example	Tue Apr 29 10:02:32 2014 +0200
@@ -0,0 +1,26 @@
+cubicweb_apps:
+  www.cubicweb.org:
+    - demo1:
+        database:
+          name: cw_blog
+          user: logidemo
+	  password: logidemo
+          cluster: 9.1/main
+        cwapp:
+          basepath: /demo/blog
+          port: 9090
+          adminuser: admin
+          adminpass: admin
+          cubes:
+            - blog
+    - demo2:
+        database:
+          name: cw_demo2
+          user: logidemo
+        cwapp:
+          basepath: /demo/demo2
+          port: 9091
+          adminuser: admin
+          adminpass: admin
+          cubes:
+            - blog